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.
4331 lines
146 KiB
4331 lines
146 KiB
local _, addon = ...
|
|
local API = addon.API;
|
|
local L = addon.L;
|
|
|
|
local BUTTON_MIN_SIZE = 24;
|
|
|
|
local Mixin = API.Mixin;
|
|
local FadeFrame = API.UIFrameFade;
|
|
|
|
local select = select;
|
|
local tinsert = table.insert;
|
|
local floor = math.floor;
|
|
local ipairs = ipairs;
|
|
local unpack = unpack;
|
|
local time = time;
|
|
local GetTime = GetTime;
|
|
local IsMouseButtonDown = IsMouseButtonDown;
|
|
local GetMouseFocus = API.GetMouseFocus;
|
|
local PlaySound = PlaySound;
|
|
local GetSpellCharges = GetSpellCharges;
|
|
local C_Item = C_Item;
|
|
local GetItemCount = C_Item.GetItemCount;
|
|
local GetItemIconByID = C_Item.GetItemIconByID;
|
|
local GetCVarBool = C_CVar.GetCVarBool;
|
|
local CreateFrame = CreateFrame;
|
|
local UIParent = UIParent;
|
|
|
|
|
|
local function DisableSharpening(texture)
|
|
texture:SetTexelSnappingBias(0);
|
|
texture:SetSnapToPixelGrid(false);
|
|
end
|
|
API.DisableSharpening = DisableSharpening;
|
|
|
|
do -- Slice Frame
|
|
local NineSliceLayouts = {
|
|
WhiteBorder = true,
|
|
WhiteBorderBlackBackdrop = true,
|
|
Tooltip_Brown = true,
|
|
Menu_Black = true,
|
|
NineSlice_GenericBox = true, --used by BackpackItemTracker
|
|
NineSlice_GenericBox_Border = true, --used by BackpackItemTracker
|
|
};
|
|
|
|
local ThreeSliceLayouts = {
|
|
GenericBox = true,
|
|
WhiteBorder = true,
|
|
WhiteBorderBlackBackdrop = true,
|
|
Metal_Hexagon = true,
|
|
Metal_Hexagon_Red = true,
|
|
Phantom = true,
|
|
CoinBox = true,
|
|
};
|
|
|
|
local SliceFrameMixin = {};
|
|
|
|
--Use the new Texture Slicing (https://warcraft.wiki.gg/wiki/Patch_10.2.0/API_changes)
|
|
--The SlicedTexture is pixel-perfect but doesn't scale with parent, so we shelve this and observer Blizzard's implementation
|
|
local function NiceSlice_CreatePieces(frame)
|
|
if not frame.NineSlice then
|
|
frame.NineSlice = frame:CreateTexture(nil, "BACKGROUND");
|
|
--frame.NineSlice:SetTextureSliceMode(0); --Enum.UITextureSliceMode, 0 Stretched(Default) 1 Tiled
|
|
--DisableSharpening(frame.NineSlice);
|
|
frame.TestBG = frame:CreateTexture(nil, "OVERLAY");
|
|
frame.TestBG:SetAllPoints(true);
|
|
frame.TestBG:SetColorTexture(1, 0, 0, 0.5);
|
|
end
|
|
end
|
|
|
|
local function NiceSlice_SetCornerSize(frame, a)
|
|
frame.NineSlice:SetTextureSliceMargins(32, 32, 32, 32);
|
|
local offset = 0;
|
|
frame.NineSlice:ClearAllPoints();
|
|
frame.NineSlice:SetPoint("TOPLEFT", frame, "TOPLEFT", -offset, offset);
|
|
frame.NineSlice:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", offset, -offset);
|
|
end
|
|
|
|
local function NiceSlice_SetTexture(frame, texture)
|
|
frame.NineSlice:SetTexture(texture);
|
|
end
|
|
|
|
function SliceFrameMixin:CreatePieces(n)
|
|
--[[
|
|
if n == 9 then
|
|
NiceSlice_CreatePieces(self);
|
|
NiceSlice_SetCornerSize(self, 16);
|
|
return
|
|
end
|
|
--]]
|
|
|
|
if self.pieces then return end;
|
|
self.pieces = {};
|
|
self.numSlices = n;
|
|
|
|
-- 1 2 3
|
|
-- 4 5 6
|
|
-- 7 8 9
|
|
|
|
for i = 1, n do
|
|
self.pieces[i] = self:CreateTexture(nil, "BORDER");
|
|
DisableSharpening(self.pieces[i]);
|
|
self.pieces[i]:ClearAllPoints();
|
|
end
|
|
|
|
self:SetCornerSize(16);
|
|
|
|
if n == 3 then
|
|
self.pieces[1]:SetPoint("CENTER", self, "LEFT", 0, 0);
|
|
self.pieces[3]:SetPoint("CENTER", self, "RIGHT", 0, 0);
|
|
self.pieces[2]:SetPoint("TOPLEFT", self.pieces[1], "TOPRIGHT", 0, 0);
|
|
self.pieces[2]:SetPoint("BOTTOMRIGHT", self.pieces[3], "BOTTOMLEFT", 0, 0);
|
|
|
|
self.pieces[1]:SetTexCoord(0, 0.25, 0, 1);
|
|
self.pieces[2]:SetTexCoord(0.25, 0.75, 0, 1);
|
|
self.pieces[3]:SetTexCoord(0.75, 1, 0, 1);
|
|
|
|
elseif n == 9 then
|
|
self.pieces[1]:SetPoint("CENTER", self, "TOPLEFT", 0, 0);
|
|
self.pieces[3]:SetPoint("CENTER", self, "TOPRIGHT", 0, 0);
|
|
self.pieces[7]:SetPoint("CENTER", self, "BOTTOMLEFT", 0, 0);
|
|
self.pieces[9]:SetPoint("CENTER", self, "BOTTOMRIGHT", 0, 0);
|
|
self.pieces[2]:SetPoint("TOPLEFT", self.pieces[1], "TOPRIGHT", 0, 0);
|
|
self.pieces[2]:SetPoint("BOTTOMRIGHT", self.pieces[3], "BOTTOMLEFT", 0, 0);
|
|
self.pieces[4]:SetPoint("TOPLEFT", self.pieces[1], "BOTTOMLEFT", 0, 0);
|
|
self.pieces[4]:SetPoint("BOTTOMRIGHT", self.pieces[7], "TOPRIGHT", 0, 0);
|
|
self.pieces[5]:SetPoint("TOPLEFT", self.pieces[1], "BOTTOMRIGHT", 0, 0);
|
|
self.pieces[5]:SetPoint("BOTTOMRIGHT", self.pieces[9], "TOPLEFT", 0, 0);
|
|
self.pieces[6]:SetPoint("TOPLEFT", self.pieces[3], "BOTTOMLEFT", 0, 0);
|
|
self.pieces[6]:SetPoint("BOTTOMRIGHT", self.pieces[9], "TOPRIGHT", 0, 0);
|
|
self.pieces[8]:SetPoint("TOPLEFT", self.pieces[7], "TOPRIGHT", 0, 0);
|
|
self.pieces[8]:SetPoint("BOTTOMRIGHT", self.pieces[9], "BOTTOMLEFT", 0, 0);
|
|
|
|
self.pieces[1]:SetTexCoord(0, 0.25, 0, 0.25);
|
|
self.pieces[2]:SetTexCoord(0.25, 0.75, 0, 0.25);
|
|
self.pieces[3]:SetTexCoord(0.75, 1, 0, 0.25);
|
|
self.pieces[4]:SetTexCoord(0, 0.25, 0.25, 0.75);
|
|
self.pieces[5]:SetTexCoord(0.25, 0.75, 0.25, 0.75);
|
|
self.pieces[6]:SetTexCoord(0.75, 1, 0.25, 0.75);
|
|
self.pieces[7]:SetTexCoord(0, 0.25, 0.75, 1);
|
|
self.pieces[8]:SetTexCoord(0.25, 0.75, 0.75, 1);
|
|
self.pieces[9]:SetTexCoord(0.75, 1, 0.75, 1);
|
|
end
|
|
end
|
|
|
|
function SliceFrameMixin:SetCornerSize(a)
|
|
if self.numSlices == 3 then
|
|
self.pieces[1]:SetSize(a, 2*a);
|
|
self.pieces[3]:SetSize(a, 2*a);
|
|
elseif self.numSlices == 9 then
|
|
--if true then
|
|
-- NiceSlice_SetCornerSize(self, a);
|
|
-- return
|
|
--end
|
|
self.pieces[1]:SetSize(a, a);
|
|
self.pieces[3]:SetSize(a, a);
|
|
self.pieces[7]:SetSize(a, a);
|
|
self.pieces[9]:SetSize(a, a);
|
|
end
|
|
end
|
|
|
|
function SliceFrameMixin:SetTexture(tex)
|
|
--if self.NineSlice then
|
|
-- NiceSlice_SetTexture(self, tex);
|
|
-- return
|
|
--end
|
|
for i = 1, #self.pieces do
|
|
self.pieces[i]:SetTexture(tex);
|
|
end
|
|
end
|
|
|
|
function SliceFrameMixin:SetColor(r, g, b)
|
|
for i = 1, #self.pieces do
|
|
self.pieces[i]:SetVertexColor(r, g, b);
|
|
end
|
|
end
|
|
|
|
function SliceFrameMixin:CoverParent(padding)
|
|
padding = padding or 0;
|
|
local parent = self:GetParent();
|
|
if parent then
|
|
self:ClearAllPoints();
|
|
self:SetPoint("TOPLEFT", parent, "TOPLEFT", -padding, padding);
|
|
self:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", padding, -padding);
|
|
end
|
|
end
|
|
|
|
function SliceFrameMixin:ShowBackground(state)
|
|
for _, piece in ipairs(self.pieces) do
|
|
piece:SetShown(state);
|
|
end
|
|
end
|
|
|
|
local function CreateNineSliceFrame(parent, layoutName)
|
|
if not (layoutName and NineSliceLayouts[layoutName]) then
|
|
layoutName = "WhiteBorder";
|
|
end
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
Mixin(f, SliceFrameMixin);
|
|
f:CreatePieces(9);
|
|
f:SetTexture("Interface/AddOns/Plumber/Art/Frame/"..layoutName);
|
|
f:ClearAllPoints();
|
|
return f
|
|
end
|
|
addon.CreateNineSliceFrame = CreateNineSliceFrame;
|
|
|
|
local function CreateThreeSliceFrame(parent, layoutName, frameType)
|
|
if not (layoutName and ThreeSliceLayouts[layoutName]) then
|
|
layoutName = "GenericBox";
|
|
end
|
|
frameType = frameType or "Frame";
|
|
local f = CreateFrame(frameType, nil, parent);
|
|
Mixin(f, SliceFrameMixin);
|
|
f:CreatePieces(3);
|
|
f:SetTexture("Interface/AddOns/Plumber/Art/Frame/ThreeSlice_"..layoutName);
|
|
f:ClearAllPoints();
|
|
return f
|
|
end
|
|
addon.CreateThreeSliceFrame = CreateThreeSliceFrame;
|
|
|
|
|
|
local function CreateTextureSlice(frame)
|
|
if not frame.TextureSlice then
|
|
frame.TextureSlice = frame:CreateTexture(nil, "BACKGROUND");
|
|
frame.TextureSlice:SetTextureSliceMode(1); --Enum.UITextureSliceMode, 0 Stretched(Default) 1 Tiled
|
|
end
|
|
local pixelMargin = 1;
|
|
frame.TextureSlice:SetTextureSliceMargins(pixelMargin, pixelMargin, pixelMargin, pixelMargin);
|
|
local offset = 0;
|
|
frame.TextureSlice:ClearAllPoints();
|
|
frame.TextureSlice:SetPoint("TOPLEFT", frame, "TOPLEFT", -offset, offset);
|
|
frame.TextureSlice:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", offset, -offset);
|
|
frame.TextureSlice:SetTexture("Interface/AddOns/Plumber/Art/Frame/PixelBorder_Dashed_Moving");
|
|
end
|
|
|
|
addon.CreateTextureSlice = CreateTextureSlice;
|
|
end
|
|
|
|
do -- Checkbox
|
|
local LABEL_OFFSET = 20;
|
|
local BUTTON_HITBOX_MIN_WIDTH = 120;
|
|
|
|
local SFX_CHECKBOX_ON = SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON or 856;
|
|
local SFX_CHECKBOX_OFF = SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF or 857;
|
|
|
|
local CheckboxMixin = {};
|
|
|
|
function CheckboxMixin:OnEnter()
|
|
if IsMouseButtonDown() then return end;
|
|
|
|
if self.tooltip then
|
|
GameTooltip:Hide();
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
GameTooltip:SetText(self.Label:GetText(), 1, 1, 1, true);
|
|
GameTooltip:AddLine(self.tooltip, 1, 0.82, 0, true);
|
|
GameTooltip:Show();
|
|
end
|
|
|
|
if self.onEnterFunc then
|
|
self.onEnterFunc(self);
|
|
end
|
|
end
|
|
|
|
function CheckboxMixin:OnLeave()
|
|
GameTooltip:Hide();
|
|
|
|
if self.onLeaveFunc then
|
|
self.onLeaveFunc(self);
|
|
end
|
|
end
|
|
|
|
function CheckboxMixin:OnClick()
|
|
local newState;
|
|
|
|
if self.dbKey then
|
|
newState = not PlumberDB[self.dbKey];
|
|
PlumberDB[self.dbKey] = newState;
|
|
self:SetChecked(newState);
|
|
else
|
|
newState = not self:GetChecked();
|
|
self:SetChecked(newState);
|
|
print("Plumber: DB Key not assigned");
|
|
end
|
|
|
|
if self.onClickFunc then
|
|
self.onClickFunc(self, newState);
|
|
end
|
|
|
|
if self.checked then
|
|
PlaySound(SFX_CHECKBOX_ON);
|
|
else
|
|
PlaySound(SFX_CHECKBOX_OFF);
|
|
end
|
|
|
|
GameTooltip:Hide();
|
|
end
|
|
|
|
function CheckboxMixin:GetChecked()
|
|
return self.checked
|
|
end
|
|
|
|
function CheckboxMixin:SetChecked(state)
|
|
state = state or false;
|
|
self.CheckedTexture:SetShown(state);
|
|
self.checked = state;
|
|
end
|
|
|
|
function CheckboxMixin:SetFixedWidth(width)
|
|
self.fixedWidth = width;
|
|
self:SetWidth(width);
|
|
end
|
|
|
|
function CheckboxMixin:SetMaxWidth(maxWidth)
|
|
--this width includes box and label
|
|
self.Label:SetWidth(maxWidth - LABEL_OFFSET);
|
|
self.SetWidth(maxWidth);
|
|
end
|
|
|
|
function CheckboxMixin:SetLabel(label)
|
|
self.Label:SetText(label);
|
|
local width = self.Label:GetWrappedWidth() + LABEL_OFFSET;
|
|
local height = self.Label:GetHeight();
|
|
local lines = self.Label:GetNumLines();
|
|
|
|
self.Label:ClearAllPoints();
|
|
if lines > 1 then
|
|
self.Label:SetPoint("TOPLEFT", self, "TOPLEFT", LABEL_OFFSET, -4);
|
|
else
|
|
self.Label:SetPoint("LEFT", self, "LEFT", LABEL_OFFSET, 0);
|
|
end
|
|
|
|
if self.fixedWidth then
|
|
return self.fixedWidth
|
|
else
|
|
self:SetWidth(math.max(BUTTON_HITBOX_MIN_WIDTH, width));
|
|
return width
|
|
end
|
|
end
|
|
|
|
function CheckboxMixin:SetData(data)
|
|
self.dbKey = data.dbKey;
|
|
self.tooltip = data.tooltip;
|
|
self.onClickFunc = data.onClickFunc;
|
|
self.onEnterFunc = data.onEnterFunc;
|
|
self.onLeaveFunc = data.onLeaveFunc;
|
|
|
|
if data.label then
|
|
return self:SetLabel(data.label)
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
local function CreateCheckbox(parent)
|
|
local b = CreateFrame("Button", nil, parent);
|
|
b:SetSize(BUTTON_MIN_SIZE, BUTTON_MIN_SIZE);
|
|
|
|
b.Label = b:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
|
b.Label:SetJustifyH("LEFT");
|
|
b.Label:SetJustifyV("TOP");
|
|
b.Label:SetTextColor(1, 0.82, 0); --labelcolor
|
|
b.Label:SetPoint("LEFT", b, "LEFT", LABEL_OFFSET, 0);
|
|
|
|
b.Border = b:CreateTexture(nil, "ARTWORK");
|
|
b.Border:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
b.Border:SetTexCoord(0, 0.5, 0, 0.5);
|
|
b.Border:SetPoint("CENTER", b, "LEFT", 8, 0);
|
|
b.Border:SetSize(32, 32);
|
|
DisableSharpening(b.Border);
|
|
|
|
b.CheckedTexture = b:CreateTexture(nil, "OVERLAY");
|
|
b.CheckedTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
b.CheckedTexture:SetTexCoord(0.5, 0.75, 0.5, 0.75);
|
|
b.CheckedTexture:SetPoint("CENTER", b.Border, "CENTER", 0, 0);
|
|
b.CheckedTexture:SetSize(16, 16);
|
|
DisableSharpening(b.CheckedTexture);
|
|
b.CheckedTexture:Hide();
|
|
|
|
b.Highlight = b:CreateTexture(nil, "HIGHLIGHT");
|
|
b.Highlight:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
b.Highlight:SetTexCoord(0, 0.5, 0.5, 1);
|
|
b.Highlight:SetPoint("CENTER", b.Border, "CENTER", 0, 0);
|
|
b.Highlight:SetSize(32, 32);
|
|
--b.Highlight:Hide();
|
|
DisableSharpening(b.Highlight);
|
|
|
|
Mixin(b, CheckboxMixin);
|
|
b:SetScript("OnClick", CheckboxMixin.OnClick);
|
|
b:SetScript("OnEnter", CheckboxMixin.OnEnter);
|
|
b:SetScript("OnLeave", CheckboxMixin.OnLeave);
|
|
|
|
return b
|
|
end
|
|
|
|
addon.CreateCheckbox = CreateCheckbox;
|
|
end
|
|
|
|
do -- Common Frame with Header (and close button)
|
|
local function CloseButton_OnClick(self)
|
|
local parent = self:GetParent();
|
|
if parent.CloseUI then
|
|
parent:CloseUI();
|
|
else
|
|
parent:Hide();
|
|
end
|
|
end
|
|
|
|
local function CloseButton_ShowNormalTexture(self)
|
|
self.Texture:SetTexCoord(0, 0.5, 0, 0.5);
|
|
self.Highlight:SetTexCoord(0, 0.5, 0.5, 1);
|
|
end
|
|
|
|
local function CloseButton_ShowPushedTexture(self)
|
|
self.Texture:SetTexCoord(0.5, 1, 0, 0.5);
|
|
self.Highlight:SetTexCoord(0.5, 1, 0.5, 1);
|
|
end
|
|
|
|
local function CreateCloseButton(parent)
|
|
local b = CreateFrame("Button", nil, parent);
|
|
b:SetSize(BUTTON_MIN_SIZE, BUTTON_MIN_SIZE);
|
|
|
|
b.Texture = b:CreateTexture(nil, "ARTWORK");
|
|
b.Texture:SetTexture("Interface/AddOns/Plumber/Art/Button/CloseButton");
|
|
b.Texture:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Texture:SetSize(32, 32);
|
|
DisableSharpening(b.Texture);
|
|
|
|
b.Highlight = b:CreateTexture(nil, "HIGHLIGHT");
|
|
b.Highlight:SetTexture("Interface/AddOns/Plumber/Art/Button/CloseButton");
|
|
b.Highlight:SetPoint("CENTER", b, "CENTER", 0, 0);
|
|
b.Highlight:SetSize(32, 32);
|
|
DisableSharpening(b.Highlight);
|
|
|
|
CloseButton_ShowNormalTexture(b);
|
|
|
|
b:SetScript("OnClick", CloseButton_OnClick);
|
|
b:SetScript("OnMouseUp", CloseButton_ShowNormalTexture);
|
|
b:SetScript("OnMouseDown", CloseButton_ShowPushedTexture);
|
|
b:SetScript("OnShow", CloseButton_ShowNormalTexture);
|
|
|
|
return b
|
|
end
|
|
|
|
|
|
local CategoryDividerMixin = {};
|
|
|
|
function CategoryDividerMixin:HideDivider()
|
|
self.Divider:Hide();
|
|
end
|
|
|
|
local function CreateCategoryDivider(parent, alignCenter)
|
|
local fontString = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
|
if alignCenter then
|
|
fontString:SetJustifyH("CENTER");
|
|
else
|
|
fontString:SetJustifyH("LEFT");
|
|
end
|
|
|
|
fontString:SetJustifyV("TOP");
|
|
fontString:SetTextColor(1, 1, 1);
|
|
|
|
local divider = parent:CreateTexture(nil, "OVERLAY");
|
|
divider:SetHeight(4);
|
|
--divider:SetWidth(240);
|
|
divider:SetPoint("TOPLEFT", fontString, "BOTTOMLEFT", 0, -4);
|
|
divider:SetPoint("RIGHT", parent, "RIGHT", -8, 0);
|
|
|
|
divider:SetTexture("Interface/AddOns/Plumber/Art/Frame/Divider_Gradient_Horizontal");
|
|
divider:SetVertexColor(0.5, 0.5, 0.5);
|
|
DisableSharpening(divider);
|
|
|
|
Mixin(fontString, CategoryDividerMixin);
|
|
|
|
return fontString
|
|
end
|
|
|
|
addon.CreateCategoryDivider = CreateCategoryDivider;
|
|
|
|
|
|
local HeaderFrameMixin = {};
|
|
|
|
function HeaderFrameMixin:SetCornerSize(a)
|
|
|
|
end
|
|
|
|
function HeaderFrameMixin:ShowCloseButton(state)
|
|
self.CloseButton:SetShown(state);
|
|
end
|
|
|
|
function HeaderFrameMixin:SetTitle(title)
|
|
self.Title:SetText(title);
|
|
end
|
|
|
|
function HeaderFrameMixin:GetHeaderHeight()
|
|
return 18
|
|
end
|
|
|
|
local function CreateHeaderFrame(parent, showCloseButton)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:ClearAllPoints();
|
|
|
|
local p = {};
|
|
f.pieces = p;
|
|
|
|
f.Title = f:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
|
f.Title:SetJustifyH("CENTER");
|
|
f.Title:SetJustifyV("MIDDLE");
|
|
f.Title:SetTextColor(1, 0.82, 0);
|
|
f.Title:SetPoint("CENTER", f, "TOP", 0, -8 -1);
|
|
|
|
f.CloseButton = CreateCloseButton(f);
|
|
f.CloseButton:SetPoint("CENTER", f, "TOPRIGHT", -9, -9);
|
|
-- 1 2 3
|
|
-- 4 5 6
|
|
-- 7 8 9
|
|
|
|
local tex = "Interface/AddOns/Plumber/Art/Frame/CommonFrameWithHeader_Opaque";
|
|
|
|
for i = 1, 9 do
|
|
p[i] = f:CreateTexture(nil, "BORDER");
|
|
p[i]:SetTexture(tex);
|
|
DisableSharpening(p[i]);
|
|
p[i]:ClearAllPoints();
|
|
end
|
|
|
|
p[1]:SetPoint("CENTER", f, "TOPLEFT", 0, -8);
|
|
p[3]:SetPoint("CENTER", f, "TOPRIGHT", 0, -8);
|
|
p[7]:SetPoint("CENTER", f, "BOTTOMLEFT", 0, 0);
|
|
p[9]:SetPoint("CENTER", f, "BOTTOMRIGHT", 0, 0);
|
|
p[2]:SetPoint("TOPLEFT", p[1], "TOPRIGHT", 0, 0);
|
|
p[2]:SetPoint("BOTTOMRIGHT", p[3], "BOTTOMLEFT", 0, 0);
|
|
p[4]:SetPoint("TOPLEFT", p[1], "BOTTOMLEFT", 0, 0);
|
|
p[4]:SetPoint("BOTTOMRIGHT",p[7], "TOPRIGHT", 0, 0);
|
|
p[5]:SetPoint("TOPLEFT",p[1], "BOTTOMRIGHT", 0, 0);
|
|
p[5]:SetPoint("BOTTOMRIGHT",p[9], "TOPLEFT", 0, 0);
|
|
p[6]:SetPoint("TOPLEFT",p[3], "BOTTOMLEFT", 0, 0);
|
|
p[6]:SetPoint("BOTTOMRIGHT",p[9], "TOPRIGHT", 0, 0);
|
|
p[8]:SetPoint("TOPLEFT",p[7], "TOPRIGHT", 0, 0);
|
|
p[8]:SetPoint("BOTTOMRIGHT",p[9], "BOTTOMLEFT", 0, 0);
|
|
|
|
p[1]:SetSize(16, 32);
|
|
p[3]:SetSize(16, 32);
|
|
p[7]:SetSize(16, 16);
|
|
p[9]:SetSize(16, 16);
|
|
|
|
p[1]:SetTexCoord(0, 0.25, 0, 0.5);
|
|
p[2]:SetTexCoord(0.25, 0.75, 0, 0.5);
|
|
p[3]:SetTexCoord(0.75, 1, 0, 0.5);
|
|
p[4]:SetTexCoord(0, 0.25, 0.5, 0.75);
|
|
p[5]:SetTexCoord(0.25, 0.75, 0.5, 0.75);
|
|
p[6]:SetTexCoord(0.75, 1, 0.5, 0.75);
|
|
p[7]:SetTexCoord(0, 0.25, 0.75, 1);
|
|
p[8]:SetTexCoord(0.25, 0.75, 0.75, 1);
|
|
p[9]:SetTexCoord(0.75, 1, 0.75, 1);
|
|
|
|
Mixin(f, HeaderFrameMixin);
|
|
f:ShowCloseButton(showCloseButton);
|
|
f:EnableMouse(true);
|
|
|
|
return f
|
|
end
|
|
|
|
addon.CreateHeaderFrame = CreateHeaderFrame;
|
|
end
|
|
|
|
do -- TokenFrame -- Money -- Coin
|
|
local TOKEN_TYPE_CURRENCY = 0;
|
|
local TOKEN_TYPE_ITEM = 1;
|
|
|
|
local TOKEN_FRAME_SIDE_PADDING = 8;
|
|
local TOKEN_FRAME_BUTTON_PADDING = 6;
|
|
local TOKEN_BUTTON_TEXT_ICON_GAP = 0;
|
|
local TOKEN_BUTTON_ICON_SIZE = 12;
|
|
local TOKEN_BUTTON_HEIGHT = 16;
|
|
|
|
local COIN_TYPE_GAP = 4;
|
|
local COIN_TEXTURE_SIZE = 13;
|
|
local COLORBLIND_TEXT_GAP = 0;
|
|
local AMOUNT_COIN_GAP = 0;
|
|
|
|
local NUMBER_K = L["Number Thousands"];
|
|
local NUMBER_M = L["Number Millions"];
|
|
|
|
local BreakUpLargeNumbers = BreakUpLargeNumbers;
|
|
local GetMoney = GetMoney;
|
|
local GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo;
|
|
|
|
|
|
local MoneyDisplayMixin = {};
|
|
|
|
|
|
function MoneyDisplayMixin:SetSimplified(simplified, noUpdate)
|
|
self.isSimplified = simplified;
|
|
if not noUpdate then
|
|
self:Layout();
|
|
end
|
|
end
|
|
|
|
function MoneyDisplayMixin:ClearAmount()
|
|
self.Amount1:SetText("");
|
|
self.Amount2:SetText("");
|
|
self.Amount3:SetText("");
|
|
self.Symbol1:Hide();
|
|
self.Symbol2:Hide();
|
|
self.Symbol3:Hide();
|
|
end
|
|
|
|
function MoneyDisplayMixin:Layout()
|
|
local gold = floor(self.rawCopper / 10000);
|
|
local silver = floor((self.rawCopper - gold * 10000) / 100);
|
|
local copper = floor(self.rawCopper - gold * 10000 - silver * 100);
|
|
|
|
self:ClearAmount();
|
|
|
|
local coinIndex = 0;
|
|
|
|
if self.isSimplified then
|
|
local showSilver = false;
|
|
|
|
if gold > 0 then
|
|
local abbrev;
|
|
|
|
if gold >= 10000000 then --15M 10,000,000
|
|
gold = floor(gold / 1000000);
|
|
gold = gold;
|
|
abbrev = NUMBER_M;
|
|
elseif gold >= 1000000 then --1.5M 1,000,000
|
|
gold = floor(gold / 100000) / 10;
|
|
abbrev = NUMBER_M;
|
|
elseif gold >= 10000 then --150K 15K 10,000
|
|
gold = floor(gold / 1000);
|
|
abbrev = NUMBER_K;
|
|
else
|
|
showSilver = true;
|
|
end
|
|
|
|
coinIndex = coinIndex + 1;
|
|
if abbrev then
|
|
self:SetGoldAmount(coinIndex, gold..abbrev);
|
|
else
|
|
self:SetGoldAmount(coinIndex, gold);
|
|
end
|
|
else
|
|
showSilver = true;
|
|
end
|
|
|
|
local showCopper = gold <= 0;
|
|
|
|
if showSilver and silver > 0 then
|
|
coinIndex = coinIndex + 1;
|
|
self:SetSilverAmount(coinIndex, silver);
|
|
end
|
|
|
|
if showCopper and (copper > 0 or self.rawCopper == 0) then
|
|
coinIndex = coinIndex + 1;
|
|
self:SetCopperAmount(coinIndex, copper);
|
|
end
|
|
else
|
|
if gold > 0 then
|
|
coinIndex = coinIndex + 1;
|
|
gold = BreakUpLargeNumbers(gold);
|
|
self:SetGoldAmount(coinIndex, gold);
|
|
end
|
|
|
|
if silver > 0 then
|
|
coinIndex = coinIndex + 1;
|
|
self:SetSilverAmount(coinIndex, silver);
|
|
end
|
|
|
|
if copper > 0 then
|
|
coinIndex = coinIndex + 1;
|
|
self:SetCopperAmount(coinIndex, copper);
|
|
end
|
|
end
|
|
|
|
|
|
--Sizing
|
|
local width;
|
|
|
|
self.Amount1:SetPoint("LEFT", self, "LEFT", 0, 0);
|
|
width = self.Amount1:GetWrappedWidth() + AMOUNT_COIN_GAP;
|
|
self.Symbol1:SetPoint("LEFT", self, "LEFT", width, 0);
|
|
|
|
if self.colorblindMode then
|
|
width = width + COLORBLIND_TEXT_GAP;
|
|
else
|
|
width = width + COIN_TEXTURE_SIZE;
|
|
end
|
|
|
|
if coinIndex >= 2 then
|
|
width = width + COIN_TYPE_GAP;
|
|
self.Amount2:SetPoint("LEFT", self, "LEFT", width, 0);
|
|
width = width + self.Amount2:GetWrappedWidth() + AMOUNT_COIN_GAP;
|
|
self.Symbol2:SetPoint("LEFT", self, "LEFT", width, 0);
|
|
if self.colorblindMode then
|
|
width = width + COLORBLIND_TEXT_GAP;
|
|
else
|
|
width = width + COIN_TEXTURE_SIZE;
|
|
end
|
|
end
|
|
|
|
if coinIndex >= 3 then
|
|
width = width + COIN_TYPE_GAP;
|
|
self.Amount3:SetPoint("LEFT", self, "LEFT", width, 0);
|
|
width = width + self.Amount3:GetWrappedWidth() + AMOUNT_COIN_GAP;
|
|
self.Symbol3:SetPoint("LEFT", self, "LEFT", width, 0);
|
|
if self.colorblindMode then
|
|
width = width + COLORBLIND_TEXT_GAP;
|
|
else
|
|
width = width + COIN_TEXTURE_SIZE;
|
|
end
|
|
end
|
|
|
|
if self.colorblindMode then
|
|
width = width - COLORBLIND_TEXT_GAP;
|
|
end
|
|
|
|
width = floor(width + 0.5);
|
|
self:SetWidth(width);
|
|
return width
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetTextureGold(texture)
|
|
texture:SetTexCoord(0, 0.25, 0, 1);
|
|
texture:Show();
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetTextureSilver(texture)
|
|
texture:SetTexCoord(0.25, 0.5, 0, 1);
|
|
texture:Show();
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetTextureCopper(texture)
|
|
texture:SetTexCoord(0.5, 0.75, 0, 1);
|
|
texture:Show();
|
|
end
|
|
|
|
function MoneyDisplayMixin:ShowPlayerMoney()
|
|
return self:SetAmount(GetMoney());
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetAmount(rawCopper, playerMoney, minusMoney)
|
|
self.rawCopper = rawCopper or 0;
|
|
|
|
local color;
|
|
|
|
if playerMoney then
|
|
if playerMoney < rawCopper then
|
|
color = 1;
|
|
end
|
|
elseif minusMoney then
|
|
color = 2;
|
|
end
|
|
|
|
if self.color ~= color then
|
|
self.color = color;
|
|
if color == 1 then
|
|
self.Amount1:SetTextColor(0.6, 0.6, 0.6);
|
|
self.Amount2:SetTextColor(0.6, 0.6, 0.6);
|
|
self.Amount3:SetTextColor(0.6, 0.6, 0.6);
|
|
elseif color == 2 then
|
|
self.Amount1:SetTextColor(1.000, 0.125, 0.125);
|
|
self.Amount2:SetTextColor(1.000, 0.125, 0.125);
|
|
self.Amount3:SetTextColor(1.000, 0.125, 0.125);
|
|
else
|
|
self.Amount1:SetTextColor(1, 1, 1);
|
|
self.Amount2:SetTextColor(1, 1, 1);
|
|
self.Amount3:SetTextColor(1, 1, 1);
|
|
end
|
|
end
|
|
|
|
self.colorblindMode = GetCVarBool("colorblindMode");
|
|
|
|
return self:Layout();
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetGoldAmount(coinIndex, amount)
|
|
if self.colorblindMode then
|
|
self["Amount"..coinIndex]:SetText(amount..(GOLD_AMOUNT_SYMBOL or "g"));
|
|
self["Symbol"..coinIndex]:Hide();
|
|
else
|
|
self["Amount"..coinIndex]:SetText(amount);
|
|
self:SetTextureGold(self["Symbol"..coinIndex]);
|
|
end
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetSilverAmount(coinIndex, amount)
|
|
if self.colorblindMode then
|
|
self["Amount"..coinIndex]:SetText(amount..(SILVER_AMOUNT_SYMBOL or "s"));
|
|
self["Symbol"..coinIndex]:Hide();
|
|
else
|
|
self["Amount"..coinIndex]:SetText(amount);
|
|
self:SetTextureSilver(self["Symbol"..coinIndex]);
|
|
end
|
|
end
|
|
|
|
function MoneyDisplayMixin:SetCopperAmount(coinIndex, amount)
|
|
if self.colorblindMode then
|
|
self["Amount"..coinIndex]:SetText(amount..(COPPER_AMOUNT_SYMBOL or "c"));
|
|
self["Symbol"..coinIndex]:Hide();
|
|
else
|
|
self["Amount"..coinIndex]:SetText(amount);
|
|
self:SetTextureCopper(self["Symbol"..coinIndex]);
|
|
end
|
|
end
|
|
|
|
local function CreateMoneyDisplay(parent, numberFont)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetHeight(16);
|
|
f:SetWidth(32);
|
|
Mixin(f, MoneyDisplayMixin);
|
|
|
|
f.rawCopper = 0;
|
|
|
|
local fontObject = numberFont or "NumberFontNormal";
|
|
|
|
f.Amount1 = f:CreateFontString(nil, "OVERLAY", fontObject);
|
|
f.Amount2 = f:CreateFontString(nil, "OVERLAY", fontObject);
|
|
f.Amount3 = f:CreateFontString(nil, "OVERLAY", fontObject);
|
|
|
|
f.Amount1:SetJustifyH("LEFT");
|
|
f.Amount2:SetJustifyH("LEFT");
|
|
f.Amount3:SetJustifyH("LEFT");
|
|
|
|
local iconSize = COIN_TEXTURE_SIZE;
|
|
|
|
f.Symbol1 = f:CreateTexture(nil, "OVERLAY");
|
|
f.Symbol1:SetSize(iconSize, iconSize);
|
|
f.Symbol1:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/CoinSymbol");
|
|
f.Symbol1:SetTexCoord(0, 0.25, 0, 1);
|
|
|
|
f.Symbol2 = f:CreateTexture(nil, "OVERLAY");
|
|
f.Symbol2:SetSize(iconSize, iconSize);
|
|
f.Symbol2:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/CoinSymbol");
|
|
f.Symbol2:SetTexCoord(0, 0.25, 0, 1);
|
|
|
|
f.Symbol3 = f:CreateTexture(nil, "OVERLAY");
|
|
f.Symbol3:SetSize(iconSize, iconSize);
|
|
f.Symbol3:SetTexture("Interface/AddOns/Plumber/Art/BackpackItemTracker/CoinSymbol");
|
|
f.Symbol3:SetTexCoord(0, 0.25, 0, 1);
|
|
|
|
f:SetTextureGold(f.Symbol1);
|
|
f:SetTextureSilver(f.Symbol2);
|
|
f:SetTextureCopper(f.Symbol3);
|
|
|
|
return f
|
|
end
|
|
addon.CreateMoneyDisplay = CreateMoneyDisplay;
|
|
|
|
|
|
local TokenDisplayMixin = {};
|
|
|
|
local function CreateTokenDisplay(parent, layoutName)
|
|
local f = addon.CreateThreeSliceFrame(parent, layoutName);
|
|
f:SetHeight(16);
|
|
f:SetWidth(32);
|
|
Mixin(f, TokenDisplayMixin);
|
|
f.tokens = {};
|
|
f.tokenButtons = {};
|
|
|
|
f:SetScript("OnHide", f.OnHide);
|
|
f:SetScript("OnEvent", f.OnEvent);
|
|
|
|
return f
|
|
end
|
|
addon.CreateTokenDisplay = CreateTokenDisplay;
|
|
|
|
function TokenDisplayMixin:AddCurrency(currencyID)
|
|
for i, tokenInfo in ipairs(self.tokens) do
|
|
if tokenInfo[1] == TOKEN_TYPE_CURRENCY and tokenInfo[2] == currencyID then
|
|
return
|
|
end
|
|
end
|
|
|
|
tinsert(self.tokens, {TOKEN_TYPE_CURRENCY, currencyID});
|
|
self:Update();
|
|
end
|
|
|
|
function TokenDisplayMixin:RemoveCurrency(currencyID)
|
|
local anyChange = false;
|
|
|
|
for i, tokenInfo in ipairs(self.tokens) do
|
|
if tokenInfo[1] == TOKEN_TYPE_CURRENCY and tokenInfo[2] == currencyID then
|
|
table.remove(self.tokens, i);
|
|
anyChange = true;
|
|
break
|
|
end
|
|
end
|
|
|
|
if anyChange then
|
|
self:Update();
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:AddItem(itemID)
|
|
for i, tokenInfo in ipairs(self.tokens) do
|
|
if tokenInfo[1] == TOKEN_TYPE_ITEM and tokenInfo[2] == itemID then
|
|
return
|
|
end
|
|
end
|
|
|
|
tinsert(self.tokens, {TOKEN_TYPE_ITEM, itemID});
|
|
self:Update();
|
|
end
|
|
|
|
function TokenDisplayMixin:SetTokens(tokens)
|
|
self.tokens = {};
|
|
|
|
--[[
|
|
local n = select('#', ...);
|
|
local tokenInfo;
|
|
|
|
for i = 1, n do
|
|
tokenInfo = select(i, ...);
|
|
tinsert(self.tokens, tokenInfo);
|
|
end
|
|
--]]
|
|
|
|
if tokens and #tokens > 0 then
|
|
if type(tokens[1]) == "table" then
|
|
self.tokens = tokens;
|
|
else
|
|
self.tokens[1] = tokens;
|
|
end
|
|
end
|
|
|
|
self:Update();
|
|
end
|
|
|
|
|
|
local function AppendItemCount(tooltip, itemID)
|
|
local inBag = GetItemCount(itemID);
|
|
local total = GetItemCount(itemID, true, false, true);
|
|
local inBank = total - inBag;
|
|
|
|
local text = L["Num Items In Bag Format"]:format(inBag);
|
|
|
|
if inBank > 0 then
|
|
text = text.." "..L["Num Items In Bank Format"]:format(inBank);
|
|
end
|
|
|
|
tooltip:AddLine(text, 1, 0.82, 0, true);
|
|
tooltip:Show();
|
|
end
|
|
|
|
local function TokenButton_OnEnter(self)
|
|
self.UpdateTooltip = nil;
|
|
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
if self.tokenType == 0 and self.currencyID then
|
|
GameTooltip:SetCurrencyByID(self.currencyID);
|
|
elseif self.tokenType == 1 and self.itemID then
|
|
GameTooltip:SetItemByID(self.itemID);
|
|
AppendItemCount(GameTooltip, self.itemID);
|
|
self.UpdateTooltip = function()
|
|
TokenButton_OnEnter(self)
|
|
end
|
|
else
|
|
GameTooltip:Hide();
|
|
end
|
|
end
|
|
|
|
local function TokenButton_OnLeave(self)
|
|
self.UpdateTooltip = nil;
|
|
GameTooltip:Hide();
|
|
end
|
|
|
|
function TokenDisplayMixin:SetupTokenButton(tokenButton, currencyData, currencyInfoCache)
|
|
local tokenType = currencyData[1];
|
|
local id = currencyData[2];
|
|
|
|
--For Vendors
|
|
local numRequired = currencyData[3];
|
|
local icon = currencyData[4];
|
|
local quantity;
|
|
local grayColor = false; --0.6 NumberFontNormalRightGray
|
|
|
|
tokenButton.tokenType = tokenType;
|
|
|
|
if tokenType == TOKEN_TYPE_CURRENCY then
|
|
--Currency
|
|
self.anyCurrency = true;
|
|
tokenButton.currencyID = id;
|
|
tokenButton.itemID = nil;
|
|
|
|
local info;
|
|
|
|
if currencyInfoCache then
|
|
if currencyInfoCache[id] then
|
|
info = currencyInfoCache[id];
|
|
else
|
|
info = GetCurrencyInfo(id);
|
|
currencyInfoCache[id] = info;
|
|
end
|
|
else
|
|
info = GetCurrencyInfo(id);
|
|
end
|
|
|
|
icon = info.iconFileID;
|
|
quantity = info.quantity;
|
|
|
|
elseif tokenType == TOKEN_TYPE_ITEM then
|
|
--Item
|
|
self.anyItem = true;
|
|
tokenButton.currencyID = nil;
|
|
tokenButton.itemID = id;
|
|
icon = GetItemIconByID(id)
|
|
quantity = GetItemCount(id);
|
|
end
|
|
|
|
if quantity then
|
|
tokenButton.Icon:SetTexture(icon);
|
|
if numRequired then
|
|
tokenButton.Count:SetText(numRequired);
|
|
else
|
|
tokenButton.Count:SetText(quantity);
|
|
end
|
|
if numRequired and numRequired > quantity then
|
|
grayColor = true;
|
|
end
|
|
else
|
|
tokenButton.Icon:SetTexture(134400); --question mark
|
|
tokenButton.Count:SetText("??");
|
|
end
|
|
|
|
if grayColor then
|
|
tokenButton.Count:SetTextColor(0.6, 0.6, 0.6);
|
|
tokenButton.Icon:SetVertexColor(0.6, 0.6, 0.6);
|
|
else
|
|
tokenButton.Count:SetTextColor(1, 1, 1);
|
|
tokenButton.Icon:SetVertexColor(1, 1, 1);
|
|
end
|
|
|
|
--update width
|
|
local span = TOKEN_BUTTON_ICON_SIZE + TOKEN_BUTTON_TEXT_ICON_GAP + floor(tokenButton.Count:GetWrappedWidth() + 0.5);
|
|
tokenButton:SetWidth(span);
|
|
return span
|
|
end
|
|
|
|
function TokenDisplayMixin:AcquireTokenButton(index)
|
|
if not self.tokenButtons[index] then
|
|
local button = CreateFrame("Frame", nil, self);
|
|
|
|
button:SetSize(TOKEN_BUTTON_ICON_SIZE, TOKEN_BUTTON_HEIGHT);
|
|
|
|
button.Icon = button:CreateTexture(nil, "ARTWORK");
|
|
button.Icon:SetPoint("RIGHT", button, "RIGHT", 0, 0);
|
|
button.Icon:SetSize(TOKEN_BUTTON_ICON_SIZE, TOKEN_BUTTON_ICON_SIZE);
|
|
button.Icon:SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375);
|
|
|
|
button.Count = button:CreateFontString(nil, "ARTWORK", self.numberFont or "GameFontHighlightSmall");
|
|
button.Count:SetJustifyH("RIGHT");
|
|
button.Count:SetPoint("RIGHT", button.Icon, "LEFT", -TOKEN_BUTTON_TEXT_ICON_GAP, 0);
|
|
|
|
button:SetScript("OnEnter", TokenButton_OnEnter);
|
|
button:SetScript("OnLeave", TokenButton_OnLeave);
|
|
|
|
self.tokenButtons[index] = button;
|
|
end
|
|
|
|
return self.tokenButtons[index]
|
|
end
|
|
|
|
function TokenDisplayMixin:Update()
|
|
local numTokens = #self.tokens;
|
|
local button;
|
|
|
|
local totalWidth = TOKEN_FRAME_SIDE_PADDING;
|
|
local buttonWidth;
|
|
|
|
self:ListenEvents(true);
|
|
|
|
if self.useMoneyFrame and self.MoneyFrame then
|
|
self.MoneyFrame:SetPoint("LEFT", self, "LEFT", totalWidth, 0);
|
|
totalWidth = totalWidth + self.MoneyFrame:ShowPlayerMoney();
|
|
totalWidth = totalWidth + TOKEN_FRAME_BUTTON_PADDING;
|
|
|
|
if numTokens > 0 then
|
|
totalWidth = totalWidth + TOKEN_FRAME_BUTTON_PADDING;
|
|
end
|
|
end
|
|
|
|
for i, tokenInfo in ipairs(self.tokens) do
|
|
button = self:AcquireTokenButton(i);
|
|
button:Show();
|
|
button:SetPoint("LEFT", self, "LEFT", totalWidth, 0);
|
|
buttonWidth = self:SetupTokenButton(button, tokenInfo);
|
|
totalWidth = totalWidth + buttonWidth + TOKEN_FRAME_BUTTON_PADDING;
|
|
end
|
|
|
|
totalWidth = totalWidth - TOKEN_FRAME_BUTTON_PADDING + TOKEN_FRAME_SIDE_PADDING;
|
|
if totalWidth < TOKEN_BUTTON_ICON_SIZE then
|
|
totalWidth = TOKEN_BUTTON_ICON_SIZE;
|
|
end
|
|
self:SetWidth(totalWidth);
|
|
|
|
for i = numTokens + 1, #self.tokenButtons do
|
|
self.tokenButtons[i]:Hide();
|
|
end
|
|
|
|
if self.anyCurrency then
|
|
self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
|
|
end
|
|
|
|
if self.anyItem then
|
|
self:RegisterEvent("BAG_UPDATE");
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:SetFrameOwner(owner, position, offsetX, offsetY)
|
|
--local b = owner:GetBottom();
|
|
--local r = owner:GetRight();
|
|
offsetX = offsetX or 0;
|
|
offsetY = offsetY or 0;
|
|
|
|
self:ClearAllPoints();
|
|
self:SetFrameStrata("FULLSCREEN");
|
|
|
|
local realParent = owner; --UIParent
|
|
|
|
if position == "BOTTOMRIGHT" then
|
|
self:SetPoint("BOTTOMRIGHT", realParent, "BOTTOMRIGHT", offsetX, offsetY);
|
|
--f:SetPoint("CENTER", UIParent, "BOTTOM", 0, 64)
|
|
elseif position == "BOTTOM" then
|
|
self:SetPoint("BOTTOM", realParent, "BOTTOM", offsetX, offsetY);
|
|
elseif position == "BOTTOMLEFT" then
|
|
self:SetPoint("BOTTOMLEFT", realParent, "BOTTOMLEFT", offsetX, offsetY);
|
|
end
|
|
|
|
self:Show();
|
|
end
|
|
|
|
function TokenDisplayMixin:DisplayCurrencyOnFrame(tokens, owner, position, offsetX, offsetY)
|
|
self:SetFrameOwner(owner, position, offsetX, offsetY);
|
|
self:SetTokens(tokens);
|
|
end
|
|
|
|
function TokenDisplayMixin:ShowMoneyFrame(state)
|
|
if state and not self.MoneyFrame then
|
|
self.MoneyFrame = CreateMoneyDisplay(self);
|
|
end
|
|
|
|
self.useMoneyFrame = state;
|
|
if self.MoneyFrame then
|
|
self.MoneyFrame:SetShown(state);
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:HideTokenFrame()
|
|
if self:IsShown() then
|
|
self:Hide();
|
|
self:ClearAllPoints();
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:ListenEvents(state)
|
|
if state then
|
|
self:RegisterEvent("BAG_UPDATE");
|
|
self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
|
|
if self.useMoneyFrame then
|
|
self:RegisterEvent("PLAYER_MONEY");
|
|
end
|
|
else
|
|
self:UnregisterEvent("BAG_UPDATE");
|
|
self:UnregisterEvent("CURRENCY_DISPLAY_UPDATE");
|
|
self:UnregisterEvent("PLAYER_MONEY");
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:OnHide()
|
|
self:ListenEvents(false);
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
|
|
local function Update_Delay(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= 0.2 then
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", nil);
|
|
self:Update();
|
|
end
|
|
end
|
|
|
|
function TokenDisplayMixin:RequestUpdate()
|
|
if not self:IsVisible() then return end;
|
|
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", Update_Delay);
|
|
end
|
|
|
|
function TokenDisplayMixin:OnEvent(event)
|
|
self:ListenEvents(false);
|
|
end
|
|
|
|
|
|
--For Merchant Vendor Item Price
|
|
--Update is controlled by a shared event listener
|
|
local PriceDisplayMixin = {};
|
|
PriceDisplayMixin.SetupTokenButton = TokenDisplayMixin.SetupTokenButton;
|
|
PriceDisplayMixin.AcquireTokenButton = TokenDisplayMixin.AcquireTokenButton;
|
|
PriceDisplayMixin.SetFrameOwner = TokenDisplayMixin.SetFrameOwner;
|
|
PriceDisplayMixin.ShowMoneyFrame = TokenDisplayMixin.ShowMoneyFrame;
|
|
|
|
function PriceDisplayMixin:SetMoneyAndAltCurrency(rawCopper, altCurrency, playerMoney)
|
|
rawCopper = rawCopper or 0;
|
|
|
|
if rawCopper > 0 then
|
|
self:ShowMoneyFrame(true);
|
|
self.MoneyFrame:SetAmount(rawCopper, playerMoney);
|
|
else
|
|
self:ShowMoneyFrame(false);
|
|
end
|
|
|
|
self.tokens = altCurrency;
|
|
|
|
self:Update();
|
|
end
|
|
|
|
function PriceDisplayMixin:Update()
|
|
local numTokens = self.tokens and #self.tokens or 0;
|
|
local button, tokenInfo;
|
|
|
|
local totalWidth = 0;
|
|
local buttonWidth;
|
|
|
|
if self.useMoneyFrame then
|
|
self.MoneyFrame:SetPoint("LEFT", self, "LEFT", totalWidth, 0);
|
|
totalWidth = totalWidth + self.MoneyFrame:GetWidth();
|
|
if numTokens > 0 then
|
|
totalWidth = totalWidth + TOKEN_FRAME_BUTTON_PADDING;
|
|
end
|
|
end
|
|
|
|
for i = 1, #self.tokenButtons do --re-trigger OnEnter
|
|
self.tokenButtons[i]:Hide();
|
|
end
|
|
|
|
local currencyInfoCache = {};
|
|
|
|
for i = 1, numTokens do
|
|
tokenInfo = self.tokens[i];
|
|
button = self:AcquireTokenButton(i);
|
|
button:Show();
|
|
if i > 1 then
|
|
totalWidth = totalWidth + TOKEN_FRAME_BUTTON_PADDING;
|
|
end
|
|
button:SetPoint("LEFT", self, "LEFT", totalWidth, 0);
|
|
buttonWidth = self:SetupTokenButton(button, tokenInfo, currencyInfoCache);
|
|
totalWidth = totalWidth + buttonWidth;
|
|
end
|
|
|
|
if totalWidth < 0 then
|
|
--On test realm some items don't have a price
|
|
totalWidth = 1;
|
|
end
|
|
|
|
self:SetWidth(totalWidth);
|
|
end
|
|
|
|
local function CreatePriceDisplay(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
|
|
f:SetHeight(16);
|
|
f:SetWidth(32);
|
|
Mixin(f, PriceDisplayMixin);
|
|
f.tokens = {};
|
|
f.tokenButtons = {};
|
|
f.numberFont = "NumberFontNormal";
|
|
|
|
return f
|
|
end
|
|
addon.CreatePriceDisplay = CreatePriceDisplay;
|
|
end
|
|
|
|
do -- PeudoActionButton (a real ActionButtonTemplate will be attached to the button onMouseOver)
|
|
local PostClickOverlay;
|
|
local GetItemMaxStackSizeByID = C_Item.GetItemMaxStackSizeByID;
|
|
|
|
local function PostClickOverlay_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
self.alpha = 1 - self.t*5;
|
|
self.scale = 1 + self.t*0.5;
|
|
if self.alpha < 0 then
|
|
self.alpha = 0;
|
|
self:Hide();
|
|
end
|
|
self:SetAlpha(self.alpha);
|
|
self:SetScale(self.scale);
|
|
end
|
|
|
|
local PeudoActionButtonMixin = {};
|
|
|
|
function PeudoActionButtonMixin:ShowPostClickEffect()
|
|
if not PostClickOverlay then
|
|
PostClickOverlay = CreateFrame("Frame", nil, self);
|
|
PostClickOverlay:Hide();
|
|
PostClickOverlay:SetScript("OnUpdate", PostClickOverlay_OnUpdate);
|
|
PostClickOverlay:SetSize(64, 64);
|
|
|
|
local texture = PostClickOverlay:CreateTexture(nil, "OVERLAY");
|
|
PostClickOverlay.Texture = texture;
|
|
texture:SetSize(64, 64);
|
|
texture:SetPoint("CENTER", PostClickOverlay, "CENTER", 0, 0);
|
|
texture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-PostClickFeedback");
|
|
texture:SetBlendMode("ADD");
|
|
end
|
|
|
|
PostClickOverlay:ClearAllPoints();
|
|
PostClickOverlay:SetParent(self);
|
|
PostClickOverlay:SetScale(1);
|
|
PostClickOverlay:SetAlpha(0);
|
|
PostClickOverlay.t = 0;
|
|
PostClickOverlay:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
PostClickOverlay:Show();
|
|
end
|
|
|
|
function PeudoActionButtonMixin:SetIcon(icon)
|
|
self.Icon:SetTexture(icon);
|
|
end
|
|
|
|
function PeudoActionButtonMixin:SetIconState(index)
|
|
if index == 1 then
|
|
self.Icon:SetVertexColor(1, 1, 1);
|
|
elseif index == 2 then
|
|
self.Icon:SetVertexColor(0.4, 0.4, 0.4);
|
|
else
|
|
self.Icon:SetVertexColor(1, 1, 1);
|
|
end
|
|
end
|
|
|
|
function PeudoActionButtonMixin:SetItem(item)
|
|
local icon = GetItemIconByID(item);
|
|
self:SetIcon(icon);
|
|
self.id = item;
|
|
self.actionType = "item";
|
|
local stackSize = GetItemMaxStackSizeByID(item)
|
|
self.stackable = stackSize and stackSize > 1;
|
|
self:UpdateCount();
|
|
end
|
|
|
|
function PeudoActionButtonMixin:UpdateCount()
|
|
local count = 0;
|
|
|
|
if self.actionType == "item" then
|
|
count = GetItemCount(self.id);
|
|
if self.stackable then
|
|
self.Count:SetText(count);
|
|
else
|
|
self.Count:SetText("");
|
|
end
|
|
elseif self.actionType == "spell" then
|
|
local currentCharges, maxCharges = GetSpellCharges();
|
|
if currentCharges then
|
|
count = currentCharges;
|
|
else
|
|
self.Count:SetText("");
|
|
end
|
|
end
|
|
|
|
self.charges = count;
|
|
|
|
if count > 0 then
|
|
self:SetIconState(1);
|
|
else
|
|
self:SetIconState(2);
|
|
--self.Count:SetText("");
|
|
end
|
|
end
|
|
|
|
function PeudoActionButtonMixin:GetCharges()
|
|
if not self.charges then
|
|
self:UpdateCount();
|
|
end
|
|
return self.charges
|
|
end
|
|
|
|
function PeudoActionButtonMixin:HasCharges()
|
|
return self:GetCharges() > 0
|
|
end
|
|
|
|
function PeudoActionButtonMixin:SetStatePushed()
|
|
self.NormalTexture:Hide();
|
|
self.PushedTexture:Show();
|
|
self.Icon:SetSize(39, 39);
|
|
end
|
|
|
|
function PeudoActionButtonMixin:SetStateNormal()
|
|
self.NormalTexture:Show();
|
|
self.PushedTexture:Hide();
|
|
self.Icon:SetSize(40, 40);
|
|
end
|
|
|
|
local function CreatePeudoActionButton(parent)
|
|
local button = CreateFrame("Button", nil, parent);
|
|
button:SetSize(46, 46); --Stock ActionButton is 45x45
|
|
|
|
--[[
|
|
button.Border = button:CreateTexture(nil, "ARTWORK", nil, 2);
|
|
button.Border:SetSize(64, 64);
|
|
button.Border:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
button.Border:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Border");
|
|
button.Border:SetTexCoord(0, 1, 0, 1);
|
|
--]]
|
|
|
|
local NormalTexture = button:CreateTexture(nil, "OVERLAY", nil, 2);
|
|
button.NormalTexture = NormalTexture;
|
|
NormalTexture:SetSize(64, 64);
|
|
NormalTexture:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
NormalTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Border");
|
|
NormalTexture:SetTexCoord(0, 1, 0, 1);
|
|
button:SetNormalTexture(NormalTexture);
|
|
|
|
local PushedTexture = button:CreateTexture(nil, "OVERLAY", nil, 2);
|
|
button.PushedTexture = PushedTexture;
|
|
PushedTexture:SetSize(64, 64);
|
|
PushedTexture:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
PushedTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Highlight-Full");
|
|
PushedTexture:SetTexCoord(0, 1, 0, 1);
|
|
button:SetPushedTexture(PushedTexture);
|
|
|
|
local HighlightTexture = button:CreateTexture(nil, "OVERLAY", nil, 5);
|
|
button.HighlightTexture = HighlightTexture;
|
|
HighlightTexture:SetSize(64, 64);
|
|
HighlightTexture:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
HighlightTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Highlight-Inner");
|
|
HighlightTexture:SetTexCoord(0, 1, 0, 1);
|
|
button:SetHighlightTexture(HighlightTexture, "BLEND");
|
|
|
|
button.Icon = button:CreateTexture(nil, "BORDER");
|
|
button.Icon:SetSize(40, 40);
|
|
button.Icon:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
button.Icon:SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375);
|
|
|
|
local mask = button:CreateMaskTexture(nil, "ARTWORK", nil, 2);
|
|
mask:SetPoint("TOPLEFT", button.Icon, "TOPLEFT", 0, 0);
|
|
mask:SetPoint("BOTTOMRIGHT", button.Icon, "BOTTOMRIGHT", 0, 0);
|
|
mask:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Circle", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE");
|
|
button.Icon:AddMaskTexture(mask);
|
|
|
|
button.Count = button:CreateFontString(nil, "OVERLAY", "NumberFontNormal", 6);
|
|
button.Count:SetJustifyH("RIGHT");
|
|
button.Count:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -2, 2);
|
|
|
|
Mixin(button, PeudoActionButtonMixin);
|
|
|
|
return button
|
|
end
|
|
addon.CreatePeudoActionButton = CreatePeudoActionButton;
|
|
|
|
|
|
local ActionButtonSpellCastOverlayMixin = {};
|
|
|
|
function ActionButtonSpellCastOverlayMixin:FadeIn()
|
|
FadeFrame(self, 0.25, 1, 0);
|
|
end
|
|
|
|
function ActionButtonSpellCastOverlayMixin:FadeOut()
|
|
FadeFrame(self, 0.25, 0);
|
|
self.Cooldown:Pause();
|
|
end
|
|
|
|
local PI2 = -2*math.pi;
|
|
local ceil = math.ceil;
|
|
|
|
local function Cooldown_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t < self.duration then
|
|
self.EdgeTexture:SetRotation( self.t/self.duration * PI2 );
|
|
end
|
|
|
|
self.tick = self.tick + elapsed;
|
|
if self.tick >= 0.2 then
|
|
self.tick = 0;
|
|
local startTimeMs, durationMs = self:GetCooldownTimes();
|
|
local currentTimeSeconds = GetTime();
|
|
local elapsedTime = currentTimeSeconds - (startTimeMs / 1000.0);
|
|
local remainingTimeSeconds = (durationMs / 1000.0) - elapsedTime;
|
|
self.t = elapsedTime; --Sync time
|
|
if self.showCountdownNumber then
|
|
remainingTimeSeconds = ceil(remainingTimeSeconds);
|
|
self.BackupCountdownNumber:SetText(remainingTimeSeconds);
|
|
end
|
|
end
|
|
end
|
|
|
|
function ActionButtonSpellCastOverlayMixin:SetDuration(second)
|
|
second = second or 0;
|
|
self.Cooldown:SetCooldownDuration(second);
|
|
if second > 0 then
|
|
self.Cooldown:Resume();
|
|
self.Cooldown.t = 0;
|
|
self.Cooldown.tick = 0;
|
|
self.Cooldown.duration = second;
|
|
self.Cooldown.EdgeTexture:Show();
|
|
self.Cooldown.EdgeTexture:SetRotation(0);
|
|
self.supposedEndTime = time() + second;
|
|
local countdownNumberEnabled = GetCVarBool("countdownForCooldowns");
|
|
self.Cooldown.showCountdownNumber = not countdownNumberEnabled;
|
|
self.Cooldown.BackupCountdownNumber:SetShown(not countdownNumberEnabled);
|
|
self.Cooldown.BackupCountdownNumber:SetText("");
|
|
self.Cooldown:SetScript("OnUpdate", Cooldown_OnUpdate);
|
|
else
|
|
self.Cooldown:SetScript("OnUpdate", nil);
|
|
self.Cooldown.EdgeTexture:Hide();
|
|
self.supposedEndTime = nil;
|
|
self.Cooldown.BackupCountdownNumber:SetText("");
|
|
end
|
|
end
|
|
|
|
local function CreateActionButtonSpellCastOverlay(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(46, 46);
|
|
|
|
--[[
|
|
f.Border = f:CreateTexture(nil, "BACKGROUND", nil, 4);
|
|
f.Border:SetSize(64, 64);
|
|
f.Border:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
f.Border:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-SpellCast-Border", nil, nil, "TRILINEAR");
|
|
f.Border:SetTexCoord(0, 1, 0, 1);
|
|
f.Border:Hide();
|
|
--]]
|
|
|
|
local InnerShadow = f:CreateTexture(nil, "OVERLAY", nil, 1); --Use this texture to increase contrast (HighlightTexture/SwipeTexture)
|
|
InnerShadow:SetSize(64, 64);
|
|
InnerShadow:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
InnerShadow:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-SpellCast-InnerShadow");
|
|
InnerShadow:SetTexCoord(0, 1, 0, 1);
|
|
|
|
f.Cooldown = CreateFrame("Cooldown", nil, f);
|
|
f.Cooldown:SetSize(64, 64);
|
|
f.Cooldown:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
f.Cooldown:SetHideCountdownNumbers(false); --globally controlled by CVar "countdownForCooldowns" (boolean)
|
|
f.Cooldown.noCooldownCount = true; --Disabled for OmniCC ( see OmniCC\core\cooldown.lua Cooldown:OnCooldownDone() )
|
|
|
|
local CountdownNumber = f.Cooldown:CreateFontString(nil, "OVERLAY", nil, 6);
|
|
f.Cooldown.BackupCountdownNumber = CountdownNumber;
|
|
local font, fontHeight, flBarShake = GameFontNormal:GetFont();
|
|
CountdownNumber:SetFont(font, 16, "OUTLINE");
|
|
CountdownNumber:SetPoint("CENTER", f.Cooldown, "CENTER", 0, -1);
|
|
CountdownNumber:SetJustifyH("CENTER");
|
|
CountdownNumber:SetJustifyV("MIDDLE");
|
|
CountdownNumber:SetShadowOffset(1, -1);
|
|
CountdownNumber:SetShadowColor(0, 0, 0);
|
|
CountdownNumber:SetTextColor(1, 1, 1);
|
|
|
|
f.Cooldown:SetSwipeTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-SpellCast-Swipe");
|
|
f.Cooldown:SetSwipeColor(1, 1, 1);
|
|
f.Cooldown:SetDrawSwipe(true);
|
|
|
|
---- It seems creating edge doesn't work in Lua
|
|
--f.Cooldown:SetEdgeTexture("Interface/Cooldown/edge", 1, 1, 1, 1); --Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-SpellCast-Edge
|
|
--f.Cooldown:SetDrawEdge(true);
|
|
--f.Cooldown:SetEdgeScale(1);
|
|
--f.Cooldown:SetUseCircularEdge(true);
|
|
|
|
local EdgeTexture = f.Cooldown:CreateTexture(nil, "OVERLAY", nil, 6);
|
|
f.Cooldown.EdgeTexture = EdgeTexture;
|
|
EdgeTexture:SetSize(64, 64);
|
|
EdgeTexture:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
EdgeTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-SpellCast-Edge");
|
|
EdgeTexture:SetTexCoord(0, 1, 0, 1);
|
|
EdgeTexture:Hide();
|
|
|
|
Mixin(f, ActionButtonSpellCastOverlayMixin);
|
|
|
|
return f
|
|
end
|
|
addon.CreateActionButtonSpellCastOverlay = CreateActionButtonSpellCastOverlay;
|
|
end
|
|
|
|
|
|
do --(In)Secure Button Pool
|
|
local InCombatLockdown = InCombatLockdown;
|
|
|
|
local SecureButtons = {}; --All SecureButton that were created. Recycle/Share unused buttons unless it was specified not to
|
|
local PrivateSecureButtons = {}; --These are the buttons that are not shared with other modules
|
|
|
|
local SecureButtonContainer = CreateFrame("Frame"); --Always hidden
|
|
SecureButtonContainer:Hide();
|
|
|
|
function SecureButtonContainer:CollectButton(button)
|
|
if not InCombatLockdown() then
|
|
button:ClearAllPoints();
|
|
button:Hide();
|
|
button:SetParent(self);
|
|
button:ClearActions();
|
|
button:ClearScripts();
|
|
button.isActive = false;
|
|
end
|
|
end
|
|
|
|
SecureButtonContainer:SetScript("OnEvent", function(self, event, ...)
|
|
if event == "PLAYER_REGEN_DISABLED" then
|
|
local anyActive = false;
|
|
for i, button in ipairs(SecureButtons) do
|
|
if button.isActive then
|
|
self:CollectButton(button);
|
|
anyActive = true;
|
|
end
|
|
end
|
|
|
|
if not anyActive then
|
|
self:UnregisterEvent(event);
|
|
end
|
|
end
|
|
end);
|
|
|
|
local function SecureActionButton_OnHide(self)
|
|
if self.isActive then
|
|
self:Release();
|
|
end
|
|
if self.onHideCallback then
|
|
self.onHideCallback(self);
|
|
end
|
|
end
|
|
|
|
local SecureButtonMixin = {};
|
|
|
|
function SecureButtonMixin:Release()
|
|
SecureButtonContainer:CollectButton(self);
|
|
end
|
|
|
|
function SecureButtonMixin:ShowDebugHitRect(state)
|
|
if state then
|
|
if not self.debugBG then
|
|
self.debugBG = self:CreateTexture(nil, "BACKGROUND");
|
|
self.debugBG:SetAllPoints(true);
|
|
self.debugBG:SetColorTexture(1, 0, 0, 0.5);
|
|
end
|
|
else
|
|
if self.debugBG then
|
|
self.debugBG:Hide();
|
|
end
|
|
end
|
|
end
|
|
|
|
function SecureButtonMixin:SetMacroText(macroText)
|
|
self:SetAttribute("macrotext", macroText);
|
|
self.macroText = macroText;
|
|
end
|
|
|
|
function SecureButtonMixin:ClearActions()
|
|
if self.macroText then
|
|
self.macroText = nil;
|
|
self:SetAttribute("type", nil);
|
|
self:SetAttribute("type1", nil);
|
|
self:SetAttribute("type2", nil);
|
|
self:SetAttribute("macrotext", nil);
|
|
end
|
|
end
|
|
|
|
function SecureButtonMixin:ClearScripts()
|
|
self:SetScript("OnEnter", nil);
|
|
self:SetScript("OnLeave", nil);
|
|
self:SetScript("PostClick", nil);
|
|
self:SetScript("OnMouseDown", nil);
|
|
self:SetScript("OnMouseUp", nil);
|
|
end
|
|
|
|
local function CreateSecureActionButton()
|
|
if InCombatLockdown() then return end;
|
|
local index = #SecureButtons + 1;
|
|
local button = CreateFrame("Button", nil, nil, "InsecureActionButtonTemplate"); --Perform action outside of combat
|
|
SecureButtons[index] = button;
|
|
button.index = index;
|
|
button.isActive = true;
|
|
Mixin(button, SecureButtonMixin);
|
|
|
|
button:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonDown", "RightButtonUp");
|
|
button:SetScript("OnHide", SecureActionButton_OnHide);
|
|
|
|
SecureButtonContainer:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
--SecureButtonContainer:RegisterEvent("PLAYER_REGEN_ENABLED");
|
|
|
|
return button
|
|
end
|
|
|
|
local function AcquireSecureActionButton(privateKey)
|
|
if InCombatLockdown() then return end;
|
|
|
|
local button;
|
|
|
|
if privateKey then
|
|
button = PrivateSecureButtons[privateKey];
|
|
if not button then
|
|
button = CreateSecureActionButton();
|
|
PrivateSecureButtons[privateKey] = button;
|
|
end
|
|
else
|
|
for i, b in ipairs(SecureButtons) do
|
|
if not b:IsShown() then
|
|
b.isActive = true;
|
|
button = b;
|
|
break
|
|
end
|
|
end
|
|
|
|
if not button then
|
|
button = CreateSecureActionButton();
|
|
end
|
|
end
|
|
|
|
button.isActive = true;
|
|
SecureButtonContainer:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
|
|
return button
|
|
end
|
|
addon.AcquireSecureActionButton = AcquireSecureActionButton;
|
|
end
|
|
|
|
|
|
do
|
|
local SecondsToTime = API.SecondsToTime;
|
|
|
|
local TimerFrameMixin = {};
|
|
--t0: totalElapsed
|
|
--t1: totalElapsed (between 0 - 1)
|
|
--s1: elapsedSeconds
|
|
--s0: full duration
|
|
|
|
function TimerFrameMixin:Init()
|
|
if not self.styleID then
|
|
self:SetStyle(2);
|
|
self:SetBarColor(131/255, 208/255, 228/255);
|
|
self:AbbreviateTimeText(true);
|
|
end
|
|
end
|
|
|
|
function TimerFrameMixin:Clear()
|
|
self:SetScript("OnUpdate", nil);
|
|
self.t0 = 0;
|
|
self.t1 = 0;
|
|
self.s1 = 1;
|
|
self.s0 = 1;
|
|
self.startTime = nil;
|
|
if self.BarMark then
|
|
self.BarMark:Hide();
|
|
end
|
|
self.DisplayProgress(self);
|
|
end
|
|
|
|
function TimerFrameMixin:Calibrate()
|
|
if self.startTime then
|
|
local currentTime = time();
|
|
self.t0 = currentTime - self.startTime;
|
|
self.s1 = self.t0;
|
|
self.DisplayProgress(self);
|
|
end
|
|
end
|
|
|
|
function TimerFrameMixin:SetTimes(currentSecond, total)
|
|
if currentSecond >= total or total == 0 then
|
|
self:Clear();
|
|
else
|
|
self.t0 = currentSecond;
|
|
self.t1 = 0;
|
|
self.s1 = floor(currentSecond + 0.5);
|
|
self.s0 = total;
|
|
self:SetScript("OnUpdate", self.OnUpdate);
|
|
self.DisplayProgress(self);
|
|
self.startTime = time();
|
|
if self.BarMark and self.styleID == 2 then
|
|
self.BarMark:Show();
|
|
end
|
|
end
|
|
end
|
|
|
|
function TimerFrameMixin:SetDuration(second)
|
|
self:SetTimes(0, second);
|
|
end
|
|
|
|
function TimerFrameMixin:SetEndTime(endTime)
|
|
local t = time();
|
|
self:SetDuration( (t > endTime and (t - endTime)) or 0 );
|
|
end
|
|
|
|
function TimerFrameMixin:SetReverse(reverse)
|
|
--If reverse, show remaining seconds instead of elpased seconds
|
|
self.isReverse = reverse;
|
|
end
|
|
|
|
function TimerFrameMixin:OnUpdate(elapsed)
|
|
self.t0 = self.t0 + elapsed;
|
|
self.t1 = self.t1 + elapsed;
|
|
|
|
if self.t0 >= self.s0 then
|
|
self:Clear();
|
|
return
|
|
end
|
|
|
|
if self.t1 > 1 then
|
|
self.t1 = self.t1 - 1;
|
|
self.s1 = self.s1 + 1;
|
|
self.DisplayProgress(self);
|
|
end
|
|
|
|
if self.continuous then
|
|
self.UpdateEveryFrame(self);
|
|
end
|
|
end
|
|
|
|
function TimerFrameMixin:AbbreviateTimeText(state)
|
|
self.abbreviated = state or false;
|
|
end
|
|
|
|
local function DisplayProgress_SimpleText(self)
|
|
if self.isReverse then
|
|
self.TimeText:SetText( SecondsToTime(self.s0 - self.s1, self.abbreviated) );
|
|
else
|
|
self.TimeText:SetText( SecondsToTime(self.s1, self.abbreviated) );
|
|
end
|
|
end
|
|
|
|
local function DisplayProgress_StatusBar(self)
|
|
if self.isReverse then
|
|
self.fw = (1 - self.s1/self.s0) * self.maxBarFillWidth;
|
|
else
|
|
self.fw = (self.s1/self.s0) * self.maxBarFillWidth;
|
|
end
|
|
if self.fw < 0.1 then
|
|
self.fw = 0.1;
|
|
end
|
|
self.BarFill:SetWidth(self.fw);
|
|
end
|
|
|
|
local function DisplayProgress_Style2(self)
|
|
DisplayProgress_SimpleText(self);
|
|
DisplayProgress_StatusBar(self);
|
|
end
|
|
|
|
local function UpdateEveryFrame_TimeText(self)
|
|
|
|
end
|
|
|
|
local function UpdateEveryFrame_StatusBar(self)
|
|
if self.isReverse then
|
|
self.fw = (1 - self.t0/self.s0) * self.maxBarFillWidth;
|
|
else
|
|
self.fw = (self.t0/self.s0) * self.maxBarFillWidth;
|
|
end
|
|
if self.fw < 0.1 then
|
|
self.fw = 0.1;
|
|
end
|
|
self.BarFill:SetWidth(self.fw);
|
|
end
|
|
|
|
function TimerFrameMixin:UpdateMaxBarFillWidth()
|
|
self.maxBarFillWidth = self:GetWidth() - 4;
|
|
end
|
|
|
|
function TimerFrameMixin:SetContinuous(state)
|
|
--Do something every frame instead of every second
|
|
self.continuous = state or false;
|
|
end
|
|
|
|
function TimerFrameMixin:SetStyle(styleID)
|
|
if styleID == self.styleID then return end;
|
|
self.styleID = styleID;
|
|
|
|
if styleID == 1 then
|
|
--Simple Text
|
|
self.DisplayProgress = DisplayProgress_SimpleText;
|
|
self.UpdateEveryFrame = UpdateEveryFrame_TimeText;
|
|
self.TimeText:SetFontObject("GameTooltipText");
|
|
self.TimeText:SetTextColor(1, 1, 1);
|
|
if self.BarLeft then
|
|
self.BarLeft:Hide();
|
|
self.BarCenter:Hide();
|
|
self.BarRight:Hide();
|
|
self.BarBG:Hide();
|
|
self.BarFill:Hide();
|
|
self.BarMark:Hide();
|
|
end
|
|
elseif styleID == 2 then
|
|
--StatusBar
|
|
self.DisplayProgress = DisplayProgress_Style2;
|
|
self.UpdateEveryFrame = UpdateEveryFrame_StatusBar;
|
|
|
|
local font, height, flBarShake = GameFontHighlightSmall:GetFont();
|
|
self.TimeText:SetFont(font, 10, "");
|
|
self.TimeText:SetTextColor(0, 0, 0);
|
|
|
|
if not self.BarLeft then
|
|
local file = "Interface/AddOns/Plumber/Art/Frame/StatusBar_Small";
|
|
self.BarLeft = self:CreateTexture(nil, "OVERLAY");
|
|
self.BarLeft:SetSize(16, 32);
|
|
self.BarLeft:SetTexture(file);
|
|
self.BarLeft:SetTexCoord(0, 0.25, 0, 0.5);
|
|
self.BarLeft:SetPoint("CENTER", self, "LEFT", 0, 0);
|
|
|
|
self.BarRight = self:CreateTexture(nil, "OVERLAY");
|
|
self.BarRight:SetSize(16, 32);
|
|
self.BarRight:SetTexture(file);
|
|
self.BarRight:SetTexCoord(0.75, 1, 0, 0.5);
|
|
self.BarRight:SetPoint("CENTER", self, "RIGHT", 0, 0);
|
|
|
|
self.BarCenter = self:CreateTexture(nil, "OVERLAY");
|
|
self.BarCenter:SetTexture(file);
|
|
self.BarCenter:SetTexCoord(0.25, 0.75, 0, 0.5);
|
|
self.BarCenter:SetPoint("TOPLEFT", self.BarLeft, "TOPRIGHT", 0, 0);
|
|
self.BarCenter:SetPoint("BOTTOMRIGHT", self.BarRight, "BOTTOMLEFT", 0, 0);
|
|
|
|
self.BarBG = self:CreateTexture(nil, "BACKGROUND");
|
|
self.BarBG:SetTexture(file);
|
|
self.BarBG:SetTexCoord(0.015625, 0.265625, 0.515625, 0.765625);
|
|
self.BarBG:SetSize(14, 14);
|
|
self.BarBG:SetPoint("LEFT", self, "LEFT", 0, 0);
|
|
self.BarBG:SetPoint("RIGHT", self, "RIGHT", 0, 0);
|
|
|
|
self.BarFill = self:CreateTexture(nil, "ARTWORK");
|
|
self.BarFill:SetTexture(file);
|
|
self.BarFill:SetTexCoord(0.296875, 0.5, 0.53125, 0.734375);
|
|
self.BarFill:SetSize(13, 13);
|
|
self.BarFill:SetPoint("LEFT", self, "LEFT", 2, 0);
|
|
|
|
self.BarMark = self:CreateTexture(nil, "OVERLAY", nil, 1);
|
|
self.BarMark:SetTexture(file);
|
|
self.BarMark:SetTexCoord(0.625, 1, 0.515625, 0.765625);
|
|
self.BarMark:SetSize(24, 16);
|
|
self.BarMark:SetPoint("CENTER", self.BarFill, "RIGHT", 0, 0);
|
|
|
|
API.DisableSharpening(self.BarLeft);
|
|
API.DisableSharpening(self.BarRight);
|
|
API.DisableSharpening(self.BarCenter);
|
|
API.DisableSharpening(self.BarBG);
|
|
API.DisableSharpening(self.BarFill);
|
|
|
|
self:UpdateMaxBarFillWidth();
|
|
end
|
|
|
|
self.BarLeft:Show();
|
|
self.BarCenter:Show();
|
|
self.BarRight:Show();
|
|
self.BarBG:Show();
|
|
self.BarFill:Show();
|
|
self.BarMark:Show();
|
|
end
|
|
end
|
|
|
|
function TimerFrameMixin:SetBarColor(r, g, b)
|
|
if self.BarFill then
|
|
self.BarFill:SetVertexColor(r, g, b);
|
|
end
|
|
end
|
|
|
|
local function CreateTimerFrame(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(48, 16);
|
|
|
|
f.TimeText = f:CreateFontString(nil, "OVERLAY", "GameTooltipText", 2);
|
|
f.TimeText:SetJustifyH("CENTER");
|
|
f.TimeText:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
|
|
Mixin(f, TimerFrameMixin);
|
|
f:SetScript("OnSizeChanged", f.UpdateMaxBarFillWidth);
|
|
f:SetScript("OnShow", f.Calibrate);
|
|
f:Init();
|
|
|
|
return f
|
|
end
|
|
addon.CreateTimerFrame = CreateTimerFrame;
|
|
|
|
|
|
local TinyStatusBarMixin = {};
|
|
|
|
function TinyStatusBarMixin:Init()
|
|
local px = API.GetPixelForWidget(self, 1);
|
|
self.Stroke:SetPoint("TOPLEFT", self, "TOPLEFT", -px, px);
|
|
self.Stroke:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", px, -px);
|
|
self.OutStroke:SetPoint("TOPLEFT", self, "TOPLEFT", -2*px, 2*px);
|
|
self.OutStroke:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 2*px, -2*px);
|
|
self:SetHeight((self.heightPixel or 2)*px);
|
|
self:UpdateMaxBarFillWidth();
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetBarColor(r, g, b)
|
|
self.BarFill:SetColorTexture(r, g, b);
|
|
end
|
|
|
|
function TinyStatusBarMixin:Calibrate()
|
|
if self.startTime then
|
|
local currentTime = time();
|
|
self.t0 = currentTime - self.startTime;
|
|
self.s1 = self.t0;
|
|
self.DisplayProgress(self);
|
|
end
|
|
end
|
|
|
|
function TinyStatusBarMixin:Clear()
|
|
self:SetScript("OnUpdate", nil);
|
|
self.t = 0;
|
|
self.duration = 0;
|
|
self.startTime = nil;
|
|
self.BarFill:Hide();
|
|
end
|
|
|
|
function TinyStatusBarMixin:UpdateMaxBarFillWidth()
|
|
self.maxBarFillWidth = self:GetWidth();
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetTimes(currentSecond, total)
|
|
if currentSecond >= total or total == 0 then
|
|
self:Clear();
|
|
else
|
|
self.t = currentSecond;
|
|
self.duration = total;
|
|
self:SetScript("OnUpdate", self.OnUpdate);
|
|
self:DisplayProgress();
|
|
self.startTime = time();
|
|
self.BarFill:Show();
|
|
end
|
|
end
|
|
|
|
function TinyStatusBarMixin:DisplayProgress()
|
|
if self.isReverse then
|
|
self.BarFill:SetWidth(self.maxBarFillWidth * (1 - self.t/self.duration));
|
|
else
|
|
self.BarFill:SetWidth(self.maxBarFillWidth * self.t/self.duration);
|
|
end
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetDuration(second)
|
|
self:SetTimes(0, second);
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetEndTime(endTime)
|
|
local t = time();
|
|
self:SetDuration( (t > endTime and (t - endTime)) or 0 );
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetReverse(reverse)
|
|
self.isReverse = reverse;
|
|
end
|
|
|
|
function TinyStatusBarMixin:OnUpdate(elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= self.duration then
|
|
self:SetScript("OnUpdate", nil);
|
|
self.BarFill:Hide();
|
|
return
|
|
end
|
|
self:DisplayProgress();
|
|
end
|
|
|
|
function TinyStatusBarMixin:SetBarHeight(pixel)
|
|
if pixel ~= self.heightPixel then
|
|
self.heightPixel = pixel;
|
|
self:Init();
|
|
end
|
|
end
|
|
|
|
local function CreateTinyStatusBar(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(24, 2);
|
|
|
|
f.BarBG = f:CreateTexture(nil, "ARTWORK");
|
|
f.BarBG:SetAllPoints(true);
|
|
f.BarBG:SetColorTexture(0, 0, 0, 0.5);
|
|
|
|
f.Stroke = f:CreateTexture(nil, "BORDER");
|
|
f.Stroke:SetColorTexture(0, 0, 0);
|
|
f.Stroke:SetPoint("TOPLEFT", f, "TOPLEFT", -1, 1);
|
|
f.Stroke:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 1, -1);
|
|
|
|
f.OutStroke = f:CreateTexture(nil, "BACKGROUND");
|
|
f.OutStroke:SetColorTexture(1, 0.82, 0, 0.5);
|
|
f.OutStroke:SetPoint("TOPLEFT", f, "TOPLEFT", -2, 2);
|
|
f.OutStroke:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 2, -2);
|
|
|
|
local mask1 = f:CreateMaskTexture(nil, "BORDER");
|
|
mask1:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
mask1:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
|
|
mask1:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Exclusion", "CLAMPTOWHITE", "CLAMPTOWHITE");
|
|
f.Stroke:AddMaskTexture(mask1);
|
|
|
|
local mask2 = f:CreateMaskTexture(nil, "BACKGROUND");
|
|
mask2:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
mask2:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
|
|
mask2:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Exclusion", "CLAMPTOWHITE", "CLAMPTOWHITE");
|
|
f.OutStroke:AddMaskTexture(mask2);
|
|
|
|
f.BarFill = f:CreateTexture(nil, "OVERLAY");
|
|
f.BarFill:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
f.BarFill:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0);
|
|
f.BarFill:SetWidth(12);
|
|
|
|
DisableSharpening(f.BarBG);
|
|
DisableSharpening(f.Stroke);
|
|
DisableSharpening(f.OutStroke);
|
|
DisableSharpening(mask1);
|
|
DisableSharpening(mask2);
|
|
DisableSharpening(f.BarFill);
|
|
|
|
Mixin(f, TinyStatusBarMixin);
|
|
f:SetBarColor(1, 0.82, 0);
|
|
f:SetBarHeight(2);
|
|
f:SetScript("OnShow", f.Calibrate);
|
|
f:Init();
|
|
|
|
return f
|
|
end
|
|
addon.CreateTinyStatusBar = CreateTinyStatusBar;
|
|
end
|
|
|
|
do --Red Button
|
|
local RedButtonMixin = {};
|
|
|
|
|
|
local LONG_CLICK_DURATION = 0.5;
|
|
local LongClickListner = CreateFrame("Frame");
|
|
|
|
function LongClickListner:OnUpdate(elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= LONG_CLICK_DURATION then
|
|
self:SetScript("OnUpdate", nil);
|
|
if self.owner and self.owner:IsVisible() and self.owner:IsEnabled() then
|
|
self.owner:SetButtonState(4);
|
|
end
|
|
end
|
|
end
|
|
|
|
function LongClickListner:SetOwner(button)
|
|
self:SetParent(button);
|
|
self.owner = button;
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", self.OnUpdate);
|
|
self:Show();
|
|
end
|
|
|
|
function LongClickListner:Stop()
|
|
self:SetScript("OnUpdate", nil);
|
|
self.owner = nil;
|
|
self:Hide();
|
|
end
|
|
|
|
function LongClickListner:OnHide()
|
|
self:Stop();
|
|
end
|
|
LongClickListner:SetScript("OnHide", LongClickListner.OnHide);
|
|
|
|
|
|
function RedButtonMixin:SetButtonText(text)
|
|
self.ButtonText:SetText(text);
|
|
end
|
|
|
|
local function SetButtonState_Nomral(self, stateIndex)
|
|
local top = 0.25*(stateIndex - 1);
|
|
local bottom = 0.25*stateIndex;
|
|
self.Left:SetTexCoord(0, 0.125, top, bottom);
|
|
self.Middle:SetTexCoord(0.125, 0.875, top, bottom);
|
|
self.Right:SetTexCoord(0.875, 1, top, bottom);
|
|
end
|
|
|
|
local function SetButtonState_Large(self, stateIndex)
|
|
local top = 0.1875*(stateIndex - 1);
|
|
local bottom = 0.1875*stateIndex;
|
|
self.Left:SetTexCoord(0, 0.125, top, bottom);
|
|
self.Middle:SetTexCoord(0.125, 0.875, top, bottom);
|
|
self.Right:SetTexCoord(0.875, 1, top, bottom);
|
|
end
|
|
|
|
function RedButtonMixin:SetButtonState(stateIndex)
|
|
--1 Normal 2 Pushed 3 Disabled
|
|
if stateIndex ~= self.stateIndex then
|
|
self.stateIndex = stateIndex;
|
|
else
|
|
return
|
|
end
|
|
|
|
if stateIndex == 1 or stateIndex == 2 or stateIndex == 4 then --Normal/Pushed/LongClick
|
|
self:Enable();
|
|
if self:IsShown() and self:IsMouseOver() then
|
|
self.ButtonText:SetTextColor(1, 1, 1);
|
|
else
|
|
self.ButtonText:SetTextColor(1, 0.82, 0);
|
|
end
|
|
if stateIndex == 1 then
|
|
self.ButtonText:SetPoint("CENTER", 0, 0);
|
|
self:StopAllAnimations();
|
|
elseif stateIndex == 2 then
|
|
self.ButtonText:SetPoint("CENTER", self.pushOffset, -self.pushOffset);
|
|
self:StopAllAnimations();
|
|
elseif stateIndex == 4 then
|
|
self.ButtonText:SetPoint("CENTER", self.pushOffset, -self.pushOffset*2);
|
|
self.AnimPulse:Play();
|
|
end
|
|
elseif stateIndex == 3 then --Disabled
|
|
self:Disable();
|
|
self:StopAllAnimations();
|
|
self.ButtonText:SetTextColor(0.5, 0.5, 0.5);
|
|
self.ButtonText:SetPoint("CENTER", 0, 0);
|
|
end
|
|
|
|
self.SetButtonStateFunc(self, stateIndex);
|
|
end
|
|
|
|
function RedButtonMixin:OnMouseDown(button)
|
|
if not self:IsEnabled() then return end;
|
|
self:SetButtonState(2);
|
|
|
|
if button == "LeftButton" then
|
|
self.leftButtonDown = true;
|
|
if self.onMouseDownFunc then
|
|
self.onMouseDownFunc(self);
|
|
end
|
|
|
|
if self.canLongClick then
|
|
self.AnimFill:Play();
|
|
LongClickListner:SetOwner(self);
|
|
end
|
|
end
|
|
end
|
|
|
|
function RedButtonMixin:StopAllAnimations()
|
|
self.AnimFill:Stop();
|
|
self.AnimPulse:Stop();
|
|
end
|
|
|
|
function RedButtonMixin:OnMouseUp()
|
|
self.leftButtonDown = nil;
|
|
|
|
LongClickListner:Stop();
|
|
self:StopAllAnimations();
|
|
|
|
if self.onMouseUpFunc then
|
|
self.onMouseUpFunc(self);
|
|
end
|
|
if not self:IsEnabled() then return end;
|
|
self:SetButtonState(1);
|
|
end
|
|
|
|
function RedButtonMixin:OnHide()
|
|
if self:IsEnabled() then
|
|
self:SetButtonState(1);
|
|
else
|
|
self:SetButtonState(3);
|
|
end
|
|
self.leftButtonDown = nil;
|
|
end
|
|
|
|
function RedButtonMixin:OnEnter()
|
|
if self:IsEnabled() then
|
|
self.ButtonText:SetTextColor(1, 1, 1);
|
|
end
|
|
end
|
|
|
|
function RedButtonMixin:OnLeave()
|
|
if self:IsEnabled() then
|
|
self.ButtonText:SetTextColor(1, 0.82, 0);
|
|
end
|
|
end
|
|
|
|
local function CreateLongClickAnimation(f)
|
|
local ScanTexture = f:CreateTexture(nil, "OVERLAY", nil, -1);
|
|
f.ScanTexture = ScanTexture;
|
|
ScanTexture:SetSize(46, 21);
|
|
ScanTexture:SetPoint("RIGHT", f, "RIGHT", -184, -1);
|
|
ScanTexture:SetTexture("Interface/AddOns/Plumber/Art/Frame/RedButton-Scan", nil, nil, "TRILINEAR");
|
|
ScanTexture:SetVertexColor(0.4, 0.1, 0.1);
|
|
ScanTexture:SetBlendMode("ADD");
|
|
ScanTexture:SetAlpha(0);
|
|
|
|
local AnimFill = f:CreateAnimationGroup();
|
|
f.AnimFill = AnimFill;
|
|
AnimFill:SetToFinalAlpha(true);
|
|
local t1 = AnimFill:CreateAnimation("Translation");
|
|
t1:SetChildKey("ScanTexture");
|
|
t1:SetOffset(184, 0);
|
|
t1:SetDuration(LONG_CLICK_DURATION);
|
|
t1:SetOrder(1);
|
|
local a1 = AnimFill:CreateAnimation("Alpha");
|
|
a1:SetChildKey("ScanTexture");
|
|
a1:SetFromAlpha(0);
|
|
a1:SetToAlpha(1);
|
|
a1:SetDuration(0.1);
|
|
a1:SetOrder(1);
|
|
local a2 = AnimFill:CreateAnimation("Alpha");
|
|
a2:SetChildKey("ScanTexture");
|
|
a2:SetFromAlpha(1);
|
|
a2:SetToAlpha(0);
|
|
a2:SetDuration(0.5);
|
|
a2:SetStartDelay(LONG_CLICK_DURATION);
|
|
a2:SetOrder(1);
|
|
|
|
local PulseTexture = f:CreateTexture(nil, "OVERLAY", nil, -1);
|
|
f.PulseTexture = PulseTexture;
|
|
PulseTexture:SetPoint("TOPLEFT", f, "LEFT", 4, 8);
|
|
PulseTexture:SetPoint("BOTTOMRIGHT", f, "RIGHT", -2, -12);
|
|
PulseTexture:SetTexture("Interface/AddOns/Plumber/Art/Frame/RedButton-Pulse", nil, nil, "TRILINEAR");
|
|
PulseTexture:SetVertexColor(0.5, 0.25, 0.1);
|
|
PulseTexture:SetBlendMode("ADD");
|
|
PulseTexture:SetAlpha(0);
|
|
|
|
local AnimPulse = f:CreateAnimationGroup();
|
|
f.AnimPulse = AnimPulse;
|
|
AnimPulse:SetToFinalAlpha(true);
|
|
AnimPulse:SetLooping("BOUNCE");
|
|
local a5 = AnimPulse:CreateAnimation("Alpha");
|
|
a5:SetChildKey("PulseTexture");
|
|
a5:SetFromAlpha(0);
|
|
a5:SetToAlpha(1);
|
|
a5:SetDuration(0.5);
|
|
a5:SetOrder(1);
|
|
end
|
|
|
|
local function CreateRedButton(parent, sizeType)
|
|
sizeType = sizeType or "normal";
|
|
|
|
local f = CreateFrame("Button", nil, parent);
|
|
Mixin(f, RedButtonMixin);
|
|
|
|
f:SetScript("OnMouseDown", RedButtonMixin.OnMouseDown);
|
|
f:SetScript("OnMouseUp", RedButtonMixin.OnMouseUp);
|
|
f:SetScript("OnHide", RedButtonMixin.OnHide);
|
|
f:SetScript("OnEnter", RedButtonMixin.OnEnter);
|
|
f:SetScript("OnLeave", RedButtonMixin.OnLeave);
|
|
|
|
f.Left = f:CreateTexture(nil, "BORDER");
|
|
f.Left:SetPoint("CENTER", f, "LEFT", 0, 0);
|
|
|
|
f.Right = f:CreateTexture(nil, "BORDER");
|
|
f.Right:SetPoint("CENTER", f, "RIGHT", 0, 0);
|
|
|
|
f.Middle = f:CreateTexture(nil, "BORDER");
|
|
f.Middle:SetPoint("TOPLEFT", f.Left, "TOPRIGHT", 0, 0);
|
|
f.Middle:SetPoint("BOTTOMRIGHT", f.Right, "BOTTOMLEFT", 0, 0);
|
|
|
|
local file;
|
|
if sizeType == "normal" then
|
|
file = "RedButton-Normal";
|
|
f:SetSize(112, 22);
|
|
f.Left:SetSize(16, 32);
|
|
f.Right:SetSize(16, 32);
|
|
f.SetButtonStateFunc = SetButtonState_Nomral;
|
|
f.pushOffset = 1;
|
|
elseif sizeType == "large" then
|
|
file = "RedButton-Large";
|
|
f:SetSize(224, 30);
|
|
f.Left:SetSize(32, 48);
|
|
f.Right:SetSize(32, 48);
|
|
f.SetButtonStateFunc = SetButtonState_Large;
|
|
f.pushOffset = 2;
|
|
end
|
|
file = "Interface/AddOns/Plumber/Art/Frame/"..file;
|
|
f.Left:SetTexture(file);
|
|
f.Right:SetTexture(file);
|
|
f.Middle:SetTexture(file);
|
|
|
|
f.ButtonText = f:CreateFontString(nil, "OVERLAY", "GameFontNormal", 4);
|
|
f.ButtonText:SetJustifyH("CENTER");
|
|
f.ButtonText:SetJustifyV("MIDDLE");
|
|
f.ButtonText:SetTextColor(1, 0.82, 0);
|
|
f.ButtonText:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
|
|
f.Highlight = f:CreateTexture(nil, "HIGHLIGHT");
|
|
f.Highlight:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
f.Highlight:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
|
|
f.Highlight:SetTexture("Interface/AddOns/Plumber/Art/Frame/RedButton-Highlight", nil, nil, "TRILINEAR");
|
|
f.Highlight:SetVertexColor(0.4, 0.1, 0.1);
|
|
f.Highlight:SetBlendMode("ADD");
|
|
|
|
DisableSharpening(f.Left);
|
|
DisableSharpening(f.Right);
|
|
DisableSharpening(f.Middle);
|
|
|
|
CreateLongClickAnimation(f);
|
|
f:SetButtonState(1);
|
|
|
|
return f
|
|
end
|
|
addon.CreateRedButton = CreateRedButton;
|
|
end
|
|
|
|
do --Metal Progress Bar
|
|
local ProgressBarMixin = {};
|
|
|
|
function ProgressBarMixin:SetBarWidth(width)
|
|
self:SetWidth(width);
|
|
self.maxBarFillWidth = width;
|
|
end
|
|
|
|
function ProgressBarMixin:SetValueByRatio(ratio)
|
|
self.BarFill:SetWidth(ratio * self.maxBarFillWidth);
|
|
self.BarFill:SetTexCoord(0, ratio, self.barfillTop, self.barfillBottom);
|
|
self.visualRatio = ratio;
|
|
end
|
|
|
|
local FILL_SIZE_PER_SEC = 100;
|
|
local EasingFunc = addon.EasingFunctions.outQuart;
|
|
|
|
local function SmoothFill_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
local ratio = EasingFunc(self.t, self.fromRatio, self.toRatio, self.easeDuration);
|
|
if self.t >= self.easeDuration then
|
|
ratio = self.toRatio;
|
|
self.easeDuration = nil;
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
self:SetValueByRatio(ratio);
|
|
end
|
|
|
|
function ProgressBarMixin:SetValue(barValue, barMax, playPulse)
|
|
if barValue > barMax then
|
|
barValue = barMax;
|
|
end
|
|
if self.BarValue then
|
|
self.BarValue:SetText(barValue.."/"..barMax);
|
|
end
|
|
if barValue == 0 or barMax == 0 then
|
|
self.BarFill:Hide();
|
|
self:SetScript("OnUpdate", nil);
|
|
else
|
|
self.BarFill:Show();
|
|
local newRatio = barValue/barMax;
|
|
if self.smoothFill then
|
|
local deltaRatio, oldRatio;
|
|
|
|
if self.barMax and self.visualRatio then
|
|
if self.barMax == 0 then
|
|
oldRatio = 0;
|
|
else
|
|
oldRatio = self.visualRatio;
|
|
end
|
|
deltaRatio = newRatio - oldRatio;
|
|
else
|
|
oldRatio = 0;
|
|
deltaRatio = newRatio;
|
|
end
|
|
|
|
if oldRatio < 0 then
|
|
oldRatio = -oldRatio;
|
|
end
|
|
|
|
if deltaRatio < 0 then
|
|
deltaRatio = -deltaRatio;
|
|
end
|
|
|
|
local easeDuration = deltaRatio*self.maxBarFillWidth / FILL_SIZE_PER_SEC;
|
|
|
|
if self.wasHidden then
|
|
--don't animte if the bar was hidden
|
|
self.wasHidden = false;
|
|
easeDuration = 0;
|
|
end
|
|
if easeDuration > 0.25 then
|
|
self.toRatio = newRatio;
|
|
self.fromRatio = oldRatio;
|
|
if easeDuration > 1.5 then
|
|
easeDuration = 1.5;
|
|
end
|
|
self.easeDuration = easeDuration;
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", SmoothFill_OnUpdate);
|
|
else
|
|
self.easeDuration = nil;
|
|
self:SetValueByRatio(newRatio);
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
else
|
|
self:SetValueByRatio(newRatio);
|
|
end
|
|
end
|
|
|
|
if playPulse and barValue > self.barValue then
|
|
self:Flash();
|
|
end
|
|
|
|
self.barValue = barValue;
|
|
self.barMax = barMax;
|
|
end
|
|
|
|
function ProgressBarMixin:OnHide()
|
|
self.wasHidden = true;
|
|
end
|
|
|
|
function ProgressBarMixin:GetValue()
|
|
return self.barValue
|
|
end
|
|
|
|
function ProgressBarMixin:GetBarMax()
|
|
return self.barMax
|
|
end
|
|
|
|
function ProgressBarMixin:SetSmoothFill(state)
|
|
state = state or false;
|
|
self.smoothFill = state;
|
|
if not state then
|
|
self:SetScript("OnUpdate", nil);
|
|
if self.barValue and self.barMax then
|
|
self:SetValue(self.barValue, self.barMax);
|
|
end
|
|
self.easeDuration = nil;
|
|
end
|
|
end
|
|
|
|
function ProgressBarMixin:Flash()
|
|
self.BarPulse.AnimPulse:Stop();
|
|
self.BarPulse.AnimPulse:Play();
|
|
if self.playShake then
|
|
self.BarShake:Play();
|
|
end
|
|
end
|
|
|
|
function ProgressBarMixin:SetBarColor(r, g, b)
|
|
self.BarFill:SetVertexColor(r, g, b);
|
|
end
|
|
|
|
function ProgressBarMixin:SetBarColorTint(index)
|
|
if index < 1 or index > 8 then index = 2 end; --White
|
|
|
|
if index ~= self.colorTint then
|
|
self.colorTint = index;
|
|
else
|
|
return
|
|
end
|
|
|
|
self.BarFill:SetVertexColor(1, 1, 1);
|
|
self.barfillTop = (index - 1)*0.125;
|
|
self.barfillBottom = index*0.125;
|
|
|
|
if self.barValue and self.barMax then
|
|
self:SetValue(self.barValue, self.barMax);
|
|
end
|
|
end
|
|
|
|
function ProgressBarMixin:GetBarColorTint()
|
|
return self.colorTint
|
|
end
|
|
|
|
local function SetupNotchTexture_Normal(notch)
|
|
notch:SetTexCoord(0.815, 0.875, 0, 0.375);
|
|
notch:SetSize(16, 24);
|
|
end
|
|
|
|
local function SetupNotchTexture_Large(notch)
|
|
notch:SetTexCoord(0.5625, 0.59375, 0, 0.25);
|
|
notch:SetSize(16, 64);
|
|
end
|
|
|
|
function ProgressBarMixin:SetNumThreshold(numThreshold)
|
|
--Divide the bar evenly
|
|
--"partitionValues", in Blizzard's term
|
|
if numThreshold == self.numThreshold then return end;
|
|
self.numThreshold = numThreshold;
|
|
|
|
if not self.notches then
|
|
self.notches = {};
|
|
end
|
|
|
|
for _, n in ipairs(self.notches) do
|
|
n:Hide();
|
|
end
|
|
|
|
if numThreshold == 0 then return end;
|
|
|
|
local d = self.maxBarFillWidth / (numThreshold + 1);
|
|
for i = 1, numThreshold do
|
|
if not self.notches[i] then
|
|
self.notches[i] = self.Container:CreateTexture(nil, "OVERLAY", nil, 2);
|
|
self.notches[i]:SetTexture(self.textureFile);
|
|
self.SetupNotchTexture(self.notches[i]);
|
|
API.DisableSharpening(self.notches[i]);
|
|
end
|
|
self.notches[i]:ClearAllPoints();
|
|
self.notches[i]:SetPoint("CENTER", self.Container, "LEFT", i*d, 0);
|
|
self.notches[i]:Show();
|
|
end
|
|
end
|
|
|
|
local function CreateMetalProgressBar(parent, sizeType)
|
|
sizeType = sizeType or "normal";
|
|
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
Mixin(f, ProgressBarMixin);
|
|
|
|
f:SetScript("OnHide", ProgressBarMixin.OnHide);
|
|
|
|
local Container = CreateFrame("Frame", nil, f); --Textures are attached to this frame, so we can setup animations
|
|
f.Container = Container;
|
|
Container:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
Container:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0 ,0);
|
|
|
|
f.visualRatio = 0;
|
|
f.wasHidden = true;
|
|
|
|
f.BarFill = Container:CreateTexture(nil, "ARTWORK");
|
|
f.BarFill:SetTexCoord(0, 1, 0, 0.125);
|
|
f.BarFill:SetTexture("Interface/AddOns/Plumber/Art/Frame/ProgressBar-Fill");
|
|
f.BarFill:SetPoint("LEFT", Container, "LEFT", 0, 0);
|
|
|
|
f.Background = Container:CreateTexture(nil, "BACKGROUND");
|
|
f.Background:SetColorTexture(0.1, 0.1, 0.1, 0.8);
|
|
f.Background:SetPoint("TOPLEFT", Container, "TOPLEFT", 0, -2);
|
|
f.Background:SetPoint("BOTTOMRIGHT", Container, "BOTTOMRIGHT", 0, 2);
|
|
|
|
f.BarLeft = Container:CreateTexture(nil, "OVERLAY");
|
|
f.BarLeft:SetPoint("CENTER", Container, "LEFT", 0, 0);
|
|
|
|
f.BarRight = Container:CreateTexture(nil, "OVERLAY");
|
|
f.BarRight:SetPoint("CENTER", Container, "RIGHT", 0, 0);
|
|
|
|
f.BarMiddle = Container:CreateTexture(nil, "OVERLAY");
|
|
f.BarMiddle:SetPoint("TOPLEFT", f.BarLeft, "TOPRIGHT", 0, 0);
|
|
f.BarMiddle:SetPoint("BOTTOMRIGHT", f.BarRight, "BOTTOMLEFT", 0, 0);
|
|
|
|
local file, barWidth, barHeight;
|
|
if sizeType == "normal" then
|
|
file = "ProgressBar-Metal-Normal";
|
|
barWidth, barHeight = 168, 18;
|
|
f.BarLeft:SetTexCoord(0, 0.09375, 0, 0.375);
|
|
f.BarRight:SetTexCoord(0.65625, 0.75, 0, 0.375);
|
|
f.BarMiddle:SetTexCoord(0.09375, 0.65625, 0, 0.375);
|
|
f.BarLeft:SetSize(24, 24);
|
|
f.BarRight:SetSize(24, 24);
|
|
f.BarFill:SetSize(barWidth, 12);
|
|
f.SetupNotchTexture = SetupNotchTexture_Normal;
|
|
elseif sizeType == "large" then
|
|
file = "ProgressBar-Metal-Large";
|
|
barWidth, barHeight = 248, 28; --32
|
|
f.BarLeft:SetTexCoord(0, 0.0625, 0, 0.25);
|
|
f.BarRight:SetTexCoord(0.46875, 0.53125, 0, 0.25);
|
|
f.BarMiddle:SetTexCoord(0.0625, 0.46875, 0, 0.25);
|
|
f.BarLeft:SetSize(32, 64);
|
|
f.BarRight:SetSize(32, 64);
|
|
f.BarFill:SetSize(barWidth, 20); --24
|
|
f.SetupNotchTexture = SetupNotchTexture_Large;
|
|
end
|
|
|
|
local barFile = "Interface/AddOns/Plumber/Art/Frame/"..file;
|
|
f.textureFile = barFile;
|
|
f.BarLeft:SetTexture(barFile);
|
|
f.BarRight:SetTexture(barFile);
|
|
f.BarMiddle:SetTexture(barFile);
|
|
|
|
API.DisableSharpening(f.BarFill);
|
|
API.DisableSharpening(f.BarLeft);
|
|
API.DisableSharpening(f.BarRight);
|
|
API.DisableSharpening(f.BarMiddle);
|
|
|
|
f:SetBarWidth(barWidth);
|
|
f:SetHeight(barHeight);
|
|
f:SetBarColorTint(2);
|
|
--f:SetNumThreshold(0);
|
|
f:SetValue(0, 100);
|
|
|
|
|
|
local BarPulse = CreateFrame("Frame", nil, f, "PlumberBarPulseTemplate");
|
|
BarPulse:SetPoint("RIGHT", f.BarFill, "RIGHT", 0, 0);
|
|
f.BarPulse = BarPulse;
|
|
|
|
|
|
local BarShake = Container:CreateAnimationGroup();
|
|
f.BarShake = BarShake;
|
|
local a1 = BarShake:CreateAnimation("Translation");
|
|
a1:SetOrder(1);
|
|
a1:SetStartDelay(0.15);
|
|
a1:SetOffset(3, 0);
|
|
a1:SetDuration(0.05);
|
|
local a2 = BarShake:CreateAnimation("Translation");
|
|
a2:SetOrder(2);
|
|
a2:SetOffset(-4, 0);
|
|
a2:SetDuration(0.1);
|
|
local a3 = BarShake:CreateAnimation("Translation");
|
|
a3:SetOrder(3);
|
|
a3:SetOffset(1, 0);
|
|
a3:SetDuration(0.1);
|
|
|
|
return f
|
|
end
|
|
addon.CreateMetalProgressBar = CreateMetalProgressBar;
|
|
end
|
|
|
|
do
|
|
local function CreateTextDropShadow(fontString, parent)
|
|
parent = parent or fontString:GetParent();
|
|
local Shadow = parent:CreateTexture(nil, "BACKGROUND", nil, -1);
|
|
Shadow:SetPoint("TOPLEFT", fontString, "TOPLEFT", -8, 6);
|
|
Shadow:SetPoint("BOTTOMRIGHT", fontString, "BOTTOMRIGHT", 8, -8);
|
|
Shadow:SetTexture("Interface/AddOns/Plumber/Art/Button/GenericTextDropShadow");
|
|
fontString.Shadow = Shadow;
|
|
end
|
|
addon.CreateTextDropShadow = CreateTextDropShadow;
|
|
end
|
|
|
|
do --Hotkey/Keyboard Icon
|
|
local TEXTURE_WIDTH, TEXTURE_HEIGHT = 256, 256;
|
|
local BLEEDING = 10; --the distance between the key icon and the texture edge
|
|
local PIXEL_INGAME_RATIO = 0.5;
|
|
|
|
local KeyboardKeys;
|
|
|
|
if IsMacClient and IsMacClient() then
|
|
--Mac
|
|
KeyboardKeys = {
|
|
--Key = {left(pixel), right, top, bottom, keyName}
|
|
Alt = {128, 192, 0, 64, "LALT"},
|
|
};
|
|
else
|
|
--Windows
|
|
KeyboardKeys = {
|
|
Alt = {0, 78, 0, 64, "LALT"},
|
|
};
|
|
end
|
|
|
|
|
|
local HotkeyIconMixin = {};
|
|
|
|
function HotkeyIconMixin:SetKey(key, responsive)
|
|
self.responsive = responsive or false;
|
|
|
|
if responsive then
|
|
self:SetScript("OnEvent", self.OnEvent);
|
|
else
|
|
self:SetScript("OnEvent", nil);
|
|
end
|
|
|
|
if key == self.hotkey then
|
|
return
|
|
else
|
|
self.hotkey = key;
|
|
end
|
|
|
|
if KeyboardKeys[key] then
|
|
local left, right, top, bottom, keyName = unpack(KeyboardKeys[key]);
|
|
local textureWidth = (right - left) * PIXEL_INGAME_RATIO;
|
|
local textureHeight = (bottom - top) * PIXEL_INGAME_RATIO;
|
|
local effectiveWidth = (right - left - 2*BLEEDING) * PIXEL_INGAME_RATIO;
|
|
local effectiveHeight = (bottom - top - 2*BLEEDING) * PIXEL_INGAME_RATIO;
|
|
self.Texture:SetTexCoord(left/TEXTURE_WIDTH, right/TEXTURE_WIDTH, top/TEXTURE_HEIGHT, bottom/TEXTURE_HEIGHT);
|
|
self.Texture:SetSize(textureWidth, textureHeight);
|
|
self:SetSize(effectiveWidth, effectiveHeight);
|
|
self.keyName = keyName;
|
|
end
|
|
end
|
|
|
|
function HotkeyIconMixin:Flash()
|
|
self.AnimFlash:Stop();
|
|
self.AnimFlash:Play();
|
|
end
|
|
|
|
function HotkeyIconMixin:OnShow()
|
|
self.FlashTexture:SetAlpha(0);
|
|
if self.responsive and self.hotkey then
|
|
self:RegisterEvent("MODIFIER_STATE_CHANGED");
|
|
end
|
|
end
|
|
|
|
function HotkeyIconMixin:OnHide()
|
|
self:UnregisterEvent("MODIFIER_STATE_CHANGED");
|
|
self.AnimFlash:Stop();
|
|
end
|
|
|
|
function HotkeyIconMixin:OnEvent(event, ...)
|
|
if event == "MODIFIER_STATE_CHANGED" then
|
|
local key, down = ...
|
|
if down == 1 then
|
|
if key == self.keyName then
|
|
self:Flash();
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CreateHotkeyIcon(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(22, 22);
|
|
f.Texture = f:CreateTexture(nil, "ARTWORK");
|
|
f.Texture:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
f.Texture:SetSize(32, 32);
|
|
f.Texture:SetTexture("Interface/AddOns/Plumber/Art/Button/Keyboard", nil, nil, "LINEAR");
|
|
f.Texture:SetTexCoord(0, 0.001, 0, 0.001);
|
|
DisableSharpening(f.Texture);
|
|
|
|
f.FlashTexture = f:CreateTexture(nil, "OVERLAY");
|
|
f.FlashTexture:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 2, 1);
|
|
f.FlashTexture:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -2, 1);
|
|
f.FlashTexture:SetHeight(8);
|
|
f.FlashTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/KeyboardFlash", nil, nil, "TRILINEAR");
|
|
f.FlashTexture:SetBlendMode("ADD");
|
|
f.FlashTexture:SetAlpha(0);
|
|
|
|
local AnimFlash = f:CreateAnimationGroup();
|
|
AnimFlash:SetToFinalAlpha(true);
|
|
f.AnimFlash = AnimFlash;
|
|
local a1 = AnimFlash:CreateAnimation("ALPHA");
|
|
a1:SetChildKey("FlashTexture");
|
|
a1:SetFromAlpha(0);
|
|
a1:SetToAlpha(0.67);
|
|
a1:SetDuration(0.1);
|
|
a1:SetOrder(1);
|
|
local a2 = AnimFlash:CreateAnimation("ALPHA");
|
|
a2:SetChildKey("FlashTexture");
|
|
a2:SetFromAlpha(0.67);
|
|
a2:SetToAlpha(0);
|
|
a2:SetDuration(0.5);
|
|
a2:SetOrder(2);
|
|
|
|
Mixin(f, HotkeyIconMixin);
|
|
f:SetScript("OnShow", HotkeyIconMixin.OnShow);
|
|
f:SetScript("OnHide", HotkeyIconMixin.OnHide);
|
|
|
|
return f
|
|
end
|
|
addon.CreateHotkeyIcon = CreateHotkeyIcon;
|
|
end
|
|
|
|
do --Cursor Cooldown (Displayed near the cursor)
|
|
local UnitCastingInfo = UnitCastingInfo;
|
|
|
|
local CursorProgressIndicator;
|
|
|
|
local CursorProgressMixin = {};
|
|
|
|
function CursorProgressMixin:FadeIn()
|
|
FadeFrame(self, 0.2, 1, 0);
|
|
end
|
|
|
|
function CursorProgressMixin:FadeOut()
|
|
FadeFrame(self, 0.2, 0);
|
|
end
|
|
|
|
function CursorProgressMixin:OnHide()
|
|
self:Clear();
|
|
end
|
|
|
|
function CursorProgressMixin:SetColorIndex(colorIndex)
|
|
if colorIndex == 1 then
|
|
self:SetSwipeTexture("Interface/AddOns/Plumber/Art/Button/GenericCooldown-Swipe-Blue");
|
|
elseif colorIndex == 2 then
|
|
self:SetSwipeTexture("Interface/AddOns/Plumber/Art/Button/GenericCooldown-Swipe-Yellow");
|
|
end
|
|
end
|
|
|
|
function CursorProgressMixin:OnEvent(event, ...)
|
|
if event == "UNIT_SPELLCAST_START" then
|
|
local _, _, spellID = ...
|
|
if spellID ~= self.watchedSpellID then
|
|
return
|
|
end
|
|
local _, _, _, startTimeMs, endTimeMs = UnitCastingInfo("player");
|
|
if startTimeMs and endTimeMs then
|
|
--self:SetCooldownUNIX(startTime, endTime - startTime);
|
|
local durationMs = endTimeMs - startTimeMs;
|
|
self:SetCooldown(startTimeMs / 1000.0, durationMs / 1000.0);
|
|
self:FadeIn();
|
|
else
|
|
self:Clear();
|
|
end
|
|
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
|
|
|
elseif event == "UNIT_SPELLCAST_STOP" then
|
|
self:Clear();
|
|
end
|
|
end
|
|
|
|
function CursorProgressMixin:WatchSpell(spellID)
|
|
self.watchedSpellID = spellID;
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_START", "player");
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player");
|
|
self:RegisterUnitEvent("UNIT_SPELLCAST_STOP", "player");
|
|
end
|
|
|
|
function CursorProgressMixin:ClearWatch()
|
|
self:Hide();
|
|
self:Clear();
|
|
self:UnregisterEvent("UNIT_SPELLCAST_START");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED");
|
|
self:UnregisterEvent("UNIT_SPELLCAST_STOP");
|
|
end
|
|
|
|
local function AcquireCursorProgressIndicator()
|
|
if not CursorProgressIndicator then
|
|
local f = CreateFrame("Cooldown", nil, UIParent, "PlumberGenericCooldownTemplate");
|
|
CursorProgressIndicator = f;
|
|
f:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
|
|
Mixin(f, CursorProgressMixin);
|
|
DisableSharpening(f.Background);
|
|
f:SetScript("OnEvent", CursorProgressMixin.OnEvent);
|
|
f:SetScript("OnHide", CursorProgressMixin.OnHide);
|
|
f:SetUseCircularEdge(true);
|
|
f:SetColorIndex(2);
|
|
f:SetFrameStrata("FULLSCREEN");
|
|
f:SetFixedFrameStrata(true);
|
|
f:WatchSpell();
|
|
end
|
|
return CursorProgressIndicator
|
|
end
|
|
addon.AcquireCursorProgressIndicator = AcquireCursorProgressIndicator;
|
|
end
|
|
|
|
do --Simple Size Select (S/M/L)
|
|
local OPTION_BUTTON_WIDTH = 16; --Slightly larger: served as gap between buttons
|
|
local OPTION_BUTTON_HEIGHT = 14;
|
|
|
|
local SizeOptionButtonMixin = {};
|
|
|
|
function SizeOptionButtonMixin:OnEnter()
|
|
self:SetAlpha(1);
|
|
self:GetParent():ShowTitle(true);
|
|
end
|
|
|
|
function SizeOptionButtonMixin:OnLeave()
|
|
if not self.selected then
|
|
self:SetAlpha(0.6);
|
|
else
|
|
self:SetAlpha(0.8);
|
|
end
|
|
self:GetParent():ShowTitle(false);
|
|
end
|
|
|
|
function SizeOptionButtonMixin:OnClick()
|
|
self:GetParent():SelectSize(self.id, true);
|
|
end
|
|
|
|
function SizeOptionButtonMixin:SetSelected(state)
|
|
self.selected = state;
|
|
if state then
|
|
self.Icon:SetTexCoord(0.25*(self.id - 1), 0.25*self.id, 0, 0.5);
|
|
self:SetAlpha(1);
|
|
else
|
|
self.Icon:SetTexCoord(0.25*(self.id - 1), 0.25*self.id, 0.5, 1);
|
|
end
|
|
|
|
if self:IsMouseOver() then
|
|
self:SetAlpha(1);
|
|
else
|
|
if state then
|
|
self:SetAlpha(0.8);
|
|
else
|
|
self:SetAlpha(0.6);
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local SizeSelectMixin = {};
|
|
|
|
function SizeSelectMixin:SelectSize(id, runScript)
|
|
if id ~= self.selectedSize then
|
|
self.selectedSize = id;
|
|
else
|
|
return
|
|
end
|
|
|
|
for i, button in ipairs(self.buttons) do
|
|
button:SetSelected(i == id);
|
|
end
|
|
|
|
if runScript and self.callback then
|
|
self.callback(id, true);
|
|
end
|
|
end
|
|
|
|
function SizeSelectMixin:SetNumChoices(numChoices)
|
|
if numChoices > 3 then
|
|
numChoices = 3;
|
|
end
|
|
|
|
if numChoices ~= self.numChoices then
|
|
self.numChoices = numChoices;
|
|
else
|
|
return
|
|
end
|
|
|
|
if not self.buttons then
|
|
self.buttons = {};
|
|
end
|
|
|
|
for i = 1, numChoices do
|
|
if not self.buttons[i] then
|
|
local button = CreateFrame("Button", nil, self);
|
|
self.buttons[i] = button;
|
|
button.id = i;
|
|
button:SetSize(OPTION_BUTTON_WIDTH, OPTION_BUTTON_HEIGHT);
|
|
button:SetPoint("LEFT", self, "LEFT", (i - 1)*OPTION_BUTTON_WIDTH, 0);
|
|
button.Icon = button:CreateTexture(nil, "OVERLAY");
|
|
button.Icon:SetSize(OPTION_BUTTON_HEIGHT, OPTION_BUTTON_HEIGHT);
|
|
button.Icon:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
button.Icon:SetTexture("Interface/AddOns/Plumber/Art/Button/SimpleSizeSelect");
|
|
button.Icon:SetTexCoord(0.75, 1, 0.5, 1);
|
|
button:SetAlpha(0.6);
|
|
button:SetScript("OnEnter", SizeOptionButtonMixin.OnEnter);
|
|
button:SetScript("OnLeave", SizeOptionButtonMixin.OnLeave);
|
|
button:SetScript("OnClick", SizeOptionButtonMixin.OnClick);
|
|
Mixin(button, SizeOptionButtonMixin);
|
|
end
|
|
self.buttons[i]:Show();
|
|
end
|
|
self:SetWidth(numChoices*OPTION_BUTTON_WIDTH);
|
|
|
|
for i = numChoices + 1, #self.buttons do
|
|
self.buttons[i]:Hide();
|
|
end
|
|
end
|
|
|
|
function SizeSelectMixin:SetOnSizeChangedCallback(callback)
|
|
self.callback = callback;
|
|
end
|
|
|
|
function SizeSelectMixin:ShowTitle(state)
|
|
self.Title:SetShown(state);
|
|
end
|
|
|
|
local function CreateSimpleSizeSelect(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(OPTION_BUTTON_WIDTH, 16);
|
|
|
|
f.Title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
|
|
f.Title:SetJustifyH("RIGHT");
|
|
f.Title:SetPoint("RIGHT", f, "LEFT", -2, 0);
|
|
f.Title:Hide();
|
|
f.Title:SetText(addon.L["Pin Size"]);
|
|
f.Title:SetTextColor(1, 0.82, 0);
|
|
|
|
Mixin(f, SizeSelectMixin);
|
|
return f
|
|
end
|
|
addon.CreateSimpleSizeSelect = CreateSimpleSizeSelect;
|
|
end
|
|
|
|
do --Draw shapes
|
|
local ArcMixin = {};
|
|
|
|
function ArcMixin:SetThickness(pixel, update)
|
|
self.px = API.GetPixelForWidget(self, pixel*0.5);
|
|
if self.radius and update then
|
|
self:SetRadius(self.radius);
|
|
end
|
|
end
|
|
|
|
function ArcMixin:SetColor(r, g, b, a)
|
|
a = a or 1;
|
|
self.Circle:SetVertexColor(r, g, b, a);
|
|
end
|
|
|
|
function ArcMixin:SetRadius(radius)
|
|
self.radius = radius;
|
|
local d = 2*(radius + self.px);
|
|
self.Circle:SetSize(d, d);
|
|
d = 2*(radius - self.px);
|
|
self.Mask1:SetSize(d, d);
|
|
self.Mask2:SetSize(d, d);
|
|
end
|
|
|
|
function ArcMixin:SetFromRadian(fromRadian)
|
|
-- y+, positive
|
|
-- y-, negative
|
|
self.Mask1:SetRotation(fromRadian);
|
|
end
|
|
|
|
function ArcMixin:SetToRadian(toRadian)
|
|
self.Mask2:SetRotation(toRadian);
|
|
end
|
|
|
|
function ArcMixin:SetFromDegree(fromDegree)
|
|
self:SetFromRadian(math.rad(fromDegree));
|
|
end
|
|
|
|
function ArcMixin:SetToDegree(toDegree)
|
|
self:SetToRadian(math.rad(toDegree));
|
|
end
|
|
|
|
function ArcMixin:Init()
|
|
local circle0 = self:CreateTexture(nil, "BACKGROUND");
|
|
self.Circle = circle0;
|
|
circle0:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Circle-HD");
|
|
circle0:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
DisableSharpening(circle0);
|
|
|
|
local circle1 = self:CreateMaskTexture(nil, "BACKGROUND");
|
|
self.Mask1 = circle1;
|
|
circle1:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Circle-Inverse-Right-HD", "CLAMP", "CLAMP");
|
|
circle1:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
circle0:AddMaskTexture(circle1);
|
|
DisableSharpening(circle1);
|
|
|
|
local circle3 = self:CreateMaskTexture(nil, "BACKGROUND");
|
|
self.Mask2 = circle3;
|
|
circle3:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Circle-Inverse-Right-HD", "CLAMP", "CLAMP");
|
|
circle3:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
circle0:AddMaskTexture(circle3);
|
|
DisableSharpening(circle3);
|
|
|
|
self.Init = nil;
|
|
end
|
|
|
|
local function CreateArc(parent)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:SetSize(8, 8);
|
|
Mixin(f, ArcMixin);
|
|
f:SetThickness(1);
|
|
f:Init();
|
|
return f
|
|
end
|
|
addon.CreateArc = CreateArc;
|
|
end
|
|
|
|
do --Shared Context Menu
|
|
local MENU_PADDING_X = 2;
|
|
local MENU_PADDING_Y = 8;
|
|
local MENU_BUTTON_HEIGHT = 24;
|
|
local MENU_DIVIDER_HEIGHT = 14;
|
|
local MENU_BUTTON_WIDTH = 240;
|
|
local MENU_BUTTON_TEXT_OFFSET = 12;
|
|
local MENU_SUBBUTTON_TEXT_OFFSET = 30;
|
|
local MENU_TOOLTIP_DELAY = 0.5;
|
|
|
|
local UIParent = UIParent;
|
|
local GetScaledCursorPosition = API.GetScaledCursorPosition;
|
|
|
|
local SharedContextMenu;
|
|
local ContextMenuMixin = {};
|
|
local MenuButtonMixin = {};
|
|
|
|
|
|
function MenuButtonMixin:OnEnter()
|
|
self.parent:FocusOnButton(self);
|
|
end
|
|
|
|
function MenuButtonMixin:OnLeave()
|
|
self.parent:FocusOnButton(nil);
|
|
GameTooltip:Hide();
|
|
end
|
|
|
|
function MenuButtonMixin:OnClick(button)
|
|
if self.onClickFunc and self.onClickFunc(self, button) then
|
|
self.parent:CloseMenu();
|
|
end
|
|
end
|
|
|
|
function MenuButtonMixin:OnMouseDown(button)
|
|
if not self:IsEnabled() then return end;
|
|
|
|
if button == "LeftButton" then
|
|
self.Text:SetPoint("LEFT", self, "LEFT", self.baseTextOffset + 1, 0);
|
|
end
|
|
end
|
|
|
|
function MenuButtonMixin:OnMouseUp(button)
|
|
self.Text:SetPoint("LEFT", self, "LEFT", self.baseTextOffset, 0);
|
|
end
|
|
|
|
function MenuButtonMixin:SetupButtonTexture()
|
|
if self.divider then
|
|
self.divider:Hide();
|
|
end
|
|
|
|
if (not self.buttonType) or self.buttonType == "title" or self.buttonType == "divider" then
|
|
if self.Tex1 then
|
|
self.Tex1:Hide();
|
|
end
|
|
if self.Tex2 then
|
|
self.Tex2:Hide();
|
|
end
|
|
|
|
if self.buttonType == "divider" then
|
|
if not self.divider then
|
|
self.divider = self:CreateTexture(nil, "ARTWORK");
|
|
self.divider:SetPoint("LEFT", self, "LEFT", MENU_PADDING_X, 0);
|
|
self.divider:SetPoint("RIGHT", self, "RIGHT", -MENU_PADDING_X, 0);
|
|
self.divider:SetColorTexture(0.2, 0.2, 0.2);
|
|
DisableSharpening(self.divider);
|
|
end
|
|
local px = API.GetPixelForWidget(self, 1);
|
|
self.divider:SetHeight(px);
|
|
self.divider:Show();
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
|
|
if not self.Tex1 then
|
|
self.Tex1 = self:CreateTexture(nil, "ARTWORK");
|
|
self.Tex1:SetSize(32, 32);
|
|
self.Tex1:SetPoint("CENTER", self, "LEFT", MENU_BUTTON_TEXT_OFFSET + 6, 0);
|
|
self.Tex1:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
self.Tex1:SetTexCoord(0, 0.5, 0, 0.5);
|
|
DisableSharpening(self.Tex1);
|
|
end
|
|
if not self.Tex2 then
|
|
self.Tex2 = self:CreateTexture(nil, "OVERLAY");
|
|
self.Tex2:SetSize(16, 16);
|
|
self.Tex2:SetPoint("CENTER", self.Tex1, "CENTER", 0, 0);
|
|
self.Tex2:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
self.Tex2:SetTexCoord(0.5, 0.75, 0.5, 0.75);
|
|
DisableSharpening(self.Tex2);
|
|
end
|
|
|
|
if self.buttonType == "checkbox" then
|
|
self.Tex1:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
self.Tex2:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
|
|
elseif self.buttonType == "radio" then
|
|
self.Tex1:SetTexture("Interface/AddOns/Plumber/Art/Button/RadioButton");
|
|
self.Tex2:SetTexture("Interface/AddOns/Plumber/Art/Button/RadioButton");
|
|
end
|
|
|
|
self.Tex2:SetShown(self.selected);
|
|
if self.selected then
|
|
self.Tex1:SetTexCoord(0, 0.5, 0, 0.5);
|
|
else
|
|
self.Tex1:SetTexCoord(0.5, 1, 0, 0.5);
|
|
end
|
|
end
|
|
|
|
function MenuButtonMixin:SetButtonType(buttonType, selected)
|
|
if buttonType ~= self.buttonType or selected ~= self.selected then
|
|
self.buttonType = buttonType;
|
|
self.selected = selected;
|
|
else
|
|
return
|
|
end
|
|
|
|
if buttonType == "divider" then
|
|
self:SetHeight(MENU_DIVIDER_HEIGHT);
|
|
else
|
|
self:SetHeight(MENU_BUTTON_HEIGHT);
|
|
end
|
|
|
|
if buttonType == "divider" or buttonType == "title" then
|
|
self:Disable();
|
|
if self.Tex1 then
|
|
self.Tex1:Hide();
|
|
end
|
|
if self.Tex2 then
|
|
self.Tex2:Hide();
|
|
end
|
|
else
|
|
self:Enable();
|
|
end
|
|
|
|
self:SetupButtonTexture();
|
|
end
|
|
|
|
function MenuButtonMixin:SetButtonColor(color)
|
|
if self.buttonType == "title" then
|
|
self.Text:SetTextColor(0.5, 0.5, 0.5);
|
|
elseif color then
|
|
self.Text:SetTextColor(color[1], color[2], color[3]);
|
|
else
|
|
self.Text:SetTextColor(1, 1, 1);
|
|
end
|
|
end
|
|
|
|
function MenuButtonMixin:SetButtonData(buttonData)
|
|
self.Text:SetText(buttonData.text);
|
|
self.onClickFunc = buttonData.onClickFunc;
|
|
self.tooltip = buttonData.tooltip;
|
|
self:SetButtonLevel(buttonData.level);
|
|
self:SetButtonType(buttonData.type, buttonData.selected);
|
|
self:SetButtonColor(buttonData.color);
|
|
end
|
|
|
|
function MenuButtonMixin:SetButtonLevel(level)
|
|
if level == 1 then
|
|
self.baseTextOffset = MENU_SUBBUTTON_TEXT_OFFSET;
|
|
else
|
|
self.baseTextOffset = MENU_BUTTON_TEXT_OFFSET;
|
|
end
|
|
self.Text:SetPoint("LEFT", self, "LEFT", self.baseTextOffset, 0);
|
|
end
|
|
|
|
function ContextMenuMixin:ReleaseButtons()
|
|
if not self.buttons then return end;
|
|
|
|
for i, button in ipairs(self.buttons) do
|
|
button:Hide();
|
|
end
|
|
|
|
self.numActive = 0;
|
|
end
|
|
|
|
function ContextMenuMixin:AcquireButton()
|
|
if not self.buttons then
|
|
self.numActive = 0;
|
|
self.buttons = {};
|
|
self.ButtonContainer = CreateFrame("Frame", nil, self);
|
|
self.ButtonContainer:SetSize(8, 8);
|
|
self.ButtonContainer:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
end
|
|
|
|
local index = self.numActive + 1;
|
|
self.numActive = index;
|
|
local button = self.buttons[index];
|
|
|
|
if not button then
|
|
button = CreateFrame("Button", nil, self.ButtonContainer);
|
|
self.buttons[index] = button;
|
|
button:SetSize(MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT);
|
|
button.Text = button:CreateFontString(nil, "OVERLAY", "GameFontNormal");
|
|
button.Text:SetJustifyH("LEFT");
|
|
button.Text:SetPoint("LEFT", button, "LEFT", MENU_BUTTON_TEXT_OFFSET, 0);
|
|
button.Text:SetTextColor(1, 1, 1);
|
|
button.id = index;
|
|
--button:SetPoint("TOPLEFT", self, "TOPLEFT", MENU_PADDING_X, -MENU_PADDING_Y + (1-index)*MENU_BUTTON_HEIGHT);
|
|
if index == 1 then
|
|
button:SetPoint("TOPLEFT", self, "TOPLEFT", MENU_PADDING_X, -MENU_PADDING_Y);
|
|
else
|
|
button:SetPoint("TOPLEFT", self.buttons[index - 1], "BOTTOMLEFT", 0, 0);
|
|
end
|
|
Mixin(button, MenuButtonMixin);
|
|
button:SetScript("OnEnter", MenuButtonMixin.OnEnter);
|
|
button:SetScript("OnLeave", MenuButtonMixin.OnLeave);
|
|
button:SetScript("OnClick", MenuButtonMixin.OnClick);
|
|
button:SetScript("OnMouseDown", MenuButtonMixin.OnMouseDown);
|
|
button:SetScript("OnMouseUp", MenuButtonMixin.OnMouseUp);
|
|
button.parent = self;
|
|
end
|
|
|
|
button:Show();
|
|
|
|
return button
|
|
end
|
|
|
|
function ContextMenuMixin:SetMinWidth(minWidth)
|
|
self.minWidth = minWidth;
|
|
end
|
|
|
|
function ContextMenuMixin:SetMinHeight(minHeight)
|
|
self.minHeight = minHeight;
|
|
end
|
|
|
|
function ContextMenuMixin:SetMenuSize(width, height)
|
|
if self.minWidth and width < self.minWidth then
|
|
width = self.minWidth;
|
|
end
|
|
if self.minHeight and height < self.minHeight then
|
|
height = self.minHeight;
|
|
end
|
|
self:SetSize(width, height);
|
|
end
|
|
|
|
function ContextMenuMixin:SetOwner(owner)
|
|
self.owner = owner;
|
|
end
|
|
|
|
function ContextMenuMixin:SetContent(content, forceUpdate)
|
|
if content == self.content and not forceUpdate then
|
|
return
|
|
end
|
|
self.content = content;
|
|
self:ReleaseButtons();
|
|
|
|
local button;
|
|
local numDivider = 0;
|
|
|
|
for i, buttonData in ipairs(content) do
|
|
button = self:AcquireButton();
|
|
button:SetButtonData(buttonData);
|
|
if buttonData.type == "divider" then
|
|
numDivider = numDivider + 1;
|
|
end
|
|
end
|
|
|
|
self:SetHeight((#content - numDivider) * MENU_BUTTON_HEIGHT + numDivider * MENU_DIVIDER_HEIGHT + 2 * MENU_PADDING_Y);
|
|
end
|
|
|
|
function ContextMenuMixin:CloseMenu()
|
|
self:Hide();
|
|
self:ClearAllPoints();
|
|
end
|
|
|
|
function ContextMenuMixin:OnHide()
|
|
self:CloseMenu();
|
|
self:SetScript("OnUpdate", nil);
|
|
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
|
|
end
|
|
|
|
function ContextMenuMixin:OnShow()
|
|
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
|
|
end
|
|
|
|
function ContextMenuMixin:IsFocuesd()
|
|
return self:IsMouseOver() or (self.owner and self.owner:IsMouseOver())
|
|
end
|
|
|
|
function ContextMenuMixin:OnEvent(event, ...)
|
|
if event == "GLOBAL_MOUSE_DOWN" then
|
|
if not self:IsFocuesd() then
|
|
self:CloseMenu();
|
|
end
|
|
end
|
|
end
|
|
|
|
local function HighlightFrame_OnUpdate(self, elapsed)
|
|
local x, y = GetScaledCursorPosition();
|
|
self.HighlightTexture:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y);
|
|
|
|
if self.mouseoverTime then
|
|
self.mouseoverTime = self.mouseoverTime + elapsed;
|
|
if self.mouseoverTime >= MENU_TOOLTIP_DELAY then
|
|
self.mouseoverTime = nil;
|
|
SharedContextMenu:ShowFocusedButtonTooltip();
|
|
end
|
|
end
|
|
end
|
|
|
|
function ContextMenuMixin:FocusOnButton(menuButton)
|
|
self.focusedButton = menuButton;
|
|
if menuButton then
|
|
self.HighlightFrame:ClearAllPoints();
|
|
self.HighlightFrame:SetPoint("TOPLEFT", menuButton, "TOPLEFT", 0, 0);
|
|
self.HighlightFrame:SetPoint("BOTTOMRIGHT", menuButton, "BOTTOMRIGHT", 0, 0);
|
|
self.HighlightFrame.mouseoverTime = 0;
|
|
self.HighlightFrame:Show();
|
|
else
|
|
self.HighlightFrame:Hide();
|
|
self.HighlightFrame.mouseoverTime = nil;
|
|
end
|
|
end
|
|
|
|
function ContextMenuMixin:ShowFocusedButtonTooltip()
|
|
if self.focusedButton and self.focusedButton.tooltip and self.focusedButton:IsVisible() then
|
|
local tooltip = GameTooltip;
|
|
tooltip:Hide();
|
|
tooltip:SetOwner(self.focusedButton, "ANCHOR_NONE");
|
|
|
|
local buttonRight = self.focusedButton:GetRight();
|
|
local uiRight = UIParent:GetRight();
|
|
if buttonRight and uiRight and buttonRight + 240 > uiRight then
|
|
tooltip:SetPoint("TOPRIGHT", self.focusedButton, "TOPLEFT", -4, 6);
|
|
else
|
|
tooltip:SetPoint("TOPLEFT", self.focusedButton, "TOPRIGHT", 4, 6);
|
|
end
|
|
|
|
tooltip:SetText(self.focusedButton.Text:GetText(), 1, 1, 1, true);
|
|
tooltip:AddLine(self.focusedButton.tooltip, 1, 0.82, 0, true);
|
|
tooltip:Show();
|
|
end
|
|
end
|
|
|
|
function ContextMenuMixin:Init()
|
|
self:SetFrameStrata("TOOLTIP");
|
|
self:SetFixedFrameStrata(true);
|
|
self:SetClampedToScreen(true);
|
|
|
|
self:SetScript("OnShow", ContextMenuMixin.OnShow);
|
|
self:SetScript("OnHide", ContextMenuMixin.OnHide);
|
|
self:SetScript("OnEvent", ContextMenuMixin.OnEvent);
|
|
|
|
self:SetMinWidth(MENU_BUTTON_WIDTH + 2*MENU_PADDING_X);
|
|
self:SetMinHeight(MENU_BUTTON_HEIGHT + 2*MENU_PADDING_Y);
|
|
self:SetMenuSize(64, 64);
|
|
|
|
self.HighlightFrame = CreateFrame("Frame", nil, self);
|
|
self.HighlightFrame:SetClipsChildren(true);
|
|
local HighlightTexture = self.HighlightFrame:CreateTexture(nil, "ARTWORK");
|
|
HighlightTexture:SetSize(480, 480);
|
|
HighlightTexture:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Circle-Blurry");
|
|
HighlightTexture:SetAlpha(0.15);
|
|
self.HighlightFrame.HighlightTexture = HighlightTexture;
|
|
self.HighlightFrame:SetScript("OnUpdate", HighlightFrame_OnUpdate);
|
|
|
|
self.Init = nil;
|
|
end
|
|
|
|
|
|
local function GetSharedContextMenu()
|
|
if not SharedContextMenu then
|
|
local parent = UIParent;
|
|
local f = addon.CreateNineSliceFrame(parent, "Menu_Black");
|
|
SharedContextMenu = f;
|
|
Mixin(f, ContextMenuMixin);
|
|
f:Hide();
|
|
f:Init();
|
|
end
|
|
return SharedContextMenu
|
|
end
|
|
addon.GetSharedContextMenu = GetSharedContextMenu;
|
|
end
|
|
|
|
do --Frame Reposition Button
|
|
local GetScaledCursorPosition = API.GetScaledCursorPosition;
|
|
|
|
local function OnUpdate_Frequency(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t > 0.016 then
|
|
self.t = 0;
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function OnUpdate_OnMoving(self, elapsed)
|
|
if OnUpdate_Frequency(self, elapsed) then
|
|
local x, y = GetScaledCursorPosition();
|
|
local offsetX, offsetY;
|
|
local anyChange;
|
|
|
|
if self.orientation == "x" then
|
|
offsetX = x - self.fromX;
|
|
if offsetX ~= self.offsetX then
|
|
self.offsetX = offsetX;
|
|
anyChange = true
|
|
end
|
|
elseif self.orientation == "y" then
|
|
offsetY = y - self.fromX;
|
|
if offsetY ~= self.offsetY then
|
|
self.offsetY = offsetY;
|
|
anyChange = true
|
|
end
|
|
end
|
|
|
|
if anyChange then
|
|
self.frameToControl:RepositionFrame(offsetX, offsetY);
|
|
end
|
|
end
|
|
end
|
|
|
|
local function OnUpdate_MonitorDiff(self, elapsed)
|
|
--start moving Owner once the cursor moves 2 units
|
|
if OnUpdate_Frequency(self, elapsed) then
|
|
local diff = 0;
|
|
local x, y = GetScaledCursorPosition();
|
|
if self.orientation == "x" then
|
|
diff = x - self.fromX;
|
|
elseif self.orientation == "y" then
|
|
diff = y - self.fromY;
|
|
end
|
|
if diff < 0 then
|
|
diff = -diff;
|
|
end
|
|
if diff >= 4 then --Threshold
|
|
self.fromX, self.fromY = x, y;
|
|
self.isMovingFrame = true;
|
|
self:OnLeave();
|
|
self.frameToControl:SnapShotFramePosition();
|
|
self:SetScript("OnUpdate", OnUpdate_OnMoving);
|
|
end
|
|
end
|
|
end
|
|
|
|
local RepositionButtonMixin = {};
|
|
|
|
function RepositionButtonMixin:OnMouseDown(button)
|
|
if self:IsEnabled() then
|
|
self.Icon:SetPoint("CENTER", self, "CENTER", 0, -1);
|
|
if button == "LeftButton" then
|
|
--Pre Frame Reposition
|
|
self:LockHighlight();
|
|
self.t = 0;
|
|
self.fromX, self.fromY = GetScaledCursorPosition();
|
|
self:SetScript("OnUpdate", OnUpdate_MonitorDiff);
|
|
end
|
|
end
|
|
end
|
|
|
|
function RepositionButtonMixin:StopReposition()
|
|
self:SetScript("OnUpdate", nil);
|
|
self.isMovingFrame = false;
|
|
self.fromX, self.fromY = nil, nil;
|
|
self.offsetX, self.offsetY = nil, nil;
|
|
end
|
|
|
|
function RepositionButtonMixin:OnMouseUp()
|
|
if self.isMovingFrame then
|
|
self.frameToControl:ConfirmNewPosition();
|
|
self:StopReposition();
|
|
end
|
|
self.Icon:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
self:UnlockHighlight();
|
|
end
|
|
|
|
function RepositionButtonMixin:OnClick(button)
|
|
if button =="RightButton" then
|
|
self:OnDoubleClick();
|
|
end
|
|
end
|
|
|
|
function RepositionButtonMixin:OnDoubleClick()
|
|
self:StopReposition();
|
|
if self.frameToControl then
|
|
self.frameToControl:ResetFramePosition();
|
|
end
|
|
end
|
|
|
|
function RepositionButtonMixin:OnEnable()
|
|
self.Icon:SetDesaturated(false);
|
|
self.Icon:SetVertexColor(1, 1, 1);
|
|
self.Icon:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
self:RefreshOnEnter();
|
|
end
|
|
|
|
function RepositionButtonMixin:OnDisable()
|
|
self.Icon:SetDesaturated(true);
|
|
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
|
|
self.Icon:SetPoint("CENTER", self, "CENTER", 0, 0);
|
|
--self.Highlight:Hide();
|
|
self:RefreshOnEnter();
|
|
end
|
|
|
|
function RepositionButtonMixin:RefreshOnEnter()
|
|
if self:IsVisible() and self:IsMouseOver() then
|
|
self:OnEnter();
|
|
end
|
|
end
|
|
|
|
function RepositionButtonMixin:OnShow()
|
|
|
|
end
|
|
|
|
function RepositionButtonMixin:OnHide()
|
|
self:StopReposition();
|
|
end
|
|
|
|
function RepositionButtonMixin:OnEnter()
|
|
if self.isMovingFrame then return end;
|
|
--self.Highlight:Show();
|
|
|
|
local tooltip = GameTooltip;
|
|
tooltip:Hide();
|
|
tooltip:SetOwner(self, "ANCHOR_RIGHT");
|
|
|
|
if self.orientation == "x" then
|
|
tooltip:SetText(L["Reposition Button Horizontal"], 1, 1, 1);
|
|
elseif self.orientation == "y" then
|
|
tooltip:SetText(L["Reposition Button Vertical"], 1, 1, 1);
|
|
end
|
|
|
|
tooltip:AddLine(L["Reposition Button Tooltip"], 1, 0.82, 0, true);
|
|
tooltip:Show();
|
|
end
|
|
|
|
function RepositionButtonMixin:OnLeave()
|
|
GameTooltip:Hide();
|
|
--self.Highlight:Hide();
|
|
end
|
|
|
|
function RepositionButtonMixin:SetOrientation(xy)
|
|
self.orientation = xy;
|
|
local tex;
|
|
if xy == "x" then
|
|
tex = "Interface/AddOns/Plumber/Art/Button/MoveButton-X";
|
|
elseif xy == "y" then
|
|
tex = "Interface/AddOns/Plumber/Art/Button/MoveButton-Y";
|
|
end
|
|
self.Highlight:SetTexture(tex);
|
|
self.Icon:SetTexture(tex);
|
|
end
|
|
|
|
local function CreateRepositionButton(frameToControl)
|
|
local button = CreateFrame("Button", nil, frameToControl);
|
|
button.frameToControl = frameToControl;
|
|
button:SetSize(20, 20);
|
|
button:SetMotionScriptsWhileDisabled(true);
|
|
button:RegisterForClicks("LeftButtonUp", "RightButtonUp");
|
|
Mixin(button, RepositionButtonMixin);
|
|
|
|
local tex = "Interface/AddOns/Plumber/Art/Button/MoveButton-X";
|
|
|
|
button.Highlight = button:CreateTexture(nil, "HIGHLIGHT");
|
|
--button.Highlight:Hide();
|
|
button.Highlight:SetSize(32, 32);
|
|
button.Highlight:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
button.Highlight:SetTexture(tex);
|
|
button.Highlight:SetTexCoord(0.5, 1, 0, 1);
|
|
|
|
button.Icon = button:CreateTexture(nil, "ARTWORK");
|
|
button.Icon:SetSize(32, 32);
|
|
button.Icon:SetPoint("CENTER", button, "CENTER", 0, 0);
|
|
button.Icon:SetTexture(tex);
|
|
button.Icon:SetTexCoord(0, 0.5, 0, 1);
|
|
|
|
button:SetScript("OnMouseDown", button.OnMouseDown);
|
|
button:SetScript("OnMouseUp", button.OnMouseUp);
|
|
button:SetScript("OnClick", button.OnClick);
|
|
button:SetScript("OnDoubleClick", button.OnDoubleClick);
|
|
button:SetScript("OnEnable", button.OnEnable);
|
|
button:SetScript("OnDisable", button.OnDisable);
|
|
button:SetScript("OnShow", button.OnShow);
|
|
button:SetScript("OnHide", button.OnHide);
|
|
button:SetScript("OnEnter", button.OnEnter);
|
|
button:SetScript("OnLeave", button.OnLeave);
|
|
|
|
return button
|
|
end
|
|
addon.CreateRepositionButton = CreateRepositionButton;
|
|
end
|
|
|
|
do --Slider
|
|
local Round = API.Round;
|
|
local SliderFrameMixin = {};
|
|
|
|
local TEXTURE_FILE = "Interface/AddOns/Plumber/Art/Frame/Slider";
|
|
local TEX_COORDS = {
|
|
Thumb_Nomral = {0, 0.5, 0, 0.25},
|
|
Thumb_Disable = {0.5, 1, 0, 0.25},
|
|
Thumb_Highlight = {0, 0.5, 0.25, 0.5},
|
|
|
|
Back_Nomral = {0, 0.25, 0.5, 0.625},
|
|
Back_Disable = {0.25, 0.5, 0.5, 0.625},
|
|
Back_Highlight = {0.5, 0.75, 0.5, 0.625},
|
|
|
|
Forward_Nomral = {0, 0.25, 0.625, 0.75},
|
|
Forward_Disable = {0.25, 0.5, 0.625, 0.75},
|
|
Forward_Highlight = {0.5, 0.75, 0.625, 0.75},
|
|
|
|
Slider_Left = {0, 0.125, 0.875, 1},
|
|
Slider_Middle = {0.125, 0.375, 0.875, 1},
|
|
Slider_Right = {0.375, 0.5, 0.875, 1},
|
|
};
|
|
|
|
local function SetTextureCoord(texture, key)
|
|
texture:SetTexCoord( unpack(TEX_COORDS[key]) );
|
|
end
|
|
|
|
local SharedMethods = {
|
|
"GetValue", "SetValue", "SetMinMaxValues",
|
|
};
|
|
|
|
for k, v in ipairs(SharedMethods) do
|
|
SliderFrameMixin[v] = function(self, ...)
|
|
return self.Slider[v](self.Slider, ...);
|
|
end;
|
|
end
|
|
|
|
|
|
local SliderScripts = {};
|
|
|
|
function SliderScripts:OnMinMaxChanged(min, max)
|
|
if self.formatMinMaxValueFunc then
|
|
self.formatMinMaxValueFunc(min, max);
|
|
end
|
|
end
|
|
|
|
function SliderScripts:OnValueChanged(value, userInput)
|
|
if value ~= self.value then
|
|
self.value = value;
|
|
else
|
|
return
|
|
end
|
|
|
|
self.ThumbTexture:SetPoint("CENTER", self.Thumb, "CENTER", 0, 0);
|
|
|
|
if self.ValueText then
|
|
if self.formatValueFunc then
|
|
self.ValueText:SetText(self.formatValueFunc(value));
|
|
else
|
|
self.ValueText:SetText(value);
|
|
end
|
|
end
|
|
|
|
if userInput then
|
|
if self.onValueChangedFunc then
|
|
self.onValueChangedFunc(value);
|
|
end
|
|
end
|
|
end
|
|
|
|
function SliderScripts:OnMouseDown()
|
|
if self:IsEnabled() then
|
|
self:LockHighlight();
|
|
end
|
|
end
|
|
|
|
function SliderScripts:OnMouseUp()
|
|
self:UnlockHighlight();
|
|
end
|
|
|
|
|
|
local function BackForwardButton_OnClick(self)
|
|
if self.delta then
|
|
self:GetParent():SetValueByDelta(self.delta, true);
|
|
end
|
|
end
|
|
|
|
function SliderFrameMixin:OnLoad()
|
|
for k, v in pairs(SliderScripts) do
|
|
self.Slider:SetScript(k, v);
|
|
end
|
|
|
|
self.Back:SetScript("OnClick", BackForwardButton_OnClick);
|
|
self.Forward:SetScript("OnClick", BackForwardButton_OnClick);
|
|
|
|
self.Slider.Left:SetTexture(TEXTURE_FILE);
|
|
self.Slider.Middle:SetTexture(TEXTURE_FILE);
|
|
self.Slider.Right:SetTexture(TEXTURE_FILE);
|
|
self.Slider.ThumbTexture:SetTexture(TEXTURE_FILE);
|
|
self.Slider.ThumbHighlight:SetTexture(TEXTURE_FILE);
|
|
SetTextureCoord(self.Slider.Left, "Slider_Left");
|
|
SetTextureCoord(self.Slider.Middle, "Slider_Middle");
|
|
SetTextureCoord(self.Slider.Right, "Slider_Right");
|
|
SetTextureCoord(self.Slider.ThumbTexture, "Thumb_Nomral");
|
|
SetTextureCoord(self.Slider.ThumbHighlight, "Thumb_Highlight");
|
|
|
|
self.Back.Texture:SetTexture(TEXTURE_FILE);
|
|
self.Back.Highlight:SetTexture(TEXTURE_FILE);
|
|
SetTextureCoord(self.Back.Texture, "Back_Nomral");
|
|
SetTextureCoord(self.Back.Highlight, "Back_Highlight");
|
|
|
|
self.Forward.Texture:SetTexture(TEXTURE_FILE);
|
|
self.Forward.Highlight:SetTexture(TEXTURE_FILE);
|
|
SetTextureCoord(self.Forward.Texture, "Forward_Nomral");
|
|
SetTextureCoord(self.Forward.Highlight, "Forward_Highlight");
|
|
|
|
self:SetMinMaxValues(0, 100);
|
|
self:SetValueStep(10);
|
|
self:SetObeyStepOnDrag(true);
|
|
self:SetValue(0);
|
|
|
|
self:Enable();
|
|
|
|
DisableSharpening(self.Slider.Left);
|
|
DisableSharpening(self.Slider.Middle);
|
|
DisableSharpening(self.Slider.Right);
|
|
end
|
|
|
|
function SliderFrameMixin:Enable()
|
|
self.Slider:Enable();
|
|
self.Back:Enable();
|
|
self.Forward:Enable();
|
|
SetTextureCoord(self.Slider.ThumbTexture, "Thumb_Nomral");
|
|
SetTextureCoord(self.Back.Texture, "Back_Nomral");
|
|
SetTextureCoord(self.Forward.Texture, "Forward_Nomral");
|
|
self.Label:SetTextColor(1, 1, 1);
|
|
self.RightText:SetTextColor(1, 0.82, 0);
|
|
end
|
|
|
|
function SliderFrameMixin:Disable()
|
|
self.Slider:Disable();
|
|
self.Back:Disable();
|
|
self.Forward:Disable();
|
|
self.Slider:UnlockHighlight();
|
|
SetTextureCoord(self.Slider.ThumbTexture, "Thumb_Disable");
|
|
SetTextureCoord(self.Back, "Back_Disable");
|
|
SetTextureCoord(self.Forward.Texture, "Forward_Disable");
|
|
self.Label:SetTextColor(0.5, 0.5, 0.5);
|
|
self.RightText:SetTextColor(0.5, 0.5, 0.5);
|
|
end
|
|
|
|
function SliderFrameMixin:SetValueByDelta(delta, userInput)
|
|
local value = self:GetValue();
|
|
self:SetValue(value + delta);
|
|
|
|
if userInput then
|
|
if self.onValueChangedFunc then
|
|
self.onValueChangedFunc(self:GetValue());
|
|
end
|
|
end
|
|
end
|
|
|
|
function SliderFrameMixin:SetValueStep(valueStep)
|
|
self.Slider:SetValueStep(valueStep);
|
|
self.Back.delta = -valueStep;
|
|
self.Forward.delta = valueStep;
|
|
end
|
|
|
|
function SliderFrameMixin:SetObeyStepOnDrag(obey)
|
|
self.Slider:SetObeyStepOnDrag(obey);
|
|
if not obey then
|
|
local min, max = self.GetMinMaxValues();
|
|
local delta = (max - min) * 0.1;
|
|
self.Back.delta = -delta;
|
|
self.Forward.delta = delta;
|
|
end
|
|
end
|
|
|
|
function SliderFrameMixin:SetLabel(label)
|
|
self.Label:SetText(label);
|
|
end
|
|
|
|
function SliderFrameMixin:SetFormatValueFunc(formatValueFunc)
|
|
self.Slider.formatValueFunc = formatValueFunc;
|
|
self.RightText:SetText(formatValueFunc(self:GetValue() or 0));
|
|
end
|
|
|
|
function SliderFrameMixin:SetOnValueChangedFunc(onValueChangedFunc)
|
|
self.Slider.onValueChangedFunc = onValueChangedFunc;
|
|
self.onValueChangedFunc = onValueChangedFunc;
|
|
end
|
|
|
|
local function FormatValue(value)
|
|
return value
|
|
end
|
|
|
|
local function CreateSlider(parent)
|
|
local f = CreateFrame("Frame", nil, parent, "PlumberMinimalSliderWithControllerTemplate");
|
|
Mixin(f, SliderFrameMixin);
|
|
|
|
f.Slider.ValueText = f.RightText;
|
|
f.Slider.Back = f.Back;
|
|
f.Slider.Forward = f.Forward;
|
|
|
|
f:SetFormatValueFunc(FormatValue);
|
|
f:OnLoad();
|
|
|
|
return f
|
|
end
|
|
addon.CreateSlider = CreateSlider;
|
|
end
|
|
|
|
do --UIPanelButton
|
|
local UIPanelButtonMixin = {};
|
|
|
|
function UIPanelButtonMixin:OnClick(button)
|
|
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnMouseDown(button)
|
|
if self:IsEnabled() then
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Down");
|
|
end
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnMouseUp(button)
|
|
if self:IsEnabled() then
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Up");
|
|
end
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnDisable()
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Disabled");
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnEnable()
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Up");
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnEnter()
|
|
|
|
end
|
|
|
|
function UIPanelButtonMixin:OnLeave()
|
|
|
|
end
|
|
|
|
function UIPanelButtonMixin:SetButtonText(text)
|
|
self:SetText(text);
|
|
end
|
|
|
|
local function CreateUIPanelButton(parent)
|
|
local f = CreateFrame("Button", nil, parent);
|
|
f:SetSize(144, 24);
|
|
Mixin(f, UIPanelButtonMixin);
|
|
|
|
f:SetScript("OnMouseDown", f.OnMouseDown);
|
|
f:SetScript("OnMouseUp", f.OnMouseUp);
|
|
f:SetScript("OnEnter", f.OnEnter);
|
|
f:SetScript("OnLeave", f.OnLeave);
|
|
f:SetScript("OnEnable", f.OnEnable);
|
|
f:SetScript("OnDisable", f.OnDisable);
|
|
|
|
f.Background = f:CreateTexture(nil, "BACKGROUND");
|
|
f.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Up");
|
|
f.Background:SetTextureSliceMargins(32, 16, 32, 16);
|
|
f.Background:SetTextureSliceMode(1);
|
|
f.Background:SetAllPoints(true);
|
|
DisableSharpening(f.Background);
|
|
|
|
f.Highlight = f:CreateTexture(nil, "HIGHLIGHT");
|
|
f.Highlight:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton-Highlight");
|
|
f.Highlight:SetTextureSliceMargins(32, 16, 32, 16);
|
|
f.Highlight:SetTextureSliceMode(0);
|
|
f.Highlight:SetAllPoints(true);
|
|
f.Highlight:SetBlendMode("ADD");
|
|
f.Highlight:SetVertexColor(0.5, 0.5, 0.5);
|
|
|
|
f:SetNormalFontObject("GameFontNormal");
|
|
f:SetHighlightFontObject("GameFontHighlight");
|
|
f:SetDisabledFontObject("GameFontDisable");
|
|
f:SetPushedTextOffset(0, -1);
|
|
|
|
return f
|
|
end
|
|
addon.CreateUIPanelButton = CreateUIPanelButton;
|
|
end
|
|
|
|
do --EditMode
|
|
local Round = API.Round;
|
|
local EditModeSelectionMixin = {};
|
|
|
|
function EditModeSelectionMixin:OnDragStart()
|
|
self.parent:OnDragStart();
|
|
end
|
|
|
|
function EditModeSelectionMixin:OnDragStop()
|
|
self.parent:OnDragStop();
|
|
end
|
|
|
|
function EditModeSelectionMixin:ShowHighlighted()
|
|
--Blue
|
|
if not self.parent:IsShown() then return end;
|
|
self.isSelected = false;
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Frame/EditModeHighlighted");
|
|
self:Show();
|
|
self.Label:Hide();
|
|
end
|
|
|
|
function EditModeSelectionMixin:ShowSelected()
|
|
--Yellow
|
|
if not self.parent:IsShown() then return end;
|
|
self.isSelected = true;
|
|
self.Background:SetTexture("Interface/AddOns/Plumber/Art/Frame/EditModeSelected");
|
|
self:Show();
|
|
|
|
if not self.hideLabel then
|
|
self.Label:Show();
|
|
end
|
|
end
|
|
|
|
function EditModeSelectionMixin:OnShow()
|
|
local offset = API.GetPixelForWidget(self, 6);
|
|
self.Background:SetPoint("TOPLEFT", self, "TOPLEFT", -offset, offset);
|
|
self.Background:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", offset, -offset);
|
|
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
|
|
end
|
|
|
|
function EditModeSelectionMixin:OnHide()
|
|
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
|
|
end
|
|
|
|
local function IsMouseOverOptionToggle()
|
|
local obj = GetMouseFocus();
|
|
if obj and obj.isPlumberEditModeToggle then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function EditModeSelectionMixin:OnEvent(event, ...)
|
|
if event == "GLOBAL_MOUSE_DOWN" then
|
|
if self:IsShown() and not(self.parent:IsFocused() or IsMouseOverOptionToggle()) then
|
|
self:ShowHighlighted();
|
|
self.parent:ShowOptions(false);
|
|
end
|
|
end
|
|
end
|
|
|
|
function EditModeSelectionMixin:OnMouseDown()
|
|
self:ShowSelected();
|
|
self.parent:ShowOptions(true);
|
|
|
|
if EditModeManagerFrame and EditModeManagerFrame.ClearSelectedSystem then
|
|
EditModeManagerFrame:ClearSelectedSystem()
|
|
end
|
|
end
|
|
|
|
|
|
local function CreateEditModeSelection(parent, uiName, hideLabel)
|
|
local f = CreateFrame("Frame", nil, parent);
|
|
f:Hide();
|
|
f:SetAllPoints(true);
|
|
f:SetFrameStrata(parent:GetFrameStrata());
|
|
f:SetToplevel(true);
|
|
f:SetFrameLevel(999);
|
|
f:EnableMouse(true);
|
|
f:RegisterForDrag("LeftButton");
|
|
f:SetIgnoreParentAlpha(true);
|
|
|
|
f.Label = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightMedium");
|
|
f.Label:SetText(uiName);
|
|
f.Label:SetJustifyH("CENTER");
|
|
f.Label:SetPoint("CENTER", f, "CENTER", 0, 0);
|
|
|
|
f.Background = f:CreateTexture(nil, "BACKGROUND");
|
|
f.Background:SetTexture("Interface/AddOns/Plumber/Art/Frame/EditModeHighlighted");
|
|
f.Background:SetTextureSliceMargins(16, 16, 16, 16);
|
|
f.Background:SetTextureSliceMode(0);
|
|
f.Background:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
|
|
f.Background:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
|
|
|
|
Mixin(f, EditModeSelectionMixin);
|
|
|
|
f:SetScript("OnShow", f.OnShow);
|
|
f:SetScript("OnHide", f.OnHide);
|
|
f:SetScript("OnEvent", f.OnEvent);
|
|
f:SetScript("OnMouseDown", f.OnMouseDown);
|
|
f:SetScript("OnDragStart", f.OnDragStart);
|
|
f:SetScript("OnDragStop", f.OnDragStop);
|
|
|
|
parent.Selection = f;
|
|
f.parent = parent;
|
|
f.hideLabel = hideLabel;
|
|
|
|
return f
|
|
end
|
|
addon.CreateEditModeSelection = CreateEditModeSelection;
|
|
|
|
|
|
local EditModeSettingsDialog;
|
|
local DIALOG_WIDTH = 382;
|
|
|
|
local EditModeSettingsDialogMixin = {};
|
|
|
|
function EditModeSettingsDialogMixin:Exit()
|
|
self:Hide();
|
|
self:ClearAllPoints();
|
|
self.requireResetPosition = true;
|
|
if self.parent then
|
|
if self.parent.Selection then
|
|
self.parent.Selection:ShowHighlighted();
|
|
end
|
|
if self.parent.ExitEditMode and not API.IsInEditMode() then
|
|
self.parent:ExitEditMode();
|
|
end
|
|
self.parent = nil;
|
|
end
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:ReleaseAllWidgets()
|
|
for _, widget in pairs(self.widgets) do
|
|
widget:Hide();
|
|
widget:ClearAllPoints();
|
|
end
|
|
|
|
self.activeWidgets = {};
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:Layout()
|
|
local leftPadding = 20;
|
|
local topPadding = 48;
|
|
local bottomPadding = 20;
|
|
local OPTION_GAP_Y = 8; --consistent with ControlCenter
|
|
local height = topPadding;
|
|
local widgetHeight;
|
|
local contentWidth = DIALOG_WIDTH - 2*leftPadding;
|
|
|
|
for order, widget in ipairs(self.activeWidgets) do
|
|
if widget.isGap then
|
|
height = height + 8 + OPTION_GAP_Y;
|
|
else
|
|
widget:SetPoint("TOPLEFT", self, "TOPLEFT", leftPadding, -height);
|
|
widgetHeight = Round(widget:GetHeight());
|
|
height = height + widgetHeight + OPTION_GAP_Y;
|
|
if widget.matchParentWidth then
|
|
widget:SetWidth(contentWidth);
|
|
end
|
|
end
|
|
end
|
|
|
|
height = height - OPTION_GAP_Y + bottomPadding;
|
|
self:SetHeight(height);
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:AcquireWidgetByType(type)
|
|
local widget;
|
|
|
|
if type == "Checkbox" then
|
|
if not self.checkboxes then
|
|
self.checkboxes = {};
|
|
end
|
|
widget = addon.CreateCheckbox(self);
|
|
elseif type == "Slider" then
|
|
if not self.sliders then
|
|
self.sliders = {};
|
|
end
|
|
widget = addon.CreateSlider(self);
|
|
elseif type == "UIPanelButton" then
|
|
widget = addon.CreateUIPanelButton(self);
|
|
elseif type == "Texture" then
|
|
widget = self:CreateTexture(nil, "OVERLAY");
|
|
widget.isDivider = nil;
|
|
widget.matchParentWidth = nil;
|
|
elseif type == "FontString" then
|
|
widget = self:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
|
|
widget.matchParentWidth = true;
|
|
end
|
|
|
|
widget:Show();
|
|
|
|
return widget
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:CreateCheckbox(widgetData)
|
|
local checkbox = self:AcquireWidgetByType("Checkbox");
|
|
|
|
checkbox.Label:SetFontObject("GameFontHighlightMedium"); --Fonts in EditMode and Options are different
|
|
checkbox.Label:SetTextColor(1, 1, 1);
|
|
|
|
checkbox:SetData(widgetData);
|
|
checkbox:SetChecked( PlumberDB[checkbox.dbKey] );
|
|
|
|
return checkbox
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:CreateSlider(widgetData)
|
|
local slider = self:AcquireWidgetByType("Slider");
|
|
|
|
slider:SetLabel(widgetData.label);
|
|
slider:SetMinMaxValues(widgetData.minValue, widgetData.maxValue);
|
|
|
|
if widgetData.valueStep then
|
|
slider:SetObeyStepOnDrag(true);
|
|
slider:SetValueStep(widgetData.valueStep);
|
|
else
|
|
slider:SetObeyStepOnDrag(false);
|
|
end
|
|
|
|
slider:SetFormatValueFunc(widgetData.formatValueFunc);
|
|
slider:SetOnValueChangedFunc(widgetData.onValueChangedFunc);
|
|
|
|
if widgetData.dbKey and PlumberDB[widgetData.dbKey] then
|
|
slider:SetValue(PlumberDB[widgetData.dbKey]);
|
|
end
|
|
|
|
return slider
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:CreateUIPanelButton(widgetData)
|
|
local button = self:AcquireWidgetByType("UIPanelButton");
|
|
button:SetButtonText(widgetData.label);
|
|
button:SetScript("OnClick", widgetData.onClickFunc);
|
|
if (not widgetData.stateCheckFunc) or (widgetData.stateCheckFunc()) then
|
|
button:Enable();
|
|
else
|
|
button:Disable();
|
|
end
|
|
button.matchParentWidth = true;
|
|
return button
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:CreateDivider(widgetData)
|
|
local texture = self:AcquireWidgetByType("Texture");
|
|
texture:SetTexture("Interface/AddOns/Plumber/Art/Frame/Divider_NineSlice");
|
|
texture:SetTextureSliceMargins(48, 4, 48, 4);
|
|
texture:SetTextureSliceMode(0);
|
|
texture:SetHeight(4);
|
|
texture.isDivider = true;
|
|
texture.matchParentWidth = true;
|
|
return texture
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:CreateHeader(widgetData)
|
|
local fontString = self:AcquireWidgetByType("FontString");
|
|
fontString:SetJustifyH("CENTER");
|
|
fontString:SetJustifyV("TOP");
|
|
fontString:SetSpacing(2);
|
|
fontString.matchParentWidth = true;
|
|
fontString:SetText(widgetData.label);
|
|
return fontString
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:SetupOptions(schematic)
|
|
self:ReleaseAllWidgets();
|
|
self:SetTitle(schematic.title);
|
|
|
|
if schematic.widgets then
|
|
for order, widgetData in ipairs(schematic.widgets) do
|
|
local widget;
|
|
if widgetData.type == "Checkbox" then
|
|
widget = self:CreateCheckbox(widgetData);
|
|
elseif widgetData.type == "RadioGroup" then
|
|
|
|
elseif widgetData.type == "Slider" then
|
|
widget = self:CreateSlider(widgetData);
|
|
elseif widgetData.type == "UIPanelButton" then
|
|
widget = self:CreateUIPanelButton(widgetData);
|
|
elseif widgetData.type == "Divider" then
|
|
widget = self:CreateDivider(widgetData);
|
|
elseif widgetData.type == "Header" then
|
|
widget = self:CreateHeader(widgetData);
|
|
end
|
|
|
|
if widget then
|
|
tinsert(self.activeWidgets, widget);
|
|
widget.widgetKey = widgetData.widgetKey;
|
|
end
|
|
end
|
|
end
|
|
self:Layout();
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:FindWidget(widgetKey)
|
|
if self.activeWidgets then
|
|
for _, widget in pairs(self.activeWidgets) do
|
|
if widget.widgetKey == widgetKey then
|
|
return widget
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:OnDragStart()
|
|
self:StartMoving();
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:OnDragStop()
|
|
self:StopMovingOrSizing();
|
|
end
|
|
|
|
function EditModeSettingsDialogMixin:SetTitle(title)
|
|
self.Title:SetText(title);
|
|
end
|
|
|
|
local function SetupSettingsDialog(parent, schematic)
|
|
if not EditModeSettingsDialog then
|
|
local f = CreateFrame("Frame", nil, UIParent);
|
|
EditModeSettingsDialog = f;
|
|
f:Hide();
|
|
f:SetSize(DIALOG_WIDTH, 350);
|
|
f:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
|
|
f:SetMovable(true);
|
|
f:SetClampedToScreen(true);
|
|
f:RegisterForDrag("LeftButton");
|
|
f:SetDontSavePosition(true);
|
|
f:SetFrameStrata("DIALOG");
|
|
f:SetFrameLevel(200);
|
|
f:EnableMouse(true);
|
|
|
|
f.widgets = {};
|
|
f.requireResetPosition = true;
|
|
|
|
Mixin(f, EditModeSettingsDialogMixin);
|
|
|
|
f.Border = CreateFrame("Frame", nil, f, "DialogBorderTranslucentTemplate");
|
|
f.CloseButton = CreateFrame("Button", nil, f, "UIPanelCloseButtonNoScripts");
|
|
f.CloseButton:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0);
|
|
f.CloseButton:SetScript("OnClick", function()
|
|
f:Exit();
|
|
end);
|
|
f.Title = f:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge");
|
|
f.Title:SetPoint("TOP", f, "TOP", 0, -16);
|
|
f.Title:SetText("Title");
|
|
|
|
f:SetScript("OnDragStart", f.OnDragStart);
|
|
f:SetScript("OnDragStop", f.OnDragStop);
|
|
end
|
|
|
|
if schematic ~= EditModeSettingsDialog.schematic then
|
|
EditModeSettingsDialog.requireResetPosition = true;
|
|
EditModeSettingsDialog.schematic = schematic;
|
|
EditModeSettingsDialog:ClearAllPoints();
|
|
EditModeSettingsDialog:SetupOptions(schematic);
|
|
end
|
|
|
|
EditModeSettingsDialog.parent = parent;
|
|
|
|
return EditModeSettingsDialog
|
|
end
|
|
addon.SetupSettingsDialog = SetupSettingsDialog;
|
|
end
|