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.
927 lines
29 KiB
927 lines
29 KiB
local _, addon = ...
|
|
local API = addon.API;
|
|
local UIFrameFade = API.UIFrameFade;
|
|
|
|
|
|
local ACTION_BUTTON_SIZE = 46;
|
|
local ACTION_BUTTON_GAP = 4;
|
|
|
|
|
|
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 QuickSlot = CreateFrame("Frame", nil, UIParent);
|
|
addon.QuickSlot = QuickSlot;
|
|
QuickSlot:Hide();
|
|
QuickSlot:SetSize(8, 8);
|
|
QuickSlot:SetAlpha(0);
|
|
QuickSlot:SetFrameStrata("MEDIUM");
|
|
QuickSlot.Buttons = {};
|
|
QuickSlot.numActiveButtons = 0;
|
|
QuickSlot.SpellXButton = {};
|
|
|
|
local ContextMenu;
|
|
|
|
local function ContextMenu_EditMode_OnClick(self, button)
|
|
QuickSlot:EnableEditMode(true);
|
|
return true
|
|
end
|
|
|
|
local ContextMenuData = {
|
|
{ text = _G["HUD_EDIT_MODE_MENU"] or "Edit Mode", onClickFunc = ContextMenu_EditMode_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:GetFromRadian()
|
|
return self.fromRadian
|
|
end
|
|
|
|
function Positioner:SetFromRadian(radian)
|
|
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 PlumberDB then
|
|
PlumberDB.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
|
|
end
|
|
|
|
local function RealActionButton_PostClick(self, button)
|
|
local owner = self.owner;
|
|
|
|
if owner then
|
|
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);
|
|
menu:SetContent(ContextMenuData);
|
|
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)
|
|
QuickSlot:SetHeaderText(API.GetColorizedItemName(self.id));
|
|
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 = string.format("/use item:%s", self.id);
|
|
RealActionButton:SetAttribute("type1", "macro"); --Any Mouseclick
|
|
RealActionButton:SetMacroText(macroText);
|
|
RealActionButton:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp");
|
|
|
|
self:LockHighlight();
|
|
self.hasActionButton = true;
|
|
end
|
|
end
|
|
|
|
local function ItemButton_OnLeave(self)
|
|
if not (self:IsVisible() and self:IsMouseOver()) then
|
|
QuickSlot:SetHeaderText();
|
|
QuickSlot:StartShowingDefaultHeaderCountdown(true);
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
function QuickSlot:Init()
|
|
if PlumberDB and PlumberDB.quickslotFromRadian then
|
|
Positioner:SetFromRadian(PlumberDB.quickslotFromRadian);
|
|
end
|
|
|
|
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);
|
|
|
|
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 = 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(itemData, spellData, systemName, isCasting)
|
|
if itemData == self.itemData then
|
|
return
|
|
end
|
|
|
|
self.itemData = itemData;
|
|
self.spellData = spellData;
|
|
self.systemName = systemName;
|
|
self.layoutDirty = true;
|
|
self.numActiveButtons = #itemData;
|
|
self.spellcastType = (isCasting and 1) or 2;
|
|
|
|
local buttonSize = ACTION_BUTTON_SIZE;
|
|
local gap = ACTION_BUTTON_GAP;
|
|
local positionIndex = 0;
|
|
local trackIndex = 0;
|
|
|
|
for i, itemID in ipairs(itemData) do
|
|
positionIndex = positionIndex + 1;
|
|
if itemID == 0 then
|
|
--Used as a spacer
|
|
|
|
elseif itemID == -1 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 = spellData and spellData[i] or nil;
|
|
if spellID then
|
|
self.SpellXButton[spellID] = button;
|
|
end
|
|
button:SetItem(itemID);
|
|
button.spellID = spellID;
|
|
button.positionIndex = positionIndex;
|
|
button.trackIndex = trackIndex;
|
|
button:SetScript("OnEnter", ItemButton_OnEnter);
|
|
button:SetScript("OnLeave", ItemButton_OnLeave);
|
|
button:Show();
|
|
end
|
|
end
|
|
|
|
for i = self.numActiveButtons + 1, #self.Buttons do
|
|
self.Buttons[i]:Hide();
|
|
end
|
|
end
|
|
|
|
function QuickSlot:SetButtonOrder(side)
|
|
if side ~= self.side then
|
|
self.side = side;
|
|
else
|
|
return
|
|
end
|
|
|
|
if not self.itemData 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;
|
|
|
|
if layoutIndex == 1 then
|
|
--Normal, below the center
|
|
--CastingBar's position is changed conditionally
|
|
|
|
local anchorTo = Positioner:GetCastBar();
|
|
local y = anchorTo:GetTop();
|
|
local scale = anchorTo:GetScale();
|
|
|
|
self:ClearAllPoints();
|
|
self:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 250); --(y + 30)*scale --Default CastingBar moves up 29y when start casting
|
|
|
|
for i, button in ipairs(self.Buttons) do
|
|
button:ClearAllPoints();
|
|
button:SetPoint("LEFT", self, "LEFT", (i - 1) * (buttonSize + buttonGap), 0);
|
|
end
|
|
|
|
self.Header:ClearAllPoints();
|
|
self.Header:SetPoint("BOTTOM", self, "TOP", 0, 8);
|
|
self.headerMaxWidth = 0;
|
|
else
|
|
--Circular, on the right side
|
|
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;
|
|
|
|
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: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.Buttons) 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()
|
|
|
|
end
|
|
|
|
function QuickSlot:OnHide()
|
|
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 math.atan2(y - cy, x - cx);
|
|
end
|
|
|
|
local function RepositionButton_OnUpdate(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:SetFrameLayout(2);
|
|
--[[
|
|
if radian > -1.57 and radian < 1.57 then
|
|
QuickSlot:SetButtonOrder(1);
|
|
else
|
|
QuickSlot:SetButtonOrder(-1);
|
|
end
|
|
--]]
|
|
end
|
|
end
|
|
end
|
|
|
|
local function RepositionButton_OnMouseDown(self, button)
|
|
if button == "RightButton" then
|
|
Positioner:SetFromRadian(0);
|
|
QuickSlot:SetFrameLayout(2);
|
|
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();
|
|
self:SetScript("OnUpdate", RepositionButton_OnUpdate);
|
|
QuickSlot:SetInteractable(false);
|
|
self:LockHighlight();
|
|
|
|
Positioner:ShowGuideLineCircle(true);
|
|
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:SetFrameLayout(2);
|
|
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:SetFixedFrameStrata(true);
|
|
|
|
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);
|
|
|
|
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:SetFrameLayout(2);
|
|
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:ShowUI()
|
|
if self.Init then
|
|
self:Init();
|
|
end
|
|
|
|
if self.layoutDirty then
|
|
self.layoutDirty = nil;
|
|
self:SetFrameLayout(2);
|
|
end
|
|
|
|
self:RegisterEvent("BAG_UPDATE");
|
|
self:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
self:RegisterEvent("PLAYER_REGEN_ENABLED");
|
|
self:RegisterEvent("UI_SCALE_CHANGED");
|
|
|
|
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
|
|
|
|
self:UpdateItemCount();
|
|
|
|
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
|
|
|
|
return true
|
|
end
|
|
|
|
function QuickSlot:CloseUI()
|
|
if self:IsShown() then
|
|
self:EnableEditMode(false);
|
|
UIFrameFade(self, 0.5, 0);
|
|
self:UnregisterEvent("BAG_UPDATE");
|
|
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: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:OnEvent(event, ...)
|
|
if event == "BAG_UPDATE" then
|
|
self:UpdateItemCount();
|
|
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:SetFrameLayout(2);
|
|
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);
|
|
end
|
|
end
|
|
QuickSlot:SetScript("OnEvent", QuickSlot.OnEvent);
|