annotate classes/Button.lua @ 235:1663c78a7f31

Don't blow away config for buttons the current character doesn't have yet
author Flick
date Thu, 24 Mar 2011 12:58:27 -0700
parents 0e20f65375d5
children dcdc0235d489
rev   line source
flickerstreak@122 1 --[[
flickerstreak@122 2 ReAction Button base class
flickerstreak@122 3 --]]
flickerstreak@122 4
flickerstreak@122 5 -- local imports
flickerstreak@175 6 local addonName, addonTable = ...
flickerstreak@175 7 local ReAction = addonTable.ReAction
flickerstreak@122 8 local L = ReAction.L
flickerstreak@183 9 local LKB = ReAction.LKB
flickerstreak@122 10 local _G = _G
flickerstreak@122 11 local CreateFrame = CreateFrame
flickerstreak@122 12 local GetBindingKey = GetBindingKey
flickerstreak@122 13 local format = string.format
flickerstreak@122 14
flickerstreak@122 15 -- private
flickerstreak@122 16 local trash = CreateFrame("Frame")
flickerstreak@122 17 local frameList = { }
flickerstreak@122 18 local idPools = { }
flickerstreak@122 19
flickerstreak@122 20 local function kb_onEnter( frame )
flickerstreak@183 21 LKB:Set(frame)
flickerstreak@122 22 end
flickerstreak@122 23
flickerstreak@122 24 -- Button class
flickerstreak@218 25 local buttonTypeID = "Button"
flickerstreak@218 26 local Button = {
flickerstreak@218 27 defaultBarConfig = {
flickerstreak@218 28 type = buttonTypeID,
flickerstreak@218 29 btnWidth = 36,
flickerstreak@218 30 btnHeight = 36,
flickerstreak@218 31 btnRows = 1,
flickerstreak@218 32 btnColumns = 12,
flickerstreak@218 33 spacing = 3
flickerstreak@218 34 },
flickerstreak@218 35 barType = L["Button Bar"]
flickerstreak@218 36 }
flickerstreak@122 37
flickerstreak@122 38 ReAction.Button = Button -- export to ReAction
flickerstreak@122 39
flickerstreak@129 40 function Button:New( name, config, bar, idx, inherits, buttonType )
flickerstreak@122 41 buttonType = buttonType or "CheckButton"
flickerstreak@122 42
flickerstreak@122 43 -- create new self
flickerstreak@122 44 self = setmetatable(
flickerstreak@122 45 {
flickerstreak@122 46 bar = bar,
flickerstreak@122 47 idx = idx,
flickerstreak@129 48 config = config,
flickerstreak@122 49 name = name,
flickerstreak@122 50 },
flickerstreak@122 51 { __index = self } )
flickerstreak@122 52
flickerstreak@122 53 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
flickerstreak@122 54 -- existing globals. Can't set to nil in the global because it's then tainted.
flickerstreak@122 55 -- Caller is responsible for ensuring global uniqueness of names.
flickerstreak@122 56 local f = name and frameList[name]
flickerstreak@122 57 if f then
flickerstreak@122 58 f:SetParent(bar:GetFrame())
flickerstreak@122 59 else
flickerstreak@122 60 f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
flickerstreak@122 61 if name then
flickerstreak@122 62 frameList[name] = f
flickerstreak@122 63 end
flickerstreak@122 64 end
flickerstreak@122 65
flickerstreak@122 66 self.frame = f
flickerstreak@122 67
flickerstreak@131 68 local frames = { }
flickerstreak@131 69 self.frames = frames
flickerstreak@131 70 frames.icon = _G[name.."Icon"]
flickerstreak@131 71 frames.flash = _G[name.."Flash"]
flickerstreak@131 72 frames.hotkey = _G[name.."HotKey"]
flickerstreak@131 73 frames.count = _G[name.."Count"]
flickerstreak@131 74 frames.name = _G[name.."Name"]
flickerstreak@131 75 frames.border = _G[name.."Border"]
flickerstreak@131 76 frames.cooldown = _G[name.."Cooldown"]
flickerstreak@131 77 frames.normalTexture = _G[name.."NormalTexture"]
flickerstreak@131 78
flickerstreak@122 79 if config then
flickerstreak@122 80 config.name = name
flickerstreak@122 81 end
flickerstreak@122 82
flickerstreak@122 83 -- install LibKeyBound handlers onto frame
flickerstreak@122 84 function f:GetActionName()
flickerstreak@122 85 return format("%s:%s", bar:GetName(), idx)
flickerstreak@122 86 end
flickerstreak@122 87
flickerstreak@122 88 local clickBinding = format("CLICK %s:LeftButton", name)
flickerstreak@122 89 function f:GetHotkey()
flickerstreak@183 90 return LKB:ToShortKey(GetBindingKey(clickBinding))
flickerstreak@122 91 end
flickerstreak@122 92
flickerstreak@122 93 return self
flickerstreak@122 94 end
flickerstreak@122 95
flickerstreak@122 96 function Button:Destroy()
flickerstreak@126 97 local f = self:GetFrame()
flickerstreak@132 98 f:UnregisterAllEvents()
flickerstreak@132 99 self:ReleaseActionID(self:GetActionID())
flickerstreak@126 100 if f then
flickerstreak@126 101 f:Hide()
flickerstreak@126 102 f:SetParent(trash)
flickerstreak@126 103 f:ClearAllPoints()
flickerstreak@126 104 end
flickerstreak@122 105 end
flickerstreak@122 106
flickerstreak@128 107 function Button:GetBar()
flickerstreak@128 108 return self.bar
flickerstreak@128 109 end
flickerstreak@128 110
flickerstreak@122 111 function Button:GetFrame()
flickerstreak@122 112 return self.frame
flickerstreak@122 113 end
flickerstreak@122 114
Flick@234 115 function Button:GetIndex()
Flick@234 116 return self.idx
Flick@234 117 end
Flick@234 118
flickerstreak@122 119 function Button:GetName()
flickerstreak@122 120 return self.name
flickerstreak@122 121 end
flickerstreak@122 122
flickerstreak@218 123 function Button:GetDefaultBarConfig()
flickerstreak@218 124 return self.defaultBarConfig
flickerstreak@218 125 end
flickerstreak@218 126
flickerstreak@218 127 function Button:GetBarType()
flickerstreak@218 128 return self.barType
flickerstreak@218 129 end
flickerstreak@218 130
Flick@231 131 function Button:GetButtonTypeID()
Flick@231 132 return self.buttonTypeID
Flick@231 133 end
Flick@231 134
flickerstreak@122 135 function Button:GetConfig()
flickerstreak@122 136 return self.config
flickerstreak@122 137 end
flickerstreak@122 138
flickerstreak@122 139 function Button:GetActionID()
flickerstreak@122 140 -- derived classes should override this
flickerstreak@122 141 return nil
flickerstreak@122 142 end
flickerstreak@122 143
flickerstreak@122 144 function Button:SetActionIDPool( poolID, maxID )
flickerstreak@122 145 self.actionPoolID = poolID
flickerstreak@122 146 self.actionMaxID = maxID
flickerstreak@122 147 end
flickerstreak@122 148
Flick@234 149 function Button:SetupBar( bar )
Flick@234 150 local config = bar:GetConfig()
Flick@234 151 if not config.buttons then
Flick@234 152 config.buttons = { }
Flick@234 153 end
Flick@234 154 local btnCfg = config.buttons
Flick@234 155
Flick@234 156 local r, c = bar:GetButtonGrid()
Flick@234 157 local n = r*c
Flick@235 158 local cfgN = n
Flick@234 159
Flick@234 160 local hint = nil
Flick@234 161 local i = 1
Flick@234 162 repeat
Flick@234 163 local b = bar:GetButton(i)
Flick@234 164 if b then
Flick@234 165 if i > n then
Flick@234 166 bar:RemoveButton(b)
Flick@234 167 b:Destroy()
Flick@235 168 if i > cfgN then
Flick@235 169 btnCfg[i] = nil
Flick@235 170 end
Flick@234 171 else
Flick@234 172 b:Refresh()
Flick@234 173 hint = b:GetActionID()
Flick@234 174 end
Flick@234 175 elseif i <= n then
Flick@234 176 local cfg = btnCfg[i] or { }
Flick@234 177 local success, r = pcall(self.New, self, cfg, bar, i, hint) -- note call semantics for derived class constructors
Flick@234 178 if success and r then
Flick@234 179 b = r
Flick@234 180 bar:AddButton(i,b)
Flick@234 181 btnCfg[i] = cfg
Flick@234 182 b:Refresh()
Flick@234 183 hint = b:GetActionID()
Flick@234 184 else
Flick@234 185 n = i - 1
Flick@234 186 bar:ClipNButtons(n)
Flick@234 187 if not success then
Flick@234 188 geterrorhandler()(r)
Flick@234 189 end
Flick@234 190 end
Flick@234 191 end
Flick@234 192 i = i + 1
Flick@234 193 until b == nil
Flick@234 194 end
Flick@234 195
flickerstreak@122 196 function Button:AcquireActionID( id, hint, unique )
flickerstreak@122 197 local poolID = self.actionPoolID
flickerstreak@122 198 local maxID = self.actionMaxID
flickerstreak@122 199 if not poolID or not maxID then
flickerstreak@122 200 error("AcquireActionID: must setup pool first with SetActionIDPool")
flickerstreak@122 201 end
flickerstreak@123 202 local pool = idPools[poolID]
flickerstreak@122 203 if not pool then
flickerstreak@122 204 pool = { nWraps = 0, useCount = { } }
flickerstreak@122 205 for i = 1, maxID do
flickerstreak@122 206 pool.useCount[i] = 0
flickerstreak@122 207 end
flickerstreak@123 208 idPools[poolID] = pool
flickerstreak@122 209 end
flickerstreak@122 210 local useCount = pool.useCount
flickerstreak@122 211 if id == nil then
flickerstreak@122 212 repeat
flickerstreak@126 213 local nWraps = pool.nWraps or 0
flickerstreak@126 214 if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
flickerstreak@122 215 id = hint
flickerstreak@122 216 else
flickerstreak@122 217 local start = hint or 1
flickerstreak@122 218 for i = start, maxID do
flickerstreak@122 219 if useCount[i] == nil or useCount[i] == nWraps then
flickerstreak@122 220 id = i
flickerstreak@122 221 break
flickerstreak@122 222 end
flickerstreak@122 223 end
flickerstreak@122 224 if not id then
flickerstreak@122 225 for i = 1, start do
flickerstreak@122 226 if useCount[i] == nil or useCount[i] == nWraps then
flickerstreak@122 227 id = i
flickerstreak@122 228 break
flickerstreak@122 229 end
flickerstreak@122 230 end
flickerstreak@122 231 end
flickerstreak@122 232 end
flickerstreak@122 233 if id == nil then
flickerstreak@122 234 if unique then
flickerstreak@122 235 return nil
flickerstreak@122 236 end
flickerstreak@122 237 pool.nWraps = nWraps + 1
flickerstreak@122 238 end
flickerstreak@126 239 until id ~= nil
flickerstreak@122 240 end
flickerstreak@122 241 useCount[id] = (useCount[id] or 0) + 1
flickerstreak@122 242 return id
flickerstreak@122 243 end
flickerstreak@122 244
flickerstreak@122 245 function Button:ReleaseActionID( id )
flickerstreak@122 246 local poolID = self.actionPoolID
flickerstreak@122 247 if not poolID then
flickerstreak@122 248 error("ReleaseActionID: must setup pool first with SetActionIDPool")
flickerstreak@122 249 end
flickerstreak@123 250 local pool = idPools[poolID]
flickerstreak@122 251 if pool and id and pool.useCount[id] then
flickerstreak@122 252 pool.useCount[id] = pool.useCount[id] - 1
flickerstreak@122 253 pool.nWraps = min(pool.useCount[id], pool.nWraps)
flickerstreak@122 254 end
flickerstreak@122 255 end
flickerstreak@122 256
flickerstreak@122 257 function Button:Refresh()
flickerstreak@129 258 local f = self:GetFrame()
flickerstreak@129 259 self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
flickerstreak@122 260 end
flickerstreak@122 261
flickerstreak@122 262 function Button:SetKeybindMode( mode )
flickerstreak@122 263 local f = self.frame
flickerstreak@122 264 if mode then
flickerstreak@122 265 self.oldOnEnter = f:GetScript("OnEnter")
flickerstreak@122 266 f:SetScript("OnEnter", kb_onEnter)
flickerstreak@124 267 elseif self.oldOnEnter then
flickerstreak@122 268 f:SetScript("OnEnter", self.oldOnEnter)
flickerstreak@122 269 self.oldOnEnter = nil
flickerstreak@122 270 end
flickerstreak@128 271 self:ShowGridTemp(mode)
flickerstreak@122 272 self:UpdateKeybindModeDisplay( mode )
flickerstreak@122 273 end
flickerstreak@122 274
flickerstreak@122 275 function Button:UpdateKeybindModeDisplay( mode )
flickerstreak@131 276 local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
flickerstreak@131 277 if border then
flickerstreak@122 278 if mode then
flickerstreak@183 279 border:SetVertexColor(LKB:GetColorKeyBoundMode())
flickerstreak@131 280 border:Show()
flickerstreak@122 281 else
flickerstreak@131 282 border:Hide()
flickerstreak@122 283 end
flickerstreak@122 284 end
flickerstreak@122 285 end
flickerstreak@122 286
flickerstreak@122 287 function Button:UpdateHotkey( hotkey )
flickerstreak@131 288 hotkey = hotkey or self.frames.hotkey
flickerstreak@122 289 if not hotkey then
flickerstreak@129 290 hotkey = _G[self:GetName().."HotKey"]
flickerstreak@131 291 self.frames.hotkey = hotkey
flickerstreak@122 292 end
flickerstreak@122 293 if hotkey then
flickerstreak@122 294 local txt = self.frame:GetHotkey()
flickerstreak@122 295 hotkey:SetText( txt )
flickerstreak@122 296 if txt == nil or txt == "" then
flickerstreak@122 297 hotkey:Hide()
flickerstreak@122 298 else
flickerstreak@122 299 hotkey:Show()
flickerstreak@122 300 end
flickerstreak@122 301 end
flickerstreak@122 302 end
flickerstreak@122 303
flickerstreak@122 304 function Button:GetActionIDLabel( create )
flickerstreak@129 305 local f = self:GetFrame()
flickerstreak@122 306 if not f.actionIDLabel and create then
flickerstreak@122 307 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
flickerstreak@122 308 label:SetAllPoints()
flickerstreak@122 309 label:SetJustifyH("CENTER")
flickerstreak@122 310 label:SetShadowColor(0,0,0,1)
flickerstreak@122 311 label:SetShadowOffset(2,-2)
flickerstreak@122 312 f.actionIDLabel = label -- store the label with the frame for recycling
flickerstreak@122 313 end
flickerstreak@122 314 return f.actionIDLabel
flickerstreak@122 315 end
flickerstreak@122 316
flickerstreak@122 317 function Button:UpdateActionIDLabel( show )
flickerstreak@122 318 local label = self:GetActionIDLabel( show )
flickerstreak@122 319 if label then
flickerstreak@122 320 if show then
flickerstreak@122 321 local id = self:GetActionID()
flickerstreak@122 322 if id then
flickerstreak@122 323 label:SetText(tostring(id))
flickerstreak@122 324 label:Show()
flickerstreak@122 325 return
flickerstreak@122 326 end
flickerstreak@122 327 end
flickerstreak@122 328 label:Hide()
flickerstreak@122 329 end
flickerstreak@122 330 end
flickerstreak@122 331
flickerstreak@122 332 function Button:SetNormalVertexColor( r, g, b, a )
flickerstreak@213 333 if ReAction.LBF then
flickerstreak@213 334 ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
flickerstreak@122 335 else
flickerstreak@129 336 self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
flickerstreak@122 337 end
flickerstreak@122 338 end
flickerstreak@122 339
flickerstreak@122 340 function Button:GetNormalVertexColor()
flickerstreak@213 341 if ReAction.LBF then
flickerstreak@213 342 return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
flickerstreak@122 343 else
flickerstreak@129 344 return self:GetFrame():GetNormalTexture():GetVertexColor()
flickerstreak@122 345 end
flickerstreak@122 346 end
flickerstreak@122 347
flickerstreak@122 348 function Button:UpdateShowGrid()
flickerstreak@122 349 -- does nothing by default
flickerstreak@122 350 end
flickerstreak@128 351
flickerstreak@128 352 function Button:ShowGridTemp(show)
flickerstreak@128 353 -- does nothing by default
flickerstreak@128 354 end
flickerstreak@128 355
flickerstreak@128 356 function Button:ShowGrid(show)
flickerstreak@128 357 -- does nothing by default
flickerstreak@128 358 end