flickerstreak@25
|
1 --[[
|
flickerstreak@62
|
2 ReAction bar state driver interface
|
flickerstreak@25
|
3
|
flickerstreak@25
|
4 --]]
|
flickerstreak@25
|
5
|
flickerstreak@25
|
6 -- local imports
|
flickerstreak@25
|
7 local ReAction = ReAction
|
flickerstreak@25
|
8 local L = ReAction.L
|
flickerstreak@25
|
9 local _G = _G
|
flickerstreak@25
|
10 local InCombatLockdown = InCombatLockdown
|
flickerstreak@25
|
11
|
flickerstreak@25
|
12 -- module declaration
|
flickerstreak@25
|
13 local moduleID = "State"
|
flickerstreak@65
|
14 local module = ReAction:NewModule( moduleID, "AceEvent-3.0" )
|
flickerstreak@62
|
15
|
flickerstreak@64
|
16 -- Utility --
|
flickerstreak@62
|
17
|
flickerstreak@62
|
18 -- traverse a table tree by key list and fetch the result or first nil
|
flickerstreak@62
|
19 local function tfetch(t, ...)
|
flickerstreak@62
|
20 for i = 1, select('#', ...) do
|
flickerstreak@62
|
21 t = t and t[select(i, ...)]
|
flickerstreak@62
|
22 end
|
flickerstreak@62
|
23 return t
|
flickerstreak@62
|
24 end
|
flickerstreak@62
|
25
|
flickerstreak@62
|
26 -- traverse a table tree by key list and build tree as necessary
|
flickerstreak@62
|
27 local function tbuild(t, ...)
|
flickerstreak@62
|
28 for i = 1, select('#', ...) do
|
flickerstreak@62
|
29 local key = select(i, ...)
|
flickerstreak@62
|
30 if not t[key] then t[key] = { } end
|
flickerstreak@62
|
31 t = t[key]
|
flickerstreak@62
|
32 end
|
flickerstreak@62
|
33 return t
|
flickerstreak@62
|
34 end
|
flickerstreak@62
|
35
|
flickerstreak@64
|
36 -- PRIVATE --
|
flickerstreak@65
|
37 local InitRules, ApplyStates
|
flickerstreak@64
|
38 do
|
flickerstreak@65
|
39 local ruleformats = { }
|
flickerstreak@65
|
40
|
flickerstreak@65
|
41 function InitRules()
|
flickerstreak@65
|
42 local forms = { }
|
flickerstreak@65
|
43 for i = 1, GetNumShapeshiftForms() do
|
flickerstreak@65
|
44 local icon = GetShapeshiftFormInfo(i)
|
flickerstreak@65
|
45 forms[icon] = i;
|
flickerstreak@65
|
46 end
|
flickerstreak@65
|
47 -- sort by icon since it's locale-independent
|
flickerstreak@65
|
48 -- use 9 if not found since 9 is never a valid stance/form
|
flickerstreak@65
|
49 -- we do these shenanigans instead of hardcoding the stances because
|
flickerstreak@65
|
50 -- the ordering varies if the character is missing a form. For warriors
|
flickerstreak@65
|
51 -- this is rarely a problem but for druids it can be. Some people never bother
|
flickerstreak@65
|
52 -- to do the aquatic form quest, and stance 5 can be either flight or tree/boomkin
|
flickerstreak@65
|
53 -- depending on talents.
|
flickerstreak@65
|
54 local defensive = forms["Interface\\Icons\\Ability_Warrior_DefensiveStance"] or 9
|
flickerstreak@65
|
55 local berserker = forms["Interface\\Icons\\Ability_Racial_Avatar"] or 9
|
flickerstreak@65
|
56 local bear = forms["Interface\\Icons\\Ability_Racial_BearForm"] or 9 -- bear and dire bear share the same icon
|
flickerstreak@65
|
57 local aquatic = forms["Interface\\Icons\\Ability_Druid_AquaticForm"] or 9
|
flickerstreak@65
|
58 local cat = forms["Interface\\Icons\\Ability_Druid_CatForm"] or 9
|
flickerstreak@65
|
59 local travel = forms["Interface\\Icons\\Ability_Druid_TravelForm"] or 9
|
flickerstreak@65
|
60 local treekin = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or forms["Interface\\Icons\\Spell_Nature_ForceOfNature"] or 9
|
flickerstreak@65
|
61 local flight = forms["Interface\\Icons\\Ability_Druid_FlightForm"] or 9 -- both flight and swift flight share the same icon
|
flickerstreak@65
|
62
|
flickerstreak@65
|
63 -- As far as I can tell the macro clauses are NOT locale-specific.
|
flickerstreak@65
|
64 ruleformats.battle = "stance:1"
|
flickerstreak@65
|
65 ruleformats.defensive = ("stance:%d"):format(defensive)
|
flickerstreak@65
|
66 ruleformats.berserker = ("stance:%d"):format(berserker)
|
flickerstreak@65
|
67 ruleformats.caster = ("form:0/%d/%d/%d"):format(aquatic, travel, flight)
|
flickerstreak@65
|
68 ruleformats.bear = ("form:%d"):format(bear)
|
flickerstreak@65
|
69 ruleformats.cat = ("form:%d"):format(cat)
|
flickerstreak@65
|
70 ruleformats.treeOrMoonkin = ("form:%d"):format(treekin)
|
flickerstreak@65
|
71 ruleformats.stealth = "stealth"
|
flickerstreak@65
|
72 ruleformats.nostealth = "nostealth"
|
flickerstreak@65
|
73 ruleformats.shadowform = "form:1"
|
flickerstreak@65
|
74 ruleformats.noshadowform = "noform"
|
flickerstreak@65
|
75 ruleformats.pet = "pet"
|
flickerstreak@65
|
76 ruleformats.nopet = "nopet"
|
flickerstreak@65
|
77 ruleformats.harm = "target=target,harm"
|
flickerstreak@65
|
78 ruleformats.help = "target=target,help"
|
flickerstreak@65
|
79 ruleformats.notarget = "target=target,noexists"
|
flickerstreak@65
|
80 ruleformats.focusharm = "target=focus,harm"
|
flickerstreak@65
|
81 ruleformats.focushelp = "target=focus,help"
|
flickerstreak@65
|
82 ruleformats.nofocus = "target=focus,noexists"
|
flickerstreak@65
|
83 ruleformats.raid = "group:raid"
|
flickerstreak@65
|
84 ruleformats.party = "group:party"
|
flickerstreak@65
|
85 ruleformats.solo = "nogroup"
|
flickerstreak@65
|
86 ruleformats.combat = "combat"
|
flickerstreak@65
|
87 ruleformats.nocombat = "nocombat"
|
flickerstreak@64
|
88 end
|
flickerstreak@62
|
89
|
flickerstreak@65
|
90 local function BuildRuleString(states)
|
flickerstreak@64
|
91 local s = ""
|
flickerstreak@64
|
92 local default
|
flickerstreak@64
|
93 local sorted = { }
|
flickerstreak@64
|
94 for name in pairs(states) do
|
flickerstreak@64
|
95 table.insert(sorted,name)
|
flickerstreak@64
|
96 end
|
flickerstreak@64
|
97 table.sort(sorted, function(lhs, rhs)
|
flickerstreak@64
|
98 local olhs = tfetch(states[lhs],"rule","order") or 0
|
flickerstreak@64
|
99 local orhs = tfetch(states[rhs],"rule","order") or 0
|
flickerstreak@64
|
100 return olhs < orhs
|
flickerstreak@64
|
101 end)
|
flickerstreak@64
|
102 for idx, name in ipairs(sorted) do
|
flickerstreak@64
|
103 local state = states[name]
|
flickerstreak@64
|
104 local semi = #s > 0 and "; " or ""
|
flickerstreak@64
|
105 local mode = tfetch(state,"rule","type")
|
flickerstreak@64
|
106 if mode == "default" then
|
flickerstreak@64
|
107 default = name
|
flickerstreak@64
|
108 elseif mode == "custom" then
|
flickerstreak@64
|
109 if state.rule.custom then
|
flickerstreak@64
|
110 -- strip out all spaces from the custom rule
|
flickerstreak@64
|
111 s = ("%s%s%s %s"):format(s, semi, state.rule.custom:gsub("%s",""), name)
|
flickerstreak@64
|
112 end
|
flickerstreak@64
|
113 elseif mode == "any" then
|
flickerstreak@64
|
114 if state.rule.values then
|
flickerstreak@64
|
115 local clause = ""
|
flickerstreak@64
|
116 for key, value in pairs(state.rule.values) do
|
flickerstreak@64
|
117 clause = ("%s[%s]"):format(clause,ruleformats[key])
|
flickerstreak@64
|
118 end
|
flickerstreak@64
|
119 if #clause > 0 then
|
flickerstreak@64
|
120 s = ("%s%s%s %s"):format(s, semi, clause, name)
|
flickerstreak@64
|
121 end
|
flickerstreak@64
|
122 end
|
flickerstreak@64
|
123 elseif mode == "all" then
|
flickerstreak@64
|
124 if state.rule.values then
|
flickerstreak@64
|
125 local clause = ""
|
flickerstreak@64
|
126 for key, value in pairs(state.rule.values) do
|
flickerstreak@64
|
127 clause = ("%s%s%s"):format(clause,#clause > 0 and "," or "", ruleformats[key])
|
flickerstreak@64
|
128 end
|
flickerstreak@64
|
129 if #clause > 0 then
|
flickerstreak@64
|
130 s = ("%s%s[%s] %s"):format(s, semi, clause, name)
|
flickerstreak@64
|
131 end
|
flickerstreak@64
|
132 end
|
flickerstreak@64
|
133 end
|
flickerstreak@64
|
134 end
|
flickerstreak@64
|
135 if default then
|
flickerstreak@64
|
136 s = ("%s%s%s"):format(s, #s > 0 and "; " or "", default)
|
flickerstreak@64
|
137 end
|
flickerstreak@64
|
138 return s
|
flickerstreak@64
|
139 end
|
flickerstreak@64
|
140
|
flickerstreak@64
|
141 local drivers = setmetatable({},{__mode="k"})
|
flickerstreak@64
|
142
|
flickerstreak@64
|
143 function ApplyStates( bar )
|
flickerstreak@64
|
144 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
|
flickerstreak@64
|
145 if states then
|
flickerstreak@64
|
146 local frame = bar:GetFrame()
|
flickerstreak@64
|
147 local string = BuildRuleString(states)
|
flickerstreak@64
|
148 ReAction:Print("'"..string.."'")
|
flickerstreak@64
|
149 if string and #string > 0 then
|
flickerstreak@64
|
150 -- register a handler to set the value of attribute "state-reaction"
|
flickerstreak@64
|
151 -- in response to events as per the rule string
|
flickerstreak@64
|
152 RegisterStateDriver(frame, "reaction", string)
|
flickerstreak@64
|
153 drivers[bar] = true
|
flickerstreak@64
|
154 -- register a trivial map for each "statemap-reaction-XXX" to set 'state' to 'XXX'
|
flickerstreak@64
|
155 for state in pairs(states) do
|
flickerstreak@64
|
156 frame:SetAttribute(("statemap-reaction-%s"):format(state), state)
|
flickerstreak@64
|
157 end
|
flickerstreak@64
|
158 elseif drivers[bar] then
|
flickerstreak@64
|
159 UnregisterStateDriver(frame, "reaction")
|
flickerstreak@64
|
160 drivers[bar] = nil
|
flickerstreak@64
|
161 end
|
flickerstreak@64
|
162 end
|
flickerstreak@64
|
163 end
|
flickerstreak@64
|
164 end
|
flickerstreak@64
|
165
|
flickerstreak@64
|
166
|
flickerstreak@65
|
167 -- module event handlers
|
flickerstreak@65
|
168 function module:OnInitialize()
|
flickerstreak@65
|
169 self.db = ReAction.db:RegisterNamespace( moduleID,
|
flickerstreak@65
|
170 {
|
flickerstreak@65
|
171 profile = {
|
flickerstreak@65
|
172 bars = { },
|
flickerstreak@65
|
173 }
|
flickerstreak@65
|
174 }
|
flickerstreak@65
|
175 )
|
flickerstreak@65
|
176
|
flickerstreak@65
|
177 InitRules()
|
flickerstreak@65
|
178 self:RegisterEvent("PLAYER_AURAS_CHANGED")
|
flickerstreak@65
|
179
|
flickerstreak@65
|
180 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
|
flickerstreak@65
|
181
|
flickerstreak@65
|
182 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
|
flickerstreak@65
|
183 ReAction.RegisterCallback(self, "OnRefreshBar")
|
flickerstreak@65
|
184 ReAction.RegisterCallback(self, "OnEraseBar")
|
flickerstreak@65
|
185 ReAction.RegisterCallback(self, "OnRenameBar")
|
flickerstreak@65
|
186 ReAction.RegisterCallback(self, "OnConfigModeChanged")
|
flickerstreak@65
|
187 end
|
flickerstreak@65
|
188
|
flickerstreak@65
|
189 function module:PLAYER_AURAS_CHANGED()
|
flickerstreak@65
|
190 self:UnregisterEvent("PLAYER_AURAS_CHANGED")
|
flickerstreak@66
|
191 -- on login the number of stances is 0 until this event fires during the init sequence.
|
flickerstreak@66
|
192 -- however if you reload just the UI the number of stances is correct immediately
|
flickerstreak@66
|
193 -- and this event won't fire until you gain/lose buffs/debuffs, at which point you might
|
flickerstreak@66
|
194 -- be in combat.
|
flickerstreak@66
|
195 if not InCombatLockdown() then
|
flickerstreak@66
|
196 InitRules()
|
flickerstreak@66
|
197 for name, bar in ReAction:IterateBars() do
|
flickerstreak@66
|
198 self:OnRefreshBar("OnRefreshBar",bar,name)
|
flickerstreak@66
|
199 end
|
flickerstreak@66
|
200 end
|
flickerstreak@65
|
201 end
|
flickerstreak@65
|
202
|
flickerstreak@65
|
203 function module:OnRefreshBar(event, bar, name)
|
flickerstreak@65
|
204 local c = self.db.profile.bars[name]
|
flickerstreak@65
|
205 if c then
|
flickerstreak@65
|
206 self:UpdateStates(bar)
|
flickerstreak@65
|
207 end
|
flickerstreak@65
|
208 end
|
flickerstreak@65
|
209
|
flickerstreak@65
|
210 function module:OnEraseBar(event, bar, name)
|
flickerstreak@65
|
211 self.db.profile.bars[name] = nil
|
flickerstreak@65
|
212 end
|
flickerstreak@65
|
213
|
flickerstreak@65
|
214 function module:OnRenameBar(event, bar, oldname, newname)
|
flickerstreak@65
|
215 local b = self.db.profile.bars
|
flickerstreak@65
|
216 bars[newname], bars[oldname] = bars[oldname], nil
|
flickerstreak@65
|
217 end
|
flickerstreak@65
|
218
|
flickerstreak@65
|
219 function module:OnConfigModeChanged(event, mode)
|
flickerstreak@65
|
220 -- TODO: unregister all state drivers (temporarily) and hidestates
|
flickerstreak@65
|
221 end
|
flickerstreak@65
|
222
|
flickerstreak@64
|
223
|
flickerstreak@64
|
224 -- API --
|
flickerstreak@64
|
225
|
flickerstreak@64
|
226 function module:UpdateStates( bar )
|
flickerstreak@64
|
227 ApplyStates(bar)
|
flickerstreak@64
|
228 end
|
flickerstreak@64
|
229
|
flickerstreak@64
|
230 function module:CreateState( bar, name )
|
flickerstreak@64
|
231 local states = tbuild(self.db.profile.bars, bar:GetName(), "states")
|
flickerstreak@64
|
232 if states[name] then
|
flickerstreak@64
|
233 ReAction:UserError(L["State named '%s' already exists"]:format(name))
|
flickerstreak@64
|
234 else
|
flickerstreak@64
|
235 states[name] = { }
|
flickerstreak@64
|
236 end
|
flickerstreak@64
|
237 end
|
flickerstreak@64
|
238
|
flickerstreak@64
|
239 function module:DeleteState( bar, name )
|
flickerstreak@64
|
240 local states = tfetch(self.db.profile.bars, bar:GetName(), "states")
|
flickerstreak@64
|
241 if states[name] then
|
flickerstreak@64
|
242 states[name] = nil
|
flickerstreak@64
|
243 ApplyStates(bar)
|
flickerstreak@64
|
244 end
|
flickerstreak@64
|
245 end
|
flickerstreak@64
|
246
|
flickerstreak@64
|
247 -- Options --
|
flickerstreak@64
|
248
|
flickerstreak@64
|
249 local CreateBarOptions
|
flickerstreak@62
|
250 do
|
flickerstreak@62
|
251 local function ClassCheck(...)
|
flickerstreak@62
|
252 for i = 1, select('#',...) do
|
flickerstreak@62
|
253 local _, c = UnitClass("player")
|
flickerstreak@62
|
254 if c == select(i,...) then
|
flickerstreak@62
|
255 return false
|
flickerstreak@62
|
256 end
|
flickerstreak@62
|
257 end
|
flickerstreak@62
|
258 return true
|
flickerstreak@62
|
259 end
|
flickerstreak@62
|
260
|
flickerstreak@64
|
261 -- pre-sorted by the order they should appear in
|
flickerstreak@64
|
262 local rules = {
|
flickerstreak@64
|
263 -- rule hidden fields
|
flickerstreak@64
|
264 { "stance", ClassCheck("WARRIOR"), { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
|
flickerstreak@64
|
265 { "form", ClassCheck("DRUID"), { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {treeOrMoonkin = L["Tree/Moonkin"]} } },
|
flickerstreak@64
|
266 { "stealth", ClassCheck("ROGUE","DRUID"), { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]} } },
|
flickerstreak@64
|
267 { "shadow", ClassCheck("PRIEST"), { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
|
flickerstreak@64
|
268 { "pet", ClassCheck("HUNTER","WARLOCK"), { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
|
flickerstreak@64
|
269 { "target", false, { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
|
flickerstreak@64
|
270 { "focus", false, { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
|
flickerstreak@64
|
271 { "group", false, { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
|
flickerstreak@64
|
272 { "combat", false, { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } },
|
flickerstreak@62
|
273 }
|
flickerstreak@62
|
274
|
flickerstreak@64
|
275 local ruleSelect = { }
|
flickerstreak@64
|
276 local ruleMap = { }
|
flickerstreak@64
|
277 local optionMap = setmetatable({},{__mode="k"})
|
flickerstreak@62
|
278
|
flickerstreak@64
|
279 -- unpack rules table into ruleSelect and ruleMap
|
flickerstreak@64
|
280 for _, c in ipairs(rules) do
|
flickerstreak@64
|
281 local rule, hidden, fields = unpack(c)
|
flickerstreak@64
|
282 if not hidden then
|
flickerstreak@64
|
283 for _, field in ipairs(fields) do
|
flickerstreak@64
|
284 local key, label = next(field)
|
flickerstreak@64
|
285 table.insert(ruleSelect, label)
|
flickerstreak@64
|
286 table.insert(ruleMap, key)
|
flickerstreak@62
|
287 end
|
flickerstreak@62
|
288 end
|
flickerstreak@62
|
289 end
|
flickerstreak@62
|
290
|
flickerstreak@62
|
291 local function CreateStateOptions(bar, name)
|
flickerstreak@62
|
292 local opts = {
|
flickerstreak@62
|
293 type = "group",
|
flickerstreak@62
|
294 name = name,
|
flickerstreak@64
|
295 childGroups = "tab",
|
flickerstreak@25
|
296 }
|
flickerstreak@62
|
297
|
flickerstreak@64
|
298 local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
|
flickerstreak@64
|
299
|
flickerstreak@64
|
300 local function put( key, value, ... )
|
flickerstreak@64
|
301 tbuild(states, opts.name, "rule", ...)[key] = value
|
flickerstreak@64
|
302 end
|
flickerstreak@64
|
303
|
flickerstreak@64
|
304 local function fetch( ... )
|
flickerstreak@64
|
305 return tfetch(states, opts.name, "rule", ...)
|
flickerstreak@64
|
306 end
|
flickerstreak@64
|
307
|
flickerstreak@64
|
308 local function fixall(setkey)
|
flickerstreak@64
|
309 -- if multiple selections in the same group are chosen when 'all' is selected,
|
flickerstreak@64
|
310 -- keep only one of them. If changing the mode, the first in the fields list will
|
flickerstreak@64
|
311 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set,
|
flickerstreak@64
|
312 -- it will be retained.
|
flickerstreak@64
|
313 local notified = false
|
flickerstreak@64
|
314 for _, c in ipairs(rules) do
|
flickerstreak@64
|
315 local rule, hidden, fields = unpack(c)
|
flickerstreak@64
|
316 local found = false
|
flickerstreak@64
|
317 for key in ipairs(fields) do
|
flickerstreak@64
|
318 if fetch("values",key) then
|
flickerstreak@64
|
319 if (found or setkey) and key ~= setkey then
|
flickerstreak@64
|
320 put(key,false,"values")
|
flickerstreak@64
|
321 if not setkey and not notified then
|
flickerstreak@64
|
322 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"])
|
flickerstreak@64
|
323 notified = true
|
flickerstreak@64
|
324 end
|
flickerstreak@64
|
325 end
|
flickerstreak@64
|
326 found = true
|
flickerstreak@64
|
327 end
|
flickerstreak@62
|
328 end
|
flickerstreak@62
|
329 end
|
flickerstreak@62
|
330 end
|
flickerstreak@62
|
331
|
flickerstreak@64
|
332 local function getNeighbors()
|
flickerstreak@64
|
333 local before, after
|
flickerstreak@64
|
334 for k, v in pairs(states) do
|
flickerstreak@64
|
335 local o = tonumber(tfetch(v, "rule", "order"))
|
flickerstreak@64
|
336 if o and k ~= opts.name then
|
flickerstreak@64
|
337 local obefore = tfetch(states,before,"rule","order")
|
flickerstreak@64
|
338 local oafter = tfetch(states,after,"rule","order")
|
flickerstreak@64
|
339 if o < opts.order and (not obefore or obefore < o) then
|
flickerstreak@64
|
340 before = k
|
flickerstreak@64
|
341 end
|
flickerstreak@64
|
342 if o > opts.order and (not oafter or oafter > o) then
|
flickerstreak@64
|
343 after = k
|
flickerstreak@64
|
344 end
|
flickerstreak@64
|
345 end
|
flickerstreak@64
|
346 end
|
flickerstreak@64
|
347 return before, after
|
flickerstreak@64
|
348 end
|
flickerstreak@64
|
349
|
flickerstreak@64
|
350 local function swapOrder( a, b )
|
flickerstreak@64
|
351 -- do options table
|
flickerstreak@64
|
352 local args = optionMap[bar].args
|
flickerstreak@64
|
353 args[a].order, args[b].order = args[b].order, args[a].order
|
flickerstreak@64
|
354 -- do profile
|
flickerstreak@64
|
355 a = tbuild(states, a, "rule")
|
flickerstreak@64
|
356 b = tbuild(states, b, "rule")
|
flickerstreak@64
|
357 a.order, b.order = b.order, a.order
|
flickerstreak@64
|
358 end
|
flickerstreak@64
|
359
|
flickerstreak@64
|
360 local function update()
|
flickerstreak@64
|
361 module:UpdateStates(bar)
|
flickerstreak@64
|
362 end
|
flickerstreak@64
|
363
|
flickerstreak@64
|
364
|
flickerstreak@64
|
365 opts.order = fetch("order")
|
flickerstreak@64
|
366 if opts.order == nil then
|
flickerstreak@64
|
367 -- add after the highest
|
flickerstreak@64
|
368 opts.order = 100
|
flickerstreak@64
|
369 for _, state in pairs(states) do
|
flickerstreak@64
|
370 local x = tonumber(tfetch(state, "rule", "order"))
|
flickerstreak@64
|
371 if x and x >= opts.order then
|
flickerstreak@64
|
372 opts.order = x + 1
|
flickerstreak@64
|
373 end
|
flickerstreak@64
|
374 end
|
flickerstreak@64
|
375 put("order",opts.order)
|
flickerstreak@64
|
376 end
|
flickerstreak@64
|
377
|
flickerstreak@64
|
378 opts.args = {
|
flickerstreak@64
|
379 properties = {
|
flickerstreak@64
|
380 type = "group",
|
flickerstreak@64
|
381 name = L["Properties"],
|
flickerstreak@64
|
382 order = 1,
|
flickerstreak@64
|
383 args = {
|
flickerstreak@64
|
384 delete = {
|
flickerstreak@64
|
385 type = "execute",
|
flickerstreak@64
|
386 name = L["Delete this State"],
|
flickerstreak@64
|
387 func = function(info)
|
flickerstreak@64
|
388 module:DeleteState(bar,opts.name)
|
flickerstreak@64
|
389 optionMap[bar].args[opts.name] = nil
|
flickerstreak@64
|
390 end,
|
flickerstreak@64
|
391 order = -1
|
flickerstreak@64
|
392 },
|
flickerstreak@64
|
393 rename = {
|
flickerstreak@64
|
394 type = "input",
|
flickerstreak@64
|
395 name = L["Name"],
|
flickerstreak@64
|
396 order = 1,
|
flickerstreak@64
|
397 get = function() return opts.name end,
|
flickerstreak@64
|
398 set = function(info, value)
|
flickerstreak@64
|
399 -- check for existing state name
|
flickerstreak@64
|
400 if states[value] then
|
flickerstreak@64
|
401 L["State named '%s' already exists"]:format(value)
|
flickerstreak@64
|
402 end
|
flickerstreak@64
|
403 local args = optionMap[bar].args
|
flickerstreak@64
|
404 states[value], args[value], states[opts.name], args[opts.name] = states[opts.name], args[opts.name], nil, nil
|
flickerstreak@64
|
405 opts.name = value
|
flickerstreak@64
|
406 update()
|
flickerstreak@64
|
407 end,
|
flickerstreak@64
|
408 pattern = "^%w*$",
|
flickerstreak@64
|
409 usage = L["State names must be alphanumeric without spaces"],
|
flickerstreak@64
|
410 },
|
flickerstreak@64
|
411 ordering = {
|
flickerstreak@64
|
412 type = "group",
|
flickerstreak@64
|
413 inline = true,
|
flickerstreak@64
|
414 name = L["Evaluation Order"],
|
flickerstreak@64
|
415 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"],
|
flickerstreak@64
|
416 order = 2,
|
flickerstreak@64
|
417 args = {
|
flickerstreak@64
|
418 up = {
|
flickerstreak@64
|
419 type = "execute",
|
flickerstreak@64
|
420 name = L["Up"],
|
flickerstreak@64
|
421 width = "half",
|
flickerstreak@64
|
422 order = 1,
|
flickerstreak@64
|
423 func = function()
|
flickerstreak@64
|
424 local before, after = getNeighbors()
|
flickerstreak@64
|
425 if before then
|
flickerstreak@64
|
426 swapOrder(before, opts.name)
|
flickerstreak@64
|
427 update()
|
flickerstreak@64
|
428 end
|
flickerstreak@64
|
429 end,
|
flickerstreak@64
|
430 },
|
flickerstreak@64
|
431 down = {
|
flickerstreak@64
|
432 type = "execute",
|
flickerstreak@64
|
433 name = L["Down"],
|
flickerstreak@64
|
434 width = "half",
|
flickerstreak@64
|
435 order = 2,
|
flickerstreak@64
|
436 func = function()
|
flickerstreak@64
|
437 local before, after = getNeighbors()
|
flickerstreak@64
|
438 if after then
|
flickerstreak@64
|
439 ReAction:Print(opts.name, after)
|
flickerstreak@64
|
440 swapOrder(opts.name, after)
|
flickerstreak@64
|
441 update()
|
flickerstreak@64
|
442 end
|
flickerstreak@64
|
443 end,
|
flickerstreak@64
|
444 }
|
flickerstreak@64
|
445 }
|
flickerstreak@64
|
446 },
|
flickerstreak@64
|
447 -- keybinding for show-this-state would go here
|
flickerstreak@64
|
448 -- show/hide would go here
|
flickerstreak@64
|
449 -- page # would go here
|
flickerstreak@64
|
450 -- anchoring would go here
|
flickerstreak@64
|
451 }
|
flickerstreak@64
|
452 },
|
flickerstreak@64
|
453 rules = {
|
flickerstreak@64
|
454 type = "group",
|
flickerstreak@64
|
455 name = L["Rules"],
|
flickerstreak@64
|
456 order = 2,
|
flickerstreak@64
|
457 args = {
|
flickerstreak@64
|
458 mode = {
|
flickerstreak@64
|
459 type = "select",
|
flickerstreak@64
|
460 style = "radio",
|
flickerstreak@64
|
461 name = L["Select this state"],
|
flickerstreak@64
|
462 values = {
|
flickerstreak@64
|
463 default = L["by default"],
|
flickerstreak@64
|
464 any = L["when ANY of these"],
|
flickerstreak@64
|
465 all = L["when ALL of these"],
|
flickerstreak@64
|
466 custom = L["via custom rule"]
|
flickerstreak@64
|
467 },
|
flickerstreak@64
|
468 set = function( info, value )
|
flickerstreak@64
|
469 put("type", value)
|
flickerstreak@64
|
470 fixall()
|
flickerstreak@64
|
471 update()
|
flickerstreak@64
|
472 end,
|
flickerstreak@64
|
473 get = function( info )
|
flickerstreak@64
|
474 return fetch("type")
|
flickerstreak@64
|
475 end,
|
flickerstreak@64
|
476 order = 2
|
flickerstreak@64
|
477 },
|
flickerstreak@64
|
478 clear = {
|
flickerstreak@64
|
479 type = "execute",
|
flickerstreak@64
|
480 name = L["Clear All"],
|
flickerstreak@64
|
481 func = function()
|
flickerstreak@64
|
482 local type = fetch("type")
|
flickerstreak@64
|
483 if type == "custom" then
|
flickerstreak@64
|
484 put("custom","")
|
flickerstreak@64
|
485 elseif type == "any" or type == "all" then
|
flickerstreak@64
|
486 put("values", {})
|
flickerstreak@64
|
487 end
|
flickerstreak@64
|
488 update()
|
flickerstreak@64
|
489 end,
|
flickerstreak@64
|
490 order = 3
|
flickerstreak@64
|
491 },
|
flickerstreak@64
|
492 inputs = {
|
flickerstreak@64
|
493 type = "multiselect",
|
flickerstreak@64
|
494 name = L["Rules"],
|
flickerstreak@64
|
495 hidden = function()
|
flickerstreak@64
|
496 return fetch("type") == "custom"
|
flickerstreak@64
|
497 end,
|
flickerstreak@64
|
498 disabled = function()
|
flickerstreak@64
|
499 return fetch("type") == "default"
|
flickerstreak@64
|
500 end,
|
flickerstreak@64
|
501 values = ruleSelect,
|
flickerstreak@64
|
502 set = function(info, key, value )
|
flickerstreak@64
|
503 put(ruleMap[key], value or nil, "values")
|
flickerstreak@64
|
504 if value then
|
flickerstreak@64
|
505 fixall(ruleMap[key])
|
flickerstreak@64
|
506 end
|
flickerstreak@64
|
507 update()
|
flickerstreak@64
|
508 end,
|
flickerstreak@64
|
509 get = function(info, key)
|
flickerstreak@64
|
510 return fetch("values", ruleMap[key]) or false
|
flickerstreak@64
|
511 end,
|
flickerstreak@64
|
512 order = 4
|
flickerstreak@64
|
513 },
|
flickerstreak@64
|
514 custom = {
|
flickerstreak@64
|
515 type = "input",
|
flickerstreak@64
|
516 multiline = true,
|
flickerstreak@64
|
517 hidden = function()
|
flickerstreak@64
|
518 return fetch("type") ~= "custom"
|
flickerstreak@64
|
519 end,
|
flickerstreak@64
|
520 disabled = function()
|
flickerstreak@64
|
521 return fetch("type") == "default"
|
flickerstreak@64
|
522 end,
|
flickerstreak@64
|
523 name = L["Custom Rule"],
|
flickerstreak@64
|
524 desc = L["Syntax like macro rules: see preset rules for examples"],
|
flickerstreak@64
|
525 set = function(info, value)
|
flickerstreak@64
|
526 put("custom",value)
|
flickerstreak@64
|
527 update()
|
flickerstreak@64
|
528 end,
|
flickerstreak@64
|
529 get = function(info)
|
flickerstreak@64
|
530 return fetch("custom") or ""
|
flickerstreak@64
|
531 end,
|
flickerstreak@64
|
532 validate = function (info, rule)
|
flickerstreak@64
|
533 local s = rule:gsub("%s","") -- remove all spaces
|
flickerstreak@64
|
534 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler
|
flickerstreak@64
|
535 repeat
|
flickerstreak@64
|
536 if s == "" then
|
flickerstreak@64
|
537 return true
|
flickerstreak@64
|
538 end
|
flickerstreak@64
|
539 local c, r = s:match("(%b[])(.*)")
|
flickerstreak@64
|
540 if c == nil and s and #s > 0 then
|
flickerstreak@64
|
541 return L["Invalid custom rule '%s': each clause must appear within [brackets]"]:format(rule)
|
flickerstreak@64
|
542 end
|
flickerstreak@64
|
543 s = r
|
flickerstreak@64
|
544 until c == nil
|
flickerstreak@64
|
545 return true
|
flickerstreak@64
|
546 end,
|
flickerstreak@64
|
547 order = 5,
|
flickerstreak@64
|
548 }
|
flickerstreak@64
|
549 }
|
flickerstreak@64
|
550 }
|
flickerstreak@62
|
551 }
|
flickerstreak@62
|
552 return opts
|
flickerstreak@25
|
553 end
|
flickerstreak@62
|
554
|
flickerstreak@64
|
555
|
flickerstreak@62
|
556 CreateBarOptions = function(bar)
|
flickerstreak@62
|
557 local private = { }
|
flickerstreak@62
|
558 local options = {
|
flickerstreak@62
|
559 type = "group",
|
flickerstreak@62
|
560 name = L["Dynamic State"],
|
flickerstreak@64
|
561 childGroups = "tree",
|
flickerstreak@62
|
562 disabled = InCombatLockdown,
|
flickerstreak@62
|
563 args = {
|
flickerstreak@64
|
564 __desc__ = {
|
flickerstreak@64
|
565 type = "description",
|
flickerstreak@64
|
566 name = L["States are evaluated in the order they are listed"],
|
flickerstreak@64
|
567 order = 1
|
flickerstreak@64
|
568 },
|
flickerstreak@64
|
569 __new__ = {
|
flickerstreak@62
|
570 type = "group",
|
flickerstreak@64
|
571 name = L["New State..."],
|
flickerstreak@64
|
572 order = 2,
|
flickerstreak@62
|
573 args = {
|
flickerstreak@64
|
574 name = {
|
flickerstreak@64
|
575 type = "input",
|
flickerstreak@64
|
576 name = L["State Name"],
|
flickerstreak@64
|
577 desc = L["Set a name for the new state"],
|
flickerstreak@64
|
578 get = function() return private.newstatename or "" end,
|
flickerstreak@64
|
579 set = function(info,value) private.newstatename = value end,
|
flickerstreak@64
|
580 pattern = "^%w*$",
|
flickerstreak@64
|
581 usage = L["State names must be alphanumeric without spaces"],
|
flickerstreak@64
|
582 order = 1
|
flickerstreak@64
|
583 },
|
flickerstreak@64
|
584 create = {
|
flickerstreak@64
|
585 type = "execute",
|
flickerstreak@64
|
586 name = L["Create State"],
|
flickerstreak@64
|
587 func = function ()
|
flickerstreak@64
|
588 local name = private.newstatename
|
flickerstreak@64
|
589 module:CreateState(bar,name) -- TODO: select default state options and pass as final argument
|
flickerstreak@64
|
590 optionMap[bar].args[name] = CreateStateOptions(bar,name)
|
flickerstreak@64
|
591 private.newstatename = ""
|
flickerstreak@64
|
592 end,
|
flickerstreak@64
|
593 disabled = function()
|
flickerstreak@64
|
594 local name = private.newstatename or ""
|
flickerstreak@64
|
595 return #name == 0 or name:find("%W")
|
flickerstreak@64
|
596 end,
|
flickerstreak@64
|
597 order = 2,
|
flickerstreak@62
|
598 }
|
flickerstreak@62
|
599 }
|
flickerstreak@64
|
600 }
|
flickerstreak@62
|
601 }
|
flickerstreak@62
|
602 }
|
flickerstreak@62
|
603 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
|
flickerstreak@62
|
604 if states then
|
flickerstreak@62
|
605 for name, config in pairs(states) do
|
flickerstreak@64
|
606 options.args[name] = CreateStateOptions(bar,name)
|
flickerstreak@62
|
607 end
|
flickerstreak@62
|
608 end
|
flickerstreak@64
|
609 optionMap[bar] = options
|
flickerstreak@62
|
610 return options
|
flickerstreak@62
|
611 end
|
flickerstreak@25
|
612 end
|
flickerstreak@25
|
613
|
flickerstreak@62
|
614 function module:GetBarOptions(bar)
|
flickerstreak@64
|
615 return CreateBarOptions(bar)
|
flickerstreak@25
|
616 end
|