comparison 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
comparison
equal deleted inserted replaced
154:df67685b340e 155:806a61b331a0
51 return olhs < orhs 51 return olhs < orhs
52 end) 52 end)
53 return r 53 return r
54 end 54 end
55 55
56 -- set a frame-ref, if the frame is valid, or set nil to the 56
57 -- corresponding attribute 57 local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty
58 local function SetFrameRef(frame, name, refFrame)
59 if refFrame then
60 local _, explicit = refFrame:IsProtected()
61 if not explicit then
62 refFrame = nil
63 end
64 end
65 if refFrame then
66 frame:SetFrameRef(name,refFrame)
67 else
68 frame:SetAttribute("frameref-"..name,nil)
69 end
70 end
71
72
73 local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty, ShowAll
74 58
75 -- PRIVATE -- 59 -- PRIVATE --
76 do 60 do
77 61
78 -- the field names must match the field names of the options table, below 62 -- the field names must match the field names of the options table, below
79 -- the field values are secure snippets or 'true' to skip the snippet for that property. 63 -- the field values are secure snippets or 'true' to skip the snippet for that property.
80 local properties = { 64 local properties = {
81 hide = 65 hide = true,
82 [[ 66 --keybindState = true, TODO: broken
83 local h = hide and hide[state] and not showAll 67 anchorEnable = true,
84 if h ~= hidden then
85 if h then
86 self:Hide()
87 else
88 self:Show()
89 end
90 hidden = h
91 end
92 if showAll then
93 control:CallMethod("UpdateHiddenLabel", hide and hide[state])
94 end
95 ]],
96
97 --keybindState TODO: broken
98
99 anchorEnable =
100 [[
101 local old_anchor = anchorstate
102 anchorstate = (anchorEnable and anchorEnable[state]) and state
103 if old_anchor ~= anchorstate or not set_state then
104 if anchorstate and anchorPoint then
105 if anchorPoint[state] then
106 self:ClearAllPoints()
107 local f = self:GetAttribute("frameref-anchor-"..anchorstate)
108 if f then
109 self:SetPoint(anchorPoint[state], f, anchorRelPoint[state], anchorX[state], anchorY[state])
110 end
111 end
112 elseif defaultAnchor and defaultAnchor.point then
113 self:ClearAllPoints()
114 self:SetPoint(defaultAnchor.point, defaultAnchor.frame,
115 defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
116 end
117 end
118 ]],
119 -- anchorEnable handles all the other bits
120 anchorFrame = true, 68 anchorFrame = true,
121 anchorPoint = true, 69 anchorPoint = true,
122 anchorRelPoint = true, 70 anchorRelPoint = true,
123 anchorX = true, 71 anchorX = true,
124 anchorY = true, 72 anchorY = true,
125 73 enableScale = true,
126
127 enableScale =
128 [[
129 local old_scale = scalestate
130 scalestate = (enableScale and enableScale[state]) and state
131 if old_scale ~= scalestate or not set_state then
132 if scalestate and scale then
133 if scale[state] then
134 self:SetScale(scale[state])
135 end
136 else
137 self:SetScale(1.0)
138 end
139 end
140 ]],
141 -- enableScale handles scale
142 scale = true, 74 scale = true,
143 75 enableAlpha = true,
144 enableAlpha =
145 [[
146 local old_alpha = alphastate
147 alphastate = (enableAlpha and enableAlpha[state]) and state
148 if old_alpha ~= alphastate or not set_state then
149 control:CallMethod("UpdateAlpha", alphastate and alpha[state] or defaultAlpha)
150 end
151 ]],
152 -- enableAlpha handles alpha
153 alpha = true, 76 alpha = true,
154 } 77 }
155
156 local weak = { __mode = "k" }
157 local statedrivers = setmetatable( { }, weak )
158 local keybinds = setmetatable( { }, weak )
159
160 --
161 -- Secure Handler Snippets
162 --
163 local SetHandlerData, SetStateDriver, SetStateKeybind, RefreshState
164 do
165 local stateHandler_propInit =
166 [[
167 propfuncs = table.new()
168 local proplist = self:GetAttribute("prop-func-list")
169 for s in string.gmatch(proplist, "(%w+)") do
170 table.insert(propfuncs, s)
171 end
172 ]]
173
174 local onStateHandler =
175 -- function _onstate-reaction( self, stateid, newstate )
176 [[
177 set_state = newstate
178
179 local oldState = state
180 state = state_override or set_state or state
181 for i = 1, #propfuncs do
182 control:RunAttribute("func-"..propfuncs[i])
183 end
184
185 control:ChildUpdate()
186
187 if oldState ~= state then
188 control:CallMethod("StateRefresh", state)
189 end
190 ]]
191
192 local onClickHandler =
193 -- function OnClick( self, button, down )
194 [[
195 if state_override == button then
196 state_override = nil -- toggle
197 else
198 state_override = button
199 end
200 ]] .. onStateHandler
201
202 local function UpdateAlpha( frame, alpha )
203 if alpha then
204 frame:SetAlpha(alpha)
205 end
206 end
207
208 -- Construct a lua assignment as a code string and execute it within the header
209 -- frame's sandbox. 'value' must be a string, boolean, number, or nil. If called
210 -- with four arguments, then it treats 'varname' as an existing global table and
211 -- sets a key-value pair. For a slight efficiency boost, pass the values in as
212 -- attributes and fetch them as attributes from the snippet code, to leverage snippet
213 -- caching.
214 function SetHandlerData( bar, varname, value, key )
215 local f = bar:GetFrame()
216 f:SetAttribute("data-varname",varname)
217 f:SetAttribute("data-value", value)
218 f:SetAttribute("data-key", key)
219 f:Execute(
220 [[
221 local name = self:GetAttribute("data-varname")
222 local value = self:GetAttribute("data-value")
223 local key = self:GetAttribute("data-key")
224 if name then
225 if key then
226 if not _G[name] then
227 _G[name] = table.new()
228 end
229 _G[name][key] = value
230 else
231 _G[name] = value
232 end
233 end
234 ]])
235 end
236
237 function SetDefaultAnchor( bar )
238 local point, frame, relPoint, x, y = bar:GetAnchor()
239 SetHandlerData(bar, "defaultAnchor", point, "point")
240 SetHandlerData(bar, "defaultAnchor", relPoint, "relPoint")
241 SetHandlerData(bar, "defaultAnchor", x, "x")
242 SetHandlerData(bar, "defaultAnchor", y, "y")
243 SetHandlerData(bar, "defaultAlpha", bar:GetAlpha())
244
245 local f = bar:GetFrame()
246 f.UpdateAlpha = UpdateAlpha
247 SetFrameRef(f, "defaultAnchor", _G[frame or "UIParent"])
248 f:Execute(
249 [[
250 defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
251 ]])
252 end
253
254 function RefreshState( bar )
255 SetDefaultAnchor(bar)
256 bar:GetFrame():Execute(
257 [[
258 if self:GetAttribute("reaction-refresh") then
259 control:RunAttribute("reaction-refresh")
260 end
261 ]])
262 end
263
264 function SetStateDriver( bar, rule )
265 local f = bar:GetFrame()
266
267 if not f.UpdateHiddenLabel then
268 function f:UpdateHiddenLabel(hide)
269 bar:SetLabelSubtext( hide and L["Hidden"] )
270 end
271 end
272
273 function f:StateRefresh( state )
274 bar:RefreshControls()
275 end
276
277 local props = { }
278 for p, h in pairs(properties) do
279 if type(h) == "string" then
280 table.insert(props,p)
281 f:SetAttribute("func-"..p, h)
282 end
283 end
284 f:SetAttribute("prop-func-list", table.concat(props," "))
285 f:Execute(stateHandler_propInit)
286 f:SetAttribute("reaction-refresh", onStateHandler)
287
288 if rule and #rule > 0 then
289 f:SetAttribute( "_onstate-reaction", onStateHandler )
290 RegisterStateDriver(f, "reaction", rule)
291 statedrivers[bar] = rule
292 elseif statedrivers[bar] then
293 UnregisterStateDriver(f, "reaction")
294 f:SetAttribute( "_onstate-reaction", nil )
295 statedrivers[bar] = nil
296 end
297 end
298
299 function SetStateKeybind( bar, key, state )
300 local f = bar:GetFrame()
301
302 local kb = keybinds[bar]
303 if kb == nil then
304 if key == nil then
305 -- nothing to do
306 return
307 end
308 kb = { }
309 keybinds[bar] = kb
310 end
311
312 -- clear the old binding, if any
313 if kb[state] then
314 SetOverrideBinding(f, false, kb[state], nil)
315 end
316 kb[state] = key
317
318 if key then
319 f:SetAttribute("_onclick", onClickHandler)
320 SetOverrideBindingClick(f, false, key, state, nil) -- state name is the virtual mouse button
321 end
322 end
323 end
324 78
325 local playerClass = select(2, UnitClass("player")) 79 local playerClass = select(2, UnitClass("player"))
326 local function ClassFilter(...) 80 local function ClassFilter(...)
327 for i = 1, select('#',...) do 81 for i = 1, select('#',...) do
328 if playerClass == select(i,...) then 82 if playerClass == select(i,...) then
343 battle = { format = "stance:1", filter = ClassFilter("WARRIOR") }, 97 battle = { format = "stance:1", filter = ClassFilter("WARRIOR") },
344 defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") }, 98 defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") },
345 berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") }, 99 berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") },
346 caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") }, 100 caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
347 bear = { format = "form:1", filter = ClassFilter("DRUID") }, 101 bear = { format = "form:1", filter = ClassFilter("DRUID") },
348 cat = { format = "form:1", filter = ClassFilter("DRUID") }, 102 cat = { format = "form:3", filter = ClassFilter("DRUID") },
349 tree = { format = "form:5", filter = ClassFilter("DRUID") }, 103 tree = { format = "form:5", filter = ClassFilter("DRUID") },
350 moonkin = { format = "form:5", filter = ClassFilter("DRUID") }, 104 moonkin = { format = "form:5", filter = ClassFilter("DRUID") },
351 pet = { format = "pet" }, 105 pet = { format = "pet" },
352 nopet = { format = "nopet" }, 106 nopet = { format = "nopet" },
353 harm = { format = "target=target,harm" }, 107 harm = { format = "target=target,harm" },
363 nocombat = { format = "nocombat" }, 117 nocombat = { format = "nocombat" },
364 possess = { format = "bonusbar:5" }, 118 possess = { format = "bonusbar:5" },
365 vehicle = { format = "target=vehicle,exists,bonusbar:5" }, 119 vehicle = { format = "target=vehicle,exists,bonusbar:5" },
366 } 120 }
367 121
368 -- Have to do these shenanigans instead of hardcoding the stances/forms because the 122 -- Determine the stance #'s programmatically: they can vary if for some reason the
369 -- ordering varies if the character is missing a form. For warriors this is rarely 123 -- player is missing a stance/form (due to not training it). Also moonkin/flight/tree form
370 -- a problem (c'mon, who actually skips the level 10 def stance quest?) but for druids 124 -- can be stance 5 or 6, depending.
371 -- it can be. Some people never bother to do the aquatic form quest until well past
372 -- when they get cat form, and stance 5/6 can be flight, tree, or moonkin depending
373 -- on talents.
374 function InitRules() 125 function InitRules()
375 local forms = { } 126 local forms = { }
376 -- sort by icon since it's locale-independent
377 for i = 1, GetNumShapeshiftForms() do 127 for i = 1, GetNumShapeshiftForms() do
378 local icon, name, active = GetShapeshiftFormInfo(i) 128 local _, name = GetShapeshiftFormInfo(i)
379 -- if it's the current form, the icon is wrong (Spell_Nature_WispSplode) 129 forms[name] = i;
380 -- so capture it from the spell info directly
381 if active then
382 local _1, _2
383 _1, _2, icon = GetSpellInfo(name)
384 end
385 forms[icon] = i;
386 end 130 end
387 -- use 9 if not found since 9 is never a valid stance/form 131 -- use 9 if not found since 9 is never a valid stance/form
388 local defensive = forms["Interface\\Icons\\Ability_Warrior_DefensiveStance"] or 9 132 local defensive = forms[GetSpellInfo(71)] or 9
389 local berserker = forms["Interface\\Icons\\Ability_Racial_Avatar"] or 9 133 local berserker = forms[GetSpellInfo(2458)] or 9
390 local bear = forms["Interface\\Icons\\Ability_Racial_BearForm"] or 9 -- bear and dire bear share the same icon 134 local bear = forms[GetSpellInfo(9634)] or forms[GetSpellInfo(5487)] or 9
391 local aquatic = forms["Interface\\Icons\\Ability_Druid_AquaticForm"] or 9 135 local aquatic = forms[GetSpellInfo(1066)] or 9
392 local cat = forms["Interface\\Icons\\Ability_Druid_CatForm"] or 9 136 local cat = forms[GetSpellInfo(768)] or 9
393 local travel = forms["Interface\\Icons\\Ability_Druid_TravelForm"] or 9 137 local travel = forms[GetSpellInfo(783)] or 9
394 local tree = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or 9 138 local tree = forms[GetSpellInfo(33891)] or 9
395 local moonkin = forms["Interface\\Icons\\Spell_Nature_ForceOfNature"] or 9 139 local moonkin = forms[GetSpellInfo(24858)] or 9
396 local flight = forms["Interface\\Icons\\Ability_Druid_FlightForm"] or 9 -- flight and swift flight share the same icon 140 local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
397 141
398 ruleformats.defensive.format = format("stance:%d",defensive) 142 ruleformats.defensive.format = format("stance:%d",defensive)
399 ruleformats.berserker.format = format("stance:%d",berserker) 143 ruleformats.berserker.format = format("stance:%d",berserker)
400 ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight) 144 ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight)
401 ruleformats.bear.format = format("form:%d",bear) 145 ruleformats.bear.format = format("form:%d",bear)
443 local function BuildKeybinds( bar, states ) 187 local function BuildKeybinds( bar, states )
444 for name, state in pairs(states) do 188 for name, state in pairs(states) do
445 local type = tfetch(state, "rule", "type") 189 local type = tfetch(state, "rule", "type")
446 if type == "keybind" then 190 if type == "keybind" then
447 local key = tfetch(state, "rule", "keybind") 191 local key = tfetch(state, "rule", "keybind")
448 SetStateKeybind(bar, key, name) 192 bar:SetStateKeybind(key, name)
449 else 193 else
450 SetStateKeybind(bar, nil, name) -- this clears an existing keybind 194 bar:SetStateKeybind(nil, name) -- this clears an existing keybind
451 end 195 end
452 end 196 end
453 end 197 end
454 198
455 function GetProperty( bar, state, propname ) 199 function GetProperty( bar, state, propname )
457 end 201 end
458 202
459 function SetProperty( bar, state, propname, value ) 203 function SetProperty( bar, state, propname, value )
460 local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state) 204 local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state)
461 s[propname] = value 205 s[propname] = value
462 SetHandlerData(bar, propname, value, state) 206 bar:SetSecureStateData(state, propname, value)
463 RefreshState(bar)
464 end 207 end
465 208
466 function RegisterProperty( propname, snippet ) 209 function RegisterProperty( propname, snippet )
467 properties[propname] = snippet or true 210 properties[propname] = true
468 for _, bar in ReAction:IterateBars() do 211 for _, bar in ReAction:IterateBars() do
469 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") 212 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
470 if states then 213 if states then
471 for name, s in pairs(states) do 214 for name, s in pairs(states) do
472 SetHandlerData(bar, propname, s[propname], name) 215 bar:SetSecureStateData(name, propname, s[propname])
473 end 216 end
474 SetStateDriver(bar, BuildRule(states)) 217 bar:SetStateDriver(BuildRule(states))
475 RefreshState(bar) 218 end
219 if type(snippet) == "string" then
220 bar:SetSecureStateExtension(propname,snippet)
476 end 221 end
477 end 222 end
478 end 223 end
479 224
480 function UnregisterProperty( propname ) 225 function UnregisterProperty( propname )
481 properties[propname] = nil 226 properties[propname] = nil
482 for _, bar in ReAction:IterateBars() do 227 for _, bar in ReAction:IterateBars() do
483 SetHandlerData(bar, propname, nil) 228 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
484 SetStateDriver(bar, BuildRule(states)) 229 if states then
485 RefreshState(bar) 230 for name, s in pairs(states) do
231 bar:SetSecureStateData(name, propname, nil)
232 end
233 end
234 bar:SetStateDriver(BuildRule(states))
235 bar:SetSecureStateExtension(propname,nil)
486 end 236 end
487 end 237 end
488 238
489 function ApplyStates( bar ) 239 function ApplyStates( bar )
490 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") 240 local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
491 if states then 241 if states then
492 for propname in pairs(properties) do 242 for propname in pairs(properties) do
493 for name, s in pairs(states) do 243 for name, s in pairs(states) do
494 if propname == "anchorFrame" then 244 if propname == "anchorFrame" then
495 SetFrameRef(bar:GetFrame(), "anchor-"..name, _G[s.anchorFrame]) 245 bar:SetFrameRef("anchor-"..name, _G[s.anchorFrame])
496 else 246 else
497 SetHandlerData(bar, propname, s[propname], name) 247 bar:SetSecureStateData(name, propname, s[propname])
498 end 248 end
499 end 249 end
500 end 250 end
501 BuildKeybinds(bar, states) 251 BuildKeybinds(bar, states)
502 SetHandlerData(bar, "showAll", ReAction:GetConfigMode()) 252 bar:SetStateDriver(BuildRule(states))
503 SetStateDriver(bar, BuildRule(states))
504 RefreshState(bar)
505 end 253 end
506 end 254 end
507 255
508 function CleanupStates( bar ) 256 function CleanupStates( bar )
509 SetStateDriver(bar, nil) 257 bar:SetStateDriver(nil)
510 end
511
512 function ShowAll( bar, show )
513 if statedrivers[bar] then
514 SetHandlerData(bar, "showAll", show)
515 RefreshState(bar)
516 end
517 end 258 end
518 end 259 end
519 260
520 261
521 262
537 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar") 278 ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
538 ReAction.RegisterCallback(self, "OnDestroyBar") 279 ReAction.RegisterCallback(self, "OnDestroyBar")
539 ReAction.RegisterCallback(self, "OnRefreshBar") 280 ReAction.RegisterCallback(self, "OnRefreshBar")
540 ReAction.RegisterCallback(self, "OnEraseBar") 281 ReAction.RegisterCallback(self, "OnEraseBar")
541 ReAction.RegisterCallback(self, "OnRenameBar") 282 ReAction.RegisterCallback(self, "OnRenameBar")
542 ReAction.RegisterCallback(self, "OnConfigModeChanged")
543 end 283 end
544 284
545 function module:OnEnable() 285 function module:OnEnable()
546 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui 286 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui
547 end 287 end
549 function module:UPDATE_SHAPESHIFT_FORMS() 289 function module:UPDATE_SHAPESHIFT_FORMS()
550 -- Re-parse the rules table according to the new form list. 290 -- Re-parse the rules table according to the new form list.
551 -- This happens both at initial login (after PLAYER_ENTERING_WORLD) 291 -- This happens both at initial login (after PLAYER_ENTERING_WORLD)
552 -- as well as when gaining new abilities. 292 -- as well as when gaining new abilities.
553 InitRules() 293 InitRules()
554 for name, bar in ReAction:IterateBars() do 294 for _, bar in ReAction:IterateBars() do
555 self:OnRefreshBar(nil,bar,name) 295 ApplyStates(bar)
556 end 296 end
557 end 297 end
558 298
559 function module:OnRefreshBar(event, bar, name) 299 function module:OnRefreshBar(event, bar, name)
560 local c = self.db.profile.bars[name] 300 local c = self.db.profile.bars[name]
572 end 312 end
573 313
574 function module:OnRenameBar(event, bar, oldname, newname) 314 function module:OnRenameBar(event, bar, oldname, newname)
575 local bars = self.db.profile.bars 315 local bars = self.db.profile.bars
576 bars[newname], bars[oldname] = bars[oldname], nil 316 bars[newname], bars[oldname] = bars[oldname], nil
577 end
578
579 function module:OnConfigModeChanged(event, mode)
580 for name, bar in ReAction:IterateBars() do
581 if self.db.profile.bars[name] then
582 ShowAll(bar, mode)
583 end
584 end
585 end 317 end
586 318
587 319
588 320
589 -- Options -- 321 -- Options --
1121 end 853 end
1122 854
1123 function StateHandler:SetAnchorFrame(info, value) 855 function StateHandler:SetAnchorFrame(info, value)
1124 local f = _G[self._anchorframes[value]] 856 local f = _G[self._anchorframes[value]]
1125 if f then 857 if f then
1126 SetFrameRef(self.bar:GetFrame(), "anchor-"..self:GetName(), f) 858 bar:SetFrameRef("anchor-"..self:GetName(), f)
1127 self:SetProp(info, f:GetName()) 859 self:SetProp(info, f:GetName())
1128 end 860 end
1129 end 861 end
1130 862
1131 function StateHandler:SetAnchorPointProp(info, value) 863 function StateHandler:SetAnchorPointProp(info, value)
1339 end 1071 end
1340 1072
1341 1073
1342 -- Export methods to Bar class -- 1074 -- Export methods to Bar class --
1343 1075
1344 function ReAction.Bar:GetState()
1345 local env = GetManagedEnvironment(self:GetFrame())
1346 return env and env.state
1347 end
1348
1349 ReAction.Bar.GetStateProperty = GetProperty 1076 ReAction.Bar.GetStateProperty = GetProperty
1350 ReAction.Bar.SetStateProperty = SetProperty 1077 ReAction.Bar.SetStateProperty = SetProperty