comparison KeyButton.lua @ 74:9824d524a661

- binding slot mixin: - store key binding definitions under their slot's data table - apply action button attributes when a slot is assigned - obtain correct macro body text when a macro is slotted - fix algorithm for resolving renamed macro indices - move spell detail lookup code out of mixin script - event chains: - initialize addon from PLAYER_LOGIN - reload keybinds from PLAYER_SPECIALIZATION_CHANGED, after spec profile is resolved - refresh interface content from SPELLS_CHANGED - hotkey text: - restore communication and detection of key binding updates and reflect them accordingly - properly respond to dynamic bindings that result from talent updates
author Nenue
date Sat, 14 Jan 2017 02:29:33 -0500
parents c48913c5924c
children 6623b7f2c1ca
comparison
equal deleted inserted replaced
73:68365bda5ab5 74:9824d524a661
3 -- Created: 7/28/2016 11:26 PM 3 -- Created: 7/28/2016 11:26 PM
4 -- %file-revision% 4 -- %file-revision%
5 -- Deals with display and manipulation of binding slots 5 -- Deals with display and manipulation of binding slots
6 6
7 local _, kb = ... 7 local _, kb = ...
8 local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SkeletonKey', ...) end or function() end 8 local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('KeyButton', ...) end or function() end
9 local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end 9 local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end
10 local L = kb.L 10 local L = kb.L
11 local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs 11 local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs
12 local _G, unpack, select, tostring = _G, unpack, select, tostring 12 local _G, unpack, select, tostring = _G, unpack, select, tostring
13 local GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo = GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo 13 local GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo = GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo
168 ResetCursor() 168 ResetCursor()
169 return 169 return
170 end 170 end
171 171
172 172
173 local name, icon, _ 173 local name, icon, _, macroName, macroText
174 local pickupID, pickupBook 174 local pickupID, pickupBook
175 175
176 if actionType == 'spell' then 176 if actionType == 'spell' then
177 actionID = subData 177 actionID = subData
178 name, _, icon = GetSpellInfo(actionID) 178 name, _, icon = GetSpellInfo(actionID)
179 179
180 elseif actionType == 'macro' then 180 elseif actionType == 'macro' then
181 name, icon = GetMacroInfo(actionID) 181 name, icon, macroText = GetMacroInfo(actionID)
182 macroName = name
182 elseif actionType == 'petaction' then 183 elseif actionType == 'petaction' then
183 if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then 184 if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then
184 185
185 local spellType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) 186 local spellType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
186 local spellName, spellText = GetSpellBookItemName(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) 187 local spellName, spellText = GetSpellBookItemName(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
215 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = GetPetInfoByPetID(actionID) 216 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = GetPetInfoByPetID(actionID)
216 name = customName or petName 217 name = customName or petName
217 icon = petIcon 218 icon = petIcon
218 219
219 end 220 end
220 local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) 221 local _, macroBody, command = kb.RegisterAction(actionType, actionID, name)
221 local slotInfo = { 222 local slotInfo = {
222 command = command, 223 command = command,
223 actionName = name, 224 actionName = name,
224 iconPath = icon, 225 iconPath = icon,
225 actionType = actionType, 226 actionType = actionType,
226 actionID = actionID, 227 actionID = actionID,
227 macroName = macroName, 228 macroName = macroName,
228 macroText = macroText, 229 macroText = macroText or macroBody,
229 spellbookSlot = pickupID, 230 spellbookSlot = pickupID,
230 spellbookType = pickupBook, 231 spellbookType = pickupBook,
231 assignedKeys = {GetBindingKey(command)} 232 assignedKeys = {GetBindingKey(command)}
232 } 233 }
233 234
240 popup.args = {slotInfo} 241 popup.args = {slotInfo}
241 SkeletonKey:SetScript('OnMouseWheel', nil) -- disable scrolling 242 SkeletonKey:SetScript('OnMouseWheel', nil) -- disable scrolling
242 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') 243 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
243 else 244 else
244 kb.currentProfile.buttons[self:GetID()] = slotInfo 245 kb.currentProfile.buttons[self:GetID()] = slotInfo
246 if #slotInfo.assignedKeys >= 1 then
247 kb:print('Obtained following hotkeys:', table.concat(slotInfo.assignedKeys, ', '))
248
249 end
250 kb.LoadBinding(slotInfo)
245 self:SetSlot(slotInfo) 251 self:SetSlot(slotInfo)
246 self:UpdateSlot() 252 self:UpdateSlot()
247 self.active = nil 253 self.active = nil
248 ClearCursor() 254 ClearCursor()
249 ResetCursor() 255 ResetCursor()
310 316
311 local borderType = BORDER_UNASSIGNED 317 local borderType = BORDER_UNASSIGNED
312 318
313 if self.command then 319 if self.command then
314 320
315 print('|cFFFF4400', self.actionName, #self.assignedKeys, self.assignedKeys) 321 print('|cFFFF4400', self.actionName, #self.assignedKeys, table.concat(self.assignedKeys, ','))
316 print(table.concat(self.assignedKeys, ',')) 322 print(self.isAvailable)
317 print(self.actionID) 323 print(self.actionID)
318 self.bindingText= kb.BindingString(unpack(self.assignedKeys)) 324 self.bindingText= kb.BindingString(unpack(self.assignedKeys))
319 if not self.isAvailable then 325 if not self.isAvailable then
320 borderType = BORDER_DYNAMIC 326 borderType = BORDER_DYNAMIC
321 self.ignoreTexture:Show() 327 self.ignoreTexture:Show()
334 if self.actionType == 'macro' then 340 if self.actionType == 'macro' then
335 self.macro:Show() 341 self.macro:Show()
336 else 342 else
337 self.macro:Hide() 343 self.macro:Hide()
338 if self.actionType == 'spell' then 344 if self.actionType == 'spell' then
339 local dummy = GetSpellInfo(self.actionName) 345 self.isAvailable = GetSpellInfo(self.actionName) and true or false
340 if not dummy then
341 self.icon:SetDesaturated(true)
342 else
343 self.icon:SetDesaturated(false)
344 end
345
346 end 346 end
347 end 347 end
348 348
349 349
350 if self.dynamicType == 'profession' then 350 if self.dynamicType == 'profession' then
376 kb.DeactivateSlot(self) 376 kb.DeactivateSlot(self)
377 end 377 end
378 378
379 end 379 end
380 380
381 self.ignoreTexture:SetShown(self.command and not self.isAvailable)
382
383 if not self.isAvailable then 381 if not self.isAvailable then
384 self.bind:SetTextColor(0.7,0.7,0.7,1) 382 self.bind:SetTextColor(.7,.7,.7,1)
383 self.ignoreTexture:SetShown(self.command and true)
384 self.icon:SetVertexColor(.5,.5,.5)
385 else 385 else
386 self.ignoreTexture:SetShown(false)
386 self.bind:SetTextColor(1,1,1,1) 387 self.bind:SetTextColor(1,1,1,1)
388 self.icon:SetVertexColor(1,1,1)
387 end 389 end
388 390
389 391
390 if kb.saveTarget and kb.saveTarget ~= self then 392 if kb.saveTarget and kb.saveTarget ~= self then
391 self:SetAlpha(0.25) 393 self:SetAlpha(0.25)
457 self.icon:SetTexture(nil) 459 self.icon:SetTexture(nil)
458 self.ignoreTexture:Hide() 460 self.ignoreTexture:Hide()
459 461
460 end 462 end
461 463
462 local spells = {} 464 local DoMacroCheck = function(name, macroText, searchID, roughResult)
463 local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon) 465
464 if not spells[spellID] then 466 return matchID, matchName, matchBody, endOfSearch
465 spells[spellID] = {} 467 end
466 spells[spellID].actionType = 'spell'
467 spells[spellID].actionID = spellID
468 spells[spellID].actionName = spellName
469 spells[spellID].iconPath = icon
470 spells[spellID].statusText = '|cFFBBBBBBSpell|r'
471 spells[spellID].dynamicType = nil
472 end
473 return spells[spellID]
474 end
475
476 local tempInfo = {}
477 -- tries to resolve spells from talent overrides/profession book/etc
478 local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'}
479 local SkeletonKey_GetSpellDetails = function(self)
480
481 local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath
482
483
484 print(' In:', spellName, spellID, command)
485 print(GetSpellInfo(spellName or spellID))
486 local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellName or spellID)
487 local isAvailable = internalName and true
488
489 if internalName and (internalName ~= spellName) then
490 -- it's a binding for the originating spell, leave it as is
491 print(' |cFFFF4400spell is an override(', internalName, '~=', spellName,') leave the name info alone')
492 self.statusText = '|cFFFFFF00Spell|r'
493 self.isAvailable = true
494 return
495 end
496
497 -- let's us match spells replaced by talents
498 local info = kb.DynamicSpells[internalName or spellName]
499 if not info then
500 local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)")
501 if kb.DynamicSpells[dynamicType] then
502 print('|cFFFF4400resolving dynamic type index:', internalName, spellName, command)
503 dynamicIndex = tonumber(dynamicIndex)
504 dynamicSubIndex = tonumber(dynamicSubIndex)
505 local cache = kb.DynamicSpells[dynamicType]
506 print('type:', dynamicType)
507 if dynamicIndex and cache[dynamicIndex] then
508 info = kb.DynamicSpells[dynamicType][dynamicIndex]
509 print('index:', dynamicIndex)
510 if dynamicSubIndex and info[dynamicSubIndex] then
511 info = info[dynamicSubIndex]
512 print('sub-index:', dynamicSubIndex)
513 end
514 isAvailable = true
515 end
516 end
517 if not info then
518 info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon)
519 end
520 end
521 info.isAvailable = isAvailable
522
523 print('|cFF00FF88SpellDetails:|r', info.actionName, info.actionID, info.dynamicType, info.isAvailable)
524 for k,v in pairs(info) do
525 --cprint(' ',k,v)
526 self[k] = v
527 end
528
529 return info
530 end
531
532 --- Assigns the slot via table copy; any manipulations from this point are temporary and 468 --- Assigns the slot via table copy; any manipulations from this point are temporary and
533 function skb:SetSlot(slotInfo) 469 function skb:SetSlot(slotInfo)
534 print('slot info', self:GetID()) 470 print('slot info', self:GetID())
535 471
536 for k,v in pairs(slotInfo) do 472 for k,v in pairs(slotInfo) do
547 print('|cFFFFFF00SetSlot|r:', self:GetID()) 483 print('|cFFFFFF00SetSlot|r:', self:GetID())
548 if self.command then 484 if self.command then
549 485
550 isBound = kb.IsCommandBound(self, self.command) 486 isBound = kb.IsCommandBound(self, self.command)
551 if actionType == 'spell' then 487 if actionType == 'spell' then
552 local info = SkeletonKey_GetSpellDetails(self) 488 local info = kb.ResolveSpellSlot(self)
553 name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook = self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType 489 name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook = self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType
554 self.isAvailable = info and info.isAvailable 490 self.isAvailable = info and info.isAvailable
555 elseif actionType == 'petaction' then 491 elseif actionType == 'petaction' then
556 self.dynamicType = 'petaction' 492 self.dynamicType = 'petaction'
557 local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)') 493 local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)')
571 end 507 end
572 self.statusText = 'Pet Action' 508 self.statusText = 'Pet Action'
573 self.isAvailable = (kb.PetCache.spellslot[name]) 509 self.isAvailable = (kb.PetCache.spellslot[name])
574 elseif actionType == 'macro' then 510 elseif actionType == 'macro' then
575 if actionID then 511 if actionID then
576 -- look for corruption 512
513 -- Update stored information if it mis-matches
577 local nameByID, _, bodyByID = GetMacroInfo(actionID) 514 local nameByID, _, bodyByID = GetMacroInfo(actionID)
578 local nameByName, _, bodyByName = GetMacroInfo(name) 515 --print(bodyByID, "\n", macroText)
579 if (nameByID ~= name) or (bodyByID ~= macroText) then 516 if (nameByID ~= name) or (bodyByID ~= macroText) then
580 local prevIndex = actionID 517 --kb:print('mismatches for slot', self:GetID(), actionID, ((nameByID ~= name) and 'name' or ''), ((bodyByID ~= macroText) and 'body' or ''))
581 actionID = GetMacroIndexByName(name) 518 local matchID, matchName, matchBody, hasMultiple
582 local firstName, _, firstBody = GetMacroInfo(actionID) 519 local roughResult = ""
520
521 local newID = GetMacroIndexByName(name)
522 local firstName, _, firstBody = GetMacroInfo(newID)
583 if (firstName ~= name) or (firstBody ~= macroText) then 523 if (firstName ~= name) or (firstBody ~= macroText) then
524
525
584 -- go even deeper 526 -- go even deeper
585 for i = 1, GetNumMacros() do 527 local numAccount, numCharacter = GetNumMacros()
586 local searchName, _ , searchBody = GetMacroInfo(i) 528 local searchID = 1
529 while searchID <= (120+numCharacter) do
530 --kb:print(searchID)
531
532
533 local searchName, _ , searchBody = GetMacroInfo(searchID)
587 if (searchName == name) and (searchBody == macroText) then 534 if (searchName == name) and (searchBody == macroText) then
535 --kb:print('definitely', matchID, searchName, '\n', searchBody)
588 -- complete match 536 -- complete match
589 actionID = i 537 matchID = searchID
590 kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')') 538 matchName = searchName
539 matchBody = searchBody
591 break 540 break
592 elseif (searchName == name) or (searchBody == macroText) then 541 elseif (searchName == name) or (searchBody == macroText) then
593 -- partial match, continue the search 542 -- partial match, continue the search
594 actionID = i 543
595 kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')') 544 if matchID then
545 hasMultiple = true
546 roughResult = roughResult .. "\n" .. tostring(searchID) .. ':'..tostring(searchName)
547 end
548
549 matchID = searchID
550 matchName = searchName
551 matchBody = searchBody
552 --kb:print('possibly', matchID, matchName, '\n', matchBody)
596 end 553 end
554
555 if searchID == numAccount then
556 searchID = 120
557 end
558 searchID = searchID + 1
597 end 559 end
560 else
561 matchID = newID
562 matchName = firstName
563 matchBody = firstBody
598 end 564 end
599 565
566 --kb:print(matchID, hasMultiple)
567 if hasMultiple then
568 kb:print('Macro assignment in slot #'..tostring(self:GetID())..' has multiple possible indexes:\nSaved Info: '..tostring(actionID)..'/'..tostring(name)..'\n|cFFFFFF00', roughResult)
569 elseif matchID then
570 kb:print('Macro for slot #'..tostring(self:GetID())..' ('..tostring(name)..') has probably changed:', ((actionID ~= newID) and (' |cFFFF4400'..tostring(actionID)..'|r to |cFF00FF88' .. newID .. '|r.') or ''), 'We\'re not sure, so you may want to re-do that assignment.')
571 actionID = matchID
572 name = matchName
573 macroName = matchName
574 macroText = matchBody
575 end
600 end 576 end
601 else 577 else
602 actionID = GetMacroIndexByName(name) 578 actionID = GetMacroIndexByName(name)
603 end 579 end
604 self.statusText = 'Macro' 580 self.statusText = 'Macro ' .. tostring(actionID)
605 self.isAvailable = true 581 self.isAvailable = true
606 else 582 else
607 if not actionID then 583 if not actionID then
608 actionID = command:match("^KeyBinderMacro:(.+)") 584 actionID = command:match("^KeyBinderMacro:(.+)")
609 end 585 end
690 self.actionName = name 666 self.actionName = name
691 self.command = command 667 self.command = command
692 self.iconPath = icon 668 self.iconPath = icon
693 self.profile = kb.db.bindMode 669 self.profile = kb.db.bindMode
694 self:RegisterForDrag('LeftButton') 670 self:RegisterForDrag('LeftButton')
671
672 return slotInfo
695 end 673 end
696 674
697 kb.GetCommandAction = function(command) 675 kb.GetCommandAction = function(command)
698 for i, data in ipairs(kb.loadedProfiles) do 676 for i, data in ipairs(kb.loadedProfiles) do
699 if data.commands[command] then 677 if data.commands[command] then