You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1289 lines
41 KiB
1289 lines
41 KiB
local _, addon = ...
|
|
local L = addon.L;
|
|
local API = addon.API;
|
|
local UIFrameFade = API.UIFrameFade;
|
|
local GetDBBool = addon.GetDBBool;
|
|
|
|
|
|
local ACTION_BUTTON_SIZE = 46;
|
|
local ACTION_BUTTON_GAP = 4;
|
|
local REPOSITION_BUTTON_OFFSET = 46;
|
|
|
|
|
|
local GetItemCooldown = C_Container.GetItemCooldown;
|
|
local UnitCastingInfo = UnitCastingInfo;
|
|
local UnitChannelInfo = UnitChannelInfo;
|
|
local InCombatLockdown = InCombatLockdown;
|
|
local GetCursorPosition = GetCursorPosition;
|
|
local math = math;
|
|
local UIParent = UIParent;
|
|
local CreateFrame = CreateFrame;
|
|
local tinsert = table.insert;
|
|
local atan2 = math.atan2;
|
|
local ipairs = ipairs;
|
|
|
|
|
|
local QuickSlot = CreateFrame("Frame", nil, UIParent);
|
|
do --QuickSlot "OnLoad"
|
|
addon.QuickSlot = QuickSlot;
|
|
QuickSlot:Hide();
|
|
QuickSlot:SetSize(46, 46);
|
|
QuickSlot:SetAlpha(0);
|
|
QuickSlot:SetFrameStrata("HIGH");
|
|
QuickSlot.Buttons = {};
|
|
QuickSlot.ItemButtons = {};
|
|
QuickSlot.SpellButtons = {};
|
|
QuickSlot.numActiveButtons = 0;
|
|
QuickSlot.SpellXButton = {};
|
|
QuickSlot:SetClampedToScreen(true);
|
|
QuickSlot:SetClampRectInsets(-ACTION_BUTTON_SIZE, ACTION_BUTTON_SIZE, 8, -8);
|
|
end
|
|
|
|
local ContextMenu;
|
|
|
|
local function ContextMenu_EditMode_OnClick(self, button)
|
|
QuickSlot:EnableEditMode(true);
|
|
return true
|
|
end
|
|
|
|
local function ContextMenu_HighContrast_OnClick(self, button)
|
|
local state = not GetDBBool("QuickSlotHighContrastMode");
|
|
addon.SetDBValue("QuickSlotHighContrastMode", state);
|
|
QuickSlot:UseHighContrast(state);
|
|
return false
|
|
end
|
|
|
|
local ContextMenuData = {
|
|
{text = L["Quick Slot Reposition"], onClickFunc = ContextMenu_EditMode_OnClick},
|
|
{text = L["Quick Slot High Contrast Mode"], onClickFunc = ContextMenu_HighContrast_OnClick,},
|
|
};
|
|
|
|
|
|
local Positioner = CreateFrame("Frame", nil, UIParent);
|
|
Positioner.alpha = 0;
|
|
Positioner:Hide();
|
|
Positioner:SetFrameStrata("BACKGROUND");
|
|
Positioner.buttonSize = 46; --Constant
|
|
Positioner.buttonGap = 8; --Constant
|
|
Positioner.fromRadian = 0; --User customizable
|
|
|
|
function Positioner:GetButtonGap()
|
|
--the gap between to round buttons
|
|
return 8
|
|
end
|
|
|
|
function Positioner:GetRadius()
|
|
return math.floor( (0.5 * UIParent:GetHeight()*16/9 /3) + (self.buttonSize*0.5) + 0.5 );
|
|
end
|
|
|
|
function Positioner:GetButtonCenterGap()
|
|
local radius = self:GetRadius();
|
|
local gapArc = self.buttonGap + self.buttonSize;
|
|
local radianGap = gapArc/radius;
|
|
return radianGap
|
|
end
|
|
|
|
function Positioner:GetButtonSpan(numActiveButtons)
|
|
return (self.buttonSize + self.buttonGap) * numActiveButtons - self.buttonGap;
|
|
end
|
|
|
|
function Positioner:GetCustomPosition()
|
|
if self.db then
|
|
return self.db.quickslot_PositionX, self.db.quickslot_PositionY
|
|
end
|
|
end
|
|
|
|
function Positioner:SetCustomPosition(x, y)
|
|
self.db.quickslot_PositionX = x;
|
|
self.db.quickslot_PositionY = y;
|
|
end
|
|
|
|
function Positioner:GetFromRadian()
|
|
return self.fromRadian
|
|
end
|
|
|
|
function Positioner:SetFromRadian(radian)
|
|
if not radian then return end;
|
|
|
|
local snappedRadian = math.rad(45);
|
|
|
|
if radian > snappedRadian then
|
|
radian = snappedRadian;
|
|
else
|
|
snappedRadian = math.rad(-60) + self:GetButtonRadianByIndex(-1);
|
|
if radian < snappedRadian then
|
|
radian = snappedRadian;
|
|
end
|
|
end
|
|
|
|
for i = 0, 1 do
|
|
snappedRadian = self:GetButtonRadianByIndex(i);
|
|
if radian < snappedRadian + 0.043 and radian > snappedRadian - 0.043 then
|
|
radian = snappedRadian;
|
|
end
|
|
end
|
|
|
|
self.fromRadian = radian;
|
|
|
|
if self.db then
|
|
self.db.quickslotFromRadian = radian;
|
|
end
|
|
end
|
|
|
|
function Positioner:GetEditButtonRadian()
|
|
local radius = self:GetRadius();
|
|
return self.fromRadian + (self.buttonSize)/radius;
|
|
end
|
|
|
|
function Positioner:GetButtonRadianByIndex(index)
|
|
local radius = self:GetRadius();
|
|
local gapArc = self.buttonGap + self.buttonSize;
|
|
local radianGap = gapArc/radius;
|
|
|
|
return (1 - index)*radianGap;
|
|
end
|
|
|
|
function Positioner:GetRadianPerButton()
|
|
local radius = self:GetRadius();
|
|
local radianPerButton = self.buttonSize/radius;
|
|
return radianPerButton
|
|
end
|
|
|
|
function Positioner:GetCastBar()
|
|
return _G["PlayerCastingBarFrame"]
|
|
end
|
|
|
|
function Positioner:OnUpdate_FadeIn(elapsed)
|
|
self.alpha = self.alpha + elapsed*5;
|
|
if self.alpha >= 1 then
|
|
self.alpha = 1;
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
self:SetAlpha(self.alpha);
|
|
end
|
|
|
|
function Positioner:FadeInGuideLine()
|
|
self:SetScript("OnUpdate", self.OnUpdate_FadeIn);
|
|
self.t = nil;
|
|
self:Show();
|
|
end
|
|
|
|
function Positioner:OnUpdate_FadeOut(elapsed)
|
|
if self.t < 0.5 then
|
|
self.t = self.t + elapsed;
|
|
return
|
|
end
|
|
|
|
self.alpha = self.alpha - elapsed*2;
|
|
if self.alpha <= 0 then
|
|
self.alpha = 0;
|
|
self.t = nil;
|
|
self:Hide();
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
self:SetAlpha(self.alpha);
|
|
end
|
|
|
|
function Positioner:FadeOutGuideLine()
|
|
if not self.t then
|
|
if self.alpha >= 0.8 then
|
|
self.t = 0;
|
|
else
|
|
self.t = 1; --no delay
|
|
end
|
|
end
|
|
self:SetScript("OnUpdate", self.OnUpdate_FadeOut);
|
|
end
|
|
|
|
function Positioner:ShowGuideLineCircle(state)
|
|
self.showingGuideLine = state;
|
|
if state then
|
|
if not self.GuideLineCircle then
|
|
self.GuideLineCircle = addon.CreateArc(self);
|
|
self.GuideLineCircle:SetThickness(2);
|
|
self.GuideLineCircle:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
|
|
|
|
local buttonRadian = self:GetRadianPerButton();
|
|
local toRdian = math.rad(-45.5) + buttonRadian*0.5;
|
|
local fromRadian = math.rad(30.5) - buttonRadian*0.5;
|
|
self.GuideLineCircle:SetToRadian(toRdian);
|
|
self.GuideLineCircle:SetFromRadian(fromRadian);
|
|
self.GuideLineCircle:SetAlpha(0.5);
|
|
|
|
--[[
|
|
local snappedRadian = math.rad(45);
|
|
|
|
if radian > snappedRadian then
|
|
radian = snappedRadian;
|
|
else
|
|
snappedRadian = math.rad(-60) + self:GetButtonRadianByIndex(-1);
|
|
if radian < snappedRadian then
|
|
radian = snappedRadian;
|
|
end
|
|
end
|
|
--]]
|
|
end
|
|
|
|
local radius = self:GetRadius();
|
|
self.GuideLineCircle:SetRadius(radius);
|
|
|
|
--self:Show();
|
|
self:FadeInGuideLine();
|
|
else
|
|
--self:Hide();
|
|
self:FadeOutGuideLine();
|
|
end
|
|
end
|
|
|
|
function Positioner:SetCircleMaskPosition(x, y)
|
|
if self.CircleMask2 then
|
|
self.CircleMask2:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y);
|
|
end
|
|
end
|
|
|
|
function Positioner:HideGuideLine()
|
|
self.showingGuideLine = false;
|
|
self:Hide();
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
|
|
|
|
local function RealActionButton_OnLeave(self)
|
|
if not InCombatLockdown() then
|
|
self:SetScript("OnLeave", nil);
|
|
self:Release();
|
|
end
|
|
|
|
if self.owner then
|
|
self.owner:UnlockHighlight();
|
|
self.owner:SetStateNormal();
|
|
self.owner.hasActionButton = nil;
|
|
self.owner = nil;
|
|
QuickSlot:SetHeaderText();
|
|
QuickSlot:StartShowingDefaultHeaderCountdown(true);
|
|
end
|
|
|
|
GameTooltip:Hide();
|
|
end
|
|
|
|
local function RealActionButton_PostClick(self, button)
|
|
local owner = self.owner;
|
|
|
|
if owner then
|
|
if owner.onClickFunc then
|
|
owner.onClickFunc();
|
|
end
|
|
|
|
if button == "LeftButton" and owner:HasCharges() then
|
|
owner:ShowPostClickEffect();
|
|
return
|
|
end
|
|
|
|
if button == "RightButton" then
|
|
if not ContextMenu then
|
|
ContextMenu = addon.GetSharedContextMenu();
|
|
end
|
|
local menu = ContextMenu;
|
|
if menu:IsShown() then
|
|
menu:CloseMenu();
|
|
return
|
|
end
|
|
menu:SetOwner(owner);
|
|
menu:ClearAllPoints();
|
|
menu:SetPoint("LEFT", owner, "RIGHT", 12, 0);
|
|
|
|
local menuData;
|
|
if QuickSlot.buttonData.developerInfo then
|
|
menuData = API.CopyTable(ContextMenuData);
|
|
tinsert(menuData, {
|
|
type = "divider",
|
|
});
|
|
tinsert(menuData, {
|
|
--type == "info",
|
|
color = {0.5, 0.5, 0.5},
|
|
text = L["Quickslot Module Info"];
|
|
tooltip = QuickSlot.buttonData.developerInfo,
|
|
});
|
|
else
|
|
menuData = ContextMenuData;
|
|
end
|
|
menu:SetContent(menuData);
|
|
menu:Show();
|
|
end
|
|
end
|
|
end
|
|
|
|
local function RealActionButton_OnMouseDown(self, button)
|
|
if self.owner then
|
|
if self.owner:HasCharges() then
|
|
self.owner:SetStatePushed();
|
|
end
|
|
end
|
|
end
|
|
|
|
local function RealActionButton_OnMouseUp(self)
|
|
if self.owner then
|
|
self.owner:SetStateNormal();
|
|
end
|
|
end
|
|
|
|
local function ItemButton_OnEnter(self)
|
|
if self.overrideName then
|
|
QuickSlot:SetHeaderText(self.overrideName);
|
|
else
|
|
if self.actionType == "item" then
|
|
QuickSlot:SetHeaderText(API.GetColorizedItemName(self.id));
|
|
elseif self.actionType == "spell" then
|
|
QuickSlot:SetHeaderText(C_Spell.GetSpellName(self.id));
|
|
end
|
|
end
|
|
|
|
QuickSlot:StartShowingDefaultHeaderCountdown(false);
|
|
|
|
local privateKey = "QuickSlot";
|
|
local RealActionButton = addon.AcquireSecureActionButton(privateKey);
|
|
|
|
if RealActionButton then
|
|
local w, h = self:GetSize();
|
|
RealActionButton:SetFrameStrata("DIALOG");
|
|
RealActionButton:SetFixedFrameStrata(true);
|
|
RealActionButton:SetScript("OnEnter", nil);
|
|
RealActionButton:SetScript("OnLeave", RealActionButton_OnLeave);
|
|
RealActionButton:SetScript("PostClick", RealActionButton_PostClick);
|
|
RealActionButton:SetScript("OnMouseDown", RealActionButton_OnMouseDown);
|
|
RealActionButton:SetScript("OnMouseUp", RealActionButton_OnMouseUp);
|
|
RealActionButton:ClearAllPoints();
|
|
RealActionButton:SetParent(self);
|
|
RealActionButton:SetSize(w, h);
|
|
RealActionButton:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
RealActionButton:Show();
|
|
RealActionButton.owner = self;
|
|
|
|
local macroText;
|
|
if self.onClickFunc then
|
|
|
|
elseif self.macroText then
|
|
macroText = self.macroText;
|
|
else
|
|
if self.actionType == "item" then
|
|
macroText = string.format("/use item:%s", self.id);
|
|
elseif self.actionType == "spell" then
|
|
local spellName = C_Spell.GetSpellName(self.id);
|
|
if spellName then
|
|
macroText = string.format("/cast %s", spellName);
|
|
end
|
|
end
|
|
end
|
|
RealActionButton:SetAttribute("type1", "macro");
|
|
RealActionButton:SetMacroText(macroText);
|
|
RealActionButton:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp");
|
|
|
|
self:LockHighlight();
|
|
self.hasActionButton = true;
|
|
end
|
|
|
|
if self.tooltipLines then
|
|
local tooltip = GameTooltip;
|
|
tooltip:Hide();
|
|
tooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
for i, text in ipairs(self.tooltipLines) do
|
|
if i == 1 then
|
|
tooltip:SetText(text, 1, 1, 1, true);
|
|
else
|
|
tooltip:AddLine(text, 1, 1, 1, true);
|
|
end
|
|
end
|
|
tooltip:Show();
|
|
end
|
|
end
|
|
|
|
local function ItemButton_OnLeave(self)
|
|
if not (self:IsVisible() and self:IsMouseOver()) then
|
|
QuickSlot:SetHeaderText();
|
|
QuickSlot:StartShowingDefaultHeaderCountdown(true);
|
|
GameTooltip:Hide();
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
function QuickSlot:Init()
|
|
Positioner.db = PlumberDB;
|
|
Positioner:SetFromRadian(Positioner.db.quickslotFromRadian);
|
|
self.side = 1;
|
|
|
|
local Header = self:CreateFontString(nil, "OVERLAY", "GameTooltipText");
|
|
self.Header = Header;
|
|
Header:SetJustifyH("CENTER");
|
|
Header:SetJustifyV("MIDDLE");
|
|
Header:SetPoint("BOTTOM", self, "TOP", 0, 8);
|
|
Header:SetSpacing(2);
|
|
|
|
local font, height = GameTooltipText:GetFont();
|
|
Header:SetFont(font, height, ""); --OUTLINE
|
|
Header:SetShadowColor(0, 0, 0);
|
|
Header:SetShadowOffset(1, -1);
|
|
|
|
--[[
|
|
local HeaderShadow = self:CreateTexture(nil, "ARTWORK");
|
|
HeaderShadow:SetPoint("TOPLEFT", Header, "TOPLEFT", -8, 6);
|
|
HeaderShadow:SetPoint("BOTTOMRIGHT", Header, "BOTTOMRIGHT", 8, -8);
|
|
HeaderShadow:SetTexture("Interface/AddOns/Plumber/Art/Button/GenericTextDropShadow");
|
|
HeaderShadow:Hide();
|
|
HeaderShadow:SetAlpha(0);
|
|
--]]
|
|
|
|
local HeaderShadow = self:CreateTexture(nil, "ARTWORK");
|
|
HeaderShadow:SetTexture("Interface/AddOns/Plumber/Art/Frame/SubtitleShadow_NineSlice_Darker");
|
|
HeaderShadow:SetTextureSliceMargins(30, 30, 30, 30);
|
|
HeaderShadow:SetTextureSliceMode(0);
|
|
HeaderShadow:Hide();
|
|
HeaderShadow:SetAlpha(0);
|
|
HeaderShadow:SetPoint("TOPLEFT", Header, "TOPLEFT", -20, 20);
|
|
HeaderShadow:SetPoint("BOTTOMRIGHT", Header, "BOTTOMRIGHT", 20, -20);
|
|
|
|
function QuickSlot:SetHeaderText(text, transparentText)
|
|
if self:IsInEditMode() then return end;
|
|
|
|
if text then
|
|
Header:SetSize(0, 0);
|
|
Header:SetText(text);
|
|
if transparentText then
|
|
local toAlpha = self.highContrastMode and 1.0 or 0.6;
|
|
UIFrameFade(Header, 0.5, toAlpha);
|
|
UIFrameFade(HeaderShadow, 0.25, 0);
|
|
else
|
|
API.UIFrameFadeIn(Header, 0.25);
|
|
UIFrameFade(HeaderShadow, 0.25, 1);
|
|
end
|
|
|
|
local textWidth = Header:GetWrappedWidth() - 2;
|
|
if textWidth > QuickSlot.headerMaxWidth then
|
|
Header:SetSize(QuickSlot.headerMaxWidth, 64);
|
|
local numLines = Header:GetNumLines();
|
|
Header:SetHeight(numLines*18);
|
|
textWidth = Header:GetWrappedWidth();
|
|
Header:SetWidth(textWidth + 2);
|
|
end
|
|
else
|
|
UIFrameFade(Header, 0.5, 0);
|
|
UIFrameFade(HeaderShadow, 0.25, 0);
|
|
end
|
|
end
|
|
|
|
self.SpellCastOverlay = addon.CreateActionButtonSpellCastOverlay(self);
|
|
self.SpellCastOverlay:Hide();
|
|
|
|
self.Init = nil;
|
|
end
|
|
|
|
local function ContainerFrame_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t > 1 then
|
|
self:SetScript("OnUpdate", nil);
|
|
self:SetHeaderText(self.defaultHeaderText, true);
|
|
end
|
|
end
|
|
|
|
function QuickSlot:SetDefaultHeaderText(text)
|
|
self.defaultHeaderText = text;
|
|
end
|
|
|
|
function QuickSlot:StartShowingDefaultHeaderCountdown(state)
|
|
if state and not self:IsInEditMode() then
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", ContainerFrame_OnUpdate);
|
|
else
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
end
|
|
|
|
function QuickSlot:SetButtonData(buttonData)
|
|
if buttonData == self.buttonData then
|
|
return
|
|
end
|
|
|
|
local privateKey = "QuickSlot";
|
|
addon.HideSecureActionButton(privateKey);
|
|
|
|
self.buttonData = buttonData;
|
|
self.systemName = buttonData.systemName;
|
|
self.layoutDirty = true;
|
|
self.anyItemAction = nil;
|
|
self.numActiveButtons = #buttonData.buttons;
|
|
self.spellcastType = buttonData.spellcastType;
|
|
self.SpellXButton = {};
|
|
self.ItemButtons = {};
|
|
self.SpellButtons = {};
|
|
|
|
local buttonSize = ACTION_BUTTON_SIZE;
|
|
local gap = ACTION_BUTTON_GAP;
|
|
local positionIndex = 0;
|
|
local trackIndex = 0;
|
|
|
|
local anyItemAction;
|
|
local anySpellAction;
|
|
|
|
for i, info in ipairs(buttonData.buttons) do
|
|
positionIndex = positionIndex + 1;
|
|
if info.spacer then
|
|
--Used as a spacer
|
|
|
|
elseif info.track then
|
|
--reset radian, reduce radius
|
|
positionIndex = 0;
|
|
trackIndex = trackIndex + 1;
|
|
else
|
|
local button = self.Buttons[i];
|
|
if not button then
|
|
button = addon.CreatePeudoActionButton(self);
|
|
tinsert(self.Buttons, button);
|
|
button:SetPoint("LEFT", self, "LEFT", (i - 1) * (buttonSize + gap), 0);
|
|
end
|
|
|
|
local spellID = info.spellID;
|
|
if spellID then
|
|
self.SpellXButton[spellID] = button;
|
|
end
|
|
|
|
if info.actionType == "item" then
|
|
anyItemAction = true;
|
|
button:SetItem(info.itemID, info.icon);
|
|
tinsert(self.ItemButtons, button);
|
|
elseif info.actionType == "spell" then
|
|
anySpellAction = true;
|
|
button:SetSpell(spellID, info.icon);
|
|
tinsert(self.SpellButtons, button);
|
|
end
|
|
|
|
button.spellID = spellID;
|
|
button.positionIndex = positionIndex;
|
|
button.trackIndex = trackIndex;
|
|
button.overrideName = info.name;
|
|
button.macroText = info.macroText;
|
|
button.onClickFunc = info.onClickFunc;
|
|
button.tooltipLines = info.tooltipLines;
|
|
button:SetScript("OnEnter", ItemButton_OnEnter);
|
|
button:SetScript("OnLeave", ItemButton_OnLeave);
|
|
button:Show();
|
|
|
|
if info.enabled ~= nil then
|
|
if info.enabled then
|
|
button:SetIconState(1);
|
|
else
|
|
button:SetIconState(2);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for i = self.numActiveButtons + 1, #self.Buttons do
|
|
self.Buttons[i]:Hide();
|
|
end
|
|
|
|
if self.numActiveButtons > 1 then
|
|
self.layoutIndex = 2;
|
|
else
|
|
self.layoutIndex = 1;
|
|
end
|
|
|
|
self.anyItemAction = anyItemAction;
|
|
self.anySpellAction = anySpellAction;
|
|
|
|
if anySpellAction then
|
|
self:RegisterEvent("SPELL_UPDATE_CHARGES");
|
|
self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
|
|
else
|
|
self:UnregisterEvent("SPELL_UPDATE_CHARGES");
|
|
self:UnregisterEvent("SPELL_UPDATE_COOLDOWN");
|
|
end
|
|
|
|
if not self.Init then
|
|
self:UpdateFrameLayout();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:SetButtonOrder(side)
|
|
if side ~= self.side then
|
|
self.side = side;
|
|
else
|
|
return
|
|
end
|
|
|
|
if not self.buttonData then
|
|
return
|
|
end
|
|
|
|
local items = self.itemData;
|
|
local spells = self.spellData;
|
|
|
|
if side > 0 then
|
|
--right side of the screen
|
|
else
|
|
--left side
|
|
--items = API.ReverseList(items);
|
|
--spells = API.ReverseList(spells);
|
|
end
|
|
|
|
--for i, button in ipairs(self.Buttons) do
|
|
-- button:SetItem(items[i]);
|
|
-- button.spellID = spells[i];
|
|
-- self.SpellXButton[ spells[i] ] = button;
|
|
--end
|
|
end
|
|
|
|
function QuickSlot:SetFrameLayout(layoutIndex)
|
|
local buttonSize = Positioner.buttonSize;
|
|
local buttonGap = Positioner.buttonGap;
|
|
|
|
local radius = math.floor( (0.5 * UIParent:GetHeight()*16/9 /3) + (buttonSize*0.5) + 0.5);
|
|
local track0Radius = radius;
|
|
local gapArc = buttonGap + buttonSize;
|
|
local fromRadian = Positioner:GetFromRadian();
|
|
local radianGap = gapArc/radius;
|
|
local radian;
|
|
local x, y;
|
|
local cx, cy = UIParent:GetCenter();
|
|
|
|
local cos = math.cos;
|
|
local sin = math.sin;
|
|
|
|
if layoutIndex == 1 then
|
|
--Normal, below the center
|
|
x, y = Positioner:GetCustomPosition();
|
|
if not (x and y) then
|
|
--x = cx + radius * cos(fromRadian);
|
|
--y = cy + radius * sin(fromRadian);
|
|
x = cx + radius;
|
|
y = cy;
|
|
end
|
|
|
|
self:ClearAllPoints();
|
|
self:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y);
|
|
|
|
for i, button in ipairs(self.Buttons) do
|
|
button:ClearAllPoints();
|
|
button:SetPoint("CENTER", self, "CENTER", (i - 1) * (buttonSize + buttonGap), 0);
|
|
end
|
|
|
|
if self.numActiveButtons > 1 then
|
|
local buttonMiddlePoint = 0.5 * Positioner:GetButtonSpan(self.numActiveButtons or 1);
|
|
self.Header:ClearAllPoints();
|
|
self.Header:SetPoint("BOTTOM", self, "TOPLEFT", buttonMiddlePoint, 8);
|
|
self.headerMaxWidth = 0;
|
|
else
|
|
self.Header:ClearAllPoints();
|
|
self.Header:SetPoint("RIGHT", self, "LEFT", -16, 0);
|
|
self.headerMaxWidth = 240;
|
|
end
|
|
|
|
if self.RepositionButton then
|
|
self.RepositionButton:ClearAllPoints();
|
|
self.RepositionButton:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y + REPOSITION_BUTTON_OFFSET);
|
|
end
|
|
else
|
|
--Circular, on the right side
|
|
local trackIndex = 0;
|
|
|
|
for i, button in ipairs(self.Buttons) do
|
|
button:ClearAllPoints();
|
|
|
|
if trackIndex ~= button.trackIndex then
|
|
trackIndex = button.trackIndex;
|
|
radius = track0Radius - trackIndex * gapArc;
|
|
radianGap = gapArc/radius;
|
|
end
|
|
|
|
radian = fromRadian + (1 - button.positionIndex or i)*radianGap;
|
|
x = cx + radius * cos(radian);
|
|
y = cy + radius * sin(radian);
|
|
button:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y);
|
|
|
|
if i == 2 then
|
|
Positioner:SetCircleMaskPosition(x, y);
|
|
end
|
|
end
|
|
|
|
local headerRadiusOffset = 112; --Positive value moves towards center
|
|
local headerMaxWidth = 2*(headerRadiusOffset - buttonSize*0.5) - 8;
|
|
radian = fromRadian - (self.numActiveButtons - 1)*radianGap*0.5;
|
|
x = cx + (radius - headerRadiusOffset) * cos(radian);
|
|
y = cy + (radius - headerRadiusOffset) * sin(radian);
|
|
|
|
self.headerMaxWidth = headerMaxWidth;
|
|
self.Header:ClearAllPoints();
|
|
self.Header:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y);
|
|
|
|
if self.RepositionButton then
|
|
--Adjust Radian:
|
|
radian = Positioner:GetEditButtonRadian();
|
|
self.RepositionButton:ClearAllPoints();
|
|
self.RepositionButton:SetPoint("CENTER", UIParent, "BOTTOMLEFT", cx + radius * cos(radian), cy + radius * sin(radian));
|
|
--self.RepositionButton:SetRotation(radian);
|
|
|
|
--Adjust Radius:
|
|
--[[
|
|
radian = fromRadian;
|
|
radius = radius + buttonSize;
|
|
self.RepositionButton:ClearAllPoints();
|
|
self.RepositionButton:SetPoint("CENTER", UIParent, "BOTTOMLEFT", cx + radius * cos(radian), cy + radius * sin(radian));
|
|
self.RepositionButton:SetRotation(radian);
|
|
--]]
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UpdateFrameLayout()
|
|
self:SetFrameLayout(self.layoutIndex or 2);
|
|
end
|
|
|
|
function QuickSlot:SetInteractable(state, dueToCombat)
|
|
if state then
|
|
UIFrameFade(self, 0.5, 1);
|
|
else
|
|
if dueToCombat then
|
|
if self:IsShown() and not self:IsInEditMode() then
|
|
local toAlpha = 0.25;
|
|
UIFrameFade(self, 0.2, toAlpha);
|
|
end
|
|
else
|
|
|
|
end
|
|
end
|
|
|
|
for i, button in ipairs(self.Buttons) do
|
|
button:SetEnabled(state);
|
|
button:EnableMouse(state);
|
|
button:UnlockHighlight();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UpdateItemCount()
|
|
for i, button in ipairs(self.ItemButtons) do
|
|
button:UpdateCount();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UpdateSpellCharge()
|
|
for i, button in ipairs(self.SpellButtons) do
|
|
button:UpdateCount();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:OnSpellCastChanged(spellID, isStartCasting)
|
|
local targetButton = self.SpellXButton[spellID];
|
|
|
|
if self.lastSpellTargetButton then
|
|
self.lastSpellTargetButton.Count:Show();
|
|
end
|
|
self.lastSpellTargetButton = targetButton;
|
|
|
|
if targetButton then
|
|
if isStartCasting then
|
|
self.isPlayerMoving = false;
|
|
self.isChanneling = true;
|
|
for i, button in ipairs(self.Buttons) do
|
|
if button.spellID == spellID then
|
|
local _, _, _, startTime, endTime = UnitChannelInfo("player");
|
|
if not _ then
|
|
_, _, _, startTime, endTime = UnitCastingInfo("player");
|
|
end
|
|
|
|
self.SpellCastOverlay:ClearAllPoints();
|
|
self.SpellCastOverlay:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
self.SpellCastOverlay:FadeIn();
|
|
self.SpellCastOverlay:SetDuration( (endTime - startTime) / 1000);
|
|
self.SpellCastOverlay:SetFrameStrata("HIGH");
|
|
|
|
button.Count:Hide();
|
|
end
|
|
end
|
|
else
|
|
self.isChanneling = false;
|
|
self.lastSpellTargetButton = nil;
|
|
self.SpellCastOverlay:FadeOut();
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuickSlot:OnShow()
|
|
self.isClosing = nil;
|
|
end
|
|
|
|
function QuickSlot:OnHide()
|
|
self.isClosing = nil;
|
|
self:EnableEditMode(false);
|
|
end
|
|
QuickSlot:SetScript("OnHide", QuickSlot.OnHide);
|
|
|
|
|
|
local function GetCursorRadianToPoint(cx, cy, uiRatio)
|
|
local x, y = GetCursorPosition();
|
|
x = x * uiRatio;
|
|
y = y * uiRatio;
|
|
return atan2(y - cy, x - cx);
|
|
end
|
|
|
|
local function RepositionButton_OnUpdate_Radial(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= 0.016 then
|
|
self.t = 0;
|
|
local radian = GetCursorRadianToPoint(self.cx, self.cy, self.uiRatio);
|
|
if radian ~= self.radian then
|
|
self.radian = radian;
|
|
Positioner:SetFromRadian(self.frameRadian + radian - self.selfRadian);
|
|
QuickSlot:UpdateFrameLayout();
|
|
--[[
|
|
if radian > -1.57 and radian < 1.57 then
|
|
QuickSlot:SetButtonOrder(1);
|
|
else
|
|
QuickSlot:SetButtonOrder(-1);
|
|
end
|
|
--]]
|
|
end
|
|
end
|
|
end
|
|
|
|
local function RepositionButton_OnUpdate_FreeMove(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= 0.016 then
|
|
self.t = 0;
|
|
local x, y = GetCursorPosition();
|
|
x = self.cxOffset + x * self.uiRatio;
|
|
y = self.cyOffset + y * self.uiRatio - REPOSITION_BUTTON_OFFSET;
|
|
Positioner:SetCustomPosition(x, y);
|
|
QuickSlot:UpdateFrameLayout();
|
|
end
|
|
end
|
|
|
|
local function RepositionButton_OnMouseDown(self, button)
|
|
if button == "RightButton" then
|
|
if QuickSlot.layoutIndex == 1 then
|
|
Positioner:SetCustomPosition(nil, nil);
|
|
else
|
|
Positioner:SetFromRadian(0);
|
|
end
|
|
QuickSlot:UpdateFrameLayout();
|
|
return
|
|
end
|
|
self.t = 0;
|
|
self.cx, self.cy = UIParent:GetCenter();
|
|
self.uiRatio = 1/ UIParent:GetEffectiveScale();
|
|
self.radian = GetCursorRadianToPoint(self.cx, self.cy, self.uiRatio);
|
|
self.selfRadian = Positioner:GetEditButtonRadian();
|
|
self.frameRadian = Positioner:GetFromRadian();
|
|
|
|
local cx0, cy0 = GetCursorPosition();
|
|
cx0 = cx0 * self.uiRatio;
|
|
cy0 = cy0 * self.uiRatio;
|
|
local x0, y0 = self:GetCenter();
|
|
self.cxOffset = x0 - cx0;
|
|
self.cyOffset = y0 - cy0;
|
|
|
|
local isRadial = QuickSlot.layoutIndex ~= 1;
|
|
if isRadial then
|
|
self:SetScript("OnUpdate", RepositionButton_OnUpdate_Radial);
|
|
Positioner:ShowGuideLineCircle(true);
|
|
else
|
|
self:SetScript("OnUpdate", RepositionButton_OnUpdate_FreeMove);
|
|
Positioner:ShowGuideLineCircle(false);
|
|
end
|
|
QuickSlot:SetInteractable(false);
|
|
self:LockHighlight();
|
|
end
|
|
|
|
local function RepositionButton_OnMouseUp(self)
|
|
self.t = nil;
|
|
self.cx, self.cy = nil, nil;
|
|
self:SetScript("OnUpdate", nil);
|
|
self:UnlockHighlight();
|
|
|
|
Positioner:ShowGuideLineCircle(false);
|
|
end
|
|
|
|
local function RepositionButton_OnClick(self)
|
|
local delta = -1; --clock-wise
|
|
local oldRadian = Positioner:GetFromRadian();
|
|
local dRadian = Positioner:GetButtonCenterGap();
|
|
local newRadian = oldRadian + delta*dRadian;
|
|
Positioner:SetFromRadian(newRadian);
|
|
QuickSlot:UpdateFrameLayout();
|
|
end
|
|
|
|
local function RepositionButton_SetRotation(self, radian)
|
|
self.Icon:SetRotation(radian);
|
|
self.Highlight:SetRotation(radian);
|
|
end
|
|
|
|
function QuickSlot:IsInEditMode()
|
|
return self.isEditing == true
|
|
end
|
|
|
|
local function SetControlNodeAnimation(obj)
|
|
local ag = obj:CreateAnimationGroup();
|
|
obj.AnimIn = ag;
|
|
|
|
local s1 = ag:CreateAnimation("Scale");
|
|
s1:SetOrder(1);
|
|
s1:SetDuration(0);
|
|
s1:SetScale(0.25, 0.25);
|
|
|
|
local s2 = ag:CreateAnimation("Scale");
|
|
s2:SetOrder(2);
|
|
s2:SetDuration(0.3);
|
|
s2:SetScale(6, 6);
|
|
s2:SetSmoothing("IN_OUT");
|
|
|
|
local s3 = ag:CreateAnimation("Scale");
|
|
s3:SetOrder(3);
|
|
s3:SetDuration(0.4);
|
|
s3:SetScale(0.67, 0.67);
|
|
s3:SetSmoothing("OUT");
|
|
end
|
|
|
|
function QuickSlot:EnableEditMode(state)
|
|
if state then
|
|
if not self.RepositionButton then
|
|
local b = CreateFrame("Button", nil, self);
|
|
b:SetSize(16, 16);
|
|
self.RepositionButton = b;
|
|
b:SetFrameStrata("DIALOG");
|
|
b:SetFrameLevel(500);
|
|
b:SetFixedFrameStrata(true);
|
|
b:SetClampedToScreen(true);
|
|
local offset = 46;
|
|
b:SetClampRectInsets(-offset, offset, offset, -offset);
|
|
|
|
local tex = "Interface/AddOns/Plumber/Art/Button/RepositionButton-Circle";
|
|
|
|
b.Icon = b:CreateTexture(nil, "ARTWORK");
|
|
b.Icon:SetSize(16, 16);
|
|
b.Icon:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Icon:SetTexture(tex, nil, nil, "TRILINEAR");
|
|
|
|
b.Highlight = b:CreateTexture(nil, "HIGHLIGHT");
|
|
b.Highlight:SetSize(32, 32);
|
|
b.Highlight:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Highlight:SetTexture(tex.."-Highlight", nil, nil, "TRILINEAR");
|
|
|
|
b.SetRotation = RepositionButton_SetRotation;
|
|
--b:SetScript("OnClick", RepositionButton_OnClick);
|
|
b:SetScript("OnMouseDown", RepositionButton_OnMouseDown);
|
|
b:SetScript("OnMouseUp", RepositionButton_OnMouseUp);
|
|
|
|
SetControlNodeAnimation(b);
|
|
end
|
|
|
|
if not self.EditModeConfirmButton then
|
|
local b = CreateFrame("Button", nil, self);
|
|
b:SetSize(30, 30);
|
|
self.EditModeConfirmButton = b;
|
|
b:SetFrameStrata("DIALOG");
|
|
b:SetFixedFrameStrata(true);
|
|
b:SetClampedToScreen(true);
|
|
local offset = 24;
|
|
b:SetClampRectInsets(-offset, offset, offset, -offset);
|
|
|
|
local tex = "Interface/AddOns/Plumber/Art/Button/EditMode-Confirm";
|
|
|
|
b.Icon = b:CreateTexture(nil, "ARTWORK");
|
|
b.Icon:SetSize(32, 32);
|
|
b.Icon:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Icon:SetTexture(tex);
|
|
API.DisableSharpening(b.Icon);
|
|
|
|
b.Highlight = b:CreateTexture(nil, "HIGHLIGHT");
|
|
b.Highlight:SetSize(32, 32);
|
|
b.Highlight:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Highlight:SetTexture(tex.."-Highlight");
|
|
API.DisableSharpening(b.Highlight);
|
|
|
|
b:SetPoint("CENTER", self.Header, "CENTER", 0, 0);
|
|
b:SetScript("OnClick", function()
|
|
self:EnableEditMode(false);
|
|
end);
|
|
end
|
|
|
|
if not self.isEditing then
|
|
self.RepositionButton:Show();
|
|
self.EditModeConfirmButton:Show();
|
|
self.RepositionButton.AnimIn:Play();
|
|
UIFrameFade(self.EditModeConfirmButton, 0.25, 1, 0);
|
|
self:SetInteractable(false);
|
|
self:SetHeaderText(); --HUD_EDIT_MODE_MENU
|
|
self:StartShowingDefaultHeaderCountdown(false);
|
|
for i, button in ipairs(self.Buttons) do
|
|
button.Count:Hide();
|
|
end
|
|
self.isEditing = true;
|
|
self:UpdateFrameLayout();
|
|
|
|
self.EditModeConfirmButton:ClearAllPoints();
|
|
if self.layoutIndex == 1 then
|
|
self.EditModeConfirmButton:SetPoint("CENTER", self, "CENTER", -54, 0);
|
|
else
|
|
self.EditModeConfirmButton:SetPoint("CENTER", self.Header, "CENTER", 0, 0);
|
|
end
|
|
end
|
|
else
|
|
if self.isEditing then
|
|
self.isEditing = nil;
|
|
self.RepositionButton:Hide();
|
|
self.RepositionButton:SetScript("OnUpdate", nil);
|
|
self.EditModeConfirmButton:Hide();
|
|
Positioner:HideGuideLine();
|
|
for i, button in ipairs(self.Buttons) do
|
|
if button ~= self.lastSpellTargetButton then
|
|
button.Count:Show();
|
|
end
|
|
end
|
|
if not InCombatLockdown() then
|
|
self:SetInteractable(true);
|
|
end
|
|
|
|
if self.closeUIAfterEditing then
|
|
self.closeUIAfterEditing = nil;
|
|
self:CloseUI();
|
|
end
|
|
else
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuickSlot:CloseUIAfterEditing()
|
|
self.closeUIAfterEditing = true;
|
|
end
|
|
|
|
function QuickSlot:ShowUI()
|
|
if self.Init then
|
|
self:Init();
|
|
end
|
|
|
|
if self.layoutDirty then
|
|
self.layoutDirty = nil;
|
|
self:UpdateFrameLayout();
|
|
end
|
|
|
|
self:UpdateItemCount();
|
|
|
|
self:RegisterEvent("BAG_UPDATE_DELAYED");
|
|
self:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
self:RegisterEvent("PLAYER_REGEN_ENABLED");
|
|
self:RegisterEvent("UI_SCALE_CHANGED");
|
|
self:RegisterEvent("LOADING_SCREEN_ENABLED");
|
|
|
|
if self.anyItemAction then
|
|
self:RegisterEvent("BAG_UPDATE_COOLDOWN");
|
|
self:UpdateItemCooldowns();
|
|
end
|
|
|
|
if self.anySpellAction then
|
|
self:RegisterEvent("SPELL_UPDATE_CHARGES");
|
|
self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
|
|
self:RequestUpdateSpellCooldowns();
|
|
self:UpdateSpellCharge();
|
|
end
|
|
|
|
if self.spellcastType == 1 then
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_START", "player");
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_STOP", "player");
|
|
else
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", "player");
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", "player");
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", "player");
|
|
end
|
|
|
|
|
|
for _, button in ipairs(self.Buttons) do
|
|
button.Count:Show();
|
|
end
|
|
|
|
self.closeUIAfterEditing = nil;
|
|
self.isChanneling = nil;
|
|
self.lastSpellTargetButton = nil;
|
|
self:Show();
|
|
|
|
if InCombatLockdown() then
|
|
self:SetInteractable(false, true);
|
|
else
|
|
self:SetInteractable(true);
|
|
end
|
|
|
|
self:UseHighContrast(GetDBBool("QuickSlotHighContrastMode"));
|
|
|
|
return true
|
|
end
|
|
|
|
function QuickSlot:CloseUI()
|
|
if self:IsShown() then
|
|
self:EnableEditMode(false);
|
|
self.isClosing = true;
|
|
UIFrameFade(self, 0.5, 0);
|
|
self:UnregisterEvent("PLAYER_REGEN_DISABLED");
|
|
self:UnregisterEvent("PLAYER_REGEN_ENABLED");
|
|
self:UnregisterEvent("UI_SCALE_CHANGED");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_START");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_STOP");
|
|
self:UnregisterEvent("LOADING_SCREEN_ENABLED");
|
|
self:UnregisterEvent("BAG_UPDATE_DELAYED");
|
|
self:UnregisterEvent("BAG_UPDATE_COOLDOWN");
|
|
self:UnregisterEvent("SPELL_UPDATE_CHARGES");
|
|
self:UnregisterEvent("SPELL_UPDATE_COOLDOWN");
|
|
self:SetInteractable(false);
|
|
self.isChanneling = nil;
|
|
self.defaultHeaderText = nil;
|
|
self.SpellCastOverlay:Hide();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:RequestCloseUI(systemName)
|
|
if self:IsInEditMode() then
|
|
self.closeUIAfterEditing = true;
|
|
else
|
|
if (not systemName) or (systemName and systemName == self.systemName) then
|
|
self:CloseUI();
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UseHighContrast(state)
|
|
state = state == true;
|
|
self.highContrastMode = state;
|
|
|
|
for i, button in ipairs(self.Buttons) do
|
|
button:UseHighContrast(state);
|
|
end
|
|
|
|
if self.Header then
|
|
local font, height, flag = self.Header:GetFont();
|
|
flag = state and "OUTLINE" or "";
|
|
self.Header:SetFont(font, height, flag);
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UpdateItemCooldowns()
|
|
if self.ItemButtons then
|
|
local startTime, duration, enable;
|
|
for _, button in ipairs(self.ItemButtons) do
|
|
if button.id and button.actionType == "item" then
|
|
startTime, duration, enable = GetItemCooldown(button.id);
|
|
if enable == 1 and startTime and startTime > 0 and duration and duration > 0 then
|
|
button.Cooldown:SetCooldown(startTime, duration);
|
|
button.Cooldown:Show();
|
|
button.Cooldown:SetHideCountdownNumbers(false);
|
|
else
|
|
button.Cooldown:Hide();
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
do --Spell Cooldown
|
|
local GetSpellCooldown = API.GetSpellCooldown;
|
|
local GetSpellCharges = API.GetSpellCharges;
|
|
|
|
local Throttler = CreateFrame("Frame", nil, QuickSlot);
|
|
QuickSlot.Throttler = Throttler;
|
|
Throttler:SetScript("OnHide", function(self)
|
|
self:SetScript("OnUpdate", nil);
|
|
self.pauseUpdate = nil;
|
|
end);
|
|
|
|
local function Throttler_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= 0.5 then
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", nil);
|
|
self.pauseUpdate = nil;
|
|
end
|
|
end
|
|
|
|
function QuickSlot:RequestUpdateSpellCooldowns()
|
|
if Throttler.pauseUpdate then
|
|
|
|
else
|
|
Throttler.pauseUpdate = true;
|
|
Throttler.t = 0;
|
|
Throttler:SetScript("OnUpdate", Throttler_OnUpdate);
|
|
self:UpdateSpellCooldowns();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:UpdateSpellCooldowns()
|
|
if not self.SpellButtons then return end;
|
|
local cooldownInfo, chargeInfo, startTime, duration, modRate, fromChargeCooldown;
|
|
for _, button in ipairs(self.SpellButtons) do
|
|
if button.id and button.actionType == "spell" then
|
|
startTime, duration, modRate, fromChargeCooldown = nil, nil, nil, nil;
|
|
|
|
chargeInfo = GetSpellCharges(button.id);
|
|
if chargeInfo and chargeInfo.currentCharges > 0 then
|
|
if chargeInfo.cooldownStartTime > 0 and chargeInfo.cooldownDuration > 0 then
|
|
startTime = chargeInfo.cooldownStartTime;
|
|
duration = chargeInfo.cooldownDuration;
|
|
modRate = chargeInfo.chargeModRate;
|
|
fromChargeCooldown = true;
|
|
end
|
|
end
|
|
|
|
if not (startTime and duration) then
|
|
cooldownInfo = GetSpellCooldown(button.id);
|
|
if cooldownInfo and cooldownInfo.isEnabled and cooldownInfo.startTime > 0 and cooldownInfo.duration > 0 then
|
|
startTime = cooldownInfo.startTime;
|
|
duration = cooldownInfo.duration;
|
|
modRate = cooldownInfo.modRate
|
|
end
|
|
end
|
|
|
|
if startTime and duration then
|
|
button.Cooldown:SetCooldown(startTime, duration, modRate);
|
|
button.Cooldown:Show();
|
|
if fromChargeCooldown then
|
|
button.Cooldown:SetHideCountdownNumbers(true);
|
|
else
|
|
button.Cooldown:SetHideCountdownNumbers(false);
|
|
end
|
|
else
|
|
button.Cooldown:Hide();
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuickSlot:OnEvent(event, ...)
|
|
if event == "BAG_UPDATE_DELAYED" then
|
|
self:UpdateItemCount();
|
|
elseif event == "SPELL_UPDATE_COOLDOWN" then
|
|
self:RequestUpdateSpellCooldowns();
|
|
elseif event == "PLAYER_REGEN_DISABLED" then
|
|
self:SetInteractable(false, true);
|
|
elseif event == "PLAYER_REGEN_ENABLED" then
|
|
if not self.isEditing then
|
|
self:SetInteractable(true);
|
|
end
|
|
elseif event == "UI_SCALE_CHANGED" then
|
|
self:UpdateFrameLayout();
|
|
elseif event == "UNIT_SPELLCAST_CHANNEL_START" or event == "UNIT_SPELLCAST_START" then
|
|
local _, _, spellID = ...
|
|
QuickSlot:OnSpellCastChanged(spellID, true);
|
|
elseif event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
|
|
|
elseif event == "UNIT_SPELLCAST_CHANNEL_STOP" or event == "UNIT_SPELLCAST_STOP" then
|
|
local _, _, spellID = ...
|
|
self:OnSpellCastChanged(spellID, false);
|
|
elseif event == "LOADING_SCREEN_ENABLED" then
|
|
self:CloseUI();
|
|
elseif event == "BAG_UPDATE_COOLDOWN" then
|
|
self:UpdateItemCooldowns();
|
|
elseif event == "SPELL_UPDATE_CHARGES" then
|
|
self:UpdateSpellCharge();
|
|
end
|
|
end
|
|
QuickSlot:SetScript("OnEvent", QuickSlot.OnEvent);
|