Mercurial > wow > reaction
comparison classes/MultiCastButton.lua @ 167:eab7e7642dd6
Rewrote MultiCastButton to show prior to learning a summon ability, cleaned up implementation.
NOTE: a typo fix will invalidate any existing keybindings to totem buttons.
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Tue, 19 Oct 2010 16:49:40 +0000 |
parents | 8241be11dcc0 |
children | 07c76dbc0236 |
comparison
equal
deleted
inserted
replaced
166:8241be11dcc0 | 167:eab7e7642dd6 |
---|---|
44 | 44 |
45 note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(), | 45 note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(), |
46 so that's action ID 132-144. | 46 so that's action ID 132-144. |
47 | 47 |
48 - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot) | 48 - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot) |
49 returns spellIDs for all totems that fit that slot. | 49 returns spellIDs for all known totems that fit that slot. This function is available in |
50 Note this is available in the secure environment, but because IsSpellKnown() is not, | 50 the secure environment. |
51 it makes it pretty much useless. | |
52 | 51 |
53 Blizzard textures: | 52 Blizzard textures: |
54 All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single | 53 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 | 54 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. | 55 this is to slightly optimize texture load performance, but it makes the UI code more clumsy. |
69 spells) with the list of spells known for each slot. | 68 spells) with the list of spells known for each slot. |
70 | 69 |
71 - Each button (except recall) has an arrow button which appears on mouseover and when clicked | 70 - 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 | 71 opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not |
73 appear. | 72 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 | 73 |
77 - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child | 74 - 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 | 75 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 | 76 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 | 77 the current page (summon) or sets a multispell to an actionID via type="multispell". None of them |
82 right-click casts the spell). The flyout also has a close button which closes the flyout: the | 79 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 | 80 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). | 81 changes dynamically because each slot has a different number of items in the list). |
85 | 82 |
86 - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of | 83 - 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 | 84 the summon spells is cast from elsewhere. |
88 always appears as the active summon when the UI is loaded, which is bad design that could be improved | 85 |
89 upon. TODO: Store state in a config variable and restore it at load time. | 86 - The default UI has Call of the Elements always selected on UI load. This module remembers the last |
87 selected one and restores it. | |
90 | 88 |
91 | 89 |
92 ]]-- | 90 ]]-- |
93 | 91 |
94 | 92 |
99 -- bar | 97 -- bar |
100 local _bar_init = -- function(self) | 98 local _bar_init = -- function(self) |
101 [[ | 99 [[ |
102 -- set up some globals in the secure environment | 100 -- set up some globals in the secure environment |
103 flyout = self:GetFrameRef("flyout") | 101 flyout = self:GetFrameRef("flyout") |
104 flyoutChildren = newtable() | 102 flyoutSlot = nil |
105 nMultiCastSlots = self:GetAttribute("nMultiCastSlots") | 103 summonSlot = self:GetAttribute("summonSlot") |
104 recallSlot = self:GetAttribute("recallSlot") | |
106 baseActionID = self:GetAttribute("baseActionID") | 105 baseActionID = self:GetAttribute("baseActionID") |
107 currentMultiCastPage = currentMultiCastPage or self:GetAttribute("lastSummon") or 1 | 106 slotsPerPage = self:GetAttribute("slotsPerPage") |
108 multiCastSpellList = newtable() | 107 currentPage = currentPage or self:GetAttribute("lastSummon") or 1 |
109 for i = 1, nMultiCastSlots do | 108 |
110 tinsert(multiCastSpellList, newtable()) | 109 totemIDsBySlot = newtable() |
111 end | 110 for i = 1, slotsPerPage do |
111 totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i) | |
112 end | |
113 | |
114 summonSpells = summonSpells or newtable() -- set up in bar:SetupBarHeader() | |
112 ]] | 115 ]] |
113 | 116 |
114 local _onstate_multispellpage = -- function(self, stateid, newstate) | 117 local _onstate_multispellpage = -- function(self, stateid, newstate) |
115 [[ | 118 [[ |
116 currentMultiCastPage = tonumber(newstate) | 119 currentPage = tonumber(newstate) |
117 control:CallMethod("UpdateLastSummon",currentMultiCastPage) | 120 control:CallMethod("UpdateLastSummon",currentPage) |
118 control:ChildUpdate() | 121 control:ChildUpdate() |
119 ]] | 122 ]] |
120 | 123 |
121 | 124 |
122 -- buttons | 125 -- buttons |
123 local _childupdate = -- function(self, snippetid, message) | 126 local _childupdate = -- function(self, snippetid, message) |
124 [[ | 127 [[ |
125 if self:GetAttribute("type") == "spell" then | 128 local t = self:GetAttribute("type") |
126 self:SetAttribute("spell", self:GetAttribute("spell-page"..currentMultiCastPage)) | 129 self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage)) |
127 elseif self:GetAttribute("type") == "action" then | |
128 self:SetAttribute("action", self:GetAttribute("action-page"..currentMultiCastPage)) | |
129 end | |
130 ]] | 130 ]] |
131 | 131 |
132 local _onEnter = -- function(self) | 132 local _onEnter = -- function(self) |
133 -- for whatever reason, RegisterAutoHide is unreliable | 133 -- for whatever reason, RegisterAutoHide is unreliable |
134 -- unless you re-anchor the frame prior to calling it. | 134 -- unless you re-anchor the frame prior to calling it. |
135 -- Even then, it's still not terribly reliable. | 135 -- Even then, it's still not terribly reliable. |
136 [[ | 136 [[ |
137 local idx = self:GetAttribute("bar-idx") | 137 local slot = self:GetAttribute("bar-idx") |
138 if not (flyout:IsVisible() and flyoutIdx == idx) then | 138 local arrow = owner:GetFrameRef("arrow-"..slot) |
139 local arrow = owner:GetFrameRef("arrow-"..idx) | 139 if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then |
140 if arrow and not arrow:IsShown() then | 140 arrow:ClearAllPoints() |
141 arrow:ClearAllPoints() | 141 arrow:SetPoint("BOTTOM",self,"TOP",0,0) |
142 arrow:SetPoint("BOTTOM",self,"TOP",0,0) -- TODO: better anchoring | 142 arrow:Show() |
143 arrow:Show() | |
144 arrow:RegisterAutoHide(0) | |
145 arrow:AddToAutoHide(self) | |
146 end | |
147 end | |
148 ]] | |
149 | |
150 local _onLeave = -- function(self) | |
151 -- to increase reliability (somewhat), re-register it for hide on leave | |
152 [[ | |
153 local arrow = owner:GetFrameRef("arrow-"..self:GetAttribute("bar-idx")) | |
154 if arrow then | |
155 arrow:RegisterAutoHide(0) | 143 arrow:RegisterAutoHide(0) |
156 arrow:AddToAutoHide(self) | 144 arrow:AddToAutoHide(self) |
157 end | 145 end |
158 ]] | 146 ]] |
159 | 147 |
160 | 148 |
161 -- flyout arrow | 149 -- flyout arrow |
162 local _arrow_openFlyout = -- function(self) | 150 local _arrow_openFlyout = -- function(self) |
163 [[ | 151 [[ |
164 local currentMultiCastSlot = self:GetAttribute("bar-idx") | 152 local slot = self:GetAttribute("bar-idx") |
165 local lastButton, lastIdx | 153 local lastButton, lastPage |
166 for idx, b in ipairs(flyoutChildren) do | 154 for page, b in ipairs(flyoutChildren) do |
167 b:Hide() -- force the OnShow handler to run later | 155 b:Hide() |
168 local spellID = multiCastSpellList[currentMultiCastSlot][idx] | 156 if slot == summonSlot then |
169 if spellID then | 157 local spellID = self:GetParent():GetAttribute("spell-page"..page) |
170 b:SetAttribute("spell",spellID) -- does passing 0 work for no-totem? Do we have to convert to nil? | 158 print("got spell-page"..tostring(page).." = ".. tostring(spellID)) |
171 if currentMultiCastSlot == 1 then | 159 if spellID then |
172 b:SetAttribute("type","changePage") | 160 b:SetAttribute("type","changePage") |
173 else | 161 b:SetAttribute("spell",spellID) |
162 b:Show() | |
163 lastButton = b | |
164 lastPage = page | |
165 end | |
166 else | |
167 local offset = summonSlot or 0 | |
168 local totemID = totemIDsBySlot[slot - offset] | |
169 local spells = newtable( 0, GetMultiCastTotemSpells(totemID) ) | |
170 if spells[page] then | |
174 b:SetAttribute("type","multispell") | 171 b:SetAttribute("type","multispell") |
175 local totemID = owner:GetAttribute("TOTEM_PRIORITY_"..(currentMultiCastSlot - 1)) | 172 b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID) |
176 b:SetAttribute("action", baseActionID + (currentMultiCastPage - 1)*(nMultiCastSlots-2) + totemID) | 173 b:SetAttribute("spell", spells[page]) |
174 b:Show() | |
175 lastButton = b | |
176 lastPage = page | |
177 end | 177 end |
178 b:Show() | |
179 lastButton = b | |
180 lastIdx = idx | |
181 end | 178 end |
182 end | 179 end |
183 | 180 |
184 local close = owner:GetFrameRef("close") | 181 local close = owner:GetFrameRef("close") |
185 if lastButton and close then | 182 if lastButton and close then |
188 close:Show() | 185 close:Show() |
189 end | 186 end |
190 | 187 |
191 flyout:ClearAllPoints() | 188 flyout:ClearAllPoints() |
192 flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring | 189 flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring |
193 if lastIdx then | 190 if lastPage then |
194 flyout:SetHeight(lastIdx * 27 + (close and close:GetHeight() or 0)) | 191 flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0)) |
195 end | 192 end |
196 flyout:Show() | 193 flyout:Show() |
197 flyout:RegisterAutoHide(1) -- TODO: configurable | 194 flyout:RegisterAutoHide(1) -- TODO: configurable |
198 flyout:AddToAutoHide(owner) | 195 flyout:AddToAutoHide(owner) |
199 flyoutIdx = currentMultiCastSlot | 196 flyoutSlot = slot |
200 self:Hide() | 197 self:Hide() |
201 ]] | 198 ]] |
202 | 199 |
203 local _closeFlyout = -- function(self) | 200 local _closeFlyout = -- function(self) |
204 [[ | 201 [[ |
256 local Action = ReAction.Button.Action | 253 local Action = ReAction.Button.Action |
257 local MultiCast = setmetatable( { }, { __index = Action } ) | 254 local MultiCast = setmetatable( { }, { __index = Action } ) |
258 ReAction.Button.MultiCast = MultiCast | 255 ReAction.Button.MultiCast = MultiCast |
259 | 256 |
260 function MultiCast:New( idx, btnConfig, bar ) | 257 function MultiCast:New( idx, btnConfig, bar ) |
261 if idx < 1 or idx > NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | 258 local maxIndex = bar.nTotemSlots or 0 |
262 error("Multicast button index out of range") | 259 if bar.summonSlot then |
263 end | 260 maxIndex = maxIndex + 1 |
264 | 261 end |
265 if idx > bar.nMultiCastSlots then | 262 if bar.recallSlot then |
263 maxIndex = maxIndex + 1 | |
264 end | |
265 | |
266 if not bar.hasMulticast or idx > maxIndex then | |
266 return false | 267 return false |
267 end | 268 end |
268 | 269 |
269 local name = format("ReAction_%s_Action_%d",bar:GetName(),idx) | 270 if idx < 1 then |
271 error("invalid index") | |
272 end | |
273 | |
274 local name = format("ReAction_%s_Totem_%d",bar:GetName(),idx) | |
270 | 275 |
271 self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) | 276 self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) |
272 | 277 |
273 local barFrame = bar:GetFrame() | 278 local barFrame = bar:GetFrame() |
274 local f = self:GetFrame() | 279 local f = self:GetFrame() |
275 | 280 |
276 -- attributes | 281 -- attributes |
277 local page = (idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2) and 1 or (bar:GetConfig().lastSummon or 1) | 282 local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1 |
278 if idx == 1 or idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | 283 if idx == bar.recallSlot or idx == bar.summonSlot then |
279 f:SetAttribute("type","spell") | 284 f:SetAttribute("type","spell") |
280 local spells = idx == 1 and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS | 285 local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS |
281 f:SetAttribute("spell",spells[page]) | 286 f:SetAttribute("spell",spells[page]) |
282 for i, spell in ipairs(spells) do | 287 for i, spell in ipairs(spells) do |
283 if spell and IsSpellKnown(spell) then | 288 if spell and IsSpellKnown(spell) then |
289 print("setting attribute spell-page"..i.." to "..spell) | |
284 f:SetAttribute("spell-page"..i, spell) | 290 f:SetAttribute("spell-page"..i, spell) |
285 end | 291 end |
286 end | 292 end |
287 else | 293 else |
288 local baseAction = barFrame:GetAttribute("baseActionID") + SHAMAN_TOTEM_PRIORITIES[idx-1] | 294 local offset = bar.summonSlot and 1 or 0 |
295 local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset] | |
296 local baseAction = barFrame:GetAttribute("baseActionID") + slot | |
289 f:SetAttribute("type","action") | 297 f:SetAttribute("type","action") |
290 f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) | 298 f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) |
291 for i = 1, NUM_MULTI_CAST_PAGES do | 299 for i = 1, NUM_MULTI_CAST_PAGES do |
292 f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) | 300 f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) |
293 end | 301 end |
294 end | 302 end |
295 f:SetAttribute("bar-idx",idx) | 303 f:SetAttribute("bar-idx",idx) |
296 barFrame:SetFrameRef("slot-"..idx,f) | |
297 | 304 |
298 -- non secure scripts | 305 -- non secure scripts |
299 f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) | 306 f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) |
300 f:SetScript("OnEnter", function(frame) self:OnEnter() end) | 307 f:SetScript("OnEnter", function(frame) self:OnEnter() end) |
301 f:SetScript("OnLeave", function(frame) self:OnLeave() end) | 308 f:SetScript("OnLeave", function(frame) self:OnLeave() end) |
302 f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) | 309 f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) |
303 f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) | 310 f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) |
304 | 311 |
305 -- secure handlers | 312 -- secure handlers |
306 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | 313 if idx ~= bar.recallSlot then |
307 f:SetAttribute("_childupdate",_childupdate) | 314 f:SetAttribute("_childupdate",_childupdate) |
308 end | 315 end |
309 barFrame:WrapScript(f, "OnEnter", _onEnter) | 316 barFrame:WrapScript(f, "OnEnter", _onEnter) |
310 | 317 |
311 -- event registration | 318 -- event registration |
329 bar:SkinButton(self) | 336 bar:SkinButton(self) |
330 | 337 |
331 f:Show() | 338 f:Show() |
332 | 339 |
333 -- open arrow | 340 -- open arrow |
334 if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then | 341 if idx ~= bar.recallSlot then |
335 local arrow = CreateFrame("Button", nil, f, "SecureFrameTemplate") | 342 local arrow = CreateFrame("Button", nil, f, "SecureFrameTemplate") |
336 arrow:SetWidth(28) | 343 arrow:SetWidth(28) |
337 arrow:SetHeight(12) | 344 arrow:SetHeight(12) |
338 arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring | 345 arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring |
339 arrow:SetNormalTexture(TOTEM_TEXTURE) | 346 arrow:SetNormalTexture(TOTEM_TEXTURE) |
341 arrow:SetHighlightTexture(TOTEM_TEXTURE) | 348 arrow:SetHighlightTexture(TOTEM_TEXTURE) |
342 arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) ) | 349 arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) ) |
343 arrow:SetAttribute("bar-idx",idx) | 350 arrow:SetAttribute("bar-idx",idx) |
344 arrow:Hide() | 351 arrow:Hide() |
345 barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout) | 352 barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout) |
346 local arrowRef = "arrow-"..idx | 353 barFrame:SetFrameRef("arrow-"..idx,arrow) |
347 barFrame:SetFrameRef(arrowRef,arrow) | |
348 end | 354 end |
349 | 355 |
350 self:Refresh() | 356 self:Refresh() |
351 | 357 |
352 return self | 358 return self |
489 | 495 |
490 | 496 |
491 -- | 497 -- |
492 -- flyout setup | 498 -- flyout setup |
493 -- | 499 -- |
494 local function ShowFlyoutTooltip(barFrame) | 500 local function ShowFlyoutTooltip(frame) |
495 if GetCVar("UberTooltips") == "1" then | 501 if GetCVar("UberTooltips") == "1" then |
496 GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) | 502 GameTooltip_SetDefaultAnchor(GameTooltip, frame) |
497 else | 503 else |
498 GameTooltip:SetOwner(barFrame) | 504 GameTooltip:SetOwner(frame) |
499 end | 505 end |
500 local spell = barFrame:GetAttribute("spell") | 506 local spell = frame:GetAttribute("spell") |
501 if barFrame == 0 then | 507 if spell == nil or spell == 0 then |
502 GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) | 508 GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) |
503 else | 509 else |
504 GameTooltip:SetSpellByID(barFrame:GetAttribute("spell"),false,true) | 510 GameTooltip:SetSpellByID(spell,false,true) |
505 end | 511 end |
506 end | 512 end |
507 | 513 |
508 local function HideFlyoutTooltip() | 514 local function HideFlyoutTooltip() |
509 GameTooltip:Hide() | 515 GameTooltip:Hide() |
510 end | 516 end |
511 | 517 |
512 local function UpdateFlyoutIcon(frame) | 518 local function UpdateFlyoutIcon(frame) |
513 local spellID = frame:GetAttribute("spell") | 519 local spellID = frame:GetAttribute("spell") |
514 if spellID == 0 then | 520 if spellID == 0 or spellID == nil then |
515 frame.icon:SetTexture(TOTEM_TEXTURE) | 521 frame.icon:SetTexture(TOTEM_TEXTURE) |
516 frame.icon:SetTexCoord( unpack(EMPTY_SLOT_TCOORDS) ) | 522 frame.icon:SetTexCoord( unpack(EMPTY_SLOT_TCOORDS) ) |
517 elseif spellID then | 523 else |
518 frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID))) | 524 frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID))) |
519 frame.icon:SetTexCoord(0,1,0,1) | 525 frame.icon:SetTexCoord(0,1,0,1) |
520 end | 526 end |
521 end | 527 end |
522 | 528 |
523 function MultiCast.SetupBarHeader( bar ) -- call this as a static method | 529 function MultiCast.SetupBarHeader( bar ) -- call this as a static method |
524 local summon = { } | 530 local slot = 0 |
525 local recall = { } | 531 local nTotemSlots = 0 |
526 local maxIdx = 1 | 532 local summonSlot = nil |
527 | 533 local recallSlot = nil |
528 for idx, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do | 534 |
535 -- figure out the capabilities of the character | |
536 for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do | |
529 if spell and IsSpellKnown(spell) then | 537 if spell and IsSpellKnown(spell) then |
530 tinsert(summon,spell) | 538 slot = 1 |
531 maxIdx = max(idx,maxIdx) | 539 summonSlot = 1 |
532 end | 540 end |
533 end | 541 end |
534 | 542 |
535 for idx, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do | 543 for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do |
544 local totem = SHAMAN_TOTEM_PRIORITIES[i]; | |
545 if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then | |
546 nTotemSlots = nTotemSlots + 1 | |
547 slot = slot + 1 | |
548 end | |
549 end | |
550 | |
551 slot = slot + 1 | |
552 for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do | |
536 if spell and IsSpellKnown(spell) then | 553 if spell and IsSpellKnown(spell) then |
537 tinsert(recall,spell) | 554 recallSlot = slot |
538 maxIdx = max(idx,maxIdx) | |
539 end | 555 end |
540 end | 556 end |
541 | 557 |
542 if #summon == 0 and #recall == 0 then | 558 if nTotemSlots == 0 then |
543 bar.nMultiCastSlots = 0 -- no multicast capability | 559 bar.hasMulticast = false -- no multicast capability |
544 return | 560 return |
545 end | 561 end |
546 | 562 |
547 local slots = { } | 563 bar.hasMulticast = true |
548 | 564 bar.summonSlot = summonSlot |
549 tinsert(slots, summon) | 565 bar.recallSlot = recallSlot |
550 | 566 bar.nTotemSlots = nTotemSlots |
551 for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do | 567 |
552 local slotSpells = { 0, GetMultiCastTotemSpells(SHAMAN_TOTEM_PRIORITIES[i]) } | 568 |
553 maxIdx = max(maxIdx, #slotSpells) | 569 local f = bar:GetFrame() |
554 tinsert(slots,slotSpells) | |
555 end | |
556 | |
557 tinsert(slots, recall) | |
558 | |
559 local barFrame = bar:GetFrame() | |
560 | 570 |
561 -- init bar secure environment | 571 -- init bar secure environment |
562 barFrame:SetAttribute("lastSummon",bar:GetConfig().lastSummon) | 572 f:SetAttribute("lastSummon", bar:GetConfig().lastSummon) |
563 barFrame:SetAttribute("nMultiCastSlots",#slots) | 573 f:SetAttribute("summonSlot", summonSlot) |
564 barFrame:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS) | 574 f:SetAttribute("recallSlot", recallSlot) |
565 barFrame:SetAttribute("_onstate-multispellpage", _onstate_multispellpage) | 575 f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE) |
566 barFrame:Execute(_bar_init) | 576 f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS) |
567 | 577 for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do |
568 function barFrame:UpdateLastSummon(value) | 578 f:SetAttribute("TOTEM_PRIORITY_"..i,p) |
579 end | |
580 f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage) | |
581 | |
582 function f:UpdateLastSummon(value) | |
569 bar:GetConfig().lastSummon = value | 583 bar:GetConfig().lastSummon = value |
570 end | |
571 | |
572 for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do | |
573 barFrame:SetAttribute("TOTEM_PRIORITY_"..i,p) | |
574 end | 584 end |
575 | 585 |
576 -- create flyout container frame and close arrow | 586 -- create flyout container frame and close arrow |
577 local flyout = bar._flyoutFrame | 587 local flyout = bar._flyoutFrame |
578 if not flyout then | 588 if not flyout then |
579 flyout = CreateFrame("Frame", nil, barFrame, "SecureFrameTemplate") | 589 flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate") |
580 bar._flyoutFrame = flyout | 590 bar._flyoutFrame = flyout |
581 barFrame:SetFrameRef("flyout",flyout) | 591 f:SetFrameRef("flyout",flyout) |
582 flyout.buttons = { } | 592 flyout.buttons = { } |
583 flyout:Hide() | 593 flyout:Hide() |
584 flyout:SetWidth(24) | 594 flyout:SetWidth(24) |
585 flyout:SetHeight(1) | 595 flyout:SetHeight(1) |
586 flyout:SetPoint("BOTTOM",barFrame,"TOP",0,0) | 596 flyout:SetPoint("BOTTOM",f,"TOP",0,0) |
587 | 597 |
588 local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate") | 598 local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate") |
589 close:SetWidth(28) | 599 close:SetWidth(28) |
590 close:SetHeight(12) | 600 close:SetHeight(12) |
591 close:SetPoint("TOP") | 601 close:SetPoint("TOP") |
592 close:SetNormalTexture(TOTEM_TEXTURE) | 602 close:SetNormalTexture(TOTEM_TEXTURE) |
593 close:GetNormalTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_TCOORDS) ) | 603 close:GetNormalTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_TCOORDS) ) |
594 close:SetHighlightTexture(TOTEM_TEXTURE) | 604 close:SetHighlightTexture(TOTEM_TEXTURE) |
595 close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) ) | 605 close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) ) |
596 barFrame:SetFrameRef("close",close) | 606 f:SetFrameRef("close",close) |
597 barFrame:WrapScript(close, "OnClick", _closeFlyout) | 607 f:WrapScript(close, "OnClick", _closeFlyout) |
598 end | 608 |
599 | 609 -- create flyout buttons |
600 -- create flyout buttons | 610 for i = 1, 10 do -- maximum 9 spells + 1 empty slot |
601 for i = #flyout.buttons + 1, maxIdx do | 611 local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate") |
602 local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate") | 612 b:SetWidth(24) |
603 b:SetWidth(24) | 613 b:SetHeight(24) |
604 b:SetHeight(24) | 614 local prev = flyout.buttons[i-1] |
605 local prev = flyout.buttons[i-1] | 615 b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring |
606 b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring | 616 b.icon = b:CreateTexture("BACKGROUND") |
607 b.icon = b:CreateTexture("BACKGROUND") | 617 b.icon:SetAllPoints() |
608 b.icon:SetAllPoints() | 618 b.icon:Show() |
609 b.icon:Show() | 619 b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") |
610 b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") | 620 b:GetHighlightTexture():SetBlendMode("ADD") |
611 b:GetHighlightTexture():SetBlendMode("ADD") | 621 b:RegisterForClicks("AnyUp") |
612 b:RegisterForClicks("AnyUp") | 622 b:SetScript("OnShow",UpdateFlyoutIcon) |
613 b:SetScript("OnShow",UpdateFlyoutIcon) | 623 b:SetScript("OnEnter",ShowFlyoutTooltip) |
614 b:SetScript("OnEnter",ShowFlyoutTooltip) | 624 b:SetScript("OnLeave",HideFlyoutTooltip) |
615 b:SetScript("OnLeave",HideFlyoutTooltip) | 625 b:SetAttribute("index",i) |
616 b:SetAttribute("index",i) | 626 f:SetAttribute("flyout-child-idx",i) |
617 b:Show() | 627 f:SetFrameRef("flyout-child",b) |
618 barFrame:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick) | 628 f:Execute([[ |
619 flyout.buttons[i] = b | 629 flyoutChildren = flyoutChildren or newtable() |
620 end | 630 flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child") |
621 | |
622 for i, b in ipairs(flyout.buttons) do | |
623 barFrame:SetFrameRef("flyout-child",b) | |
624 barFrame:Execute([[ | |
625 tinsert(flyoutChildren,self:GetFrameRef("flyout-child")) | |
626 ]]) | |
627 end | |
628 | |
629 -- transfer the table of spell IDs into the secure environment | |
630 for i, spells in ipairs(slots) do | |
631 barFrame:SetAttribute("spell-slot", i) | |
632 for j, spell in ipairs(spells) do | |
633 barFrame:SetAttribute("spell-index", j) | |
634 barFrame:SetAttribute("spell-id", spell) | |
635 barFrame:Execute([[ | |
636 multiCastSpellList[self:GetAttribute("spell-slot")][self:GetAttribute("spell-index")] = self:GetAttribute("spell-id") | |
637 ]]) | 631 ]]) |
638 end | 632 f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick) |
639 end | 633 b:Show() |
640 | 634 flyout.buttons[i] = b |
641 bar.nMultiCastSlots = #slots | 635 end |
642 end | 636 end |
643 | 637 |
638 f:Execute(_bar_init) | |
639 end | |
640 |