diff Button.lua @ 245:65f2805957a0

No real reason to store some of the code in a subdirectory.
author Flick
date Sat, 26 Mar 2011 12:35:08 -0700
parents classes/Button.lua@dcdc0235d489
children 46b59a9ded76
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Button.lua	Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,359 @@
+--[[
+  ReAction Button base class
+--]]
+
+-- local imports
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local _G = _G
+local CreateFrame = CreateFrame
+local GetBindingKey = GetBindingKey
+local format = string.format
+
+-- private
+local trash = CreateFrame("Frame")
+local frameList = { }
+local idPools = { }
+
+local function kb_onEnter( frame )
+  LKB:Set(frame)
+end
+
+-- Button class
+local buttonTypeID = "Button"
+local Button = { 
+  defaultBarConfig = {
+    type = buttonTypeID,
+    btnWidth = 36,
+    btnHeight = 36,
+    btnRows = 1,
+    btnColumns = 12,
+    spacing = 3
+  },
+  barType = L["Button Bar"]
+} 
+
+ReAction.Button = Button -- export to ReAction
+
+function Button:New( name, config, bar, idx, inherits, buttonType )
+  buttonType = buttonType or "CheckButton"
+
+  -- create new self
+  self = setmetatable( 
+    { 
+      bar = bar,
+      idx = idx,
+      config = config,
+      name = name,
+    }, 
+    { __index = self } )
+
+  -- 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.
+  -- Caller is responsible for ensuring global uniqueness of names.
+  local f = name and frameList[name]
+  if f then
+    f:SetParent(bar:GetFrame())
+  else
+    f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
+    if name then
+      frameList[name] = f
+    end
+  end
+
+  self.frame = f
+
+  local frames = { }
+  self.frames = frames
+  frames.icon          = _G[name.."Icon"]
+  frames.flash         = _G[name.."Flash"]
+  frames.hotkey        = _G[name.."HotKey"]
+  frames.count         = _G[name.."Count"]
+  frames.name          = _G[name.."Name"]
+  frames.border        = _G[name.."Border"]
+  frames.cooldown      = _G[name.."Cooldown"]
+  frames.normalTexture = _G[name.."NormalTexture"]
+
+  if config then
+    config.name = name
+  end
+
+  -- install LibKeyBound handlers onto frame
+  function f:GetActionName()
+    return format("%s:%s", bar:GetName(), idx)
+  end
+
+  local clickBinding = format("CLICK %s:LeftButton", name)
+  function f:GetHotkey()
+    return LKB:ToShortKey(GetBindingKey(clickBinding))
+  end
+
+  return self
+end
+
+function Button:Destroy()
+  local f = self:GetFrame()
+  f:UnregisterAllEvents()
+  self:ReleaseActionID(self:GetActionID())
+  if f then
+    f:Hide()
+    f:SetParent(trash)
+    f:ClearAllPoints()
+  end
+end
+
+function Button:GetBar()
+  return self.bar
+end
+
+function Button:GetFrame()
+  return self.frame
+end
+
+function Button:GetIndex()
+  return self.idx
+end
+
+function Button:GetName()
+  return self.name
+end
+
+function Button:GetDefaultBarConfig()
+  return self.defaultBarConfig
+end
+
+function Button:GetBarType()
+  return self.barType
+end
+
+function Button:GetButtonTypeID()
+  return self.buttonTypeID
+end
+
+function Button:GetConfig()
+  return self.config
+end
+
+function Button:GetActionID()
+  -- derived classes should override this
+  return nil
+end
+
+function Button:SetActionIDPool( poolID, maxID )
+  self.actionPoolID = poolID
+  self.actionMaxID = maxID
+end
+
+function Button:SetupBar( bar )
+  local config = bar:GetConfig()
+  if not config.buttons then
+    config.buttons = { }
+  end
+  local btnCfg = config.buttons
+
+  local r, c = bar:GetButtonGrid()
+  local n = r*c
+  local cfgN = n
+
+  local hint = nil
+  local i = 1
+  repeat
+    local b = bar:GetButton(i)
+    if b then
+      if i > n then
+        bar:RemoveButton(b)
+        b:Destroy()
+        if i > cfgN then
+          btnCfg[i] = nil
+        end
+      else
+        b:Refresh()
+        hint = b:GetActionID()
+      end
+    elseif i <= n then
+      local cfg = btnCfg[i] or { }
+      local success, r = pcall(self.New, self, cfg, bar, i, hint)  -- note call semantics for derived class constructors
+      if success and r then
+        b = r
+        bar:AddButton(i,b)
+        btnCfg[i] = cfg
+        b:Refresh()
+        hint = b:GetActionID()
+      else
+        n = i - 1
+        if not success then
+          bar:ClipNButtons(n)
+          cfgN = n
+          geterrorhandler()(r)
+        end
+      end
+    end
+    i = i + 1
+  until b == nil
+end
+
+function Button:AcquireActionID( id, hint, unique )
+  local poolID = self.actionPoolID
+  local maxID = self.actionMaxID
+  if not poolID or not maxID then
+    error("AcquireActionID: must setup pool first with SetActionIDPool")
+  end
+  local pool = idPools[poolID]
+  if not pool then
+    pool = { nWraps = 0, useCount = { } }
+    for i = 1, maxID do
+      pool.useCount[i] = 0
+    end
+    idPools[poolID] = pool
+  end
+  local useCount = pool.useCount
+  if id == nil then
+    repeat
+      local nWraps = pool.nWraps or 0
+      if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
+        id = hint
+      else
+        local start = hint or 1
+        for i = start, maxID do
+          if useCount[i] == nil or useCount[i] == nWraps then
+            id = i
+            break
+          end
+        end
+        if not id then
+          for i = 1, start do
+            if useCount[i] == nil or useCount[i] == nWraps then
+              id = i
+              break
+            end
+          end
+        end
+      end
+      if id == nil then
+        if unique then
+          return nil
+        end
+        pool.nWraps = nWraps + 1
+      end
+    until id ~= nil
+  end
+  useCount[id] = (useCount[id] or 0) + 1
+  return id
+end
+
+function Button:ReleaseActionID( id )
+  local poolID = self.actionPoolID
+  if not poolID  then
+    error("ReleaseActionID: must setup pool first with SetActionIDPool")
+  end
+  local pool = idPools[poolID]
+  if pool and id and pool.useCount[id] then
+    pool.useCount[id] = pool.useCount[id] - 1
+    pool.nWraps = min(pool.useCount[id], pool.nWraps)
+  end
+end
+
+function Button:Refresh()
+  local f = self:GetFrame()
+  self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
+end
+
+function Button:SetKeybindMode( mode )
+  local f = self.frame
+  if mode then
+    self.oldOnEnter = f:GetScript("OnEnter")
+    f:SetScript("OnEnter", kb_onEnter)
+  elseif self.oldOnEnter then
+    f:SetScript("OnEnter", self.oldOnEnter)
+    self.oldOnEnter = nil
+  end
+  self:ShowGridTemp(mode)
+  self:UpdateKeybindModeDisplay( mode )
+end
+
+function Button:UpdateKeybindModeDisplay( mode )
+  local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
+  if border then
+    if mode then
+      border:SetVertexColor(LKB:GetColorKeyBoundMode())
+      border:Show()
+    else
+      border:Hide()
+    end
+  end
+end
+
+function Button:UpdateHotkey( hotkey )
+  hotkey = hotkey or self.frames.hotkey
+  if not hotkey then
+    hotkey = _G[self:GetName().."HotKey"]
+    self.frames.hotkey = hotkey
+  end
+  if hotkey then
+    local txt = self.frame:GetHotkey()
+    hotkey:SetText( txt )
+    if txt == nil or txt == "" then
+      hotkey:Hide()
+    else
+      hotkey:Show()
+    end
+  end
+end
+
+function Button:GetActionIDLabel( create )
+  local f = self:GetFrame()
+  if not f.actionIDLabel and create 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
+  end
+  return f.actionIDLabel
+end
+
+function Button:UpdateActionIDLabel( show )
+  local label = self:GetActionIDLabel( show )
+  if label then
+    if show then
+      local id = self:GetActionID()
+      if id then
+        label:SetText(tostring(id))
+        label:Show()
+        return
+      end
+    end
+    label:Hide()
+  end
+end
+
+function Button:SetNormalVertexColor( r, g, b, a )
+  if ReAction.LBF then
+    ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
+  else
+    self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
+  end
+end
+
+function Button:GetNormalVertexColor()
+  if ReAction.LBF then
+    return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
+  else
+    return self:GetFrame():GetNormalTexture():GetVertexColor()
+  end
+end
+
+function Button:UpdateShowGrid()
+ -- does nothing by default
+end
+
+function Button:ShowGridTemp(show)
+  -- does nothing by default
+end
+
+function Button:ShowGrid(show)
+  -- does nothing by default
+end