diff SkeletonKey/KeyButton.lua @ 27:73df13211b22

- actionbar hotkey text properly updates after hotkeys get switched - remove a unused function call
author Nenue
date Tue, 02 Aug 2016 12:33:13 -0400
parents SkeletonKey/KeySlot.lua@f6dd297cb812
children bb160c04de88
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SkeletonKey/KeyButton.lua	Tue Aug 02 12:33:13 2016 -0400
@@ -0,0 +1,656 @@
+-- SkeletonKey
+-- KeyButton.lua
+-- Created: 7/28/2016 11:26 PM
+-- %file-revision%
+-- Code dealing with the slot button innards; they are invoked by frame script and should only chain to Set/Release
+
+local kb, print = LibStub('LibKraken').register(KeyBinder, 'Slot')
+local L = kb.L
+local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION, CURSOR_TEXTURE
+local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
+local BORDER_UNASSIGNED = {0.2,0.2,0.2,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,
+
+}
+
+-- 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
+
+
+kb.DropToSlot = function(self)
+  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 = C_MountJournal.GetMountInfoByID(actionID)
+      end
+    elseif actionType == 'item' then
+      name = GetItemInfo(actionID)
+      icon = GetItemIcon(actionID)
+      actionID = name
+    elseif actionType == 'battlepet' then
+
+      local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail);
+      name = customName or petName
+      icon = petIcon
+
+    end
+    local macroName, macroText, command = kb.RegisterAction(actionType, actionID, name)
+
+
+    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 = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook }
+      kb:SetScript('OnMouseWheel', nil) -- disable scrolling
+      StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
+    else
+      kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook)
+      kb.UpdateSlot(self)
+      self.active = nil
+      ClearCursor()
+      ResetCursor()
+    end
+  end
+end
+
+
+do
+  local PickupAction = {
+    spell = _G.PickupSpell,
+    petaction = _G.PickupSpellBookItem,
+    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,
+  }
+  kb.PickupSlot = function(self)
+    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
+      kb.ReleaseSlot(self)
+      kb.UpdateSlot(self)
+    end
+  end
+end
+
+kb.UnbindSlot = function(self)
+
+  local keys = {GetBindingKey(self.command) }
+  if #keys >= 1 then
+    kb.UpdateBindingsCache(self.actionType, self.actionID, {})
+  end
+
+
+  --print('detected', #keys, 'bindings')
+  for i, key in pairs(keys) do
+    --print('clearing', key)
+    SetBinding(key, nil)
+    SaveBindings(GetCurrentBindingSet())
+    if kb.currentProfile.bindings[key] then
+      --kb:print(L('BINDING_REMOVED', self.actionName, kb.currentHeader))
+      kb.currentProfile.bindings[key] = nil
+    end
+    if kb.currentProfile.talents[self.actionName] then
+      kb.currentProfile.talents[self.actionName] = nil
+    end
+    kb.bindings[self.actionType][self.actionID] = nil
+  end
+  if kb.currentProfile.bound[self.command] then
+    kb.currentProfile.bound[self.command] = nil
+    --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode]))
+  end
+
+
+  self.active = false
+  kb.UpdateSlot(self, true)
+end
+
+--- Updates the current KeyBinding for the button's command
+kb.SaveSlot = function(self, key)
+
+  if not self.command then
+    return
+  end
+  print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
+
+  local modifier = ''
+  if IsAltKeyDown() then
+    modifier = 'ALT-'
+  end
+  if IsControlKeyDown() then
+    modifier = modifier.. 'CTRL-'
+  end
+  if IsShiftKeyDown() then
+    modifier = modifier..'SHIFT-'
+  end
+  local binding = modifier..key
+
+  if key == 'ESCAPE' then
+  else
+    if kb.SystemBindings[binding] then
+      kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', binding, kb.SystemBindings[binding]))
+      return
+    end
+
+
+    if self.command then
+
+      local previousCommand = GetBindingAction(binding)
+      if previousCommand ~= "" and previousCommand ~= self.command then
+        if kb.SystemBindings[binding] then
+          -- bounce out if trying to use a protected key
+          kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, GetBindingAction(binding)))
+          kb.bindingstext:SetText(nil)
+          return false
+        end
+
+        local actionType, actionID, name = kb.GetCommandAction(previousCommand)
+        if actionType then
+          local keys = {GetBindingKey(previousCommand) }
+          local  i = 1
+          while keys[i] do
+            if keys[i] == binding then
+              table.remove(keys, i)
+              kb.UpdateBindingsCache(actionType, actionID, keys)
+              break
+            end
+            i = i + 1
+          end
+        end
+      end
+
+      local currentHotKeys = {GetBindingKey(self.command)}
+      local found
+      for i, key in ipairs(currentHotKeys) do
+        if key == binding then
+          found = true
+          kb:print('hotkey already assigned')
+        end
+      end
+      if not found then
+        table.insert(currentHotKeys, 1, binding)
+        kb.UpdateBindingsCache(self.actionType, self.actionID, currentHotKeys)
+      end
+
+      self.binding = binding
+
+
+
+      SetBinding(binding, self.command)
+      SaveBindings(GetCurrentBindingSet())
+
+
+
+      local talentInfo
+      if self.actionType == 'spell' and kb.TalentCache[self.actionID] then
+        print('conditional binding (talent = "'..self.actionName..'")')
+        talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID}
+        local bindings = {GetBindingKey(self.command) }
+        for i, key in ipairs(bindings) do
+          tinsert(talentInfo, key)
+        end
+      end
+
+      for level, profile in ipairs(kb.orderedProfiles) do
+        if (level == kb.db.bindMode) then
+          profile.bound[self.command] = true
+          if talentInfo then
+            profile.bindings[self.binding] = nil
+          else
+            profile.bindings[self.binding] = self.command
+          end
+          profile.talents[self.actionName] = talentInfo
+        else
+          profile.bindings[self.binding] = nil
+          profile.bound[self.command] = nil
+          kb.currentProfile.talents[self.actionName] = nil
+        end
+        if kb.currentProfile.talents[self.actionID] then
+          kb.currentProfile.talents[self.actionID] = nil
+        end
+      end
+
+      kb:print(L('BINDING_ASSIGNED', self.binding, self.actionName, kb.currentHeader))
+    end
+  end
+  kb.UpdateSlot(self, true)
+  return true
+end
+
+
+--- Updates profile assignment and button contents
+kb.UpdateSlot = function(self, force)
+  local slot = self:GetID()
+
+  if force then
+    if kb.currentProfile.buttons[slot] then
+      kb.SetSlot(self, unpack(kb.currentProfile.buttons[slot]))
+    else
+      kb.ReleaseSlot(self)
+    end
+  end
+
+  if self.command then
+    print('['..slot..'] =', self.command, GetBindingKey(self.command))
+
+    if not self.isAvailable then
+      self.border:SetColorTexture(1,0,0,1)
+      self.ignoreTexture:Show()
+    else
+      self.ignoreTexture:Hide()
+
+      if self.pending then
+        self.border:SetColorTexture(unpack(BORDER_PENDING))
+      elseif self.isDynamic then
+        self.border:SetColorTexture(unpack(BORDER_DYNAMIC))
+      else
+        self.border:SetColorTexture(unpack(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.isDynamic then
+      print('|cFF00BBFFUpdateSlot|r:', self.isDynamic, self.isAvailable, self.actionID)
+    end
+
+    if self.isDynamic == 'profession'  then
+      local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex))
+      if self.isAvailable then
+        print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1))
+
+        self.statusText = '|cFFFFFF00'..profText..'|r'
+        self.bindingText = kb.BindingString(GetBindingKey(self.command))
+      else
+        self.statusText = '|cFFFF4400'..profText..'|r'
+        self.actionName = '(need to train profession #'..self.profNum..')'
+        self.bindingText ='?'
+      end
+    elseif self.isDynamic == '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.isDynamic == 'petaction' then
+      local specialType, specialNum =  self.command:match("petaction_([%a%s]+)_(%d)")
+      if specialType and specialNum then
+        print('pet skill|cFF00FF00', specialType..'|r', specialNum)
+        self.statusText = L(specialType..' %%d'):format(specialNum)
+      else
+        self.statusText = L('Pet Action')
+      end
+      self.bindingText = kb.BindingString(GetBindingKey(self.command))
+    else
+      self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r'
+      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
+  else
+    self.ignoreTexture:Hide()
+  end
+
+  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.header:SetText(self.statusText)
+  self.bind:SetText(self.bindingText)
+  self.details:SetText(self.actionName)
+end
+
+--- Resets button command
+kb.ReleaseSlot = function(self)
+  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
+  if self.actionType == 'spell' and IsTalentSpell(self.actionName) then
+    if kb.currentProfile.talents[self.actionID] then
+      kb.currentProfile.talents[self.actionID] = nil
+    end
+  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.isDynamic = nil
+  self.bindingText = nil
+  self.statusText = nil
+  self.command = nil
+  self.actionType = nil
+  self.actionID = nil
+  self.actionName = nil
+  self.pickupSlot = nil
+  self.pickupBook = nil
+  self.macroName = nil
+  self.profile = nil
+  self.icon:SetTexture(nil)
+  self.border:SetColorTexture(unpack(BORDER_UNASSIGNED))
+  self:EnableKeyboard(false)
+  self:SetScript('OnKeyDown', nil)
+  self.ignoreTexture:Hide()
+end
+
+kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook)
+  local slot = self:GetID()
+  local isDynamic, isAvailable
+
+  print('|cFFFFFF00SetSlot|r:', self:GetID())
+  if command then
+
+    if actionType == 'spell' then
+      local professionNum, spellNum = command:match("profession_(%d)_(%d)")
+      if (professionNum and spellNum) then
+        isDynamic = 'profession'
+        local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum]
+        if cacheInfo then
+          isAvailable = true
+          name = cacheInfo.spellName
+          icon = cacheInfo.icon
+          actionID = cacheInfo.spellID
+          self.profIndex = cacheInfo.profIndex
+          self.spellOffset = cacheInfo.spellOffset
+        end
+        print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable)
+
+        self.professionNum = tonumber(professionNum)
+        self.spellNum = tonumber(spellNum)
+
+      else
+        if kb.TalentCache[actionID] then
+          isDynamic = 'talent'
+          print(' Special slot: |cFFBBFF00talent|r', name, isAvailable)
+        end
+
+        isAvailable = GetSpellInfo(name)
+      end
+    elseif actionType == 'petaction' then
+      isDynamic = 'petaction'
+      local specialType, specialNum = command:match(actionType..'_([%a%s]+)_(%d)')
+
+      if kb.PetCache.subtext[specialType] and kb.PetCache.subtext[specialType][tonumber(specialNum)] then
+        print('***dynamic pet thign', specialType, specialNum)
+        --[[ i, spellName, subText, spellID,  texture, specialNum[subText ]]
+        pickupSlot, name, specialType, actionID, icon, specialNum = unpack(kb.PetCache.subtext[specialType][tonumber(specialNum)])
+        pickupBook = BOOKTYPE_PET
+      end
+
+      isAvailable = (kb.PetCache.spellslot[name])
+
+
+    elseif actionType == 'macro' then
+      if not actionID then
+        actionID = GetMacroIndexByName(name)
+      end
+      isAvailable = true
+    else
+      --- Journal selections
+      -- todo: consider using the deep end of blizzard action bar instead
+      if not actionID then
+        actionID = command:match("^KeyBinderMacro:(.+)")
+      end
+      isAvailable = true
+    end
+
+    if isAvailable then
+      local oldCommand = command
+      macroName, macroText, command = kb.RegisterAction(actionType, actionID, name)
+      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
+      kb.LoadBinding(command, name, icon, actionType, actionID, macroName, macroText)
+    end
+
+
+    actionID = actionID or 0
+    self:EnableKeyboard(true)
+    print(' |cFF00FF00kb.currentProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name.. '"|r |cFFFFFF00icon:'.. tostring(icon) .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r')
+    kb.currentProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook }
+
+
+    -- 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
+
+    if not (kb.IsCommandBound(self, command) or kb.currentProfile.bound[command]) then
+
+      local binds = {GetBindingKey(command) }
+        if #binds >= 1 then
+        kb:print('Recovered key binding for', name)
+        for i, key in ipairs(binds) do
+          kb.currentProfile.bindings[key] = command
+          kb.currentProfile.bound[command] = true
+        end
+      end
+    end
+
+
+    kb.currentProfile.commands[command] = slot
+
+  end
+
+  self.isAvailable = isAvailable
+  self.isDynamic = isDynamic
+
+  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.icon:SetTexture(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
+
+
+--- Add to blizzard interfaces
+StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = {
+  text = "Confirm moving an assigned command.",
+  button1 = OKAY,
+  button2 = CANCEL,
+  timeout = 0,
+  whileDead = 1,
+  showAlert = 1,
+  OnAccept = kb.AcceptAssignment,
+  OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end
+}
\ No newline at end of file