Mercurial > wow > reaction
comparison classes/MultiCastButton.lua @ 161:d0a41fc7b0d7
Totem bar support
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Fri, 21 Aug 2009 04:15:09 +0000 |
parents | |
children | fc08372f0c7a |
comparison
equal
deleted
inserted
replaced
160:caec78119a17 | 161:d0a41fc7b0d7 |
---|---|
1 local ReAction = ReAction | |
2 local L = ReAction.L | |
3 local _G = _G | |
4 local CreateFrame = CreateFrame | |
5 local format = string.format | |
6 local unpack = unpack | |
7 local GetCVar = GetCVar | |
8 local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor | |
9 local CooldownFrame_SetTimer = CooldownFrame_SetTimer | |
10 local InCombatLockdown = InCombatLockdown | |
11 local IsUsableSpell = IsUsableSpell | |
12 local IsUsableAction = IsUsableAction | |
13 local IsSpellKnown = IsSpellKnown | |
14 local IsSpellInRange = IsSpellInRange | |
15 local IsActionInRange = IsActionInRange | |
16 local GetSpellInfo = GetSpellInfo | |
17 local GetSpellCooldown = GetSpellCooldown | |
18 local GetActionCooldown = GetActionCooldown | |
19 local GetSpellTexture = GetSpellTexture | |
20 local GetActionTexture = GetActionTexture | |
21 local GetMultiCastTotemSpells = GetMultiCastTotemSpells | |
22 | |
23 ReAction:UpdateRevision("$Revision: 154 $") | |
24 | |
25 | |
26 --[[ | |
27 Blizzard Constants: | |
28 - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4 | |
29 - NUM_MULTI_CAST_PAGES = 3 | |
30 - TOTEM_PRIORITIES = { } -- sets the order of the totems | |
31 - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs | |
32 - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs | |
33 | |
34 Blizzard Events: | |
35 - UPDATE_MULTI_CAST_ACTIONBAR | |
36 | |
37 Blizzard APIs: | |
38 - GetMultiCastBarOffset() : returns 6 | |
39 | |
40 - SetMultiCastSpell(actionID, spellID) (protected) OR | |
41 SetAttribute("type","multispell") | |
42 SetAttribute("action",actionID) | |
43 SetAttribute("spell",spellID) | |
44 | |
45 note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(), | |
46 so that's action ID 132-144. | |
47 | |
48 - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot) | |
49 returns spellIDs for all totems that fit that slot. | |
50 Note this is available in the secure environment, but because IsSpellKnown() is not, | |
51 it makes it pretty much useless. | |
52 | |
53 Blizzard textures: | |
54 All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single | |
55 texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose | |
56 this is to slightly optimize texture load performance, but it makes the UI code more clumsy. | |
57 | |
58 Each totem button and arrow has a colored border indicating its elemental type. | |
59 TODO: update code to use these pretty per-slot icons, or start setting a border. | |
60 | |
61 Design Notes: | |
62 - Only the header has a secure context. All other frames execute in its context. | |
63 | |
64 - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are | |
65 GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by | |
66 the summon flyout, which is also paged with the summon spells (the recall button is not paged) | |
67 | |
68 - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new | |
69 spells) with the list of spells known for each slot. | |
70 | |
71 - Each button (except recall) has an arrow button which appears on mouseover and when clicked | |
72 opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not | |
73 appear. | |
74 TODO: add an alt-button ("SHOWMULTICASTFLYOUT") statemachine to the bar to listen for alt key | |
75 presses and open/close the bar. Tapping the alt key toggles the flyout. | |
76 | |
77 - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child | |
78 of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding | |
79 spell/type from the list, according to the slot which opened the flyout. Each button either sets | |
80 the current page (summon) or sets a multispell to an actionID via type="multispell". None of them | |
81 actually cast any spells (though, I suppose we could modify this so that e.g. configurable | |
82 right-click casts the spell). The flyout also has a close button which closes the flyout: the | |
83 flyout-open code positions the close button anchored to the last button in the flyout (which | |
84 changes dynamically because each slot has a different number of items in the list). | |
85 | |
86 - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of | |
87 the summon spells is cast from elsewhere. Additionally, in the default UI Call of the Elements | |
88 always appears as the active summon when the UI is loaded, which is bad design that could be improved | |
89 upon. TODO: Store state in a config variable and restore it at load time. | |
90 | |
91 | |
92 ]]-- | |
93 | |
94 | |
95 -- | |
96 -- Secure snippets | |
97 -- | |
98 | |
99 -- bar | |
100 local _bar_init = -- function(self) | |
101 [[ | |
102 -- set up some globals in the secure environment | |
103 flyout = self:GetFrameRef("flyout") | |
104 flyoutChildren = newtable() | |
105 nMultiCastSlots = self:GetAttribute("nMultiCastSlots") | |
106 baseActionID = self:GetAttribute("baseActionID") | |
107 currentMultiCastPage = currentMultiCastPage or 1 | |
108 multiCastSpellList = newtable() | |
109 for i = 1, nMultiCastSlots do | |
110 tinsert(multiCastSpellList, newtable()) | |
111 end | |
112 ]] | |
113 | |
114 local _onstate_multispellpage = -- function(self, stateid, newstate) | |
115 [[ | |
116 currentMultiCastPage = tonumber(newstate) | |
117 control:ChildUpdate() | |
118 ]] | |
119 | |
120 | |
121 -- buttons | |
122 local _childupdate = -- function(self, snippetid, message) | |
123 [[ | |
124 if self:GetAttribute("type") == "spell" then | |
125 self:SetAttribute("spell", self:GetAttribute("spell-page"..currentMultiCastPage)) | |
126 elseif self:GetAttribute("type") == "action" then | |
127 self:SetAttribute("action", self:GetAttribute("action-page"..currentMultiCastPage)) | |
128 end | |
129 ]] | |
130 | |
131 local _onEnter = -- function(self) | |
132 -- for whatever reason, RegisterAutoHide is unreliable | |
133 -- unless you re-anchor the frame prior to calling it. | |
134 -- Even then, it's still not terribly reliable. | |
135 [[ | |
136 local idx = self:GetAttribute("bar-idx") | |
137 if not (flyout:IsVisible() and flyoutIdx == idx) then | |
138 local arrow = owner:GetFrameRef("arrow-"..idx) | |
139 if arrow and not arrow:IsShown() then | |
140 arrow:ClearAllPoints() | |
141 arrow:SetPoint("BOTTOM",self,"TOP",0,0) -- TODO: better anchoring | |
142 arrow:Show() | |
143 arrow:RegisterAutoHide(0) | |
144 arrow:AddToAutoHide(self) | |
145 end | |
146 end | |
147 ]] | |
148 | |
149 local _onLeave = -- function(self) | |
150 -- to increase reliability (somewhat), re-register it for hide on leave | |
151 [[ | |
152 local arrow = owner:GetFrameRef("arrow-"..self:GetAttribute("bar-idx")) | |
153 if arrow then | |
154 arrow:RegisterAutoHide(0) | |
155 arrow:AddToAutoHide(self) | |
156 end | |
157 ]] | |
158 | |
159 | |
160 -- flyout arrow | |
161 local _arrow_openFlyout = -- function(self) | |
162 [[ | |
163 local currentMultiCastSlot = self:GetAttribute("bar-idx") | |
164 local lastButton, lastIdx | |
165 for idx, b in ipairs(flyoutChildren) do | |
166 b:Hide() -- force the OnShow handler to run later | |
167 local spellID = multiCastSpellList[currentMultiCastSlot][idx] | |
168 if spellID then | |
169 b:SetAttribute("spell",spellID) -- does passing 0 work for no-totem? Do we have to convert to nil? | |
170 if currentMultiCastSlot == 1 then | |
171 b:SetAttribute("type","changePage") | |
172 else | |
173 b:SetAttribute("type","multispell") | |
174 local totemID = owner:GetAttribute("TOTEM_PRIORITY_"..(currentMultiCastSlot - 1)) | |
175 b:SetAttribute("action", baseActionID + (currentMultiCastPage - 1)*(nMultiCastSlots-2) + totemID) | |
176 end | |
177 b:Show() | |
178 lastButton = b | |
179 lastIdx = idx | |
180 end | |
181 end | |
182 | |
183 local close = owner:GetFrameRef("close") | |
184 if lastButton and close then | |
185 close:ClearAllPoints() | |
186 close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring | |
187 close:Show() | |
188 end | |
189 | |
190 flyout:ClearAllPoints() | |
191 flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring | |
192 if lastIdx then | |
193 flyout:SetHeight(lastIdx * 27 + (close and close:GetHeight() or 0)) | |
194 end | |
195 flyout:Show() | |
196 flyout:RegisterAutoHide(1) -- TODO: configurable | |
197 flyout:AddToAutoHide(owner) | |
198 flyoutIdx = currentMultiCastSlot | |
199 self:Hide() | |
200 ]] | |
201 | |
202 local _closeFlyout = -- function(self) | |
203 [[ | |
204 flyout:Hide() | |
205 ]] | |
206 | |
207 | |
208 -- flyout child buttons | |
209 local _flyout_child_preClick = -- function(self, button, down) | |
210 [[ | |
211 local button = button | |
212 if self:GetAttribute("type") == "changePage" then | |
213 owner:SetAttribute("state-multispellpage",self:GetAttribute("index")) | |
214 self:GetParent():Hide() | |
215 return false | |
216 else | |
217 return nil, "close" | |
218 end | |
219 ]] | |
220 | |
221 local _flyout_child_postClick = -- function(self, message, button, down) | |
222 [[ | |
223 if message == "close" then | |
224 self:GetParent():Hide() -- hide flyout after selecting | |
225 end | |
226 ]] | |
227 | |
228 | |
229 -- | |
230 -- The Blizzard totem bar textures are all actually one big texture, | |
231 -- with texcoord offsets | |
232 -- | |
233 local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar" | |
234 local FLYOUT_UP_BUTTON_TCOORDS = { 99/128, 127/128, 84/256, 102/256 } | |
235 local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 } | |
236 local FLYOUT_DOWN_BUTTON_TCOORDS = { 99/128, 127/128, 65/256, 83/256 } | |
237 local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 } | |
238 local EMPTY_SLOT_TCOORDS = { 66/128, 96/128, 3/256, 33/256 } | |
239 | |
240 local eventList = { | |
241 -- TODO | |
242 "PLAYER_REGEN_ENABLED", | |
243 "PLAYER_ENTERING_WORLD", | |
244 "ACTIONBAR_PAGE_CHANGED", | |
245 "ACTIONBAR_SLOT_CHANGED", | |
246 "UPDATE_BINDINGS", | |
247 "ACTIONBAR_UPDATE_STATE", | |
248 "ACTIONBAR_UPDATE_USABLE", | |
249 "ACTIONBAR_UPDATE_COOLDOWN", | |
250 "UPDATE_INVENTORY_ALERTS", | |
251 "PLAYER_TARGET_CHANGED", | |
252 "TRADE_SKILL_SHOW", | |
253 "TRADE_SKILL_CLOSE", | |
254 "PLAYER_ENTER_COMBAT", | |
255 "PLAYER_LEAVE_COMBAT", | |
256 "START_AUTOREPEAT_SPELL", | |
257 "STOP_AUTOREPEAT_SPELL", | |
258 "UNIT_ENTERED_VEHICLE", | |
259 "UNIT_EXITED_VEHICLE", | |
260 "COMPANION_UPDATE", | |
261 "UPDATE_MULTI_CAST_ACTIONBAR", | |
262 } | |
263 | |
264 -- | |
265 -- MultiCast Button class | |
266 -- Inherits implementation methods from Action button class, but circumvents the constructor | |
267 -- and redefines/removes some methods. | |
268 -- | |
269 local Super = ReAction.Button | |
270 local Action = ReAction.Button.Action | |
271 local MultiCast = setmetatable( { }, { __index = Action } ) | |
272 ReAction.Button.MultiCast = MultiCast | |
273 | |
274 function MultiCast:New( idx, btnConfig, bar ) | |
275 if idx < 1 or idx > NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | |
276 error("Multicast button index out of range") | |
277 end | |
278 | |
279 local name = format("ReAction_%s_Action_%d",bar:GetName(),idx) | |
280 | |
281 self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) | |
282 | |
283 local barFrame = bar:GetFrame() | |
284 local f = self:GetFrame() | |
285 | |
286 -- attributes | |
287 if idx == 1 or idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | |
288 f:SetAttribute("type","spell") | |
289 local spells = idx == 1 and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS | |
290 for i, spell in ipairs(spells) do | |
291 if spell and IsSpellKnown(spell) then | |
292 f:SetAttribute("spell-page"..i, spell) | |
293 if i == 1 then | |
294 -- TODO: store/restore last used summon | |
295 f:SetAttribute("spell",spell) | |
296 end | |
297 end | |
298 end | |
299 else | |
300 local baseAction = barFrame:GetAttribute("baseActionID") + TOTEM_PRIORITIES[idx-1] | |
301 f:SetAttribute("type","action") | |
302 f:SetAttribute("action", baseAction) | |
303 for i = 1, NUM_MULTI_CAST_PAGES do | |
304 f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) | |
305 end | |
306 end | |
307 f:SetAttribute("bar-idx",idx) | |
308 barFrame:SetFrameRef("slot-"..idx,f) | |
309 | |
310 -- non secure scripts | |
311 f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) | |
312 f:SetScript("OnEnter", function(frame) self:OnEnter() end) | |
313 f:SetScript("OnLeave", function(frame) self:OnLeave() end) | |
314 f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) | |
315 f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) | |
316 | |
317 -- secure handlers | |
318 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | |
319 f:SetAttribute("_childupdate",_childupdate) | |
320 end | |
321 barFrame:WrapScript(f, "OnEnter", _onEnter) | |
322 | |
323 -- event registration | |
324 f:EnableMouse(true) | |
325 f:RegisterForClicks("AnyUp") | |
326 for _, evt in pairs(eventList) do | |
327 f:RegisterEvent(evt) | |
328 end | |
329 | |
330 -- attach to skinner | |
331 bar:SkinButton(self) | |
332 | |
333 f:Show() | |
334 | |
335 -- open arrow | |
336 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | |
337 local arrow = CreateFrame("Button", nil, f, "SecureFrameTemplate") | |
338 arrow:SetWidth(28) | |
339 arrow:SetHeight(12) | |
340 arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring | |
341 arrow:SetNormalTexture(TOTEM_TEXTURE) | |
342 arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS) ) | |
343 arrow:SetHighlightTexture(TOTEM_TEXTURE) | |
344 arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) ) | |
345 arrow:SetAttribute("bar-idx",idx) | |
346 arrow:Hide() | |
347 barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout) | |
348 local arrowRef = "arrow-"..idx | |
349 barFrame:SetFrameRef(arrowRef,arrow) | |
350 end | |
351 | |
352 self:Refresh() | |
353 | |
354 return self | |
355 end | |
356 | |
357 function MultiCast:Destroy() | |
358 local barFrame = self:GetFrame() | |
359 Super.Destroy(self) | |
360 end | |
361 | |
362 function MultiCast:Refresh() | |
363 Super.Refresh(self) | |
364 self:UpdateAction() | |
365 end | |
366 | |
367 function MultiCast:ShowGrid( show ) | |
368 end | |
369 | |
370 function MultiCast:ShowGridTemp( show ) | |
371 end | |
372 | |
373 function MultiCast:AcquireActionID() | |
374 end | |
375 | |
376 function MultiCast:ReleaseActionID() | |
377 end | |
378 | |
379 function MultiCast:UpdateShowGrid() | |
380 end | |
381 | |
382 function MultiCast:UpdateBorder() | |
383 end | |
384 | |
385 function MultiCast:UpdateMacroText() | |
386 end | |
387 | |
388 function MultiCast:UpdateCount() | |
389 end | |
390 | |
391 function MultiCast:UpdateCheckedState() | |
392 local action = self:GetActionID() | |
393 if action and IsCurrentAction(action) then | |
394 self:GetFrame():SetChecked(1) | |
395 else | |
396 self:GetFrame():SetChecked(0) | |
397 end | |
398 end | |
399 | |
400 function MultiCast:RefreshHasActionAttributes() | |
401 end | |
402 | |
403 function MultiCast:UpdateFlash() | |
404 end | |
405 | |
406 function MultiCast:GetIconTexture() | |
407 local tx | |
408 if self.spellID then | |
409 tx = GetSpellTexture(GetSpellInfo(self.spellID)) | |
410 elseif self.actionID then | |
411 tx = GetActionTexture(self.actionID) | |
412 end | |
413 if tx then | |
414 return tx | |
415 else | |
416 return TOTEM_TEXTURE, unpack(EMPTY_SLOT_TCOORDS) | |
417 end | |
418 end | |
419 | |
420 function MultiCast:UpdateAction() | |
421 local action = self:GetActionID() | |
422 if action then | |
423 if action ~= self.actionID then | |
424 self.actionID = action | |
425 self:UpdateAll() | |
426 end | |
427 else | |
428 local spellID = self:GetSpellID() | |
429 if spellID ~= self.spellID then | |
430 self.spellID = spellID | |
431 self:UpdateAll() | |
432 end | |
433 end | |
434 end | |
435 | |
436 function MultiCast:GetActionID(page) | |
437 return self:GetFrame():GetAttribute("action") | |
438 end | |
439 | |
440 function MultiCast:GetSpellID(page) | |
441 return self:GetFrame():GetAttribute("spell") | |
442 end | |
443 | |
444 function MultiCast:SetActionID( id ) | |
445 error("Can not set action ID of multicast buttons") | |
446 end | |
447 | |
448 function MultiCast:SetTooltip() | |
449 local barFrame = self:GetFrame() | |
450 if GetCVar("UberTooltips") == "1" then | |
451 GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) | |
452 else | |
453 GameTooltip:SetOwner(barFrame) | |
454 end | |
455 if self.spellID then | |
456 GameTooltip:SetSpellByID(self.spellID,false,true) | |
457 elseif self.actionID then | |
458 GameTooltip:SetAction(self.actionID) | |
459 end | |
460 end | |
461 | |
462 function MultiCast:GetUsable() | |
463 if self.spellID then | |
464 return IsUsableSpell((GetSpellInfo(self.spellID))) | |
465 elseif self.actionID then | |
466 return IsUsableAction(self.actionID) | |
467 end | |
468 end | |
469 | |
470 function MultiCast:GetInRange() | |
471 if self.spellID then | |
472 return IsSpellInRange((GetSpellInfo(self.spellID))) == 0 | |
473 elseif self.actionID then | |
474 return IsActionInRange(self.actionID) == 0 | |
475 end | |
476 end | |
477 | |
478 function MultiCast:GetCooldown() | |
479 if self.spellID then | |
480 return GetSpellCooldown((GetSpellInfo(self.spellID))) | |
481 elseif self.actionID then | |
482 return GetActionCooldown(self.actionID) | |
483 else | |
484 return 0, 0, 0 | |
485 end | |
486 end | |
487 | |
488 function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR() | |
489 self:UpdateAll() | |
490 end | |
491 | |
492 | |
493 -- | |
494 -- flyout setup | |
495 -- | |
496 local function ShowFlyoutTooltip(barFrame) | |
497 if GetCVar("UberTooltips") == "1" then | |
498 GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) | |
499 else | |
500 GameTooltip:SetOwner(barFrame) | |
501 end | |
502 local spell = barFrame:GetAttribute("spell") | |
503 if barFrame == 0 then | |
504 GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) | |
505 else | |
506 GameTooltip:SetSpellByID(barFrame:GetAttribute("spell"),false,true) | |
507 end | |
508 end | |
509 | |
510 local function HideFlyoutTooltip() | |
511 GameTooltip:Hide() | |
512 end | |
513 | |
514 local function UpdateFlyoutIcon(frame) | |
515 local spellID = frame:GetAttribute("spell") | |
516 if spellID == 0 then | |
517 frame.icon:SetTexture(TOTEM_TEXTURE) | |
518 frame.icon:SetTexCoord( unpack(EMPTY_SLOT_TCOORDS) ) | |
519 elseif spellID then | |
520 frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID))) | |
521 frame.icon:SetTexCoord(0,1,0,1) | |
522 end | |
523 end | |
524 | |
525 function MultiCast.SetupBarHeader( bar ) -- call this as a static method | |
526 local summon = { } | |
527 local recall = { } | |
528 local maxIdx = 1 | |
529 | |
530 for idx, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do | |
531 if spell and IsSpellKnown(spell) then | |
532 tinsert(summon,spell) | |
533 maxIdx = max(idx,maxIdx) | |
534 end | |
535 end | |
536 | |
537 for idx, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do | |
538 if spell and IsSpellKnown(spell) then | |
539 tinsert(recall,spell) | |
540 maxIdx = max(idx,maxIdx) | |
541 end | |
542 end | |
543 | |
544 if #summon == 0 and #recall == 0 then | |
545 return 0 -- no multicast capability | |
546 end | |
547 | |
548 local slots = { } | |
549 | |
550 tinsert(slots, summon) | |
551 | |
552 for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do | |
553 local slotSpells = { 0, GetMultiCastTotemSpells(TOTEM_PRIORITIES[i]) } | |
554 maxIdx = max(maxIdx, #slotSpells) | |
555 tinsert(slots,slotSpells) | |
556 end | |
557 | |
558 tinsert(slots, recall) | |
559 | |
560 local barFrame = bar:GetFrame() | |
561 | |
562 -- init bar secure environment | |
563 barFrame:SetAttribute("nMultiCastSlots",#slots) | |
564 barFrame:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS) | |
565 barFrame:SetAttribute("_onstate-multispellpage", _onstate_multispellpage) | |
566 barFrame:Execute(_bar_init) | |
567 | |
568 for i, p in ipairs(TOTEM_PRIORITIES) do | |
569 barFrame:SetAttribute("TOTEM_PRIORITY_"..i,p) | |
570 end | |
571 | |
572 -- create flyout container frame and close arrow | |
573 local flyout = bar._flyoutFrame | |
574 if not flyout then | |
575 flyout = CreateFrame("Frame", nil, barFrame, "SecureFrameTemplate") | |
576 bar._flyoutFrame = flyout | |
577 barFrame:SetFrameRef("flyout",flyout) | |
578 flyout.buttons = { } | |
579 flyout:Hide() | |
580 flyout:SetWidth(24) | |
581 flyout:SetHeight(1) | |
582 flyout:SetPoint("BOTTOM",barFrame,"TOP",0,0) | |
583 | |
584 local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate") | |
585 close:SetWidth(28) | |
586 close:SetHeight(12) | |
587 close:SetPoint("TOP") | |
588 close:SetNormalTexture(TOTEM_TEXTURE) | |
589 close:GetNormalTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_TCOORDS) ) | |
590 close:SetHighlightTexture(TOTEM_TEXTURE) | |
591 close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) ) | |
592 barFrame:SetFrameRef("close",close) | |
593 barFrame:WrapScript(close, "OnClick", _closeFlyout) | |
594 end | |
595 | |
596 -- create flyout buttons | |
597 for i = #flyout.buttons + 1, maxIdx do | |
598 local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate") | |
599 b:SetWidth(24) | |
600 b:SetHeight(24) | |
601 local prev = flyout.buttons[i-1] | |
602 b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring | |
603 b.icon = b:CreateTexture("BACKGROUND") | |
604 b.icon:SetAllPoints() | |
605 b.icon:Show() | |
606 b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") | |
607 b:GetHighlightTexture():SetBlendMode("ADD") | |
608 b:RegisterForClicks("AnyUp") | |
609 b:SetScript("OnShow",UpdateFlyoutIcon) | |
610 b:SetScript("OnEnter",ShowFlyoutTooltip) | |
611 b:SetScript("OnLeave",HideFlyoutTooltip) | |
612 b:SetAttribute("index",i) | |
613 b:Show() | |
614 barFrame:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick) | |
615 flyout.buttons[i] = b | |
616 end | |
617 | |
618 for i, b in ipairs(flyout.buttons) do | |
619 barFrame:SetFrameRef("flyout-child",b) | |
620 barFrame:Execute([[ | |
621 tinsert(flyoutChildren,self:GetFrameRef("flyout-child")) | |
622 ]]) | |
623 end | |
624 | |
625 -- transfer the table of spell IDs into the secure environment | |
626 for i, spells in ipairs(slots) do | |
627 barFrame:SetAttribute("spell-slot", i) | |
628 for j, spell in ipairs(spells) do | |
629 barFrame:SetAttribute("spell-index", j) | |
630 barFrame:SetAttribute("spell-id", spell) | |
631 barFrame:Execute([[ | |
632 multiCastSpellList[self:GetAttribute("spell-slot")][self:GetAttribute("spell-index")] = self:GetAttribute("spell-id") | |
633 ]]) | |
634 end | |
635 end | |
636 | |
637 return #slots | |
638 end | |
639 |