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.

6025 lines
203 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 = C_Spell.GetSpellCharges;
local C_Item = C_Item;
local GetItemCount = C_Item.GetItemCount;
local GetItemIconByID = C_Item.GetItemIconByID;
local GetCVarBool = C_CVar.GetCVarBool;
local GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo;
local CreateFrame = CreateFrame;
local UIParent = UIParent;
local GameTooltip = GameTooltip;
local function DisableSharpening(texture)
texture:SetTexelSnappingBias(0);
texture:SetSnapToPixelGrid(false);
end
API.DisableSharpening = DisableSharpening;
local DelayedTooltip = CreateFrame("Frame");
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
NineSlice_GenericBox_Black = true,
NineSlice_GenericBox_Black_Shadowed = true,
};
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:SetCornerSizeByScale(scale)
self:SetCornerSize(16 * scale);
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:SetDisableSharpening(state)
for i = 1, #self.pieces do
self.pieces[i]:SetSnapToPixelGrid(not state);
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:ShowTooltip()
if self.tooltip then
local f = GameTooltip;
f:Hide();
f:SetOwner(self, "ANCHOR_RIGHT");
f:SetText(self.Label:GetText(), 1, 1, 1, true);
if type(self.tooltip) == "function" then
f:AddLine(self.tooltip(), 1, 0.82, 0, true);
else
f:AddLine(self.tooltip, 1, 0.82, 0, true);
end
if self.tooltip2 then
local tooltip2;
if type(self.tooltip2) == "function" then
tooltip2 = self.tooltip2();
else
tooltip2 = self.tooltip2;
end
if tooltip2 then
f:AddLine(" ", 1, 0.82, 0, true);
f:AddLine(tooltip2, 1, 0.82, 0, true);
end
end
f:Show();
end
end
function CheckboxMixin:OnEnter()
if IsMouseButtonDown() then return end;
self:ShowTooltip();
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 addon.GetDBValue(self.dbKey)
addon.SetDBValue(self.dbKey, newState, true);
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();
if self.keepTooltipAfterClicks then
if self:IsMouseMotionFocus() then
self:ShowTooltip();
end
end
end
function CheckboxMixin:OnEnable()
self.CheckedTexture:SetDesaturated(false);
self.CheckedTexture:SetVertexColor(1, 1, 1);
self.Label:SetTextColor(1, 0.82, 0);
end
function CheckboxMixin:OnDisable()
self.CheckedTexture:SetDesaturated(true);
self.CheckedTexture:SetVertexColor(0.5, 0.5, 0.5);
self.Label:SetTextColor(0.5, 0.5, 0.5);
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.tooltip2 = data.tooltip2;
self.onClickFunc = data.onClickFunc;
self.onEnterFunc = data.onEnterFunc;
self.onLeaveFunc = data.onLeaveFunc;
self.keepTooltipAfterClicks = data.keepTooltipAfterClicks;
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);
b:SetScript("OnEnable", CheckboxMixin.OnEnable);
b:SetScript("OnDisable", CheckboxMixin.OnDisable);
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;
local ExpandCollapseButtonMixin = {};
function ExpandCollapseButtonMixin:OnClick()
local parent = self:GetParent();
if parent.ToggleExpanded then
parent:ToggleExpanded();
end
end
function ExpandCollapseButtonMixin:ShowNormalTexture()
if self.expanded then
self.Texture:SetTexCoord(0, 0.15625, 0, 0.15625);
else
self.Texture:SetTexCoord(0, 0.15625, 0.15625, 0.3125);
end
end
function ExpandCollapseButtonMixin:ShowPushedTexture()
if self.expanded then
self.Texture:SetTexCoord(0.15625, 0.3125, 0, 0.15625);
else
self.Texture:SetTexCoord(0.15625, 0.3125, 0.15625, 0.3125);
end
end
function ExpandCollapseButtonMixin:SetExpanded(state)
self.expanded = state;
self:ShowNormalTexture();
end
local function CreateExpandCollapseButton(parent)
local b = CreateFrame("Button", nil, parent);
b:SetSize(BUTTON_MIN_SIZE, BUTTON_MIN_SIZE);
Mixin(b, ExpandCollapseButtonMixin);
b.Texture = b:CreateTexture(nil, "ARTWORK");
b.Texture:SetTexture("Interface/AddOns/Plumber/Art/Button/ExpandCollapseButton");
b.Texture:SetPoint("CENTER", b, "CENTER", 0, 0);
b.Texture:SetSize(20, 20);
DisableSharpening(b.Texture);
b.Highlight = b:CreateTexture(nil, "HIGHLIGHT");
b.Highlight:SetTexture("Interface/AddOns/Plumber/Art/Button/ExpandCollapseButton");
b.Highlight:SetBlendMode("ADD");
b.Highlight:SetPoint("CENTER", b, "CENTER", 0, 0);
b.Highlight:SetSize(20, 20);
b.Highlight:SetTexCoord(0.3125, 0.46875, 0, 0.15625);
b.Highlight:SetVertexColor(0.8, 0.8, 0.8);
b:SetExpanded(true);
b:SetScript("OnClick", b.OnClick);
b:SetScript("OnMouseUp", b.ShowNormalTexture);
b:SetScript("OnMouseDown", b.ShowPushedTexture);
b:SetScript("OnShow", b.ShowNormalTexture);
return b
end
addon.CreateExpandCollapseButton = CreateExpandCollapseButton;
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 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;
self:SetGoldAmount(coinIndex, BreakUpLargeNumbers(gold));
end
if silver > 0 or (gold > 0 and self.showCopperDuringAnimation) then
coinIndex = coinIndex + 1;
self:SetSilverAmount(coinIndex, silver);
end
if copper > 0 or self.showCopperDuringAnimation 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() + self.valueSymbolGap;
self.Symbol1:SetPoint("LEFT", self, "LEFT", width, 0);
if self.colorblindMode then
width = width + COLORBLIND_TEXT_GAP;
else
width = width + COIN_TEXTURE_SIZE + AMOUNT_COIN_GAP;
end
if coinIndex >= 2 then
width = width + COIN_TYPE_GAP;
self.Amount2:SetPoint("LEFT", self, "LEFT", width, 0);
width = width + self.Amount2:GetWrappedWidth() + self.valueSymbolGap;
self.Symbol2:SetPoint("LEFT", self, "LEFT", width, 0);
if self.colorblindMode then
width = width + COLORBLIND_TEXT_GAP;
else
width = width + COIN_TEXTURE_SIZE + AMOUNT_COIN_GAP;
end
end
if coinIndex >= 3 then
width = width + COIN_TYPE_GAP;
self.Amount3:SetPoint("LEFT", self, "LEFT", width, 0);
width = width + self.Amount3:GetWrappedWidth() + self.valueSymbolGap;
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 not color then
color = 0;
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
return self:Layout();
end
function MoneyDisplayMixin:GetAmount()
return self.rawCopper or 0
end
function MoneyDisplayMixin:OnUpdate_AnimateValue(elapsed)
self.totalTime = self.totalTime + elapsed;
self.updateTime = self.updateTime + elapsed;
if self.totalTime > 0.8 then
self.fromCopper = self.toCopper;
self:SetScript("OnUpdate", nil);
self:SetAmount(self.toCopper);
self.totalTime = nil;
self.updateTime = nil;
else
if self.updateTime > 0.05 then
self.newValue = self.deltaLerp(self.fromCopper, self.toCopper, 0.2, self.updateTime);
local delta = self.newValue - self.fromCopper;
if delta < 10 and delta > -10 then
self.totalTime = 1;
else
self.fromCopper = self.newValue;
self.updateTime = self.updateTime - 0.05;
local _rawCopper = self.rawCopper;
self:SetAmount(self.fromCopper);
self.rawCopper = _rawCopper;
end
end
end
end
function MoneyDisplayMixin:SetAmountByDelta(addRawCopper, animte)
if animte then
if not self.fromCopper then
self.fromCopper = 0;
end
self.rawCopper = self:GetAmount() + addRawCopper;
self.toCopper = self.rawCopper;
self.updateTime = 0;
self.totalTime = 0;
local copper = self.toCopper % 10000;
self.showCopperDuringAnimation = floor(copper) > 0;
self:SetScript("OnUpdate", self.OnUpdate_AnimateValue);
else
self.fromCopper = self:GetAmount() + addRawCopper;
self.showCopperDuringAnimation = nil;
self:SetAmount(self.fromCopper);
end
end
function MoneyDisplayMixin:SetGoldAmount(coinIndex, amount)
if self.colorblindMode then
self["Amount"..coinIndex]:SetText(amount..self.goldSymbol);
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..self.silverSymbol);
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..self.copperSymbol);
self["Symbol"..coinIndex]:Hide();
else
self["Amount"..coinIndex]:SetText(amount);
self:SetTextureCopper(self["Symbol"..coinIndex]);
end
end
function MoneyDisplayMixin:OnShow()
self.colorblindMode = GetCVarBool("colorblindMode");
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);
f.goldSymbol = GOLD_AMOUNT_SYMBOL or "g";
f.silverSymbol = SILVER_AMOUNT_SYMBOL or "s";
f.copperSymbol = COPPER_AMOUNT_SYMBOL or "c";
f.valueSymbolGap = 2;
f.deltaLerp = API.DeltaLerp;
f:SetScript("OnShow", f.OnShow);
f:OnShow();
return f
end
addon.CreateMoneyDisplay = CreateMoneyDisplay;
local TokenDisplayMixin = {};
local ITEM_COUNT_HANDLED_ALIENT;
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 CheckOtherItemAddOns()
ITEM_COUNT_HANDLED_ALIENT = false;
local addons = {
"Syndicator", "Bagnon",
"ElvUI", "NDui",
};
local IsAddOnLoaded = C_AddOns.IsAddOnLoaded;
for _, name in ipairs(addons) do
if IsAddOnLoaded(name) then
ITEM_COUNT_HANDLED_ALIENT = true;
return
end
end
end
local function AppendItemCount(tooltip, itemID, questionableData)
if ITEM_COUNT_HANDLED_ALIENT == nil then
CheckOtherItemAddOns();
end
if ITEM_COUNT_HANDLED_ALIENT then
return
end
local inBag = GetItemCount(itemID);
local total = GetItemCount(itemID, true, false, true, 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);
if questionableData and total > 0 then
tooltip:AddLine(L["Questionable Item Count Tooltip"], 0.5, 0.5, 0.5, true);
end
tooltip:Show();
return true
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.item then
if self.merchantSlot and self.metchantCostIndex then
GameTooltip:SetMerchantCostItem(self.merchantSlot, self.metchantCostIndex)
elseif self.link or type(self.item) == "string" then
GameTooltip:SetHyperlink(self.link or self.item);
else
GameTooltip:SetItemByID(self.item);
end
if not AppendItemCount(GameTooltip, self.item, self.questionableData) then
GameTooltip:Show();
end
self.UpdateTooltip = function()
TokenButton_OnEnter(self)
end
else
GameTooltip:Hide();
end
end
local function TokenButton_OnLeave(self)
self.UpdateTooltip = nil;
GameTooltip:Hide();
end
local function TokenButton_OnClick(self)
if (not self.owner.clickable) or InCombatLockdown() then return end;
if IsModifiedClick("CHATLINK") then
local link;
if self.tokenType == 0 and self.currencyID then
link = C_CurrencyInfo.GetCurrencyLink(self.currencyID);
elseif self.tokenType == 1 and self.item then
local _;
_, link = C_Item.GetItemInfo(self.item);
end
local linkedToChat = link and HandleModifiedItemClick(link);
if linkedToChat then
return
end
end
if self.tokenType == 0 and self.currencyID then
API.ToggleBlizzardTokenUIIfWarbandCurrency(self.currencyID);
--[[ --Taint!!
C_Timer.After(0, function()
if not InCombatLockdown() then
local function FindSelectedTokenButton(elementData)
return elementData.currencyID == self.currencyID;
end
TokenFrame.ScrollBox:ScrollToElementDataByPredicate(FindSelectedTokenButton);
end
end);
--]]
end
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 link = currencyData[5];
local quantity;
local grayColor = false; --0.6 NumberFontNormalRightGray
tokenButton.tokenType = tokenType;
tokenButton.link = link;
tokenButton.merchantSlot = currencyData[6];
tokenButton.metchantCostIndex = currencyData[7];
tokenButton.questionableData = nil;
if tokenType == TOKEN_TYPE_CURRENCY then
--Currency
self.anyCurrency = true;
tokenButton.currencyID = id;
tokenButton.item = 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.item = id;
icon = GetItemIconByID(id)
if type(id) == "string" then
--here "id" can be itemlink, but the count may not be accurate
tokenButton.questionableData = true;
end
if self.includeBank then
quantity = GetItemCount(id, true, false, true, true);
else
quantity = GetItemCount(id);
end
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("Button", nil, self);
button.owner = 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);
button:SetScript("OnClick", TokenButton_OnClick);
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, frameStrata)
--local b = owner:GetBottom();
--local r = owner:GetRight();
offsetX = offsetX or 0;
offsetY = offsetY or 0;
self:ClearAllPoints();
self:SetFrameStrata(frameStrata or "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:DisplayMerchantPriceOnFrame(tokens, owner, offsetX, offsetY, merchantSlotIndexList)
local position = "BOTTOMRIGHT";
local fullyLoaded = true;
if merchantSlotIndexList then
--We use C_Tooltip.GetMerchantCostItem to get the real itemlink b/c GetMerchantItemCostItem only returns the basic itemlink
local GetMerchantCostItem = C_TooltipInfo.GetMerchantCostItem;
local numCost, slot;
local uniqueLinks = {};
for _, v in ipairs(merchantSlotIndexList) do
slot, numCost = v[1], v[2];
if numCost > 0 then
for costIndex = 1, numCost do
local info = GetMerchantCostItem(slot, costIndex);
local itemLevel = 0;
if info and info.hyperlink then
for _, line in ipairs(info.lines) do
if line.itemLevel then
itemLevel = line.itemLevel;
break
end
end
uniqueLinks[info.hyperlink] = itemLevel;
else
fullyLoaded = false;
end
end
end
end
local linkList = {};
for link, itemLevel in pairs(uniqueLinks) do
tinsert(linkList, {link, itemLevel});
end
table.sort(linkList, function(a, b)
--Sort by itemLevel then link
if a[2] ~= b[2] and a[2] > 0 and b[2] > 0 then
return a[2] < b[2]
end
return a[1] < b[1]
end);
tokens = {};
local match = string.match;
local currencyType;
local id;
for i, v in ipairs(linkList) do
local hyperlink = v[1];
id = match(hyperlink, "currency:(%d+)");
if id then
currencyType = 0;
id = tonumber(id);
tokens[i] = {currencyType, id, nil, nil, hyperlink};
else --item
currencyType = 1;
tokens[i] = {currencyType, hyperlink, nil, nil, hyperlink};
end
end
end
self:DisplayCurrencyOnFrame(tokens, owner, position, offsetX, offsetY);
return fullyLoaded
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);
self:RequestUpdate();
end
function TokenDisplayMixin:SetIncludeBank(includeBank)
self.includeBank = includeBank == true;
end
function TokenDisplayMixin:SetButtonClickable(state)
--Click to open WoW's TokenFrame
self.clickable = state;
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;
PriceDisplayMixin.SetIncludeBank = TokenDisplayMixin.SetIncludeBank;
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";
f:SetIncludeBank(true);
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);
elseif index == 3 then
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
else
self.Icon:SetVertexColor(1, 1, 1);
end
end
function PeudoActionButtonMixin:SetItem(item, icon)
icon = icon or 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:SetSpell(spell, icon)
if not icon then
icon = C_Spell.GetSpellTexture(spell);
end
self:SetIcon(icon);
self.id = spell;
self.actionType = "spell";
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 chargeInfo = GetSpellCharges(self.id);
local currentCharges = chargeInfo and chargeInfo.currentCharges;
if currentCharges then
count = currentCharges;
self.Count:SetText(count);
else
count = 1;
self.Count:SetText("");
end
end
if count > 0 then
self:SetIconState(1);
else
if self.actionType == "item" then
self:SetIconState(2);
else
self:SetIconState(3);
end
end
self.charges = count;
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
function PeudoActionButtonMixin:UseHighContrast(state)
if state then
self.NormalTexture:SetSize(128, 128);
self.NormalTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Border-HC");
self.PushedTexture:SetSize(128, 128);
self.PushedTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Highlight-Full-HC");
else
self.NormalTexture:SetSize(64, 64);
self.NormalTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Border");
self.PushedTexture:SetSize(64, 64);
self.PushedTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/ActionButtonCircle-Highlight-Full");
end
end
function PeudoActionButtonMixin:HideCooldownNumber(state)
self.Cooldown:SetHideCountdownNumbers(state);
--TO-DO --For OmniCC: https://github.com/tullamods/OmniCC/blob/f4cb9745a077920b12fca43d2bb74e7fc1141fab/OmniCC/core/cooldown.lua#L408
end
local function CreatePeudoActionButton(parent)
local button = CreateFrame("Button", nil, parent, "PlumberPeudoActionButtonTemplate");
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:SetUseRadialEdge(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
function SecureButtonMixin:CoverObject(object, padding)
padding = padding or 0;
self:ClearAllPoints();
self:SetPoint("TOPLEFT", object, "TOPLEFT", -padding, padding);
self:SetPoint("BOTTOMRIGHT", object, "BOTTOMRIGHT", padding, -padding);
end
function SecureButtonMixin:CoverParent(padding)
local parent = self:GetParent();
if parent then
self:CoverObject(parent, padding);
end
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");
if GetCVarBool("ActionButtonUseKeyDown") then
button:RegisterForClicks("LeftButtonDown", "RightButtonDown");
else
button:RegisterForClicks("LeftButtonUp", "RightButtonUp");
end
return button
end
addon.AcquireSecureActionButton = AcquireSecureActionButton;
local function HideSecureActionButton(privateKey)
if InCombatLockdown() then return end;
if privateKey then
local button = PrivateSecureButtons[privateKey];
if button then
button:Release();
end
end
end
addon.HideSecureActionButton = HideSecureActionButton;
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:SetUseRadialEdge(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 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, true);
end
end
end
function SliderScripts:OnMouseDown()
if self:IsEnabled() then
self:LockHighlight();
self:GetParent().isDraggingThumb = true;
if self.onMouseDownFunc then
self.onMouseDownFunc(self);
end
else
self:GetParent().isDraggingThumb = false;
end
end
function SliderScripts:OnMouseUp()
self:UnlockHighlight();
self:GetParent().isDraggingThumb = false;
if self.onMouseUpFunc then
self.onMouseUpFunc(self);
end
end
local ValueFormatter = {};
function ValueFormatter.NoChange(value)
return value
end
function ValueFormatter.Percentage(value)
return string.format("%.0f%%", value * 100);
end
function ValueFormatter.Decimal0(value)
return string.format("%.0f", value);
end
function ValueFormatter.Decimal1(value)
return string.format("%.1f", value);
end
function ValueFormatter.Decimal2(value)
return string.format("%.2f", value);
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);
self:SetLabelWidth(144);
local function OnEnter()
self:OnEnter();
end
local function OnLeave()
self:OnLeave();
end
self:SetScript("OnEnter", OnEnter);
self:SetScript("OnLeave", OnLeave);
self.Back:SetScript("OnEnter", OnEnter);
self.Back:SetScript("OnLeave", OnLeave);
self.Forward:SetScript("OnEnter", OnEnter);
self.Forward:SetScript("OnLeave", OnLeave);
self.Slider:SetScript("OnEnter", OnEnter);
self.Slider:SetScript("OnLeave", OnLeave);
self:SetFormatValueFunc(nil);
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)
if not formatValueFunc then
formatValueFunc = ValueFormatter.NoChange;
end
self.Slider.formatValueFunc = formatValueFunc;
self.RightText:SetText(formatValueFunc(self:GetValue() or 0));
end
function SliderFrameMixin:SetFormatValueMethod(method)
self:SetFormatValueFunc(ValueFormatter[method]);
end
function SliderFrameMixin:SetOnValueChangedFunc(onValueChangedFunc)
self.Slider.onValueChangedFunc = onValueChangedFunc;
self.onValueChangedFunc = onValueChangedFunc;
end
function SliderFrameMixin:SetOnMouseDownFunc(onMouseDownFunc)
self.Slider.onMouseDownFunc = onMouseDownFunc;
end
function SliderFrameMixin:SetOnMouseUpFunc(onMouseUpFunc)
self.Slider.onMouseUpFunc = onMouseUpFunc;
end
function SliderFrameMixin:SetLabelWidth(width)
self.Label:SetWidth(width);
self:SetWidth(242 + width);
self.Slider:SetPoint("LEFT", self, "LEFT", 28 + width, 0);
end
function SliderFrameMixin:OnEnter()
if self.tooltip then
local f = GameTooltip;
f:Hide();
f:SetOwner(self, "ANCHOR_RIGHT");
f:SetText(self.Label:GetText(), 1, 1, 1, true);
f:AddLine(self.tooltip, 1, 0.82, 0, true);
if self.tooltip2 then
local tooltip2;
if type(self.tooltip2) == "function" then
tooltip2 = self.tooltip2();
else
tooltip2 = self.tooltip2;
end
if tooltip2 then
f:AddLine(" ", 1, 0.82, 0, true);
f:AddLine(tooltip2, 1, 0.82, 0, true);
end
end
f:Show();
end
if self.onEnterFunc then
self.onEnterFunc(self);
end
end
function SliderFrameMixin:OnLeave()
GameTooltip:Hide();
if self.onLeaveFunc and not self.isDraggingThumb then
self.onLeaveFunc(self);
end
end
function SliderFrameMixin:IsDraggingThumb()
return self.isDraggingThumb
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:OnLoad();
return f
end
addon.CreateSlider = CreateSlider;
end
do --UIPanelButton
local UIPanelButtonMixin = {};
function UIPanelButtonMixin:OnClick(button)
end
function UIPanelButtonMixin:SetButtonState(stateIndex)
--1 Normal 2 Pushed 3 Disabled
if stateIndex == 1 then
self.Background:SetTexCoord(0/512, 128/512, 0, 0.125);
elseif stateIndex == 2 then
self.Background:SetTexCoord(132/512, 260/512, 0, 0.125);
elseif stateIndex == 3 then
self.Background:SetTexCoord(264/512, 392/512, 0, 0.125);
end
end
function UIPanelButtonMixin:OnMouseDown(button)
if self:IsEnabled() then
self:SetButtonState(2);
end
end
function UIPanelButtonMixin:OnMouseUp(button)
if self:IsEnabled() then
self:SetButtonState(1);
end
end
function UIPanelButtonMixin:OnDisable()
self:SetButtonState(3);
end
function UIPanelButtonMixin:OnEnable()
self:SetButtonState(1);
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");
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");
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.Highlight:SetTexCoord(396/512, 1, 0, 0.125);
f:SetNormalFontObject("GameFontNormal");
f:SetHighlightFontObject("GameFontHighlight");
f:SetDisabledFontObject("GameFontDisable");
f:SetPushedTextOffset(0, -1);
f:SetButtonState(1);
return f
end
addon.CreateUIPanelButton = CreateUIPanelButton;
end
do --KeybindButton
local KeybindListener = CreateFrame("Frame");
function KeybindListener:SetOwner(keybindButton)
if keybindButton:IsVisible() then
self:OnHide();
self:SetParent(keybindButton);
self.owner = keybindButton;
self:SetScript("OnKeyDown", self.OnKeyDown);
self:Show();
end
end
function KeybindListener:OnHide()
self:Hide();
self:SetScript("OnKeyDown", nil);
if self.owner then
self.owner:ListenKey(false);
self.owner = nil;
end
end
KeybindListener:SetScript("OnHide", KeybindListener.OnHide);
KeybindListener.invalidKeys = {
ESCAPE = true,
UNKNOWN = true,
PRINTSCREEN = true,
};
function KeybindListener:OnKeyDown(key, down)
if self.invalidKeys[key] then
self:Hide();
return
end
if self.owner then
self.owner:SetKeyText(key);
if self.owner.dbKey then
addon.SetDBValue(self.owner.dbKey, key, true);
end
end
self:Hide();
end
local KeybindButtonMixin = {};
function KeybindButtonMixin:OnClick(button)
if button == "LeftButton" then
self.isActive = not self.isActive;
self:ListenKey(self.isActive);
else
self:ListenKey(false);
end
end
function KeybindButtonMixin:ListenKey(state)
self.isActive = state;
if state then
self:SetButtonState(3);
KeybindListener:SetOwner(self);
else
self:SetButtonState(1);
if KeybindListener.owner == self then
KeybindListener:Hide();
end
end
end
function KeybindButtonMixin:SetButtonState(stateIndex)
--1 Normal 2 Pushed 3 Activated
if stateIndex == 1 then
self.Background:SetTexCoord(0/512, 128/512, 68/512, 132/512);
self.Highlight:SetTexCoord(396/512, 1, 68/512, 132/512);
self:UnlockHighlight();
self.Highlight:SetVertexColor(0.5, 0.5, 0.5);
elseif stateIndex == 2 then
self.Background:SetTexCoord(132/512, 260/512, 68/512, 132/512);
self.Highlight:SetTexCoord(396/512, 1, 68/512, 132/512);
self:UnlockHighlight();
self.Highlight:SetVertexColor(0.5, 0.5, 0.5);
elseif stateIndex == 3 then
self.Background:SetTexCoord(0/512, 128/512, 68/512, 132/512);
self.Highlight:SetTexCoord(270/512, 386/512, 68/512, 132/512);
self.Highlight:SetVertexColor(0.8, 0.8, 0.8);
self:LockHighlight();
end
end
function KeybindButtonMixin:OnMouseDown(button)
self:SetButtonState(2);
end
function KeybindButtonMixin:OnMouseUp(button)
self:SetButtonState(1);
end
function KeybindButtonMixin:OnDisable()
end
function KeybindButtonMixin:OnEnable()
end
function KeybindButtonMixin:OnEnter()
if self.tooltip then
local f = GameTooltip;
f:Hide();
f:SetOwner(self, "ANCHOR_RIGHT");
f:SetText(self.Label:GetText(), 1, 1, 1, true);
f:AddLine(self.tooltip, 1, 0.82, 0, true);
f:Show();
end
end
function KeybindButtonMixin:OnLeave()
GameTooltip:Hide();
end
function KeybindButtonMixin:SetLabel(text)
self.Label:SetText(text);
self.effectiveWidth = self:GetWidth() + 20 + self.Label:GetWrappedWidth();
end
function KeybindButtonMixin:SetKeyText(text)
if text and type(text) == "string" then
self:SetText(text);
else
text = NOT_BOUND or "Not Bound";
self:SetText("|cff808080"..text.."|r");
end
end
local function CreateKeybindButton(parent)
local f = CreateFrame("Button", nil, parent);
f:SetSize(144, 24);
Mixin(f, KeybindButtonMixin);
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:SetScript("OnClick", f.OnClick);
f.Background = f:CreateTexture(nil, "BACKGROUND");
f.Background:SetTexture("Interface/AddOns/Plumber/Art/Button/UIPanelButton");
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");
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.Highlight:SetTexCoord(396/512, 1, 68/512, 132/512);
f:SetNormalFontObject("GameFontHighlight");
f:SetHighlightFontObject("GameFontHighlight");
f:SetDisabledFontObject("GameFontDisable");
f:SetPushedTextOffset(0, -1);
f.Label = f:CreateFontString(nil, "OVERLAY", "GameFontNormal");
f.Label:SetJustifyH("RIGHT");
f.Label:SetJustifyV("MIDDLE");
f.Label:SetTextColor(1, 0.82, 0);
f.Label:SetPoint("RIGHT", f, "LEFT", -20, 0);
f.Label:SetWidth(144);
f.effectiveWidth = 288;
f.align = "center";
f:SetButtonState(1);
return f
end
addon.CreateKeybindButton = CreateKeybindButton;
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);
if self.parent.ExitEditMode and not API.IsInEditMode() then
self.parent:ExitEditMode();
end
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 = 432;
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 ipairs(self.activeWidgets) do
if widget.isCustomWidget then
widget:Hide();
widget:ClearAllPoints();
end
end
self.activeWidgets = {};
self.checkboxPool:ReleaseAll();
self.sliderPool:ReleaseAll();
self.uiPanelButtonPool:ReleaseAll();
self.texturePool:ReleaseAll();
self.fontStringPool:ReleaseAll();
self.keybindButtonPool:ReleaseAll();
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;
local preOffset, postOffset;
for order, widget in ipairs(self.activeWidgets) do
if widget.isGap then
height = height + 8 + OPTION_GAP_Y;
else
if widget.widgetType == "Divider" then
preOffset = 2;
postOffset = 2;
elseif widget.widgetType == "Custom" then
preOffset = 0;
postOffset = 2;
else
preOffset = 0;
postOffset = 0;
end
height = height + preOffset;
widget:ClearAllPoints();
if widget.align and widget.align ~= "left" then
if widget.align == "center" then
if widget.effectiveWidth then
widget:SetPoint("TOPRIGHT", self, "TOPRIGHT", -0.5*(contentWidth - widget.effectiveWidth) - leftPadding, -height);
else
widget:SetPoint("TOP", self, "TOP", 0, -height);
end
else
widget:SetPoint("TOPRIGHT", self, "TOPRIGHT", -leftPadding, -height);
end
else
widget:SetPoint("TOPLEFT", self, "TOPLEFT", leftPadding, -height);
end
widgetHeight = Round(widget:GetHeight());
height = height + widgetHeight + OPTION_GAP_Y + postOffset;
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
widget = self.checkboxPool:Acquire();
elseif type == "Slider" then
widget = self.sliderPool:Acquire();
elseif type == "UIPanelButton" then
widget = self.uiPanelButtonPool:Acquire();
elseif type == "Texture" then
widget = self.texturePool:Acquire();
widget.matchParentWidth = nil;
elseif type == "FontString" then
widget = self.fontStringPool:Acquire();
widget.matchParentWidth = true;
elseif type == "Keybind" then
widget = self.keybindButtonPool:Acquire();
end
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(addon.GetDBValue(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
if widgetData.formatValueFunc then
slider:SetFormatValueFunc(widgetData.formatValueFunc);
elseif widgetData.formatValueMethod then
slider:SetFormatValueMethod(widgetData.formatValueMethod);
else
slider:SetFormatValueFunc(nil);
end
slider:SetOnValueChangedFunc(widgetData.onValueChangedFunc);
slider:SetOnMouseDownFunc(widgetData.onMouseDownFunc);
slider:SetOnMouseUpFunc(widgetData.onMouseUpFunc);
slider.tooltip = widgetData.tooltip;
slider.onEnterFunc = widgetData.onEnterFunc;
slider.onLeaveFunc = widgetData.onLeaveFunc;
slider.isDraggingThumb = false;
if widgetData.dbKey and addon.GetDBValue(widgetData.dbKey) then
slider:SetValue(addon.GetDBValue(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.matchParentWidth = true;
DisableSharpening(texture);
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:CreateKeybindButton(widgetData)
local button = self:AcquireWidgetByType("Keybind");
button.dbKey = widgetData.dbKey;
button.tooltip = widgetData.tooltip;
button:SetKeyText(addon.GetDBValue(widgetData.dbKey));
button:SetLabel(widgetData.label);
return button
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 (not widgetData.validityCheckFunc) or (widgetData.validityCheckFunc()) then
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);
elseif widgetData.type == "Keybind" then
widget = self:CreateKeybindButton(widgetData);
elseif widgetData.type == "Custom" then
widget = widgetData.onAcquire();
if widget then
widget:SetParent(self);
widget:ClearAllPoints();
widget:Show();
widget.isCustomWidget = true;
widget.align = widgetData.align or "center";
end
end
if widget then
tinsert(self.activeWidgets, widget);
widget.widgetKey = widgetData.widgetKey;
widget.widgetType = widgetData.type;
end
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();
self:ConvertAnchor();
end
function EditModeSettingsDialogMixin:ConvertAnchor()
--Convert any anchor to the top left
--so that changing frame height don't affect the positions of most buttons
local left = self:GetLeft();
local top = self:GetTop();
self:ClearAllPoints();
self:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left, top);
end
function EditModeSettingsDialogMixin:SetTitle(title)
self.Title:SetText(title);
end
function EditModeSettingsDialogMixin:IsOwner(parent)
return parent == self.parent
end
function EditModeSettingsDialogMixin:IsFromSchematic(schematic)
return schematic and self.schematic == schematic;
end
function EditModeSettingsDialogMixin:HideOption(parent)
if (not parent) or self:IsOwner(parent) then
self:Hide();
end
end
local function SetupSettingsDialog(parent, schematic, forceUpdate)
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.activeWidgets = {};
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);
local function CreateCheckbox()
return addon.CreateCheckbox(f);
end
f.checkboxPool = API.CreateObjectPool(CreateCheckbox);
local function CreateSlider()
return addon.CreateSlider(f);
end
f.sliderPool = API.CreateObjectPool(CreateSlider);
local function CreateUIPanelButton()
return addon.CreateUIPanelButton(f);
end
f.uiPanelButtonPool = API.CreateObjectPool(CreateUIPanelButton);
local function CreateTexture()
return f:CreateTexture(nil, "OVERLAY");
end
f.texturePool = API.CreateObjectPool(CreateTexture);
local function CreateFontString()
return f:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
end
f.fontStringPool = API.CreateObjectPool(CreateFontString);
local function CreateKeybindButton()
return addon.CreateKeybindButton(f);
end
f.keybindButtonPool = API.CreateObjectPool(CreateKeybindButton);
end
if EditModeSettingsDialog:IsShown() and not EditModeSettingsDialog:IsOwner(parent) then
EditModeSettingsDialog:Exit();
end
if (schematic ~= EditModeSettingsDialog.schematic) then
EditModeSettingsDialog.requireResetPosition = true;
EditModeSettingsDialog.schematic = schematic;
EditModeSettingsDialog:ClearAllPoints();
EditModeSettingsDialog:SetupOptions(schematic);
elseif forceUpdate then
EditModeSettingsDialog.schematic = schematic;
EditModeSettingsDialog:SetupOptions(schematic);
end
EditModeSettingsDialog.parent = parent;
return EditModeSettingsDialog
end
addon.SetupSettingsDialog = SetupSettingsDialog;
local function ToggleSettingsDialog(parent, schematic, forceUpdate)
if EditModeSettingsDialog and EditModeSettingsDialog:IsShown() and EditModeSettingsDialog:IsOwner(parent) then
EditModeSettingsDialog:Exit();
else
local f = SetupSettingsDialog(parent, schematic, forceUpdate);
if f then
f:Show();
f:ClearAllPoints();
f:SetPoint("LEFT", UIParent, "CENTER", 256, 0);
return f
end
end
end
addon.ToggleSettingsDialog = ToggleSettingsDialog;
end
do --Radial Progress Bar
local RadialProgressBarMixin = {};
function RadialProgressBarMixin:SetPercentage(percentage)
local seconds = 100;
if percentage >= 1 then
percentage = 1;
elseif percentage <= 0 then
percentage = 0;
else
percentage = self.visualOffset * (1- percentage) + (1 - self.visualOffset) * percentage; --Additional shrinking due to level background --Remap 0-100 to 7-93
end
self:Pause();
self:SetCooldown(GetTime() - (seconds * percentage), seconds);
self:SetDrawEdge(percentage > 0);
end
function RadialProgressBarMixin:SetValue(currentValue, maxValue)
if not currentValue or not maxValue or maxValue == 0 then
currentValue = 0;
maxValue = 1;
end
self:SetPercentage(currentValue / maxValue);
end
function RadialProgressBarMixin:ShowNumber(showNumber)
if showNumber then
if self.showNumber ~= true then
self.showNumber = true;
self.ValueText:Show();
self.visualOffset = 0.07;
self.Border:SetTexCoord(0, 80/256, 80/256, 160/256);
self.BorderHighlight:SetTexCoord(0, 80/256, 80/256, 160/256);
local lowTexCoords =
{
x = 80/256,
y = 80/256,
};
local highTexCoords =
{
x = 160/256,
y = 160/256,
};
self:SetTexCoordRange(lowTexCoords, highTexCoords);
end
else
if self.showNumber ~= false then
self.showNumber = false;
self.ValueText:Hide();
self.visualOffset = 0.01;
self.Border:SetTexCoord(0, 80/256, 0/256, 80/256);
self.BorderHighlight:SetTexCoord(0, 80/256, 0/256, 80/256);
local lowTexCoords =
{
x = 80/256,
y = 0/256,
};
local highTexCoords =
{
x = 160/256,
y = 80/256,
};
self:SetTexCoordRange(lowTexCoords, highTexCoords);
end
end
end
local function CreateRadialProgressBar(parent)
local f = CreateFrame("Cooldown", nil, parent, "PlumberRadialProgressBarTemplate");
Mixin(f, RadialProgressBarMixin);
local tex = "Interface/AddOns/Plumber/Art/Frame/ProgressBar-Radial-WarWithin";
f.Border:SetTexture(tex);
f.BorderHighlight:SetTexture(tex);
f:SetSwipeTexture(tex);
f.ValueText = f:CreateFontString("OVERLAY", nil, "GameFontNormalLargeOutline");
f.ValueText:SetJustifyH("CENTER");
f.ValueText:SetPoint("CENTER", f, "BOTTOM", 2, 14);
f.ValueText:SetTextColor(1, 0.82, 0);
f:ShowNumber(true);
f.noCooldownCount = true;
return f
end
addon.CreateRadialProgressBar = CreateRadialProgressBar;
addon.RadialProgressBarMixin = RadialProgressBarMixin;
end
do --Progress Bar With Level
local LevelProgressBarMixin = {};
local FILL_TEXTURE_LEFT = 26;
local FILL_TEXTURE_RIGHT = 262;
local FILL_TEXTURE_FULLWIDTH = 288;
function LevelProgressBarMixin:SetSizeScale(scale)
self.sizeScale = scale;
local hexSize = 96;
local hexOffset = -16;
local barBGWidth, barBGHeight = 288, 96;
local barFillHeight = 32;
local effectiveHeight = 64;
local effectiveWidth, barOffsetX, barOffsetY;
self.Label:ClearAllPoints();
if self.showLevel then
effectiveWidth = 300;
barOffsetX = 26;
barOffsetY = 8;
self.Label:SetPoint("BOTTOMLEFT", self.BarBackground, "LEFT", 36 * scale, 8 * scale);
self.Label:SetJustifyH("LEFT");
else
effectiveWidth = 248;
barOffsetX = 0;
barOffsetY = 0;
self.Label:SetPoint("BOTTOM", self.BarBackground, "CENTER", 0, 8 * scale);
self.Label:SetJustifyH("CENTER");
end
self:SetSize(effectiveWidth*scale, effectiveHeight*scale);
self.BarBackground:ClearAllPoints();
self.BarBackground:SetPoint("CENTER", self, "CENTER", barOffsetX * scale, barOffsetY * scale);
self.BarBackground:SetSize(barBGWidth * scale, barBGHeight * scale);
self.BarFill:ClearAllPoints();
self.BarFill:SetPoint("LEFT", self.BarBackground, "LEFT", 0, -16 * scale);
self.BarFill:SetHeight(barFillHeight * scale);
self.MouseoverFrame.ValueText:SetPoint("CENTER", self.BarBackground, "CENTER", 0, -16 * scale);
self.BarSurface:ClearAllPoints();
self.BarSurface:SetPoint("RIGHT", self.BarFill, "RIGHT", 8 * scale, 0);
self.BarSurface:SetSize(48 * scale, 32 * scale);
self.LevelBackground:ClearAllPoints();
self.LevelBackground:SetPoint("LEFT", self, "LEFT", hexOffset * scale, 0);
self.LevelBackground:SetSize(hexSize * scale, hexSize * scale);
self.MaxLevelIcon:SetSize(48 * scale, 48 * scale);
self.MouseoverArea:SetSize(248 * scale, 32 * scale);
self.MouseoverArea:SetPoint("CENTER", self.BarBackground, "CENTER", 0, -16 * scale);
self.BarSurfaceMask:SetWidth(236 * scale);
self.DeltaValueFrame:ClearAllPoints();
self.DeltaValueFrame:SetPoint("BOTTOMLEFT", self.BarBackground, "RIGHT", -60, 8);
self:SetValue(self.value or 0);
end
function LevelProgressBarMixin:SetLabel(label)
self.Label:SetText(label);
end
function LevelProgressBarMixin:ShowLevel(state)
state = state == true or state == nil;
self.showLevel = state;
self.LevelText:SetShown(state);
self.LevelBackground:SetShown(state);
if self.sizeScale then
self:SetSizeScale(self.sizeScale);
end
end
function LevelProgressBarMixin:SetLevel(level, reachMaxLevel)
self.level = level;
if reachMaxLevel then
self.LevelText:Hide();
self.MaxLevelIcon:Show();
else
self.LevelText:SetText(level);
self.LevelText:Show();
self.MaxLevelIcon:Hide();
end
end
function LevelProgressBarMixin:SetVisualByRatio(ratio)
if ratio > 1 then
ratio = 1;
end
self.visualRatio = ratio;
local textureWidth = FILL_TEXTURE_LEFT + (FILL_TEXTURE_RIGHT - FILL_TEXTURE_LEFT) * ratio;
self.BarFill:SetWidth(textureWidth * self.sizeScale);
self.BarFill:SetTexCoord(0, textureWidth / 512, 0.1875, 0.25);
end
local FILL_RATIO_PER_SEC = 0.25; --50%/sec
local EasingFunc = addon.EasingFunctions.outSine;
local function CalculateEaseDuration(deltaRatio)
if deltaRatio < 0 then
deltaRatio = -deltaRatio;
end
if deltaRatio < 0.02 then
return 0
else
local t = deltaRatio / FILL_RATIO_PER_SEC;
if t < 0.5 then
t = 0.5;
elseif t > 2 then
t = 2;
end
return t
end
end
local function AnimFill_Plus_SameLevel(self, elapsed)
self.t = self.t + elapsed;
local ratio = EasingFunc(self.t, self.fromRatio, self.toRatio, self.easeDuration);
if self.t >= self.easeDuration then
self:ClearAnimation();
return
end
self:SetVisualByRatio(ratio);
end
local function AnimFill_Plus_LevelUp(self, elapsed)
local ratio = self.fromRatio + 2*FILL_RATIO_PER_SEC * elapsed;
self.fromRatio = ratio;
if ratio >= 1 then
ratio = 1;
self.t = 0;
self.fromRatio = 0;
self.easeDuration = CalculateEaseDuration(self.toRatio - self.fromRatio);
if self.easeDuration > 0 then
self:SetScript("OnUpdate", AnimFill_Plus_SameLevel);
else
self:ClearAnimation();
end
else
self:SetVisualByRatio(ratio);
end
end
function LevelProgressBarMixin:ClearAnimation()
if self.toRatio then
self:SetScript("OnUpdate", nil);
self:SetVisualByRatio(self.toRatio);
self.t = nil;
self.easeDuration = nil;
self.fromRatio = nil;
self.toRatio = nil;
end
if self:IsShown() and self.StartFadeOutCountdown and self.autoFadeOut and not self.MouseoverArea:IsMouseMotionFocus() then
self:StartFadeOutCountdown();
end
end
function LevelProgressBarMixin:SetValue(value, levelUp)
self.value = value;
local ratio = value / self.maxValue;
self.MouseoverFrame.ValueText:SetText(value.." / "..self.maxValue);
if self.useAnimation and self:IsVisible() then
self.t = 0;
self.fromRatio = self.visualRatio or 0;
self.toRatio = ratio;
if levelUp then
self:SetScript("OnUpdate", AnimFill_Plus_LevelUp);
return
else
self.easeDuration = CalculateEaseDuration(self.toRatio - self.fromRatio);
if self.easeDuration > 0 then
self:SetScript("OnUpdate", AnimFill_Plus_SameLevel);
return
end
end
end
self:ClearAnimation();
self:SetVisualByRatio(ratio);
end
function LevelProgressBarMixin:SetMaxValue(maxValue)
if maxValue <= 0 then
maxValue = 1;
end
self.maxValue = maxValue;
end
function LevelProgressBarMixin:AnimateDeltaValue(deltaValue)
self.DeltaValueFrame.Value:SetText(deltaValue);
self.DeltaValueFrame.AnimText:Stop();
self.DeltaValueFrame.AnimText:Play();
self.DeltaValueFrame:Show();
end
function LevelProgressBarMixin:SetValueByDelta(deltaValue, newMaxValue)
local newValue = (self.value or 0) + deltaValue;
local levelUp = self.maxValue and newValue > self.maxValue;
local value;
if levelUp then
value = newValue - (self.maxValue or 0);
else
value = newValue;
end
if newMaxValue then
self.maxValue = newMaxValue;
end
self:SetValue(value, levelUp);
self:AnimateDeltaValue(deltaValue);
end
function LevelProgressBarMixin:SetBarReachMaxLevel(state)
if state and not self.isMaxed then
self.isMaxed = true;
self:SetLevel(self.level or 0, true);
elseif (not state) and self.isMaxed then
self.isMaxed = false;
self:SetLevel(self.level or 0);
end
end
function LevelProgressBarMixin:SetUseAnimation(state)
self.useAnimation = state;
end
function LevelProgressBarMixin:IsAnimating()
return self.easeDuration ~= nil
end
function LevelProgressBarMixin:SetAutoFadeOut(state)
self.autoFadeOut = state == true;
end
local function CreateLevelProgressBar(parent)
local f = CreateFrame("Frame", nil, parent, "PlumberWoWProgressBarTemplate");
Mixin(f, LevelProgressBarMixin);
f:SetMaxValue(100);
f:ShowLevel(true);
f:SetSizeScale(0.8);
f.BarSurfaceMask:SetTexture("Interface/AddOns/Plumber/Art/BasicShape/Mask-Full", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE", "NEAREST");
f.MouseoverArea:SetScript("OnEnter", function()
f.MouseoverFrame:Show();
if f.onEnterFunc then
f.onEnterFunc(f);
end
end);
f.MouseoverArea:SetScript("OnLeave", function()
f.MouseoverFrame:Hide();
if f.onLeaveFunc then
f.onLeaveFunc(f);
end
end);
f.MouseoverArea:SetScript("OnMouseDown", function()
f.MouseoverFrame:Hide();
f:Hide();
f:ClearAnimation();
end);
return f
end
addon.CreateLevelProgressBar = CreateLevelProgressBar;
end
do --DelayedTooltip
function DelayedTooltip:OnUpdate(elapsed)
self.t = self.t + elapsed;
if self.t > 0.5 then
self.t = 0;
self:SetScript("OnUpdate", nil);
self:ProcessTooltip();
end
end
function DelayedTooltip:ProcessTooltip()
if self.owner and self.owner:IsVisible() and self.owner:IsMouseMotionFocus() then
if self.owner.ShowTooltip then
self.owner.ShowTooltip(self.owner);
end
end
self.owner = nil;
end
function DelayedTooltip:OnObjectEnter(owner)
self.owner = owner;
self.t = 0;
self:SetScript("OnUpdate", self.OnUpdate);
end
function DelayedTooltip:OnObjectLeave(owner)
if self.owner == owner then
self.owner = nil;
end
end
end
do --Displayed required items on nameplate widget set
--The frame itself has events
local NameplateTokenMixin = {};
function NameplateTokenMixin:SetStyle(styleID)
if styleID == self.styleID then return end;
local selfSize, iconSize, borderSize, borderTexture;
local mask = "Interface/AddOns/Plumber/Art/BasicShape/";
self.Count:ClearAllPoints();
self.Border:ClearAllPoints();
if styleID == 2 then
--Circle, Quantity on the bottom-right
selfSize = 32;
iconSize = 30;
borderSize = 64;
borderTexture = "Interface/AddOns/Plumber/Art/Button/SmallCircle-Border";
mask = mask.."Mask-Circle";
self.Icon:SetPoint("CENTER", self, "CENTER", 0, 0);
self.Count:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 2, -2);
self.Border:SetPoint("CENTER", self, "CENTER", 0, 0);
self.dynamicSize = false;
else
--Square, Quantity on the right
selfSize = 20;
iconSize = 16;
borderSize = 32;
borderTexture = "Interface/AddOns/Plumber/Art/Button/SmallSquare-Border";
mask = mask.."Mask-Chamfer";
self.Icon:SetPoint("RIGHT", self, "RIGHT", -2, 0);
self.Count:SetPoint("RIGHT", self.Icon, "LEFT", -3, 0);
self.Border:SetPoint("CENTER", self.Icon, "CENTER", 0, 0);
self.dynamicSize = true;
self.sizeConstant = 20;
end
self:SetSize(selfSize, selfSize);
self.Icon:SetSize(iconSize, iconSize);
self.Border:SetSize(borderSize, borderSize);
self.Border:SetTexture(borderTexture);
self.IconMask:SetTexture(mask, "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE");
end
function NameplateTokenMixin:OnLoad()
self:SetScript("OnEnter", self.OnEnter);
self:SetScript("OnLeave", self.OnLeave);
self:Release();
DisableSharpening(self.Border);
DisableSharpening(self.Icon);
end
function NameplateTokenMixin:SetItem(itemID)
if itemID == self.id then return end;
self.id = itemID;
self.type = "item";
local icon = GetItemIconByID(itemID) or 134400;
self.Icon:SetTexture(icon);
self:UpdateCount();
end
function NameplateTokenMixin:SetCurrency(currencyID)
if currencyID == self.id then return end;
self.id = currencyID;
self.type = "currency";
local info = GetCurrencyInfo(currencyID);
local icon, quantity;
if info then
icon = info.iconFileID;
quantity = info.quantity;
else
icon = 134400;
quantity = 0;
end
self.Icon:SetTexture(icon);
self:UpdateCount(quantity);
end
function NameplateTokenMixin:OnShow()
if self.type == "item" then
self:RegisterEvent("BAG_UPDATE_DELAYED");
elseif self.type == "currency" then
self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
end
if self.requiredWidgetID then
self:RegisterEvent("UPDATE_UI_WIDGET");
end
self:SetScript("OnEvent", self.OnEvent);
end
function NameplateTokenMixin:OnHide()
self:UnregisterEvent("BAG_UPDATE_DELAYED");
self:UnregisterEvent("CURRENCY_DISPLAY_UPDATE");
self:UnregisterEvent("UPDATE_UI_WIDGET");
self:SetScript("OnEvent", nil);
self.t = 0;
end
function NameplateTokenMixin:OnEvent(event, ...)
if event == "BAG_UPDATE_DELAYED" then
self:RequestUpdateCount();
elseif event == "CURRENCY_DISPLAY_UPDATE" then
local currencyID = ...
if currencyID == self.currencyID then
self:RequestUpdateCount();
end
elseif event == "UPDATE_UI_WIDGET" then
local widgetInfo = ...
if widgetInfo.widgetID == self.requiredWidgetID then
self:EvaluateVisibility();
end
end
end
function NameplateTokenMixin:OnUpdate(elapsed)
if self.quantityDirty then
self.t = self.t + elapsed;
if self.t > 0.016 then
self.t = 0;
self:UpdateCount();
end
end
if self.toAlpha then
self.alpha = self.alpha + 5 * elapsed;
if self.alpha > 1 then
self.alpha = 1;
self.toAlpha = nil;
end
self:SetAlpha(self.alpha);
end
if not (self.quantityDirty or self.toAlpha) then
self:SetScript("OnUpdate", nil);
end
end
function NameplateTokenMixin:RequestUpdateCount()
self.t = 0;
self.quantityDirty = true;
self:SetScript("OnUpdate", self.OnUpdate);
end
function NameplateTokenMixin:UpdateCount(quantity)
self.quantityDirty = nil;
if not quantity then
if self.type == "item" then
quantity = GetItemCount(self.id);
elseif self.type == "currency" then
local info = GetCurrencyInfo(self.id);
quantity = info and info.quantity or 0;
end
end
self.Count:SetText(quantity);
if quantity > 0 then
self.Icon:SetVertexColor(1, 1, 1);
self.Count:SetTextColor(1, 1, 1);
else
self.Icon:SetVertexColor(0.4, 0.4, 0.4);
self.Count:SetTextColor(0.5, 0.5, 0.5);
end
if self.dynamicSize then
self:SetWidth(self.Count:GetWidth() + self.sizeConstant);
end
end
function NameplateTokenMixin:FadeIn()
self.toAlpha = true;
self:Show();
self:SetScript("OnUpdate", self.OnUpdate);
end
function NameplateTokenMixin:Release()
self:ClearAllPoints();
self:Hide();
self:SetAlpha(0);
self.id = nil;
self.type = nil;
self.alpha = 0;
self:SetScript("OnUpdate", nil);
end
function NameplateTokenMixin:OnEnter()
NamePlateTooltip:Hide();
DelayedTooltip:OnObjectEnter(self);
end
function NameplateTokenMixin:OnLeave()
NamePlateTooltip:Hide();
DelayedTooltip:OnObjectLeave(self);
end
function NameplateTokenMixin:ShowTooltip()
if not self.visible then return end;
local method;
if self.type == "item" then
method = "SetItemByID";
elseif self.type == "currency" then
method = "GetCurrencyByID";
end
if method then
--Anchor the GameTooltip to nameplate nullify its "clampedToScreen"
--Blizzard_NamePlates use NamePlateTooltip, so we'll do that too.
local tooltip = NamePlateTooltip;
tooltip:SetOwner(self, "ANCHOR_RIGHT");
tooltip[method](tooltip, self.id);
end
end
function NameplateTokenMixin:SetInteractable(state)
state = state or false;
self:EnableMouse(false); --Pass Through Clicks
self:EnableMouseMotion(state);
end
function API.CreateNameplateToken(parent, selfDrivenUpdate)
local f = CreateFrame("Frame", nil, parent, "PlumberSmallItemButtonTemplate");
Mixin(f, NameplateTokenMixin);
f:OnLoad();
f:SetInteractable(true);
if selfDrivenUpdate then
f:SetScript("OnShow", f.OnShow);
f:SetScript("OnHide", f.OnHide);
end
return f
end
end
do --Simple Tooltip (2 FontString)
local SimpleTooltipMixin = {};
function SimpleTooltipMixin:SetText(title, description)
local textHeight, textWidth;
if not (title or description) then
self.Text1:SetText(nil);
self.Text2:SetText(nil);
textHeight = 12;
textWidth = 12;
else
self.Text2:ClearAllPoints();
if description then
self.Text2:SetPoint("TOPLEFT", self.Text1, "BOTTOMLEFT", 0, -self.titleDescGap);
self.Text1:SetText(title);
self.Text2:SetText(description);
textHeight = self.Text1:GetHeight() + self.titleDescGap + self.Text2:GetHeight();
textWidth = math.max(self.Text1:GetWrappedWidth(), self.Text2:GetWrappedWidth());
else
self.Text2:SetPoint("TOPLEFT", self, "TOPLEFT", self.padding, -self.padding);
self.Text1:SetText(nil);
self.Text2:SetText(title);
textHeight = self.Text2:GetHeight();
textWidth = self.Text2:GetWrappedWidth();
end
end
self:SetSize(API.Round(textWidth + 2*self.padding), API.Round(textHeight + 2*self.padding));
end
function SimpleTooltipMixin:SetPadding()
self.padding = 8;
end
function SimpleTooltipMixin:SetTitleDescGap(titleDescGap)
self.titleDescGap = titleDescGap;
end
function SimpleTooltipMixin:SetMaxLineWidth(width)
self.Text1:SetWidth(width);
self.Text2:SetWidth(width);
end
local function CreateSimpleTooltip(parent)
local f = CreateFrame("Frame", nil, parent);
f.padding = 8;
f.titleDescGap = 4;
Mixin(f, SimpleTooltipMixin);
local bg = addon.CreateNineSliceFrame(f, "NineSlice_GenericBox_Black");
bg:SetUsingParentLevel(true);
bg:SetCornerSize(8);
bg:SetAllPoints(true);
f.Text1 = f:CreateFontString(nil, "OVERLAY", "GameTooltipHeaderText");
f.Text1:SetJustifyH("LEFT");
f.Text1:SetJustifyV("TOP");
f.Text1:SetPoint("TOPLEFT", f, "TOPLEFT", f.padding, -f.padding);
f.Text1:SetTextColor(1, 0.82, 0);
f.Text1:SetSpacing(2);
f.Text2 = f:CreateFontString(nil, "OVERLAY", "GameTooltipText");
f.Text2:SetJustifyH("LEFT");
f.Text2:SetJustifyV("TOP");
f.Text2:SetPoint("TOPLEFT", f.Text1, "BOTTOMLEFT", 0, -f.titleDescGap);
f.Text2:SetSpacing(2);
f:SetMaxLineWidth(290);
return f
end
addon.CreateSimpleTooltip = CreateSimpleTooltip;
end
do --SliceFrame
local NewSliceFrameMixin = {};
local LayoutInfo = {
RoughWideFrame = {
file = "Interface/AddOns/Plumber/Art/Frame/MacroForge.png",
imageWidth = 512, imageHeight = 512,
coords = {0, 264, 0, 72},
margins = {8, 8, 8, 8},
pixelOffset = 4,
};
};
function NewSliceFrameMixin:UpdatePixel()
local scale = API.GetPixelForScale(self:GetEffectiveScale());
self.Background:SetScale(scale);
local pixelOffset = self.Background.pixelOffset;
--local scale = self.Background:GetEffectiveScale()
--local offset = API.GetPixelForScale(scale, pixelOffset);
local offset = pixelOffset * scale;
self.Background:ClearAllPoints();
self.Background:SetPoint("TOPLEFT", self, "TOPLEFT", -offset, offset);
self.Background:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", offset, -offset);
end
function NewSliceFrameMixin:SetLayoutByName(layoutName)
local info = LayoutInfo[layoutName];
if info then
self.Background:SetTexture(info.file);
self.Background:SetTexCoord(info.coords[1]/info.imageWidth, info.coords[2]/info.imageWidth, info.coords[3]/info.imageHeight, info.coords[4]/info.imageHeight);
self.Background:SetTextureSliceMargins(unpack(info.margins));
self.Background.pixelOffset = info.pixelOffset or 0;
end
end
function API.CreateNewSliceFrame(parent, layoutName)
local f = CreateFrame("Frame", nil, parent);
f.Background = f:CreateTexture(nil, "BACKGROUND");
f.Background:SetTextureSliceMode(1); --Tiled
API.Mixin(f, NewSliceFrameMixin);
f:SetLayoutByName(layoutName);
f:UpdatePixel();
return f
end
end
do --Small Golden Border Circle, See "MainHelpPlateButton" in Blizzard_SharedXML/SharedUIPanelTemplates
function API.CreateGoldPlateButton(parent, onEnterFunc, onLeaveFunc, onClickFunc)
local f = CreateFrame("Button", nil, parent);
f:SetSize(32, 32);
f.Ring = f:CreateTexture(nil, "BORDER");
f.Ring:SetSize(64, 64);
f.Ring:SetPoint("CENTER", f, "CENTER", 12 ,-13);
f.Ring:SetTexture("Interface/Minimap/MiniMap-TrackingBorder");
f.Icon = f:CreateTexture(nil, "BACKGROUND");
f.Icon:SetSize(23, 23);
f.Icon:SetPoint("CENTER", f, "CENTER", 0, 0);
f.Icon:SetColorTexture(1, 0, 0)
f:SetScript("OnEnter", onEnterFunc);
f:SetScript("OnLeave", onLeaveFunc);
f:SetScript("OnClick", onClickFunc);
return f
end
end
do --Blizzard Check Button
local BlizzardCheckButtonMixin = {};
BlizzardCheckButtonMixin.ButtonMixin = {};
do
function BlizzardCheckButtonMixin.ButtonMixin:OnEnter()
if self.tooltip1 then
local tooltip1, tooltip2;
if type(self.tooltip1 == "function") then
tooltip1, tooltip2 = self.tooltip1();
else
tooltip1 = self.tooltip1;
tooltip2 = self.tooltip2;
end
if tooltip1 then
local GameTooltip = GameTooltip;
GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
GameTooltip:SetText(tooltip1, 1, 1, 1);
if tooltip2 then
GameTooltip:AddLine(tooltip2, 1, 0.82, 0, true);
end
GameTooltip:Show();
end
end
end
function BlizzardCheckButtonMixin.ButtonMixin:OnLeave()
GameTooltip:Hide();
end
function BlizzardCheckButtonMixin.ButtonMixin:OnClick()
local checked = self:GetChecked();
local dbKey = self:GetParent().dbKey;
if dbKey then
addon.SetDBValue(dbKey, checked, true);
end
if self.onCheckedFunc then
self.onCheckedFunc(self, checked);
end
if checked then
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
else
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
end
end
end
function BlizzardCheckButtonMixin:SetLabel(label)
self.Label:SetText(label);
self:Layout();
end
function BlizzardCheckButtonMixin:Layout()
local textWidth = 5 + self.Label:GetWrappedWidth();
self:SetSize(API.Round(32 + textWidth + 6), 32);
self.Button:SetHitRectInsets(0, -textWidth, 0, 0);
end
function BlizzardCheckButtonMixin:SetTooltip(tooltip1, tooltip2)
self.Button.tooltip1 = tooltip1;
self.Button.tooltip2 = tooltip2;
end
function BlizzardCheckButtonMixin:SetChecked(state)
self.Button:SetChecked(state);
end
function BlizzardCheckButtonMixin:GetChecked()
return self.Button:GetChecked();
end
function BlizzardCheckButtonMixin:SetDBKey(dbKey)
self.dbKey = dbKey;
end
function BlizzardCheckButtonMixin:SetOnCheckedFunc(onCheckedFunc)
self.Button.onCheckedFunc = onCheckedFunc;
end
function API.CreateBlizzardCheckButton(parent)
local f = CreateFrame("Frame", nil, parent, "PlumberBlizzardCheckButtonTemplate");
Mixin(f, BlizzardCheckButtonMixin);
Mixin(f.Button, BlizzardCheckButtonMixin.ButtonMixin);
for method, func in pairs(BlizzardCheckButtonMixin.ButtonMixin) do
f.Button:SetScript(method, func);
end
return f
end
end