diff modules/Action.lua @ 116:fb48811a8736

Convert to standard keybindings
author Flick <flickerstreak@gmail.com>
date Fri, 23 Jan 2009 23:44:55 +0000
parents 77bb68eb402b
children fb6c3a642ae3
line wrap: on
line diff
--- a/modules/Action.lua	Fri Jan 23 23:40:13 2009 +0000
+++ b/modules/Action.lua	Fri Jan 23 23:44:55 2009 +0000
@@ -18,6 +18,8 @@
 
 ReAction:UpdateRevision("$Revision$")
 
+local weak = { __mode="k" }
+
 -- libraries
 local KB = LibStub("LibKeyBound-1.0")
 local LBF -- initialized later
@@ -267,7 +269,6 @@
     },
   }
 
-  local weak  = { __mode="k" }
   local meta = { __index = Handle }
 
   function Handle:New( bar, config )
@@ -365,15 +366,7 @@
 
   function Handle:SetKeybindMode(mode)
     for _, b in pairs(self.btns) do
-      if mode then
-        -- set the border for all buttons to the keybind-enable color
-      	b.border:SetVertexColor(KB:GetColorKeyBoundMode())
-        b.border:Show()
-      elseif IsEquippedAction(b:GetActionID()) then
-        b.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua
-      else
-        b.border:Hide()
-      end
+      b:SetKeybindMode(mode)
     end
   end
 
@@ -763,398 +756,368 @@
 end
 
 ------ Button class ------
+local frameRecycler = { }
+local trash = CreateFrame("Frame")
+local OnUpdate, KBAttach, GetHotkey
+do
+  local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
+  local IsActionInRange = IsActionInRange
 
-do
-  local frameRecycler = { }
-  local trash = CreateFrame("Frame")
-  local OnUpdate, KBAttach, GetActionName, GetHotkey, SetKey, FreeKey, ClearBindings, GetBindings
-  do
-    local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
-    local IsActionInRange = IsActionInRange
+  function OnUpdate(frame, elapsed)
+    -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these
+    --       are only read by ActionButton_OnUpdate (which this function replaces). In
+    --       all other places they're just written, so it doesn't taint any secure code.
+    if frame.flashing == 1 then
+      frame.flashtime = frame.flashtime - elapsed
+      if frame.flashtime <= 0 then
+        local overtime = -frame.flashtime
+        if overtime >= ATTACK_BUTTON_FLASH_TIME then
+          overtime = 0
+        end
+        frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
 
-    local buttonLookup = setmetatable({},{__mode="kv"})
-
-    function OnUpdate(frame, elapsed)
-      -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these
-      --       are only read by ActionButton_OnUpdate (which this function replaces). In
-      --       all other places they're just written, so it doesn't taint any secure code.
-      if frame.flashing == 1 then
-        frame.flashtime = frame.flashtime - elapsed
-        if frame.flashtime <= 0 then
-          local overtime = -frame.flashtime
-          if overtime >= ATTACK_BUTTON_FLASH_TIME then
-            overtime = 0
-          end
-          frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
-
-          local flashTexture = frame.flash
-          if flashTexture:IsShown() then
-            flashTexture:Hide()
-          else
-            flashTexture:Show()
-          end
-        end
-      end
-      
-      if frame.rangeTimer then
-        frame.rangeTimer = frame.rangeTimer - elapsed;
-
-        if frame.rangeTimer <= 0 then
-          if IsActionInRange(frame.action) == 0 then
-            frame.icon:SetVertexColor(1.0,0.1,0.1)
-          else
-            ActionButton_UpdateUsable(frame)
-          end
-          frame.rangeTimer = 0.1
+        local flashTexture = frame.flash
+        if flashTexture:IsShown() then
+          flashTexture:Hide()
+        else
+          flashTexture:Show()
         end
       end
     end
+    
+    if frame.rangeTimer then
+      frame.rangeTimer = frame.rangeTimer - elapsed;
 
-    -- Use KeyBound-1.0 for binding, but use Override bindings instead of
-    -- regular bindings to support multiple profile use. This is a little
-    -- weird with the KeyBound dialog box (which has per-char selector as well
-    -- as an OK/Cancel box) but it's the least amount of effort to implement.
-    function GetActionName(f)
-      local b = buttonLookup[f]
-      if b then
-        return format("%s:%s", b.bar:GetName(), b.idx)
-      end
-    end
-
-    function GetHotkey(f)
-      local b = buttonLookup[f]
-      if b then
-        return KB:ToShortKey(b:GetConfig().hotkey)
-      end
-    end
-
-    function SetKey(f, key)
-      local b = buttonLookup[f]
-      if b then
-        local c = b:GetConfig()
-        if c.hotkey then
-          SetOverrideBinding(f, false, c.hotkey, nil)
+      if frame.rangeTimer <= 0 then
+        if IsActionInRange(frame.action) == 0 then
+          frame.icon:SetVertexColor(1.0,0.1,0.1)
+        else
+          ActionButton_UpdateUsable(frame)
         end
-        if key then
-          SetOverrideBindingClick(f, false, key, f:GetName(), nil)
-        end
-        c.hotkey = key
-        b:DisplayHotkey(GetHotkey(f))
-      end
-    end
-
-    function FreeKey(f, key)
-      local b = buttonLookup[f]
-      if b then
-        local c = b:GetConfig()
-        if c.hotkey == key then
-          local action = f:GetActionName()
-          SetOverrideBinding(f, false, c.hotkey, nil)
-          c.hotkey = nil
-          b:DisplayHotkey(nil)
-          return action
-        end
-      end
-      return ReAction:FreeOverrideHotkey(key)
-    end
-
-    function ClearBindings(f)
-      SetKey(f, nil)
-    end
-
-    function GetBindings(f)
-      local b = buttonLookup[f]
-      if b then
-        return b:GetConfig().hotkey
-      end
-    end
-
-    function KBAttach( button )
-      local f = button:GetFrame()
-      f.GetActionName = GetActionName
-      f.GetHotkey     = GetHotkey
-      f.SetKey        = SetKey
-      f.FreeKey       = FreeKey
-      f.ClearBindings = ClearBindings
-      f.GetBindings   = GetBindings
-      buttonLookup[f] = button
-      f:SetKey(button:GetConfig().hotkey)
-      ReAction:RegisterKeybindFrame(f)
-      if ReAction:GetKeybindMode() then
-      	button.border:SetVertexColor(KB:GetColorKeyBoundMode())
-        button.border:Show()
+        frame.rangeTimer = 0.1
       end
     end
   end
 
-  local meta = {__index = Button}
-
-  function Button:New( handle, idx, config, barConfig )
-    local bar = handle.bar
-
-    -- create new self
-    self = setmetatable( 
-      { 
-        bar = bar,
-        idx = idx,
-        config = config,
-        barConfig = barConfig,
-      }, meta )
-
-    local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx)
-    self.name = name
-    config.name = name
-    local lastButton = handle:GetLastButton()
-    config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured
-    self.nPages = 1
-    
-    -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
-    -- existing globals. Can't set to nil in the global because it's then tainted.
-    local parent = bar:GetFrame()
-    local f = frameRecycler[name]
-    if f then
-      f:SetParent(parent)
-    else
-      f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate")
-      -- ditch the old hotkey text because it's tied in ActionButton_Update() to the
-      -- standard binding. We use override bindings.
-      local hotkey = _G[name.."HotKey"]
-      hotkey:SetParent(trash)
-      hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray")
-      hotkey:SetWidth(36)
-      hotkey:SetHeight(18)
-      hotkey:SetJustifyH("RIGHT")
-      hotkey:SetJustifyV("TOP")
-      hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
-      f.hotkey = hotkey
-      f.icon = _G[name.."Icon"]
-      f.flash = _G[name.."Flash"]
-      f:SetScript("OnUpdate",OnUpdate)
-    end
-
-    self.hotkey = f.hotkey
-    self.border = _G[name.."Border"]
-
-    f:SetAttribute("action", config.actionID)
-    f:SetAttribute("default-action", config.actionID)
-    -- install mind control actions for all buttons just for simplicity
-    if self.idx <= 12 then
-      f:SetAttribute("mindcontrol-action", 120 + self.idx)
-    end
-    
-    -- set a _childupdate handler, called within the header's context
-    f:SetAttribute("_childupdate", 
-      -- function _childupdate(self, snippetid, message)
-      [[
-        local action = "default-action"
-        if doMindControl and GetBonusBarOffset() == 5 then
-          action = "mindcontrol-action"
-        elseif page and state and page[state] then
-          action = "action-"..page[state]
-        end
-        local value = self:GetAttribute(action)
-        if value then
-          self:SetAttribute("action",value)
-        end
-      ]])
-
-    -- install drag wrappers to lock buttons 
-    bar:GetFrame():WrapScript(f, "OnDragStart",
-      -- OnDragStart(self, button, kind, value, ...)
-      [[
-        if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
-          return "clear"
-        end
-      ]])
-
-    self.frame = f
-
-
-    -- initialize the hide state
-    f:SetAttribute("showgrid",0)
-    self:ShowGrid(not barConfig.hideEmpty)
-    if ReAction:GetConfigMode() then
-      self:ShowGrid(true)
-    end
-
-    -- show the ID label if applicable
-    self:ShowActionIDLabel(ReAction:GetConfigMode())
-
-    -- attach the keybinder
-    KBAttach(self)
-
-    -- attach to skinner
-    bar:SkinButton(self,
-      {
-        HotKey = self.hotkey,
-      }
-    )
-
-    self:Refresh()
-    return self
-  end
-
-  function Button:Destroy()
-    local f = self.frame
-    f:UnregisterAllEvents()
-    f:Hide()
-    f:SetParent(UIParent)
-    f:ClearAllPoints()
-    if self.name then
-      frameRecycler[self.name] = f
-    end
-    if self.config.actionID then
-      IDAlloc:Release(self.config.actionID)
-    end
-    if self.config.pageactions then
-      for _, id in ipairs(self.config.pageactions) do
-        IDAlloc:Release(id)
-      end
-    end
-    self.frame = nil
-    self.config = nil
-    self.bar = nil
-  end
-
-  function Button:Refresh()
-    local f = self.frame
-    self.bar:PlaceButton(self, 36, 36)
-    self:RefreshPages()
-  end
-
-  function Button:GetFrame()
-    return self.frame
-  end
-
-  function Button:GetName()
-    return self.name
-  end
-
-  function Button:GetConfig()
-    return self.config
-  end
-
-  function Button:GetActionID(page)
-    if page == nil then
-      -- get the effective ID
-      return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction()
-    else
-      if page == 1 then
-        return self.config.actionID
-      else
-        return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
-      end
+  local function GetActionName(f)
+    local b = f and f._reactionButton
+    if b then
+      return format("%s:%s", b.bar:GetName(), b.idx)
     end
   end
 
-  function Button:SetActionID( id, page )
-    id = tonumber(id)
-    page = tonumber(page)
-    if id == nil or id < 1 or id > 120 then
-      error("Button:SetActionID - invalid action ID")
-    end
-    if page and page ~= 1 then
-      if not self.config.pageactions then
-        self.config.pageactions = { }
-      end
-      if self.config.pageactions[page] then
-        IDAlloc:Release(self.config.pageactions[page])
-      end
-      self.config.pageactions[page] = id
-      IDAlloc:Acquire(self.config.pageactions[page])
-      self.frame:SetAttribute(("action-page%d"):format(page),id)
-    else
-      IDAlloc:Release(self.config.actionID)
-      self.config.actionID = id
-      IDAlloc:Acquire(self.config.actionID)
-      self.frame:SetAttribute("action",id)
-      if self.config.pageactions then
-        self.config.pageactions[1] = id
-        self.frame:SetAttribute("action-page1",id)
-      end
+  function GetHotkey(f)
+    return KB:ToShortKey(GetBindingKey(format("CLICK %s:LeftButton",f:GetName())))
+  end
+
+  local function kb_onEnter( self )
+    if ReAction:GetKeybindMode() then
+      KB:Set(self)
     end
   end
 
-  function Button:RefreshPages( force )
-    local nPages = self.barConfig.nPages
-    if nPages and (nPages ~= self.nPages or force) then
-      local f = self:GetFrame()
-      local c = self.config.pageactions
-      if nPages > 1 and not c then
-        c = { }
-        self.config.pageactions = c
-      end
-      for i = 1, nPages do
-        if i > 1 then
-          c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
-        else
-          c[i] = self.config.actionID  -- page 1 is the same as the base actionID
-        end
-        f:SetAttribute(("action-page%d"):format(i),c[i])
-      end
-      for i = nPages+1, #c do
-        IDAlloc:Release(c[i])
-        c[i] = nil
-        f:SetAttribute(("action-page%d"):format(i),nil)
-      end
-      self.nPages = nPages
+  function KBAttach( button )
+    if not button.kbHooked then
+      button.kbHooked = true
+      local f = button:GetFrame()
+      f:HookScript("OnEnter", kb_onEnter)
+      f.GetActionName = GetActionName
+      f.GetHotkey     = GetHotkey
     end
   end
 
-  function Button:ShowGrid( show )
-    if not InCombatLockdown() then
-      local f = self.frame
-      local count = f:GetAttribute("showgrid")
-      if show then
-        count = count + 1
-      else
-        count = count - 1
-      end
-      if count < 0 then
-        count = 0
-      end
-      f:SetAttribute("showgrid",count)
-
-      if count >= 1 and not f:GetAttribute("statehidden") then
-        if LBF then
-          LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5)
-        else
-          self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
-        end
-        f:Show()
-      elseif count < 1 and not HasAction(self:GetActionID()) then
-        f:Hide()
-      end
+  -- This is a bit hokey : install a bare hook on ActionButton_UpdateHotkey because
+  -- even though it's secure it's never called in a way that can cause taint. This is 
+  -- for performance reasons to avoid having to hook frame:OnEvent securely.
+  local UpdateHotkey_old = ActionButton_UpdateHotkeys
+  ActionButton_UpdateHotkeys = function( frame, ... )
+    local b = frame._reactionButton
+    if b then
+      b.hotkey:SetText( GetHotkey(frame) )
+    else
+      return UpdateHotkey_old(frame, ...)
     end
   end
+end
 
-  function Button:ShowActionIDLabel( show )
-    local f = self:GetFrame()
-    if show then
-      local id = self:GetActionID()
-      if not f.actionIDLabel then
-        local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
-        label:SetAllPoints()
-        label:SetJustifyH("CENTER")
-        label:SetShadowColor(0,0,0,1)
-        label:SetShadowOffset(2,-2)
-        f.actionIDLabel = label -- store the label with the frame for recycling
+local meta = {__index = Button}
 
-        f:HookScript("OnAttributeChanged", 
-          function(frame, attr, value)
-            if label:IsVisible() and attr:match("action") then
-              label:SetText(tostring(frame.action))
-            end
-          end)
+function Button:New( handle, idx, config, barConfig )
+  local bar = handle.bar
+
+  -- create new self
+  self = setmetatable( 
+    { 
+      bar = bar,
+      idx = idx,
+      config = config,
+      barConfig = barConfig,
+    }, meta )
+
+  local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx)
+  self.name = name
+  config.name = name
+  local lastButton = handle:GetLastButton()
+  config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured
+  self.nPages = 1
+  
+  -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
+  -- existing globals. Can't set to nil in the global because it's then tainted.
+  local parent = bar:GetFrame()
+  local f = frameRecycler[name]
+  if f then
+    f:SetParent(parent)
+  else
+    f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate")
+    -- ditch the old hotkey text because it's tied in ActionButton_Update() to the
+    -- standard binding.
+    local hotkey = _G[name.."HotKey"]
+    hotkey:SetParent(trash)
+    hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray")
+    hotkey:SetWidth(36)
+    hotkey:SetHeight(18)
+    hotkey:SetJustifyH("RIGHT")
+    hotkey:SetJustifyV("TOP")
+    hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
+    f.hotkey = hotkey
+    f.icon = _G[name.."Icon"]
+    f.flash = _G[name.."Flash"]
+    f:SetScript("OnUpdate",OnUpdate)
+  end
+
+  f._reactionButton = self
+
+  self.hotkey = f.hotkey
+  self.border = _G[name.."Border"]
+
+  f:SetAttribute("action", config.actionID)
+  f:SetAttribute("default-action", config.actionID)
+  -- install mind control actions for all buttons just for simplicity
+  if self.idx <= 12 then
+    f:SetAttribute("mindcontrol-action", 120 + self.idx)
+  end
+  
+  -- set a _childupdate handler, called within the header's context
+  f:SetAttribute("_childupdate", 
+    -- function _childupdate(self, snippetid, message)
+    [[
+      local action = "default-action"
+      if doMindControl and GetBonusBarOffset() == 5 then
+        action = "mindcontrol-action"
+      elseif page and state and page[state] then
+        action = "action-"..page[state]
       end
-      f.actionIDLabel:SetText(tostring(id))
-      f.actionIDLabel:Show()
-    elseif f.actionIDLabel then
-      f.actionIDLabel:Hide()
+      local value = self:GetAttribute(action)
+      if value then
+        self:SetAttribute("action",value)
+      end
+    ]])
+
+  -- install drag wrappers to lock buttons 
+  bar:GetFrame():WrapScript(f, "OnDragStart",
+    -- OnDragStart(self, button, kind, value, ...)
+    [[
+      if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+        return "clear"
+      end
+    ]])
+
+  self.frame = f
+
+  -- initialize the hide state
+  f:SetAttribute("showgrid",0)
+  self:ShowGrid(not barConfig.hideEmpty)
+  if ReAction:GetConfigMode() then
+    self:ShowGrid(true)
+  end
+
+  -- set the hotkey text
+  self.hotkey:SetText( GetHotkey(self.frame) )
+
+  -- show the ID label if applicable
+  self:ShowActionIDLabel(ReAction:GetConfigMode())
+
+  -- attach to skinner
+  bar:SkinButton(self,
+    {
+      HotKey = self.hotkey,
+    }
+  )
+
+  self:Refresh()
+  return self
+end
+
+function Button:Destroy()
+  local f = self.frame
+  f:UnregisterAllEvents()
+  f:Hide()
+  f:SetParent(UIParent)
+  f:ClearAllPoints()
+  if self.name then
+    frameRecycler[self.name] = f
+  end
+  if self.config.actionID then
+    IDAlloc:Release(self.config.actionID)
+  end
+  if self.config.pageactions then
+    for _, id in ipairs(self.config.pageactions) do
+      IDAlloc:Release(id)
     end
   end
+  f._reactionButton = nil
+  self.frame = nil
+  self.config = nil
+  self.bar = nil
+end
 
-  function Button:DisplayHotkey( key )
-    self.hotkey:SetText(key or "")
+function Button:Refresh()
+  local f = self.frame
+  self.bar:PlaceButton(self, 36, 36)
+  self:RefreshPages()
+end
+
+function Button:GetFrame()
+  return self.frame
+end
+
+function Button:GetName()
+  return self.name
+end
+
+function Button:GetConfig()
+  return self.config
+end
+
+function Button:GetActionID(page)
+  if page == nil then
+    -- get the effective ID
+    return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction()
+  else
+    if page == 1 then
+      return self.config.actionID
+    else
+      return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
+    end
   end
 end
+
+function Button:SetActionID( id, page )
+  id = tonumber(id)
+  page = tonumber(page)
+  if id == nil or id < 1 or id > 120 then
+    error("Button:SetActionID - invalid action ID")
+  end
+  if page and page ~= 1 then
+    if not self.config.pageactions then
+      self.config.pageactions = { }
+    end
+    if self.config.pageactions[page] then
+      IDAlloc:Release(self.config.pageactions[page])
+    end
+    self.config.pageactions[page] = id
+    IDAlloc:Acquire(self.config.pageactions[page])
+    self.frame:SetAttribute(("action-page%d"):format(page),id)
+  else
+    IDAlloc:Release(self.config.actionID)
+    self.config.actionID = id
+    IDAlloc:Acquire(self.config.actionID)
+    self.frame:SetAttribute("action",id)
+    if self.config.pageactions then
+      self.config.pageactions[1] = id
+      self.frame:SetAttribute("action-page1",id)
+    end
+  end
+end
+
+function Button:RefreshPages( force )
+  local nPages = self.barConfig.nPages
+  if nPages and (nPages ~= self.nPages or force) then
+    local f = self:GetFrame()
+    local c = self.config.pageactions
+    if nPages > 1 and not c then
+      c = { }
+      self.config.pageactions = c
+    end
+    for i = 1, nPages do
+      if i > 1 then
+        c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
+      else
+        c[i] = self.config.actionID  -- page 1 is the same as the base actionID
+      end
+      f:SetAttribute(("action-page%d"):format(i),c[i])
+    end
+    for i = nPages+1, #c do
+      IDAlloc:Release(c[i])
+      c[i] = nil
+      f:SetAttribute(("action-page%d"):format(i),nil)
+    end
+    self.nPages = nPages
+  end
+end
+
+function Button:ShowGrid( show )
+  if not InCombatLockdown() then
+    local f = self.frame
+    local count = f:GetAttribute("showgrid")
+    if show then
+      count = count + 1
+    else
+      count = count - 1
+    end
+    if count < 0 then
+      count = 0
+    end
+    f:SetAttribute("showgrid",count)
+
+    if count >= 1 and not f:GetAttribute("statehidden") then
+      if LBF then
+        LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5)
+      else
+        self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
+      end
+      f:Show()
+    elseif count < 1 and not HasAction(self:GetActionID()) then
+      f:Hide()
+    end
+  end
+end
+
+function Button:ShowActionIDLabel( show )
+  local f = self:GetFrame()
+  if show then
+    local id = self:GetActionID()
+    if not f.actionIDLabel then
+      local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+      label:SetAllPoints()
+      label:SetJustifyH("CENTER")
+      label:SetShadowColor(0,0,0,1)
+      label:SetShadowOffset(2,-2)
+      f.actionIDLabel = label -- store the label with the frame for recycling
+
+      f:HookScript("OnAttributeChanged", 
+        function(frame, attr, value)
+          if label:IsVisible() and attr:match("action") then
+            label:SetText(tostring(frame.action))
+          end
+        end)
+    end
+    f.actionIDLabel:SetText(tostring(id))
+    f.actionIDLabel:Show()
+  elseif f.actionIDLabel then
+    f.actionIDLabel:Hide()
+  end
+end
+
+function Button:SetKeybindMode( mode )
+  if mode then
+    KBAttach( self )
+    -- set the border for all buttons to the keybind-enable color
+    self.border:SetVertexColor(KB:GetColorKeyBoundMode())
+    self.border:Show()
+  elseif IsEquippedAction(self:GetActionID()) then
+    self.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua
+  else
+    self.border:Hide()
+  end
+end
\ No newline at end of file