Mercurial > wow > reaction
comparison classes/State.lua @ 240:98d7ad4a1158
move state.lua into classes for now, removed obsolete functions
author | Flick |
---|---|
date | Fri, 25 Mar 2011 16:42:21 -0700 |
parents | modules/State.lua@2669f737d9d7 |
children | 09c8e9baa35a |
comparison
equal
deleted
inserted
replaced
239:2669f737d9d7 | 240:98d7ad4a1158 |
---|---|
1 --[[ | |
2 ReAction bar state driver interface | |
3 | |
4 --]] | |
5 | |
6 -- local imports | |
7 local addonName, addonTable = ... | |
8 local ReAction = addonTable.ReAction | |
9 local L = ReAction.L | |
10 local _G = _G | |
11 local format = string.format | |
12 local InCombatLockdown = InCombatLockdown | |
13 local RegisterStateDriver = RegisterStateDriver | |
14 | |
15 -- module declaration | |
16 local moduleID = "State" | |
17 local module = ReAction:NewModule( moduleID, "AceEvent-3.0" ) | |
18 | |
19 -- Utility -- | |
20 | |
21 -- traverse a table tree by key list and fetch the result or first nil | |
22 local function tfetch(t, ...) | |
23 for i = 1, select('#', ...) do | |
24 t = t and t[select(i, ...)] | |
25 end | |
26 return t | |
27 end | |
28 | |
29 -- traverse a table tree by key list and build tree as necessary | |
30 local function tbuild(t, ...) | |
31 for i = 1, select('#', ...) do | |
32 local key = select(i, ...) | |
33 if not t[key] then t[key] = { } end | |
34 t = t[key] | |
35 end | |
36 return t | |
37 end | |
38 | |
39 -- return a new array of keys of table 't', sorted by comparing | |
40 -- sub-fields (obtained via tfetch) of the table values | |
41 local function fieldsort( t, ... ) | |
42 local r = { } | |
43 for k in pairs(t) do | |
44 table.insert(r,k) | |
45 end | |
46 local path = { ... } | |
47 table.sort(r, function(lhs, rhs) | |
48 local olhs = tfetch(t[lhs], unpack(path)) or 0 | |
49 local orhs = tfetch(t[rhs], unpack(path)) or 0 | |
50 return olhs < orhs | |
51 end) | |
52 return r | |
53 end | |
54 | |
55 | |
56 local ApplyStates, CleanupStates, SetProperty, GetProperty | |
57 | |
58 -- PRIVATE -- | |
59 do | |
60 function GetProperty( bar, state, propname ) | |
61 return tfetch(bar:GetConfig(), "states", state, propname) | |
62 end | |
63 | |
64 function SetProperty( bar, state, propname, value ) | |
65 local s = tbuild(bar:GetConfig(), "states", state) | |
66 s[propname] = value | |
67 bar:SetSecureStateData(state, propname, value) | |
68 end | |
69 | |
70 function ApplyStates( bar ) | |
71 local states = tfetch(bar:GetConfig(), "states") | |
72 if states then | |
73 bar:SetStateDriver(states) | |
74 end | |
75 end | |
76 | |
77 function CleanupStates( bar ) | |
78 bar:SetStateDriver(nil) | |
79 end | |
80 end | |
81 | |
82 | |
83 | |
84 -- module event handlers -- | |
85 | |
86 function module:OnInitialize() | |
87 self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS") | |
88 | |
89 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") | |
90 | |
91 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar") | |
92 ReAction.RegisterCallback(self, "OnDestroyBar") | |
93 ReAction.RegisterCallback(self, "OnRefreshBar") | |
94 end | |
95 | |
96 function module:OnEnable() | |
97 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui | |
98 end | |
99 | |
100 function module:UPDATE_SHAPESHIFT_FORMS() | |
101 -- Re-parse the rules table according to the new form list. | |
102 -- This happens both at initial login (after PLAYER_ENTERING_WORLD) | |
103 -- as well as when gaining new abilities. | |
104 ReAction.Bar.InitRuleFormats() | |
105 for _, bar in ReAction:IterateBars() do | |
106 ApplyStates(bar) | |
107 end | |
108 end | |
109 | |
110 function module:OnRefreshBar(event, bar, name) | |
111 ApplyStates(bar) | |
112 end | |
113 | |
114 function module:OnDestroyBar(event, bar, name) | |
115 CleanupStates(bar) | |
116 end | |
117 | |
118 | |
119 | |
120 | |
121 -- Options -- | |
122 | |
123 do | |
124 -- pre-sorted by the order they should appear in | |
125 local rules = { | |
126 -- rule fields | |
127 { "stance", { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } }, | |
128 { "form", { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } }, | |
129 { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]}, {shadowdance = L["Shadow Dance"]} } }, | |
130 { "shadow", { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } }, | |
131 { "demon", { {demon = L["Demon Form"]}, {nodemon = L["No Demon Form"]} } }, | |
132 { "pet", { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } }, | |
133 { "target", { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } }, | |
134 { "focus", { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } }, | |
135 { "possess", { {possess = L["Mind Control"]} } }, | |
136 { "vehicle", { {vehicle = L["In a Vehicle"]} } }, | |
137 { "group", { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } }, | |
138 { "combat", { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } }, | |
139 } | |
140 | |
141 local ruleSelect = { } | |
142 local ruleMap = { } | |
143 local optionMap = setmetatable({},{__mode="k"}) | |
144 | |
145 local pointTable = { | |
146 NONE = " ", | |
147 CENTER = L["Center"], | |
148 LEFT = L["Left"], | |
149 RIGHT = L["Right"], | |
150 TOP = L["Top"], | |
151 BOTTOM = L["Bottom"], | |
152 TOPLEFT = L["Top Left"], | |
153 TOPRIGHT = L["Top Right"], | |
154 BOTTOMLEFT = L["Bottom Left"], | |
155 BOTTOMRIGHT = L["Bottom Right"], | |
156 } | |
157 | |
158 -- unpack rules table into ruleSelect and ruleMap | |
159 for _, c in ipairs(rules) do | |
160 local rule, fields = unpack(c) | |
161 for _, field in ipairs(fields) do | |
162 local key, label = next(field) | |
163 table.insert(ruleSelect, label) | |
164 table.insert(ruleMap, key) | |
165 end | |
166 end | |
167 | |
168 local stateOptions = { | |
169 ordering = { | |
170 name = L["Info"], | |
171 order = 1, | |
172 type = "group", | |
173 args = { | |
174 delete = { | |
175 name = L["Delete this State"], | |
176 order = -1, | |
177 type = "execute", | |
178 func = "DeleteState", | |
179 }, | |
180 rename = { | |
181 name = L["Name"], | |
182 order = 1, | |
183 type = "input", | |
184 get = "GetName", | |
185 set = "SetStateName", | |
186 pattern = "^%w*$", | |
187 usage = L["State names must be alphanumeric without spaces"], | |
188 }, | |
189 ordering = { | |
190 name = L["Evaluation Order"], | |
191 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"], | |
192 order = 2, | |
193 type = "group", | |
194 inline = true, | |
195 args = { | |
196 up = { | |
197 name = L["Up"], | |
198 order = 1, | |
199 type = "execute", | |
200 width = "half", | |
201 func = "MoveStateUp", | |
202 }, | |
203 down = { | |
204 name = L["Down"], | |
205 order = 2, | |
206 type = "execute", | |
207 width = "half", | |
208 func = "MoveStateDown", | |
209 } | |
210 } | |
211 } | |
212 } | |
213 }, | |
214 properties = { | |
215 name = L["Properties"], | |
216 order = 2, | |
217 type = "group", | |
218 args = { | |
219 desc = { | |
220 name = L["Set the properties for the bar when in this state"], | |
221 order = 1, | |
222 type = "description" | |
223 }, | |
224 page = { | |
225 name = L["Show Page #"], | |
226 order = 11, | |
227 type = "select", | |
228 width = "half", | |
229 disabled = "IsPageDisabled", | |
230 hidden = "IsPageHidden", | |
231 values = "GetPageValues", | |
232 set = "SetProp", | |
233 get = "GetPage", | |
234 }, | |
235 hide = { | |
236 name = L["Hide Bar"], | |
237 order = 90, | |
238 type = "toggle", | |
239 set = "SetProp", | |
240 get = "GetProp", | |
241 }, | |
242 --[[ BROKEN | |
243 keybindState = { | |
244 name = L["Override Keybinds"], | |
245 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], | |
246 order = 91, | |
247 type = "toggle", | |
248 set = "SetProp", | |
249 get = "GetProp", | |
250 }, ]] | |
251 position = { | |
252 name = L["Position"], | |
253 order = 92, | |
254 type = "group", | |
255 inline = true, | |
256 args = { | |
257 anchorEnable = { | |
258 name = L["Reposition"], | |
259 order = 1, | |
260 type = "toggle", | |
261 set = "SetProp", | |
262 get = "GetProp", | |
263 }, | |
264 anchorFrame = { | |
265 name = L["Anchor Frame"], | |
266 order = 2, | |
267 type = "select", | |
268 values = "GetAnchorFrames", | |
269 set = "SetAnchorFrame", | |
270 get = "GetAnchorFrame", | |
271 disabled = "GetAnchorDisabled", | |
272 hidden = "GetAnchorDisabled", | |
273 }, | |
274 anchorPoint = { | |
275 name = L["Point"], | |
276 order = 3, | |
277 type = "select", | |
278 values = pointTable, | |
279 set = "SetAnchorPointProp", | |
280 get = "GetAnchorPointProp", | |
281 disabled = "GetAnchorDisabled", | |
282 hidden = "GetAnchorDisabled", | |
283 }, | |
284 anchorRelPoint = { | |
285 name = L["Relative Point"], | |
286 order = 4, | |
287 type = "select", | |
288 values = pointTable, | |
289 set = "SetAnchorPointProp", | |
290 get = "GetAnchorPointProp", | |
291 disabled = "GetAnchorDisabled", | |
292 hidden = "GetAnchorDisabled", | |
293 }, | |
294 anchorX = { | |
295 name = L["X Offset"], | |
296 order = 5, | |
297 type = "range", | |
298 min = -100, | |
299 max = 100, | |
300 step = 1, | |
301 set = "SetProp", | |
302 get = "GetProp", | |
303 disabled = "GetAnchorDisabled", | |
304 hidden = "GetAnchorDisabled", | |
305 }, | |
306 anchorY = { | |
307 name = L["Y Offset"], | |
308 order = 6, | |
309 type = "range", | |
310 min = -100, | |
311 max = 100, | |
312 step = 1, | |
313 set = "SetProp", | |
314 get = "GetProp", | |
315 disabled = "GetAnchorDisabled", | |
316 hidden = "GetAnchorDisabled", | |
317 }, | |
318 }, | |
319 }, | |
320 scale = { | |
321 name = L["Scale"], | |
322 order = 93, | |
323 type = "group", | |
324 inline = true, | |
325 args = { | |
326 enableScale = { | |
327 name = L["Set New Scale"], | |
328 order = 1, | |
329 type = "toggle", | |
330 set = "SetProp", | |
331 get = "GetProp", | |
332 }, | |
333 scale = { | |
334 name = L["Scale"], | |
335 order = 2, | |
336 type = "range", | |
337 min = 0.25, | |
338 max = 2.5, | |
339 step = 0.05, | |
340 isPercent = true, | |
341 set = "SetProp", | |
342 get = "GetScale", | |
343 disabled = "GetScaleDisabled", | |
344 hidden = "GetScaleDisabled", | |
345 }, | |
346 }, | |
347 }, | |
348 alpha = { | |
349 name = L["Transparency"], | |
350 order = 94, | |
351 type = "group", | |
352 inline = true, | |
353 args = { | |
354 enableAlpha = { | |
355 name = L["Set Transparency"], | |
356 order = 1, | |
357 type = "toggle", | |
358 set = "SetProp", | |
359 get = "GetProp", | |
360 }, | |
361 alpha = { | |
362 name = L["Transparency"], | |
363 order = 2, | |
364 type = "range", | |
365 min = 0, | |
366 max = 1, | |
367 step = 0.01, | |
368 bigStep = 0.05, | |
369 isPercent = true, | |
370 set = "SetProp", | |
371 get = "GetAlpha", | |
372 disabled = "GetAlphaDisabled", | |
373 hidden = "GetAlphaDisabled", | |
374 }, | |
375 }, | |
376 }, | |
377 }, | |
378 plugins = { } | |
379 }, | |
380 rules = { | |
381 name = L["Rule"], | |
382 order = 3, | |
383 type = "group", | |
384 args = { | |
385 mode = { | |
386 name = L["Select this state"], | |
387 order = 2, | |
388 type = "select", | |
389 style = "radio", | |
390 values = { | |
391 default = L["by default"], | |
392 any = L["when ANY of these"], | |
393 all = L["when ALL of these"], | |
394 custom = L["via custom rule"], | |
395 keybind = L["via keybinding"], | |
396 }, | |
397 set = "SetType", | |
398 get = "GetType", | |
399 }, | |
400 clear = { | |
401 name = L["Clear All"], | |
402 order = 3, | |
403 type = "execute", | |
404 hidden = "GetClearAllDisabled", | |
405 disabled = "GetClearAllDisabled", | |
406 func = "ClearAllConditions", | |
407 }, | |
408 inputs = { | |
409 name = L["Conditions"], | |
410 order = 4, | |
411 type = "multiselect", | |
412 hidden = "GetConditionsDisabled", | |
413 disabled = "GetConditionsDisabled", | |
414 values = ruleSelect, | |
415 set = "SetCondition", | |
416 get = "GetCondition", | |
417 }, | |
418 custom = { | |
419 name = L["Custom Rule"], | |
420 order = 5, | |
421 type = "input", | |
422 multiline = true, | |
423 hidden = "GetCustomDisabled", | |
424 disabled = "GetCustomDisabled", | |
425 desc = L["Syntax like macro rules: see preset rules for examples"], | |
426 set = "SetCustomRule", | |
427 get = "GetCustomRule", | |
428 validate = "ValidateCustomRule", | |
429 }, | |
430 keybind = { | |
431 name = L["Keybinding"], | |
432 order = 6, | |
433 inline = true, | |
434 hidden = "GetKeybindDisabled", | |
435 disabled = "GetKeybindDisabled", | |
436 type = "group", | |
437 args = { | |
438 desc = { | |
439 name = L["Invoking a state keybind toggles an override of all other transition rules."], | |
440 order = 1, | |
441 type = "description", | |
442 }, | |
443 keybind = { | |
444 name = L["State Hotkey"], | |
445 desc = L["Define an override toggle keybind"], | |
446 order = 2, | |
447 type = "keybinding", | |
448 set = "SetKeybind", | |
449 get = "GetKeybind", | |
450 }, | |
451 }, | |
452 }, | |
453 }, | |
454 }, | |
455 } | |
456 | |
457 local StateHandler = { } | |
458 local meta = { __index = StateHandler } | |
459 | |
460 function StateHandler:New( bar, opts ) | |
461 local self = setmetatable( | |
462 { | |
463 bar = bar | |
464 }, | |
465 meta ) | |
466 | |
467 function self:GetName() | |
468 return opts.name | |
469 end | |
470 | |
471 function self:SetName(name) | |
472 opts.name = name | |
473 end | |
474 | |
475 function self:GetOrder() | |
476 return opts.order | |
477 end | |
478 | |
479 -- get reference to states table: even if the bar | |
480 -- name changes the states table ref won't | |
481 self.states = tbuild(bar:GetConfig(), "states") | |
482 self.state = tbuild(self.states, opts.name) | |
483 | |
484 opts.order = self:GetRuleField("order") | |
485 if opts.order == nil then | |
486 -- add after the highest | |
487 opts.order = 100 | |
488 for _, state in pairs(self.states) do | |
489 local x = tonumber(tfetch(state, "rule", "order")) | |
490 if x and x >= opts.order then | |
491 opts.order = x + 1 | |
492 end | |
493 end | |
494 self:SetRuleField("order",opts.order) | |
495 end | |
496 | |
497 return self | |
498 end | |
499 | |
500 -- helper methods | |
501 | |
502 function StateHandler:SetRuleField( key, value, ... ) | |
503 tbuild(self.state, "rule", ...)[key] = value | |
504 end | |
505 | |
506 function StateHandler:GetRuleField( ... ) | |
507 return tfetch(self.state, "rule", ...) | |
508 end | |
509 | |
510 function StateHandler:FixAll( setkey ) | |
511 -- if multiple selections in the same group are chosen when 'all' is selected, | |
512 -- keep only one of them. If changing the mode, the first in the fields list will | |
513 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, | |
514 -- it will be retained. | |
515 local notified = false | |
516 if self:GetRuleField("type") == "all" then | |
517 for _, c in ipairs(rules) do | |
518 local rule, fields = unpack(c) | |
519 local once = false | |
520 if setkey then | |
521 for idx, field in ipairs(fields) do | |
522 if next(field) == setkey then | |
523 once = true | |
524 end | |
525 end | |
526 end | |
527 for idx, field in ipairs(fields) do | |
528 local key = next(field) | |
529 if self:GetRuleField("values",key) then | |
530 if once and key ~= setkey then | |
531 self:SetRuleField(key,false,"values") | |
532 if not setkey and not notified then | |
533 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) | |
534 notified = true | |
535 end | |
536 end | |
537 once = true | |
538 end | |
539 end | |
540 end | |
541 end | |
542 end | |
543 | |
544 function StateHandler:GetNeighbors() | |
545 local before, after | |
546 for k, v in pairs(self.states) do | |
547 local o = tonumber(tfetch(v, "rule", "order")) | |
548 if o and k ~= self:GetName() then | |
549 local obefore = tfetch(self.states,before,"rule","order") | |
550 local oafter = tfetch(self.states,after,"rule","order") | |
551 if o < self:GetOrder() and (not obefore or obefore < o) then | |
552 before = k | |
553 end | |
554 if o > self:GetOrder() and (not oafter or oafter > o) then | |
555 after = k | |
556 end | |
557 end | |
558 end | |
559 return before, after | |
560 end | |
561 | |
562 function StateHandler:SwapOrder( a, b ) | |
563 -- do options table | |
564 local args = optionMap[self.bar].args | |
565 args[a].order, args[b].order = args[b].order, args[a].order | |
566 -- do profile | |
567 a = tbuild(self.states, a, "rule") | |
568 b = tbuild(self.states, b, "rule") | |
569 a.order, b.order = b.order, a.order | |
570 end | |
571 | |
572 -- handler methods | |
573 | |
574 function StateHandler:GetProp( info ) | |
575 -- gets property of the same name as the options arg | |
576 return GetProperty(self.bar, self:GetName(), info[#info]) | |
577 end | |
578 | |
579 function StateHandler:SetProp( info, value ) | |
580 -- sets property of the same name as the options arg | |
581 SetProperty(self.bar, self:GetName(), info[#info], value) | |
582 end | |
583 | |
584 function StateHandler:DeleteState() | |
585 if self.states[self:GetName()] then | |
586 self.states[self:GetName()] = nil | |
587 ApplyStates(self.bar) | |
588 end | |
589 optionMap[self.bar].args[self:GetName()] = nil | |
590 end | |
591 | |
592 function StateHandler:SetStateName(info, value) | |
593 -- check for existing state name | |
594 if self.states[value] then | |
595 ReAction:UserError(format(L["State named '%s' already exists"],value)) | |
596 return | |
597 end | |
598 local args = optionMap[self.bar].args | |
599 local name = self:GetName() | |
600 self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil | |
601 self:SetName(value) | |
602 ApplyStates(self.bar) | |
603 ReAction:ShowEditor(self.bar, moduleID, value) | |
604 end | |
605 | |
606 function StateHandler:MoveStateUp() | |
607 local before, after = self:GetNeighbors() | |
608 if before then | |
609 self:SwapOrder(before, self:GetName()) | |
610 ApplyStates(self.bar) | |
611 end | |
612 end | |
613 | |
614 function StateHandler:MoveStateDown() | |
615 local before, after = self:GetNeighbors() | |
616 if after then | |
617 self:SwapOrder(self:GetName(), after) | |
618 ApplyStates(self.bar) | |
619 end | |
620 end | |
621 | |
622 function StateHandler:GetAnchorDisabled() | |
623 return not GetProperty(self.bar, self:GetName(), "anchorEnable") | |
624 end | |
625 | |
626 function StateHandler:IsPageDisabled() | |
627 local n = self.bar:GetConfig().nPages or 1 | |
628 return not (n > 1) | |
629 end | |
630 | |
631 function StateHandler:IsPageHidden() | |
632 return not self.bar:GetConfig().nPages | |
633 end | |
634 | |
635 function StateHandler:GetPageValues() | |
636 if not self._pagevalues then | |
637 self._pagevalues = { } | |
638 end | |
639 local n = self.bar:GetConfig().nPages | |
640 -- cache the results | |
641 if self._npages ~= n then | |
642 self._npages = n | |
643 wipe(self._pagevalues) | |
644 for i = 1, n do | |
645 self._pagevalues["page"..i] = i | |
646 end | |
647 end | |
648 return self._pagevalues | |
649 end | |
650 | |
651 function StateHandler:GetPage(info) | |
652 return self:GetProp(info) or 1 | |
653 end | |
654 | |
655 function StateHandler:GetAnchorFrames(info) | |
656 self._anchorframes = self._anchorframes or { } | |
657 table.wipe(self._anchorframes) | |
658 | |
659 table.insert(self._anchorframes, "UIParent") | |
660 for name, bar in ReAction:IterateBars() do | |
661 table.insert(self._anchorframes, bar:GetFrame():GetName()) | |
662 end | |
663 return self._anchorframes | |
664 end | |
665 | |
666 function StateHandler:GetAnchorFrame(info) | |
667 local value = self:GetProp(info) | |
668 for k,v in pairs(self._anchorframes) do | |
669 if v == value then | |
670 return k | |
671 end | |
672 end | |
673 end | |
674 | |
675 function StateHandler:SetAnchorFrame(info, value) | |
676 local f = _G[self._anchorframes[value]] | |
677 if f then | |
678 self.bar:SetFrameRef("anchor-"..self:GetName(), f) | |
679 self:SetProp(info, f:GetName()) | |
680 end | |
681 end | |
682 | |
683 function StateHandler:SetAnchorPointProp(info, value) | |
684 self:SetProp(info, value ~= "NONE" and value or nil) | |
685 end | |
686 | |
687 function StateHandler:GetAnchorPointProp(info) | |
688 return self:GetProp(info) or "NONE" | |
689 end | |
690 | |
691 function StateHandler:GetScale(info) | |
692 return self:GetProp(info) or 1.0 | |
693 end | |
694 | |
695 function StateHandler:GetScaleDisabled() | |
696 return not GetProperty(self.bar, self:GetName(), "enableScale") | |
697 end | |
698 | |
699 function StateHandler:GetAlpha(info) | |
700 return self:GetProp(info) or 1.0 | |
701 end | |
702 | |
703 function StateHandler:GetAlphaDisabled() | |
704 return not GetProperty(self.bar, self:GetName(), "enableAlpha") | |
705 end | |
706 | |
707 function StateHandler:SetType(info, value) | |
708 self:SetRuleField("type", value) | |
709 self:FixAll() | |
710 ApplyStates(self.bar) | |
711 end | |
712 | |
713 function StateHandler:GetType() | |
714 return self:GetRuleField("type") | |
715 end | |
716 | |
717 function StateHandler:GetClearAllDisabled() | |
718 local t = self:GetRuleField("type") | |
719 return not( t == "any" or t == "all" or t == "custom") | |
720 end | |
721 | |
722 function StateHandler:ClearAllConditions() | |
723 local t = self:GetRuleField("type") | |
724 if t == "custom" then | |
725 self:SetRuleField("custom","") | |
726 elseif t == "any" or t == "all" then | |
727 self:SetRuleField("values", {}) | |
728 end | |
729 ApplyStates(self.bar) | |
730 end | |
731 | |
732 function StateHandler:GetConditionsDisabled() | |
733 local t = self:GetRuleField("type") | |
734 return not( t == "any" or t == "all") | |
735 end | |
736 | |
737 function StateHandler:SetCondition(info, key, value) | |
738 self:SetRuleField(ruleMap[key], value or nil, "values") | |
739 if value then | |
740 self:FixAll(ruleMap[key]) | |
741 end | |
742 ApplyStates(self.bar) | |
743 end | |
744 | |
745 function StateHandler:GetCondition(info, key) | |
746 return self:GetRuleField("values", ruleMap[key]) or false | |
747 end | |
748 | |
749 function StateHandler:GetCustomDisabled() | |
750 return self:GetRuleField("type") ~= "custom" | |
751 end | |
752 | |
753 function StateHandler:SetCustomRule(info, value) | |
754 self:SetRuleField("custom",value) | |
755 ApplyStates(self.bar) | |
756 end | |
757 | |
758 function StateHandler:GetCustomRule() | |
759 return self:GetRuleField("custom") or "" | |
760 end | |
761 | |
762 function StateHandler:ValidateCustomRule(info, value) | |
763 local s = value:gsub("%s","") -- remove all spaces | |
764 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler | |
765 repeat | |
766 if s == "" then | |
767 return true | |
768 end | |
769 local c, r = s:match("(%b[])(.*)") | |
770 if c == nil and s and #s > 0 then | |
771 return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "") | |
772 end | |
773 s = r | |
774 until c == nil | |
775 return true | |
776 end | |
777 | |
778 function StateHandler:GetKeybindDisabled() | |
779 return self:GetRuleField("type") ~= "keybind" | |
780 end | |
781 | |
782 function StateHandler:GetKeybind() | |
783 return self:GetRuleField("keybind") | |
784 end | |
785 | |
786 function StateHandler:SetKeybind(info, value) | |
787 if value and #value == 0 then | |
788 value = nil | |
789 end | |
790 self:SetRuleField("keybind",value) | |
791 ApplyStates(self.bar) | |
792 end | |
793 | |
794 local function CreateStateOptions(bar, name) | |
795 local opts = { | |
796 type = "group", | |
797 name = name, | |
798 childGroups = "tab", | |
799 args = stateOptions | |
800 } | |
801 | |
802 opts.handler = StateHandler:New(bar,opts) | |
803 | |
804 return opts | |
805 end | |
806 | |
807 function module:GetBarOptions(bar) | |
808 local private = { } | |
809 local states = tbuild(bar:GetConfig(), "states") | |
810 local options = { | |
811 name = L["Dynamic State"], | |
812 type = "group", | |
813 order = -1, | |
814 childGroups = "tree", | |
815 disabled = InCombatLockdown, | |
816 args = { | |
817 __desc__ = { | |
818 name = L["States are evaluated in the order they are listed"], | |
819 order = 1, | |
820 type = "description", | |
821 }, | |
822 __new__ = { | |
823 name = L["New State..."], | |
824 order = 2, | |
825 type = "group", | |
826 args = { | |
827 name = { | |
828 name = L["State Name"], | |
829 desc = L["Set a name for the new state"], | |
830 order = 1, | |
831 type = "input", | |
832 get = function() return private.newstatename or "" end, | |
833 set = function(info,value) private.newstatename = value end, | |
834 pattern = "^%w*$", | |
835 usage = L["State names must be alphanumeric without spaces"], | |
836 }, | |
837 create = { | |
838 name = L["Create State"], | |
839 order = 2, | |
840 type = "execute", | |
841 func = function () | |
842 local name = private.newstatename | |
843 if states[name] then | |
844 ReAction:UserError(format(L["State named '%s' already exists"],name)) | |
845 else | |
846 -- TODO: select default state options and pass as final argument | |
847 states[name] = { } | |
848 optionMap[bar].args[name] = CreateStateOptions(bar,name) | |
849 ReAction:ShowEditor(bar, moduleID, name) | |
850 private.newstatename = "" | |
851 end | |
852 end, | |
853 disabled = function() | |
854 local name = private.newstatename or "" | |
855 return #name == 0 or name:find("%W") | |
856 end, | |
857 } | |
858 } | |
859 } | |
860 } | |
861 } | |
862 for name, config in pairs(states) do | |
863 options.args[name] = CreateStateOptions(bar,name) | |
864 end | |
865 optionMap[bar] = options | |
866 return options | |
867 end | |
868 end | |
869 | |
870 | |
871 -- Export methods to Bar class -- | |
872 | |
873 ReAction.Bar.GetStateProperty = GetProperty | |
874 ReAction.Bar.SetStateProperty = SetProperty |