Mercurial > wow > reaction
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 } |