annotate modules/State.lua @ 155:806a61b331a0

Pushed the state implementation into Bar
author Flick <flickerstreak@gmail.com>
date Fri, 15 May 2009 22:38:19 +0000
parents 42cade25d40d
children e77f716af1b7
rev   line source
flickerstreak@109 1 --[[
flickerstreak@109 2 ReAction bar state driver interface
flickerstreak@109 3
flickerstreak@109 4 --]]
flickerstreak@109 5
flickerstreak@109 6 -- local imports
flickerstreak@109 7 local ReAction = ReAction
flickerstreak@109 8 local L = ReAction.L
flickerstreak@109 9 local _G = _G
flickerstreak@109 10 local format = string.format
flickerstreak@109 11 local InCombatLockdown = InCombatLockdown
flickerstreak@109 12 local RegisterStateDriver = RegisterStateDriver
flickerstreak@109 13
flickerstreak@109 14 ReAction:UpdateRevision("$Revision$")
flickerstreak@109 15
flickerstreak@109 16 -- module declaration
flickerstreak@109 17 local moduleID = "State"
flickerstreak@109 18 local module = ReAction:NewModule( moduleID, "AceEvent-3.0" )
flickerstreak@109 19
flickerstreak@109 20 -- Utility --
flickerstreak@109 21
flickerstreak@109 22 -- traverse a table tree by key list and fetch the result or first nil
flickerstreak@109 23 local function tfetch(t, ...)
flickerstreak@109 24 for i = 1, select('#', ...) do
flickerstreak@109 25 t = t and t[select(i, ...)]
flickerstreak@109 26 end
flickerstreak@109 27 return t
flickerstreak@109 28 end
flickerstreak@109 29
flickerstreak@109 30 -- traverse a table tree by key list and build tree as necessary
flickerstreak@109 31 local function tbuild(t, ...)
flickerstreak@109 32 for i = 1, select('#', ...) do
flickerstreak@109 33 local key = select(i, ...)
flickerstreak@109 34 if not t[key] then t[key] = { } end
flickerstreak@109 35 t = t[key]
flickerstreak@109 36 end
flickerstreak@109 37 return t
flickerstreak@109 38 end
flickerstreak@109 39
flickerstreak@109 40 -- return a new array of keys of table 't', sorted by comparing
flickerstreak@109 41 -- sub-fields (obtained via tfetch) of the table values
flickerstreak@109 42 local function fieldsort( t, ... )
flickerstreak@109 43 local r = { }
flickerstreak@109 44 for k in pairs(t) do
flickerstreak@109 45 table.insert(r,k)
flickerstreak@109 46 end
flickerstreak@109 47 local path = { ... }
flickerstreak@109 48 table.sort(r, function(lhs, rhs)
flickerstreak@109 49 local olhs = tfetch(t[lhs], unpack(path)) or 0
flickerstreak@109 50 local orhs = tfetch(t[rhs], unpack(path)) or 0
flickerstreak@109 51 return olhs < orhs
flickerstreak@109 52 end)
flickerstreak@109 53 return r
flickerstreak@109 54 end
flickerstreak@109 55
flickerstreak@109 56
flickerstreak@155 57 local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty
flickerstreak@109 58
flickerstreak@109 59 -- PRIVATE --
flickerstreak@109 60 do
flickerstreak@109 61
flickerstreak@109 62 -- the field names must match the field names of the options table, below
flickerstreak@109 63 -- the field values are secure snippets or 'true' to skip the snippet for that property.
flickerstreak@109 64 local properties = {
flickerstreak@155 65 hide = true,
flickerstreak@155 66 --keybindState = true, TODO: broken
flickerstreak@155 67 anchorEnable = true,
flickerstreak@109 68 anchorFrame = true,
flickerstreak@109 69 anchorPoint = true,
flickerstreak@109 70 anchorRelPoint = true,
flickerstreak@109 71 anchorX = true,
flickerstreak@109 72 anchorY = true,
flickerstreak@155 73 enableScale = true,
flickerstreak@109 74 scale = true,
flickerstreak@155 75 enableAlpha = true,
flickerstreak@109 76 alpha = true,
flickerstreak@109 77 }
flickerstreak@109 78
flickerstreak@118 79 local playerClass = select(2, UnitClass("player"))
flickerstreak@118 80 local function ClassFilter(...)
flickerstreak@118 81 for i = 1, select('#',...) do
flickerstreak@118 82 if playerClass == select(i,...) then
flickerstreak@118 83 return false
flickerstreak@118 84 end
flickerstreak@118 85 end
flickerstreak@118 86 return true
flickerstreak@118 87 end
flickerstreak@118 88
flickerstreak@109 89 -- As far as I can tell the macro clauses are NOT locale-specific.
flickerstreak@118 90 -- 'filter' specifies whether rules should be omitted from execution.
flickerstreak@118 91 -- 'true' indicates they should be filtered out.
flickerstreak@109 92 local ruleformats = {
flickerstreak@118 93 stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") },
flickerstreak@118 94 nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") },
flickerstreak@118 95 shadowform = { format = "form:1", filter = ClassFilter("PRIEST") },
flickerstreak@118 96 noshadowform = { format = "noform", filter = ClassFilter("PRIEST") },
flickerstreak@118 97 battle = { format = "stance:1", filter = ClassFilter("WARRIOR") },
flickerstreak@118 98 defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") },
flickerstreak@118 99 berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") },
flickerstreak@118 100 caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
flickerstreak@118 101 bear = { format = "form:1", filter = ClassFilter("DRUID") },
flickerstreak@155 102 cat = { format = "form:3", filter = ClassFilter("DRUID") },
flickerstreak@118 103 tree = { format = "form:5", filter = ClassFilter("DRUID") },
flickerstreak@118 104 moonkin = { format = "form:5", filter = ClassFilter("DRUID") },
flickerstreak@118 105 pet = { format = "pet" },
flickerstreak@118 106 nopet = { format = "nopet" },
flickerstreak@118 107 harm = { format = "target=target,harm" },
flickerstreak@118 108 help = { format = "target=target,help" },
flickerstreak@118 109 notarget = { format = "target=target,noexists" },
flickerstreak@118 110 focusharm = { format = "target=focus,harm" },
flickerstreak@118 111 focushelp = { format = "target=focus,help" },
flickerstreak@118 112 nofocus = { format = "target=focus,noexists" },
flickerstreak@118 113 raid = { format = "group:raid" },
flickerstreak@118 114 party = { format = "group:party" },
flickerstreak@118 115 solo = { format = "nogroup" },
flickerstreak@118 116 combat = { format = "combat" },
flickerstreak@118 117 nocombat = { format = "nocombat" },
flickerstreak@118 118 possess = { format = "bonusbar:5" },
flickerstreak@145 119 vehicle = { format = "target=vehicle,exists,bonusbar:5" },
flickerstreak@109 120 }
flickerstreak@109 121
flickerstreak@155 122 -- Determine the stance #'s programmatically: they can vary if for some reason the
flickerstreak@155 123 -- player is missing a stance/form (due to not training it). Also moonkin/flight/tree form
flickerstreak@155 124 -- can be stance 5 or 6, depending.
flickerstreak@109 125 function InitRules()
flickerstreak@109 126 local forms = { }
flickerstreak@109 127 for i = 1, GetNumShapeshiftForms() do
flickerstreak@155 128 local _, name = GetShapeshiftFormInfo(i)
flickerstreak@155 129 forms[name] = i;
flickerstreak@109 130 end
flickerstreak@109 131 -- use 9 if not found since 9 is never a valid stance/form
flickerstreak@155 132 local defensive = forms[GetSpellInfo(71)] or 9
flickerstreak@155 133 local berserker = forms[GetSpellInfo(2458)] or 9
flickerstreak@155 134 local bear = forms[GetSpellInfo(9634)] or forms[GetSpellInfo(5487)] or 9
flickerstreak@155 135 local aquatic = forms[GetSpellInfo(1066)] or 9
flickerstreak@155 136 local cat = forms[GetSpellInfo(768)] or 9
flickerstreak@155 137 local travel = forms[GetSpellInfo(783)] or 9
flickerstreak@155 138 local tree = forms[GetSpellInfo(33891)] or 9
flickerstreak@155 139 local moonkin = forms[GetSpellInfo(24858)] or 9
flickerstreak@155 140 local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
flickerstreak@109 141
flickerstreak@118 142 ruleformats.defensive.format = format("stance:%d",defensive)
flickerstreak@118 143 ruleformats.berserker.format = format("stance:%d",berserker)
flickerstreak@118 144 ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight)
flickerstreak@118 145 ruleformats.bear.format = format("form:%d",bear)
flickerstreak@118 146 ruleformats.cat.format = format("form:%d",cat)
flickerstreak@118 147 ruleformats.tree.format = format("form:%d",tree)
flickerstreak@118 148 ruleformats.moonkin.format = format("form:%d",moonkin)
flickerstreak@109 149 end
flickerstreak@109 150
flickerstreak@109 151 local function BuildRule(states)
flickerstreak@109 152 local rules = { }
flickerstreak@109 153 local default
flickerstreak@109 154
flickerstreak@109 155 for idx, state in ipairs(fieldsort(states, "rule", "order")) do
flickerstreak@109 156 local c = states[state].rule
flickerstreak@109 157 local type = c.type
flickerstreak@109 158 if type == "default" then
flickerstreak@109 159 default = default or state
flickerstreak@109 160 elseif type == "custom" then
flickerstreak@109 161 if c.custom then
flickerstreak@109 162 -- strip out all spaces from the custom rule
flickerstreak@109 163 table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
flickerstreak@109 164 end
flickerstreak@109 165 elseif type == "any" or type == "all" then
flickerstreak@109 166 if c.values then
flickerstreak@109 167 local clauses = { }
flickerstreak@109 168 for key, value in pairs(c.values) do
flickerstreak@118 169 if ruleformats[key] and not ruleformats[key].filter then
flickerstreak@118 170 table.insert(clauses, ruleformats[key].format)
flickerstreak@118 171 end
flickerstreak@109 172 end
flickerstreak@109 173 if #clauses > 0 then
flickerstreak@109 174 local sep = (type == "any") and "][" or ","
flickerstreak@109 175 table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
flickerstreak@109 176 end
flickerstreak@109 177 end
flickerstreak@109 178 end
flickerstreak@109 179 end
flickerstreak@109 180 -- make sure that the default, if any, is last
flickerstreak@109 181 if default then
flickerstreak@109 182 table.insert(rules, default)
flickerstreak@109 183 end
flickerstreak@109 184 return table.concat(rules,";")
flickerstreak@109 185 end
flickerstreak@109 186
flickerstreak@109 187 local function BuildKeybinds( bar, states )
flickerstreak@109 188 for name, state in pairs(states) do
flickerstreak@109 189 local type = tfetch(state, "rule", "type")
flickerstreak@109 190 if type == "keybind" then
flickerstreak@109 191 local key = tfetch(state, "rule", "keybind")
flickerstreak@155 192 bar:SetStateKeybind(key, name)
flickerstreak@109 193 else
flickerstreak@155 194 bar:SetStateKeybind(nil, name) -- this clears an existing keybind
flickerstreak@109 195 end
flickerstreak@109 196 end
flickerstreak@109 197 end
flickerstreak@109 198
flickerstreak@109 199 function GetProperty( bar, state, propname )
flickerstreak@109 200 return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname)
flickerstreak@109 201 end
flickerstreak@109 202
flickerstreak@109 203 function SetProperty( bar, state, propname, value )
flickerstreak@109 204 local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state)
flickerstreak@109 205 s[propname] = value
flickerstreak@155 206 bar:SetSecureStateData(state, propname, value)
flickerstreak@109 207 end
flickerstreak@109 208
flickerstreak@109 209 function RegisterProperty( propname, snippet )
flickerstreak@155 210 properties[propname] = true
flickerstreak@109 211 for _, bar in ReAction:IterateBars() do
flickerstreak@109 212 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
flickerstreak@109 213 if states then
flickerstreak@109 214 for name, s in pairs(states) do
flickerstreak@155 215 bar:SetSecureStateData(name, propname, s[propname])
flickerstreak@109 216 end
flickerstreak@155 217 bar:SetStateDriver(BuildRule(states))
flickerstreak@155 218 end
flickerstreak@155 219 if type(snippet) == "string" then
flickerstreak@155 220 bar:SetSecureStateExtension(propname,snippet)
flickerstreak@109 221 end
flickerstreak@109 222 end
flickerstreak@109 223 end
flickerstreak@109 224
flickerstreak@109 225 function UnregisterProperty( propname )
flickerstreak@109 226 properties[propname] = nil
flickerstreak@109 227 for _, bar in ReAction:IterateBars() do
flickerstreak@155 228 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
flickerstreak@155 229 if states then
flickerstreak@155 230 for name, s in pairs(states) do
flickerstreak@155 231 bar:SetSecureStateData(name, propname, nil)
flickerstreak@155 232 end
flickerstreak@155 233 end
flickerstreak@155 234 bar:SetStateDriver(BuildRule(states))
flickerstreak@155 235 bar:SetSecureStateExtension(propname,nil)
flickerstreak@109 236 end
flickerstreak@109 237 end
flickerstreak@109 238
flickerstreak@109 239 function ApplyStates( bar )
flickerstreak@109 240 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
flickerstreak@109 241 if states then
flickerstreak@109 242 for propname in pairs(properties) do
flickerstreak@109 243 for name, s in pairs(states) do
flickerstreak@109 244 if propname == "anchorFrame" then
flickerstreak@155 245 bar:SetFrameRef("anchor-"..name, _G[s.anchorFrame])
flickerstreak@109 246 else
flickerstreak@155 247 bar:SetSecureStateData(name, propname, s[propname])
flickerstreak@109 248 end
flickerstreak@109 249 end
flickerstreak@109 250 end
flickerstreak@109 251 BuildKeybinds(bar, states)
flickerstreak@155 252 bar:SetStateDriver(BuildRule(states))
flickerstreak@109 253 end
flickerstreak@109 254 end
flickerstreak@109 255
flickerstreak@109 256 function CleanupStates( bar )
flickerstreak@155 257 bar:SetStateDriver(nil)
flickerstreak@109 258 end
flickerstreak@109 259 end
flickerstreak@109 260
flickerstreak@109 261
flickerstreak@109 262
flickerstreak@109 263 -- module event handlers --
flickerstreak@109 264
flickerstreak@109 265 function module:OnInitialize()
flickerstreak@109 266 self.db = ReAction.db:RegisterNamespace( moduleID,
flickerstreak@109 267 {
flickerstreak@109 268 profile = {
flickerstreak@109 269 bars = { },
flickerstreak@109 270 }
flickerstreak@109 271 }
flickerstreak@109 272 )
flickerstreak@109 273
flickerstreak@109 274 self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
flickerstreak@109 275
flickerstreak@109 276 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
flickerstreak@109 277
flickerstreak@109 278 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
flickerstreak@109 279 ReAction.RegisterCallback(self, "OnDestroyBar")
flickerstreak@109 280 ReAction.RegisterCallback(self, "OnRefreshBar")
flickerstreak@109 281 ReAction.RegisterCallback(self, "OnEraseBar")
flickerstreak@109 282 ReAction.RegisterCallback(self, "OnRenameBar")
flickerstreak@109 283 end
flickerstreak@109 284
flickerstreak@109 285 function module:OnEnable()
flickerstreak@109 286 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui
flickerstreak@109 287 end
flickerstreak@109 288
flickerstreak@109 289 function module:UPDATE_SHAPESHIFT_FORMS()
flickerstreak@109 290 -- Re-parse the rules table according to the new form list.
flickerstreak@109 291 -- This happens both at initial login (after PLAYER_ENTERING_WORLD)
flickerstreak@109 292 -- as well as when gaining new abilities.
flickerstreak@109 293 InitRules()
flickerstreak@155 294 for _, bar in ReAction:IterateBars() do
flickerstreak@155 295 ApplyStates(bar)
flickerstreak@109 296 end
flickerstreak@109 297 end
flickerstreak@109 298
flickerstreak@109 299 function module:OnRefreshBar(event, bar, name)
flickerstreak@109 300 local c = self.db.profile.bars[name]
flickerstreak@109 301 if c then
flickerstreak@109 302 ApplyStates(bar)
flickerstreak@109 303 end
flickerstreak@109 304 end
flickerstreak@109 305
flickerstreak@109 306 function module:OnDestroyBar(event, bar, name)
flickerstreak@109 307 CleanupStates(bar)
flickerstreak@109 308 end
flickerstreak@109 309
flickerstreak@109 310 function module:OnEraseBar(event, bar, name)
flickerstreak@109 311 self.db.profile.bars[name] = nil
flickerstreak@109 312 end
flickerstreak@109 313
flickerstreak@109 314 function module:OnRenameBar(event, bar, oldname, newname)
flickerstreak@109 315 local bars = self.db.profile.bars
flickerstreak@109 316 bars[newname], bars[oldname] = bars[oldname], nil
flickerstreak@109 317 end
flickerstreak@109 318
flickerstreak@109 319
flickerstreak@109 320
flickerstreak@109 321 -- Options --
flickerstreak@109 322
flickerstreak@109 323 local CreateBarOptions, RegisterPropertyOptions
flickerstreak@109 324 do
flickerstreak@109 325 -- pre-sorted by the order they should appear in
flickerstreak@109 326 local rules = {
flickerstreak@118 327 -- rule fields
flickerstreak@118 328 { "stance", { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
flickerstreak@118 329 { "form", { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } },
flickerstreak@118 330 { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]} } },
flickerstreak@118 331 { "shadow", { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
flickerstreak@118 332 { "pet", { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
flickerstreak@118 333 { "target", { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
flickerstreak@118 334 { "focus", { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
flickerstreak@118 335 { "possess", { {possess = L["Mind Control"]} } },
flickerstreak@118 336 { "vehicle", { {vehicle = L["In a Vehicle"]} } },
flickerstreak@118 337 { "group", { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
flickerstreak@118 338 { "combat", { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } },
flickerstreak@109 339 }
flickerstreak@109 340
flickerstreak@109 341 local ruleSelect = { }
flickerstreak@109 342 local ruleMap = { }
flickerstreak@109 343 local optionMap = setmetatable({},{__mode="k"})
flickerstreak@109 344
flickerstreak@109 345 local pointTable = {
flickerstreak@109 346 NONE = " ",
flickerstreak@109 347 CENTER = L["Center"],
flickerstreak@109 348 LEFT = L["Left"],
flickerstreak@109 349 RIGHT = L["Right"],
flickerstreak@109 350 TOP = L["Top"],
flickerstreak@109 351 BOTTOM = L["Bottom"],
flickerstreak@109 352 TOPLEFT = L["Top Left"],
flickerstreak@109 353 TOPRIGHT = L["Top Right"],
flickerstreak@109 354 BOTTOMLEFT = L["Bottom Left"],
flickerstreak@109 355 BOTTOMRIGHT = L["Bottom Right"],
flickerstreak@109 356 }
flickerstreak@109 357
flickerstreak@109 358 -- unpack rules table into ruleSelect and ruleMap
flickerstreak@109 359 for _, c in ipairs(rules) do
flickerstreak@118 360 local rule, fields = unpack(c)
flickerstreak@118 361 for _, field in ipairs(fields) do
flickerstreak@118 362 local key, label = next(field)
flickerstreak@118 363 table.insert(ruleSelect, label)
flickerstreak@118 364 table.insert(ruleMap, key)
flickerstreak@109 365 end
flickerstreak@109 366 end
flickerstreak@109 367
flickerstreak@109 368 local stateOptions = {
flickerstreak@109 369 ordering = {
flickerstreak@109 370 name = L["Info"],
flickerstreak@109 371 order = 1,
flickerstreak@109 372 type = "group",
flickerstreak@109 373 args = {
flickerstreak@109 374 delete = {
flickerstreak@109 375 name = L["Delete this State"],
flickerstreak@109 376 order = -1,
flickerstreak@109 377 type = "execute",
flickerstreak@109 378 func = "DeleteState",
flickerstreak@109 379 },
flickerstreak@109 380 rename = {
flickerstreak@109 381 name = L["Name"],
flickerstreak@109 382 order = 1,
flickerstreak@109 383 type = "input",
flickerstreak@109 384 get = "GetName",
flickerstreak@109 385 set = "SetStateName",
flickerstreak@109 386 pattern = "^%w*$",
flickerstreak@109 387 usage = L["State names must be alphanumeric without spaces"],
flickerstreak@109 388 },
flickerstreak@109 389 ordering = {
flickerstreak@109 390 name = L["Evaluation Order"],
flickerstreak@109 391 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"],
flickerstreak@109 392 order = 2,
flickerstreak@109 393 type = "group",
flickerstreak@109 394 inline = true,
flickerstreak@109 395 args = {
flickerstreak@109 396 up = {
flickerstreak@109 397 name = L["Up"],
flickerstreak@109 398 order = 1,
flickerstreak@109 399 type = "execute",
flickerstreak@109 400 width = "half",
flickerstreak@109 401 func = "MoveStateUp",
flickerstreak@109 402 },
flickerstreak@109 403 down = {
flickerstreak@109 404 name = L["Down"],
flickerstreak@109 405 order = 2,
flickerstreak@109 406 type = "execute",
flickerstreak@109 407 width = "half",
flickerstreak@109 408 func = "MoveStateDown",
flickerstreak@109 409 }
flickerstreak@109 410 }
flickerstreak@109 411 }
flickerstreak@109 412 }
flickerstreak@109 413 },
flickerstreak@109 414 properties = {
flickerstreak@109 415 name = L["Properties"],
flickerstreak@109 416 order = 2,
flickerstreak@109 417 type = "group",
flickerstreak@109 418 args = {
flickerstreak@109 419 desc = {
flickerstreak@109 420 name = L["Set the properties for the bar when in this state"],
flickerstreak@109 421 order = 1,
flickerstreak@109 422 type = "description"
flickerstreak@109 423 },
flickerstreak@109 424 hide = {
flickerstreak@109 425 name = L["Hide Bar"],
flickerstreak@109 426 order = 90,
flickerstreak@109 427 type = "toggle",
flickerstreak@109 428 set = "SetProp",
flickerstreak@109 429 get = "GetProp",
flickerstreak@109 430 },
flickerstreak@109 431 --[[ BROKEN
flickerstreak@109 432 keybindState = {
flickerstreak@109 433 name = L["Override Keybinds"],
flickerstreak@109 434 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
flickerstreak@109 435 order = 91,
flickerstreak@109 436 type = "toggle",
flickerstreak@109 437 set = "SetProp",
flickerstreak@109 438 get = "GetProp",
flickerstreak@109 439 }, ]]
flickerstreak@109 440 position = {
flickerstreak@109 441 name = L["Position"],
flickerstreak@109 442 order = 92,
flickerstreak@109 443 type = "group",
flickerstreak@109 444 inline = true,
flickerstreak@109 445 args = {
flickerstreak@109 446 anchorEnable = {
flickerstreak@109 447 name = L["Reposition"],
flickerstreak@109 448 order = 1,
flickerstreak@109 449 type = "toggle",
flickerstreak@109 450 set = "SetProp",
flickerstreak@109 451 get = "GetProp",
flickerstreak@109 452 },
flickerstreak@109 453 anchorFrame = {
flickerstreak@109 454 name = L["Anchor Frame"],
flickerstreak@109 455 order = 2,
flickerstreak@109 456 type = "select",
flickerstreak@109 457 values = "GetAnchorFrames",
flickerstreak@109 458 set = "SetAnchorFrame",
flickerstreak@109 459 get = "GetAnchorFrame",
flickerstreak@109 460 disabled = "GetAnchorDisabled",
flickerstreak@109 461 hidden = "GetAnchorDisabled",
flickerstreak@109 462 },
flickerstreak@109 463 anchorPoint = {
flickerstreak@109 464 name = L["Point"],
flickerstreak@109 465 order = 3,
flickerstreak@109 466 type = "select",
flickerstreak@109 467 values = pointTable,
flickerstreak@109 468 set = "SetAnchorPointProp",
flickerstreak@109 469 get = "GetAnchorPointProp",
flickerstreak@109 470 disabled = "GetAnchorDisabled",
flickerstreak@109 471 hidden = "GetAnchorDisabled",
flickerstreak@109 472 },
flickerstreak@109 473 anchorRelPoint = {
flickerstreak@109 474 name = L["Relative Point"],
flickerstreak@109 475 order = 4,
flickerstreak@109 476 type = "select",
flickerstreak@109 477 values = pointTable,
flickerstreak@109 478 set = "SetAnchorPointProp",
flickerstreak@109 479 get = "GetAnchorPointProp",
flickerstreak@109 480 disabled = "GetAnchorDisabled",
flickerstreak@109 481 hidden = "GetAnchorDisabled",
flickerstreak@109 482 },
flickerstreak@109 483 anchorX = {
flickerstreak@109 484 name = L["X Offset"],
flickerstreak@109 485 order = 5,
flickerstreak@109 486 type = "range",
flickerstreak@109 487 min = -100,
flickerstreak@109 488 max = 100,
flickerstreak@109 489 step = 1,
flickerstreak@109 490 set = "SetProp",
flickerstreak@109 491 get = "GetProp",
flickerstreak@109 492 disabled = "GetAnchorDisabled",
flickerstreak@109 493 hidden = "GetAnchorDisabled",
flickerstreak@109 494 },
flickerstreak@109 495 anchorY = {
flickerstreak@109 496 name = L["Y Offset"],
flickerstreak@109 497 order = 6,
flickerstreak@109 498 type = "range",
flickerstreak@109 499 min = -100,
flickerstreak@109 500 max = 100,
flickerstreak@109 501 step = 1,
flickerstreak@109 502 set = "SetProp",
flickerstreak@109 503 get = "GetProp",
flickerstreak@109 504 disabled = "GetAnchorDisabled",
flickerstreak@109 505 hidden = "GetAnchorDisabled",
flickerstreak@109 506 },
flickerstreak@109 507 },
flickerstreak@109 508 },
flickerstreak@109 509 scale = {
flickerstreak@109 510 name = L["Scale"],
flickerstreak@109 511 order = 93,
flickerstreak@109 512 type = "group",
flickerstreak@109 513 inline = true,
flickerstreak@109 514 args = {
flickerstreak@109 515 enableScale = {
flickerstreak@109 516 name = L["Set New Scale"],
flickerstreak@109 517 order = 1,
flickerstreak@109 518 type = "toggle",
flickerstreak@109 519 set = "SetProp",
flickerstreak@109 520 get = "GetProp",
flickerstreak@109 521 },
flickerstreak@109 522 scale = {
flickerstreak@109 523 name = L["Scale"],
flickerstreak@109 524 order = 2,
flickerstreak@109 525 type = "range",
flickerstreak@109 526 min = 0.25,
flickerstreak@109 527 max = 2.5,
flickerstreak@109 528 step = 0.05,
flickerstreak@109 529 isPercent = true,
flickerstreak@109 530 set = "SetProp",
flickerstreak@109 531 get = "GetScale",
flickerstreak@109 532 disabled = "GetScaleDisabled",
flickerstreak@109 533 hidden = "GetScaleDisabled",
flickerstreak@109 534 },
flickerstreak@109 535 },
flickerstreak@109 536 },
flickerstreak@109 537 alpha = {
flickerstreak@109 538 name = L["Transparency"],
flickerstreak@109 539 order = 94,
flickerstreak@109 540 type = "group",
flickerstreak@109 541 inline = true,
flickerstreak@109 542 args = {
flickerstreak@109 543 enableAlpha = {
flickerstreak@109 544 name = L["Set Transparency"],
flickerstreak@109 545 order = 1,
flickerstreak@109 546 type = "toggle",
flickerstreak@109 547 set = "SetProp",
flickerstreak@109 548 get = "GetProp",
flickerstreak@109 549 },
flickerstreak@109 550 alpha = {
flickerstreak@109 551 name = L["Transparency"],
flickerstreak@109 552 order = 2,
flickerstreak@109 553 type = "range",
flickerstreak@109 554 min = 0,
flickerstreak@109 555 max = 1,
flickerstreak@109 556 step = 0.01,
flickerstreak@109 557 bigStep = 0.05,
flickerstreak@109 558 isPercent = true,
flickerstreak@109 559 set = "SetProp",
flickerstreak@109 560 get = "GetAlpha",
flickerstreak@109 561 disabled = "GetAlphaDisabled",
flickerstreak@109 562 hidden = "GetAlphaDisabled",
flickerstreak@109 563 },
flickerstreak@109 564 },
flickerstreak@109 565 },
flickerstreak@109 566 },
flickerstreak@109 567 plugins = { }
flickerstreak@109 568 },
flickerstreak@109 569 rules = {
flickerstreak@109 570 name = L["Rule"],
flickerstreak@109 571 order = 3,
flickerstreak@109 572 type = "group",
flickerstreak@109 573 args = {
flickerstreak@109 574 mode = {
flickerstreak@109 575 name = L["Select this state"],
flickerstreak@109 576 order = 2,
flickerstreak@109 577 type = "select",
flickerstreak@109 578 style = "radio",
flickerstreak@109 579 values = {
flickerstreak@109 580 default = L["by default"],
flickerstreak@109 581 any = L["when ANY of these"],
flickerstreak@109 582 all = L["when ALL of these"],
flickerstreak@109 583 custom = L["via custom rule"],
flickerstreak@109 584 keybind = L["via keybinding"],
flickerstreak@109 585 },
flickerstreak@109 586 set = "SetType",
flickerstreak@109 587 get = "GetType",
flickerstreak@109 588 },
flickerstreak@109 589 clear = {
flickerstreak@109 590 name = L["Clear All"],
flickerstreak@109 591 order = 3,
flickerstreak@109 592 type = "execute",
flickerstreak@109 593 hidden = "GetClearAllDisabled",
flickerstreak@109 594 disabled = "GetClearAllDisabled",
flickerstreak@109 595 func = "ClearAllConditions",
flickerstreak@109 596 },
flickerstreak@109 597 inputs = {
flickerstreak@109 598 name = L["Conditions"],
flickerstreak@109 599 order = 4,
flickerstreak@109 600 type = "multiselect",
flickerstreak@109 601 hidden = "GetConditionsDisabled",
flickerstreak@109 602 disabled = "GetConditionsDisabled",
flickerstreak@109 603 values = ruleSelect,
flickerstreak@109 604 set = "SetCondition",
flickerstreak@109 605 get = "GetCondition",
flickerstreak@109 606 },
flickerstreak@109 607 custom = {
flickerstreak@109 608 name = L["Custom Rule"],
flickerstreak@109 609 order = 5,
flickerstreak@109 610 type = "input",
flickerstreak@109 611 multiline = true,
flickerstreak@109 612 hidden = "GetCustomDisabled",
flickerstreak@109 613 disabled = "GetCustomDisabled",
flickerstreak@109 614 desc = L["Syntax like macro rules: see preset rules for examples"],
flickerstreak@109 615 set = "SetCustomRule",
flickerstreak@109 616 get = "GetCustomRule",
flickerstreak@109 617 validate = "ValidateCustomRule",
flickerstreak@109 618 },
flickerstreak@109 619 keybind = {
flickerstreak@109 620 name = L["Keybinding"],
flickerstreak@109 621 order = 6,
flickerstreak@109 622 inline = true,
flickerstreak@109 623 hidden = "GetKeybindDisabled",
flickerstreak@109 624 disabled = "GetKeybindDisabled",
flickerstreak@109 625 type = "group",
flickerstreak@109 626 args = {
flickerstreak@109 627 desc = {
flickerstreak@109 628 name = L["Invoking a state keybind toggles an override of all other transition rules."],
flickerstreak@109 629 order = 1,
flickerstreak@109 630 type = "description",
flickerstreak@109 631 },
flickerstreak@109 632 keybind = {
flickerstreak@109 633 name = L["State Hotkey"],
flickerstreak@109 634 desc = L["Define an override toggle keybind"],
flickerstreak@109 635 order = 2,
flickerstreak@109 636 type = "keybinding",
flickerstreak@109 637 set = "SetKeybind",
flickerstreak@109 638 get = "GetKeybind",
flickerstreak@109 639 },
flickerstreak@109 640 },
flickerstreak@109 641 },
flickerstreak@109 642 },
flickerstreak@109 643 },
flickerstreak@109 644 }
flickerstreak@109 645
flickerstreak@109 646 local handlers = { }
flickerstreak@109 647 local meta = {
flickerstreak@109 648 __index = function(self, key)
flickerstreak@109 649 for _, h in pairs(handlers) do
flickerstreak@109 650 if h[key] then
flickerstreak@109 651 return h[key]
flickerstreak@109 652 end
flickerstreak@109 653 end
flickerstreak@109 654 end,
flickerstreak@109 655 }
flickerstreak@109 656 local StateHandler = setmetatable({ }, meta)
flickerstreak@109 657 local proto = { __index = StateHandler }
flickerstreak@109 658
flickerstreak@109 659 function RegisterPropertyOptions( field, options, handler )
flickerstreak@109 660 stateOptions.properties.plugins[field] = options
flickerstreak@109 661 handlers[field] = handler
flickerstreak@109 662 end
flickerstreak@109 663
flickerstreak@109 664 function UnregisterPropertyOptions( field )
flickerstreak@109 665 stateOptions.properties.plugins[field] = nil
flickerstreak@109 666 handlers[field] = nil
flickerstreak@109 667 end
flickerstreak@109 668
flickerstreak@109 669 function StateHandler:New( bar, opts )
flickerstreak@109 670 local self = setmetatable(
flickerstreak@109 671 {
flickerstreak@109 672 bar = bar
flickerstreak@109 673 },
flickerstreak@109 674 proto )
flickerstreak@109 675
flickerstreak@109 676 function self:GetName()
flickerstreak@109 677 return opts.name
flickerstreak@109 678 end
flickerstreak@109 679
flickerstreak@109 680 function self:SetName(name)
flickerstreak@109 681 opts.name = name
flickerstreak@109 682 end
flickerstreak@109 683
flickerstreak@109 684 function self:GetOrder()
flickerstreak@109 685 return opts.order
flickerstreak@109 686 end
flickerstreak@109 687
flickerstreak@109 688 -- get reference to states table: even if the bar
flickerstreak@109 689 -- name changes the states table ref won't
flickerstreak@109 690 self.states = tbuild(module.db.profile.bars, bar:GetName(), "states")
flickerstreak@109 691 self.state = tbuild(self.states, opts.name)
flickerstreak@109 692
flickerstreak@109 693 opts.order = self:GetRuleField("order")
flickerstreak@109 694 if opts.order == nil then
flickerstreak@109 695 -- add after the highest
flickerstreak@109 696 opts.order = 100
flickerstreak@109 697 for _, state in pairs(self.states) do
flickerstreak@109 698 local x = tonumber(tfetch(state, "rule", "order"))
flickerstreak@109 699 if x and x >= opts.order then
flickerstreak@109 700 opts.order = x + 1
flickerstreak@109 701 end
flickerstreak@109 702 end
flickerstreak@109 703 self:SetRuleField("order",opts.order)
flickerstreak@109 704 end
flickerstreak@109 705
flickerstreak@109 706 return self
flickerstreak@109 707 end
flickerstreak@109 708
flickerstreak@109 709 -- helper methods
flickerstreak@109 710
flickerstreak@109 711 function StateHandler:SetRuleField( key, value, ... )
flickerstreak@109 712 tbuild(self.state, "rule", ...)[key] = value
flickerstreak@109 713 end
flickerstreak@109 714
flickerstreak@109 715 function StateHandler:GetRuleField( ... )
flickerstreak@109 716 return tfetch(self.state, "rule", ...)
flickerstreak@109 717 end
flickerstreak@109 718
flickerstreak@109 719 function StateHandler:FixAll( setkey )
flickerstreak@109 720 -- if multiple selections in the same group are chosen when 'all' is selected,
flickerstreak@109 721 -- keep only one of them. If changing the mode, the first in the fields list will
flickerstreak@109 722 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set,
flickerstreak@109 723 -- it will be retained.
flickerstreak@109 724 local notified = false
flickerstreak@109 725 if self:GetRuleField("type") == "all" then
flickerstreak@109 726 for _, c in ipairs(rules) do
flickerstreak@118 727 local rule, fields = unpack(c)
flickerstreak@109 728 local once = false
flickerstreak@109 729 if setkey then
flickerstreak@109 730 for idx, field in ipairs(fields) do
flickerstreak@109 731 if next(field) == setkey then
flickerstreak@109 732 once = true
flickerstreak@109 733 end
flickerstreak@109 734 end
flickerstreak@109 735 end
flickerstreak@109 736 for idx, field in ipairs(fields) do
flickerstreak@109 737 local key = next(field)
flickerstreak@109 738 if self:GetRuleField("values",key) then
flickerstreak@109 739 if once and key ~= setkey then
flickerstreak@109 740 self:SetRuleField(key,false,"values")
flickerstreak@109 741 if not setkey and not notified then
flickerstreak@109 742 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"])
flickerstreak@109 743 notified = true
flickerstreak@109 744 end
flickerstreak@109 745 end
flickerstreak@109 746 once = true
flickerstreak@109 747 end
flickerstreak@109 748 end
flickerstreak@109 749 end
flickerstreak@109 750 end
flickerstreak@109 751 end
flickerstreak@109 752
flickerstreak@109 753 function StateHandler:GetNeighbors()
flickerstreak@109 754 local before, after
flickerstreak@109 755 for k, v in pairs(self.states) do
flickerstreak@109 756 local o = tonumber(tfetch(v, "rule", "order"))
flickerstreak@109 757 if o and k ~= self:GetName() then
flickerstreak@109 758 local obefore = tfetch(self.states,before,"rule","order")
flickerstreak@109 759 local oafter = tfetch(self.states,after,"rule","order")
flickerstreak@109 760 if o < self:GetOrder() and (not obefore or obefore < o) then
flickerstreak@109 761 before = k
flickerstreak@109 762 end
flickerstreak@109 763 if o > self:GetOrder() and (not oafter or oafter > o) then
flickerstreak@109 764 after = k
flickerstreak@109 765 end
flickerstreak@109 766 end
flickerstreak@109 767 end
flickerstreak@109 768 return before, after
flickerstreak@109 769 end
flickerstreak@109 770
flickerstreak@109 771 function StateHandler:SwapOrder( a, b )
flickerstreak@109 772 -- do options table
flickerstreak@109 773 local args = optionMap[self.bar].args
flickerstreak@109 774 args[a].order, args[b].order = args[b].order, args[a].order
flickerstreak@109 775 -- do profile
flickerstreak@109 776 a = tbuild(self.states, a, "rule")
flickerstreak@109 777 b = tbuild(self.states, b, "rule")
flickerstreak@109 778 a.order, b.order = b.order, a.order
flickerstreak@109 779 end
flickerstreak@109 780
flickerstreak@109 781 -- handler methods
flickerstreak@109 782
flickerstreak@109 783 function StateHandler:GetProp( info )
flickerstreak@109 784 -- gets property of the same name as the options arg
flickerstreak@109 785 return GetProperty(self.bar, self:GetName(), info[#info])
flickerstreak@109 786 end
flickerstreak@109 787
flickerstreak@109 788 function StateHandler:SetProp( info, value )
flickerstreak@109 789 -- sets property of the same name as the options arg
flickerstreak@109 790 SetProperty(self.bar, self:GetName(), info[#info], value)
flickerstreak@109 791 end
flickerstreak@109 792
flickerstreak@109 793 function StateHandler:DeleteState()
flickerstreak@109 794 if self.states[self:GetName()] then
flickerstreak@109 795 self.states[self:GetName()] = nil
flickerstreak@109 796 ApplyStates(self.bar)
flickerstreak@109 797 end
flickerstreak@109 798 optionMap[self.bar].args[self:GetName()] = nil
flickerstreak@109 799 end
flickerstreak@109 800
flickerstreak@109 801 function StateHandler:SetStateName(info, value)
flickerstreak@109 802 -- check for existing state name
flickerstreak@109 803 if self.states[value] then
flickerstreak@109 804 ReAction:UserError(format(L["State named '%s' already exists"],value))
flickerstreak@109 805 return
flickerstreak@109 806 end
flickerstreak@109 807 local args = optionMap[self.bar].args
flickerstreak@109 808 local name = self:GetName()
flickerstreak@109 809 self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil
flickerstreak@109 810 self:SetName(value)
flickerstreak@109 811 ApplyStates(self.bar)
flickerstreak@109 812 ReAction:ShowEditor(self.bar, moduleID, value)
flickerstreak@109 813 end
flickerstreak@109 814
flickerstreak@109 815 function StateHandler:MoveStateUp()
flickerstreak@109 816 local before, after = self:GetNeighbors()
flickerstreak@109 817 if before then
flickerstreak@109 818 self:SwapOrder(before, self:GetName())
flickerstreak@109 819 ApplyStates(self.bar)
flickerstreak@109 820 end
flickerstreak@109 821 end
flickerstreak@109 822
flickerstreak@109 823 function StateHandler:MoveStateDown()
flickerstreak@109 824 local before, after = self:GetNeighbors()
flickerstreak@109 825 if after then
flickerstreak@109 826 self:SwapOrder(self:GetName(), after)
flickerstreak@109 827 ApplyStates(self.bar)
flickerstreak@109 828 end
flickerstreak@109 829 end
flickerstreak@109 830
flickerstreak@109 831 function StateHandler:GetAnchorDisabled()
flickerstreak@109 832 return not GetProperty(self.bar, self:GetName(), "anchorEnable")
flickerstreak@109 833 end
flickerstreak@109 834
flickerstreak@109 835 function StateHandler:GetAnchorFrames(info)
flickerstreak@109 836 self._anchorframes = self._anchorframes or { }
flickerstreak@109 837 table.wipe(self._anchorframes)
flickerstreak@109 838
flickerstreak@109 839 table.insert(self._anchorframes, "UIParent")
flickerstreak@109 840 for name, bar in ReAction:IterateBars() do
flickerstreak@109 841 table.insert(self._anchorframes, bar:GetFrame():GetName())
flickerstreak@109 842 end
flickerstreak@109 843 return self._anchorframes
flickerstreak@109 844 end
flickerstreak@109 845
flickerstreak@109 846 function StateHandler:GetAnchorFrame(info)
flickerstreak@109 847 local value = self:GetProp(info)
flickerstreak@109 848 for k,v in pairs(self._anchorframes) do
flickerstreak@109 849 if v == value then
flickerstreak@109 850 return k
flickerstreak@109 851 end
flickerstreak@109 852 end
flickerstreak@109 853 end
flickerstreak@109 854
flickerstreak@109 855 function StateHandler:SetAnchorFrame(info, value)
flickerstreak@109 856 local f = _G[self._anchorframes[value]]
flickerstreak@109 857 if f then
flickerstreak@155 858 bar:SetFrameRef("anchor-"..self:GetName(), f)
flickerstreak@109 859 self:SetProp(info, f:GetName())
flickerstreak@109 860 end
flickerstreak@109 861 end
flickerstreak@109 862
flickerstreak@109 863 function StateHandler:SetAnchorPointProp(info, value)
flickerstreak@109 864 self:SetProp(info, value ~= "NONE" and value or nil)
flickerstreak@109 865 end
flickerstreak@109 866
flickerstreak@109 867 function StateHandler:GetAnchorPointProp(info)
flickerstreak@109 868 return self:GetProp(info) or "NONE"
flickerstreak@109 869 end
flickerstreak@109 870
flickerstreak@109 871 function StateHandler:GetScale(info)
flickerstreak@109 872 return self:GetProp(info) or 1.0
flickerstreak@109 873 end
flickerstreak@109 874
flickerstreak@109 875 function StateHandler:GetScaleDisabled()
flickerstreak@109 876 return not GetProperty(self.bar, self:GetName(), "enableScale")
flickerstreak@109 877 end
flickerstreak@109 878
flickerstreak@109 879 function StateHandler:GetAlpha(info)
flickerstreak@109 880 return self:GetProp(info) or 1.0
flickerstreak@109 881 end
flickerstreak@109 882
flickerstreak@109 883 function StateHandler:GetAlphaDisabled()
flickerstreak@109 884 return not GetProperty(self.bar, self:GetName(), "enableAlpha")
flickerstreak@109 885 end
flickerstreak@109 886
flickerstreak@109 887 function StateHandler:SetType(info, value)
flickerstreak@109 888 self:SetRuleField("type", value)
flickerstreak@109 889 self:FixAll()
flickerstreak@109 890 ApplyStates(self.bar)
flickerstreak@109 891 end
flickerstreak@109 892
flickerstreak@109 893 function StateHandler:GetType()
flickerstreak@109 894 return self:GetRuleField("type")
flickerstreak@109 895 end
flickerstreak@109 896
flickerstreak@109 897 function StateHandler:GetClearAllDisabled()
flickerstreak@109 898 local t = self:GetRuleField("type")
flickerstreak@109 899 return not( t == "any" or t == "all" or t == "custom")
flickerstreak@109 900 end
flickerstreak@109 901
flickerstreak@109 902 function StateHandler:ClearAllConditions()
flickerstreak@109 903 local t = self:GetRuleField("type")
flickerstreak@109 904 if t == "custom" then
flickerstreak@109 905 self:SetRuleField("custom","")
flickerstreak@109 906 elseif t == "any" or t == "all" then
flickerstreak@109 907 self:SetRuleField("values", {})
flickerstreak@109 908 end
flickerstreak@109 909 ApplyStates(self.bar)
flickerstreak@109 910 end
flickerstreak@109 911
flickerstreak@109 912 function StateHandler:GetConditionsDisabled()
flickerstreak@109 913 local t = self:GetRuleField("type")
flickerstreak@109 914 return not( t == "any" or t == "all")
flickerstreak@109 915 end
flickerstreak@109 916
flickerstreak@109 917 function StateHandler:SetCondition(info, key, value)
flickerstreak@109 918 self:SetRuleField(ruleMap[key], value or nil, "values")
flickerstreak@109 919 if value then
flickerstreak@109 920 self:FixAll(ruleMap[key])
flickerstreak@109 921 end
flickerstreak@109 922 ApplyStates(self.bar)
flickerstreak@109 923 end
flickerstreak@109 924
flickerstreak@109 925 function StateHandler:GetCondition(info, key)
flickerstreak@109 926 return self:GetRuleField("values", ruleMap[key]) or false
flickerstreak@109 927 end
flickerstreak@109 928
flickerstreak@109 929 function StateHandler:GetCustomDisabled()
flickerstreak@109 930 return self:GetRuleField("type") ~= "custom"
flickerstreak@109 931 end
flickerstreak@109 932
flickerstreak@109 933 function StateHandler:SetCustomRule(info, value)
flickerstreak@109 934 self:SetRuleField("custom",value)
flickerstreak@109 935 ApplyStates(self.bar)
flickerstreak@109 936 end
flickerstreak@109 937
flickerstreak@109 938 function StateHandler:GetCustomRule()
flickerstreak@109 939 return self:GetRuleField("custom") or ""
flickerstreak@109 940 end
flickerstreak@109 941
flickerstreak@109 942 function StateHandler:ValidateCustomRule(info, value)
flickerstreak@109 943 local s = value:gsub("%s","") -- remove all spaces
flickerstreak@109 944 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler
flickerstreak@109 945 repeat
flickerstreak@109 946 if s == "" then
flickerstreak@109 947 return true
flickerstreak@109 948 end
flickerstreak@109 949 local c, r = s:match("(%b[])(.*)")
flickerstreak@109 950 if c == nil and s and #s > 0 then
flickerstreak@109 951 return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "")
flickerstreak@109 952 end
flickerstreak@109 953 s = r
flickerstreak@109 954 until c == nil
flickerstreak@109 955 return true
flickerstreak@109 956 end
flickerstreak@109 957
flickerstreak@109 958 function StateHandler:GetKeybindDisabled()
flickerstreak@109 959 return self:GetRuleField("type") ~= "keybind"
flickerstreak@109 960 end
flickerstreak@109 961
flickerstreak@109 962 function StateHandler:GetKeybind()
flickerstreak@109 963 return self:GetRuleField("keybind")
flickerstreak@109 964 end
flickerstreak@109 965
flickerstreak@109 966 function StateHandler:SetKeybind(info, value)
flickerstreak@109 967 if value and #value == 0 then
flickerstreak@109 968 value = nil
flickerstreak@109 969 end
flickerstreak@109 970 self:SetRuleField("keybind",value)
flickerstreak@109 971 ApplyStates(self.bar)
flickerstreak@109 972 end
flickerstreak@109 973
flickerstreak@109 974 local function CreateStateOptions(bar, name)
flickerstreak@109 975 local opts = {
flickerstreak@109 976 type = "group",
flickerstreak@109 977 name = name,
flickerstreak@109 978 childGroups = "tab",
flickerstreak@109 979 args = stateOptions
flickerstreak@109 980 }
flickerstreak@109 981
flickerstreak@109 982 opts.handler = StateHandler:New(bar,opts)
flickerstreak@109 983
flickerstreak@109 984 return opts
flickerstreak@109 985 end
flickerstreak@109 986
flickerstreak@109 987 function module:GetBarOptions(bar)
flickerstreak@109 988 local private = { }
flickerstreak@109 989 local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
flickerstreak@109 990 local options = {
flickerstreak@109 991 name = L["Dynamic State"],
flickerstreak@109 992 type = "group",
flickerstreak@109 993 order = -1,
flickerstreak@109 994 childGroups = "tree",
flickerstreak@109 995 disabled = InCombatLockdown,
flickerstreak@109 996 args = {
flickerstreak@109 997 __desc__ = {
flickerstreak@109 998 name = L["States are evaluated in the order they are listed"],
flickerstreak@109 999 order = 1,
flickerstreak@109 1000 type = "description",
flickerstreak@109 1001 },
flickerstreak@109 1002 __new__ = {
flickerstreak@109 1003 name = L["New State..."],
flickerstreak@109 1004 order = 2,
flickerstreak@109 1005 type = "group",
flickerstreak@109 1006 args = {
flickerstreak@109 1007 name = {
flickerstreak@109 1008 name = L["State Name"],
flickerstreak@109 1009 desc = L["Set a name for the new state"],
flickerstreak@109 1010 order = 1,
flickerstreak@109 1011 type = "input",
flickerstreak@109 1012 get = function() return private.newstatename or "" end,
flickerstreak@109 1013 set = function(info,value) private.newstatename = value end,
flickerstreak@109 1014 pattern = "^%w*$",
flickerstreak@109 1015 usage = L["State names must be alphanumeric without spaces"],
flickerstreak@109 1016 },
flickerstreak@109 1017 create = {
flickerstreak@109 1018 name = L["Create State"],
flickerstreak@109 1019 order = 2,
flickerstreak@109 1020 type = "execute",
flickerstreak@109 1021 func = function ()
flickerstreak@109 1022 local name = private.newstatename
flickerstreak@109 1023 if states[name] then
flickerstreak@109 1024 ReAction:UserError(format(L["State named '%s' already exists"],name))
flickerstreak@109 1025 else
flickerstreak@109 1026 -- TODO: select default state options and pass as final argument
flickerstreak@109 1027 states[name] = { }
flickerstreak@109 1028 optionMap[bar].args[name] = CreateStateOptions(bar,name)
flickerstreak@109 1029 ReAction:ShowEditor(bar, moduleID, name)
flickerstreak@109 1030 private.newstatename = ""
flickerstreak@109 1031 end
flickerstreak@109 1032 end,
flickerstreak@109 1033 disabled = function()
flickerstreak@109 1034 local name = private.newstatename or ""
flickerstreak@109 1035 return #name == 0 or name:find("%W")
flickerstreak@109 1036 end,
flickerstreak@109 1037 }
flickerstreak@109 1038 }
flickerstreak@109 1039 }
flickerstreak@109 1040 }
flickerstreak@109 1041 }
flickerstreak@109 1042 for name, config in pairs(states) do
flickerstreak@109 1043 options.args[name] = CreateStateOptions(bar,name)
flickerstreak@109 1044 end
flickerstreak@109 1045 optionMap[bar] = options
flickerstreak@109 1046 return options
flickerstreak@109 1047 end
flickerstreak@109 1048 end
flickerstreak@109 1049
flickerstreak@109 1050 -- Module API --
flickerstreak@109 1051
flickerstreak@109 1052 -- Pass in a property field-name, an implementation secure snippet, a static options table, and an
flickerstreak@109 1053 -- optional options handler method-table
flickerstreak@109 1054 --
flickerstreak@109 1055 -- The options table is static, i.e. not bar-specific and should only reference handler method
flickerstreak@109 1056 -- strings (either existing ones or those added via optHandler). The existing options are ordered
flickerstreak@109 1057 -- 90-99. Order #1 is reserved for the heading.
flickerstreak@109 1058 --
flickerstreak@109 1059 -- The contents of optHandler, if provided, will be added to the existing StateHandler options metatable.
flickerstreak@109 1060 -- See above, for existing API. In particular see the properties set up in the New method: self.bar,
flickerstreak@109 1061 -- self.states, and self:GetName(), and the generic property handlers self:GetProp() and self:SetProp().
flickerstreak@109 1062 --
flickerstreak@109 1063 function module:RegisterStateProperty( field, snippetHandler, options, optHandler )
flickerstreak@109 1064 RegisterProperty(field, snippetHandler)
flickerstreak@109 1065 RegisterPropertyOptions(field, options, optHandler)
flickerstreak@109 1066 end
flickerstreak@109 1067
flickerstreak@109 1068 function module:UnregisterStateProperty( field )
flickerstreak@109 1069 UnregisterProperty(field)
flickerstreak@109 1070 UnregisterPropertyOptions(field)
flickerstreak@109 1071 end
flickerstreak@109 1072
flickerstreak@109 1073
flickerstreak@109 1074 -- Export methods to Bar class --
flickerstreak@109 1075
flickerstreak@109 1076 ReAction.Bar.GetStateProperty = GetProperty
flickerstreak@109 1077 ReAction.Bar.SetStateProperty = SetProperty