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