Nenue@14: -- SkeletonKey Nenue@14: -- KeySlot.lua Nenue@14: -- Created: 7/28/2016 11:26 PM Nenue@14: -- %file-revision% Nenue@14: -- All the internal slot logic is kept here Nenue@14: Nenue@14: local kb, print = LibStub('LibKraken').register(KeyBinder, 'Slot') Nenue@14: local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION Nenue@14: local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 Nenue@14: local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } Nenue@14: local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } Nenue@14: local BORDER_DYNAMIC = {1,1,0,1} Nenue@14: local BORDER_PENDING = {1,0.5,0,1 } Nenue@14: Nenue@14: local BUTTON_HEADERS = { Nenue@14: ['spell'] = SPELLS, Nenue@14: ['macro'] = MACRO, Nenue@14: ['petaction'] = PET, Nenue@14: ['mount'] = MOUNT, Nenue@14: ['battlepet'] = BATTLEPET, Nenue@14: Nenue@14: Nenue@14: [5] = PROFESSIONS_FIRST_AID, Nenue@14: [7] = PROFESSIONS_COOKING, Nenue@14: [9] = PROFESSIONS_FISHING, Nenue@14: [10] = PROFESSIONS_ARCHAEOLOGY, Nenue@14: Nenue@14: } Nenue@14: Nenue@14: -- This is needed to identify a spells that aren't reflected by GetCursorInfo() Nenue@14: hooksecurefunc("PickupSpellBookItem", function(slot, bookType) Nenue@14: print('|cFFFF4400PickupSpellBookItem(..', tostring(slot),', '..tostring(bookType)..')') Nenue@14: CURSOR_SPELLSLOT = slot Nenue@14: CURSOR_BOOKTYPE = bookType Nenue@14: end) Nenue@14: Nenue@14: do Nenue@14: -- Pet actions Nenue@14: local isPickup Nenue@14: hooksecurefunc("PickupPetAction", function(slot, ...) Nenue@14: isPickup = GetCursorInfo() Nenue@14: Nenue@14: CURSOR_PETACTION = isPickup and slot Nenue@14: print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION) Nenue@14: end) Nenue@14: end Nenue@14: Nenue@14: Nenue@14: kb.DropToSlot = function(self) Nenue@14: print(self:GetName(),'|cFF0088FFreceived|r') Nenue@14: local actionType, actionID, subType, subData = GetCursorInfo() Nenue@14: print('GetCursorInfo', GetCursorInfo()) Nenue@14: if actionType then Nenue@14: Nenue@14: if actionType == 'flyout' then Nenue@14: ClearCursor() Nenue@14: ResetCursor() Nenue@14: return Nenue@14: end Nenue@14: Nenue@14: Nenue@14: local macroName, macroText Nenue@14: local command, name, icon, _ Nenue@14: local pickupID, pickupBook Nenue@14: Nenue@14: if actionType == 'spell' then Nenue@14: actionID = subData Nenue@14: name, _, icon = GetSpellInfo(actionID) Nenue@14: Nenue@14: elseif actionType == 'macro' then Nenue@14: name, icon = GetMacroInfo(actionID) Nenue@14: elseif actionType == 'petaction' then Nenue@14: if not (CURSOR_SPELLSLOT and CURSOR_BOOKTYPE) then Nenue@14: Nenue@14: ClearCursor() Nenue@14: ResetCursor() Nenue@14: end Nenue@14: Nenue@14: local bookType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) Nenue@14: actionID = spellID Nenue@14: pickupID = CURSOR_SPELLSLOT Nenue@14: pickupBook = CURSOR_BOOKTYPE Nenue@14: name, _, icon = GetSpellInfo(spellID) Nenue@14: elseif actionType == 'mount' then Nenue@14: if subType == 0 then Nenue@14: name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) Nenue@14: actionID = 0 Nenue@14: else Nenue@14: name, _, icon = C_MountJournal.GetMountInfoByID(actionID) Nenue@14: end Nenue@14: elseif actionType == 'item' then Nenue@14: name = GetItemInfo(actionID) Nenue@14: icon = GetItemIcon(actionID) Nenue@14: actionID = name Nenue@14: elseif actionType == 'battlepet' then Nenue@14: Nenue@14: local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail); Nenue@14: name = customName or petName Nenue@14: icon = petIcon Nenue@14: Nenue@14: end Nenue@14: macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) Nenue@14: Nenue@14: Nenue@14: local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) Nenue@14: if isAssigned then Nenue@14: local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] Nenue@14: popup.slot = self Nenue@14: popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?" Nenue@14: popup.oldProfile = assignedBy Nenue@14: popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook } Nenue@14: kb:SetScript('OnMouseWheel', nil) -- disable scrolling Nenue@14: StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') Nenue@14: else Nenue@14: kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) Nenue@14: kb.UpdateSlot(self) Nenue@14: self.active = nil Nenue@14: ClearCursor() Nenue@14: ResetCursor() Nenue@14: end Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: Nenue@14: do Nenue@14: local PickupAction = { Nenue@14: spell = _G.PickupSpell, Nenue@14: petaction = _G.PickupSpellBookItem, Nenue@14: macro = _G.PickupMacro, Nenue@14: item = _G.PickupItem, Nenue@14: mount = _G.C_MountJournal.Pickup Nenue@14: } Nenue@14: local GetPickupValue = { Nenue@14: spell = function(self) return select(7, GetSpellInfo(self.actionID)) end, Nenue@14: petaction = function(self) return self.pickupSlot, self.pickupBook end, Nenue@14: } Nenue@14: kb.PickupSlot = function(self) Nenue@14: if not self.command then Nenue@14: return Nenue@14: end Nenue@14: print(self.actionType) Nenue@14: if self.actionType == 'spell' then Nenue@14: -- It can't be picked up if SpellInfo(name) returns void Nenue@14: local dummy = GetSpellInfo(self.actionName) Nenue@14: if not dummy then Nenue@14: return Nenue@14: end Nenue@14: end Nenue@14: if PickupAction[self.actionType] then Nenue@14: if GetPickupValue[self.actionType] then Nenue@14: PickupAction[self.actionType](GetPickupValue[self.actionType](self)) Nenue@14: else Nenue@14: PickupAction[self.actionType](self.actionID) Nenue@14: end Nenue@14: kb.ReleaseSlot(self) Nenue@14: kb.UpdateSlot(self) Nenue@14: end Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: Nenue@14: Nenue@14: --- Updates profile assignment and button contents Nenue@14: kb.UpdateSlot = function(self, force) Nenue@14: local slot = self:GetID() Nenue@14: Nenue@14: if force then Nenue@14: if kb.currentProfile.buttons[slot] then Nenue@14: kb.SetSlot(self, unpack(kb.currentProfile.buttons[slot])) Nenue@14: else Nenue@14: kb.ReleaseSlot(self) Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: if self.command then Nenue@14: print('['..slot..'] =', self.command, GetBindingKey(self.command)) Nenue@14: Nenue@14: if self.pending then Nenue@14: self.border:SetColorTexture(unpack(BORDER_PENDING)) Nenue@14: elseif self.isDynamic then Nenue@14: self.border:SetColorTexture(unpack(BORDER_DYNAMIC)) Nenue@14: else Nenue@14: self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) Nenue@14: end Nenue@14: Nenue@14: if self.actionType == 'macro' then Nenue@14: self.macro:Show() Nenue@14: else Nenue@14: self.macro:Hide() Nenue@14: if self.actionType == 'spell' then Nenue@14: local dummy = GetSpellInfo(self.actionName) Nenue@14: if not dummy then Nenue@14: self.icon:SetDesaturated(true) Nenue@14: else Nenue@14: self.icon:SetDesaturated(false) Nenue@14: end Nenue@14: Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: if self.isDynamic then Nenue@14: print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID) Nenue@14: end Nenue@14: Nenue@14: if self.isDynamic == 'profession' then Nenue@14: local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex)) Nenue@14: if self.isAvailable then Nenue@14: print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1)) Nenue@14: Nenue@14: self.statusText = '|cFFFFFF00'..profText..'|r' Nenue@14: self.bindingText = kb.BindingString(GetBindingKey(self.command)) Nenue@14: else Nenue@14: self.statusText = '|cFFFF4400'..profText..'|r' Nenue@14: self.actionName = '(need to train profession #'..self.profNum..')' Nenue@14: self.bindingText ='?' Nenue@14: end Nenue@14: elseif self.isDynamic == 'talent' then Nenue@14: Nenue@14: self.statusText = '|cFF00FFFF'.. TALENT .. '|r' Nenue@14: if self.isAvailable then Nenue@14: self.bindingText = kb.BindingString(GetBindingKey(self.command)) Nenue@14: else Nenue@14: if kb.inactiveTalentBindings[self.actionID] then Nenue@14: print(self.actionID, #kb.inactiveTalentBindings[self.actionID]) Nenue@14: self.bindingText= kb.BindingString(unpack(kb.inactiveTalentBindings[self.actionID])) Nenue@14: end Nenue@14: Nenue@14: end Nenue@14: else Nenue@14: self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r' Nenue@14: self.bindingText = kb.BindingString(GetBindingKey(self.command)) Nenue@14: end Nenue@14: Nenue@14: local locked, layer = kb.IsCommandBound(self) Nenue@14: if locked then Nenue@14: self.icon:SetAlpha(0.5) Nenue@14: else Nenue@14: self.icon:SetAlpha(1) Nenue@14: end Nenue@14: Nenue@14: if self.actionType == 'spell' then Nenue@14: self.icon:SetTexture(GetSpellTexture(self.actionID)) Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: if not self.isAvailable then Nenue@14: self.bind:SetTextColor(0.7,0.7,0.7,1) Nenue@14: else Nenue@14: self.bind:SetTextColor(1,1,1,1) Nenue@14: end Nenue@14: Nenue@14: self.header:SetText(self.statusText) Nenue@14: self.bind:SetText(self.bindingText) Nenue@14: self.details:SetText(self.actionName) Nenue@14: end Nenue@14: Nenue@14: --- Resets button command Nenue@14: kb.ReleaseSlot = function(self) Nenue@14: local slot = self:GetID() Nenue@14: Nenue@14: Nenue@14: if kb.currentProfile.buttons[slot] then Nenue@14: kb.currentProfile.buttons[slot] = nil Nenue@14: end Nenue@14: if self.command then Nenue@14: kb.currentProfile.commands[self.command] = nil Nenue@14: end Nenue@14: if self.actionType == 'spell' and IsTalentSpell(self.actionName) then Nenue@14: if kb.currentProfile.talents[self.actionID] then Nenue@14: kb.currentProfile.talents[self.actionID] = nil Nenue@14: end Nenue@14: end Nenue@14: local droppedKeys = {} Nenue@14: Nenue@14: -- doing removal in second loop to avoid possible iterator shenanigans Nenue@14: for k,v in pairs(kb.currentProfile.bindings) do Nenue@14: if v == self.command then Nenue@14: tinsert(droppedKeys, k) Nenue@14: end Nenue@14: end Nenue@14: if #droppedKeys >=1 then Nenue@14: for i, k in ipairs(droppedKeys) do Nenue@14: kb.currentProfile.bindings[k] = nil Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: self.isAvailable = nil Nenue@14: self.isDynamic = nil Nenue@14: self.bindingText = nil Nenue@14: self.statusText = nil Nenue@14: self.command = nil Nenue@14: self.actionType = nil Nenue@14: self.actionID = nil Nenue@14: self.actionName = nil Nenue@14: self.pickupSlot = nil Nenue@14: self.pickupBook = nil Nenue@14: self.macroName = nil Nenue@14: self.profile = nil Nenue@14: self.icon:SetTexture(nil) Nenue@14: self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) Nenue@14: self:EnableKeyboard(false) Nenue@14: self:SetScript('OnKeyDown', nil) Nenue@14: end Nenue@14: Nenue@14: kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook) Nenue@14: local slot = self:GetID() Nenue@14: local isDynamic, isAvailable Nenue@14: Nenue@14: print('|cFFFFFF00SetSlot|r:', self:GetID()) Nenue@14: if command then Nenue@14: Nenue@14: if actionType == 'spell' then Nenue@14: local professionNum, spellNum = command:match("profession_(%d)_(%d)") Nenue@14: Nenue@14: if (professionNum and spellNum) then Nenue@14: isDynamic = 'profession' Nenue@14: local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum] Nenue@14: if cacheInfo then Nenue@14: isAvailable = true Nenue@14: name = cacheInfo.spellName Nenue@14: icon = cacheInfo.icon Nenue@14: actionID = cacheInfo.spellID Nenue@14: self.profIndex = cacheInfo.profIndex Nenue@14: self.spellOffset = cacheInfo.spellOffset Nenue@14: end Nenue@14: print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable) Nenue@14: Nenue@14: self.professionNum = tonumber(professionNum) Nenue@14: self.spellNum = tonumber(spellNum) Nenue@14: Nenue@14: else Nenue@14: if kb.TalentCache[actionID] then Nenue@14: isDynamic = 'talent' Nenue@14: print(' Special slot: |cFFBBFF00talent|r', name, isAvailable) Nenue@14: end Nenue@14: Nenue@14: isAvailable = GetSpellInfo(name) Nenue@14: end Nenue@14: elseif actionType == 'macro' then Nenue@14: if not actionID then Nenue@14: actionID = GetMacroIndexByName(name) Nenue@14: end Nenue@14: isAvailable = true Nenue@14: else Nenue@14: --- Journal selections Nenue@14: -- todo: consider using the deep end of blizzard action bar instead Nenue@14: if not actionID then Nenue@14: actionID = command:match("^KeyBinderMacro:(.+)") Nenue@14: end Nenue@14: isAvailable = true Nenue@14: end Nenue@14: Nenue@14: if isAvailable then Nenue@14: local oldCommand = command Nenue@14: macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) Nenue@14: if oldCommand ~= command then Nenue@14: print('|cFFFF4400fixing command string', actionType, actionID, name) Nenue@14: kb.currentProfile.bound[oldCommand] = nil Nenue@14: kb.currentProfile.bound[command] = slot Nenue@14: for k,v in pairs(kb.currentProfile.bindings) do Nenue@14: if v == oldCommand then Nenue@14: kb.currentProfile.bindings[k] = command Nenue@14: end Nenue@14: end Nenue@14: end Nenue@14: kb.LoadBinding(command, name, icon, actionType, actionID, macroName, macroText) Nenue@14: end Nenue@14: Nenue@14: if actionType == 'petaction' then Nenue@14: self.pickupSlot = pickupSlot Nenue@14: self.pickupBook = pickupBook Nenue@14: else Nenue@14: self.pickupSlot = nil Nenue@14: self.pickupBook = nil Nenue@14: end Nenue@14: Nenue@14: actionID = actionID or 0 Nenue@14: self:EnableKeyboard(true) Nenue@14: print(' |cFF00FF00kb.currentProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r') Nenue@14: kb.currentProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook} Nenue@14: Nenue@14: -- Clean up conflicting entries for loaded button Nenue@14: local previous = kb.currentProfile.commands[command] Nenue@14: if previous ~= slot and kb.buttons[previous] then Nenue@14: kb.ReleaseSlot(kb.buttons[previous]) Nenue@14: end Nenue@14: kb.currentProfile.commands[command] = slot Nenue@14: end Nenue@14: Nenue@14: self.isAvailable = isAvailable Nenue@14: self.isDynamic = isDynamic Nenue@14: Nenue@14: self.macroText = macroText Nenue@14: self.macroName = macroName Nenue@14: self.actionType = actionType Nenue@14: self.actionID = actionID Nenue@14: self.actionName = name Nenue@14: self.command = command Nenue@14: self.icon:SetTexture(icon) Nenue@14: self.profile = kb.db.bindMode Nenue@14: self:RegisterForDrag('LeftButton') Nenue@14: end Nenue@14: Nenue@14: Nenue@14: Nenue@14: --- Add to blizzard interfaces Nenue@14: StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = { Nenue@14: text = "Confirm moving an assigned command.", Nenue@14: button1 = OKAY, Nenue@14: button2 = CANCEL, Nenue@14: timeout = 0, Nenue@14: whileDead = 1, Nenue@14: showAlert = 1, Nenue@14: OnAccept = kb.AcceptAssignment, Nenue@14: OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end Nenue@14: }