annotate KeyButton.lua @ 71:ca3118127e5e

- Talent change detection - Use stored assignments for inactive talent slots
author Nenue
date Fri, 06 Jan 2017 16:21:49 -0500
parents 131d9190db6b
children c48913c5924c
rev   line source
Nenue@70 1 -- SkeletonKey
Nenue@70 2 -- KeyButton.lua
Nenue@70 3 -- Created: 7/28/2016 11:26 PM
Nenue@70 4 -- %file-revision%
Nenue@70 5 -- Deals with display and manipulation of binding slots
Nenue@70 6
Nenue@70 7 local _, kb = ...
Nenue@70 8 local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SkeletonKey', ...) end or function() end
Nenue@70 9 local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end
Nenue@70 10 local L = kb.L
Nenue@70 11 local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs
Nenue@70 12 local _G, unpack, select, tostring = _G, unpack, select, tostring
Nenue@70 13 local GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo = GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo
Nenue@70 14 local GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon = GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon
Nenue@70 15 local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor
Nenue@70 16 local GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown, IsShiftKeyDown = GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown,IsShiftKeyDown
Nenue@70 17 local GetBindingKey, GetProfessionInfo = GetBindingKey, GetProfessionInfo
Nenue@70 18 local GetMountInfoByID, GetPetInfoByPetID = C_MountJournal.GetMountInfoByID, C_PetJournal.GetPetInfoByPetID
Nenue@70 19 local skb = SkeletonKeyButtonMixin
Nenue@70 20 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION, CURSOR_TEXTURE
Nenue@70 21 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
Nenue@70 22 local BORDER_UNASSIGNED = {0.6,0.6,0.6,1}
Nenue@70 23 local BORDER_ASSIGNED = {1,1,1,1}
Nenue@70 24 local BORDER_DYNAMIC = {1,1,0,1}
Nenue@70 25 local BORDER_PENDING = {1,0.5,0,1 }
Nenue@70 26 local BUTTON_HEADERS = {
Nenue@70 27 ['spell'] = SPELLS,
Nenue@70 28 ['macro'] = MACRO,
Nenue@70 29 ['petaction'] = PET,
Nenue@70 30 ['mount'] = MOUNT,
Nenue@70 31 ['battlepet'] = BATTLEPET,
Nenue@70 32
Nenue@70 33
Nenue@70 34 [5] = PROFESSIONS_FIRST_AID,
Nenue@70 35 [7] = PROFESSIONS_COOKING,
Nenue@70 36 [9] = PROFESSIONS_FISHING,
Nenue@70 37 [10] = PROFESSIONS_ARCHAEOLOGY,
Nenue@70 38
Nenue@70 39 }
Nenue@70 40
Nenue@70 41 local PROFESSION_HEADERS = {
Nenue@70 42 [1] = 'Profession 1',
Nenue@70 43 [2] = 'Profession 2',
Nenue@70 44 [3] = 10,
Nenue@70 45 [4] = 7,
Nenue@70 46 [5] = 9,
Nenue@70 47 [6] = 5
Nenue@70 48 }
Nenue@70 49
Nenue@70 50
Nenue@70 51 -- This is needed to identify a spells that aren't reflected by GetCursorInfo()
Nenue@70 52 kb.OnPickupPetAction = function(slot, ...)
Nenue@70 53 local isPickup = GetCursorInfo()
Nenue@70 54 print(slot, ...)
Nenue@70 55 if kb.PetCache.action[slot] then
Nenue@70 56 if isPickup then
Nenue@70 57 local key, _, texture = unpack(kb.PetCache.action[slot])
Nenue@70 58 local spellName = _G[key] or key
Nenue@70 59 if spellName and kb.PetCache.spellslot[spellName] then
Nenue@70 60 CURSOR_SPELLSLOT = kb.PetCache.spellslot[spellName][1]
Nenue@70 61 CURSOR_BOOKTYPE = BOOKTYPE_PET
Nenue@70 62 CURSOR_TEXTURE = _G[texture] or texture
Nenue@70 63 end
Nenue@70 64 else
Nenue@70 65 CURSOR_SPELLSLOT = nil
Nenue@70 66 CURSOR_BOOKTYPE = nil
Nenue@70 67 CURSOR_TEXTURE = nil
Nenue@70 68 end
Nenue@70 69 print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION)
Nenue@70 70 end
Nenue@70 71
Nenue@70 72 local name, subtext, texture, isToken = GetPetActionInfo(slot)
Nenue@70 73 if name then
Nenue@70 74 kb.PetCache.action[slot] = {name, subtext, texture, isToken}
Nenue@70 75 end
Nenue@70 76
Nenue@70 77
Nenue@70 78 print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE)
Nenue@70 79
Nenue@70 80 end
Nenue@70 81
Nenue@70 82 kb.OnPickupSpellBookItem = function(slot, bookType)
Nenue@70 83 print('|cFFFF4400PickupSpellBookItem('.. tostring(slot).. ', '..tostring(bookType)..')')
Nenue@70 84 CURSOR_SPELLSLOT = slot
Nenue@70 85 CURSOR_BOOKTYPE = bookType
Nenue@70 86 CURSOR_TEXTURE = GetSpellBookItemTexture(slot, bookType)
Nenue@70 87 print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE)
Nenue@70 88 end
Nenue@70 89
Nenue@70 90 kb.CreateHooks = function()
Nenue@70 91 hooksecurefunc("PickupSpellBookItem", kb.OnPickupSpellBookItem)
Nenue@70 92 hooksecurefunc("PickupPetAction", kb.OnPickupPetAction)
Nenue@70 93 end
Nenue@70 94
Nenue@70 95
Nenue@70 96
Nenue@70 97 function skb:OnLoad()
Nenue@70 98 self:EnableKeyboard(false)
Nenue@70 99 self:EnableMouse(true)
Nenue@70 100 self:RegisterForDrag('LeftButton')
Nenue@70 101 self:RegisterForClicks('AnyUp')
Nenue@70 102 end
Nenue@70 103
Nenue@70 104 function skb:OnEnter()
Nenue@70 105 if not self.command then
Nenue@70 106 return
Nenue@70 107 end
Nenue@70 108 if self.statusText then
Nenue@70 109 SkeletonKey.statustext:SetText(self.statusText .. ': '..self.actionName)
Nenue@70 110 SkeletonKey.bindingstext:SetText(self.bindingText)
Nenue@70 111 end
Nenue@70 112
Nenue@70 113
Nenue@70 114 if kb.db.hoverInput and kb.saveTarget ~= self then
Nenue@70 115 self:GetParent():ActivateSlot(self)
Nenue@70 116 SkeletonKey:Update()
Nenue@70 117 end
Nenue@70 118 end
Nenue@70 119
Nenue@70 120 function skb:OnLeave()
Nenue@70 121 if kb.db.hoverInput and kb.saveTarget == self then
Nenue@70 122 self:GetParent():DeactivateSlot(self)
Nenue@70 123 SkeletonKey:Update()
Nenue@70 124 end
Nenue@70 125 end
Nenue@70 126
Nenue@70 127 function skb:OnUpdate()
Nenue@70 128 end
Nenue@70 129 function skb:OnClick(click)
Nenue@70 130 print(self:GetName(), 'OnMouseDown', click)
Nenue@70 131 local cursorType = GetCursorInfo()
Nenue@70 132 if click == 'LeftButton' then
Nenue@70 133 if cursorType then
Nenue@70 134 self:DropToSlot()
Nenue@70 135 else
Nenue@70 136 if self.command and self.isAvailable then
Nenue@70 137 if IsShiftKeyDown() then
Nenue@70 138 kb.db.stickyMode = true
Nenue@70 139 KeyBinderStickyMode:SetChecked(true)
Nenue@70 140 end
Nenue@70 141 self:GetParent():ActivateSlot(self)
Nenue@70 142 end
Nenue@70 143 end
Nenue@70 144 elseif click == 'RightButton' then
Nenue@70 145 self:ReleaseSlot()
Nenue@70 146 else
Nenue@70 147 kb.ProcessInput(strupper(click))
Nenue@70 148 end
Nenue@70 149 SkeletonKey:Update()
Nenue@70 150 end
Nenue@70 151
Nenue@70 152 function skb:OnDragStart()
Nenue@70 153 self:PickupSlot()
Nenue@70 154 end
Nenue@70 155
Nenue@70 156 function skb:OnReceiveDrag(...)
Nenue@70 157 self:DropToSlot()
Nenue@70 158 end
Nenue@70 159
Nenue@70 160 function skb:DropToSlot ()
Nenue@70 161 print(self:GetName(),'|cFF0088FFreceived|r')
Nenue@70 162 local actionType, actionID, subType, subData = GetCursorInfo()
Nenue@70 163 print('GetCursorInfo', GetCursorInfo())
Nenue@70 164 if actionType then
Nenue@70 165
Nenue@70 166 if actionType == 'flyout' then
Nenue@70 167 ClearCursor()
Nenue@70 168 ResetCursor()
Nenue@70 169 return
Nenue@70 170 end
Nenue@70 171
Nenue@70 172
Nenue@70 173 local name, icon, _
Nenue@70 174 local pickupID, pickupBook
Nenue@70 175
Nenue@70 176 if actionType == 'spell' then
Nenue@70 177 actionID = subData
Nenue@70 178 name, _, icon = GetSpellInfo(actionID)
Nenue@70 179
Nenue@70 180 elseif actionType == 'macro' then
Nenue@70 181 name, icon = GetMacroInfo(actionID)
Nenue@70 182 elseif actionType == 'petaction' then
Nenue@70 183 if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then
Nenue@70 184
Nenue@70 185 local spellType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
Nenue@70 186 local spellName, spellText = GetSpellBookItemName(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
Nenue@70 187 if spellType == 'PETACTION' then
Nenue@70 188 name = spellName
Nenue@70 189 actionID = spellText
Nenue@70 190 icon = CURSOR_TEXTURE
Nenue@70 191 else
Nenue@70 192 name, _, icon = GetSpellInfo(spellID)
Nenue@70 193 actionID = spellID
Nenue@70 194 end
Nenue@70 195
Nenue@70 196 pickupID = CURSOR_SPELLSLOT
Nenue@70 197 pickupBook = CURSOR_BOOKTYPE
Nenue@70 198 else
Nenue@70 199
Nenue@70 200
Nenue@70 201 end
Nenue@70 202
Nenue@70 203 elseif actionType == 'mount' then
Nenue@70 204 if subType == 0 then
Nenue@70 205 name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL)
Nenue@70 206 actionID = 0
Nenue@70 207 else
Nenue@70 208 name, _, icon = GetMountInfoByID(actionID)
Nenue@70 209 end
Nenue@70 210 elseif actionType == 'item' then
Nenue@70 211 name = GetItemInfo(actionID)
Nenue@70 212 icon = GetItemIcon(actionID)
Nenue@70 213 elseif actionType == 'battlepet' then
Nenue@70 214
Nenue@70 215 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = GetPetInfoByPetID(actionID)
Nenue@70 216 name = customName or petName
Nenue@70 217 icon = petIcon
Nenue@70 218
Nenue@70 219 end
Nenue@70 220 local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name)
Nenue@70 221 local slotInfo = {
Nenue@70 222 command = command,
Nenue@70 223 actionName = name,
Nenue@70 224 iconPath = icon,
Nenue@70 225 actionType = actionType,
Nenue@70 226 actionID = actionID,
Nenue@70 227 macroName = macroName,
Nenue@70 228 macroText = macroText,
Nenue@70 229 spellbookSlot = pickupID,
Nenue@70 230 spellbookType = pickupBook,
Nenue@70 231 assignedKeys = {GetBindingKey(command)}
Nenue@70 232 }
Nenue@70 233
Nenue@70 234 local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command)
Nenue@70 235 if isAssigned then
Nenue@70 236 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
Nenue@70 237 popup.slot = self
Nenue@70 238 popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?"
Nenue@70 239 popup.oldProfile = assignedBy
Nenue@70 240 popup.args = {slotInfo}
Nenue@70 241 SkeletonKey:SetScript('OnMouseWheel', nil) -- disable scrolling
Nenue@70 242 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
Nenue@70 243 else
Nenue@70 244 kb.currentProfile.buttons[self:GetID()] = slotInfo
Nenue@70 245 self:SetSlot(slotInfo)
Nenue@70 246 self:UpdateSlot()
Nenue@70 247 self.active = nil
Nenue@70 248 ClearCursor()
Nenue@70 249 ResetCursor()
Nenue@70 250 end
Nenue@70 251 end
Nenue@70 252 end
Nenue@70 253
Nenue@70 254
Nenue@70 255 do
Nenue@70 256 local PickupAction = {
Nenue@70 257 spell = _G.PickupSpell,
Nenue@70 258 petaction =
Nenue@70 259 function(...)
Nenue@70 260 -- needs to be enclosed to acquire hooksecurefunc effects
Nenue@70 261 _G.PickupSpellBookItem(...)
Nenue@70 262 end,
Nenue@70 263 macro = _G.PickupMacro,
Nenue@70 264 item = _G.PickupItem,
Nenue@70 265 mount = _G.C_MountJournal.Pickup
Nenue@70 266 }
Nenue@70 267 local GetPickupValue = {
Nenue@70 268 spell = function(self) return select(7, GetSpellInfo(self.actionID)) end,
Nenue@70 269 petaction = function(self) return self.pickupSlot, self.pickupBook end,
Nenue@70 270 }
Nenue@70 271 function skb:PickupSlot ()
Nenue@70 272 if not (self.command and self.isAvailable) then
Nenue@70 273 return
Nenue@70 274 end
Nenue@70 275 print(self.actionType)
Nenue@70 276 if self.actionType == 'spell' then
Nenue@70 277 -- It can't be picked up if SpellInfo(name) returns void
Nenue@70 278 local dummy = GetSpellInfo(self.actionName)
Nenue@70 279 if not dummy then
Nenue@70 280 return
Nenue@70 281 end
Nenue@70 282 end
Nenue@70 283 if PickupAction[self.actionType] then
Nenue@70 284 if GetPickupValue[self.actionType] then
Nenue@70 285 PickupAction[self.actionType](GetPickupValue[self.actionType](self))
Nenue@70 286 else
Nenue@70 287 PickupAction[self.actionType](self.actionID)
Nenue@70 288 end
Nenue@70 289 self:ReleaseSlot()
Nenue@70 290 self:UpdateSlot()
Nenue@70 291 end
Nenue@70 292 end
Nenue@70 293 end
Nenue@70 294
Nenue@70 295
Nenue@70 296
Nenue@70 297
Nenue@70 298 --- Updates profile assignment and button contents
Nenue@70 299 function skb:UpdateSlot (force)
Nenue@70 300 local slot = self:GetID()
Nenue@70 301
Nenue@70 302 if force then
Nenue@70 303 if kb.currentProfile.buttons[slot] then
Nenue@70 304 print('loading in', slot, kb.db.bindMode)
Nenue@70 305 self:SetSlot(kb.currentProfile.buttons[slot])
Nenue@70 306 else
Nenue@70 307 self:ReleaseSlot()
Nenue@70 308 end
Nenue@70 309 end
Nenue@70 310
Nenue@70 311 local borderType = BORDER_UNASSIGNED
Nenue@70 312
Nenue@70 313 if self.command then
Nenue@70 314
Nenue@70 315 if not self.isAvailable then
Nenue@70 316 borderType = BORDER_DYNAMIC
Nenue@70 317 self.ignoreTexture:Show()
Nenue@70 318 else
Nenue@70 319 self.ignoreTexture:Hide()
Nenue@70 320
Nenue@70 321 if self.pending then
Nenue@70 322 borderType = BORDER_PENDING
Nenue@70 323 elseif self.dynamicType then
Nenue@70 324 borderType = BORDER_DYNAMIC
Nenue@70 325 else
Nenue@70 326 borderType = BORDER_ASSIGNED
Nenue@70 327 end
Nenue@70 328 end
Nenue@70 329
Nenue@70 330
Nenue@70 331 if self.actionType == 'macro' then
Nenue@70 332 self.macro:Show()
Nenue@70 333 else
Nenue@70 334 self.macro:Hide()
Nenue@70 335 if self.actionType == 'spell' then
Nenue@70 336 local dummy = GetSpellInfo(self.actionName)
Nenue@70 337 if not dummy then
Nenue@70 338 self.icon:SetDesaturated(true)
Nenue@70 339 else
Nenue@70 340 self.icon:SetDesaturated(false)
Nenue@70 341 end
Nenue@70 342
Nenue@70 343 end
Nenue@70 344 end
Nenue@70 345
Nenue@70 346
Nenue@70 347 if self.dynamicType == 'profession' then
Nenue@70 348 if self.isAvailable then
Nenue@70 349
Nenue@70 350 self.statusText = '|cFFFFFF00Profession|r'
Nenue@70 351 self.bindingText = kb.BindingString(GetBindingKey(self.command))
Nenue@70 352 else
Nenue@70 353
Nenue@70 354 self.statusText = '|cFFFF4400'..PROFESSION_HEADERS[self.dynamicIndex]..'|r'
Nenue@70 355 self.actionName = '(#'..self.dynamicIndex..')'
Nenue@70 356 self.bindingText ='?'
Nenue@70 357 end
Nenue@70 358 elseif self.dynamicType == 'talent' then
Nenue@70 359 self.statusText = '|cFF00FFFF'.. TALENT .. '|r'
Nenue@70 360 if self.isAvailable then
Nenue@70 361 self.bindingText = kb.BindingString(GetBindingKey(self.command))
Nenue@70 362 else
Nenue@70 363
Nenue@71 364 print('|cFFFF4400', self.actionName, #self.assignedKeys, self.assignedKeys)
Nenue@71 365 print(self.actionID)
Nenue@71 366 self.bindingText= kb.BindingString(self.assignedKeys)
Nenue@70 367 end
Nenue@70 368 elseif self.dynamicType == 'petaction' then
Nenue@70 369 self.bindingText = kb.BindingString(GetBindingKey(self.command))
Nenue@70 370 else
Nenue@70 371 self.bindingText = kb.BindingString(GetBindingKey(self.command))
Nenue@70 372 end
Nenue@70 373
Nenue@70 374 local locked, layer = kb.IsCommandBound(self)
Nenue@70 375 if locked then
Nenue@70 376 self.icon:SetAlpha(0.5)
Nenue@70 377 else
Nenue@70 378 self.icon:SetAlpha(1)
Nenue@70 379 end
Nenue@70 380
Nenue@70 381
Nenue@70 382 if self.actionType == 'spell' then
Nenue@70 383 self.icon:SetTexture(GetSpellTexture(self.actionID))
Nenue@70 384 end
Nenue@70 385 print('|cFF00BBFFUpdateSlot|r:', '['..slot..'] =', self.command, self.bindingText, self.dynamicType, self.isAvailable, self.actionID)
Nenue@70 386 else
Nenue@70 387 if kb.saveTarget == self then
Nenue@70 388 kb.DeactivateSlot(self)
Nenue@70 389 end
Nenue@70 390
Nenue@70 391 end
Nenue@70 392
Nenue@70 393 self.ignoreTexture:SetShown(self.command and not self.isAvailable)
Nenue@70 394
Nenue@70 395 if not self.isAvailable then
Nenue@70 396 self.bind:SetTextColor(0.7,0.7,0.7,1)
Nenue@70 397 else
Nenue@70 398 self.bind:SetTextColor(1,1,1,1)
Nenue@70 399 end
Nenue@70 400
Nenue@70 401
Nenue@70 402 if kb.saveTarget and kb.saveTarget ~= self then
Nenue@70 403 self:SetAlpha(0.25)
Nenue@70 404 else
Nenue@70 405
Nenue@70 406 self:SetAlpha(1)
Nenue@70 407 end
Nenue@70 408
Nenue@70 409 --self.alert:SetShown(self.command and not self.isBound)
Nenue@70 410
Nenue@70 411 self.icon:SetTexture(self.iconPath)
Nenue@70 412
Nenue@70 413 self.border:SetColorTexture(unpack(borderType))
Nenue@70 414 self.header:SetText(self.statusText)
Nenue@70 415 self.bind:SetText(self.bindingText)
Nenue@70 416 self.details:SetText(self.actionName)
Nenue@70 417 end
Nenue@70 418
Nenue@70 419 --- Resets button command
Nenue@70 420 function skb:ReleaseSlot ()
Nenue@70 421 local slot = self:GetID()
Nenue@70 422
Nenue@70 423
Nenue@70 424 if kb.currentProfile.buttons[slot] then
Nenue@70 425 kb.currentProfile.buttons[slot] = nil
Nenue@70 426 end
Nenue@70 427 if self.command then
Nenue@70 428 kb.currentProfile.commands[self.command] = nil
Nenue@70 429 end
Nenue@70 430 local talentName = self.actionName
Nenue@70 431 if self.actionType == 'macro' then
Nenue@70 432 talentName = GetMacroSpell(self.actionID)
Nenue@70 433 end
Nenue@70 434 -- remove any matching talent data
Nenue@70 435 if talentName and kb.currentProfile.talents[talentName] then
Nenue@70 436 kb.currentProfile.talents[talentName] = nil
Nenue@70 437 end
Nenue@70 438 local droppedKeys = {}
Nenue@70 439
Nenue@70 440 -- doing removal in second loop to avoid possible iterator shenanigans
Nenue@70 441 for k,v in pairs(kb.currentProfile.bindings) do
Nenue@70 442 if v == self.command then
Nenue@70 443 tinsert(droppedKeys, k)
Nenue@70 444 end
Nenue@70 445 end
Nenue@70 446 if #droppedKeys >=1 then
Nenue@70 447 for i, k in ipairs(droppedKeys) do
Nenue@70 448 kb.currentProfile.bindings[k] = nil
Nenue@70 449 end
Nenue@70 450 end
Nenue@70 451
Nenue@70 452 self.isAvailable = nil
Nenue@70 453 self.dynamicType = nil
Nenue@70 454 self.bindingText = nil
Nenue@70 455 self.statusText = nil
Nenue@70 456 self.command = nil
Nenue@70 457 self.iconPath = nil
Nenue@70 458 self.actionType = nil
Nenue@70 459 self.actionID = nil
Nenue@70 460 self.actionName = nil
Nenue@70 461 self.pickupSlot = nil
Nenue@70 462 self.pickupBook = nil
Nenue@70 463 self.macroName = nil
Nenue@70 464 self.profile = nil
Nenue@70 465 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED))
Nenue@70 466 self:EnableKeyboard(false)
Nenue@70 467 self:SetScript('OnKeyDown', nil)
Nenue@70 468 self.bindingText = nil
Nenue@70 469 self.icon:SetTexture(nil)
Nenue@70 470 self.ignoreTexture:Hide()
Nenue@70 471
Nenue@70 472 end
Nenue@70 473
Nenue@70 474 local spells = {}
Nenue@70 475 local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon)
Nenue@70 476 if not spells[spellID] then
Nenue@70 477 spells[spellID] = {}
Nenue@70 478 spells[spellID].actionType = 'spell'
Nenue@70 479 spells[spellID].actionID = spellID
Nenue@70 480 spells[spellID].actionName = spellName
Nenue@70 481 spells[spellID].iconPath = icon
Nenue@70 482 spells[spellID].statusText = '|cFFBBBBBBSpell|r'
Nenue@70 483 spells[spellID].dynamicType = nil
Nenue@70 484 end
Nenue@70 485 return spells[spellID]
Nenue@70 486 end
Nenue@70 487
Nenue@70 488 local tempInfo = {}
Nenue@70 489 -- tries to resolve spells from talent overrides/profession book/etc
Nenue@70 490 local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'}
Nenue@70 491 local SkeletonKey_GetSpellDetails = function(self)
Nenue@70 492
Nenue@70 493 local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath
Nenue@70 494
Nenue@70 495
Nenue@70 496 cprint(' In:', spellName, spellID, command)
Nenue@70 497 cprint(GetSpellInfo(spellName or spellID))
Nenue@70 498 local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellName or spellID)
Nenue@70 499 local isAvailable = internalName and true
Nenue@70 500
Nenue@70 501 if internalName and (internalName ~= spellName) then
Nenue@70 502 -- it's a binding for the originating spell, leave it as is
Nenue@70 503 cprint(' |cFFFF4400spell is an override(', internalName, '~=', spellName,') leave the name info alone')
Nenue@70 504 self.statusText = '|cFFFFFF00Spell|r'
Nenue@70 505 self.isAvailable = true
Nenue@70 506 return
Nenue@70 507 end
Nenue@70 508
Nenue@70 509 -- let's us match spells replaced by talents
Nenue@70 510 local info = kb.DynamicSpells[internalName or spellName]
Nenue@70 511 if not info then
Nenue@70 512 local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)")
Nenue@70 513 if kb.DynamicSpells[dynamicType] then
Nenue@70 514 cprint('|cFFFF4400resolving dynamic type index:', internalName, spellName, command)
Nenue@70 515 dynamicIndex = tonumber(dynamicIndex)
Nenue@70 516 dynamicSubIndex = tonumber(dynamicSubIndex)
Nenue@70 517 local cache = kb.DynamicSpells[dynamicType]
Nenue@70 518 cprint('type:', dynamicType)
Nenue@70 519 if dynamicIndex and cache[dynamicIndex] then
Nenue@70 520 info = kb.DynamicSpells[dynamicType][dynamicIndex]
Nenue@70 521 cprint('index:', dynamicIndex)
Nenue@70 522 if dynamicSubIndex and info[dynamicSubIndex] then
Nenue@70 523 info = info[dynamicSubIndex]
Nenue@70 524 cprint('sub-index:', dynamicSubIndex)
Nenue@70 525 end
Nenue@70 526 isAvailable = true
Nenue@70 527 end
Nenue@70 528 end
Nenue@70 529 if not info then
Nenue@70 530 info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon)
Nenue@70 531 end
Nenue@70 532 end
Nenue@70 533 info.isAvailable = isAvailable
Nenue@70 534
Nenue@71 535 cprint('|cFF00FF88SpellDetails:|r', info.actionName, info.actionID, info.dynamicType, info.isAvailable)
Nenue@70 536 for k,v in pairs(info) do
Nenue@71 537 --cprint(' ',k,v)
Nenue@70 538 self[k] = v
Nenue@70 539 end
Nenue@70 540
Nenue@70 541 return info
Nenue@70 542 end
Nenue@70 543
Nenue@70 544 --- Assigns the slot via table copy; any manipulations from this point are temporary and
Nenue@70 545 function skb:SetSlot(slotInfo)
Nenue@70 546 print('slot info', self:GetID())
Nenue@70 547
Nenue@70 548 for k,v in pairs(slotInfo) do
Nenue@70 549 print(' -', k, v)
Nenue@70 550 self[k] = v
Nenue@70 551 end
Nenue@70 552 self.dynamicType = slotInfo.dynamicType
Nenue@70 553 local command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook
Nenue@70 554 = self.command, self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType
Nenue@70 555
Nenue@70 556
Nenue@70 557 local slot = self:GetID()
Nenue@70 558 local isBound = false
Nenue@70 559 print('|cFFFFFF00SetSlot|r:', self:GetID())
Nenue@70 560 if self.command then
Nenue@70 561
Nenue@70 562 isBound = kb.IsCommandBound(self, self.command)
Nenue@70 563 if actionType == 'spell' then
Nenue@70 564 local info = SkeletonKey_GetSpellDetails(self)
Nenue@70 565 name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook = self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType
Nenue@71 566 self.isAvailable = info and info.isAvailable
Nenue@70 567 elseif actionType == 'petaction' then
Nenue@70 568 self.dynamicType = 'petaction'
Nenue@70 569 local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)')
Nenue@70 570
Nenue@70 571 if kb.PetCache.subtext[specialType] then
Nenue@70 572
Nenue@70 573 local info = kb.PetCache.subtext[specialType][tonumber(specialNum)]
Nenue@70 574 if info then
Nenue@70 575 print('***dynamic pet skill', specialType, specialNum)
Nenue@70 576 --[[ i, spellName, subText, spellID, texture, specialNum[subText ]]
Nenue@70 577
Nenue@70 578 for k,v in pairs(info) do
Nenue@70 579 self[k] = v
Nenue@70 580 end
Nenue@70 581 end
Nenue@70 582
Nenue@70 583 end
Nenue@70 584 self.statusText = 'Pet Action'
Nenue@70 585 self.isAvailable = (kb.PetCache.spellslot[name])
Nenue@70 586 elseif actionType == 'macro' then
Nenue@70 587 if actionID then
Nenue@70 588 -- look for corruption
Nenue@70 589 local nameByID, _, bodyByID = GetMacroInfo(actionID)
Nenue@70 590 local nameByName, _, bodyByName = GetMacroInfo(name)
Nenue@70 591 if (nameByID ~= name) or (bodyByID ~= macroText) then
Nenue@70 592 local prevIndex = actionID
Nenue@70 593 actionID = GetMacroIndexByName(name)
Nenue@70 594 local firstName, _, firstBody = GetMacroInfo(actionID)
Nenue@70 595 if (firstName ~= name) or (firstBody ~= macroText) then
Nenue@70 596 -- go even deeper
Nenue@70 597 for i = 1, GetNumMacros() do
Nenue@70 598 local searchName, _ , searchBody = GetMacroInfo(i)
Nenue@70 599 if (searchName == name) and (searchBody == macroText) then
Nenue@70 600 -- complete match
Nenue@70 601 actionID = i
Nenue@70 602 break
Nenue@70 603 elseif (searchName == name) or (searchBody == macroText) then
Nenue@70 604 -- partial match, continue the search
Nenue@70 605 actionID = i
Nenue@70 606 end
Nenue@70 607 end
Nenue@70 608 end
Nenue@70 609 kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')')
Nenue@70 610 end
Nenue@70 611 else
Nenue@70 612 actionID = GetMacroIndexByName(name)
Nenue@70 613 end
Nenue@70 614 self.statusText = 'Macro'
Nenue@70 615 self.isAvailable = true
Nenue@70 616 else
Nenue@70 617 if not actionID then
Nenue@70 618 actionID = command:match("^KeyBinderMacro:(.+)")
Nenue@70 619 end
Nenue@70 620 self.isAvailable = true
Nenue@70 621 end
Nenue@70 622
Nenue@70 623 if self.isAvailable then
Nenue@70 624 local oldCommand = command
Nenue@70 625 command = kb.LoadBinding(self)
Nenue@70 626 if oldCommand ~= command then
Nenue@70 627 print('|cFFFF4400fixing command string', actionType, actionID, name)
Nenue@70 628 kb.currentProfile.bound[oldCommand] = nil
Nenue@70 629 kb.currentProfile.bound[command] = slot
Nenue@70 630 for k,v in pairs(kb.currentProfile.bindings) do
Nenue@70 631 if v == oldCommand then
Nenue@70 632 kb.currentProfile.bindings[k] = command
Nenue@70 633 end
Nenue@70 634 end
Nenue@70 635 end
Nenue@70 636 end
Nenue@70 637
Nenue@70 638
Nenue@70 639 actionID = actionID or 0
Nenue@70 640 self:EnableKeyboard(true)
Nenue@70 641
Nenue@70 642 -- this is done to keep legacy key-values from breaking algorithm assumptions
Nenue@71 643 print(slotInfo.assignedKeys)
Nenue@71 644 print(GetBindingKey(command))
Nenue@71 645 self.assignedKeys = slotInfo.assignedKeys or {GetBindingKey(command)}
Nenue@71 646
Nenue@70 647 local slotInfo = {
Nenue@70 648 command = command,
Nenue@70 649 actionName = name,
Nenue@70 650 iconPath = icon,
Nenue@70 651 actionID = actionID,
Nenue@70 652 actionType = actionType,
Nenue@70 653 macroName = macroName,
Nenue@70 654 macroText = macroText,
Nenue@70 655 spellbookSlot = pickupSlot,
Nenue@70 656 spellbookType = pickupBook,
Nenue@71 657 assignedKeys = slotInfo.assignedKeys,
Nenue@71 658 dynamicType = self.dynamicType,
Nenue@71 659 dynamicID = self.dynamicID,
Nenue@71 660 dynamicIndex = self.dynamicIndex,
Nenue@71 661 dynamicSubIndex = self.dynamicSubIndex
Nenue@70 662 }
Nenue@70 663 kb.currentProfile.buttons[slot] = slotInfo
Nenue@70 664
Nenue@70 665 -- Clean up conflicting entries for loaded button
Nenue@70 666 local previous = kb.currentProfile.commands[command]
Nenue@70 667 if previous ~= slot and kb.buttons[previous] then
Nenue@70 668 kb.ReleaseSlot(kb.buttons[previous])
Nenue@70 669 end
Nenue@70 670
Nenue@70 671 local binds = {GetBindingKey(command) }
Nenue@70 672 if self.isAvailable and (#binds >= 1) then
Nenue@70 673 local found
Nenue@70 674 for i, key in ipairs(binds) do
Nenue@70 675 if not tContains(self.assignedKeys, key) then
Nenue@70 676 tinsert(self.assignedKeys, key)
Nenue@70 677 kb.currentProfile.bindings[key] = command
Nenue@70 678 kb.currentProfile.bound[command] = true
Nenue@70 679 found = true
Nenue@70 680 end
Nenue@70 681 end
Nenue@70 682 if found then
Nenue@70 683 kb:print('Recovered key binding for', name)
Nenue@70 684 end
Nenue@70 685 end
Nenue@70 686
Nenue@70 687 kb.currentProfile.commands[command] = slot
Nenue@70 688 end
Nenue@70 689
Nenue@71 690 --self.assignedKeys = slotInfo.assignedKeys
Nenue@70 691 self.isBound = isBound
Nenue@70 692 self.pickupSlot = pickupSlot
Nenue@70 693 self.pickupBook = pickupBook
Nenue@70 694 self.macroText = macroText
Nenue@70 695 self.macroName = macroName
Nenue@70 696 self.actionType = actionType
Nenue@70 697 self.actionID = actionID
Nenue@70 698 self.actionName = name
Nenue@70 699 self.command = command
Nenue@70 700 self.iconPath = icon
Nenue@70 701 self.profile = kb.db.bindMode
Nenue@70 702 self:RegisterForDrag('LeftButton')
Nenue@70 703 end
Nenue@70 704
Nenue@70 705 kb.GetCommandAction = function(command)
Nenue@70 706 for i, data in ipairs(kb.loadedProfiles) do
Nenue@70 707 if data.commands[command] then
Nenue@70 708 if data.buttons[data.commands[command]] then
Nenue@70 709 local _, _, _, actionType, actionID = unpack(data.buttons[data.commands[command]])
Nenue@70 710 return actionType, actionID
Nenue@70 711 end
Nenue@70 712 end
Nenue@70 713 end
Nenue@70 714 end
Nenue@70 715