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 |
