Mercurial > wow > reaction
comparison State.lua @ 90:7cabc8ac6c16
Updates for wow 3.0
- TOC update
- updated changed APIs/frame names
- rewrote state code per new SecureHandlers API
- cleaned up Bar, ActionButton code
- removed AceLibrary/Dewdrop, menu from bar right-click
- fixed various small bugs
Updated WowAce external locations
Updated README.html
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Wed, 15 Oct 2008 16:29:41 +0000 |
parents | 1ad208c25618 |
children | c2504a8b996c |
comparison
equal
deleted
inserted
replaced
89:491a6ffe7260 | 90:7cabc8ac6c16 |
---|---|
5 | 5 |
6 -- local imports | 6 -- local imports |
7 local ReAction = ReAction | 7 local ReAction = ReAction |
8 local L = ReAction.L | 8 local L = ReAction.L |
9 local _G = _G | 9 local _G = _G |
10 local format = string.format | |
10 local InCombatLockdown = InCombatLockdown | 11 local InCombatLockdown = InCombatLockdown |
11 local format = string.format | 12 local RegisterStateDriver = RegisterStateDriver |
12 | 13 |
13 ReAction:UpdateRevision("$Revision$") | 14 ReAction:UpdateRevision("$Revision$") |
14 | 15 |
15 -- module declaration | 16 -- module declaration |
16 local moduleID = "State" | 17 local moduleID = "State" |
51 end) | 52 end) |
52 return r | 53 return r |
53 end | 54 end |
54 | 55 |
55 | 56 |
56 local InitRules, ApplyStates, SetProperty, GetProperty, RegisterProperty | 57 local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty, ShowAll |
57 | 58 |
58 -- PRIVATE -- | 59 -- PRIVATE -- |
59 do | 60 do |
61 | |
62 -- the field names must match the field names of the options table, below | |
63 -- the field values are secure snippets | |
64 local properties = { | |
65 hide = | |
66 [[ | |
67 local h = hide and hide[state] and not showAll | |
68 if h ~= hidden then | |
69 if h then | |
70 self:Hide() | |
71 else | |
72 self:Show() | |
73 end | |
74 hidden = h | |
75 end | |
76 ]], | |
77 | |
78 --keybindState TODO: broken | |
79 | |
80 -- the anchoring is handled in a special handler | |
81 anchorEnable = true, | |
82 --anchorFrame = true, TODO: broken | |
83 anchorPoint = true, | |
84 anchorRelPoint = true, | |
85 anchorX = true, | |
86 anchorY = true, | |
87 enableScale = true, | |
88 scale = true, | |
89 } | |
90 | |
91 | |
92 -- | |
93 -- Secure Handler Snippets | |
94 -- | |
95 local SetHandlerData, SetStateDriver, SetStateKeybind, RefreshState | |
96 do | |
97 local stateHandler_propInit = | |
98 [[ | |
99 propfuncs = table.new() | |
100 local proplist = self:GetAttribute("prop-func-list") | |
101 for s in string.gmatch(proplist, "(%w+)") do | |
102 table.insert(propfuncs, s) | |
103 end | |
104 ]] | |
105 | |
106 local onStateHandler = | |
107 -- function _onstate-reaction( self, stateid, newstate ) | |
108 [[ | |
109 print("received state",newstate,"on bar",self:GetName()) | |
110 set_state = newstate or set_state | |
111 | |
112 local oldState = state | |
113 state = state_override or set_state or state | |
114 | |
115 for i = 1, #propfuncs do | |
116 print("running state func",propfuncs[i]) | |
117 control:RunAttribute("func-"..propfuncs[i]) | |
118 end | |
119 | |
120 if anchorEnable and anchorEnable[state] ~= anchorstate then | |
121 anchorstate = anchorEnable[state] | |
122 control:RunAttribute("func-doanchor") | |
123 end | |
124 | |
125 control:ChildUpdate() | |
126 ]] | |
127 | |
128 local anchorHandler = | |
129 -- function func-doanchor( self ) | |
130 [[ | |
131 -- TODO | |
132 if anchorstate then | |
133 -- TODO: get anchor data from state tables | |
134 else | |
135 -- TODO: get anchor data from defaults | |
136 end | |
137 ]] | |
138 | |
139 local onClickHandler = | |
140 -- function OnClick( self, button, down ) | |
141 [[ | |
142 if state_override == button then | |
143 state_override = nil -- toggle | |
144 else | |
145 state_override = button | |
146 end | |
147 ]] .. onStateHandler | |
148 | |
149 local weak = { __mode = "k" } | |
150 local statedrivers = setmetatable( { }, weak ) | |
151 local keybinds = setmetatable( { }, weak ) | |
152 | |
153 -- Construct a lua assignment as a code string and execute it within the header | |
154 -- frame's sandbox. 'value' must be a string, boolean, number, or nil. If called | |
155 -- with four arguments, then it treats 'varname' as an existing global table and | |
156 -- sets a key-value pair. For a slight efficiency boost, pass the values in as | |
157 -- attributes and fetch them as attributes from the snippet code, to leverage snippet | |
158 -- caching. | |
159 function SetHandlerData( bar, varname, value, key ) | |
160 local f = bar:GetFrame() | |
161 f:SetAttribute("data-varname",varname) | |
162 f:SetAttribute("data-value", value) | |
163 f:SetAttribute("data-key", key) | |
164 f:Execute( | |
165 [[ | |
166 local name = self:GetAttribute("data-varname") | |
167 local value = self:GetAttribute("data-value") | |
168 local key = self:GetAttribute("data-key") | |
169 if name then | |
170 if key then | |
171 if not _G[name] then | |
172 _G[name] = table.new() | |
173 end | |
174 _G[name][key] = value | |
175 else | |
176 _G[name] = value | |
177 end | |
178 end | |
179 ]]) | |
180 end | |
181 | |
182 function SetDefaultAnchor( bar ) | |
183 local point, frame, relPoint, x, y = bar:GetAnchor() | |
184 SetHandlerData(bar, "defaultAnchor", point, "point") | |
185 SetHandlerData(bar, "defaultAnchor", relPoint, "relPoint") | |
186 SetHandlerData(bar, "defaultAnchor", x, "x") | |
187 SetHandlerData(bar, "defaultAnchor", y, "y") | |
188 | |
189 if frame then | |
190 local f = bar:GetFrame() | |
191 f:SetFrameRef("defaultAnchor", f) | |
192 f:Execute( | |
193 [[ | |
194 defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor") | |
195 ]]) | |
196 end | |
197 end | |
198 | |
199 function RefreshState( bar ) | |
200 SetDefaultAnchor(bar) | |
201 bar:GetFrame():Execute([[control:RunAttribute("reaction-refresh")]]) | |
202 end | |
203 | |
204 function SetStateDriver( bar, rule ) | |
205 local f = bar:GetFrame() | |
206 | |
207 local props = { } | |
208 for p, h in pairs(properties) do | |
209 if type(h) == "string" then | |
210 table.insert(props,p) | |
211 f:SetAttribute("func-"..p, h) | |
212 end | |
213 end | |
214 f:SetAttribute("prop-func-list", table.concat(props," ")) | |
215 f:Execute(stateHandler_propInit) | |
216 f:SetAttribute("reaction-refresh", onStateHandler) | |
217 f:SetAttribute("func-doanchor", anchorHandler) | |
218 | |
219 if rule and #rule > 0 then | |
220 f:SetAttribute( "_onstate-reaction", onStateHandler ) | |
221 RegisterStateDriver(f, "reaction", rule) | |
222 statedrivers[bar] = rule | |
223 elseif statedrivers[bar] then | |
224 UnregisterStateDriver(f, "reaction") | |
225 f:SetAttribute( "_onstate-reaction", nil ) | |
226 statedrivers[bar] = nil | |
227 end | |
228 end | |
229 | |
230 function SetStateKeybind( bar, key, state ) | |
231 local f = bar:GetFrame() | |
232 | |
233 local kb = keybinds[bar] | |
234 if kb == nil then | |
235 if key == nil then | |
236 -- nothing to do | |
237 return | |
238 end | |
239 kb = { } | |
240 keybinds[bar] = kb | |
241 end | |
242 | |
243 -- clear the old binding, if any | |
244 if kb[state] then | |
245 SetOverrideBinding(f, false, kb[state], nil) | |
246 end | |
247 kb[state] = key | |
248 | |
249 if key then | |
250 f:SetAttribute("_onclick", onClickHandler) | |
251 SetOverrideBindingClick(f, false, key, state, nil) -- state name is the virtual mouse button | |
252 end | |
253 end | |
254 end | |
255 | |
60 -- As far as I can tell the macro clauses are NOT locale-specific. | 256 -- As far as I can tell the macro clauses are NOT locale-specific. |
61 local ruleformats = { | 257 local ruleformats = { |
62 stealth = "stealth", | 258 stealth = "stealth", |
63 nostealth = "nostealth", | 259 nostealth = "nostealth", |
64 shadowform = "form:1", | 260 shadowform = "form:1", |
111 ruleformats.cat = format("form:%d",cat) | 307 ruleformats.cat = format("form:%d",cat) |
112 ruleformats.tree = format("form:%d",tree) | 308 ruleformats.tree = format("form:%d",tree) |
113 ruleformats.moonkin = format("form:%d",moonkin) | 309 ruleformats.moonkin = format("form:%d",moonkin) |
114 end | 310 end |
115 | 311 |
116 | 312 local function BuildRule(states) |
117 -- state property functions | |
118 local ofskeys = { | |
119 anchorPoint = "point", | |
120 anchorRelPoint = "relpoint", | |
121 anchorX = "x", | |
122 anchorY = "y" | |
123 } | |
124 | |
125 local barofsidx = { | |
126 anchorPoint = 1, | |
127 anchorRelPoint = 3, | |
128 anchorX = 4, | |
129 anchorY = 5 | |
130 } | |
131 | |
132 local function UpdatePartialAnchor(bar, states, ckey) | |
133 local map = { } | |
134 local bc = bar.config | |
135 for state, c in pairs(states) do | |
136 if c.enableAnchor then | |
137 map[state] = c[ckey] | |
138 end | |
139 end | |
140 local ofskey = ofskeys[ckey] | |
141 local default = select(barofsidx[ckey], bar:GetAnchor()) | |
142 bar:SetStateAttribute(format("headofs%s",ofskeys[ckey]), map, default) | |
143 end | |
144 | |
145 -- the table key name for each function maps to the name of the config element | |
146 local propertyFuncs = { | |
147 hide = function( bar, states ) | |
148 local hs = { } | |
149 for state, config in pairs(states) do | |
150 if config.hide then | |
151 table.insert(hs, state) | |
152 end | |
153 end | |
154 bar:GetButtonFrame():SetAttribute("hidestates", table.concat(hs,",")) | |
155 end, | |
156 | |
157 keybindstate = function( bar, states ) | |
158 local map = { } | |
159 for state, config in pairs(states) do | |
160 local kbset = config.keybindstate and state | |
161 map[state] = kbset | |
162 for button in bar:IterateButtons() do | |
163 -- TODO: inform children they should maintain multiple binding sets | |
164 -- ?? button:UpdateBindingSet(kbset) | |
165 end | |
166 end | |
167 bar:SetStateAttribute("statebindings", map, true) -- apply to button frame, bindings only work for direct children | |
168 end, | |
169 | |
170 enableAnchor = function( bar, states ) | |
171 for ckey in pairs(ofskeys) do | |
172 UpdatePartialAnchor(bar, states, ckey) | |
173 end | |
174 end, | |
175 | |
176 enableScale = function( bar, states ) | |
177 local map = { } | |
178 for state, c in pairs(states) do | |
179 if c.enableScale then | |
180 map[state] = c.scale | |
181 end | |
182 end | |
183 bar:SetStateAttribute("headscale", map, 1.0) | |
184 end, | |
185 } | |
186 | |
187 -- generate some table entries | |
188 propertyFuncs.scale = propertyFuncs.enableScale | |
189 for ckey in pairs(ofskeys) do | |
190 propertyFuncs[ckey] = function( bar, states ) | |
191 UpdatePartialAnchor(bar, states, ckey) | |
192 end | |
193 end | |
194 | |
195 | |
196 function GetProperty( bar, state, propname ) | |
197 return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname) | |
198 end | |
199 | |
200 function SetProperty( bar, state, propname, value ) | |
201 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") | |
202 tbuild(states, state)[propname] = value | |
203 local f = propertyFuncs[propname] | |
204 if f then | |
205 f(bar, states) | |
206 end | |
207 end | |
208 | |
209 function RegisterProperty( propname, f ) | |
210 propertyFuncs[propname] = f | |
211 for bar in ReAction:IterateBars() do | |
212 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") | |
213 if states then | |
214 f(bar,states) | |
215 end | |
216 end | |
217 end | |
218 | |
219 | |
220 | |
221 -- | |
222 -- Build a state-transition spec string and statemap to be passed to | |
223 -- Bar:SetStateDriver(). | |
224 -- | |
225 -- The statemap building is complex: keybound states override all | |
226 -- other transitions, so must remain in their current state, but must | |
227 -- also remember other transitions that happen while they're stuck there | |
228 -- so that when the binding is toggled off it can return to the proper state | |
229 -- | |
230 local function BuildStateMap(states) | |
231 local rules = { } | 313 local rules = { } |
232 local statemap = { } | |
233 local keybinds = { } | |
234 local default | 314 local default |
235 | 315 |
236 -- first grab all the keybind override states | |
237 -- and construct an override template | |
238 local override | |
239 do | |
240 local overrides = { } | |
241 for name, state in pairs(states) do | |
242 local type = tfetch(state, "rule", "type") | |
243 if type == "keybind" then | |
244 -- use the state-stack to remember the current transition | |
245 -- use $s as a marker for a later call to gsub() | |
246 table.insert(overrides, format("%s:$s set() %s", name, name)) | |
247 end | |
248 end | |
249 if #overrides > 0 then | |
250 table.insert(overrides, "") -- for a trailing ';' | |
251 end | |
252 override = table.concat(overrides, ";") or "" | |
253 end | |
254 | |
255 -- now iterate the rules in order | |
256 for idx, state in ipairs(fieldsort(states, "rule", "order")) do | 316 for idx, state in ipairs(fieldsort(states, "rule", "order")) do |
257 local c = states[state].rule | 317 local c = states[state].rule |
258 local type = c.type | 318 local type = c.type |
259 if type == "default" then | 319 if type == "default" then |
260 default = default or state | 320 default = default or state |
282 if #clauses > 0 then | 342 if #clauses > 0 then |
283 table.insert(rules, format("%s %s", format("[%s]", table.concat(clauses, ",")), state)) | 343 table.insert(rules, format("%s %s", format("[%s]", table.concat(clauses, ",")), state)) |
284 end | 344 end |
285 end | 345 end |
286 end | 346 end |
287 | |
288 -- use a different virtual button for the actual keybind transition, | |
289 -- to implement a toggle. You have to clear it regardless of the type | |
290 -- (which is usually a no-op) to unbind state transitions when switching | |
291 -- transition types. | |
292 local bindbutton = format("%s_binding",state) | |
293 if type == "keybind" then | |
294 keybinds[bindbutton] = c.keybind or false | |
295 statemap[bindbutton] = format("%s:pop();*:set(%s)", state, state) | |
296 else | |
297 keybinds[bindbutton] = false | |
298 end | |
299 | |
300 -- construct the statemap. gsub() the state name into the override template. | |
301 statemap[state] = format("%s%s", override:gsub("%$s",state), state) | |
302 end | 347 end |
303 -- make sure that the default, if any, is last | 348 -- make sure that the default, if any, is last |
304 if default then | 349 if default then |
305 table.insert(rules, default) | 350 table.insert(rules, default) |
306 end | 351 end |
307 return table.concat(rules,";"), statemap, keybinds | 352 return table.concat(rules,";") |
353 end | |
354 | |
355 local function BuildKeybinds( bar, states ) | |
356 for name, state in pairs(states) do | |
357 local type = tfetch(state, "rule", "type") | |
358 if type == "keybind" then | |
359 local key = tfetch(state, "rule", "keybind") | |
360 SetStateKeybind(bar, key, name) | |
361 else | |
362 SetStateKeybind(bar, nil, name) -- this clears an existing keybind | |
363 end | |
364 end | |
365 end | |
366 | |
367 function GetProperty( bar, state, propname ) | |
368 return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname) | |
369 end | |
370 | |
371 function SetProperty( bar, state, propname, value ) | |
372 local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state) | |
373 s[propname] = value | |
374 SetHandlerData(bar, propname, value, state) | |
375 RefreshState(bar) | |
376 end | |
377 | |
378 function RegisterProperty( propname, snippet ) | |
379 properties[propname] = snippet or true | |
380 print("registered property",propname) | |
381 for _, bar in ReAction:IterateBars() do | |
382 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") | |
383 if states then | |
384 for name, s in pairs(states) do | |
385 SetHandlerData(bar, propname, s[propname], name) | |
386 end | |
387 SetStateDriver(bar, BuildRule(states)) | |
388 RefreshState(bar) | |
389 end | |
390 end | |
391 end | |
392 | |
393 function UnregisterProperty( propname ) | |
394 properties[propname] = nil | |
395 for _, bar in ReAction:IterateBars() do | |
396 SetHandlerData(bar, propname, nil) | |
397 SetStateDriver(bar, BuildRule(states)) | |
398 RefreshState(bar) | |
399 end | |
308 end | 400 end |
309 | 401 |
310 function ApplyStates( bar ) | 402 function ApplyStates( bar ) |
311 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") | 403 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") |
312 if states then | 404 if states then |
313 local rule, statemap, keybinds = BuildStateMap(states) | 405 for propname in pairs(properties) do |
314 bar:SetStateDriver("reaction", rule, statemap) | 406 for name, s in pairs(states) do |
315 for state, key in pairs(keybinds) do | 407 SetHandlerData(bar, propname, s[propname], name) |
316 bar:SetAttributeBinding(state, key, "state-reaction", state) | 408 end |
317 end | 409 end |
318 for k, f in pairs(propertyFuncs) do | 410 BuildKeybinds(bar, states) |
319 f(bar, states) | 411 SetStateDriver(bar, BuildRule(states)) |
320 end | 412 RefreshState(bar) |
321 end | 413 end |
322 end | 414 end |
323 | 415 |
416 function CleanupStates( bar ) | |
417 SetStateDriver(bar, nil) | |
418 end | |
419 | |
420 function ShowAll( bar, show ) | |
421 SetHandlerData(bar, "showAll", show) | |
422 RefreshState(bar) | |
423 end | |
324 end | 424 end |
325 | 425 |
326 | 426 |
327 | 427 |
328 -- module event handlers -- | 428 -- module event handlers -- |
340 self:RegisterEvent("PLAYER_AURAS_CHANGED") | 440 self:RegisterEvent("PLAYER_AURAS_CHANGED") |
341 | 441 |
342 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") | 442 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") |
343 | 443 |
344 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar") | 444 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar") |
445 ReAction.RegisterCallback(self, "OnDestroyBar") | |
345 ReAction.RegisterCallback(self, "OnRefreshBar") | 446 ReAction.RegisterCallback(self, "OnRefreshBar") |
346 ReAction.RegisterCallback(self, "OnEraseBar") | 447 ReAction.RegisterCallback(self, "OnEraseBar") |
347 ReAction.RegisterCallback(self, "OnRenameBar") | 448 ReAction.RegisterCallback(self, "OnRenameBar") |
348 ReAction.RegisterCallback(self, "OnConfigModeChanged") | 449 ReAction.RegisterCallback(self, "OnConfigModeChanged") |
349 end | 450 end |
350 | 451 |
351 function module:PLAYER_AURAS_CHANGED() | 452 function module:PLAYER_AURAS_CHANGED() |
352 self:UnregisterEvent("PLAYER_AURAS_CHANGED") | 453 self:UnregisterEvent("PLAYER_AURAS_CHANGED") |
353 -- on login the number of stances is 0 until this event fires during the init sequence. | 454 -- on login the number of stances is 0 until this event fires during the init sequence. |
354 -- however if you reload just the UI the number of stances is correct immediately | 455 -- however if you just reload the UI the number of stances is correct immediately |
355 -- and this event won't fire until you gain/lose buffs/debuffs, at which point you might | 456 -- and this event won't fire until you gain/lose buffs/debuffs, at which point you might |
356 -- be in combat. | 457 -- be in combat. |
357 if not InCombatLockdown() then | 458 if not InCombatLockdown() then |
358 InitRules() | 459 InitRules() |
359 for name, bar in ReAction:IterateBars() do | 460 for name, bar in ReAction:IterateBars() do |
367 if c then | 468 if c then |
368 ApplyStates(bar) | 469 ApplyStates(bar) |
369 end | 470 end |
370 end | 471 end |
371 | 472 |
473 function module:OnDestroyBar(event, bar, name) | |
474 CleanupStates(bar) | |
475 end | |
476 | |
372 function module:OnEraseBar(event, bar, name) | 477 function module:OnEraseBar(event, bar, name) |
373 self.db.profile.bars[name] = nil | 478 self.db.profile.bars[name] = nil |
374 end | 479 end |
375 | 480 |
376 function module:OnRenameBar(event, bar, oldname, newname) | 481 function module:OnRenameBar(event, bar, oldname, newname) |
377 local bars = self.db.profile.bars | 482 local bars = self.db.profile.bars |
378 bars[newname], bars[oldname] = bars[oldname], nil | 483 bars[newname], bars[oldname] = bars[oldname], nil |
379 end | 484 end |
380 | 485 |
381 function module:OnConfigModeChanged(event, mode) | 486 function module:OnConfigModeChanged(event, mode) |
382 -- nothing to do (yet) | 487 for name, bar in ReAction:IterateBars() do |
488 if self.db.profile.bars[name] then | |
489 ShowAll(bar, mode) | |
490 end | |
491 end | |
383 end | 492 end |
384 | 493 |
385 | 494 |
386 | 495 |
387 -- Options -- | 496 -- Options -- |
503 order = 90, | 612 order = 90, |
504 type = "toggle", | 613 type = "toggle", |
505 set = "SetProp", | 614 set = "SetProp", |
506 get = "GetProp", | 615 get = "GetProp", |
507 }, | 616 }, |
508 keybindstate = { | 617 --[[ BROKEN |
618 keybindState = { | |
509 name = L["Override Keybinds"], | 619 name = L["Override Keybinds"], |
510 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], | 620 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], |
511 order = 91, | 621 order = 91, |
512 type = "toggle", | 622 type = "toggle", |
513 set = "SetProp", | 623 set = "SetProp", |
514 get = "GetProp", | 624 get = "GetProp", |
515 }, | 625 }, ]] |
516 position = { | 626 position = { |
517 name = L["Position"], | 627 name = L["Position"], |
518 order = 92, | 628 order = 92, |
519 type = "group", | 629 type = "group", |
520 inline = true, | 630 inline = true, |
521 args = { | 631 args = { |
522 enableAnchor = { | 632 anchorEnable = { |
523 name = L["Set New Position"], | 633 name = L["Set New Position"], |
524 order = 1, | 634 order = 1, |
525 type = "toggle", | 635 type = "toggle", |
526 set = "SetProp", | 636 set = "SetProp", |
527 get = "GetProp", | 637 get = "GetProp", |
528 }, | 638 }, |
639 --[[ TODO: broken | |
640 anchorFrame = { | |
641 name = L["Anchor Frame"], | |
642 order = 2, | |
643 type = "select", | |
644 values = "GetAnchorFrames", | |
645 set = ??? | |
646 get = ??? | |
647 }, ]] | |
529 anchorPoint = { | 648 anchorPoint = { |
530 name = L["Point"], | 649 name = L["Point"], |
531 order = 2, | 650 order = 3, |
532 type = "select", | 651 type = "select", |
533 values = pointTable, | 652 values = pointTable, |
534 set = "SetAnchorPointProp", | 653 set = "SetAnchorPointProp", |
535 get = "GetAnchorPointProp", | 654 get = "GetAnchorPointProp", |
536 disabled = "GetAnchorDisabled", | 655 disabled = "GetAnchorDisabled", |
537 hidden = "GetAnchorDisabled", | 656 hidden = "GetAnchorDisabled", |
538 }, | 657 }, |
539 anchorRelPoint = { | 658 anchorRelPoint = { |
540 name = L["Relative Point"], | 659 name = L["Relative Point"], |
541 order = 3, | 660 order = 4, |
542 type = "select", | 661 type = "select", |
543 values = pointTable, | 662 values = pointTable, |
544 set = "SetAnchorPointProp", | 663 set = "SetAnchorPointProp", |
545 get = "GetAnchorPointProp", | 664 get = "GetAnchorPointProp", |
546 disabled = "GetAnchorDisabled", | 665 disabled = "GetAnchorDisabled", |
547 hidden = "GetAnchorDisabled", | 666 hidden = "GetAnchorDisabled", |
548 }, | 667 }, |
549 anchorX = { | 668 anchorX = { |
550 name = L["X Offset"], | 669 name = L["X Offset"], |
551 order = 4, | 670 order = 5, |
552 type = "range", | 671 type = "range", |
553 min = -100, | 672 min = -100, |
554 max = 100, | 673 max = 100, |
555 step = 1, | 674 step = 1, |
556 set = "SetProp", | 675 set = "SetProp", |
558 disabled = "GetAnchorDisabled", | 677 disabled = "GetAnchorDisabled", |
559 hidden = "GetAnchorDisabled", | 678 hidden = "GetAnchorDisabled", |
560 }, | 679 }, |
561 anchorY = { | 680 anchorY = { |
562 name = L["Y Offset"], | 681 name = L["Y Offset"], |
563 order = 5, | 682 order = 6, |
564 type = "range", | 683 type = "range", |
565 min = -100, | 684 min = -100, |
566 max = 100, | 685 max = 100, |
567 step = 1, | 686 step = 1, |
568 set = "SetProp", | 687 set = "SetProp", |
678 }, | 797 }, |
679 }, | 798 }, |
680 }, | 799 }, |
681 } | 800 } |
682 | 801 |
683 local StateHandler = { } | 802 local handlers = { } |
803 local meta = { | |
804 __index = function(self, key) | |
805 for _, h in pairs(handlers) do | |
806 if h[key] then | |
807 return h[key] | |
808 end | |
809 end | |
810 end, | |
811 } | |
812 local StateHandler = setmetatable({ }, meta) | |
813 local proto = { __index = StateHandler } | |
814 | |
815 function RegisterPropertyOptions( field, options, handler ) | |
816 stateOptions.properties.plugins[field] = options | |
817 handlers[field] = handler | |
818 end | |
819 | |
820 function UnregisterPropertyOptions( field ) | |
821 stateOptions.properties.plugins[field] = nil | |
822 handlers[field] = nil | |
823 end | |
684 | 824 |
685 function StateHandler:New( bar, opts ) | 825 function StateHandler:New( bar, opts ) |
686 local self = setmetatable({ bar = bar }, { __index = StateHandler }) | 826 local self = setmetatable( |
827 { | |
828 bar = bar | |
829 }, | |
830 proto ) | |
687 | 831 |
688 function self:GetName() | 832 function self:GetName() |
689 return opts.name | 833 return opts.name |
690 end | 834 end |
691 | 835 |
698 end | 842 end |
699 | 843 |
700 -- get reference to states table: even if the bar | 844 -- get reference to states table: even if the bar |
701 -- name changes the states table ref won't | 845 -- name changes the states table ref won't |
702 self.states = tbuild(module.db.profile.bars, bar:GetName(), "states") | 846 self.states = tbuild(module.db.profile.bars, bar:GetName(), "states") |
703 | 847 self.state = tbuild(self.states, opts.name) |
704 tbuild(self.states, opts.name) | 848 |
705 | 849 opts.order = self:GetRuleField("order") |
706 opts.order = self:GetRule("order") | |
707 if opts.order == nil then | 850 if opts.order == nil then |
708 -- add after the highest | 851 -- add after the highest |
709 opts.order = 100 | 852 opts.order = 100 |
710 for _, state in pairs(self.states) do | 853 for _, state in pairs(self.states) do |
711 local x = tonumber(tfetch(state, "rule", "order")) | 854 local x = tonumber(tfetch(state, "rule", "order")) |
712 if x and x >= opts.order then | 855 if x and x >= opts.order then |
713 opts.order = x + 1 | 856 opts.order = x + 1 |
714 end | 857 end |
715 end | 858 end |
716 self:SetRule("order",opts.order) | 859 self:SetRuleField("order",opts.order) |
717 end | 860 end |
718 | 861 |
719 return self | 862 return self |
720 end | 863 end |
721 | 864 |
722 -- helper methods | 865 -- helper methods |
723 | 866 |
724 function StateHandler:SetRule( key, value, ... ) | 867 function StateHandler:SetRuleField( key, value, ... ) |
725 tbuild(self.states, self:GetName(), "rule", ...)[key] = value | 868 tbuild(self.state, "rule", ...)[key] = value |
726 end | 869 end |
727 | 870 |
728 function StateHandler:GetRule( ... ) | 871 function StateHandler:GetRuleField( ... ) |
729 return tfetch(self.states, self:GetName(), "rule", ...) | 872 return tfetch(self.state, "rule", ...) |
730 end | 873 end |
731 | 874 |
732 function StateHandler:FixAll( setkey ) | 875 function StateHandler:FixAll( setkey ) |
733 -- if multiple selections in the same group are chosen when 'all' is selected, | 876 -- if multiple selections in the same group are chosen when 'all' is selected, |
734 -- keep only one of them. If changing the mode, the first in the fields list will | 877 -- keep only one of them. If changing the mode, the first in the fields list will |
735 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, | 878 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, |
736 -- it will be retained. | 879 -- it will be retained. |
737 local notified = false | 880 local notified = false |
738 if self:GetRule("type") == "all" then | 881 if self:GetRuleField("type") == "all" then |
739 for _, c in ipairs(rules) do | 882 for _, c in ipairs(rules) do |
740 local rule, hidden, fields = unpack(c) | 883 local rule, hidden, fields = unpack(c) |
741 local once = false | 884 local once = false |
742 if setkey then | 885 if setkey then |
743 for idx, field in ipairs(fields) do | 886 for idx, field in ipairs(fields) do |
746 end | 889 end |
747 end | 890 end |
748 end | 891 end |
749 for idx, field in ipairs(fields) do | 892 for idx, field in ipairs(fields) do |
750 local key = next(field) | 893 local key = next(field) |
751 if self:GetRule("values",key) then | 894 if self:GetRuleField("values",key) then |
752 if once and key ~= setkey then | 895 if once and key ~= setkey then |
753 self:SetRule(key,false,"values") | 896 self:SetRuleField(key,false,"values") |
754 if not setkey and not notified then | 897 if not setkey and not notified then |
755 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) | 898 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) |
756 notified = true | 899 notified = true |
757 end | 900 end |
758 end | 901 end |
856 function StateHandler:GetScaleDisabled() | 999 function StateHandler:GetScaleDisabled() |
857 return not GetProperty(self.bar, self:GetName(), "enableScale") | 1000 return not GetProperty(self.bar, self:GetName(), "enableScale") |
858 end | 1001 end |
859 | 1002 |
860 function StateHandler:SetType(info, value) | 1003 function StateHandler:SetType(info, value) |
861 self:SetRule("type", value) | 1004 self:SetRuleField("type", value) |
862 self:FixAll() | 1005 self:FixAll() |
863 ApplyStates(self.bar) | 1006 ApplyStates(self.bar) |
864 end | 1007 end |
865 | 1008 |
866 function StateHandler:GetType() | 1009 function StateHandler:GetType() |
867 return self:GetRule("type") | 1010 return self:GetRuleField("type") |
868 end | 1011 end |
869 | 1012 |
870 function StateHandler:GetClearAllDisabled() | 1013 function StateHandler:GetClearAllDisabled() |
871 local t = self:GetRule("type") | 1014 local t = self:GetRuleField("type") |
872 return not( t == "any" or t == "all" or t == "custom") | 1015 return not( t == "any" or t == "all" or t == "custom") |
873 end | 1016 end |
874 | 1017 |
875 function StateHandler:ClearAllConditions() | 1018 function StateHandler:ClearAllConditions() |
876 local t = self:GetRule("type") | 1019 local t = self:GetRuleField("type") |
877 if t == "custom" then | 1020 if t == "custom" then |
878 self:SetRule("custom","") | 1021 self:SetRuleField("custom","") |
879 elseif t == "any" or t == "all" then | 1022 elseif t == "any" or t == "all" then |
880 self:SetRule("values", {}) | 1023 self:SetRuleField("values", {}) |
881 end | 1024 end |
882 ApplyStates(self.bar) | 1025 ApplyStates(self.bar) |
883 end | 1026 end |
884 | 1027 |
885 function StateHandler:GetConditionsDisabled() | 1028 function StateHandler:GetConditionsDisabled() |
886 local t = self:GetRule("type") | 1029 local t = self:GetRuleField("type") |
887 return not( t == "any" or t == "all") | 1030 return not( t == "any" or t == "all") |
888 end | 1031 end |
889 | 1032 |
890 function StateHandler:SetCondition(info, key, value) | 1033 function StateHandler:SetCondition(info, key, value) |
891 self:SetRule(ruleMap[key], value or nil, "values") | 1034 self:SetRuleField(ruleMap[key], value or nil, "values") |
892 if value then | 1035 if value then |
893 self:FixAll(ruleMap[key]) | 1036 self:FixAll(ruleMap[key]) |
894 end | 1037 end |
895 ApplyStates(self.bar) | 1038 ApplyStates(self.bar) |
896 end | 1039 end |
897 | 1040 |
898 function StateHandler:GetCondition(info, key) | 1041 function StateHandler:GetCondition(info, key) |
899 return self:GetRule("values", ruleMap[key]) or false | 1042 return self:GetRuleField("values", ruleMap[key]) or false |
900 end | 1043 end |
901 | 1044 |
902 function StateHandler:GetCustomDisabled() | 1045 function StateHandler:GetCustomDisabled() |
903 return self:GetRule("type") ~= "custom" | 1046 return self:GetRuleField("type") ~= "custom" |
904 end | 1047 end |
905 | 1048 |
906 function StateHandler:SetCustomRule(info, value) | 1049 function StateHandler:SetCustomRule(info, value) |
907 self:SetRule("custom",value) | 1050 self:SetRuleField("custom",value) |
908 ApplyStates(self.bar) | 1051 ApplyStates(self.bar) |
909 end | 1052 end |
910 | 1053 |
911 function StateHandler:GetCustomRule() | 1054 function StateHandler:GetCustomRule() |
912 return self:GetRule("custom") or "" | 1055 return self:GetRuleField("custom") or "" |
913 end | 1056 end |
914 | 1057 |
915 function StateHandler:ValidateCustomRule(info, value) | 1058 function StateHandler:ValidateCustomRule(info, value) |
916 local s = value:gsub("%s","") -- remove all spaces | 1059 local s = value:gsub("%s","") -- remove all spaces |
917 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler | 1060 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler |
927 until c == nil | 1070 until c == nil |
928 return true | 1071 return true |
929 end | 1072 end |
930 | 1073 |
931 function StateHandler:GetKeybindDisabled() | 1074 function StateHandler:GetKeybindDisabled() |
932 return self:GetRule("type") ~= "keybind" | 1075 return self:GetRuleField("type") ~= "keybind" |
933 end | 1076 end |
934 | 1077 |
935 function StateHandler:GetKeybind() | 1078 function StateHandler:GetKeybind() |
936 return self:GetRule("keybind") | 1079 return self:GetRuleField("keybind") |
937 end | 1080 end |
938 | 1081 |
939 function StateHandler:SetKeybind(info, value) | 1082 function StateHandler:SetKeybind(info, value) |
940 if value and #value == 0 then | 1083 if value and #value == 0 then |
941 value = nil | 1084 value = nil |
942 end | 1085 end |
943 self:SetRule("keybind",value) | 1086 self:SetRuleField("keybind",value) |
944 ApplyStates(self.bar) | 1087 ApplyStates(self.bar) |
945 end | 1088 end |
946 | 1089 |
947 local function CreateStateOptions(bar, name) | 1090 local function CreateStateOptions(bar, name) |
948 local opts = { | 1091 local opts = { |
954 | 1097 |
955 opts.handler = StateHandler:New(bar,opts) | 1098 opts.handler = StateHandler:New(bar,opts) |
956 | 1099 |
957 return opts | 1100 return opts |
958 end | 1101 end |
959 | |
960 | |
961 function RegisterPropertyOptions( field, options, handler ) | |
962 stateOptions.properties.plugins[field] = options | |
963 if handler then | |
964 for k,v in pairs(handler) do | |
965 StateHandler[k] = v | |
966 end | |
967 end | |
968 end | |
969 | |
970 | 1102 |
971 function module:GetBarOptions(bar) | 1103 function module:GetBarOptions(bar) |
972 local private = { } | 1104 local private = { } |
973 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") | 1105 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") |
974 local options = { | 1106 local options = { |
1031 end | 1163 end |
1032 end | 1164 end |
1033 | 1165 |
1034 -- Module API -- | 1166 -- Module API -- |
1035 | 1167 |
1036 -- Pass in a property field-name, an implementation function, a static options table, and an | 1168 -- Pass in a property field-name, an implementation secure snippet, a static options table, and an |
1037 -- optional options handler method-table | 1169 -- optional options handler method-table |
1038 -- | |
1039 -- propertyImplFunc prototype: | |
1040 -- propertyImplFunc( bar, stateTable ) | |
1041 -- where stateTable is a { ["statename"] = { state config } } table. | |
1042 -- | 1170 -- |
1043 -- The options table is static, i.e. not bar-specific and should only reference handler method | 1171 -- The options table is static, i.e. not bar-specific and should only reference handler method |
1044 -- strings (either existing ones or those added via optHandler). The existing options are ordered | 1172 -- strings (either existing ones or those added via optHandler). The existing options are ordered |
1045 -- 90-99. Order #1 is reserved for the heading. | 1173 -- 90-99. Order #1 is reserved for the heading. |
1046 -- | 1174 -- |
1047 -- The contents of optHandler, if provided, will be added to the existing StateHandler metatable. | 1175 -- The contents of optHandler, if provided, will be added to the existing StateHandler options metatable. |
1048 -- See above, for existing API. In particular see the properties set up in the New method: self.bar, | 1176 -- See above, for existing API. In particular see the properties set up in the New method: self.bar, |
1049 -- self.states, and self:GetName(), and the generic property handlers self:GetProp() and self:SetProp(). | 1177 -- self.states, and self:GetName(), and the generic property handlers self:GetProp() and self:SetProp(). |
1050 -- | 1178 -- |
1051 function module:RegisterStateProperty( field, propertyImplFunc, options, optHandler ) | 1179 function module:RegisterStateProperty( field, snippetHandler, options, optHandler ) |
1052 RegisterProperty(field, propertyImplFunc) | 1180 RegisterProperty(field, snippetHandler) |
1053 RegisterPropertyOptions(field, options, optHandler) | 1181 RegisterPropertyOptions(field, options, optHandler) |
1054 end | 1182 end |
1055 | 1183 |
1184 function module:UnregisterStateProperty( field ) | |
1185 UnregisterProperty(field) | |
1186 UnregisterPropertyOptions(field) | |
1187 end |