Nenue@70: -- SkeletonKey Nenue@70: -- KeyButton.lua Nenue@70: -- Created: 7/28/2016 11:26 PM Nenue@70: -- %file-revision% Nenue@70: -- Deals with display and manipulation of binding slots Nenue@70: Nenue@70: local _, kb = ... Nenue@74: local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('KeyButton', ...) end or function() end Nenue@70: local cprint = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('Cfg', ...) end or function() end Nenue@70: local L = kb.L Nenue@70: local type, tonumber, tostring, tinsert, tremove, ipairs, pairs = type, tonumber, tostring, tinsert, tremove, ipairs, pairs Nenue@70: local _G, unpack, select, tostring = _G, unpack, select, tostring Nenue@70: local GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo = GetSpellBookItemName, GetSpellBookItemTexture, GetSpellBookItemInfo, GetPetActionInfo Nenue@70: local GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon = GetSpellInfo, GetMacroInfo, GetItemInfo, GetItemIcon Nenue@70: local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor Nenue@70: local GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown, IsShiftKeyDown = GetSpellTexture, IsTalentSpell, GetMacroIndexByName, IsAltKeyDown, IsControlKeyDown,IsShiftKeyDown Nenue@70: local GetBindingKey, GetProfessionInfo = GetBindingKey, GetProfessionInfo Nenue@70: local GetMountInfoByID, GetPetInfoByPetID = C_MountJournal.GetMountInfoByID, C_PetJournal.GetPetInfoByPetID Nenue@70: local skb = SkeletonKeyButtonMixin Nenue@70: local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION, CURSOR_TEXTURE Nenue@70: local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 Nenue@70: local BORDER_UNASSIGNED = {0.6,0.6,0.6,1} Nenue@70: local BORDER_ASSIGNED = {1,1,1,1} Nenue@70: local BORDER_DYNAMIC = {1,1,0,1} Nick@80: local BORDER_PENDING = {1,0.5,0,1} Nick@80: local BORDER_REPLACED = {0,1,.5,1} Nenue@70: local BUTTON_HEADERS = { Nenue@70: ['spell'] = SPELLS, Nenue@70: ['macro'] = MACRO, Nenue@70: ['petaction'] = PET, Nenue@70: ['mount'] = MOUNT, Nenue@70: ['battlepet'] = BATTLEPET, Nenue@70: Nenue@70: Nenue@70: [5] = PROFESSIONS_FIRST_AID, Nenue@70: [7] = PROFESSIONS_COOKING, Nenue@70: [9] = PROFESSIONS_FISHING, Nenue@70: [10] = PROFESSIONS_ARCHAEOLOGY, Nenue@70: Nenue@70: } Nenue@70: Nenue@70: local PROFESSION_HEADERS = { Nenue@70: [1] = 'Profession 1', Nenue@70: [2] = 'Profession 2', Nenue@70: [3] = 10, Nenue@70: [4] = 7, Nenue@70: [5] = 9, Nenue@70: [6] = 5 Nenue@70: } Nenue@70: Nenue@81: -- Spell replacements that can't be easily detected Nenue@81: local TALENT_SPELLS = { Nenue@81: -- Shimmer Nenue@81: [212653] = { Nenue@81: actionName = 'Blink', Nenue@81: actionID = 1953, Nenue@83: icon = [[Interface\\ICONS\\spell_arcane_blink]] Nenue@81: }, Nenue@81: -- Sidewinders; have to assume arcane sadly Nenue@81: [214579] = { Nenue@81: actionName = 'Arcane Shot', Nenue@81: actionID = 185358, Nenue@83: icon = [[Interface\\ICONS\\ability_impalingbolt]] Nenue@81: }, Nenue@81: -- Serenity Nenue@81: [152173] = { Nenue@81: actionName = 'Storm, Earth, and Fire', Nenue@83: actionID = 137639, Nenue@83: icon = [[Interface\\ICONS\\spell_nature_giftofthewild]] Nenue@83: }, Nenue@83: -- Carve Nenue@83: [212436] = { Nenue@83: actionName = 'Carve', Nenue@83: actionID = 187708, Nenue@83: icon = [[Interface\\ICONS\\ability_hunter_carve]] Nenue@81: } Nenue@81: } Nenue@81: Nenue@70: Nenue@93: -- This is needed to identify spells that aren't reflected by GetCursorInfo() Nenue@70: kb.OnPickupPetAction = function(slot, ...) Nenue@93: local pickupType, texture, slot = GetCursorInfo() Nenue@93: print('|cFFFF4400PickupPetAction|r', GetCursorInfo()) Nenue@70: Nenue@93: CURSOR_SPELLSLOT = slot Nenue@93: CURSOR_BOOKTYPE = 'pet' Nenue@93: CURSOR_TEXTURE = texture Nenue@70: Nenue@93: print('[cursor book]', CURSOR_BOOKTYPE, CURSOR_SPELLSLOT, 'texture:', CURSOR_TEXTURE) Nenue@70: Nenue@70: end Nenue@70: Nenue@70: kb.OnPickupSpellBookItem = function(slot, bookType) Nenue@70: print('|cFFFF4400PickupSpellBookItem('.. tostring(slot).. ', '..tostring(bookType)..')') Nenue@70: CURSOR_SPELLSLOT = slot Nenue@70: CURSOR_BOOKTYPE = bookType Nenue@70: CURSOR_TEXTURE = GetSpellBookItemTexture(slot, bookType) Nenue@93: print('[cursor book]', CURSOR_BOOKTYPE, CURSOR_SPELLSLOT, 'texture:', CURSOR_TEXTURE) Nenue@70: end Nenue@70: Nenue@70: kb.CreateHooks = function() Nenue@70: hooksecurefunc("PickupSpellBookItem", kb.OnPickupSpellBookItem) Nenue@70: hooksecurefunc("PickupPetAction", kb.OnPickupPetAction) Nenue@70: end Nenue@70: Nenue@70: Nenue@70: Nenue@70: function skb:OnLoad() Nenue@70: self:EnableKeyboard(false) Nenue@70: self:EnableMouse(true) Nenue@70: self:RegisterForDrag('LeftButton') Nenue@70: self:RegisterForClicks('AnyUp') Nenue@70: end Nenue@70: Nenue@70: function skb:OnEnter() Nenue@70: if not self.command then Nenue@70: return Nenue@70: end Nenue@70: if self.statusText then Nenue@70: SkeletonKey.statustext:SetText(self.statusText .. ': '..self.actionName) Nenue@70: SkeletonKey.bindingstext:SetText(self.bindingText) Nenue@70: end Nenue@70: Nenue@70: Nenue@70: if kb.db.hoverInput and kb.saveTarget ~= self then Nenue@70: self:GetParent():ActivateSlot(self) Nenue@70: SkeletonKey:Update() Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: function skb:OnLeave() Nenue@70: if kb.db.hoverInput and kb.saveTarget == self then Nenue@70: self:GetParent():DeactivateSlot(self) Nenue@70: SkeletonKey:Update() Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: function skb:OnClick(click) Nenue@70: print(self:GetName(), 'OnMouseDown', click) Nenue@70: local cursorType = GetCursorInfo() Nenue@70: if click == 'LeftButton' then Nenue@70: if cursorType then Nenue@70: self:DropToSlot() Nenue@70: else Nenue@76: if self.command then Nenue@70: if IsShiftKeyDown() then Nenue@70: kb.db.stickyMode = true Nenue@70: KeyBinderStickyMode:SetChecked(true) Nenue@70: end Nenue@70: self:GetParent():ActivateSlot(self) Nenue@70: end Nenue@70: end Nenue@70: elseif click == 'RightButton' then Nenue@70: self:ReleaseSlot() Nenue@70: else Nick@80: SkeletonKey:ProcessInput(strupper(click)) Nenue@70: end Nenue@70: SkeletonKey:Update() Nenue@70: end Nenue@70: Nenue@70: function skb:OnDragStart() Nenue@70: self:PickupSlot() Nenue@70: end Nenue@70: Nenue@70: function skb:OnReceiveDrag(...) Nenue@70: self:DropToSlot() Nenue@70: end Nenue@70: Nenue@70: function skb:DropToSlot () Nenue@70: local actionType, actionID, subType, subData = GetCursorInfo() Nenue@93: print(self:GetName(),'|cFF0088FFDropToSlot|r', actionType, actionID, subType, subData) Nenue@70: if actionType then Nenue@93: print('##', actionType) Nenue@70: Nenue@70: if actionType == 'flyout' then Nenue@93: print('## flyout button, abort') Nenue@70: ClearCursor() Nenue@70: ResetCursor() Nenue@70: return Nenue@70: end Nenue@70: Nenue@70: Nenue@74: local name, icon, _, macroName, macroText Nenue@70: local pickupID, pickupBook Nenue@70: Nenue@93: if actionType == 'spell' then Nenue@93: local realName = GetSpellInfo(subData) Nenue@93: name, _, icon, _, _, _, actionID = GetSpellInfo(subData) Nenue@83: Nenue@93: if TALENT_SPELLS[actionID] then Nenue@93: name = TALENT_SPELLS[actionID].actionName Nenue@93: actionID = TALENT_SPELLS[actionID].actionID Nenue@93: icon = TALENT_SPELLS[actionID].icon Nenue@93: end Nenue@70: Nenue@93: elseif actionType == 'macro' then Nenue@93: name, icon, macroText = GetMacroInfo(actionID) Nenue@93: macroName = name Nenue@93: elseif actionType == 'petaction' then Nenue@91: Nenue@91: Nenue@91: Nenue@93: --local spellType, spellID = GetSpellBookItemInfo(actionID, BOOKTYPE_PET) Nenue@93: local spellName, spellText = GetSpellBookItemName(actionID, BOOKTYPE_PET) Nenue@70: Nenue@93: if subType then Nenue@93: actionID = subType Nenue@93: end Nenue@70: Nenue@70: Nenue@93: Nenue@93: print('##PET', actionID, '=>', spellName, spellText) Nenue@93: pickupID = actionID Nenue@93: name = GetSpellBookItemName(actionID, BOOKTYPE_PET) Nenue@93: icon = GetSpellBookItemTexture(actionID, BOOKTYPE_PET) Nenue@93: actionID = name Nenue@93: pickupBook = BOOKTYPE_PET Nenue@93: Nenue@93: elseif actionType == 'mount' then Nenue@93: if subType == 0 then Nenue@93: name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) Nenue@93: actionID = 0 Nenue@93: else Nenue@93: name, _, icon = GetMountInfoByID(actionID) Nenue@70: end Nenue@93: elseif actionType == 'item' then Nenue@93: name = GetItemInfo(actionID) Nenue@93: icon = GetItemIcon(actionID) Nenue@93: elseif actionType == 'battlepet' then Nenue@70: Nenue@93: local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = GetPetInfoByPetID(actionID) Nenue@93: name = customName or petName Nenue@93: icon = petIcon Nenue@93: Nenue@93: end Nenue@93: local _, macroBody, command = kb.RegisterAction(actionType, actionID, name) Nenue@93: local slotInfo = { Nenue@93: command = command, Nenue@93: actionName = name, Nenue@93: iconPath = icon, Nenue@93: actionType = actionType, Nenue@93: actionID = actionID, Nenue@93: macroName = macroName, Nenue@93: macroText = macroText or macroBody, Nenue@93: spellbookSlot = pickupID, Nenue@93: spellbookType = pickupBook, Nenue@93: assignedKeys = {GetBindingKey(command)} Nenue@93: } Nenue@93: Nenue@93: local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) Nenue@91: if isAssigned then Nenue@91: local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] Nenue@91: popup.slot = self Nenue@91: popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?" Nenue@91: popup.oldProfile = assignedBy Nenue@91: popup.args = {slotInfo} Nenue@91: SkeletonKey:SetScript('OnMouseWheel', nil) -- disable scrolling Nenue@91: StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') Nenue@70: else Nenue@91: kb.currentProfile.buttons[self:GetID()] = slotInfo Nenue@91: kb.LoadBinding(slotInfo) Nenue@91: self:SetSlot(slotInfo) Nenue@91: self:UpdateSlot() Nenue@91: self.active = nil Nenue@91: ClearCursor() Nenue@91: ResetCursor() Nenue@70: end Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: Nenue@91: Nenue@70: do Nenue@70: local PickupAction = { Nenue@70: spell = _G.PickupSpell, Nenue@70: petaction = Nenue@70: function(...) Nenue@70: -- needs to be enclosed to acquire hooksecurefunc effects Nenue@70: _G.PickupSpellBookItem(...) Nenue@70: end, Nenue@70: macro = _G.PickupMacro, Nenue@70: item = _G.PickupItem, Nenue@70: mount = _G.C_MountJournal.Pickup Nenue@70: } Nenue@70: local GetPickupValue = { Nenue@70: spell = function(self) return select(7, GetSpellInfo(self.actionID)) end, Nenue@70: petaction = function(self) return self.pickupSlot, self.pickupBook end, Nenue@70: } Nenue@70: function skb:PickupSlot () Nenue@70: if not (self.command and self.isAvailable) then Nenue@70: return Nenue@70: end Nenue@70: print(self.actionType) Nenue@70: if self.actionType == 'spell' then Nenue@70: -- It can't be picked up if SpellInfo(name) returns void Nenue@70: local dummy = GetSpellInfo(self.actionName) Nenue@70: if not dummy then Nenue@70: return Nenue@70: end Nenue@70: end Nenue@70: if PickupAction[self.actionType] then Nenue@70: if GetPickupValue[self.actionType] then Nenue@70: PickupAction[self.actionType](GetPickupValue[self.actionType](self)) Nenue@70: else Nenue@70: PickupAction[self.actionType](self.actionID) Nenue@70: end Nenue@70: self:ReleaseSlot() Nenue@70: self:UpdateSlot() Nenue@70: end Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: Nenue@70: Nenue@70: Nenue@70: --- Updates profile assignment and button contents Nenue@70: function skb:UpdateSlot (force) Nenue@70: local slot = self:GetID() Nenue@70: Nenue@70: if force then Nenue@70: if kb.currentProfile.buttons[slot] then Nenue@70: print('loading in', slot, kb.db.bindMode) Nenue@70: self:SetSlot(kb.currentProfile.buttons[slot]) Nenue@70: else Nenue@70: self:ReleaseSlot() Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: local borderType = BORDER_UNASSIGNED Nick@80: local displayName = self.actionName Nick@80: local displayTexture = self.iconPath Nick@80: local altName, altTexture Nenue@70: if self.command then Nenue@70: Nick@80: print('|cFFFF4400:', self.actionName, #self.assignedKeys, table.concat(self.assignedKeys, ',')) Nick@80: print('|cFF00FF88:', self.isAvailable, self.actionID) Nick@80: Nenue@72: self.bindingText= kb.BindingString(unpack(self.assignedKeys)) Nick@80: Nenue@70: if not self.isAvailable then Nenue@70: borderType = BORDER_DYNAMIC Nenue@70: self.ignoreTexture:Show() Nenue@70: else Nenue@70: self.ignoreTexture:Hide() Nenue@70: Nenue@70: if self.pending then Nenue@70: borderType = BORDER_PENDING Nenue@70: elseif self.dynamicType then Nenue@70: borderType = BORDER_DYNAMIC Nenue@70: else Nenue@70: borderType = BORDER_ASSIGNED Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: if self.actionType == 'macro' then Nenue@70: self.macro:Show() Nenue@70: else Nenue@70: self.macro:Hide() Nenue@70: if self.actionType == 'spell' then Nick@80: altName, _, altTexture = GetSpellInfo(self.actionName) Nick@80: self.isAvailable = displayName and true or false Nick@80: if altName and (altName ~= self.actionName) then Nick@80: displayName = '|cFFFFFF00'..altName..'|r ('..self.actionName..')' Nick@80: displayTexture = altTexture Nick@80: borderType = BORDER_REPLACED Nick@80: end Nick@80: Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: Nenue@70: if self.dynamicType == 'profession' then Nenue@70: if self.isAvailable then Nenue@81: self.statusText = '|cFFFFFF00Profession Slot|r ' .. tostring(self.dynamicIndex) .. '-' .. tostring(self.dynamicSubIndex) Nenue@70: else Nenue@70: Nenue@70: self.statusText = '|cFFFF4400'..PROFESSION_HEADERS[self.dynamicIndex]..'|r' Nenue@70: self.actionName = '(#'..self.dynamicIndex..')' Nenue@70: end Nenue@70: elseif self.dynamicType == 'talent' then Nenue@70: self.statusText = '|cFF00FFFF'.. TALENT .. '|r' Nenue@70: end Nenue@70: Nenue@70: local locked, layer = kb.IsCommandBound(self) Nenue@70: if locked then Nenue@70: self.icon:SetAlpha(0.5) Nenue@70: else Nenue@70: self.icon:SetAlpha(1) Nenue@70: end Nenue@70: Nenue@70: Nenue@70: print('|cFF00BBFFUpdateSlot|r:', '['..slot..'] =', self.command, self.bindingText, self.dynamicType, self.isAvailable, self.actionID) Nenue@70: Nenue@70: end Nenue@70: Nenue@70: if not self.isAvailable then Nenue@74: self.bind:SetTextColor(.7,.7,.7,1) Nenue@74: self.ignoreTexture:SetShown(self.command and true) Nenue@74: self.icon:SetVertexColor(.5,.5,.5) Nenue@70: else Nenue@74: self.ignoreTexture:SetShown(false) Nenue@70: self.bind:SetTextColor(1,1,1,1) Nenue@74: self.icon:SetVertexColor(1,1,1) Nenue@70: end Nenue@70: Nenue@70: Nenue@70: if kb.saveTarget and kb.saveTarget ~= self then Nenue@70: self:SetAlpha(0.25) Nenue@70: else Nenue@70: Nenue@70: self:SetAlpha(1) Nenue@70: end Nenue@70: Nenue@70: --self.alert:SetShown(self.command and not self.isBound) Nenue@70: Nick@80: self.icon:SetTexture(displayTexture) Nenue@70: Nenue@70: self.border:SetColorTexture(unpack(borderType)) Nenue@70: self.header:SetText(self.statusText) Nenue@70: self.bind:SetText(self.bindingText) Nick@80: self.details:SetText(displayName) Nenue@70: end Nenue@70: Nenue@70: --- Resets button command Nenue@70: function skb:ReleaseSlot () Nenue@70: local slot = self:GetID() Nenue@70: Nick@80: -- keep right click from deleting an assignment during bind mode Nick@80: if kb.saveTarget == self then Nick@80: self:GetParent():DeactivateSlot(self) Nick@80: return Nick@80: end Nenue@70: Nenue@70: if kb.currentProfile.buttons[slot] then Nenue@70: kb.currentProfile.buttons[slot] = nil Nenue@70: end Nenue@70: if self.command then Nenue@70: kb.currentProfile.commands[self.command] = nil Nenue@70: end Nenue@70: local talentName = self.actionName Nenue@70: if self.actionType == 'macro' then Nenue@70: talentName = GetMacroSpell(self.actionID) Nenue@70: end Nenue@76: Nenue@70: local droppedKeys = {} Nenue@70: Nenue@70: -- doing removal in second loop to avoid possible iterator shenanigans Nenue@70: for k,v in pairs(kb.currentProfile.bindings) do Nenue@70: if v == self.command then Nenue@70: tinsert(droppedKeys, k) Nenue@70: end Nenue@70: end Nenue@70: if #droppedKeys >=1 then Nenue@70: for i, k in ipairs(droppedKeys) do Nenue@70: kb.currentProfile.bindings[k] = nil Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: self.isAvailable = nil Nenue@70: self.dynamicType = nil Nenue@70: self.bindingText = nil Nenue@70: self.statusText = nil Nenue@70: self.command = nil Nenue@70: self.iconPath = nil Nenue@70: self.actionType = nil Nenue@70: self.actionID = nil Nenue@70: self.actionName = nil Nenue@70: self.pickupSlot = nil Nenue@70: self.pickupBook = nil Nenue@70: self.macroName = nil Nenue@70: self.profile = nil Nenue@70: self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) Nenue@70: self:EnableKeyboard(false) Nenue@70: self:SetScript('OnKeyDown', nil) Nenue@70: self.bindingText = nil Nenue@70: self.icon:SetTexture(nil) Nenue@70: self.ignoreTexture:Hide() Nenue@70: Nenue@70: end Nenue@70: Nenue@70: --- Assigns the slot via table copy; any manipulations from this point are temporary and Nenue@70: function skb:SetSlot(slotInfo) Nenue@70: print('slot info', self:GetID()) Nenue@70: Nenue@70: for k,v in pairs(slotInfo) do Nenue@70: print(' -', k, v) Nenue@70: self[k] = v Nenue@70: end Nenue@70: self.dynamicType = slotInfo.dynamicType Nenue@70: local command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook Nenue@70: = self.command, self.actionName, self.iconPath, self.actionType, self.actionID, self.macroName, self.macroText, self.spellbookSlot, self.spellbookType Nenue@70: Nenue@70: Nenue@70: local slot = self:GetID() Nenue@70: local isBound = false Nenue@70: print('|cFFFFFF00SetSlot|r:', self:GetID()) Nenue@70: if self.command then Nenue@70: Nenue@70: isBound = kb.IsCommandBound(self, self.command) Nenue@70: if actionType == 'spell' then Nenue@74: local info = kb.ResolveSpellSlot(self) Nenue@70: 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: self.isAvailable = info and info.isAvailable Nenue@70: elseif actionType == 'petaction' then Nenue@70: self.dynamicType = 'petaction' Nenue@70: local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)') Nenue@70: Nenue@70: if kb.PetCache.subtext[specialType] then Nenue@70: Nenue@70: local info = kb.PetCache.subtext[specialType][tonumber(specialNum)] Nenue@70: if info then Nenue@70: print('***dynamic pet skill', specialType, specialNum) Nenue@70: --[[ i, spellName, subText, spellID, texture, specialNum[subText ]] Nenue@70: Nenue@70: for k,v in pairs(info) do Nenue@70: self[k] = v Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: end Nenue@70: self.statusText = 'Pet Action' Nenue@70: self.isAvailable = (kb.PetCache.spellslot[name]) Nenue@70: elseif actionType == 'macro' then Nenue@70: if actionID then Nenue@74: Nenue@74: -- Update stored information if it mis-matches Nenue@70: local nameByID, _, bodyByID = GetMacroInfo(actionID) Nenue@74: --print(bodyByID, "\n", macroText) Nenue@70: if (nameByID ~= name) or (bodyByID ~= macroText) then Nenue@74: --kb:print('mismatches for slot', self:GetID(), actionID, ((nameByID ~= name) and 'name' or ''), ((bodyByID ~= macroText) and 'body' or '')) Nenue@74: local matchID, matchName, matchBody, hasMultiple Nenue@74: local roughResult = "" Nenue@74: Nenue@74: local newID = GetMacroIndexByName(name) Nenue@74: local firstName, _, firstBody = GetMacroInfo(newID) Nenue@70: if (firstName ~= name) or (firstBody ~= macroText) then Nenue@74: Nenue@74: Nenue@70: -- go even deeper Nenue@74: local numAccount, numCharacter = GetNumMacros() Nenue@74: local searchID = 1 Nenue@74: while searchID <= (120+numCharacter) do Nenue@74: --kb:print(searchID) Nenue@74: Nenue@74: Nenue@74: local searchName, _ , searchBody = GetMacroInfo(searchID) Nenue@70: if (searchName == name) and (searchBody == macroText) then Nenue@74: --kb:print('definitely', matchID, searchName, '\n', searchBody) Nenue@70: -- complete match Nenue@74: matchID = searchID Nenue@74: matchName = searchName Nenue@74: matchBody = searchBody Nenue@70: break Nenue@70: elseif (searchName == name) or (searchBody == macroText) then Nenue@70: -- partial match, continue the search Nenue@74: Nenue@74: if matchID then Nenue@74: hasMultiple = true Nenue@74: roughResult = roughResult .. "\n" .. tostring(searchID) .. ':'..tostring(searchName) Nenue@74: end Nenue@74: Nenue@74: matchID = searchID Nenue@74: matchName = searchName Nenue@74: matchBody = searchBody Nenue@74: --kb:print('possibly', matchID, matchName, '\n', matchBody) Nenue@70: end Nenue@74: Nenue@74: if searchID == numAccount then Nenue@74: searchID = 120 Nenue@74: end Nenue@74: searchID = searchID + 1 Nenue@70: end Nenue@74: else Nenue@74: matchID = newID Nenue@74: matchName = firstName Nenue@74: matchBody = firstBody Nenue@70: end Nenue@72: Nenue@74: --kb:print(matchID, hasMultiple) Nenue@74: if hasMultiple then Nenue@74: kb:print('Macro assignment in slot #'..tostring(self:GetID())..' has multiple possible indexes:\nSaved Info: '..tostring(actionID)..'/'..tostring(name)..'\n|cFFFFFF00', roughResult) Nenue@74: elseif matchID then Nenue@74: 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.') Nenue@74: actionID = matchID Nenue@74: name = matchName Nenue@74: macroName = matchName Nenue@74: macroText = matchBody Nenue@74: end Nenue@70: end Nenue@70: else Nenue@70: actionID = GetMacroIndexByName(name) Nenue@70: end Nenue@74: self.statusText = 'Macro ' .. tostring(actionID) Nenue@70: self.isAvailable = true Nenue@70: else Nenue@70: if not actionID then Nenue@70: actionID = command:match("^KeyBinderMacro:(.+)") Nenue@70: end Nenue@70: self.isAvailable = true Nenue@70: end Nenue@70: Nenue@70: if self.isAvailable then Nenue@72: --[[ Nenue@72: local checkCommand = command Nenue@72: checkCommand = kb.LoadBinding(self) Nenue@72: if checkCommand and (checkCommand ~= command) then Nenue@70: print('|cFFFF4400fixing command string', actionType, actionID, name) Nenue@72: kb.currentProfile.bound[command] = nil Nenue@72: kb.currentProfile.bound[checkCommand] = slot Nenue@70: for k,v in pairs(kb.currentProfile.bindings) do Nenue@72: if v == command then Nenue@72: kb.currentProfile.bindings[k] = checkCommand Nenue@70: end Nenue@70: end Nenue@70: end Nenue@72: --]] Nenue@70: end Nenue@70: Nenue@70: Nenue@70: actionID = actionID or 0 Nenue@70: self:EnableKeyboard(true) Nenue@70: Nenue@70: -- this is done to keep legacy key-values from breaking algorithm assumptions Nick@80: print('assigned', table.concat(slotInfo.assignedKeys,', ')) Nick@80: Nick@80: if #slotInfo.assignedKeys == 0 then Nick@80: print('updating assigned table to:', GetBindingKey(command)) Nick@80: slotInfo.assignedKeys = {GetBindingKey(command) } Nick@80: end Nick@80: Nick@80: self.assignedKeys = slotInfo.assignedKeys Nenue@71: Nenue@70: local slotInfo = { Nenue@70: command = command, Nenue@70: actionName = name, Nenue@70: iconPath = icon, Nenue@70: actionID = actionID, Nenue@70: actionType = actionType, Nenue@70: macroName = macroName, Nenue@70: macroText = macroText, Nenue@70: spellbookSlot = pickupSlot, Nenue@70: spellbookType = pickupBook, Nenue@71: assignedKeys = slotInfo.assignedKeys, Nenue@71: dynamicType = self.dynamicType, Nenue@71: dynamicID = self.dynamicID, Nenue@71: dynamicIndex = self.dynamicIndex, Nenue@71: dynamicSubIndex = self.dynamicSubIndex Nenue@70: } Nenue@70: kb.currentProfile.buttons[slot] = slotInfo Nenue@70: Nenue@70: -- Clean up conflicting entries for loaded button Nenue@70: local previous = kb.currentProfile.commands[command] Nenue@70: if previous ~= slot and kb.buttons[previous] then Nenue@70: kb.ReleaseSlot(kb.buttons[previous]) Nenue@70: end Nenue@70: Nenue@70: local binds = {GetBindingKey(command) } Nenue@70: if self.isAvailable and (#binds >= 1) then Nenue@70: local found Nenue@70: for i, key in ipairs(binds) do Nenue@70: if not tContains(self.assignedKeys, key) then Nenue@70: tinsert(self.assignedKeys, key) Nenue@70: kb.currentProfile.bindings[key] = command Nenue@70: kb.currentProfile.bound[command] = true Nenue@70: found = true Nenue@70: end Nenue@70: end Nenue@70: if found then Nenue@70: kb:print('Recovered key binding for', name) Nenue@70: end Nenue@70: end Nenue@70: Nenue@70: kb.currentProfile.commands[command] = slot Nenue@70: end Nenue@70: Nenue@71: --self.assignedKeys = slotInfo.assignedKeys Nenue@70: self.isBound = isBound Nenue@70: self.pickupSlot = pickupSlot Nenue@70: self.pickupBook = pickupBook Nenue@70: self.macroText = macroText Nenue@70: self.macroName = macroName Nenue@70: self.actionType = actionType Nenue@70: self.actionID = actionID Nenue@70: self.actionName = name Nenue@70: self.command = command Nenue@70: self.iconPath = icon Nenue@70: self.profile = kb.db.bindMode Nenue@70: self:RegisterForDrag('LeftButton') Nenue@74: Nenue@74: return slotInfo Nenue@70: end Nenue@70: Nenue@70: kb.GetCommandAction = function(command) Nenue@70: for i, data in ipairs(kb.loadedProfiles) do Nenue@70: if data.commands[command] then Nenue@70: if data.buttons[data.commands[command]] then Nenue@70: local _, _, _, actionType, actionID = unpack(data.buttons[data.commands[command]]) Nenue@70: return actionType, actionID Nenue@70: end Nenue@70: end Nenue@70: end Nenue@70: end Nenue@70: