comparison SkeletonKey/KeyButton.lua @ 27:73df13211b22

- actionbar hotkey text properly updates after hotkeys get switched - remove a unused function call
author Nenue
date Tue, 02 Aug 2016 12:33:13 -0400
parents SkeletonKey/KeySlot.lua@f6dd297cb812
children bb160c04de88
comparison
equal deleted inserted replaced
26:c081f117c19d 27:73df13211b22
1 -- SkeletonKey
2 -- KeyButton.lua
3 -- Created: 7/28/2016 11:26 PM
4 -- %file-revision%
5 -- Code dealing with the slot button innards; they are invoked by frame script and should only chain to Set/Release
6
7 local kb, print = LibStub('LibKraken').register(KeyBinder, 'Slot')
8 local L = kb.L
9 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION, CURSOR_TEXTURE
10 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
11 local BORDER_UNASSIGNED = {0.2,0.2,0.2,1}
12 local BORDER_ASSIGNED = {1,1,1,1}
13 local BORDER_DYNAMIC = {1,1,0,1}
14 local BORDER_PENDING = {1,0.5,0,1 }
15 local BUTTON_HEADERS = {
16 ['spell'] = SPELLS,
17 ['macro'] = MACRO,
18 ['petaction'] = PET,
19 ['mount'] = MOUNT,
20 ['battlepet'] = BATTLEPET,
21
22
23 [5] = PROFESSIONS_FIRST_AID,
24 [7] = PROFESSIONS_COOKING,
25 [9] = PROFESSIONS_FISHING,
26 [10] = PROFESSIONS_ARCHAEOLOGY,
27
28 }
29
30 -- This is needed to identify a spells that aren't reflected by GetCursorInfo()
31 kb.OnPickupPetAction = function(slot, ...)
32 local isPickup = GetCursorInfo()
33 print(slot, ...)
34 if kb.PetCache.action[slot] then
35 if isPickup then
36 local key, _, texture = unpack(kb.PetCache.action[slot])
37 local spellName = _G[key] or key
38 if spellName and kb.PetCache.spellslot[spellName] then
39 CURSOR_SPELLSLOT = kb.PetCache.spellslot[spellName][1]
40 CURSOR_BOOKTYPE = BOOKTYPE_PET
41 CURSOR_TEXTURE = _G[texture] or texture
42 end
43 else
44 CURSOR_SPELLSLOT = nil
45 CURSOR_BOOKTYPE = nil
46 CURSOR_TEXTURE = nil
47 end
48 print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION)
49 end
50
51 local name, subtext, texture, isToken = GetPetActionInfo(slot)
52 if name then
53 kb.PetCache.action[slot] = {name, subtext, texture, isToken}
54 end
55
56
57 print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE)
58
59 end
60
61 kb.OnPickupSpellBookItem = function(slot, bookType)
62 print('|cFFFF4400PickupSpellBookItem('.. tostring(slot).. ', '..tostring(bookType)..')')
63 CURSOR_SPELLSLOT = slot
64 CURSOR_BOOKTYPE = bookType
65 CURSOR_TEXTURE = GetSpellBookItemTexture(slot, bookType)
66 print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE)
67 end
68
69 kb.CreateHooks = function()
70 hooksecurefunc("PickupSpellBookItem", kb.OnPickupSpellBookItem)
71 hooksecurefunc("PickupPetAction", kb.OnPickupPetAction)
72 end
73
74
75 kb.DropToSlot = function(self)
76 print(self:GetName(),'|cFF0088FFreceived|r')
77 local actionType, actionID, subType, subData = GetCursorInfo()
78 print('GetCursorInfo', GetCursorInfo())
79 if actionType then
80
81 if actionType == 'flyout' then
82 ClearCursor()
83 ResetCursor()
84 return
85 end
86
87
88 local name, icon, _
89 local pickupID, pickupBook
90
91 if actionType == 'spell' then
92 actionID = subData
93 name, _, icon = GetSpellInfo(actionID)
94
95 elseif actionType == 'macro' then
96 name, icon = GetMacroInfo(actionID)
97 elseif actionType == 'petaction' then
98 if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then
99
100 local spellType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
101 local spellName, spellText = GetSpellBookItemName(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
102 if spellType == 'PETACTION' then
103 name = spellName
104 actionID = spellText
105 icon = CURSOR_TEXTURE
106 else
107 name, _, icon = GetSpellInfo(spellID)
108 actionID = spellID
109 end
110
111 pickupID = CURSOR_SPELLSLOT
112 pickupBook = CURSOR_BOOKTYPE
113 else
114
115 end
116
117 elseif actionType == 'mount' then
118 if subType == 0 then
119 name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL)
120 actionID = 0
121 else
122 name, _, icon = C_MountJournal.GetMountInfoByID(actionID)
123 end
124 elseif actionType == 'item' then
125 name = GetItemInfo(actionID)
126 icon = GetItemIcon(actionID)
127 actionID = name
128 elseif actionType == 'battlepet' then
129
130 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail);
131 name = customName or petName
132 icon = petIcon
133
134 end
135 local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name)
136
137
138 local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command)
139 if isAssigned then
140 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
141 popup.slot = self
142 popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?"
143 popup.oldProfile = assignedBy
144 popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook }
145 kb:SetScript('OnMouseWheel', nil) -- disable scrolling
146 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
147 else
148 kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook)
149 kb.UpdateSlot(self)
150 self.active = nil
151 ClearCursor()
152 ResetCursor()
153 end
154 end
155 end
156
157
158 do
159 local PickupAction = {
160 spell = _G.PickupSpell,
161 petaction = _G.PickupSpellBookItem,
162 macro = _G.PickupMacro,
163 item = _G.PickupItem,
164 mount = _G.C_MountJournal.Pickup
165 }
166 local GetPickupValue = {
167 spell = function(self) return select(7, GetSpellInfo(self.actionID)) end,
168 petaction = function(self) return self.pickupSlot, self.pickupBook end,
169 }
170 kb.PickupSlot = function(self)
171 if not (self.command and self.isAvailable) then
172 return
173 end
174 print(self.actionType)
175 if self.actionType == 'spell' then
176 -- It can't be picked up if SpellInfo(name) returns void
177 local dummy = GetSpellInfo(self.actionName)
178 if not dummy then
179 return
180 end
181 end
182 if PickupAction[self.actionType] then
183 if GetPickupValue[self.actionType] then
184 PickupAction[self.actionType](GetPickupValue[self.actionType](self))
185 else
186 PickupAction[self.actionType](self.actionID)
187 end
188 kb.ReleaseSlot(self)
189 kb.UpdateSlot(self)
190 end
191 end
192 end
193
194 kb.UnbindSlot = function(self)
195
196 local keys = {GetBindingKey(self.command) }
197 if #keys >= 1 then
198 kb.UpdateBindingsCache(self.actionType, self.actionID, {})
199 end
200
201
202 --print('detected', #keys, 'bindings')
203 for i, key in pairs(keys) do
204 --print('clearing', key)
205 SetBinding(key, nil)
206 SaveBindings(GetCurrentBindingSet())
207 if kb.currentProfile.bindings[key] then
208 --kb:print(L('BINDING_REMOVED', self.actionName, kb.currentHeader))
209 kb.currentProfile.bindings[key] = nil
210 end
211 if kb.currentProfile.talents[self.actionName] then
212 kb.currentProfile.talents[self.actionName] = nil
213 end
214 kb.bindings[self.actionType][self.actionID] = nil
215 end
216 if kb.currentProfile.bound[self.command] then
217 kb.currentProfile.bound[self.command] = nil
218 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode]))
219 end
220
221
222 self.active = false
223 kb.UpdateSlot(self, true)
224 end
225
226 --- Updates the current KeyBinding for the button's command
227 kb.SaveSlot = function(self, key)
228
229 if not self.command then
230 return
231 end
232 print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
233
234 local modifier = ''
235 if IsAltKeyDown() then
236 modifier = 'ALT-'
237 end
238 if IsControlKeyDown() then
239 modifier = modifier.. 'CTRL-'
240 end
241 if IsShiftKeyDown() then
242 modifier = modifier..'SHIFT-'
243 end
244 local binding = modifier..key
245
246 if key == 'ESCAPE' then
247 else
248 if kb.SystemBindings[binding] then
249 kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', binding, kb.SystemBindings[binding]))
250 return
251 end
252
253
254 if self.command then
255
256 local previousCommand = GetBindingAction(binding)
257 if previousCommand ~= "" and previousCommand ~= self.command then
258 if kb.SystemBindings[binding] then
259 -- bounce out if trying to use a protected key
260 kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, GetBindingAction(binding)))
261 kb.bindingstext:SetText(nil)
262 return false
263 end
264
265 local actionType, actionID, name = kb.GetCommandAction(previousCommand)
266 if actionType then
267 local keys = {GetBindingKey(previousCommand) }
268 local i = 1
269 while keys[i] do
270 if keys[i] == binding then
271 table.remove(keys, i)
272 kb.UpdateBindingsCache(actionType, actionID, keys)
273 break
274 end
275 i = i + 1
276 end
277 end
278 end
279
280 local currentHotKeys = {GetBindingKey(self.command)}
281 local found
282 for i, key in ipairs(currentHotKeys) do
283 if key == binding then
284 found = true
285 kb:print('hotkey already assigned')
286 end
287 end
288 if not found then
289 table.insert(currentHotKeys, 1, binding)
290 kb.UpdateBindingsCache(self.actionType, self.actionID, currentHotKeys)
291 end
292
293 self.binding = binding
294
295
296
297 SetBinding(binding, self.command)
298 SaveBindings(GetCurrentBindingSet())
299
300
301
302 local talentInfo
303 if self.actionType == 'spell' and kb.TalentCache[self.actionID] then
304 print('conditional binding (talent = "'..self.actionName..'")')
305 talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID}
306 local bindings = {GetBindingKey(self.command) }
307 for i, key in ipairs(bindings) do
308 tinsert(talentInfo, key)
309 end
310 end
311
312 for level, profile in ipairs(kb.orderedProfiles) do
313 if (level == kb.db.bindMode) then
314 profile.bound[self.command] = true
315 if talentInfo then
316 profile.bindings[self.binding] = nil
317 else
318 profile.bindings[self.binding] = self.command
319 end
320 profile.talents[self.actionName] = talentInfo
321 else
322 profile.bindings[self.binding] = nil
323 profile.bound[self.command] = nil
324 kb.currentProfile.talents[self.actionName] = nil
325 end
326 if kb.currentProfile.talents[self.actionID] then
327 kb.currentProfile.talents[self.actionID] = nil
328 end
329 end
330
331 kb:print(L('BINDING_ASSIGNED', self.binding, self.actionName, kb.currentHeader))
332 end
333 end
334 kb.UpdateSlot(self, true)
335 return true
336 end
337
338
339 --- Updates profile assignment and button contents
340 kb.UpdateSlot = function(self, force)
341 local slot = self:GetID()
342
343 if force then
344 if kb.currentProfile.buttons[slot] then
345 kb.SetSlot(self, unpack(kb.currentProfile.buttons[slot]))
346 else
347 kb.ReleaseSlot(self)
348 end
349 end
350
351 if self.command then
352 print('['..slot..'] =', self.command, GetBindingKey(self.command))
353
354 if not self.isAvailable then
355 self.border:SetColorTexture(1,0,0,1)
356 self.ignoreTexture:Show()
357 else
358 self.ignoreTexture:Hide()
359
360 if self.pending then
361 self.border:SetColorTexture(unpack(BORDER_PENDING))
362 elseif self.isDynamic then
363 self.border:SetColorTexture(unpack(BORDER_DYNAMIC))
364 else
365 self.border:SetColorTexture(unpack(BORDER_ASSIGNED))
366 end
367 end
368
369
370 if self.actionType == 'macro' then
371 self.macro:Show()
372 else
373 self.macro:Hide()
374 if self.actionType == 'spell' then
375 local dummy = GetSpellInfo(self.actionName)
376 if not dummy then
377 self.icon:SetDesaturated(true)
378 else
379 self.icon:SetDesaturated(false)
380 end
381
382 end
383 end
384
385 if self.isDynamic then
386 print('|cFF00BBFFUpdateSlot|r:', self.isDynamic, self.isAvailable, self.actionID)
387 end
388
389 if self.isDynamic == 'profession' then
390 local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex))
391 if self.isAvailable then
392 print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1))
393
394 self.statusText = '|cFFFFFF00'..profText..'|r'
395 self.bindingText = kb.BindingString(GetBindingKey(self.command))
396 else
397 self.statusText = '|cFFFF4400'..profText..'|r'
398 self.actionName = '(need to train profession #'..self.profNum..')'
399 self.bindingText ='?'
400 end
401 elseif self.isDynamic == 'talent' then
402
403 self.statusText = '|cFF00FFFF'.. TALENT .. '|r'
404 if self.isAvailable then
405 self.bindingText = kb.BindingString(GetBindingKey(self.command))
406 else
407 if kb.TalentBindings[self.actionID] then
408 print(self.actionID, #kb.TalentBindings[self.actionID])
409 self.bindingText= kb.BindingString(unpack(kb.TalentBindings[self.actionID]))
410 end
411
412 end
413 elseif self.isDynamic == 'petaction' then
414 local specialType, specialNum = self.command:match("petaction_([%a%s]+)_(%d)")
415 if specialType and specialNum then
416 print('pet skill|cFF00FF00', specialType..'|r', specialNum)
417 self.statusText = L(specialType..' %%d'):format(specialNum)
418 else
419 self.statusText = L('Pet Action')
420 end
421 self.bindingText = kb.BindingString(GetBindingKey(self.command))
422 else
423 self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r'
424 self.bindingText = kb.BindingString(GetBindingKey(self.command))
425 end
426
427 local locked, layer = kb.IsCommandBound(self)
428 if locked then
429 self.icon:SetAlpha(0.5)
430 else
431 self.icon:SetAlpha(1)
432 end
433
434
435 if self.actionType == 'spell' then
436 self.icon:SetTexture(GetSpellTexture(self.actionID))
437 end
438 else
439 self.ignoreTexture:Hide()
440 end
441
442 if not self.isAvailable then
443 self.bind:SetTextColor(0.7,0.7,0.7,1)
444 else
445 self.bind:SetTextColor(1,1,1,1)
446 end
447
448
449 if kb.saveTarget and kb.saveTarget ~= self then
450 self:SetAlpha(0.25)
451 else
452
453 self:SetAlpha(1)
454 end
455
456
457 self.header:SetText(self.statusText)
458 self.bind:SetText(self.bindingText)
459 self.details:SetText(self.actionName)
460 end
461
462 --- Resets button command
463 kb.ReleaseSlot = function(self)
464 local slot = self:GetID()
465
466
467 if kb.currentProfile.buttons[slot] then
468 kb.currentProfile.buttons[slot] = nil
469 end
470 if self.command then
471 kb.currentProfile.commands[self.command] = nil
472 end
473 if self.actionType == 'spell' and IsTalentSpell(self.actionName) then
474 if kb.currentProfile.talents[self.actionID] then
475 kb.currentProfile.talents[self.actionID] = nil
476 end
477 end
478 local droppedKeys = {}
479
480 -- doing removal in second loop to avoid possible iterator shenanigans
481 for k,v in pairs(kb.currentProfile.bindings) do
482 if v == self.command then
483 tinsert(droppedKeys, k)
484 end
485 end
486 if #droppedKeys >=1 then
487 for i, k in ipairs(droppedKeys) do
488 kb.currentProfile.bindings[k] = nil
489 end
490 end
491
492 self.isAvailable = nil
493 self.isDynamic = nil
494 self.bindingText = nil
495 self.statusText = nil
496 self.command = nil
497 self.actionType = nil
498 self.actionID = nil
499 self.actionName = nil
500 self.pickupSlot = nil
501 self.pickupBook = nil
502 self.macroName = nil
503 self.profile = nil
504 self.icon:SetTexture(nil)
505 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED))
506 self:EnableKeyboard(false)
507 self:SetScript('OnKeyDown', nil)
508 self.ignoreTexture:Hide()
509 end
510
511 kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook)
512 local slot = self:GetID()
513 local isDynamic, isAvailable
514
515 print('|cFFFFFF00SetSlot|r:', self:GetID())
516 if command then
517
518 if actionType == 'spell' then
519 local professionNum, spellNum = command:match("profession_(%d)_(%d)")
520 if (professionNum and spellNum) then
521 isDynamic = 'profession'
522 local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum]
523 if cacheInfo then
524 isAvailable = true
525 name = cacheInfo.spellName
526 icon = cacheInfo.icon
527 actionID = cacheInfo.spellID
528 self.profIndex = cacheInfo.profIndex
529 self.spellOffset = cacheInfo.spellOffset
530 end
531 print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable)
532
533 self.professionNum = tonumber(professionNum)
534 self.spellNum = tonumber(spellNum)
535
536 else
537 if kb.TalentCache[actionID] then
538 isDynamic = 'talent'
539 print(' Special slot: |cFFBBFF00talent|r', name, isAvailable)
540 end
541
542 isAvailable = GetSpellInfo(name)
543 end
544 elseif actionType == 'petaction' then
545 isDynamic = 'petaction'
546 local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)')
547
548 if kb.PetCache.subtext[specialType] and kb.PetCache.subtext[specialType][tonumber(specialNum)] then
549 print('***dynamic pet thign', specialType, specialNum)
550 --[[ i, spellName, subText, spellID, texture, specialNum[subText ]]
551 pickupSlot, name, specialType, actionID, icon, specialNum = unpack(kb.PetCache.subtext[specialType][tonumber(specialNum)])
552 pickupBook = BOOKTYPE_PET
553 end
554
555 isAvailable = (kb.PetCache.spellslot[name])
556
557
558 elseif actionType == 'macro' then
559 if not actionID then
560 actionID = GetMacroIndexByName(name)
561 end
562 isAvailable = true
563 else
564 --- Journal selections
565 -- todo: consider using the deep end of blizzard action bar instead
566 if not actionID then
567 actionID = command:match("^KeyBinderMacro:(.+)")
568 end
569 isAvailable = true
570 end
571
572 if isAvailable then
573 local oldCommand = command
574 macroName, macroText, command = kb.RegisterAction(actionType, actionID, name)
575 if oldCommand ~= command then
576 print('|cFFFF4400fixing command string', actionType, actionID, name)
577 kb.currentProfile.bound[oldCommand] = nil
578 kb.currentProfile.bound[command] = slot
579 for k,v in pairs(kb.currentProfile.bindings) do
580 if v == oldCommand then
581 kb.currentProfile.bindings[k] = command
582 end
583 end
584 end
585 kb.LoadBinding(command, name, icon, actionType, actionID, macroName, macroText)
586 end
587
588
589 actionID = actionID or 0
590 self:EnableKeyboard(true)
591 print(' |cFF00FF00kb.currentProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name.. '"|r |cFFFFFF00icon:'.. tostring(icon) .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r')
592 kb.currentProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook }
593
594
595 -- Clean up conflicting entries for loaded button
596 local previous = kb.currentProfile.commands[command]
597 if previous ~= slot and kb.buttons[previous] then
598 kb.ReleaseSlot(kb.buttons[previous])
599 end
600
601 if not (kb.IsCommandBound(self, command) or kb.currentProfile.bound[command]) then
602
603 local binds = {GetBindingKey(command) }
604 if #binds >= 1 then
605 kb:print('Recovered key binding for', name)
606 for i, key in ipairs(binds) do
607 kb.currentProfile.bindings[key] = command
608 kb.currentProfile.bound[command] = true
609 end
610 end
611 end
612
613
614 kb.currentProfile.commands[command] = slot
615
616 end
617
618 self.isAvailable = isAvailable
619 self.isDynamic = isDynamic
620
621 self.pickupSlot = pickupSlot
622 self.pickupBook = pickupBook
623 self.macroText = macroText
624 self.macroName = macroName
625 self.actionType = actionType
626 self.actionID = actionID
627 self.actionName = name
628 self.command = command
629 self.icon:SetTexture(icon)
630 self.profile = kb.db.bindMode
631 self:RegisterForDrag('LeftButton')
632 end
633
634 kb.GetCommandAction = function(command)
635 for i, data in ipairs(kb.loadedProfiles) do
636 if data.commands[command] then
637 if data.buttons[data.commands[command]] then
638 local _, _, _, actionType, actionID = unpack(data.buttons[data.commands[command]])
639 return actionType, actionID
640 end
641 end
642 end
643 end
644
645
646 --- Add to blizzard interfaces
647 StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = {
648 text = "Confirm moving an assigned command.",
649 button1 = OKAY,
650 button2 = CANCEL,
651 timeout = 0,
652 whileDead = 1,
653 showAlert = 1,
654 OnAccept = kb.AcceptAssignment,
655 OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end
656 }