annotate modules/ReAction_State/ReAction_State.lua @ 64:2000f4f4c6af

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