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 |
