Mercurial > wow > reaction
view MultiCastButton.lua @ 294:30c9bdaad7a3 stable
merge 1.1 beta 10 to stable
author | Flick |
---|---|
date | Fri, 05 Aug 2011 16:28:13 -0700 |
parents | 276165a0e860 |
children |
line wrap: on
line source
local _, ns = ... local ReAction = ns.ReAction local L = ReAction.L local _G = _G local CreateFrame = CreateFrame local format = string.format local unpack = unpack local GetCVar = GetCVar local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor local InCombatLockdown = InCombatLockdown local IsUsableSpell = IsUsableSpell local IsUsableAction = IsUsableAction local IsSpellKnown = IsSpellKnown local IsSpellInRange = IsSpellInRange local IsActionInRange = IsActionInRange local GetSpellInfo = GetSpellInfo local GetSpellCooldown = GetSpellCooldown local GetActionCooldown = GetActionCooldown local GetSpellTexture = GetSpellTexture local GetActionTexture = GetActionTexture local GetMultiCastTotemSpells = GetMultiCastTotemSpells --@do-not-package@ --[[ Blizzard Constants: - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4 - NUM_MULTI_CAST_PAGES = 3 - SHAMAN_TOTEM_PRIORITIES = { } -- sets the order of the totems - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs Blizzard Events: - UPDATE_MULTI_CAST_ACTIONBAR Blizzard APIs: - GetMultiCastBarOffset() : returns 6 - SetMultiCastSpell(actionID, spellID) (protected) OR SetAttribute("type","multispell") SetAttribute("action",actionID) SetAttribute("spell",spellID) note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(), so that's action ID 132-144. - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot) returns spellIDs for all known totems that fit that slot. This function is available in the secure environment. Blizzard textures: All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose this is to slightly optimize texture load performance, but it makes the UI code more clumsy. Each totem button and arrow has a colored border indicating its elemental type. TODO: - make whether to show the colored border configurable (looks really bad with ButtonFacade:Zoomed) - apply ButtonFacade to the flyout buttons? Or at least zoom the textures slightly? - use a multiplier with SetTexCoord on totem bar texture? Design Notes: - Only the header has a secure context. All other frames execute in its context. - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by the summon flyout, which is also paged with the summon spells (the recall button is not paged) - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new spells) with the list of spells known for each slot. - Each button (except recall) has an arrow button which appears on mouseover and when clicked opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not appear. - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding spell/type from the list, according to the slot which opened the flyout. Each button either sets the current page (summon) or sets a multispell to an actionID via type="multispell". None of them actually cast any spells (though, I suppose we could modify this so that e.g. configurable right-click casts the spell). The flyout also has a close button which closes the flyout: the flyout-open code positions the close button anchored to the last button in the flyout (which changes dynamically because each slot has a different number of items in the list). - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of the summon spells is cast from elsewhere. - The default UI has Call of the Elements always selected on UI load. This module remembers the last selected one and restores it. ]]-- --@end-do-not-package@ -- -- Secure snippets -- -- bar local _bar_init = -- function(self) [[ -- set up some globals in the secure environment flyout = self:GetFrameRef("flyout") flyoutSlot = nil summonSlot = self:GetAttribute("summonSlot") recallSlot = self:GetAttribute("recallSlot") baseActionID = self:GetAttribute("baseActionID") slotsPerPage = self:GetAttribute("slotsPerPage") currentPage = currentPage or self:GetAttribute("lastSummon") or 1 totemIDsBySlot = newtable() for i = 1, slotsPerPage do totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i) end -- these are set up in bar:SetupBar() flyoutChildren = flyoutChildren or newtable() summonSpells = summonSpells or newtable() ]] local _onstate_multispellpage = -- function(self, stateid, newstate) [[ currentPage = tonumber(newstate) control:CallMethod("UpdateLastSummon",currentPage) control:ChildUpdate() ]] -- buttons local _childupdate = -- function(self, snippetid, message) [[ local t = self:GetAttribute("type") self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage)) ]] local _onEnter = -- function(self) -- for whatever reason, RegisterAutoHide is unreliable -- unless you re-anchor the frame prior to calling it. -- Even then, it's still not terribly reliable. [[ local slot = self:GetAttribute("bar-idx") local arrow = owner:GetFrameRef("arrow-"..slot) if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then arrow:ClearAllPoints() arrow:SetPoint("BOTTOM",self,"TOP",0,0) arrow:Show() arrow:RegisterAutoHide(0) arrow:AddToAutoHide(self) end ]] -- flyout arrow local _arrow_openFlyout = -- function(self) [[ local slot = self:GetAttribute("bar-idx") local totemID = totemIDsBySlot[slot - (summonSlot or 0)] if totemID == 0 then totemID = "summon" end local lastButton, lastPage for page, b in ipairs(flyoutChildren) do b:Hide() b:SetAttribute("totemSlot",totemID) if slot == summonSlot then local spellID = self:GetParent():GetAttribute("spell-page"..page) if spellID then b:SetAttribute("type","changePage") b:SetAttribute("spell",spellID) b:Show() lastButton = b lastPage = page end else local spell = select(page, 0, GetMultiCastTotemSpells(totemID) ) if spell then b:SetAttribute("type","multispell") b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID) b:SetAttribute("spell", spell) b:Show() lastButton = b lastPage = page end end end local close = owner:GetFrameRef("close") if lastButton and close then close:ClearAllPoints() close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring close:Show() control:CallMethod("UpdateFlyoutTextures",totemID) end flyout:ClearAllPoints() flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring if lastPage then flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0)) end flyout:Show() flyout:RegisterAutoHide(1) -- TODO: configurable flyout:AddToAutoHide(owner) flyoutSlot = slot self:Hide() ]] local _closeFlyout = -- function(self) [[ flyout:Hide() ]] -- flyout child buttons local _flyout_child_preClick = -- function(self, button, down) [[ local button = button if self:GetAttribute("type") == "changePage" then owner:SetAttribute("state-multispellpage",self:GetAttribute("index")) self:GetParent():Hide() return false else return nil, "close" end ]] local _flyout_child_postClick = -- function(self, message, button, down) [[ if message == "close" then self:GetParent():Hide() -- hide flyout after selecting end ]] -- -- The Blizzard totem bar textures are all actually one big texture, -- with texcoord offsets. Shamelessly stolen from FrameXML/MultiCastActionBarFrame.lua -- local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar" local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 } local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 } local SLOT_EMPTY_TCOORDS = { [EARTH_TOTEM_SLOT] = { 66/128, 96/128, 3/256, 33/256 }, [FIRE_TOTEM_SLOT] = { 67/128, 97/128, 100/256, 130/256 }, [WATER_TOTEM_SLOT] = { 39/128, 69/128, 209/256, 239/256 }, [AIR_TOTEM_SLOT] = { 66/128, 96/128, 36/256, 66/256 }, } local SLOT_OVERLAY_TCOORDS = { [EARTH_TOTEM_SLOT] = { 1/128, 35/128, 172/256, 206/256 }, [FIRE_TOTEM_SLOT] = { 36/128, 70/128, 172/256, 206/256 }, [WATER_TOTEM_SLOT] = { 1/128, 35/128, 207/256, 240/256 }, [AIR_TOTEM_SLOT] = { 36/128, 70/128, 137/256, 171/256 }, } local FLYOUT_UP_BUTTON_TCOORDS = { ["summon"] = { 99/128, 127/128, 84/256, 102/256 }, [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 160/256, 178/256 }, [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 122/256, 140/256 }, [WATER_TOTEM_SLOT] = { 99/128, 127/128, 199/256, 217/256 }, [AIR_TOTEM_SLOT] = { 99/128, 127/128, 237/256, 255/256 }, } local FLYOUT_DOWN_BUTTON_TCOORDS = { ["summon"] = { 99/128, 127/128, 65/256, 83/256 }, [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 141/256, 159/256 }, [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 103/256, 121/256 }, [WATER_TOTEM_SLOT] = { 99/128, 127/128, 180/256, 198/256 }, [AIR_TOTEM_SLOT] = { 99/128, 127/128, 218/256, 236/256 }, } local FLYOUT_TOP_TCOORDS = { ["summon"] = { 33/128, 65/128, 1/256, 23/256 }, [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 46/256, 68/256 }, [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 46/256, 68/256 }, [WATER_TOTEM_SLOT] = { 0/128, 32/128, 1/256, 23/256 }, [AIR_TOTEM_SLOT] = { 0/128, 32/128, 91/256, 113/256 }, } local FLYOUT_MIDDLE_TCOORDS = { ["summon"] = { 33/128, 65/128, 23/256, 43/256 }, [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 68/256, 88/256 }, [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 68/256, 88/256 }, [WATER_TOTEM_SLOT] = { 0/128, 32/128, 23/256, 43/256 }, [AIR_TOTEM_SLOT] = { 0/128, 32/128, 113/256, 133/256 }, } local eventList = { "ACTIONBAR_SLOT_CHANGED", "ACTIONBAR_UPDATE_STATE", "ACTIONBAR_UPDATE_USABLE", "ACTIONBAR_UPDATE_COOLDOWN", "UPDATE_BINDINGS", "UPDATE_MULTI_CAST_ACTIONBAR", } -- -- MultiCast Button class -- Inherits implementation methods from Action button class, but circumvents the constructor -- and redefines/removes some methods. -- local buttonTypeID = "Totem" local Super = ReAction.Button local Action = ReAction.Button.Action local MultiCast = setmetatable( { defaultBarConfig = { type = buttonTypeID, btnWidth = 36, btnHeight = 36, btnRows = 1, btnColumns = 6, spacing = 3, buttons = { } }, barType = L["Totem Bar"], buttonTypeID = buttonTypeID }, { __index = Action } ) ReAction.Button.MultiCast = MultiCast ReAction:RegisterBarType(MultiCast) function MultiCast:New( btnConfig, bar, idx ) if idx < 1 or idx > NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then ReAction:UserError(L["All %s buttons are in use for this bar, cannot create any more buttons"]:format(self.barType)) error(nil) end self = Super.New(self, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) if not bar.hasMulticast or idx > bar.maxIndex then -- Not enough multicast capability to use this button self:Refresh() return self end local barFrame = bar:GetFrame() local f = self:GetFrame() -- attributes local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1 if idx == bar.recallSlot or idx == bar.summonSlot then f:SetAttribute("type","spell") local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS f:SetAttribute("spell",spells[page]) for i, spell in ipairs(spells) do if spell and IsSpellKnown(spell) then f:SetAttribute("spell-page"..i, spell) end end else local offset = bar.summonSlot and 1 or 0 local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset] local baseAction = barFrame:GetAttribute("baseActionID") + slot self.totemSlot = slot f:SetAttribute("type","action") f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) for i = 1, NUM_MULTI_CAST_PAGES do f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) end if not f.overlayTex then local tx = f:CreateTexture("OVERLAY") tx:SetTexture(TOTEM_TEXTURE) tx:SetTexCoord(unpack(SLOT_OVERLAY_TCOORDS[self.totemSlot])) tx:SetWidth(34) tx:SetHeight(34) tx:SetPoint("CENTER") tx:Show() f.overlayTex = tx end end f:SetAttribute("bar-idx",idx) -- non secure scripts f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) f:SetScript("OnEnter", function(frame) self:OnEnter() end) f:SetScript("OnLeave", function(frame) self:OnLeave() end) f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) -- secure handlers if idx ~= bar.recallSlot then f:SetAttribute("_childupdate",_childupdate) end barFrame:WrapScript(f, "OnEnter", _onEnter) -- event registration for _, evt in pairs(eventList) do f:RegisterEvent(evt) end -- Set up a proxy for the icon texture for use with ButtonFacade local SetTexCoordRaw = self.frames.icon.SetTexCoord self.frames.icon.SetTexCoord = function( tx, ... ) if self:GetIconTexture() == TOTEM_TEXTURE then SetTexCoordRaw(tx,select(2,self:GetIconTexture())) else SetTexCoordRaw(tx,...) end end -- attach to skinner bar:SkinButton(self) f:Show() -- open arrow and flyout background textures if idx ~= bar.recallSlot then local arrow = f._arrowFrame or CreateFrame("Button", nil, f, "SecureFrameTemplate") f._arrowFrame = arrow arrow:SetWidth(28) arrow:SetHeight(18) arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring arrow:SetNormalTexture(TOTEM_TEXTURE) local slot = self.totemSlot or "summon" arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS[slot]) ) arrow:SetHighlightTexture(TOTEM_TEXTURE) arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) ) arrow:SetAttribute("bar-idx",idx) arrow:Hide() barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout) barFrame:SetFrameRef("arrow-"..idx,arrow) end self:Refresh() return self end function MultiCast:Destroy() local barFrame = self.bar:GetFrame() local f = self:GetFrame() pcall( barFrame.UnwrapScript, barFrame, f, "OnEnter" ) -- ignore errors if f._arrowFrame then pcall( barFrame.UnwrapScript, barFrame, f._arrowFrame,"OnClick" ) -- ignore errors end Super.Destroy(self) end function MultiCast:Refresh() Super.Refresh(self) self:UpdateAction() local bar = self.bar if bar.hasMulticast == true and self.idx <= bar.maxIndex or ReAction:GetConfigMode() then self:GetFrame():Show() else self:GetFrame():Hide() end end function MultiCast:ShowGrid( show ) end function MultiCast:ShowGridTemp( show ) end function MultiCast:AcquireActionID() end function MultiCast:ReleaseActionID() end function MultiCast:UpdateShowGrid() end function MultiCast:UpdateBorder() end function MultiCast:UpdateMacroText() end function MultiCast:UpdateCount() end function MultiCast:UpdateCheckedState() local action = self:GetActionID() if action and IsCurrentAction(action) then self:GetFrame():SetChecked(1) else self:GetFrame():SetChecked(0) end end function MultiCast:RefreshHasActionAttributes() end function MultiCast:UpdateFlash() end function MultiCast:GetIconTexture() local tx if self.spellID then tx = GetSpellTexture(GetSpellInfo(self.spellID)) elseif self.actionID then tx = GetActionTexture(self.actionID) end if tx then return tx else return TOTEM_TEXTURE, unpack(SLOT_EMPTY_TCOORDS[self.totemSlot or 1]) end end function MultiCast:UpdateAction() local action = self:GetActionID() if action then if action ~= self.actionID then self.actionID = action self:UpdateAll() end else local spellID = self:GetSpellID() if spellID ~= self.spellID then self.spellID = spellID self:UpdateAll() end end end function MultiCast:GetActionID(page) return self:GetFrame():GetAttribute("action") end function MultiCast:GetSpellID(page) return self:GetFrame():GetAttribute("spell") end function MultiCast:SetActionID( id ) error("Can not set action ID of multicast buttons") end function MultiCast:SetTooltip() local barFrame = self:GetFrame() if GetCVar("UberTooltips") == "1" then GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) else GameTooltip:SetOwner(barFrame) end if self.spellID then GameTooltip:SetSpellByID(self.spellID,false,true) elseif self.actionID then GameTooltip:SetAction(self.actionID) end end function MultiCast:GetUsable() if self.spellID then return IsUsableSpell((GetSpellInfo(self.spellID))) elseif self.actionID then return IsUsableAction(self.actionID) end end function MultiCast:GetInRange() if self.spellID then return IsSpellInRange((GetSpellInfo(self.spellID))) == 0 elseif self.actionID then return IsActionInRange(self.actionID) == 0 end end function MultiCast:GetCooldown() if self.spellID then return GetSpellCooldown((GetSpellInfo(self.spellID))) elseif self.actionID then return GetActionCooldown(self.actionID) else return 0, 0, 0 end end function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR() self:UpdateAll() end -- -- flyout setup -- local function ShowFlyoutTooltip(frame) if GetCVar("UberTooltips") == "1" then GameTooltip_SetDefaultAnchor(GameTooltip, frame) else GameTooltip:SetOwner(frame) end local spell = frame:GetAttribute("spell") if spell == nil or spell == 0 then GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) else GameTooltip:SetSpellByID(spell,false,true) end end local function HideFlyoutTooltip() GameTooltip:Hide() end local function UpdateFlyoutIcon(frame) local spellID = frame:GetAttribute("spell") if spellID == 0 or spellID == nil then frame.icon:SetTexture(TOTEM_TEXTURE) local slot = tonumber(frame:GetAttribute("totemSlot")) or 1 frame.icon:SetTexCoord( unpack(SLOT_EMPTY_TCOORDS[slot]) ) else frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID))) frame.icon:SetTexCoord(0,1,0,1) end end function MultiCast:SetupBar( bar ) local slot = 0 local nTotemSlots = 0 local summonSlot = nil local recallSlot = nil -- figure out the capabilities of the character for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do if spell and IsSpellKnown(spell) then slot = 1 summonSlot = 1 end end for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do local totem = SHAMAN_TOTEM_PRIORITIES[i]; if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then nTotemSlots = nTotemSlots + 1 slot = slot + 1 end end slot = slot + 1 for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do if spell and IsSpellKnown(spell) then recallSlot = slot end end local maxIndex = nTotemSlots if summonSlot then maxIndex = maxIndex + 1 end if recallSlot then maxIndex = maxIndex + 1 end bar.hasMulticast = nTotemSlots > 0 bar.summonSlot = summonSlot bar.recallSlot = recallSlot bar.nTotemSlots = nTotemSlots bar.maxIndex = maxIndex if bar.hasMulticast == false then Super.SetupBar(self,bar) return -- no multicast capability end local f = bar:GetFrame() -- init bar secure environment f:SetAttribute("lastSummon", bar:GetConfig().lastSummon) f:SetAttribute("summonSlot", summonSlot) f:SetAttribute("recallSlot", recallSlot) f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE) f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS) for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do f:SetAttribute("TOTEM_PRIORITY_"..i,p) end f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage) function f:UpdateLastSummon(value) bar:GetConfig().lastSummon = value end -- create flyout container frame and close arrow local flyout = bar._flyoutFrame if not flyout then flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate") bar._flyoutFrame = flyout f:SetFrameRef("flyout",flyout) flyout.buttons = { } flyout:Hide() flyout:SetWidth(24) flyout:SetHeight(1) flyout:SetPoint("BOTTOM",f,"TOP",0,0) local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate") close:SetWidth(28) close:SetHeight(18) close:SetPoint("BOTTOM",flyout,"TOP") close:SetNormalTexture(TOTEM_TEXTURE) close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS["summon"])) close:SetHighlightTexture(TOTEM_TEXTURE) close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) ) f:SetFrameRef("close",close) f:WrapScript(close, "OnClick", _closeFlyout) close:Show() local midTx = flyout:CreateTexture("BACKGROUND") midTx:SetWidth(32) midTx:SetHeight(20) midTx:SetPoint("BOTTOM") midTx:SetTexture(TOTEM_TEXTURE) midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS["summon"])) midTx:Show() local topTx = flyout:CreateTexture("BACKGROUND") topTx:SetWidth(32) topTx:SetHeight(20) topTx:SetTexture(TOTEM_TEXTURE) midTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS["summon"])) topTx:SetPoint("BOTTOM",midTx,"TOP",0,-10) topTx:Show() function flyout:UpdateTextures(slot) slot = slot or "summon" close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS[slot])) midTx:ClearAllPoints() midTx:SetPoint("BOTTOM") midTx:SetPoint("TOP",close,"BOTTOM",0,0) midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS[slot])) topTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS[slot])) end -- create flyout buttons for i = 1, 10 do -- maximum 9 spells + 1 empty slot local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate") b:SetWidth(24) b:SetHeight(24) local prev = flyout.buttons[i-1] b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring b.icon = b:CreateTexture("BACKGROUND") b.icon:SetAllPoints() b.icon:Show() b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") b:GetHighlightTexture():SetBlendMode("ADD") b:EnableMouse(true) b:RegisterForClicks(bar:GetConfig().clickDown and "AnyDown" or "AnyUp") b:SetScript("OnShow",UpdateFlyoutIcon) b:SetScript("OnEnter",ShowFlyoutTooltip) b:SetScript("OnLeave",HideFlyoutTooltip) b:SetAttribute("index",i) f:SetAttribute("flyout-child-idx",i) f:SetFrameRef("flyout-child",b) f:Execute([[ flyoutChildren = flyoutChildren or newtable() flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child") ]]) f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick) b:Show() flyout.buttons[i] = b end end -- scale flyout frame local scale = bar:GetButtonSize() / 36 flyout:SetScale(scale) function f:UpdateFlyoutTextures(slot) flyout:UpdateTextures(slot) end -- re-execute setup when new spells are loaded if not f.events_registered then f:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR") f:RegisterEvent("PLAYER_ENTERING_WORLD") -- Bar.frame does not use OnEvent f:SetScript("OnEvent", function() if not InCombatLockdown() then self:SetupBar(bar) end end) f.events_registered = true end f:Execute(_bar_init) Super.SetupBar(self,bar) -- create buttons after this is done end