diff BindingsFrame.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/BindingsFrame.lua	Wed Dec 28 16:31:15 2016 -0500
@@ -0,0 +1,652 @@
+-- KrakTool
+-- BindingsFrame.lua
+-- Created: 7/28/2016 3:39 PM
+-- %file-revision%
+-- Handles the arrangement of and interaction with the SkeletonKey frame
+--[=[
+  -- some useful texture paths
+  [[Interface\PaperDollInfoFrame\UI-GearManager-Undo]]
+  [[Interface\PetPaperDollFrame\UI-PetHappiness]]
+  [[Interface\RAIDFRAME\ReadyCheck-Waiting]]
+  [[Interface\RAIDFRAME\ReadyCheck-Read]]
+  [[Interface\RAIDFRAME\ReadyCheck-NotReady]]
+  [[Interface\TradeSkillFrame\UI-TradeSkill-LinkButton]]
+  [[Interface\TUTORIALFRAME\UI-TUTORIAL-FRAME]]
+  [[Interface\UI-TutorialFrame-QuestGiver\UI-TutorialFrame-QuestGray]]
+--]=]
+
+SkeletonKeyButtonMixin = {}
+local _, kb = ...
+local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SK', ...) end or nop
+local L = kb.L
+local BINDS_PER_ROW = 2
+local BINDING_TYPE_SPECIALIZATION = 3
+local BINDING_TYPE_CHARACTER = 2
+local BINDING_TYPE_GLOBAL = 1
+local BUTTON_HSPACING = 128
+local BUTTON_SPACING = 4
+local BUTTON_PADDING = 12
+local TAB_HEIGHT = 24
+local KEY_BUTTON_SIZE = 48
+local NUM_KEY_SLOTS = BINDS_PER_ROW * 8
+local TAB_HEIGHT = 40
+local BG_INSET = 4
+
+local BINDING_SCHEME_COLOR = {
+  [BINDING_TYPE_GLOBAL] = {0,.125,.5,.8},
+  [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.8},
+  [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.8},
+}
+local BINDING_SCHEME_VERTEX = {
+  [BINDING_TYPE_GLOBAL] = {0,.5,1,1},
+  [BINDING_TYPE_CHARACTER] = {0,1,0,1},
+  [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1},
+}
+local BINDING_SCHEME_TEXT = {
+  [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1},
+  [BINDING_TYPE_CHARACTER] = {0, 1, 0},
+  [BINDING_TYPE_GLOBAL] = {0, 1, 1}
+}
+
+local match, strupper = string.match, string.upper
+local tremove, tinsert, ipairs, pairs, unpack = table.remove, table.insert, ipairs, pairs, unpack
+local tonumber, tostring = tonumber, tostring
+local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor
+local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
+local GetBindingAction, GetBindingKey, GetCurrentBindingSet = GetBindingAction, GetBindingKey, GetCurrentBindingSet
+local SetBinding, SaveBindings = SetBinding, SaveBindings
+local GetSpellInfo, InCombatLockdown = GetSpellInfo, InCombatLockdown
+
+
+local ActionListPanel = {
+  tabButtons = {
+    [BINDING_TYPE_GLOBAL] = {
+      icon = "Interface\\WORLDMAP\\WorldMap-Icon",
+      label = "Global",
+    },
+    [BINDING_TYPE_CHARACTER] ={
+      func = function(self, index)
+        SetPortraitTexture(self.Icon, 'player')
+        self.Label:SetText(kb.configHeaders[index])
+        self.tooltipText = kb.configHeaders[index]
+      end
+    },
+    [BINDING_TYPE_SPECIALIZATION] = {
+      func = function(self, index)
+        self.Icon:SetTexture(kb.specInfo.texture)
+        self.Label:SetText(kb.configHeaders[index])
+        self.tooltipText = kb.configHeaders[index]
+      end
+    },
+  }
+}
+local SystemBindingsPanel = {
+  tabButtons = {
+    {label = "Global"},
+    {label = "Character"}
+  }
+}
+function SkeletonKeyMixin:ProcessInput (key)
+  if self.currentPanel then
+    if self.currentPanel:OnInput(key) then
+      self:Update(true)
+    end
+  end
+end
+
+local lastFolder
+local restingAlpha = 0.7
+local fadeTime, fadeDelay = .30, 0.15
+local saveButton
+
+
+
+local frameCount = 0
+local lastCheckFrame
+local KeyBinder_CheckButton = function(frame ,enableText, disableText, dbKey, tooltipText, callback, header)
+  if kb.db[dbKey] then
+    frame:SetChecked(true)
+  end
+
+  frame.header:SetText(header)
+
+  frame:SetScript('OnClick', function(self)
+    kb.db[dbKey] = self:GetChecked()
+    if callback then
+      callback(self)
+    end
+    kb.ui()
+  end)
+
+  frame:SetScript('OnEnter', function(self)
+    if tooltipText then
+      GameTooltip:SetOwner(self)
+      GameTooltip:SetText(tooltipText)
+      GameTooltip:Show()
+    end
+  end)
+
+  frame:SetScript('OnLeave', function(self)
+    if tooltipText and GameTooltip:GetOwner() == self then
+      GameTooltip:Hide()
+    end
+  end)
+
+  if frame:GetID() == 0 then
+    frameCount = frameCount + 1
+    frame:SetID(frameCount)
+    print('checkbutton #', frameCount)
+    if frameCount == 1 then
+      frame:ClearAllPoints()
+      frame:SetPoint('TOP', KeyBinderInventoryButton, 'BOTTOM', 0, -22)
+      frame:SetPoint('LEFT', SkeletonKey 'LEFT', 2, 0)
+    else
+      frame:ClearAllPoints()
+      frame:SetPoint('TOPLEFT', lastCheckFrame, 'BOTTOMLEFT', 0, -2)
+    end
+
+    frame.header:ClearAllPoints()
+    frame.header:SetPoint('LEFT', frame, 'RIGHT', 2, 0)
+
+    lastCheckFrame = frame
+  end
+end
+
+
+
+function SkeletonKeyMixin:OnMouseWheel(delta)
+
+  -- let the updaters handle range
+  if IsControlKeyDown() then
+    self.zoomScale = self.zoomScale - (delta/10)
+  else
+    self.scrollOffset = ceil(self.scrollOffset - delta)
+  end
+
+  self:Update(true)
+  print(self.zoomScale, self.scrollOffset)
+end
+
+function SkeletonKeyMixin:OnHide()
+  KeyBinderImportLog:Hide()
+end
+
+
+local tabID = 0
+local prevTab
+
+function SkeletonKeyMixin:SetupTabButton (index, text, icon, func)
+  print('|cFF00FFFF'..self:GetName()..':SetupTabButton()', index, text, icon, func)
+  local tabName = 'SkeletonKeyProfileTab'..index
+  local tab = _G[tabName]
+
+  if not tab then
+    tab = CreateFrame('Button', tabName, self, 'SkeletonKeyTabTemplate')
+    self.numTabs = self.numTabs + 1
+    tab:SetID(self.numTabs)
+    TAB_HEIGHT = tab:GetHeight()
+
+    if self.numTabs == 1 then
+      tab:SetPoint('TOPLEFT', self.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING)
+    else
+      tab:SetPoint('TOPLEFT', self.lastTab,'TOPRIGHT', BUTTON_SPACING, 0)
+    end
+
+    tab.tooltipText = text
+    tab:SetScript('OnEnter', function(button)
+      if button.tooltipText then
+        GameTooltip:SetOwner(button)
+        GameTooltip:SetText(button.tooltipText)
+        GameTooltip:Show()
+      end
+    end)
+
+    tab:SetScript('OnLeave', function(button)
+      if GameTooltip:IsOwned(button) then
+        GameTooltip:Hide()
+      end
+    end)
+
+    tab:SetScript('OnClick', function(button)
+      self.selectedTabIndex = button:GetID()
+      self:Update(true)
+    end)
+    self.lastTab = tab
+  end
+  if text then
+
+    tab.Label:SetText(text)
+  end
+
+  if icon then
+    tab.Icon:SetTexture(icon)
+  end
+  if func then
+    func(tab, index, text)
+  end
+
+  local selected = (index == self.selectedTabIndex)
+  if selected then
+    tab.Icon:SetDesaturated(false)
+    tab.Label:SetTextColor(0,1,0, 1)
+  else
+
+    tab.Icon:SetDesaturated(true)
+    tab.Label:SetTextColor(1,1,1,0.7)
+  end
+
+  tab.used = true
+
+  tab:SetSize(tab.Icon:GetWidth()+tab.Label:GetStringWidth()+3, tab.Icon:GetHeight())
+  tab:Show()
+  print(tab:GetPoint(1))
+  print(tab:GetSize())
+
+  return tab
+end
+
+
+
+--- push current information into living UI
+function SkeletonKeyMixin:Update(force)
+  print('|cFFFF8800'..self:GetName()..':Update()|r', InCombatLockdown() and 'combat', self:IsShown())
+  for index, frame in ipairs(self.Plugins) do
+    if frame.Update then
+      frame:Update(force)
+    end
+  end
+
+  self.currentPanel = self.currentPanel or self.Panels[1]
+  if InCombatLockdown() or not self:IsShown() then
+    return
+  end
+
+  self.numTabs = 0
+  for index, tab in ipairs(self.tabButtons) do
+    tab.used = nil
+    tab:Hide()
+  end
+
+  for index, panel in ipairs(self.Panels) do
+    print(panel:GetName())
+    if panel == self.currentPanel then
+      print('Updating panel:', panel:GetName())
+      panel:SetAllPoints(self.bg)
+      self.selectedTabIndex, self.scrollOffset = panel:Update(force)
+      panel:Show()
+
+      for tabIndex, info in ipairs(panel.tabButtons) do
+        self:SetupTabButton(tabIndex, info.label, info.icon, info.func)
+      end
+
+    else
+      panel:Hide()
+    end
+  end
+
+
+
+  --- Frame Sizing
+  self.profilebg:SetHeight(TAB_HEIGHT + BUTTON_PADDING * 2 + self.profiletext:GetStringHeight())
+
+  self.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2)
+  local numRows = NUM_KEY_SLOTS/BINDS_PER_ROW
+
+  self.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2)
+
+
+  self:SetHeight(self.headerbg:GetHeight() + self.profilebg:GetHeight() + self.bg:GetHeight() + self.footer:GetHeight()+BG_INSET*2)
+  self:SetWidth(((BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) ))
+
+
+  self.backdrop.insets.left = BG_INSET
+  self.backdrop.insets.right = BG_INSET
+  self.backdrop.insets.top = BG_INSET
+  self.backdrop.insets.bottom = BG_INSET
+  self:SetBackdrop(self.backdrop)
+  self:SetBackdropColor(unpack(self.backdropColor))
+  self:SetBackdropBorderColor(unpack(self.backdropBorder))
+
+  self:SetScale(self.zoomScale)
+
+  self.profiletext:SetText(kb.configHeaders[kb.db.bindMode])
+  print(kb.db.bindMode, kb.configHeaders[kb.db.bindMode], self:GetSize())
+  print(self:GetPoint(1))
+
+
+  self:EnableKeyboard((kb.saveTarget and true) or false)
+  print('keyboard input:', (kb.saveTarget and true) or false)
+
+  -- Reset this so talent cache can be rebuilt
+  kb.talentsPushed = nil
+end
+
+local SkeletonKeyPanel = {}
+function SkeletonKeyPanel:OnShow()
+  print('|cFFFFFF00'..self:GetName()..':OnShow()|r')
+end
+
+function ActionListPanel:OnLoad()
+
+
+  self.UnbindButton:SetScript('OnClick', function()
+    self:UnbindSlot(kb.saveTarget)
+    SkeletonKey:Update()
+  end)
+end
+
+function ActionListPanel:Update(force)
+  local parent = self:GetParent()
+  local tabID = parent.selectedTabIndex
+  local scrollOffset = parent.scrollOffset
+  if not tabID then
+    tabID = kb.db.bindMode or BINDING_TYPE_GLOBAL
+  end
+  print('|cFF0088FF'..self:GetName()..':Update()|r', 'tab', parent.selectedTabIndex, 'scroll', parent.scrollOffset)
+
+  local selectedProfile = kb.loadedProfiles[tabID]
+  if selectedProfile then
+    kb.currentProfile = selectedProfile
+    kb.db.bindMode = tabID
+  else
+    tabID = BINDING_TYPE_GLOBAL
+  end
+  scrollOffset = scrollOffset or 0
+
+  local leftSlot, upSlot
+  local buttonTable = self.buttons or {}
+  for index = 1, NUM_KEY_SLOTS do
+    if not buttonTable[index] then
+      local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, self, 'KeyButton')
+      local newRow = (mod(index, BINDS_PER_ROW) == 1)
+
+      if index == 1 then
+        button:SetPoint('TOPLEFT', self, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING)
+        upSlot = button
+      elseif newRow then
+        button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING)
+        upSlot = button
+      else
+        button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0)
+      end
+
+      button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE)
+      button:Show()
+      buttonTable[index] = button
+      leftSlot = button
+    end
+  end
+  self.buttons = buttonTable
+
+  local startIndex = scrollOffset * BINDS_PER_ROW
+  for i, button in ipairs(self.buttons) do
+    button:SetID(startIndex+i)
+    button:UpdateSlot(force)
+    button:SetFrameLevel(50 + i + (button.isActive and #self.buttons or 0))
+  end
+
+
+  local r,g,b,a = unpack(BINDING_SCHEME_COLOR[kb.db.bindMode])
+  self.profileStripe:SetColorTexture(r,g,b)
+  if kb.saveTarget then
+    self.bg:SetColorTexture(.2,.5, .2, .5)
+    self.UnbindButton:SetFrameLevel(kb.saveTarget:GetFrameLevel()-1)
+    self.UnbindButton:SetPoint('TOPLEFT', kb.saveTarget, 'BOTTOMLEFT', 0, -1)
+    self.UnbindButton:Show()
+
+  else
+    self.bg:SetColorTexture(.2,.2,.2,1)
+    self.UnbindButton:Hide()
+  end
+
+  return tabID, scrollOffset
+end
+
+
+function ActionListPanel:ActivateSlot (button)
+  if kb.saveTarget then
+    kb.saveTarget.isActive = nil
+  end
+  button.isActive = true
+  kb.saveTarget = button
+  return true
+end
+
+function ActionListPanel:DeactivateSlot (button)
+  button.isActive = nil
+  kb.saveTarget = nil
+  return true
+end
+
+function ActionListPanel:OnInput(key)
+
+  if key == 'ESCAPE' then
+    return self:DeactivateSlot(kb.saveTarget)
+  end
+
+  if (match(key, '[RL]SHIFT') or match(key, '[RL]ALT') or match(key, '[RL]CTRL')) then
+    return
+  end
+
+  if kb.saveTarget then
+    if kb.saveTarget:SaveSlot(key) then
+      if not (kb.db.stickyMode or kb.db.hoverInput) then
+        return self:DeactivateSlot(kb.saveTarget)
+      end
+      return true
+    end
+  end
+end
+
+
+function SystemBindingsPanel:Update(force)
+end
+
+--- Associate processed input with the given slot's metadata
+function SkeletonKeyButtonMixin:SaveSlot (key)
+
+  if not self.command then
+    return
+  end
+  if InCombatLockdown() then
+    kb:print(L('Bindings cannot be changed during combat.'))
+    return
+  end
+
+  local spellName = self.actionName
+
+  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
+
+  -- check for system bindings
+  --bprint('|cFFFFFF00SaveBind|r', 'protectKeys', kb.db.protectBlizKeys)
+  if kb.db.protectBlizKeys and kb.SystemBindings[binding] then
+    kb:print(L('BINDING_FAILED_PROTECTED', binding, kb.SystemBindings[binding]))
+    return false
+  end
+
+  -- check for other keys
+  local previousCommand = GetBindingAction(binding)
+  if previousCommand ~= "" and previousCommand ~= self.command then
+    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
+          tremove(keys, i)
+          kb.UpdateBindingsCache(actionType, actionID, keys)
+          break
+        end
+        i = i + 1
+      end
+    end
+  end
+
+
+  if self.isAvailable then
+    print('Binding available spell', binding, self.command)
+    SetBinding(binding, self.command)
+    SaveBindings(GetCurrentBindingSet())
+    self.assignedKeys = {GetBindingKey(self.command) }
+
+    kb:print(L('BINDING_ASSIGNED', binding, self.actionName, kb.currentHeader))
+  else
+    kb:print(L('UNSELECTED_TALENT_ASSIGNED', binding, self.actionName, kb.currentHeader))
+  end
+
+  if not tContains(self.assignedKeys, binding) then
+    tinsert(self.assignedKeys, 1, binding)
+  end
+
+  local talentInfo
+  if spellName and kb.TalentCache[spellName] then
+    print('store dynamicType talent')
+    talentInfo = {
+      macroName = self.macroName,
+      actionName = self.actionName,
+      actionType = self.actionType,
+      actionID = self.actionID,
+      assignedKeys = self.assignedKeys
+    }
+    kb.currentProfile.talents[spellName] = talentInfo
+  end
+
+  for _, key in ipairs(self.assignedKeys) do
+    if not kb.currentProfile.bindings[key] then
+      kb.currentProfile.bindings[key] = self.command
+    end
+  end
+
+  for level, profile in ipairs(kb.orderedProfiles) do
+    if (level > kb.db.bindMode) then
+      profile.bindings[binding] = nil
+      profile.commands[self.command] = nil
+      profile.bound[self.command] = nil
+      if spellName then
+        profile.talents[spellName] = nil
+      end
+    end
+  end
+
+  kb.UpdateBindingsCache(self.actionType, self.actionID, self.assignedKeys)
+
+  self.binding = binding
+
+  return true
+end
+
+function SkeletonKeyMixin:OnKeyDown(key)
+  self:ProcessInput(key)
+end
+function SkeletonKeyMixin:OnKeyUp(key)
+end
+
+function SkeletonKeyMixin:OnDragStart()
+  self:StartMoving()
+end
+function SkeletonKeyMixin:OnDragStop()
+  self:StopMovingOrSizing()
+end
+
+function ActionListPanel:UnbindSlot (button)
+
+  local button = button or kb.saveTarget
+  if not button then
+    return
+  end
+
+  local command = button.command
+  local actionType = button.actionType
+  local actionID = button.actionID
+
+  local keys = {GetBindingKey(command) }
+  if #keys >= 1 then
+    kb.UpdateBindingsCache(actionType, actionID, {})
+  end
+
+  local talentName = button.actionName
+  if actionType == 'macro' then
+    local spellName, _, spellID = GetMacroSpell(actionID)
+    talentName = spellName
+  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[talentName] then
+      kb.currentProfile.talents[talentName] = nil
+    end
+
+    kb.bindings[tostring(actionType)..'_'..tostring(actionID)] = nil
+  end
+  if kb.currentProfile.bound[command] then
+    kb.currentProfile.bound[command] = nil
+    --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode]))
+  end
+  kb.saveTarget = nil
+
+  return true
+end
+
+kb.AcceptAssignment = function(self, ...)
+  local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
+  local source = kb.  loadedProfiles[popup.oldProfile]
+  popup.slot:SetSlot(unpack(popup.args))
+  popup.slot:UpdateSlot()
+  --kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling
+  ClearCursor()
+  ResetCursor()
+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
+}
+
+
+
+do
+  local MACRO_SELECTED_ID = 1
+  local MACRO_SELECTED_NAME = GetMacroInfo(1)
+  kb.CreateMacroHooks = function()
+    print('|cFF00FF00setting up MacroUI hooks')
+    hooksecurefunc("MacroFrame_SelectMacro", function(id)
+      print('|cFF0088FFMacroFrame_SelectMacro|r', id)
+      MACRO_SELECTED_ID = id
+      for k,v in pairs(kb.bindings) do
+        --print(k,v)
+      end
+
+    end)
+  end
+end
+
+
+SkeletonKeyActionListMixin = Mixin(ActionListPanel, SkeletonKeyPanel)
+SkeletonKeySystemBindingsMixin = Mixin(SystemBindingsPanel, SkeletonKeyPanel)
\ No newline at end of file