comparison Bar.lua @ 77:da8ba8783924

- added revision updater to each code file - Changed button/bar class mechanic to metatable-based - Changed buttons to live within a sub-frame, to play nicely between show-empty-buttons and hidestates - bar frame is now available only via accessor - Changed some semantics with AddButton/PlaceButton - Cleaned up action buttons options, fixed hide-when-empty option - moved show-action-ID-label as a button method - converted drag overlay from nested-frame to :Raise() - fixed ReAction:SetConfigMode() to not call event when mode doesn't change - Fixed ordering for dynamic state tab (always last)
author Flick <flickerstreak@gmail.com>
date Mon, 23 Jun 2008 22:27:50 +0000
parents 06cd74bdc7da
children 57f8151ea0f0
comparison
equal deleted inserted replaced
76:c8c8610fd864 77:da8ba8783924
5 local floor = math.floor 5 local floor = math.floor
6 local fmod = math.fmod 6 local fmod = math.fmod
7 local format = string.format 7 local format = string.format
8 local SecureStateHeader_Refresh = SecureStateHeader_Refresh 8 local SecureStateHeader_Refresh = SecureStateHeader_Refresh
9 9
10 10 ReAction:UpdateRevision("$Revision$")
11 -- update ReAction revision if this file is newer
12 local revision = tonumber(("$Revision$"):match("%d+"))
13 if revision > ReAction.revision then
14 ReAction.revision = revision
15 end
16 11
17 12
18 ------ BAR CLASS ------ 13 ------ BAR CLASS ------
19 local Bar = { _classID = {} } 14 local Bar = { _classID = {} }
20 15 ReAction.Bar = Bar -- export to ReAction
21 local function Constructor( self, name, config ) 16
17 function Bar:New( name, config )
18 -- create new self
19 self = setmetatable( { }, {__index = Bar} )
22 if type(config) ~= "table" then 20 if type(config) ~= "table" then
23 error("ReAction.Bar: config table required") 21 error("ReAction.Bar: config table required")
24 end 22 end
25 config.width = config.width or 480 23 config.width = config.width or 480
26 config.height = config.height or 40 24 config.height = config.height or 40
30 self.statedrivers = { } 28 self.statedrivers = { }
31 self.keybinds = { } 29 self.keybinds = { }
32 30
33 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent 31 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
34 local f = CreateFrame("Button",name and format("ReAction-%s",name),parent,"SecureStateHeaderTemplate, SecureActionButtonTemplate") 32 local f = CreateFrame("Button",name and format("ReAction-%s",name),parent,"SecureStateHeaderTemplate, SecureActionButtonTemplate")
35 33 f:SetFrameStrata("MEDIUM")
36 -- The frame itself is read-only 34 f:SetWidth(config.width)
37 function self:GetFrame() 35 f:SetWidth(config.height)
38 return f 36 f:Show()
39 end
40 37
41 -- The bar itself is also a Button derived from SecureActionButtonTemplate, so it has an OnClick handler 38 -- The bar itself is also a Button derived from SecureActionButtonTemplate, so it has an OnClick handler
42 -- which we can use as a virtual button for keybinds, which will send attribute-value changes to itself. 39 -- which we can use as a virtual button for keybinds, which will send attribute-value changes to itself.
43 -- However, we don't ever want the user to be able to click it directly. 40 -- However, we don't ever want the user to be able to click it directly.
44 f:EnableMouse(false) 41 f:EnableMouse(false)
45 f:SetAttribute("type","attribute") 42 f:SetAttribute("type","attribute")
46 f:SetFrameStrata("MEDIUM") 43
47 f:SetWidth(config.width) 44 -- Buttons are contained in an anonymous intermediate sub-frame. This arrangement is to specifically
48 f:SetWidth(config.height) 45 -- address the issue of the interaction with hidestates and auto-hiding empty action buttons (the two
49 f:Show() 46 -- don't play nicely together). It also has the fringe benefit of making show/hide faster because a
47 -- single frame is shown/hidden instead of potentially dozens. Unfortunately it does add an extra layer
48 -- of indirection to all state changes, as a secondary (trivial) statemap must be invoked. This
49 -- complicates frame setup slightly.
50 local bf = CreateFrame("Frame", nil, f, "SecureStateHeaderTemplate")
51 bf:SetAllPoints()
52 bf:Show()
53 bf:SetAttribute("useparent*",true) -- this facilitates SecureButton_GetModifiedAttribute()
54 bf:SetAttribute("statemap-parent","*:=") -- however some methods don't use it, so propagate the state too
55 f:SetAttribute("addchild",bf)
56
57 -- Both frames are read-only. Override the default accessors for this object.
58 function self:GetFrame()
59 return f
60 end
61
62 function self:GetButtonFrame()
63 return bf
64 end
50 65
51 self:ApplyAnchor() 66 self:ApplyAnchor()
52 ReAction.RegisterCallback(self, "OnConfigModeChanged") 67 ReAction.RegisterCallback(self, "OnConfigModeChanged")
68
69 return self
53 end 70 end
54 71
55 function Bar:Destroy() 72 function Bar:Destroy()
56 local f = self:GetFrame() 73 local f = self:GetFrame()
57 f:UnregisterAllEvents() 74 f:UnregisterAllEvents()
156 173
157 function Bar:GetName() 174 function Bar:GetName()
158 return self.name 175 return self.name
159 end 176 end
160 177
178 function Bar:GetFrame()
179 -- this method is included for documentation purposes. It is overridden
180 -- in the New method for each object.
181 error("Invalid Bar object: used without initialization")
182 end
183
184 function Bar:GetButtonFrame()
185 -- this method is included for documentation purposes. It is overridden
186 -- in the New method for each object.
187 error("Invalid Bar object: used without initialization")
188 end
189
161 -- only ReAction:RenameBar() should call this function 190 -- only ReAction:RenameBar() should call this function
162 function Bar:SetName(name) 191 function Bar:SetName(name)
163 self.name = name 192 self.name = name
164 -- controlLabelString is defined in Overlay.lua 193 -- controlLabelString is defined in Overlay.lua
165 if self.controlLabelString then 194 if self.controlLabelString then
166 self.controlLabelString:SetText(self.name) 195 self.controlLabelString:SetText(self.name)
167 end 196 end
168 end 197 end
169 198
170 function Bar:AddButton(idx, button) 199 function Bar:AddButton(idx, button)
200 -- store in a reverse-index array
171 self.buttons[button] = idx 201 self.buttons[button] = idx
202 self:GetButtonFrame():SetAttribute("addchild",button:GetFrame())
172 SecureStateHeader_Refresh(self:GetFrame()) 203 SecureStateHeader_Refresh(self:GetFrame())
173 end 204 end
174 205
175 function Bar:RemoveButton(button) 206 function Bar:RemoveButton(button)
176 self.buttons[button] = nil 207 self.buttons[button] = nil
232 UnregisterStateDriver(f, name) 263 UnregisterStateDriver(f, name)
233 self.statedrivers[name] = nil 264 self.statedrivers[name] = nil
234 end 265 end
235 end 266 end
236 267
237 -- Set an attribute on the frame (or its buttons if 'doButtons' = true) 268 -- Set an attribute on the frame (or buttonFrame if 'buttonFrame' = true)
238 -- Either or both 'map' and 'default' can be passed: 269 -- Either or both 'map' and 'default' can be passed:
239 -- - If 'map' is omitted, then 'default' is set to the attribute. 270 -- - If 'map' is omitted, then 'default' is set to the attribute.
240 -- - If 'map' is provided, then it is interpreted as an unordered 271 -- - If 'map' is provided, then it is interpreted as an unordered
241 -- table of the form { ["statename"] = ["value"] }, and will be 272 -- table of the form { ["statename"] = ["value"] }, and will be
242 -- converted into a SecureStateHeaderTemplate style state-parsed 273 -- converted into a SecureStateHeaderTemplate style state-parsed
243 -- string, e.g. "<state1>:<value1>;<state2>:<value2>". If 'default' 274 -- string, e.g. "<state1>:<value1>;<state2>:<value2>". If 'default'
244 -- is also provided, then its value will be converted to a string 275 -- is also provided, then its value will be converted to a string
245 -- and appended. 276 -- and appended.
246 function Bar:SetStateAttribute( attribute, map, default, doButtons ) 277 function Bar:SetStateAttribute( attribute, map, default, buttonFrame )
278 local f = buttonFrame and self:GetButtonFrame() or self:GetFrame()
247 local value = default 279 local value = default
248 if map then 280 if map then
249 local tmp = { } 281 local tmp = { }
250 for state, value in pairs(map) do 282 for state, value in pairs(map) do
251 table.insert(tmp, format("%s:%s",tostring(state),tostring(value))) 283 table.insert(tmp, format("%s:%s",tostring(state),tostring(value)))
253 if default then 285 if default then
254 table.insert(tmp, tostring(default)) 286 table.insert(tmp, tostring(default))
255 end 287 end
256 value = table.concat(tmp,";") 288 value = table.concat(tmp,";")
257 end 289 end
258 if doButtons then 290 f:SetAttribute(attribute, value)
259 for b in pairs(self.buttons) do 291 SecureStateHeader_Refresh(f)
260 local f = b.GetFrame and b:GetFrame() 292 end
261 if f then
262 f:SetAttribute(attribute, value)
263 end
264 end
265 else
266 self:GetFrame():SetAttribute(attribute, value)
267 end
268 SecureStateHeader_Refresh(self:GetFrame())
269 end
270
271
272 ------ Export as a class-factory ------
273 ReAction.Bar = {
274 prototype = Bar,
275 New = function(self, ...)
276 local x = { }
277 for k,v in pairs(Bar) do
278 x[k] = v
279 end
280 Constructor(x, ...)
281 return x
282 end
283 }