Mercurial > wow > skeletonkey
diff KeyButton.lua @ 70:131d9190db6b
Curseforge migration
author | Nenue |
---|---|
date | Wed, 28 Dec 2016 16:31:15 -0500 |
parents | |
children | ca3118127e5e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KeyButton.lua Wed Dec 28 16:31:15 2016 -0500 @@ -0,0 +1,710 @@ +-- SkeletonKey +-- KeyButton.lua +-- Created: 7/28/2016 11:26 PM +-- %file-revision% +-- Deals with display and manipulation of binding slots + +local _, kb = ... +local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SkeletonKey', ...) end or function() end +local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end +local L = kb.L +local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs +local _G, unpack, select, tostring = _G, unpack, select, tostring +local GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo = GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo +local GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon = GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon +local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor +local GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown, IsShiftKeyDown = GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown,IsShiftKeyDown +local GetBindingKey, GetProfessionInfo = GetBindingKey, GetProfessionInfo +local GetMountInfoByID, GetPetInfoByPetID = C_MountJournal.GetMountInfoByID, C_PetJournal.GetPetInfoByPetID +local skb = SkeletonKeyButtonMixin +local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION, CURSOR_TEXTURE +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 +local BORDER_UNASSIGNED = {0.6,0.6,0.6,1} +local BORDER_ASSIGNED = {1,1,1,1} +local BORDER_DYNAMIC = {1,1,0,1} +local BORDER_PENDING = {1,0.5,0,1 } +local BUTTON_HEADERS = { + ['spell'] = SPELLS, + ['macro'] = MACRO, + ['petaction'] = PET, + ['mount'] = MOUNT, + ['battlepet'] = BATTLEPET, + + + [5] = PROFESSIONS_FIRST_AID, + [7] = PROFESSIONS_COOKING, + [9] = PROFESSIONS_FISHING, + [10] = PROFESSIONS_ARCHAEOLOGY, + +} + +local PROFESSION_HEADERS = { + [1] = 'Profession 1', + [2] = 'Profession 2', + [3] = 10, + [4] = 7, + [5] = 9, + [6] = 5 +} + + +-- This is needed to identify a spells that aren't reflected by GetCursorInfo() +kb.OnPickupPetAction = function(slot, ...) + local isPickup = GetCursorInfo() + print(slot, ...) + if kb.PetCache.action[slot] then + if isPickup then + local key, _, texture = unpack(kb.PetCache.action[slot]) + local spellName = _G[key] or key + if spellName and kb.PetCache.spellslot[spellName] then + CURSOR_SPELLSLOT = kb.PetCache.spellslot[spellName][1] + CURSOR_BOOKTYPE = BOOKTYPE_PET + CURSOR_TEXTURE = _G[texture] or texture + end + else + CURSOR_SPELLSLOT = nil + CURSOR_BOOKTYPE = nil + CURSOR_TEXTURE = nil + end + print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION) + end + + local name, subtext, texture, isToken = GetPetActionInfo(slot) + if name then + kb.PetCache.action[slot] = {name, subtext, texture, isToken} + end + + + print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE) + +end + +kb.OnPickupSpellBookItem = function(slot, bookType) + print('|cFFFF4400PickupSpellBookItem('.. tostring(slot).. ', '..tostring(bookType)..')') + CURSOR_SPELLSLOT = slot + CURSOR_BOOKTYPE = bookType + CURSOR_TEXTURE = GetSpellBookItemTexture(slot, bookType) + print('current cursor info', CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_TEXTURE) +end + +kb.CreateHooks = function() + hooksecurefunc("PickupSpellBookItem", kb.OnPickupSpellBookItem) + hooksecurefunc("PickupPetAction", kb.OnPickupPetAction) +end + + + +function skb:OnLoad() + self:EnableKeyboard(false) + self:EnableMouse(true) + self:RegisterForDrag('LeftButton') + self:RegisterForClicks('AnyUp') +end + +function skb:OnEnter() + if not self.command then + return + end + if self.statusText then + SkeletonKey.statustext:SetText(self.statusText .. ': '..self.actionName) + SkeletonKey.bindingstext:SetText(self.bindingText) + end + + + if kb.db.hoverInput and kb.saveTarget ~= self then + self:GetParent():ActivateSlot(self) + SkeletonKey:Update() + end +end + +function skb:OnLeave() + if kb.db.hoverInput and kb.saveTarget == self then + self:GetParent():DeactivateSlot(self) + SkeletonKey:Update() + end +end + +function skb:OnUpdate() +end +function skb:OnClick(click) + print(self:GetName(), 'OnMouseDown', click) + local cursorType = GetCursorInfo() + if click == 'LeftButton' then + if cursorType then + self:DropToSlot() + else + if self.command and self.isAvailable then + if IsShiftKeyDown() then + kb.db.stickyMode = true + KeyBinderStickyMode:SetChecked(true) + end + self:GetParent():ActivateSlot(self) + end + end + elseif click == 'RightButton' then + self:ReleaseSlot() + else + kb.ProcessInput(strupper(click)) + end + SkeletonKey:Update() +end + +function skb:OnDragStart() + self:PickupSlot() +end + +function skb:OnReceiveDrag(...) + self:DropToSlot() +end + +function skb:DropToSlot () + print(self:GetName(),'|cFF0088FFreceived|r') + local actionType, actionID, subType, subData = GetCursorInfo() + print('GetCursorInfo', GetCursorInfo()) + if actionType then + + if actionType == 'flyout' then + ClearCursor() + ResetCursor() + return + end + + + local name, icon, _ + local pickupID, pickupBook + + if actionType == 'spell' then + actionID = subData + name, _, icon = GetSpellInfo(actionID) + + elseif actionType == 'macro' then + name, icon = GetMacroInfo(actionID) + elseif actionType == 'petaction' then + if CURSOR_SPELLSLOT and CURSOR_BOOKTYPE then + + local spellType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) + local spellName, spellText = GetSpellBookItemName(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) + if spellType == 'PETACTION' then + name = spellName + actionID = spellText + icon = CURSOR_TEXTURE + else + name, _, icon = GetSpellInfo(spellID) + actionID = spellID + end + + pickupID = CURSOR_SPELLSLOT + pickupBook = CURSOR_BOOKTYPE + else + + + end + + elseif actionType == 'mount' then + if subType == 0 then + name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) + actionID = 0 + else + name, _, icon = GetMountInfoByID(actionID) + end + elseif actionType == 'item' then + name = GetItemInfo(actionID) + icon = GetItemIcon(actionID) + elseif actionType == 'battlepet' then + + local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = GetPetInfoByPetID(actionID) + name = customName or petName + icon = petIcon + + end + local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) + local slotInfo = { + command = command, + actionName = name, + iconPath = icon, + actionType = actionType, + actionID = actionID, + macroName = macroName, + macroText = macroText, + spellbookSlot = pickupID, + spellbookType = pickupBook, + assignedKeys = {GetBindingKey(command)} + } + + local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) + if isAssigned then + local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] + popup.slot = self + popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?" + popup.oldProfile = assignedBy + popup.args = {slotInfo} + SkeletonKey:SetScript('OnMouseWheel', nil) -- disable scrolling + StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') + else + kb.currentProfile.buttons[self:GetID()] = slotInfo + self:SetSlot(slotInfo) + self:UpdateSlot() + self.active = nil + ClearCursor() + ResetCursor() + end + end +end + + +do + local PickupAction = { + spell = _G.PickupSpell, + petaction = + function(...) + -- needs to be enclosed to acquire hooksecurefunc effects + _G.PickupSpellBookItem(...) + end, + macro = _G.PickupMacro, + item = _G.PickupItem, + mount = _G.C_MountJournal.Pickup + } + local GetPickupValue = { + spell = function(self) return select(7, GetSpellInfo(self.actionID)) end, + petaction = function(self) return self.pickupSlot, self.pickupBook end, + } + function skb:PickupSlot () + if not (self.command and self.isAvailable) then + return + end + print(self.actionType) + if self.actionType == 'spell' then + -- It can't be picked up if SpellInfo(name) returns void + local dummy = GetSpellInfo(self.actionName) + if not dummy then + return + end + end + if PickupAction[self.actionType] then + if GetPickupValue[self.actionType] then + PickupAction[self.actionType](GetPickupValue[self.actionType](self)) + else + PickupAction[self.actionType](self.actionID) + end + self:ReleaseSlot() + self:UpdateSlot() + end + end +end + + + + +--- Updates profile assignment and button contents +function skb:UpdateSlot (force) + local slot = self:GetID() + + if force then + if kb.currentProfile.buttons[slot] then + print('loading in', slot, kb.db.bindMode) + self:SetSlot(kb.currentProfile.buttons[slot]) + else + self:ReleaseSlot() + end + end + + local borderType = BORDER_UNASSIGNED + + if self.command then + + if not self.isAvailable then + borderType = BORDER_DYNAMIC + self.ignoreTexture:Show() + else + self.ignoreTexture:Hide() + + if self.pending then + borderType = BORDER_PENDING + elseif self.dynamicType then + borderType = BORDER_DYNAMIC + else + borderType = BORDER_ASSIGNED + end + end + + + if self.actionType == 'macro' then + self.macro:Show() + else + self.macro:Hide() + if self.actionType == 'spell' then + local dummy = GetSpellInfo(self.actionName) + if not dummy then + self.icon:SetDesaturated(true) + else + self.icon:SetDesaturated(false) + end + + end + end + + + if self.dynamicType == 'profession' then + if self.isAvailable then + + self.statusText = '|cFFFFFF00Profession|r' + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + else + + self.statusText = '|cFFFF4400'..PROFESSION_HEADERS[self.dynamicIndex]..'|r' + self.actionName = '(#'..self.dynamicIndex..')' + self.bindingText ='?' + end + elseif self.dynamicType == 'talent' then + + self.statusText = '|cFF00FFFF'.. TALENT .. '|r' + if self.isAvailable then + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + else + if kb.TalentBindings[self.actionID] then + print(self.actionID, #kb.TalentBindings[self.actionID]) + self.bindingText= kb.BindingString(unpack(kb.TalentBindings[self.actionID])) + end + + end + elseif self.dynamicType == 'petaction' then + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + else + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + end + + local locked, layer = kb.IsCommandBound(self) + if locked then + self.icon:SetAlpha(0.5) + else + self.icon:SetAlpha(1) + end + + + if self.actionType == 'spell' then + self.icon:SetTexture(GetSpellTexture(self.actionID)) + end + print('|cFF00BBFFUpdateSlot|r:', '['..slot..'] =', self.command, self.bindingText, self.dynamicType, self.isAvailable, self.actionID) + else + if kb.saveTarget == self then + kb.DeactivateSlot(self) + end + + end + + self.ignoreTexture:SetShown(self.command and not self.isAvailable) + + if not self.isAvailable then + self.bind:SetTextColor(0.7,0.7,0.7,1) + else + self.bind:SetTextColor(1,1,1,1) + end + + + if kb.saveTarget and kb.saveTarget ~= self then + self:SetAlpha(0.25) + else + + self:SetAlpha(1) + end + + --self.alert:SetShown(self.command and not self.isBound) + + self.icon:SetTexture(self.iconPath) + + self.border:SetColorTexture(unpack(borderType)) + self.header:SetText(self.statusText) + self.bind:SetText(self.bindingText) + self.details:SetText(self.actionName) +end + +--- Resets button command +function skb:ReleaseSlot () + local slot = self:GetID() + + + if kb.currentProfile.buttons[slot] then + kb.currentProfile.buttons[slot] = nil + end + if self.command then + kb.currentProfile.commands[self.command] = nil + end + local talentName = self.actionName + if self.actionType == 'macro' then + talentName = GetMacroSpell(self.actionID) + end + -- remove any matching talent data + if talentName and kb.currentProfile.talents[talentName] then + kb.currentProfile.talents[talentName] = nil + end + local droppedKeys = {} + + -- doing removal in second loop to avoid possible iterator shenanigans + for k,v in pairs(kb.currentProfile.bindings) do + if v == self.command then + tinsert(droppedKeys, k) + end + end + if #droppedKeys >=1 then + for i, k in ipairs(droppedKeys) do + kb.currentProfile.bindings[k] = nil + end + end + + self.isAvailable = nil + self.dynamicType = nil + self.bindingText = nil + self.statusText = nil + self.command = nil + self.iconPath = nil + self.actionType = nil + self.actionID = nil + self.actionName = nil + self.pickupSlot = nil + self.pickupBook = nil + self.macroName = nil + self.profile = nil + self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) + self:EnableKeyboard(false) + self:SetScript('OnKeyDown', nil) + self.bindingText = nil + self.icon:SetTexture(nil) + self.ignoreTexture:Hide() + +end + +local spells = {} +local SkeletonKey_GetGenericSpell = function(spellName, spellID, icon) + if not spells[spellID] then + spells[spellID] = {} + spells[spellID].actionType = 'spell' + spells[spellID].actionID = spellID + spells[spellID].actionName = spellName + spells[spellID].iconPath = icon + spells[spellID].statusText = '|cFFBBBBBBSpell|r' + spells[spellID].dynamicType = nil + end + return spells[spellID] +end + +local tempInfo = {} +-- tries to resolve spells from talent overrides/profession book/etc +local dynamicTypes = {['profession'] = 'ProfessionCache', ['talent'] = 'TalentCache', ['petaction'] = 'PetInfoCache'} +local SkeletonKey_GetSpellDetails = function(self) + + local spellName, spellID, command, icon = self.actionName, self.actionID, self.command, self.iconPath + + + cprint(' In:', spellName, spellID, command) + cprint(GetSpellInfo(spellName or spellID)) + local internalName, _, internalIcon, _, _, _, _ = GetSpellInfo(spellName or spellID) + local isAvailable = internalName and true + + if internalName and (internalName ~= spellName) then + -- it's a binding for the originating spell, leave it as is + cprint(' |cFFFF4400spell is an override(', internalName, '~=', spellName,') leave the name info alone') + self.statusText = '|cFFFFFF00Spell|r' + self.isAvailable = true + return + end + + -- let's us match spells replaced by talents + local info = kb.DynamicSpells[internalName or spellName] + if not info then + local dynamicType, dynamicIndex, dynamicSubIndex = command:match("(%a+)_(%S+)_(%S+)") + if kb.DynamicSpells[dynamicType] then + cprint('|cFFFF4400resolving dynamic type index:', internalName, spellName, command) + dynamicIndex = tonumber(dynamicIndex) + dynamicSubIndex = tonumber(dynamicSubIndex) + local cache = kb.DynamicSpells[dynamicType] + cprint('type:', dynamicType) + if dynamicIndex and cache[dynamicIndex] then + info = kb.DynamicSpells[dynamicType][dynamicIndex] + cprint('index:', dynamicIndex) + if dynamicSubIndex and info[dynamicSubIndex] then + info = info[dynamicSubIndex] + cprint('sub-index:', dynamicSubIndex) + end + isAvailable = true + end + end + if not info then + info = SkeletonKey_GetGenericSpell(spellName, spellID, internalIcon or icon) + end + end + info.isAvailable = isAvailable + + cprint('|cFF00FF88SpellDetails:|r', info.actionName, info.actionID, info.dynamicType) + for k,v in pairs(info) do + cprint(' ',k,v) + self[k] = v + end + + return info +end + +--- Assigns the slot via table copy; any manipulations from this point are temporary and +function skb:SetSlot(slotInfo) + print('slot info', self:GetID()) + + for k,v in pairs(slotInfo) do + print(' -', k, v) + self[k] = v + end + self.dynamicType = slotInfo.dynamicType + local command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook + = self.command, self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType + + + local slot = self:GetID() + local isBound = false + print('|cFFFFFF00SetSlot|r:', self:GetID()) + if self.command then + + isBound = kb.IsCommandBound(self, self.command) + if actionType == 'spell' then + local info = SkeletonKey_GetSpellDetails(self) + name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook = self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType + + elseif actionType == 'petaction' then + self.dynamicType = 'petaction' + local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)') + + if kb.PetCache.subtext[specialType] then + + local info = kb.PetCache.subtext[specialType][tonumber(specialNum)] + if info then + print('***dynamic pet skill', specialType, specialNum) + --[[ i, spellName, subText, spellID, texture, specialNum[subText ]] + + for k,v in pairs(info) do + self[k] = v + end + end + + end + self.statusText = 'Pet Action' + self.isAvailable = (kb.PetCache.spellslot[name]) + elseif actionType == 'macro' then + if actionID then + -- look for corruption + local nameByID, _, bodyByID = GetMacroInfo(actionID) + local nameByName, _, bodyByName = GetMacroInfo(name) + if (nameByID ~= name) or (bodyByID ~= macroText) then + local prevIndex = actionID + actionID = GetMacroIndexByName(name) + local firstName, _, firstBody = GetMacroInfo(actionID) + if (firstName ~= name) or (firstBody ~= macroText) then + -- go even deeper + for i = 1, GetNumMacros() do + local searchName, _ , searchBody = GetMacroInfo(i) + if (searchName == name) and (searchBody == macroText) then + -- complete match + actionID = i + break + elseif (searchName == name) or (searchBody == macroText) then + -- partial match, continue the search + actionID = i + end + end + end + kb:print('Macro index changed: |cFFFFFF00', actionType, '|r', name, '(was '..tostring(prevIndex)..', now '..tostring(actionID)..')') + end + else + actionID = GetMacroIndexByName(name) + end + self.statusText = 'Macro' + self.isAvailable = true + else + if not actionID then + actionID = command:match("^KeyBinderMacro:(.+)") + end + self.isAvailable = true + end + + if self.isAvailable then + local oldCommand = command + command = kb.LoadBinding(self) + if oldCommand ~= command then + print('|cFFFF4400fixing command string', actionType, actionID, name) + kb.currentProfile.bound[oldCommand] = nil + kb.currentProfile.bound[command] = slot + for k,v in pairs(kb.currentProfile.bindings) do + if v == oldCommand then + kb.currentProfile.bindings[k] = command + end + end + end + end + + + actionID = actionID or 0 + self:EnableKeyboard(true) + + -- this is done to keep legacy key-values from breaking algorithm assumptions + local slotInfo = { + command = command, + actionName = name, + iconPath = icon, + actionID = actionID, + actionType = actionType, + macroName = macroName, + macroText = macroText, + spellbookSlot = pickupSlot, + spellbookType = pickupBook, + assignedKeys = {GetBindingKey(command)} + } + kb.currentProfile.buttons[slot] = slotInfo + + -- Clean up conflicting entries for loaded button + local previous = kb.currentProfile.commands[command] + if previous ~= slot and kb.buttons[previous] then + kb.ReleaseSlot(kb.buttons[previous]) + end + + local binds = {GetBindingKey(command) } + if self.isAvailable and (#binds >= 1) then + local found + for i, key in ipairs(binds) do + if not tContains(self.assignedKeys, key) then + tinsert(self.assignedKeys, key) + kb.currentProfile.bindings[key] = command + kb.currentProfile.bound[command] = true + found = true + end + end + if found then + kb:print('Recovered key binding for', name) + end + end + + kb.currentProfile.commands[command] = slot + end + + + + self.isBound = isBound + self.pickupSlot = pickupSlot + self.pickupBook = pickupBook + self.macroText = macroText + self.macroName = macroName + self.actionType = actionType + self.actionID = actionID + self.actionName = name + self.command = command + self.iconPath = icon + self.profile = kb.db.bindMode + self:RegisterForDrag('LeftButton') +end + +kb.GetCommandAction = function(command) + for i, data in ipairs(kb.loadedProfiles) do + if data.commands[command] then + if data.buttons[data.commands[command]] then + local _, _, _, actionType, actionID = unpack(data.buttons[data.commands[command]]) + return actionType, actionID + end + end + end +end +