annotate modules/ReAction_State/ReAction_State.lua @ 66:44d3716aba8d

fixed init sequence on PLAYER_AURAS_CHANGED
author Flick <flickerstreak@gmail.com>
date Wed, 28 May 2008 17:41:29 +0000
parents 5ea65ec7d162
children 84721edaa749
rev   line source
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