-- globals
MULTICASTACTIONBAR_SLIDETIME = 0.09;
MULTICASTACTIONBAR_YPOS = 0;
MULTICASTACTIONBAR_XPOS = 30;
NUM_MULTI_CAST_PAGES = 3;
NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4; -- NOTE: must match MAX_TOTEMS!!!
-- locals
local MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET = 4;
local MULTI_CAST_FLYOUT_BUTTON_OFFSET = 2;
local MULTI_CAST_FLYOUT_CLOSE_SEC = 3;
local SLOT_EMPTY_TCOORDS = {
[EARTH_TOTEM_SLOT] = {
left = 66 / 128,
right = 96 / 128,
top = 3 / 256,
bottom = 33 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 67 / 128,
right = 97 / 128,
top = 100 / 256,
bottom = 130 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 39 / 128,
right = 69 / 128,
top = 209 / 256,
bottom = 239 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 66 / 128,
right = 96 / 128,
top = 36 / 256,
bottom = 66 / 256,
},
};
local SLOT_OVERLAY_TCOORDS = {
[EARTH_TOTEM_SLOT] = {
left = 1 / 128,
right = 35 / 128,
top = 172 / 256,
bottom = 206 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 36 / 128,
right = 70 / 128,
top = 172 / 256,
bottom = 206 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 1 / 128,
right = 35 / 128,
top = 207 / 256,
bottom = 240 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 36 / 128,
right = 70 / 128,
top = 137 / 256,
bottom = 171 / 256,
},
};
local FLYOUT_UP_BUTTON_TCOORDS = {
["summon"] = {
left = 99 / 128,
right = 127 / 128,
top = 84 / 256,
bottom = 102 / 256,
},
[EARTH_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 160 / 256,
bottom = 178 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 122 / 256,
bottom = 140 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 199 / 256,
bottom = 217 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 237 / 256,
bottom = 255 / 256,
},
};
local FLYOUT_DOWN_BUTTON_TCOORDS = {
["summon"] = {
left = 99 / 128,
right = 127 / 128,
top = 65 / 256,
bottom = 83 / 256,
},
[EARTH_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 141 / 256,
bottom = 159 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 103 / 256,
bottom = 121 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 180 / 256,
bottom = 198 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 99 / 128,
right = 127 / 128,
top = 218 / 256,
bottom = 236 / 256,
},
};
local FLYOUT_TOP_TCOORDS = {
["summon"] = {
left = 33 / 128,
right = 65 / 128,
top = 1 / 256,
bottom = 23 / 256,
},
[EARTH_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 46 / 256,
bottom = 68 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 33 / 128,
right = 65 / 128,
top = 46 / 256,
bottom = 68 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 1 / 256,
bottom = 23 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 91 / 256,
bottom = 113 / 256,
},
};
local FLYOUT_MIDDLE_TCOORDS = {
["summon"] = {
left = 33 / 128,
right = 65 / 128,
top = 23 / 256,
bottom = 43 / 256,
},
[EARTH_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 68 / 256,
bottom = 88 / 256,
},
[FIRE_TOTEM_SLOT] = {
left = 33 / 128,
right = 65 / 128,
top = 68 / 256,
bottom = 88 / 256,
},
[WATER_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 23 / 256,
bottom = 43 / 256,
},
[AIR_TOTEM_SLOT] = {
left = 0 / 128,
right = 32 / 128,
top = 113 / 256,
bottom = 133 / 256,
},
};
-- knownMultiCastSummonSpells
-- index: TOTEM_MULTI_CAST_SUMMON_SPELLS
-- value: spellId if the spell is known, nil otherwise
local knownMultiCastSummonSpells = { };
-- knownMultiCastRecallSpells
-- index: TOTEM_MULTI_CAST_RECALL_SPELLS
-- value: spellId if the spell is known, nil otherwise
local knownMultiCastRecallSpells = { };
local function _ComputeMultiCastSlot(id)
return mod(id - 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE) + 1;
end
--
-- MultiCastActionBar
--
function MultiCastActionBarFrame_OnLoad(self)
self:RegisterEvent("PLAYER_ENTERING_WORLD");
self:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR");
self.currentPage = 1;
MultiCastSummonSpellButton:SetID(self.currentPage);
self.numActiveSlots = 0;
end
function MultiCastActionBarFrame_OnEvent(self, event, ...)
if ( event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_MULTI_CAST_ACTIONBAR" ) then
MultiCastActionBarFrame_Update(self);
if ( HasMultiCastActionBar() ) then
ShowMultiCastActionBar();
LockMultiCastActionBar();
else
UnlockMultiCastActionBar();
HideMultiCastActionBar();
end
end
end
function MultiCastActionBarFrame_OnUpdate(self, elapsed)
local yPos;
if ( self.slideTimer and (self.slideTimer < self.timeToSlide) ) then
self.completed = false;
if ( self.mode == "show" ) then
yPos = (self.slideTimer/self.timeToSlide) * MULTICASTACTIONBAR_YPOS;
self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, yPos);
self.state = "showing";
self:Show();
elseif ( self.mode == "hide" ) then
yPos = (1 - (self.slideTimer/self.timeToSlide)) * MULTICASTACTIONBAR_YPOS;
self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, yPos);
self.state = "hiding";
end
self.slideTimer = self.slideTimer + elapsed;
else
self.completed = true;
if ( self.mode == "show" ) then
self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, MULTICASTACTIONBAR_YPOS);
self.state = "top";
--Move the chat frame and edit box up a bit
elseif ( self.mode == "hide" ) then
self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, 0);
self.state = "bottom";
self:Hide();
--Move the chat frame and edit box back down to original position
end
self.mode = "none";
end
end
function ShowMultiCastActionBar(doNotSlide)
if ( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) then --Don't change while we're animating out MainMenuBar for vehicle UI
if ( (MultiCastActionBarFrame.mode ~= "show" and MultiCastActionBarFrame.state ~= "top") or (not UIParent:IsShown())) then
MultiCastActionBarFrame:Show();
if ( MultiCastActionBarFrame.completed ) then
MultiCastActionBarFrame.slideTimer = 0;
end
MultiCastActionBarFrame.timeToSlide = MULTICASTACTIONBAR_SLIDETIME;
MultiCastActionBarFrame.mode = "show";
end
end
end
function HideMultiCastActionBar()
if ( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) then --Don't change while we're animating out MainMenuBar for vehicle UI
if ( (MultiCastActionBarFrame:IsShown()) or (not UIParent:IsShown())) then
if ( MultiCastActionBarFrame.completed ) then
MultiCastActionBarFrame.slideTimer = 0;
end
MultiCastActionBarFrame.timeToSlide = MULTICASTACTIONBAR_SLIDETIME;
MultiCastActionBarFrame.mode = "hide";
end
end
end
function LockMultiCastActionBar()
MultiCastActionBarFrame.locked = true;
end
function UnlockMultiCastActionBar()
MultiCastActionBarFrame.locked = false;
end
function MultiCastActionBarFrame_Update(self)
local currentPage = self.currentPage;
-- update the action buttons and slot buttons
local slot;
local actionButton, slotButton;
local actionIndex;
local slotIndex = 1;
local inverseSlotIndex;
local pageOffset;
local actionId;
for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
slot = SHAMAN_TOTEM_PRIORITIES[i];
if ( GetTotemInfo(slot) and GetMultiCastTotemSpells(slot) ) then
-- update the slot button
slotButton = _G["MultiCastSlotButton"..slotIndex];
MultiCastSlotButton_Update(slotButton, slot);
-- update the action buttons using this totem slot on each page
for j = 1, NUM_MULTI_CAST_PAGES do
pageOffset = (j-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE;
actionIndex = pageOffset + slotIndex;
actionButton = _G["MultiCastActionButton"..actionIndex];
actionButton.slotButton = slotButton;
actionId = pageOffset + slot;
MultiCastActionButton_Update(actionButton, actionId, actionIndex, slot);
-- if this is the current page, store a reference to the action button on the slot button
if ( j == currentPage ) then
slotButton.actionButton = actionButton;
end
end
slotIndex = slotIndex + 1;
else
inverseSlotIndex = NUM_MULTI_CAST_BUTTONS_PER_PAGE - i + slotIndex;
-- hide the slot button
slotButton = _G["MultiCastSlotButton"..inverseSlotIndex];
MultiCastSlotButton_Update(slotButton, 0);
-- hide the action buttons for this button index on each page
for j = 1, NUM_MULTI_CAST_PAGES do
pageOffset = (j-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE;
actionIndex = pageOffset + inverseSlotIndex;
actionButton = _G["MultiCastActionButton"..actionIndex];
actionButton.slotButton = nil;
actionId = pageOffset + slot;
MultiCastActionButton_Update(actionButton, actionId, actionIndex, 0);
end
slotButton.actionButton = nil;
end
end
self.numActiveSlots = slotIndex - 1;
if ( self.numActiveSlots == 0 ) then
self:Hide();
return;
end
self:Show();
-- update the multi cast spells
MultiCastSummonSpellButton_Update(MultiCastSummonSpellButton);
MultiCastRecallSpellButton_Update(MultiCastRecallSpellButton);
end
function HasMultiCastActionBar()
return MultiCastActionBarFrame.numActiveSlots and MultiCastActionBarFrame.numActiveSlots > 0;
end
function HasMultiCastActionPage(page)
return ( page >= 1 and page <= NUM_MULTI_CAST_PAGES and knownMultiCastSummonSpells[page] );
end
function ChangeMultiCastActionPage(page)
local prevPage = MultiCastActionBarFrame.currentPage;
if ( page ~= prevPage and HasMultiCastActionPage(page) ) then
MultiCastActionBarFrame.currentPage = page;
MultiCastSummonSpellButton:SetID(page);
_G["MultiCastActionPage"..prevPage]:Hide();
_G["MultiCastActionPage"..page]:Show();
MultiCastActionBarFrame_Update(MultiCastActionBarFrame);
end
end
--
-- MultiCastSlotButton
--
function MultiCastSlotButton_OnEvent(self, event, ...)
if ( event == "MODIFIER_STATE_CHANGED" ) then
if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
MultiCastSlotButton_OnEnter(self);
end
end
end
function MultiCastSlotButton_OnEnter(self)
if ( MultiCastFlyoutFrame.parent ~= self ) then
MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, "slot", self);
end
--[[
self:RegisterEvent("MODIFIER_STATE_CHANGED");
if ( IsModifiedClick("SHOWMULTICASTFLYOUT") ) then
local slot = self:GetID();
MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, "slot", self);
end
--]]
end
function MultiCastSlotButton_OnLeave(self)
GameTooltip:Hide();
MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
end
function MultiCastSlotButton_Update(self, slot)
self:SetID(slot);
if ( slot == 0 ) then
self:Hide();
else
-- fixup textures
local tcoords = SLOT_OVERLAY_TCOORDS[slot];
self.overlayTex:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
tcoords = SLOT_EMPTY_TCOORDS[slot];
self.background:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
self:Show();
end
end
--
-- MultiCastActionButton
--
function MultiCastActionButton_OnLoad(self)
-- fixup textures
local name = self:GetName();
local normalTexture = _G[name.."NormalTexture"];
normalTexture:SetWidth(50);
normalTexture:SetHeight(50);
-- setup action button stuff
self.buttonType = "MULTICASTACTIONBUTTON";
self.buttonIndex = self:GetID();
ActionButton_OnLoad(self);
end
function MultiCastActionButton_OnEvent(self, event, ...)
ActionButton_OnEvent(self, event, ...);
if ( event == "MODIFIER_STATE_CHANGED" ) then
if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
MultiCastActionButton_OnEnter(self);
end
end
end
function MultiCastActionButton_OnShow(self)
if ( not self.slotButton ) then
self:Hide();
end
end
function MultiCastActionButton_OnEnter(self)
MultiCastSlotButton_OnEnter(self.slotButton);
ActionButton_SetTooltip(self);
end
function MultiCastActionButton_OnLeave(self)
GameTooltip:Hide();
MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
end
function MultiCastActionButton_OnPostClick(self, button, down)
ActionButton_UpdateState(self, button, down);
MultiCastFlyoutFrame_Hide(MultiCastFlyoutFrame, true);
end
function MultiCastActionButton_Update(self, id, index, slot)
self:SetID(id);
self.buttonIndex = index;
if ( slot == 0 ) then
self:Hide();
else
ActionButton_UpdateAction(self);
ActionButton_Update(self);
ActionButton_UpdateHotkeys(self, self.buttonType);
-- fixup textures
local tcoords;
tcoords = SLOT_OVERLAY_TCOORDS[slot];
self.overlayTex:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
self:Show();
end
end
function MultiCastActionButtonDown(id)
local button = _G["MultiCastActionButton"..id];
if ( button:GetButtonState() == "NORMAL" ) then
button:SetButtonState("PUSHED");
end
if (GetCVarBool("ActionButtonUseKeyDown")) then
SecureActionButton_OnClick(button, "LeftButton");
ActionButton_UpdateState(button);
end
end
function MultiCastActionButtonUp(id)
local button = _G["MultiCastActionButton"..id];
if ( button:GetButtonState() == "PUSHED" ) then
button:SetButtonState("NORMAL");
if (not GetCVarBool("ActionButtonUseKeyDown")) then
SecureActionButton_OnClick(button, "LeftButton");
ActionButton_UpdateState(button);
end
end
MultiCastFlyoutFrame_Hide(MultiCastFlyoutFrame, true);
end
--
-- MultiCastFlyoutButton
--
function MultiCastFlyoutButton_OnLoad(self)
self:RegisterForClicks("AnyUp");
local parent = self:GetParent();
tinsert(parent.buttons, self);
end
function MultiCastFlyoutButton_OnClick(self)
local parent = self:GetParent();
if ( self.spellId ) then
local type = parent.type;
if ( type == "page" ) then
ChangeMultiCastActionPage(self.page);
elseif ( type == "slot" ) then
SetMultiCastSpell(ActionButton_CalculateAction(parent.parent.actionButton), self.spellId);
end
end
MultiCastFlyoutFrame_Hide(parent, true);
end
function MultiCastFlyoutButton_OnEnter(self)
MultiCastFlyoutButton_SetTooltip(self);
end
function MultiCastFlyoutButton_OnLeave(self)
GameTooltip:Hide();
end
function MultiCastFlyoutButton_SetTooltip(self)
if ( self.spellId ) then
if ( self.spellId == 0 ) then
if ( GetCVarBool("UberTooltips") ) then
GameTooltip_SetDefaultAnchor(GameTooltip, self);
else
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
end
GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
self.UpdateTooltip = nil;
else
if ( GetCVarBool("UberTooltips") ) then
GameTooltip_SetDefaultAnchor(GameTooltip, self);
else
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
end
if ( GameTooltip:SetSpellByID(self.spellId, false, true) ) then
self.UpdateTooltip = MultiCastFlyoutButton_SetTooltip;
else
self.UpdateTooltip = nil;
end
end
end
end
--
-- MultiCastFlyoutFrame
--
function MultiCastFlyoutFrame_OnShow(self)
MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton, true);
end
function MultiCastFlyoutFrame_OnHide(self)
self.type = nil;
self.parent = nil;
end
function MultiCastFlyoutFrame_OnEnter(self)
end
function MultiCastFlyoutFrame_OnLeave(self)
--[[
if ( not self:IsMouseOver() ) then
self.closeCountdownSec = MULTI_CAST_FLYOUT_CLOSE_SEC;
end
--]]
end
function MultiCastFlyoutFrame_OnUpdate(self, elapsed)
--[[
local closeCountdownSec = self.closeCountdownSec;
if ( closeCountdownSec ) then
closeCountdownSec = closeCountdownSec - elapsed;
if ( closeCountdownSec <= 0 ) then
self.closeCountdownSec = nil;
self:Hide();
else
self.closeCountdownSec = closeCountdownSec;
end
end
--]]
end
function MultiCastFlyoutFrame_Hide(self, forceHide)
if ( forceHide or not self:IsMouseOver() ) then
if ( self.parent ) then
if ( self.parent:IsMouseOver() ) then
MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, self.type, self.parent);
else
self.parent:UnregisterEvent("MODIFIER_STATE_CHANGED");
end
end
self:Hide();
end
end
function MultiCastFlyoutFrame_ToggleFlyout(self, type, parent)
if ( self:IsShown() and self.parent == parent ) then
MultiCastFlyoutFrame_Hide(self, true);
else
local toptcoords;
local midtcoords;
local closetcoords;
if ( type == "slot" ) then
local actionId = parent:GetID();
local slot = _ComputeMultiCastSlot(actionId);
if ( MultiCastFlyoutFrame_LoadSlotSpells(self, slot, GetMultiCastTotemSpells(actionId)) ) then
toptcoords = FLYOUT_TOP_TCOORDS[slot];
midtcoords = FLYOUT_MIDDLE_TCOORDS[slot];
closetcoords = FLYOUT_DOWN_BUTTON_TCOORDS[slot];
end
elseif ( type == "page" ) then
if ( MultiCastFlyoutFrame_LoadPageSpells(self) ) then
toptcoords = FLYOUT_TOP_TCOORDS["summon"];
midtcoords = FLYOUT_MIDDLE_TCOORDS["summon"];
closetcoords = FLYOUT_DOWN_BUTTON_TCOORDS["summon"];
end
end
if ( toptcoords ) then
self.type = type;
self.parent = parent;
self:SetPoint("BOTTOM", parent, "TOP", 0, 0);
self:Show();
self.top:SetTexCoord(toptcoords.left, toptcoords.right, toptcoords.top, toptcoords.bottom);
self.middle:SetTexCoord(midtcoords.left, midtcoords.right, midtcoords.top, midtcoords.bottom);
MultiCastFlyoutFrameCloseButton.normalTexture:SetTexCoord(closetcoords.left, closetcoords.right, closetcoords.top, closetcoords.bottom);
end
end
end
function MultiCastFlyoutFrame_LoadPageSpells(self)
local numKnownSpells = 0;
for i, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
if ( knownMultiCastSummonSpells[i] ) then
numKnownSpells = numKnownSpells + 1;
end
end
if ( numKnownSpells == 0 ) then
return false;
end
self.buttons = self.buttons or {};
local buttons = self.buttons;
local numButtons = #buttons;
local name = self:GetName();
local totalHeight = 0;
local button;
local spellId;
local name, rank, icon;
local buttonIndex = 1;
for i, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
if ( knownMultiCastSummonSpells[i] ) then
-- create the button
if ( buttonIndex <= numButtons ) then
button = buttons[buttonIndex];
if ( buttonIndex == 1 ) then
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
else
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
end
else
button = CreateFrame("Button", "MultiCastFlyoutButton"..buttonIndex, self, "MultiCastFlyoutButtonTemplate");
if ( buttonIndex == 1 ) then
-- this is the first button, anchor it to the frame
button:SetPoint("BOTTOM", self, "BOTTOM", 0, MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET);
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
else
-- this is not the first button, anchor it to the previous button
button:SetPoint("BOTTOM", buttons[buttonIndex - 1], "TOP", 0, MULTI_CAST_FLYOUT_BUTTON_OFFSET);
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
end
end
totalHeight = totalHeight + button:GetHeight();
-- setup the button
button.page = i;
spellId = TOTEM_MULTI_CAST_SUMMON_SPELLS[i];
button.spellId = spellId;
name, rank, icon = GetSpellInfo(spellId);
button.icon:SetTexture(icon);
button.icon:SetTexCoord(0.0, 1.0, 0.0, 1.0);
button:Show();
buttonIndex = buttonIndex + 1;
end
end
-- hide unused buttons
for i = buttonIndex, numButtons do
buttons[i]:Hide();
end
self:SetHeight(totalHeight + 2 + MultiCastFlyoutFrameCloseButton:GetHeight());
return true;
end
function MultiCastFlyoutFrame_LoadSlotSpells(self, slot, ...)
local numSpells = select("#", ...);
if ( numSpells == 0 ) then
return false;
end
-- add one to numSpells to represent the "none" slot
numSpells = numSpells + 1;
self.buttons = self.buttons or {};
local buttons = self.buttons;
local numButtons = #buttons;
local name = self:GetName();
local totalHeight = 0;
local button;
local spellId;
local name, rank, icon;
local tcoords;
local tcoordLeft, tcoordRight, tcoordTop, tcoordBottom;
for i = 1, numSpells do
-- create the button
if ( i <= numButtons ) then
button = buttons[i];
if ( i == 1 ) then
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
else
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
end
else
button = CreateFrame("Button", "MultiCastFlyoutButton"..i, self, "MultiCastFlyoutButtonTemplate");
button:ClearAllPoints();
if ( i == 1 ) then
-- this is the first button, anchor it to the frame
button:SetPoint("BOTTOM", self, "BOTTOM", 0, MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET);
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
else
-- this is not the first button, anchor it to the previous button
button:SetPoint("BOTTOM", buttons[i - 1], "TOP", 0, MULTI_CAST_FLYOUT_BUTTON_OFFSET);
totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
end
end
totalHeight = totalHeight + button:GetHeight();
-- setup the button
if ( i == 1 ) then
-- the first button clears your slot
spellId = 0;
icon = "Interface\\Buttons\\UI-TotemBar";
tcoords = SLOT_EMPTY_TCOORDS[slot];
tcoordLeft, tcoordRight, tcoordTop, tcoordBottom = tcoords.left, tcoords.right, tcoords.top, tcoords.bottom;
else
spellId = select(i - 1, ...);
name, rank, icon = GetSpellInfo(spellId);
tcoordLeft, tcoordRight, tcoordTop, tcoordBottom = 0.0, 1.0, 0.0, 1.0;
end
button.spellId = spellId;
button.icon:SetTexture(icon);
button.icon:SetTexCoord(tcoordLeft, tcoordRight, tcoordTop, tcoordBottom);
button:Show();
end
-- hide unused buttons
for i = numSpells + 1, numButtons do
buttons[i]:Hide();
end
self:SetHeight(totalHeight + 2 + MultiCastFlyoutFrameCloseButton:GetHeight());
return true;
end
--
-- MultiCastFlyoutFrameCloseButton
--
function MultiCastFlyoutFrameCloseButton_OnClick(self)
self:GetParent():Hide();
end
--
-- MultiCastFlyoutFrameOpenButton
--
function MultiCastFlyoutFrameOpenButton_OnClick(self)
MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, self.type, self.parent);
end
function MultiCastFlyoutFrameOpenButton_OnLeave(self)
self:Hide();
end
function MultiCastFlyoutFrameOpenButton_Show(self, type, parent)
local tcoords;
if ( type == "page" ) then
tcoords = FLYOUT_UP_BUTTON_TCOORDS["summon"];
elseif ( type == "slot" ) then
local slot = _ComputeMultiCastSlot(parent:GetID());
tcoords = FLYOUT_UP_BUTTON_TCOORDS[slot];
end
if ( tcoords ) then
self.normalTexture:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
self.type = type;
self.parent = parent;
self:SetParent(parent);
self:SetPoint("BOTTOM", parent, "TOP", 0, 0);
self:Show();
end
end
function MultiCastFlyoutFrameOpenButton_Hide(self, force)
if ( force or (not self:IsMouseOver() and not self.parent:IsMouseOver()) ) then
self.type = nil;
self:Hide();
end
end
--
-- MultiCastSpellButton
--
function MultiCastSpellButton_OnLoad(self)
self:RegisterForClicks("AnyUp");
local name = self:GetName();
local normalTexture = _G[name.."NormalTexture"];
normalTexture:SetWidth(50);
normalTexture:SetHeight(50);
end
function MultiCastSpellButton_OnEvent(self, event, ...)
if ( event == "UPDATE_BINDINGS" ) then
ActionButton_UpdateHotkeys(self, self.buttonType);
elseif ( event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
MultiCastSpellButton_UpdateCooldown(self);
elseif ( event == "ACTIONBAR_UPDATE_STATE" ) then
MultiCastSpellButton_UpdateState(self);
end
end
function MultiCastSpellButton_OnEnter(self)
MultiCastSpellButton_SetTooltip(self);
end
function MultiCastSpellButton_OnLeave(self)
GameTooltip:Hide();
end
function MultiCastSpellButton_SetTooltip(self)
if ( GetCVarBool("UberTooltips") ) then
GameTooltip_SetDefaultAnchor(GameTooltip, self);
else
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
end
if ( GameTooltip:SetSpellByID(self.spellId, false, true) ) then
self.UpdateTooltip = MultiCastSpellButton_SetTooltip;
else
self.UpdateTooltip = nil;
end
end
function MultiCastSpellButton_UpdateCooldown(self)
local cooldown = _G[self:GetName().."Cooldown"];
local start, duration, enable = GetSpellCooldown(self.spellId);
CooldownFrame_SetTimer(cooldown, start, duration, enable);
end
function MultiCastSpellButton_UpdateState(self)
if ( IsCurrentSpell(self.spellId) ) then
self:SetChecked(1);
else
self:SetChecked(nil);
end
end
--
-- MultiCastSummonSpellButton
--
function MultiCastSummonSpellButton_OnLoad(self)
self.buttonType = "MULTICASTSUMMONBUTTON";
MultiCastSpellButton_OnLoad(self);
end
function MultiCastSummonSpellButton_OnEvent(self, event, ...)
MultiCastSpellButton_OnEvent(self, event, ...);
--[[
if ( event == "MODIFIER_STATE_CHANGED" ) then
if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
MultiCastSummonSpellButton_OnEnter(self);
end
end
--]]
end
function MultiCastSummonSpellButton_OnClick(self)
MultiCastSummonSpellButtonUp(self:GetID());
end
function MultiCastSummonSpellButton_OnEnter(self)
MultiCastSpellButton_OnEnter(self);
if ( MultiCastFlyoutFrame.parent ~= self ) then
MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, "page", self);
end
--[[
self:RegisterEvent("MODIFIER_STATE_CHANGED");
if ( IsModifiedClick("SHOWMULTICASTFLYOUT") ) then
MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, "page", self);
end
--]]
end
function MultiCastSummonSpellButton_OnLeave(self)
MultiCastSpellButton_OnLeave(self);
MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
end
function MultiCastSummonSpellButton_Update(self)
-- first update which multi-cast spells we actually know
for index, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
knownMultiCastSummonSpells[index] = (IsSpellKnown(spellId) and spellId) or nil;
end
-- update the spell button
local spellId = knownMultiCastSummonSpells[self:GetID()];
self.spellId = spellId;
if ( HasMultiCastActionBar() and spellId ) then
local name, rank, icon, cost, isFunnel, powerType, castTime, minRage, maxRange = GetSpellInfo(spellId);
local buttonName = self:GetName();
_G[buttonName.."Icon"]:SetTexture(icon);
if ( not self.eventsRegistered ) then
self:RegisterEvent("UPDATE_BINDINGS");
self:RegisterEvent("ACTIONBAR_UPDATE_STATE");
self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
self.eventsRegistered = true;
end
ActionButton_UpdateHotkeys(self, self.buttonType);
MultiCastSpellButton_UpdateCooldown(self);
if ( GameTooltip:GetOwner() == self ) then
MultiCastSpellButton_SetTooltip(self);
end
-- reanchor the first slot button take make room for this button
local width = self:GetWidth();
local xOffset = width + 8 + 3;
local page;
for i = 1, NUM_MULTI_CAST_PAGES do
page = _G["MultiCastActionPage"..i];
page:SetPoint("BOTTOMLEFT", page:GetParent(), "BOTTOMLEFT", xOffset, 3);
end
MultiCastSlotButton1:SetPoint("BOTTOMLEFT", self:GetParent(), "BOTTOMLEFT", xOffset, 3);
self:Show();
else
if ( self.eventsRegistered ) then
self:UnregisterEvent("UPDATE_BINDINGS");
self:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
self.eventsRegistered = false;
end
-- reanchor the first slot button take the place of this button
local xOffset = 3;
local page;
for i = 1, NUM_MULTI_CAST_PAGES do
page = _G["MultiCastActionPage"..i];
page:SetPoint("BOTTOMLEFT", page:GetParent(), "BOTTOMLEFT", xOffset, 3);
end
MultiCastSlotButton1:SetPoint("BOTTOMLEFT", self:GetParent(), "BOTTOMLEFT", xOffset, 3);
self:Hide();
end
end
function MultiCastSummonSpellButtonUp(id)
CastSpellByID(TOTEM_MULTI_CAST_SUMMON_SPELLS[id]);
end
--
-- MultiCastRecallSpellButton
--
function MultiCastRecallSpellButton_OnLoad(self)
self.buttonType = "MULTICASTRECALLBUTTON";
MultiCastSpellButton_OnLoad(self);
end
function MultiCastRecallSpellButton_OnClick(self)
MultiCastRecallSpellButtonUp(self:GetID());
end
function MultiCastRecallSpellButton_Update(self)
-- first update which multi-cast spells we actually know
for index, spellId in next, TOTEM_MULTI_CAST_RECALL_SPELLS do
knownMultiCastRecallSpells[index] = (IsSpellKnown(spellId) and spellId) or nil;
end
-- update the spell button
local spellId = knownMultiCastRecallSpells[self:GetID()];
self.spellId = spellId;
if ( HasMultiCastActionBar() and spellId ) then
local name, rank, icon, cost, isFunnel, powerType, castTime, minRage, maxRange = GetSpellInfo(spellId);
local buttonName = self:GetName();
_G[buttonName.."Icon"]:SetTexture(icon);
if ( not self.eventsRegistered ) then
self:RegisterEvent("UPDATE_BINDINGS");
self:RegisterEvent("ACTIONBAR_UPDATE_STATE");
self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
self.eventsRegistered = true;
end
ActionButton_UpdateHotkeys(self, self.buttonType);
MultiCastSpellButton_UpdateCooldown(self);
if ( GameTooltip:GetOwner() == self ) then
MultiCastSpellButton_SetTooltip(self);
end
-- anchor to the last shown slot
local activeSlots = MultiCastActionBarFrame.numActiveSlots;
if ( activeSlots > 0 ) then
self:SetPoint("LEFT", _G["MultiCastSlotButton"..activeSlots], "RIGHT", 8, 0);
end
self:Show();
else
if ( self.eventsRegistered ) then
self:UnregisterEvent("UPDATE_BINDINGS");
self:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
self.eventsRegistered = false;
end
self:Hide();
end
end
function MultiCastRecallSpellButtonUp(id)
CastSpellByID(TOTEM_MULTI_CAST_RECALL_SPELLS[id]);
end