Mercurial > wow > reaction
comparison Bar.lua @ 245:65f2805957a0
No real reason to store some of the code in a subdirectory.
author | Flick |
---|---|
date | Sat, 26 Mar 2011 12:35:08 -0700 |
parents | classes/Bar.lua@b56cff349bd6 |
children | 36a29870bf34 |
comparison
equal
deleted
inserted
replaced
244:f255cd69e890 | 245:65f2805957a0 |
---|---|
1 local addonName, addonTable = ... | |
2 local ReAction = addonTable.ReAction | |
3 local L = ReAction.L | |
4 local LKB = ReAction.LKB | |
5 local _G = _G | |
6 local CreateFrame = CreateFrame | |
7 local floor = math.floor | |
8 local fmod = math.fmod | |
9 local format = string.format | |
10 local tfetch = addonTable.tfetch | |
11 local tbuild = addonTable.tbuild | |
12 local fieldsort = addonTable.fieldsort | |
13 | |
14 local LSG = LibStub("ReAction-LibShowActionGrid-1.0") | |
15 | |
16 ---- Secure snippets ---- | |
17 local _reaction_init = | |
18 [[ | |
19 anchorKeys = newtable("point","relPoint","x","y") | |
20 | |
21 state = nil | |
22 set_state = nil | |
23 state_override = nil | |
24 unit_exists = nil | |
25 | |
26 showAll = false | |
27 hidden = false | |
28 | |
29 defaultAlpha = 1.0 | |
30 defaultScale = 1.0 | |
31 defaultAnchor = newtable() | |
32 | |
33 activeStates = newtable() | |
34 settings = newtable() | |
35 extensions = newtable() | |
36 ]] | |
37 | |
38 local _reaction_refresh = | |
39 [[ | |
40 local oldState = state | |
41 state = state_override or set_state or state | |
42 | |
43 local hide = nil | |
44 if state then | |
45 local settings = settings[state] | |
46 if settings then | |
47 -- show/hide | |
48 hide = settings.hide | |
49 -- re-anchor | |
50 local old_anchor = activeStates.anchor | |
51 activeStates.anchor = settings.anchorEnable and state | |
52 if old_anchor ~= activeStates.anchor or not set_state then | |
53 if activeStates.anchor then | |
54 if settings.anchorPoint then | |
55 self:ClearAllPoints() | |
56 local f = self:GetAttribute("frameref-anchor-"..state) | |
57 if f then | |
58 self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY) | |
59 end | |
60 end | |
61 elseif defaultAnchor.point then | |
62 self:ClearAllPoints() | |
63 self:SetPoint(defaultAnchor.point, defaultAnchor.frame, | |
64 defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y) | |
65 end | |
66 end | |
67 -- re-scale | |
68 local old_scale = activeStates.scale | |
69 activeStates.scale = settings.enableScale and state | |
70 if old_scale ~= activeStates.scale or not set_state then | |
71 self:SetScale(activeStates.scale and settings.scale or defaultScale) | |
72 end | |
73 -- alpha | |
74 local old_alpha = activeStates.alpha | |
75 activeStates.alpha = settings.enableAlpha and state | |
76 if old_alpha ~= activeStates.alpha or not set_state then | |
77 self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha) | |
78 end | |
79 end | |
80 end | |
81 | |
82 -- hide if state or unit_exists says to | |
83 hide = not showAll and (hide or unithide) | |
84 if hide ~= hidden then | |
85 hidden = hide | |
86 if hide then | |
87 self:Hide() | |
88 else | |
89 self:Show() | |
90 end | |
91 end | |
92 | |
93 for _, attr in pairs(extensions) do | |
94 control:RunAttribute(attr) | |
95 end | |
96 | |
97 control:ChildUpdate() | |
98 | |
99 if showAll then | |
100 control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide) | |
101 end | |
102 | |
103 if oldState ~= state then | |
104 control:CallMethod("StateRefresh", state) | |
105 end | |
106 ]] | |
107 | |
108 local _onstate_reaction = -- function( self, stateid, newstate ) | |
109 [[ | |
110 set_state = newstate | |
111 ]] .. _reaction_refresh | |
112 | |
113 local _onstate_showgrid = -- function( self, stateid, newstate ) | |
114 [[ | |
115 control:ChildUpdate(stateid,newstate) | |
116 control:CallMethod("UpdateShowGrid") | |
117 ]] | |
118 | |
119 local _onstate_unitexists = -- function( self, stateid, newstate ) | |
120 [[ | |
121 unithide = not newstate or newstate == "hide" | |
122 ]] .. _reaction_refresh | |
123 | |
124 local _onclick = -- function( self, button, down ) | |
125 [[ | |
126 if state_override == button then | |
127 state_override = nil -- toggle | |
128 else | |
129 state_override = button | |
130 end | |
131 ]] .. _reaction_refresh | |
132 | |
133 -- For reference | |
134 -- the option field names must match the field names of the options table, below | |
135 local stateProperties = { | |
136 hide = true, | |
137 --keybindState = true, TODO: broken | |
138 anchorEnable = true, | |
139 anchorFrame = true, | |
140 anchorPoint = true, | |
141 anchorRelPoint = true, | |
142 anchorX = true, | |
143 anchorY = true, | |
144 enableScale = true, | |
145 scale = true, | |
146 enableAlpha = true, | |
147 alpha = true, | |
148 } | |
149 | |
150 | |
151 | |
152 ---- Bar class ---- | |
153 local Bar = { } | |
154 local frameList = { } | |
155 | |
156 ReAction.Bar = Bar -- export to ReAction | |
157 | |
158 function Bar:New( name, config, buttonClass ) | |
159 if type(config) ~= "table" then | |
160 error("ReAction.Bar: config table required") | |
161 end | |
162 | |
163 -- create new self | |
164 self = setmetatable( | |
165 { | |
166 config = config, | |
167 name = name, | |
168 buttons = { }, | |
169 buttonClass = buttonClass, | |
170 width = config.width or 480, | |
171 height = config.height or 40, | |
172 }, | |
173 {__index = self} ) | |
174 | |
175 -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is | |
176 -- not mouse-clickable by the user. | |
177 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent | |
178 name = name and "ReAction-"..name | |
179 local f = name and frameList[name] | |
180 if not f then | |
181 f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate") | |
182 if name then | |
183 frameList[name] = f | |
184 end | |
185 end | |
186 f:SetFrameStrata("MEDIUM") | |
187 f:SetWidth(self.width) | |
188 f:SetHeight(self.height) | |
189 f:SetAlpha(config.alpha or 1.0) | |
190 f:Show() | |
191 f:EnableMouse(false) | |
192 f:SetClampedToScreen(true) | |
193 LSG:AddFrame(f) | |
194 | |
195 -- secure handlers | |
196 f:Execute(_reaction_init) | |
197 f:SetAttribute("_onstate-reaction", _onstate_reaction) | |
198 f:SetAttribute("_onstate-showgrid", _onstate_showgrid) | |
199 f:SetAttribute("_onstate-unitexists", _onstate_unitexists) | |
200 f:SetAttribute("_onclick", _onclick) | |
201 | |
202 -- secure handler CallMethod()s | |
203 f.UpdateShowGrid = function() self:UpdateShowGrid() end | |
204 f.StateRefresh = function() self:RefreshControls() end | |
205 f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end | |
206 | |
207 -- Override the default frame accessor to provide strict read-only access | |
208 function self:GetFrame() | |
209 return f | |
210 end | |
211 | |
212 self:ApplyAnchor() | |
213 self:SetConfigMode(ReAction:GetConfigMode()) | |
214 self:SetKeybindMode(ReAction:GetKeybindMode()) | |
215 | |
216 if ReAction.LBF then | |
217 local g = ReAction.LBF:Group(L["ReAction"], self.name) | |
218 self.config.ButtonFacade = self.config.ButtonFacade or { | |
219 skinID = "Blizzard", | |
220 backdrop = true, | |
221 gloss = 0, | |
222 colors = {}, | |
223 } | |
224 local c = self.config.ButtonFacade | |
225 g:Skin(c.skinID, c.gloss, c.backdrop, c.colors) | |
226 self.LBFGroup = g | |
227 end | |
228 | |
229 ReAction.RegisterCallback(self, "OnConfigModeChanged") | |
230 | |
231 buttonClass:SetupBar(self) | |
232 self:ApplyStates() | |
233 | |
234 return self | |
235 end | |
236 | |
237 function Bar:Destroy() | |
238 local f = self:GetFrame() | |
239 self:CleanupStates() | |
240 for idx, b in self:IterateButtons() do | |
241 b:Destroy() | |
242 end | |
243 f:UnregisterAllEvents() | |
244 self:ShowControls(false) | |
245 ReAction.UnregisterAllCallbacks(self) | |
246 LKB.UnregisterAllCallbacks(self) | |
247 if self.LBFGroup then | |
248 self.LBFGroup:Delete(true) | |
249 end | |
250 LSG:RemoveFrame(f) | |
251 f:SetParent(UIParent) | |
252 f:ClearAllPoints() | |
253 f:Hide() | |
254 end | |
255 | |
256 -- | |
257 -- Events | |
258 -- | |
259 | |
260 function Bar:OnConfigModeChanged(event, mode) | |
261 self:SetConfigMode(mode) | |
262 end | |
263 | |
264 -- | |
265 -- Accessors | |
266 -- | |
267 | |
268 function Bar:GetName() | |
269 return self.name | |
270 end | |
271 | |
272 -- only ReAction:RenameBar() should call this function. Calling from any other | |
273 -- context will desync the bar list in the ReAction class. | |
274 function Bar:SetName(name) | |
275 if self.LBFGroup then | |
276 -- LBF doesn't offer a method of renaming a group, so delete and remake the group. | |
277 local c = self.config.ButtonFacade | |
278 local g = ReAction.LBF:Group(L["ReAction"], name) | |
279 for idx, b in self:IterateButtons() do | |
280 self.LBFGroup:RemoveButton(b:GetFrame(), true) | |
281 g:AddButton(b:GetFrame()) | |
282 end | |
283 self.LBFGroup:Delete(true) | |
284 self.LBFGroup = g | |
285 self.LBFGroup:Skin(c.skinID, c.gloss, c.backdrop, c.colors) | |
286 end | |
287 self.name = name | |
288 if self.overlay then | |
289 self.overlay:SetLabel(self.name) | |
290 end | |
291 end | |
292 | |
293 function Bar:GetFrame() | |
294 -- this method is included for documentation purposes. It is overridden | |
295 -- for each object in the :New() method. | |
296 error("Invalid Bar object: used without initialization") | |
297 end | |
298 | |
299 function Bar:GetButton(idx) | |
300 return self.buttons[idx] | |
301 end | |
302 | |
303 function Bar:GetButtonClass() | |
304 return self.buttonClass | |
305 end | |
306 | |
307 function Bar:GetConfig() | |
308 return self.config | |
309 end | |
310 | |
311 function Bar:GetAnchor() | |
312 local c = self.config | |
313 return (c.point or "CENTER"), | |
314 (c.anchor or self:GetFrame():GetParent():GetName()), | |
315 (c.relpoint or c.point or "CENTER"), | |
316 (c.x or 0), | |
317 (c.y or 0) | |
318 end | |
319 | |
320 function Bar:SetAnchor(point, frame, relativePoint, x, y) | |
321 local c = self.config | |
322 c.point = point or c.point | |
323 c.anchor = frame or c.anchor | |
324 c.relpoint = relativePoint or c.relpoint | |
325 c.x = x or c.x | |
326 c.y = y or c.y | |
327 self:ApplyAnchor() | |
328 end | |
329 | |
330 function Bar:GetSize() | |
331 local f = self:GetFrame() | |
332 return f:GetWidth(), f:GetHeight() | |
333 end | |
334 | |
335 function Bar:SetSize(w,h) | |
336 local f = self:GetFrame() | |
337 self.config.width = w | |
338 self.config.height = h | |
339 f:SetWidth(w) | |
340 f:SetHeight(h) | |
341 end | |
342 | |
343 function Bar:GetButtonSize() | |
344 local w = self.config.btnWidth or 32 | |
345 local h = self.config.btnHeight or 32 | |
346 -- TODO: get from modules? | |
347 return w,h | |
348 end | |
349 | |
350 function Bar:SetButtonSize(w,h) | |
351 if w > 0 and h > 0 then | |
352 self.config.btnWidth = w | |
353 self.config.btnHeight = h | |
354 end | |
355 end | |
356 | |
357 function Bar:GetNumButtons() | |
358 local r,c = self:GetButtonGrid() | |
359 return r*c | |
360 end | |
361 | |
362 function Bar:GetButtonGrid() | |
363 local cfg = self.config | |
364 local r = cfg.btnRows or 1 | |
365 local c = cfg.btnColumns or 1 | |
366 local s = cfg.spacing or 4 | |
367 return r,c,s | |
368 end | |
369 | |
370 function Bar:SetButtonGrid(r,c,s) | |
371 if r > 0 and c > 0 and s > 0 then | |
372 local cfg = self.config | |
373 cfg.btnRows = r | |
374 cfg.btnColumns = c | |
375 cfg.spacing = s | |
376 end | |
377 self.buttonClass:SetupBar(self) | |
378 end | |
379 | |
380 function Bar:GetAlpha() | |
381 return self.config.alpha or 1.0 | |
382 end | |
383 | |
384 function Bar:SetAlpha(value) | |
385 self.config.alpha = value | |
386 self:GetFrame():SetAlpha(value or 1.0) | |
387 self:UpdateDefaultStateAlpha() | |
388 end | |
389 | |
390 function Bar:IterateButtons() | |
391 -- iterator returns idx, button, but does NOT iterate in index order | |
392 return pairs(self.buttons) | |
393 end | |
394 | |
395 -- | |
396 -- Methods | |
397 -- | |
398 | |
399 function Bar:SetConfigMode(mode) | |
400 self:SetSecureData("showAll",mode) | |
401 self:ShowControls(mode) | |
402 for idx, b in self:IterateButtons() do | |
403 b:ShowGridTemp(mode) | |
404 b:UpdateActionIDLabel(mode) | |
405 end | |
406 end | |
407 | |
408 function Bar:SetKeybindMode(mode) | |
409 self:SetSecureData("showAll",mode) | |
410 for idx, b in self:IterateButtons() do | |
411 b:SetKeybindMode(mode) | |
412 end | |
413 end | |
414 | |
415 function Bar:ApplyAnchor() | |
416 local f = self:GetFrame() | |
417 local c = self.config | |
418 local p = c.point | |
419 | |
420 f:SetWidth(c.width) | |
421 f:SetHeight(c.height) | |
422 f:ClearAllPoints() | |
423 | |
424 if p then | |
425 local a = f:GetParent() | |
426 if c.anchor then | |
427 local bar = ReAction:GetBar(c.anchor) | |
428 if bar then | |
429 a = bar:GetFrame() | |
430 else | |
431 a = _G[c.anchor] | |
432 end | |
433 end | |
434 local fr = a or f:GetParent() | |
435 f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0) | |
436 else | |
437 f:SetPoint("CENTER") | |
438 end | |
439 | |
440 self:UpdateDefaultStateAnchor() | |
441 end | |
442 | |
443 function Bar:ClipNButtons( n ) | |
444 local cfg = self.config | |
445 local r = cfg.btnRows or 1 | |
446 local c = cfg.btnColumns or 1 | |
447 | |
448 cfg.btnRows = ceil(n/c) | |
449 cfg.btnColumns = min(n,c) | |
450 end | |
451 | |
452 function Bar:AddButton(idx, button) | |
453 local f = self:GetFrame() | |
454 | |
455 self.buttons[idx] = button | |
456 | |
457 -- Store a properly wrapped reference to the child frame as an attribute | |
458 -- (accessible via "frameref-btn#") | |
459 f:SetFrameRef(format("btn%d",idx), button:GetFrame()) | |
460 | |
461 -- button constructors are responsible for calling SkinButton | |
462 end | |
463 | |
464 function Bar:RemoveButton(button) | |
465 local idx = button:GetIndex() | |
466 if idx then | |
467 self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil) | |
468 self.buttons[idx] = nil | |
469 end | |
470 if self.LBFGroup then | |
471 self.LBFGroup:RemoveButton(button:GetFrame(),true) | |
472 end | |
473 end | |
474 | |
475 function Bar:PlaceButton(button, baseW, baseH) | |
476 local idx = button:GetIndex() | |
477 if idx then | |
478 local r, c, s = self:GetButtonGrid() | |
479 local bh, bw = self:GetButtonSize() | |
480 local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based | |
481 local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s) | |
482 local scale = bw/baseW | |
483 local b = button:GetFrame() | |
484 | |
485 b:ClearAllPoints() | |
486 b:SetPoint("TOPLEFT",x/scale,y/scale) | |
487 b:SetScale(scale) | |
488 end | |
489 end | |
490 | |
491 function Bar:SkinButton( button, data ) | |
492 if self.LBFGroup then | |
493 self.LBFGroup:AddButton(button:GetFrame(), data) | |
494 end | |
495 end | |
496 | |
497 function Bar:UpdateShowGrid() | |
498 for idx, button in self:IterateButtons() do | |
499 button:UpdateShowGrid() | |
500 end | |
501 end | |
502 | |
503 function Bar:ShowControls(show) | |
504 if show then | |
505 if not self.overlay then | |
506 self.overlay = Bar.Overlay:New(self) -- see Overlay.lua | |
507 end | |
508 self.overlay:Show() | |
509 self:RefreshSecureState() | |
510 elseif self.overlay then | |
511 self.overlay:Hide() | |
512 end | |
513 end | |
514 | |
515 function Bar:RefreshControls() | |
516 if self.overlay and self.overlay:IsShown() then | |
517 self.overlay:RefreshControls() | |
518 end | |
519 end | |
520 | |
521 function Bar:SetLabelSubtext(text) | |
522 if self.overlay then | |
523 self.overlay:SetLabelSubtext(text) | |
524 end | |
525 end | |
526 | |
527 -- | |
528 -- Secure state functions | |
529 -- | |
530 | |
531 function Bar:GetSecureState() | |
532 local env = GetManagedEnvironment(self:GetFrame()) | |
533 return env and env.state | |
534 end | |
535 | |
536 function Bar:GetStateProperty(state, propname) | |
537 return tfetch(self:GetConfig(), "states", state, propname) | |
538 end | |
539 | |
540 function Bar:SetStateProperty(state, propname, value) | |
541 local s = tbuild(self:GetConfig(), "states", state) | |
542 s[propname] = value | |
543 self:SetSecureStateData(state, propname, value) | |
544 end | |
545 | |
546 function Bar:ApplyStates() | |
547 local states = tfetch(self:GetConfig(), "states") | |
548 if states then | |
549 self:SetStateDriver(states) | |
550 end | |
551 end | |
552 | |
553 function Bar:CleanupStates() | |
554 self:SetStateDriver(nil) | |
555 end | |
556 | |
557 function Bar:RefreshSecureState() | |
558 self:GetFrame():Execute(_reaction_refresh) | |
559 end | |
560 | |
561 -- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value) | |
562 function Bar:SetSecureData( ... ) | |
563 local n = select('#',...) | |
564 if n < 2 then | |
565 error("ReAction.Bar:SetSecureData() requires at least 2 arguments") | |
566 end | |
567 local f = self:GetFrame() | |
568 f:SetAttribute("data-depth",n-1) | |
569 f:SetAttribute("data-value",select(n,...)) | |
570 for i = 1, n-1 do | |
571 local key = select(i,...) | |
572 if key == nil then | |
573 error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")") | |
574 end | |
575 f:SetAttribute("data-key-"..i, key) | |
576 end | |
577 f:Execute( | |
578 [[ | |
579 local n = self:GetAttribute("data-depth") | |
580 if n > 0 then | |
581 local value = self:GetAttribute("data-value") | |
582 local t = _G | |
583 for i = 1, n do | |
584 local key = self:GetAttribute("data-key-"..i) | |
585 if not key then return end | |
586 if not t[key] then | |
587 t[key] = newtable() | |
588 end | |
589 if i == n then | |
590 t[key] = value | |
591 else | |
592 t = t[key] | |
593 end | |
594 end | |
595 end | |
596 ]]) | |
597 self:RefreshSecureState() | |
598 end | |
599 | |
600 function Bar:SetSecureStateData( state, key, value ) | |
601 self:SetSecureData("settings",state,key,value) | |
602 end | |
603 | |
604 -- sets a snippet to be run as an extension to _onstate-reaction | |
605 function Bar:SetSecureStateExtension( id, snippet ) | |
606 if id == nil then | |
607 error("ReAction.Bar:SetSecureStateExtension() requires an id") | |
608 end | |
609 local f = self:GetFrame() | |
610 f:SetAttribute("input-secure-ext-id",id) | |
611 f:SetAttribute("secure-ext-"..id,snippet) | |
612 f:Execute( | |
613 [[ | |
614 local id = self:GetAttribute("input-secure-ext-id") | |
615 if id then | |
616 extensions[id] = self:GetAttribute("secure-ext-"..id) or nil | |
617 end | |
618 ]]) | |
619 self:RefreshSecureState() | |
620 end | |
621 | |
622 function Bar:SetFrameRef( name, refFrame ) | |
623 if refFrame then | |
624 local _, explicit = refFrame:IsProtected() | |
625 if not explicit then | |
626 refFrame = nil | |
627 end | |
628 end | |
629 if refFrame then | |
630 self:GetFrame():SetFrameRef(name,refFrame) | |
631 else | |
632 self:GetFrame():SetAttribute("frameref-"..name,nil) | |
633 end | |
634 end | |
635 | |
636 function Bar:SetStateDriver( states ) | |
637 if states then | |
638 for state, props in pairs(states) do | |
639 self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state | |
640 for propname, value in pairs(props) do | |
641 if propname == "anchorFrame" then | |
642 self:SetFrameRef("anchor-"..state, _G[value]) | |
643 elseif propname == "rule" then | |
644 -- do nothing | |
645 else | |
646 self:SetSecureStateData(state, propname, value) | |
647 end | |
648 end | |
649 end | |
650 end | |
651 local rule = states and self:BuildStateRule(states) | |
652 if rule then | |
653 RegisterStateDriver(self:GetFrame(),"reaction",rule) | |
654 elseif self.statedriver then | |
655 UnregisterStateDriver(self:GetFrame(),"reaction") | |
656 end | |
657 self.statedriver = rule | |
658 self:BuildStateKeybinds(states) | |
659 self:RefreshSecureState() | |
660 end | |
661 | |
662 -- pass unit=nil to set up the unit elsewhere, if you want something more complex | |
663 function Bar:RegisterUnitWatch( unit, enable ) | |
664 local f = self:GetFrame() | |
665 if unit then | |
666 f:SetAttribute("unit",unit) | |
667 end | |
668 if enable then | |
669 if not self.unitwatch then | |
670 RegisterUnitWatch(self:GetFrame(),true) | |
671 end | |
672 elseif self.unitwatch then | |
673 UnregisterUnitWatch(self:GetFrame()) | |
674 end | |
675 self.unitwatch = enable | |
676 self:RefreshSecureState() | |
677 end | |
678 | |
679 function Bar:SetStateKeybind( key, state ) | |
680 local f = self:GetFrame() | |
681 local binds = self.statebinds | |
682 if not binds then | |
683 binds = { } | |
684 self.statebinds = binds | |
685 end | |
686 | |
687 -- clear the old binding, if any | |
688 if binds[state] then | |
689 SetOverrideBinding(f, false, binds[state], nil) | |
690 end | |
691 | |
692 if key then | |
693 SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button | |
694 end | |
695 binds[state] = key | |
696 end | |
697 | |
698 function Bar:GetStateKeybind( state ) | |
699 if self.statebinds and state then | |
700 return self.statebinds[state] | |
701 end | |
702 end | |
703 | |
704 function Bar:UpdateDefaultStateAnchor() | |
705 local point, frame, relPoint, x, y = self:GetAnchor() | |
706 local f = self:GetFrame() | |
707 f:SetAttribute("defaultAnchor-point",point) | |
708 f:SetAttribute("defaultAnchor-relPoint",relPoint) | |
709 f:SetAttribute("defaultAnchor-x",x) | |
710 f:SetAttribute("defaultAnchor-y",y) | |
711 self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"]) | |
712 f:Execute([[ | |
713 for _, k in pairs(anchorKeys) do | |
714 defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k) | |
715 end | |
716 defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor") | |
717 ]]) | |
718 end | |
719 | |
720 function Bar:UpdateDefaultStateAlpha() | |
721 local f = self:GetFrame() | |
722 f:SetAttribute("defaultAlpha",self:GetAlpha()) | |
723 f:Execute([[ | |
724 defaultAlpha = self:GetAttribute("defaultAlpha") | |
725 ]]) | |
726 end | |
727 | |
728 ---- secure state driver rules ---- | |
729 | |
730 local playerClass = select(2, UnitClass("player")) | |
731 local function ClassFilter(...) | |
732 for i = 1, select('#',...) do | |
733 if playerClass == select(i,...) then | |
734 return false | |
735 end | |
736 end | |
737 return true | |
738 end | |
739 | |
740 local ruleformats = { | |
741 stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") }, | |
742 nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") }, | |
743 shadowdance = { format = "bonusbar:2", filter = ClassFilter("ROGUE") }, | |
744 shadowform = { format = "form:1", filter = ClassFilter("PRIEST") }, | |
745 noshadowform = { format = "noform", filter = ClassFilter("PRIEST") }, | |
746 battle = { format = "stance:1", filter = ClassFilter("WARRIOR") }, | |
747 defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") }, | |
748 berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") }, | |
749 caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") }, | |
750 bear = { format = "form:1", filter = ClassFilter("DRUID") }, | |
751 cat = { format = "form:3", filter = ClassFilter("DRUID") }, | |
752 tree = { format = "form:5", filter = ClassFilter("DRUID") }, | |
753 moonkin = { format = "form:5", filter = ClassFilter("DRUID") }, | |
754 demon = { format = "form:2", filter = ClassFilter("WARLOCK") }, | |
755 nodemon = { format = "noform", filter = ClassFilter("WARLOCK") }, | |
756 pet = { format = "pet" }, | |
757 nopet = { format = "nopet" }, | |
758 harm = { format = "@target,harm" }, | |
759 help = { format = "@target,help" }, | |
760 notarget = { format = "@target,noexists" }, | |
761 focusharm = { format = "@focus,harm" }, | |
762 focushelp = { format = "@focus,help" }, | |
763 nofocus = { format = "@focus,noexists" }, | |
764 raid = { format = "group:raid" }, | |
765 party = { format = "group:party" }, | |
766 solo = { format = "nogroup" }, | |
767 combat = { format = "combat" }, | |
768 nocombat = { format = "nocombat" }, | |
769 possess = { format = "@vehicle,noexists,bonusbar:5" }, | |
770 vehicle = { format = "@vehicle,exists,bonusbar:5" }, | |
771 } | |
772 | |
773 function Bar.InitRuleFormats() | |
774 local forms = { } | |
775 for i = 1, GetNumShapeshiftForms() do | |
776 local _, name = GetShapeshiftFormInfo(i) | |
777 forms[name] = i; | |
778 end | |
779 -- use 9 if not found since 9 is never a valid stance/form | |
780 local defensive = forms[GetSpellInfo(71)] or 9 | |
781 local berserker = forms[GetSpellInfo(2458)] or 9 | |
782 local bear = forms[GetSpellInfo(5487)] or 9 | |
783 local aquatic = forms[GetSpellInfo(1066)] or 9 | |
784 local cat = forms[GetSpellInfo(768)] or 9 | |
785 local travel = forms[GetSpellInfo(783)] or 9 | |
786 local tree = forms[GetSpellInfo(33891)] or 9 | |
787 local moonkin = forms[GetSpellInfo(24858)] or 9 | |
788 local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9 | |
789 | |
790 ruleformats.defensive.format = "stance:"..defensive | |
791 ruleformats.berserker.format = "stance:"..berserker | |
792 ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight) | |
793 ruleformats.bear.format = "form:"..bear | |
794 ruleformats.cat.format = "form:"..cat | |
795 ruleformats.tree.format = "form:"..tree | |
796 ruleformats.moonkin.format = "form:"..moonkin | |
797 end | |
798 | |
799 function Bar:BuildStateRule(states) | |
800 -- states is a table : | |
801 -- states[statename].rule = { | |
802 -- order = #, | |
803 -- type = "default"/"custom"/"any"/"all", | |
804 -- values = { ... }, -- keys of ruleformats[] | |
805 -- custom = "...", | |
806 -- } | |
807 local rules = { } | |
808 local default | |
809 | |
810 for idx, state in ipairs(fieldsort(states, "rule", "order")) do | |
811 local c = states[state].rule | |
812 local type = c.type | |
813 if type == "default" then | |
814 default = default or state | |
815 elseif type == "custom" then | |
816 if c.custom then | |
817 -- strip out all spaces from the custom rule | |
818 table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state)) | |
819 end | |
820 elseif type == "any" or type == "all" then | |
821 if c.values then | |
822 local clauses = { } | |
823 for key, value in pairs(c.values) do | |
824 if ruleformats[key] and not ruleformats[key].filter then | |
825 table.insert(clauses, ruleformats[key].format) | |
826 end | |
827 end | |
828 if #clauses > 0 then | |
829 local sep = (type == "any") and "][" or "," | |
830 table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state)) | |
831 end | |
832 end | |
833 end | |
834 end | |
835 -- make sure that the default, if any, is last | |
836 if default then | |
837 table.insert(rules, default) | |
838 end | |
839 return table.concat(rules,";") | |
840 end | |
841 | |
842 function Bar:BuildStateKeybinds( states ) | |
843 if states then | |
844 for name, state in pairs(states) do | |
845 local rule = tfetch(state, "rule") | |
846 if rule and rule.type == "keybind" then | |
847 self:SetStateKeybind(rule.keybind, name) | |
848 else | |
849 self:SetStateKeybind(nil, name) -- this clears an existing keybind | |
850 end | |
851 end | |
852 end | |
853 end | |
854 |