Mercurial > wow > skeletonkey
comparison SkeletonKey/KeyBinds.lua @ 6:f6d1c192afc6
Refactored file layout:
- frame display logic in UI.lua
- player data in Cache.lua
- event responses in Events.lua
a lot of local tables are now stored members of KeyBinder for that to work
author | Nenue |
---|---|
date | Thu, 28 Jul 2016 16:45:56 -0400 |
parents | 9ac29fe77455 |
children | a2fc77fa4c73 |
comparison
equal
deleted
inserted
replaced
5:9ac29fe77455 | 6:f6d1c192afc6 |
---|---|
19 local db | 19 local db |
20 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end | 20 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end |
21 | 21 |
22 --- Caps Lock literals | 22 --- Caps Lock literals |
23 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" | 23 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" |
24 local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:" | |
24 local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' | 25 local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' |
25 local BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.' | 26 local BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.' |
26 local BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r' | 27 local BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r' |
27 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" | 28 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" |
28 local FOOTER_OFFSET | 29 local FOOTER_OFFSET |
29 local HEADER_OFFSET | 30 local HEADER_OFFSET |
30 local HELP_1 = "Drag and drop spells/items from your inventory, spellbook, or collections panels." | 31 local HELP_1 = "Drag and drop spells/items from your inventory, spellbook, or collections panels." |
31 local HELP_2 = "While the cursor is above an icon, up to two key combinations will be bound to that action." | 32 local HELP_2 = "While the cursor is above an icon, up to two key combinations will be bound to that action." |
32 local HELP_3 = "If that key used for a client binding (e.g. game menu), a confirmation popup will appear before making the change." | 33 local HELP_3 = "If that key used for a client binding (e.g. game menu), a confirmation popup will appear before making the change." |
33 local BINDS_PER_ROW = 2 | 34 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 |
34 local BUTTON_HSPACING = 128 | 35 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION |
35 local BUTTON_SPACING = 4 | |
36 local BUTTON_PADDING = 12 | |
37 local BINDING_TYPE_SPECIALIZATION = 3 | 36 local BINDING_TYPE_SPECIALIZATION = 3 |
38 local BINDING_TYPE_CHARACTER = 2 | 37 local BINDING_TYPE_CHARACTER = 2 |
39 local BINDING_TYPE_GLOBAL = 1 | 38 local BINDING_TYPE_GLOBAL = 1 |
40 local KEY_BUTTON_SIZE = 48 | |
41 local MIN_BIND_SLOTS = 32 | |
42 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 | |
43 local TAB_OFFSET = 12 | |
44 local TAB_HEIGHT = 40 | |
45 local TAB_SPACING = 2 | |
46 local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } | |
47 local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } | |
48 local BORDER_DYNAMIC = {1,1,0,1} | |
49 local BORDER_PENDING = {1,0.5,0,1 } | |
50 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION | |
51 | 39 |
52 | 40 |
53 --- Caps Lock derivatives | 41 --- Caps Lock derivatives |
54 local ACTION_SCRIPT = { | 42 local ACTION_SCRIPT = { |
55 ['mount'] = "/script C_MountJournal.SummonByID(%d)", | 43 ['mount'] = "/script C_MountJournal.SummonByID(%d)", |
58 ['spell'] = "/cast %s", | 46 ['spell'] = "/cast %s", |
59 ['petaction'] = "/cast %s", | 47 ['petaction'] = "/cast %s", |
60 ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", | 48 ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", |
61 ['item'] = "/use %s" | 49 ['item'] = "/use %s" |
62 } | 50 } |
63 local BUTTON_HEADERS = { | |
64 ['spell'] = SPELLS, | |
65 ['macro'] = MACRO, | |
66 ['petaction'] = PET, | |
67 ['mount'] = MOUNT, | |
68 ['battlepet'] = BATTLEPET, | |
69 | |
70 | |
71 [5] = PROFESSIONS_FIRST_AID, | |
72 [7] = PROFESSIONS_COOKING, | |
73 [9] = PROFESSIONS_FISHING, | |
74 [10] = PROFESSIONS_ARCHAEOLOGY, | |
75 | |
76 } | |
77 | 51 |
78 local professionMappings = { | 52 local professionMappings = { |
79 [5] = 3, | 53 [5] = 3, |
80 [7] = 4, | 54 [7] = 4, |
81 [9] = 5, | 55 [9] = 5, |
82 [10] = 6 | 56 [10] = 6 |
83 } | 57 } |
84 | 58 |
85 local BINDING_MODE = { | 59 kb.configTitle = { |
86 [BINDING_TYPE_GLOBAL] = 'Global Binds', | 60 [BINDING_TYPE_GLOBAL] = 'Global Binds', |
87 [BINDING_TYPE_CHARACTER] = 'Character: %s', | 61 [BINDING_TYPE_CHARACTER] = 'Character: %s', |
88 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' | 62 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' |
89 } | 63 } |
90 local BINDING_DESCRIPTION = { | 64 kb.configDescription = { |
91 | |
92 [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.', | 65 [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.', |
93 [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.', | 66 [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.', |
94 [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.', | 67 [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.', |
95 } | 68 } |
96 | 69 |
97 local BINDING_SCHEME_COLOR = { | 70 |
98 [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5}, | 71 |
99 [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5}, | 72 kb.configHeaders = {} |
100 [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.5}, | 73 kb.loadedProfiles = {} |
101 } | 74 kb.orderedProfiles = {} |
102 local BINDING_SCHEME_VERTEX = { | 75 kb.buttons = {} |
103 [BINDING_TYPE_GLOBAL] = {0,.5,1,1}, | 76 kb.macros = {} |
104 [BINDING_TYPE_CHARACTER] = {0,1,0,1}, | 77 |
105 [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, | |
106 } | |
107 local BINDING_SCHEME_TEXT = { | |
108 [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1}, | |
109 [BINDING_TYPE_CHARACTER] = {0, 1, 0}, | |
110 [BINDING_TYPE_GLOBAL] = {0, 1, 1} | |
111 } | |
112 | |
113 | |
114 | |
115 local loadedProfiles = {} | |
116 -- Profiles ordered by precedance | |
117 local priority = {} | |
118 -- Button pointers | |
119 local buttons = {} | 78 local buttons = {} |
120 -- Backlog of changes | 79 -- Backlog of changes |
121 local reverts = {} | 80 local reverts = {} |
122 -- macro buttons used for mounts and other buttonable non-spells | 81 -- macro buttons used for mounts and other buttonable non-spells |
123 local macros = {} | 82 local macros = {} |
126 -- unselected talents | 85 -- unselected talents |
127 local talentBindings = {} | 86 local talentBindings = {} |
128 kb.inactiveTalentBindings = {} | 87 kb.inactiveTalentBindings = {} |
129 -- placeholder for the StaticPopup used for confirmations | 88 -- placeholder for the StaticPopup used for confirmations |
130 local confirmation | 89 local confirmation |
131 -- header text | |
132 local configHeaders = {} | |
133 | 90 |
134 local protected = { | 91 local protected = { |
135 ['OPENCHATSLASH'] = true, | 92 ['OPENCHATSLASH'] = true, |
136 ['OPENCHAT'] = true, | 93 ['OPENCHAT'] = true, |
137 } | 94 } |
138 | 95 |
139 --- Used to reflect the current working state | 96 --- Used to reflect the current working state |
140 local bindMode = 3 | |
141 local bindHeader, currentHeader = '', '' | 97 local bindHeader, currentHeader = '', '' |
142 local configProfile, character, specialization, global, character_specialization | |
143 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' | 98 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' |
144 local classHeader, className, classID = '', '', 0 | 99 local classHeader, className, classID = '', '', 0 |
145 local numButtons = BINDS_PER_ROW * 8 | |
146 local bindsCommitted = true | 100 local bindsCommitted = true |
147 local forceButtonUpdate = false | 101 local forceButtonUpdate = false |
148 | 102 |
149 --- Control handles | 103 --- Control handles |
150 local saveButton, restoreButton, clearButton | 104 local saveButton, restoreButton, clearButton |
157 PickupAction.mount = _G.C_MountJournal.Pickup | 111 PickupAction.mount = _G.C_MountJournal.Pickup |
158 local GetPickupValue = {} | 112 local GetPickupValue = {} |
159 GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end | 113 GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end |
160 | 114 |
161 --- Returns conflicting assignment and binding profiles for use in displaying confirmations | 115 --- Returns conflicting assignment and binding profiles for use in displaying confirmations |
162 local IsCommandBound = function(self, command) | 116 kb.IsCommandBound = function(self, command) |
163 local isAssigned, assignedBy = false, bindMode | 117 local isAssigned, assignedBy = false, db.bindMode |
164 local isBound, boundBy = false, bindMode | 118 local isBound, boundBy = false, db.bindMode |
165 | 119 |
166 | 120 |
167 command = command or self.command | 121 command = command or self.command |
168 for i = 1, #BINDING_MODE do | 122 for i = 1, #kb.orderedProfiles do |
169 local tier = priority[i] | 123 local tier = kb.orderedProfiles[i] |
170 if i ~= bindMode then | 124 if i ~= db.bindMode then |
171 | 125 |
172 if tier.commands[command] then | 126 if tier.commands[command] then |
173 isAssigned = true | 127 isAssigned = true |
174 assignedBy = i | 128 assignedBy = i |
175 end | 129 end |
186 end | 140 end |
187 end | 141 end |
188 | 142 |
189 end | 143 end |
190 | 144 |
191 print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) | 145 print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) |
192 return isAssigned, isBound, assignedBy, boundBy | 146 return isAssigned, isBound, assignedBy, boundBy |
193 end | 147 end |
194 | 148 |
195 local talentSpellHardCodes = { | 149 local talentSpellHardCodes = { |
196 [109248] = 'Binding Shot', | 150 [109248] = 'Binding Shot', |
197 } | 151 } |
198 | 152 |
199 --- Returns a value for use with Texture:SetDesaturated() | 153 --- Returns a value for use with Texture:SetDesaturated() |
200 local BindingIsLocked = function(key) | 154 kb.BindingIsLocked = function(key) |
201 local success = false | 155 local success = false |
202 for i = 1, bindMode-1 do | 156 for i = 1, db.bindMode-1 do |
203 local tier = priority[i] | 157 local tier = kb.orderedProfiles[i] |
204 if tier.bindings[key] then | 158 if tier.bindings[key] then |
205 success = true | 159 success = true |
206 break | 160 break |
207 end | 161 end |
208 end | 162 end |
209 return success | 163 return success |
210 end | 164 end |
211 | 165 |
212 --- Translates GetBindingKey() results into a printable string. | 166 --- Translates GetBindingKey() results into a printable string. |
213 local BindingString = function(...) | 167 kb.BindingString = function(...) |
214 local stack = {} | 168 local stack = {} |
215 for i = 1, select('#', ...) do | 169 for i = 1, select('#', ...) do |
216 local key = select(i, ...) | 170 local key = select(i, ...) |
217 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') | 171 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') |
218 end | 172 end |
222 else | 176 else |
223 return nil | 177 return nil |
224 end | 178 end |
225 end | 179 end |
226 | 180 |
227 local restingAlpha = 0.7 | 181 |
228 local fadeTime, fadeDelay = .30, 0.15 | 182 |
229 | |
230 local portraitLayers = {} | |
231 kb.UpdatePortraits = function() | |
232 for i, layeredRegion in ipairs(portraitLayers) do | |
233 SetPortraitTexture(layeredRegion , 'player') | |
234 end | |
235 end | |
236 | |
237 | |
238 | |
239 local KeyButton_OnKeyDown = function(self, key) | |
240 kb.StoreBinding(self, key) | |
241 end | |
242 local KeyButton_OnClick = function(self, click) | |
243 print(self:GetName(), 'OnMouseDown', click) | |
244 if click == 'LeftButton' then | |
245 kb.DropToSlot(self) | |
246 elseif click == 'RightButton' then | |
247 kb.ReleaseSlot(self) | |
248 else | |
249 kb.StoreBinding(self, click:upper()) | |
250 end | |
251 end | |
252 | |
253 local KeyButton_OnDragStart = function(self) | |
254 kb.PickupSlot(self) | |
255 end | |
256 | |
257 local KeyButton_OnReceiveDrag = function(self, ...) | |
258 kb.DropToSlot(self) | |
259 end | |
260 | |
261 | |
262 local KeyBinder_OnUpdate = function(self, elapsed) | |
263 self.elapsed = self.elapsed + elapsed | |
264 self.throttle = self.throttle + elapsed | |
265 | |
266 if (self.throttle >= 0.032) then | |
267 self.throttle = 0 | |
268 else | |
269 return | |
270 end | |
271 | |
272 local progress = 1 | |
273 if self.elapsed > fadeTime then | |
274 self.elapsed = 0 | |
275 self.fadeStep = 0 | |
276 --self.statustext:SetText(nil) | |
277 --self.bindingstext:SetText(nil) | |
278 self:SetScript('OnUpdate', nil) | |
279 else | |
280 if self.elapsed < fadeDelay then | |
281 progress = 0 | |
282 else | |
283 self.fadeStep = self.fadeStep + 1 | |
284 progress = (self.elapsed - fadeDelay) /(fadeTime - fadeDelay) | |
285 end | |
286 --print(self.fadeStep, format('%.02f/%.02f', (self.elapsed - fadeDelay) ,(fadeTime - fadeDelay)) , progress) | |
287 end | |
288 | |
289 local alpha = 1 - progress * (1- restingAlpha) | |
290 self.statustext:SetAlpha(alpha) | |
291 self.bindingstext:SetAlpha(alpha) | |
292 end | |
293 | |
294 local KeyButton_OnUpdate = function(self) | |
295 if not self.command then | |
296 return | |
297 end | |
298 | |
299 if self:IsMouseOver() then | |
300 kb.elapsed = 0 | |
301 if not self.active then | |
302 -- only set this handler when the button is activated/mouseOver | |
303 self.active = true | |
304 self:SetScript('OnKeyDown', KeyButton_OnKeyDown) | |
305 | |
306 kb.statustext:SetText(self.statusText .. ': '..self.actionName) | |
307 kb.bindingstext:SetText(self.bindingText) | |
308 kb.fadeStep = 0 | |
309 kb.throttle = 0 | |
310 kb:SetScript('OnUpdate', KeyBinder_OnUpdate) | |
311 | |
312 end | |
313 else | |
314 if self.active then | |
315 self.active = nil | |
316 self:SetScript('OnKeyDown', nil) | |
317 end | |
318 end | |
319 end | |
320 | |
321 local KeyBinder_OnMouseWheel = function(self, delta) | |
322 print(self, delta, self.scrollOffset, (self.scrollOffset <= 0)) | |
323 | |
324 | |
325 if IsControlKeyDown() then | |
326 KEY_BUTTON_SIZE = KEY_BUTTON_SIZE - delta | |
327 else | |
328 | |
329 | |
330 if (delta > 0) and (self.scrollOffset <= 0) then | |
331 return | |
332 elseif delta < 0 and kb.scrollOffset >= 42 then | |
333 return | |
334 end | |
335 kb.scrollOffset = ceil(kb.scrollOffset - (delta * BINDS_PER_ROW)) | |
336 end | |
337 | |
338 kb.ui(true) | |
339 end | |
340 | |
341 local KeyBinder_OnHide = function() | |
342 KeyBinderImportLog:Hide() | |
343 end | |
344 | |
345 local CloseButton_OnClick = function() | |
346 db.showUI = false | |
347 kb:Hide() | |
348 end | |
349 local CancelButton_OnClick = function() | |
350 kb.RevertBindings() | |
351 end | |
352 local SaveButton_OnClick = function() | |
353 kb.ConfirmBindings() | |
354 end | |
355 | |
356 local KeyBinder_Initialize = function() | |
357 for i = 1, GetNumBindings() do | |
358 local command = GetBinding(i) | |
359 bindings[command] = true | |
360 end | |
361 | |
362 kb.scrollOffset = 0 | |
363 kb.tabAnchor = {'TOPLEFT', kb.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} | |
364 kb.tabGrowth = {'TOPLEFT', nil,'TOPRIGHT', BUTTON_SPACING, 0} | |
365 kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT } | |
366 kb.UIPanelAnchor = {'TOPLEFT', kb.sourcesbg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} | |
367 kb.UIPanelGrowth = {'TOPLEFT', nil, 'BOTTOMLEFT', 0, -2 } | |
368 kb.UIPanelSize = {84, 32 } | |
369 kb.UIPanelIcon = {24, 32, 'LEFT', -12, 0} | |
370 kb.controlsAnchor = {'BOTTOMLEFT', kb.footer, BUTTON_PADDING, BUTTON_PADDING } | |
371 kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0} | |
372 | |
373 -- order of these is important | |
374 kb:tab('KeyBinderGlobalTab', | |
375 BINDING_MODE[BINDING_TYPE_GLOBAL] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) | |
376 kb:tab('KeyBinderCharacterTab', | |
377 configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_CHARACTER], nil) | |
378 kb:tab('KeyBinderSpecTab', | |
379 configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_SPECIALIZATION], specTexture) | |
380 KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) | |
381 | |
382 | |
383 | |
384 portraitLayers[1] = KeyBinderCharacterTab.icon | |
385 | |
386 saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', SaveButton_OnClick) | |
387 --restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', CancelButton_OnClick) | |
388 --clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', ResetButton_OnClick) | |
389 | |
390 kb:uibutton( | |
391 'KeyBinderSpellBookButton', 'SpellBook', nil, | |
392 function() ToggleSpellBook(BOOKTYPE_SPELL) end, | |
393 "Interface\\BUTTONS\\UI-MicroButton-Spellbook-Up", {0, 1, .4, 1}) | |
394 kb:uibutton( | |
395 'KeyBinderTalentFrameButton', TALENTS, SPECIALIZATION, | |
396 function() ToggleTalentFrame() end, | |
397 "Interface\\BUTTONS\\UI-MicroButton-Talents-Up", {0, 1, .4, 1}) | |
398 | |
399 kb:uibutton( | |
400 'KeyBinderMacroFrameButton', 'Macros', nil, | |
401 function() if MacroFrame and MacroFrame:IsVisible() then | |
402 HideUIPanel(MacroFrame) | |
403 else | |
404 ShowMacroFrame() end | |
405 end, | |
406 "Interface\\BUTTONS\\UI-MicroButton-Help-Up", {0, 1, .4, 1}) | |
407 | |
408 kb:uibutton( | |
409 'KeyBinderInventoryButton', 'Bags', nil, | |
410 function() OpenAllBags() end, | |
411 "Interface\\BUTTONS\\UI-MicroButtonCharacter-Up", {0, 1, .4, 1}) | |
412 | |
413 | |
414 | |
415 kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING) | |
416 HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING | |
417 + kb.info:GetHeight() | |
418 FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING | |
419 | |
420 kb:SetScript('OnHide', KeyBinder_OnHide) | |
421 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) | |
422 kb.CloseButton:SetScript('OnClick', CloseButton_OnClick) | |
423 | |
424 kb.UpdatePortraits() | |
425 end | |
426 | 183 |
427 kb.DropToSlot = function(self) | 184 kb.DropToSlot = function(self) |
428 | 185 |
429 print(self:GetName(),'|cFF0088FFreceived|r') | 186 print(self:GetName(),'|cFF0088FFreceived|r') |
430 local actionType, actionID, subType, subData = GetCursorInfo() | 187 local actionType, actionID, subType, subData = GetCursorInfo() |
483 | 240 |
484 end | 241 end |
485 macroName, macroText, command = kb.RegisterAction(actionType, actionID) | 242 macroName, macroText, command = kb.RegisterAction(actionType, actionID) |
486 | 243 |
487 | 244 |
488 local isAssigned, isBound, assignedBy, boundBy = IsCommandBound(self, command) | 245 local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) |
489 if isAssigned then | 246 if isAssigned then |
490 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] | 247 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] |
491 popup.slot = self | 248 popup.slot = self |
492 popup.text = "Currently assigned in |cFFFFFF00"..tostring(configHeaders[assignedBy]).."|r. Are you sure?" | 249 popup.text = "Currently assigned in |cFFFFFF00"..tostring(configHeaders[assignedBy]).."|r. Are you sure?" |
493 popup.oldProfile = assignedBy | 250 popup.oldProfile = assignedBy |
496 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') | 253 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') |
497 else | 254 else |
498 kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) | 255 kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) |
499 kb.UpdateSlot(self) | 256 kb.UpdateSlot(self) |
500 self.active = nil | 257 self.active = nil |
501 KeyButton_OnUpdate(self, 0) | |
502 ClearCursor() | 258 ClearCursor() |
503 ResetCursor() | 259 ResetCursor() |
504 end | 260 end |
505 end | 261 end |
506 end | 262 end |
529 kb.UpdateSlot(self) | 285 kb.UpdateSlot(self) |
530 end | 286 end |
531 end | 287 end |
532 | 288 |
533 | 289 |
534 --- Resolve the appropriate command and assign the corresponding secure state driver | 290 --- Resolve the appropriate command and macroText for the given action parameters |
535 kb.RegisterAction = function(type, id) | 291 kb.RegisterAction = function(type, id) |
292 local macroText, macroName, command = '', '', '' | |
536 | 293 |
537 if type == 'spell' then | 294 if type == 'spell' then |
538 | 295 if kb.ProfessionCache[id] then |
539 id = GetSpellInfo(id) | 296 command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum |
540 end | 297 else |
541 | 298 command = CLICK_KEYBINDER_KEY ..id |
542 local macroText | 299 end |
543 local macroName = type ..'_' .. id | |
544 | |
545 if kb.ProfessionCache[id] then | |
546 macroName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum | |
547 macroText = "/cast " .. kb.ProfessionCache[id].spellName | |
548 macros[macroName] = nil | |
549 else | 300 else |
550 macroName = macroName:gsub(' ', '') | 301 macroName = type .. ' ' .. id |
551 macroText = ACTION_SCRIPT[type]:format(id) | 302 macroText = ACTION_SCRIPT[type]:format(id) |
552 end | 303 local baseName, iterative = macroName, 1 |
553 | 304 while (macros[macroName] and macros[macroName][1] ~= macroText) do |
554 local baseName, iterative = macroName, 1 | 305 print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"') |
555 while (macros[macroName] and macros[macroName][1] ~= macroText) do | 306 macroName = baseName .. '_' .. iterative |
556 print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"') | 307 iterative = iterative + 1 |
557 macroName = baseName .. '_' .. iterative | 308 end |
558 iterative = iterative + 1 | 309 if macroName ~= baseName then |
559 end | 310 print(' * Creating|cFF00FF00', macroName) |
560 if macroName ~= baseName then | 311 else |
561 print(' * Creating|cFF00FF00', macroName) | 312 print(' * Re-using|cFF00FF00', macroName) |
562 else | 313 end |
563 print(' * Re-using|cFF00FF00', macroName) | 314 command = 'CLICK KeyBinderMacro:'.. macroName |
564 end | 315 macros[macroName] = {macroText, command } |
565 | 316 end |
566 local command = 'CLICK KeyBinderMacro:'.. macroName | 317 |
567 macros[macroName] = {macroText, command } | 318 print('RegisterAction', type, id, '->', command , macroText) |
568 print('RegisterAction', command , macroText) | |
569 if type == 'macro' then | |
570 kb.LoadMacro(macroName) | |
571 else | |
572 kb.LoadAction(macroName, macroText, command) | |
573 end | |
574 | |
575 | |
576 return macroName, macroText, command | 319 return macroName, macroText, command |
577 end | 320 end |
578 | |
579 kb.LoadMacro = function(macroName) | |
580 KeyBinderMacro:SetAttribute('*macro-'..macroName, macros[macroName][1]) | |
581 return true | |
582 end | |
583 | |
584 kb.LoadAction = function(macroName) | |
585 if not macros[macroName] then | |
586 return false | |
587 end | |
588 KeyBinderMacro:SetAttribute('*macrotext-'..macroName, macros[macroName][1]) | |
589 return true | |
590 end | |
591 | |
592 local profressionsCache | |
593 | |
594 kb.AcceptAssignment = function(self, ...) | |
595 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] | |
596 local source = loadedProfiles[popup.oldProfile] | |
597 kb.SetSlot(popup.slot, unpack(popup.args)) | |
598 kb.UpdateSlot(popup.slot) | |
599 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling | |
600 ClearCursor() | |
601 ResetCursor() | |
602 end | |
603 | |
604 | 321 |
605 --- Updates the current KeyBinding for the button's command | 322 --- Updates the current KeyBinding for the button's command |
606 kb.StoreBinding = function(self, key) | 323 kb.StoreBinding = function(self, key) |
607 | 324 |
608 if not self.command then | 325 if not self.command then |
619 --print('detected', #keys, 'bindings') | 336 --print('detected', #keys, 'bindings') |
620 for i, key in pairs(keys) do | 337 for i, key in pairs(keys) do |
621 --print('clearing', key) | 338 --print('clearing', key) |
622 SetBinding(key, nil) | 339 SetBinding(key, nil) |
623 SaveBindings(GetCurrentBindingSet()) | 340 SaveBindings(GetCurrentBindingSet()) |
624 if configProfile.bindings[key] then | 341 if kb.currentProfile.bindings[key] then |
625 kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode])) | 342 kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) |
626 configProfile.bindings[key] = nil | 343 kb.currentProfile.bindings[key] = nil |
627 end | 344 end |
628 if configProfile.talents[self.actionName] then | 345 if kb.currentProfile.talents[self.actionName] then |
629 configProfile.talents[self.actionName] = nil | 346 kb.currentProfile.talents[self.actionName] = nil |
630 end | 347 end |
631 bindings[self.actionType][self.actionID] = nil | 348 bindings[self.actionType][self.actionID] = nil |
632 end | 349 end |
633 if configProfile.bound[self.command] then | 350 if kb.currentProfile.bound[self.command] then |
634 configProfile.bound[self.command] = nil | 351 kb.currentProfile.bound[self.command] = nil |
635 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode])) | 352 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) |
636 end | 353 end |
637 | 354 |
638 bindsCommitted = false | 355 bindsCommitted = false |
639 self.active = false | 356 self.active = false |
640 else | 357 else |
684 for i, key in ipairs(bindings) do | 401 for i, key in ipairs(bindings) do |
685 tinsert(talentInfo, key) | 402 tinsert(talentInfo, key) |
686 end | 403 end |
687 end | 404 end |
688 | 405 |
689 for level, configProfile in ipairs(priority) do | 406 for level, profile in ipairs(kb.orderedProfiles) do |
690 if (level == bindMode) then | 407 if (level == db.bindMode) then |
691 configProfile.bound[self.command] = true | 408 profile.bound[self.command] = true |
692 if talentInfo then | 409 if talentInfo then |
693 configProfile.bindings[self.binding] = nil | 410 profile.bindings[self.binding] = nil |
694 else | 411 else |
695 configProfile.bindings[self.binding] = self.command | 412 profile.bindings[self.binding] = self.command |
696 end | 413 end |
697 configProfile.talents[self.actionName] = talentInfo | 414 profile.talents[self.actionName] = talentInfo |
698 else | 415 else |
699 configProfile.bindings[self.binding] = nil | 416 profile.bindings[self.binding] = nil |
700 configProfile.bound[self.command] = nil | 417 profile.bound[self.command] = nil |
701 configProfile.talents[self.actionName] = nil | 418 kb.currentProfile.talents[self.actionName] = nil |
702 end | 419 end |
703 if configProfile.talents[self.actionID] then | 420 if kb.currentProfile.talents[self.actionID] then |
704 configProfile.talents[self.actionID] = nil | 421 kb.currentProfile.talents[self.actionID] = nil |
705 end | 422 end |
706 | 423 |
707 end | 424 end |
708 | 425 |
709 | 426 |
710 | 427 |
711 kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, configHeaders[bindMode])) | 428 kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, kb.configHeaders[db.bindMode])) |
712 | 429 |
713 end | 430 end |
714 end | 431 end |
715 | 432 |
716 kb.UpdateSlot(self, true) | 433 kb.UpdateSlot(self, true) |
717 KeyBinderSaveButton:Enable() | 434 KeyBinderSaveButton:Enable() |
718 | 435 |
719 end | 436 end |
720 | 437 |
721 --- Resets button command | 438 |
722 kb.ReleaseSlot = function(self) | 439 kb.inactiveTalentBindings = {} |
723 local slot = self:GetID() | |
724 | |
725 | |
726 if configProfile.buttons[slot] then | |
727 configProfile.buttons[slot] = nil | |
728 end | |
729 if self.command then | |
730 configProfile.commands[self.command] = nil | |
731 end | |
732 if self.actionType == 'spell' and IsTalentSpell(self.actionName) then | |
733 if configProfile.talents[self.actionID] then | |
734 configProfile.talents[self.actionID] = nil | |
735 end | |
736 end | |
737 local droppedKeys = {} | |
738 | |
739 -- doing removal in second loop to avoid possible iterator shenanigans | |
740 for k,v in pairs(configProfile.bindings) do | |
741 if v == self.command then | |
742 tinsert(droppedKeys, k) | |
743 end | |
744 end | |
745 if #droppedKeys >=1 then | |
746 for i, k in ipairs(droppedKeys) do | |
747 configProfile.bindings[k] = nil | |
748 end | |
749 end | |
750 | |
751 self.isAvailable = nil | |
752 self.isDynamic = nil | |
753 self.bindingText = nil | |
754 self.statusText = nil | |
755 self.command = nil | |
756 self.actionType = nil | |
757 self.actionID = nil | |
758 self.actionName = nil | |
759 self.pickupSlot = nil | |
760 self.pickupBook = nil | |
761 self.macroName = nil | |
762 self.profile = nil | |
763 self.icon:SetTexture(nil) | |
764 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) | |
765 self:EnableKeyboard(false) | |
766 self:SetScript('OnKeyDown', nil) | |
767 end | |
768 | |
769 kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook) | |
770 local slot = self:GetID() | |
771 local isDynamic, isAvailable | |
772 | |
773 print('|cFFFFFF00SetSlot|r:', self:GetID()) | |
774 if command then | |
775 | |
776 if actionType == 'spell' then | |
777 local professionNum, spellNum = command:match("profession_(%d)_(%d)") | |
778 | |
779 if (professionNum and spellNum) then | |
780 isDynamic = 'profession' | |
781 local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum] | |
782 if cacheInfo then | |
783 isAvailable = true | |
784 name = cacheInfo.spellName | |
785 icon = cacheInfo.icon | |
786 actionID = cacheInfo.spellID | |
787 self.profIndex = cacheInfo.profIndex | |
788 self.spellOffset = cacheInfo.spellOffset | |
789 end | |
790 print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable) | |
791 | |
792 self.professionNum = tonumber(professionNum) | |
793 self.spellNum = tonumber(spellNum) | |
794 | |
795 elseif kb.TalentCache[actionID] then | |
796 | |
797 isDynamic = 'talent' | |
798 isAvailable = GetSpellInfo(name) | |
799 print(' Special slot: |cFFBBFF00talent|r', name, isAvailable) | |
800 end | |
801 if not actionID then | |
802 actionID = select(7, GetSpellInfo(name)) | |
803 end | |
804 elseif actionType == 'macro' then | |
805 if not actionID then | |
806 actionID = GetMacroIndexByName(name) | |
807 end | |
808 else | |
809 --- Journal selections | |
810 -- todo: consider using the deep end of blizzard action bar instead | |
811 if not actionID then | |
812 actionID = command:match("^KeyBinderMacro:(.+)") | |
813 end | |
814 end | |
815 | |
816 if not macroName then | |
817 local previousCommand = command | |
818 macroName, macroText, command = kb.RegisterAction(actionType, actionID) | |
819 | |
820 -- Clean up conflicting command entry for loaded buttons | |
821 if macroName and command ~= previousCommand then | |
822 print(' Repaired corruption in |cFFFFFF00'..currentHeader..'|r button #'.. self:GetID()) | |
823 configProfile.commands[previousCommand] = nil | |
824 configProfile.bound[previousCommand] = nil | |
825 end | |
826 end | |
827 | |
828 if actionType == 'petaction' then | |
829 self.pickupSlot = pickupSlot | |
830 self.pickupBook = pickupBook | |
831 else | |
832 self.pickupSlot = nil | |
833 self.pickupBook = nil | |
834 end | |
835 | |
836 actionID = actionID or 0 | |
837 self:EnableKeyboard(true) | |
838 print(' |cFF00FF00configProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r') | |
839 configProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook} | |
840 | |
841 -- Clean up conflicting entries for loaded button | |
842 local previous = configProfile.commands[command] | |
843 if previous ~= slot and buttons[previous] then | |
844 kb.ReleaseSlot(buttons[previous]) | |
845 end | |
846 configProfile.commands[command] = slot | |
847 end | |
848 | |
849 self.isAvailable = isAvailable | |
850 self.isDynamic = isDynamic | |
851 | |
852 self.macroText = macroText | |
853 self.macroName = macroName | |
854 self.actionType = actionType | |
855 self.actionID = actionID | |
856 self.actionName = name | |
857 self.command = command | |
858 self.icon:SetTexture(icon) | |
859 self.profile = bindMode | |
860 self:RegisterForDrag('LeftButton') | |
861 end | |
862 | |
863 --- Retrieves button at index; creates said button and instates any stored parameters | |
864 local leftSlot, upSlot | |
865 local buttonsDepth = 0 | |
866 kb.GetSlot = function(index) | |
867 | |
868 local slot = index + kb.scrollOffset | |
869 | |
870 if not buttons[index] then | |
871 local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton') | |
872 button:SetScript('OnClick', KeyButton_OnClick) | |
873 button:SetScript('OnUpdate', KeyButton_OnUpdate) | |
874 button:SetScript('OnDragStart', KeyButton_OnDragStart) | |
875 button:SetScript('OnReceiveDrag', KeyButton_OnReceiveDrag) | |
876 button:RegisterForClicks('AnyUp') | |
877 | |
878 | |
879 local newRow = (mod(index, BINDS_PER_ROW) == 1) | |
880 | |
881 if index == 1 then | |
882 button:SetPoint('TOPLEFT', kb.bg, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING) | |
883 upSlot = button | |
884 buttonsDepth = KEY_BUTTON_SIZE + BUTTON_PADDING * 2 | |
885 elseif newRow then | |
886 button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING) | |
887 upSlot = button | |
888 buttonsDepth = buttonsDepth + KEY_BUTTON_SIZE + BUTTON_SPACING | |
889 else | |
890 button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0) | |
891 end | |
892 | |
893 button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) | |
894 button:Show() | |
895 buttons[index] = button | |
896 leftSlot = button | |
897 end | |
898 return buttons[index] | |
899 end | |
900 | |
901 --- Updates profile assignment and button contents | |
902 kb.UpdateSlot = function(self, force) | |
903 local slot = self:GetID() | |
904 | |
905 if force then | |
906 if configProfile.buttons[slot] then | |
907 kb.SetSlot(self, unpack(configProfile.buttons[slot])) | |
908 else | |
909 kb.ReleaseSlot(self) | |
910 end | |
911 end | |
912 | |
913 if self.command then | |
914 print('['..slot..'] =', self.command, GetBindingKey(self.command)) | |
915 | |
916 if self.pending then | |
917 self.border:SetColorTexture(unpack(BORDER_PENDING)) | |
918 elseif self.isDynamic then | |
919 self.border:SetColorTexture(unpack(BORDER_DYNAMIC)) | |
920 else | |
921 self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) | |
922 end | |
923 | |
924 if self.actionType == 'macro' then | |
925 self.macro:Show() | |
926 else | |
927 self.macro:Hide() | |
928 if self.actionType == 'spell' then | |
929 local dummy = GetSpellInfo(self.actionName) | |
930 if not dummy then | |
931 self.icon:SetDesaturated(true) | |
932 else | |
933 self.icon:SetDesaturated(false) | |
934 end | |
935 | |
936 end | |
937 end | |
938 | |
939 if self.isDynamic then | |
940 print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID) | |
941 end | |
942 | |
943 if self.isDynamic == 'profession' then | |
944 local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex)) | |
945 if self.isAvailable then | |
946 print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1)) | |
947 | |
948 self.statusText = '|cFFFFFF00'..profText..'|r' | |
949 self.bindingText = BindingString(GetBindingKey(self.command)) | |
950 else | |
951 self.statusText = '|cFFFF4400'..profText..'|r' | |
952 self.actionName = '(need to train profession #'..self.profNum..')' | |
953 self.bindingText ='?' | |
954 end | |
955 elseif self.isDynamic == 'talent' then | |
956 | |
957 self.statusText = '|cFF00FFFF'.. TALENT .. '|r' | |
958 if self.isAvailable then | |
959 self.bindingText = BindingString(GetBindingKey(self.command)) | |
960 else | |
961 print(self.actionID, #kb.inactiveTalentBindings[self.actionID]) | |
962 self.bindingText= BindingString(unpack(kb.inactiveTalentBindings[self.actionID])) | |
963 end | |
964 else | |
965 self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r' | |
966 self.bindingText = BindingString(GetBindingKey(self.command)) | |
967 end | |
968 | |
969 local locked, layer = IsCommandBound(self) | |
970 if locked then | |
971 self.icon:SetAlpha(0.5) | |
972 else | |
973 self.icon:SetAlpha(1) | |
974 end | |
975 | |
976 if self.actionType == 'spell' then | |
977 self.icon:SetTexture(GetSpellTexture(self.actionID)) | |
978 end | |
979 end | |
980 | |
981 if not self.isAvailable then | |
982 self.bind:SetTextColor(0.7,0.7,0.7,1) | |
983 else | |
984 self.bind:SetTextColor(1,1,1,1) | |
985 end | |
986 | |
987 self.header:SetText(self.statusText) | |
988 self.bind:SetText(self.bindingText) | |
989 self.macro:SetText(self.macroName) | |
990 self.details:SetText(self.actionName) | |
991 end | |
992 | |
993 | |
994 kb.ApplyTalentBinding = function(talentInfo, cache) | 440 kb.ApplyTalentBinding = function(talentInfo, cache) |
995 for i = 5, #talentInfo do | 441 for i = 5, #talentInfo do |
996 SetBinding(talentInfo[i], "CLICK KeyBinderMacro:".. talentInfo[1]) | 442 local command = CLICK_KEYBINDER_KEY.. talentInfo[2] |
443 SetBinding(talentInfo[i], command) | |
444 cprint(' **', talentInfo[i], '->', command) | |
997 tinsert(cache, talentInfo[i]) | 445 tinsert(cache, talentInfo[i]) |
998 end | 446 end |
999 end | 447 end |
1000 kb.CacheTalentBinding = function(talentInfo, cache) | 448 kb.CacheTalentBinding = function(talentInfo, cache) |
449 | |
1001 local spellID = talentInfo[4] | 450 local spellID = talentInfo[4] |
1002 kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {} | 451 kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {} |
1003 kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) } | 452 kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) } |
1004 cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) | 453 --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) |
1005 end | 454 end |
1006 | 455 |
1007 kb.ApplyBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) | 456 kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) |
1008 | 457 |
1009 if actionType == 'macro' then | 458 |
459 | |
460 if actionType == 'spell' then | |
461 KeyBinderKey:SetAttribute("*type-"..name, actionType) | |
462 KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) | |
463 elseif actionType == 'item' then | |
464 KeyBinderKey:SetAttribute("*type-"..name, actionType) | |
465 KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) | |
466 elseif actionType == 'macro' then | |
1010 KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID) | 467 KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID) |
1011 else | 468 else |
1012 KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText) | 469 KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText) |
1013 end | 470 end |
1014 bindings[actionType] = bindings[actionType] or {} | 471 bindings[actionType] = bindings[actionType] or {} |
1018 end | 475 end |
1019 | 476 |
1020 kb.ApplyBindings = function (profile) | 477 kb.ApplyBindings = function (profile) |
1021 cprint('binding profile', profile) | 478 cprint('binding profile', profile) |
1022 for slot, data in pairs(profile.buttons) do | 479 for slot, data in pairs(profile.buttons) do |
1023 kb.ApplyBinding(unpack(data)) | 480 kb.LoadBinding(unpack(data)) |
1024 end | 481 end |
1025 | 482 |
1026 for key, command in pairs(profile.bindings) do | 483 for key, command in pairs(profile.bindings) do |
1027 | 484 |
1028 cprint('Bindings data registered', command, key) | 485 cprint(' *', key, '->', command) |
1029 | 486 |
1030 --_G.print('HotKey','loading', key, command) | 487 --_G.print('HotKey','loading', key, command) |
1031 SetBinding(key, command) | 488 SetBinding(key, command) |
1032 if bindings[command] and not tContains(bindings[command], key) then | 489 if bindings[command] and not tContains(bindings[command], key) then |
1033 tinsert(bindings[command], key) | 490 tinsert(bindings[command], key) |
1056 end | 513 end |
1057 | 514 |
1058 kb.ApplyAllBindings =function () | 515 kb.ApplyAllBindings =function () |
1059 table.wipe(kb.inactiveTalentBindings) | 516 table.wipe(kb.inactiveTalentBindings) |
1060 | 517 |
1061 for i, profile in ipairs(priority) do | 518 -- reflect action key settings |
519 if GetCVarBool("ActionButtonUseKeyDown") then | |
520 KeyBinderMacro:RegisterForClicks("AnyDown") | |
521 KeyBinderKey:RegisterForClicks("AnyDown") | |
522 else | |
523 KeyBinderMacro:RegisterForClicks("AnyUp") | |
524 KeyBinderKey:RegisterForClicks("AnyUp") | |
525 end | |
526 | |
527 for i, profile in ipairs(kb.orderedProfiles) do | |
1062 kb.ApplyBindings(profile) | 528 kb.ApplyBindings(profile) |
1063 end | 529 end |
1064 -- do this after to ensure that profession binds are properly overridden | 530 -- do this after to ensure that profession binds are properly overridden |
1065 kb.UpdateProfessionInfo() | 531 kb.UpdateProfessionInfo() |
532 | |
533 | |
1066 end | 534 end |
1067 | 535 |
1068 kb.Command = function(args, editor) | 536 kb.Command = function(args, editor) |
1069 if args:match("import") then | 537 if args:match("import") then |
1070 kb.ImportCommmit(args) | 538 kb.ImportCommmit(args) |
1110 profile.talents = profile.talents or {} | 578 profile.talents = profile.talents or {} |
1111 return profile | 579 return profile |
1112 end | 580 end |
1113 | 581 |
1114 kb.ResetProfile = function(profile, prototype) | 582 kb.ResetProfile = function(profile, prototype) |
1115 if profile == configProfile then | 583 if profile == kb.currentProfile then |
1116 for i, button in pairs(buttons) do | 584 for i, button in pairs(buttons) do |
1117 kb.ReleaseSlot(button) | 585 kb.ReleaseSlot(button) |
1118 end | 586 end |
1119 end | 587 end |
1120 table.wipe(profile) | 588 table.wipe(profile) |
1124 | 592 |
1125 | 593 |
1126 --- Handles constructing spec profiles as they are selected | 594 --- Handles constructing spec profiles as they are selected |
1127 | 595 |
1128 | 596 |
1129 kb.TalentCache = {} | |
1130 | |
1131 kb.UpdateSpecInfo = function() | |
1132 specID = GetSpecialization() | |
1133 specGlobalID, specName, specDesc , specTexture = GetSpecializationInfo(specID) | |
1134 loadedProfiles[BINDING_TYPE_CHARACTER][specID] = kb.InitProfile(loadedProfiles[BINDING_TYPE_CHARACTER][specID], { | |
1135 specID = specID}) | |
1136 | |
1137 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName) | |
1138 loadedProfiles[BINDING_TYPE_SPECIALIZATION] = loadedProfiles[BINDING_TYPE_CHARACTER][specID] | |
1139 configProfile = loadedProfiles[bindMode] | |
1140 print('|cFF00FF00bindMode:|r', bindMode) | |
1141 | |
1142 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]} | |
1143 | |
1144 print('|cFF00FF00current spec:|r', specID, 'of', GetNumSpecializations()) | |
1145 end | |
1146 | |
1147 kb.UpdateTalentInfo = function() | |
1148 if kb.talentsPushed then | |
1149 return | |
1150 end | |
1151 | |
1152 | |
1153 table.wipe(kb.TalentCache) | |
1154 | |
1155 for row =1, MAX_TALENT_TIERS do | |
1156 for col = 1, NUM_TALENT_COLUMNS do | |
1157 local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) | |
1158 local talentInfo = kb.TalentCache[spellID] or {} | |
1159 talentInfo.row = 1 | |
1160 talentInfo.col = col | |
1161 talentInfo.name = talentName | |
1162 talentInfo.talentID = talentID | |
1163 talentInfo.selected = selected | |
1164 talentInfo.available = available | |
1165 talentInfo.spellID = spellID | |
1166 kb.TalentCache[spellID] = talentInfo | |
1167 print('Talent ', row, col, spellID, talentName) | |
1168 end | |
1169 end | |
1170 kb.talentsPushed = true | |
1171 end | |
1172 | |
1173 | |
1174 kb.ProfessionCache = {} | |
1175 kb.UpdateProfessionInfo = function() | |
1176 table.wipe(kb.ProfessionCache) | |
1177 local profs = {GetProfessions() } | |
1178 local primaryNum = 0 | |
1179 for i, index in ipairs(profs) do | |
1180 local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index) | |
1181 cprint(i, index, profName, numSpells, spellOffset) | |
1182 if not professionMappings[index] then | |
1183 primaryNum = primaryNum + 1 | |
1184 end | |
1185 local profNum = professionMappings[index] or primaryNum | |
1186 | |
1187 | |
1188 kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {} | |
1189 | |
1190 for j = 1, numSpells do | |
1191 local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION) | |
1192 | |
1193 local profInfo = { | |
1194 spellName = spellName, | |
1195 spellID = spellID, | |
1196 icon = icon, | |
1197 profOffset = i, | |
1198 profIndex = index, | |
1199 spellOffset = (spellOffset+j), | |
1200 spellNum = j | |
1201 } | |
1202 KeyBinderMacro:SetAttribute("*macrotext-profession_"..i .. '_' ..j, "/cast ".. spellName) | |
1203 | |
1204 kb.ProfessionCache[i .. '_' .. j] = profInfo | |
1205 kb.ProfessionCache[spellName] = profInfo | |
1206 kb.ProfessionCache[spellID] = profInfo | |
1207 cprint(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "*macrotext-profession_"..i .. '_' ..j) | |
1208 end | |
1209 | |
1210 end | |
1211 | |
1212 end | |
1213 | |
1214 --- Obtains profile data or creates the necessary tables | 597 --- Obtains profile data or creates the necessary tables |
1215 kb.SelectProfileSet = function(name) | 598 kb.SelectProfileSet = function(name) |
1216 | 599 |
600 local defaultMode | |
1217 --- General info | 601 --- General info |
1218 classHeader, className, classID = UnitClass('player') | 602 classHeader, className, classID = UnitClass('player') |
1219 print('|cFF00FF00profile:|r', name) | 603 print('|cFF00FF00profile:|r', name) |
1220 print('|cFF00FF00class:|r', UnitClass('player')) | 604 print('|cFF00FF00class:|r', UnitClass('player')) |
1221 | 605 |
1222 --- Global | 606 --- Global |
1223 bindMode = BINDING_TYPE_GLOBAL | 607 defaultMode = BINDING_TYPE_GLOBAL |
1224 kb.InitProfile(db) | 608 kb.InitProfile(db) |
1225 loadedProfiles[BINDING_TYPE_GLOBAL] = db | 609 kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db |
1226 | 610 |
1227 --- Character | 611 --- Character |
1228 if name then | 612 if name then |
1229 db[name] = kb.InitProfile(db[name], | 613 db[name] = kb.InitProfile(db[name], |
1230 {classHeader = classHeader, className = className, classID = classID}) | 614 {classHeader = classHeader, className = className, classID = classID}) |
1231 loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] | 615 kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] |
1232 bindMode = BINDING_TYPE_CHARACTER | 616 defaultMode = BINDING_TYPE_CHARACTER |
1233 end | 617 end |
1234 | 618 |
1235 --- Mutable skills data | 619 --- Mutable skills data |
1236 kb.UpdateSpecInfo() | 620 kb.UpdateSpecInfo() |
1237 kb.UpdateTalentInfo() | 621 kb.UpdateTalentInfo() |
1238 | 622 |
1239 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]} | 623 kb.orderedProfiles = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]} |
1240 if db.bindMode and loadedProfiles[db.bindMode] then | 624 if db.bindMode and (not kb.configTitle[db.bindMode]) then |
1241 bindMode = db.bindMode | 625 print('fixing bad bindMode value, was', db.bindMode) |
1242 end | 626 db.bindMode = defaultMode |
1243 | 627 end |
1244 db.bindMode = bindMode | 628 |
1245 | |
1246 if not BINDING_MODE[bindMode] then | |
1247 bindMode = 3 | |
1248 db.bindMode = 3 | |
1249 print('overriding', bindMode) | |
1250 end | |
1251 | 629 |
1252 print(BINDING_TYPE_GLOBAL) | 630 print(BINDING_TYPE_GLOBAL) |
1253 configHeaders[BINDING_TYPE_GLOBAL] = BINDING_MODE[BINDING_TYPE_GLOBAL] | 631 kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL] |
1254 configHeaders[BINDING_TYPE_CHARACTER] = BINDING_MODE[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) | 632 kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) |
1255 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName) | 633 kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(specName) |
1256 | 634 |
1257 | 635 |
1258 setmetatable(loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return configHeaders[BINDING_TYPE_GLOBAL] end}) | 636 setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end}) |
1259 setmetatable(loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return configHeaders[BINDING_TYPE_CHARACTER] end}) | 637 setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end}) |
1260 setmetatable(loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return configHeaders[BINDING_TYPE_SPECIALIZATION] end}) | 638 setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end}) |
1261 | 639 |
1262 print('|cFF00FF00bindMode:|r', bindMode) | 640 print('|cFF00FF00bindMode:|r', db.bindMode) |
1263 configProfile = loadedProfiles[bindMode] | 641 kb.currentProfile = kb.loadedProfiles[db.bindMode] |
1264 end | 642 end |
1265 | 643 |
1266 local scrollCache = {} | 644 local scrollCache = {} |
1267 kb.SelectTab = function(self) | 645 kb.SelectTab = function(self) |
1268 scrollCache[bindMode] = kb.scrollOffset | 646 scrollCache[db.bindMode] = kb.scrollOffset |
1269 bindMode = self:GetID() | |
1270 configProfile = loadedProfiles[self:GetID()] | |
1271 db.bindMode = self:GetID() | 647 db.bindMode = self:GetID() |
1272 kb.scrollOffset = scrollCache[bindMode] or 0 | 648 kb.currentProfile = kb.loadedProfiles[self:GetID()] |
649 kb.scrollOffset = scrollCache[db.bindMode] or 0 | |
1273 kb.ui(true) | 650 kb.ui(true) |
1274 end | 651 end |
1275 | 652 |
1276 kb.RevertBindings = function() | 653 kb.RevertBindings = function() |
1277 -- todo: reversion code | 654 -- todo: reversion code |
1289 kb:print('Keybinds saved.') | 666 kb:print('Keybinds saved.') |
1290 end | 667 end |
1291 | 668 |
1292 | 669 |
1293 | 670 |
1294 | |
1295 | |
1296 | |
1297 --- push current information into living UI | |
1298 kb.ui = function(force) | |
1299 for i, module in ipairs(kb.modules) do | |
1300 if module.ui then | |
1301 module.ui(force) | |
1302 end | |
1303 end | |
1304 | |
1305 if not db.showUI then | |
1306 print('---end of refresh') | |
1307 return | |
1308 end | |
1309 if not kb.loaded then | |
1310 KeyBinder_Initialize() | |
1311 kb.loaded = true | |
1312 end | |
1313 for i = 1, numButtons do | |
1314 local button = kb.GetSlot(i) | |
1315 button:SetID(i+kb.scrollOffset) | |
1316 kb.UpdateSlot(button, force) | |
1317 end | |
1318 | |
1319 if bindsCommitted then | |
1320 KeyBinderSaveButton:Disable() | |
1321 --KeyBinderRestoreButton:Disable() | |
1322 else | |
1323 KeyBinderSaveButton:Enable() | |
1324 --KeyBinderRestoreButton:Enable() | |
1325 end | |
1326 | |
1327 --- Frame Sizing | |
1328 kb.profilebg:SetHeight(kb.tabSize[2] + BUTTON_PADDING * 2 + kb.profiletext:GetStringHeight()) | |
1329 | |
1330 kb.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING) | |
1331 local numRows = numButtons/BINDS_PER_ROW | |
1332 | |
1333 kb.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING) | |
1334 | |
1335 kb:SetHeight(kb.headerbg:GetHeight() + kb.profilebg:GetHeight() + kb.bg:GetHeight() + kb.footer:GetHeight()) | |
1336 kb:SetWidth((kb.sourcesbg:GetWidth() +(BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) )) | |
1337 | |
1338 kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[bindMode])) | |
1339 for i, tab in ipairs(kb.tabButtons) do | |
1340 local border = tab:GetNormalTexture() | |
1341 local tabTexture = "Interface\\Buttons\\UI-Quickslot2" | |
1342 local left, top, right, bottom = -12, 12, 13, -13 | |
1343 if i == bindMode then | |
1344 tabTexture = "Interface\\Buttons\\CheckButtonGlow" | |
1345 left, top, right, bottom = -14, 14, 15, -15 | |
1346 tab.icon:SetDesaturated(false) | |
1347 if tab.icon2 then tab.icon2:SetDesaturated(false) end | |
1348 border:SetDesaturated(true) | |
1349 border:SetVertexColor(1,1,1, 1) | |
1350 else | |
1351 tab.icon:SetDesaturated(true) | |
1352 if tab.icon2 then tab.icon2:SetDesaturated(true) end | |
1353 border:SetDesaturated(false) | |
1354 border:SetVertexColor(1,1,1) | |
1355 end | |
1356 border:SetTexture(tabTexture) | |
1357 border:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top) | |
1358 border:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom) | |
1359 end | |
1360 | |
1361 KeyBinderSpecTab.icon:SetTexture(specTexture) | |
1362 | |
1363 kb.profiletext:SetText(configHeaders[bindMode]) | |
1364 print(bindMode, configHeaders[bindMode], kb:GetSize()) | |
1365 print(kb:GetPoint(1)) | |
1366 | |
1367 kb:Show() | |
1368 | |
1369 -- Reset this so talent cache can be rebuilt | |
1370 kb.talentsPushed = nil | |
1371 end | |
1372 | 671 |
1373 --- post ADDON_LOADED | 672 --- post ADDON_LOADED |
1374 kb.variables = function() | 673 kb.variables = function() |
1375 SkeletonKeyDB = SkeletonKeyDB or {spec = {}} | 674 SkeletonKeyDB = SkeletonKeyDB or {spec = {}} |
1376 kb.db = SkeletonKeyDB | 675 kb.db = SkeletonKeyDB |
1378 kb.playerRealm = SelectedRealmName() | 677 kb.playerRealm = SelectedRealmName() |
1379 kb.profileName = kb.playerRealm .. '_' .. kb.playerName | 678 kb.profileName = kb.playerRealm .. '_' .. kb.playerName |
1380 db = kb.db | 679 db = kb.db |
1381 | 680 |
1382 kb.SelectProfileSet(kb.profileName) | 681 kb.SelectProfileSet(kb.profileName) |
1383 if not configProfile.imported then | 682 -- todo: redo import checking |
1384 kb.ImportScan() | 683 |
1385 end | 684 |
685 | |
1386 kb.ApplyAllBindings() | 686 kb.ApplyAllBindings() |
1387 | 687 |
1388 kb.ui(true) | 688 kb.ui(true) |
1389 end | 689 end |
1390 | 690 |
1393 kb.modules = kb.modules or {} | 693 kb.modules = kb.modules or {} |
1394 tinsert(kb.modules, module) | 694 tinsert(kb.modules, module) |
1395 end | 695 end |
1396 | 696 |
1397 -- Volatiles Access | 697 -- Volatiles Access |
1398 kb.BindingIsLocked = BindingIsLocked | |
1399 kb.BindingString = BindingString | |
1400 kb.GetBindings = function() return bindings end | 698 kb.GetBindings = function() return bindings end |
1401 kb.GetButtons = function() return buttons end | 699 kb.GetButtons = function() return buttons end |
1402 kb.GetCharacterProfile = function () return loadedProfiles[BINDING_TYPE_CHARACTER] end | 700 kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end |
1403 kb.GetGlobalProfile = function () return loadedProfiles[BINDING_TYPE_GLOBAL] end | 701 kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end |
1404 kb.GetLooseTalents = function() return talentBindings end | 702 kb.GetLooseTalents = function() return talentBindings end |
1405 kb.GetProfileStack = function() return priority end | |
1406 kb.GetReverts = function() return reverts end | 703 kb.GetReverts = function() return reverts end |
1407 kb.GetSpecProfile = function () return loadedProfiles[BINDING_TYPE_SPECIALIZATION] end | 704 kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end |
1408 | 705 |
1409 --- Add to blizzard interfaces | |
1410 StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = { | |
1411 text = "Confirm moving an assigned command.", | |
1412 button1 = OKAY, | |
1413 button2 = CANCEL, | |
1414 timeout = 0, | |
1415 whileDead = 1, | |
1416 showAlert = 1, | |
1417 OnAccept = kb.AcceptAssignment, | |
1418 OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end | |
1419 } | |
1420 | 706 |
1421 SLASH_SKB1 = "/skb" | 707 SLASH_SKB1 = "/skb" |
1422 SLASH_SKB2 = "/skeletonkey" | 708 SLASH_SKB2 = "/skeletonkey" |
1423 SlashCmdList.SKB = kb.Command | 709 SlashCmdList.SKB = kb.Command |
1424 | 710 |