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