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.
465 lines
13 KiB
465 lines
13 KiB
|
2 years ago
|
local _, addon = ...
|
||
|
|
local L = addon.L;
|
||
|
|
local API = addon.API;
|
||
|
|
local Lerp = API.Lerp;
|
||
|
|
local Clamp = API.Clamp;
|
||
|
|
local GetPlayerLevelXP = API.GetPlayerLevelXP;
|
||
|
|
local TooltipFrame = addon.SharedTooltip;
|
||
|
|
local inOutSine = addon.EasingFunctions.inOutSine;
|
||
|
|
|
||
|
|
local BreakUpLargeNumbers = BreakUpLargeNumbers;
|
||
|
|
|
||
|
|
|
||
|
|
local FILL_DURATION = 2.0;
|
||
|
|
|
||
|
|
local function AnimFill_OnUpdate(self, elapsed)
|
||
|
|
self.t = self.t + elapsed;
|
||
|
|
local ratio = inOutSine(self.t, self.fromRatio, self.toRatio, FILL_DURATION)
|
||
|
|
|
||
|
|
if self.t >= FILL_DURATION then
|
||
|
|
self.t = 0;
|
||
|
|
self:SetScript("OnUpdate", nil);
|
||
|
|
ratio = self.toRatio;
|
||
|
|
end
|
||
|
|
|
||
|
|
if ratio > 1 then
|
||
|
|
ratio = ratio - 1;
|
||
|
|
self:OnOverflow();
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetBarWidthByPercentage(ratio);
|
||
|
|
end
|
||
|
|
|
||
|
|
local function CrossFade_OnUpdate(self, elapsed)
|
||
|
|
if self.t <= 1.0 then
|
||
|
|
self.alpha = self.alpha + 10*elapsed;
|
||
|
|
if self.alpha > 1 then
|
||
|
|
self.alpha = 1;
|
||
|
|
self.t = self.t + elapsed;
|
||
|
|
end
|
||
|
|
else
|
||
|
|
self.alpha = self.alpha - 1*elapsed;
|
||
|
|
if self.alpha <= 0 then
|
||
|
|
self.alpha = 0;
|
||
|
|
self:SetScript("OnUpdate", nil);
|
||
|
|
self:Hide();
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAlpha(self.alpha);
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
local StatusBarMixin = {};
|
||
|
|
|
||
|
|
function StatusBarMixin:OnLoad()
|
||
|
|
local FILE_PATH = "Interface/AddOns/DialogueUI/Art/Theme_Shared/";
|
||
|
|
|
||
|
|
if not self.Border then
|
||
|
|
self.Border = self:CreateTexture(nil, "OVERLAY", nil, 2);
|
||
|
|
self.Border:SetTextureSliceMode(1);
|
||
|
|
local margin = 6;
|
||
|
|
self.Border:SetTextureSliceMargins(margin, margin, margin, margin);
|
||
|
|
self.Border:SetAllPoints(true);
|
||
|
|
self.Border:SetTexture(FILE_PATH.."StatusBar-Border.png");
|
||
|
|
self:SetBorderColor(0.25, 0.25, 0.25);
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.Background then
|
||
|
|
self.Background = self:CreateTexture(nil, "BACKGROUND");
|
||
|
|
self.Background:SetTextureSliceMode(1);
|
||
|
|
local margin = 6;
|
||
|
|
self.Background:SetTextureSliceMargins(margin, margin, margin, margin);
|
||
|
|
self.Background:SetAllPoints(true);
|
||
|
|
self.Background:SetTexture(FILE_PATH.."StatusBar-Background.png");
|
||
|
|
self.Background:SetAlpha(0.5);
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.Fill then
|
||
|
|
self.Fill = self:CreateTexture(nil, "ARTWORK");
|
||
|
|
self.Fill:SetTextureSliceMode(1);
|
||
|
|
local margin = 6;
|
||
|
|
self.Fill:SetTextureSliceMargins(margin, margin, margin, margin);
|
||
|
|
self.Fill:SetWidth(0.1);
|
||
|
|
self.Fill:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0);
|
||
|
|
self.Fill:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, 0);
|
||
|
|
self.Fill:SetTexture(FILE_PATH.."StatusBar-FillShort-Purple.png");
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.Surface then
|
||
|
|
self.Surface = self:CreateTexture(nil, "ARTWORK", nil, 2);
|
||
|
|
self.Surface:SetHeight(6);
|
||
|
|
self.Surface:SetWidth(48);
|
||
|
|
self.Surface:SetColorTexture(1, 1, 1);
|
||
|
|
self.Surface:SetGradient("HORIZONTAL", CreateColor(1, 0.5, 1, 0), CreateColor(1, 0.5, 1, 0.5));
|
||
|
|
self.Surface:SetBlendMode("ADD");
|
||
|
|
self.Surface:SetPoint("RIGHT", self.Fill, "RIGHT", 0, 0);
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.ValueBlock then
|
||
|
|
local f = CreateFrame("Frame", nil, self);
|
||
|
|
self.ValueBlock = f;
|
||
|
|
f:SetHeight(32);
|
||
|
|
|
||
|
|
local bg = f:CreateTexture(nil, "OVERLAY", nil, 4);
|
||
|
|
bg:SetTextureSliceMode(0);
|
||
|
|
local margin = 8;
|
||
|
|
bg:SetTextureSliceMargins(margin, margin, margin, margin);
|
||
|
|
bg:SetAllPoints(true);
|
||
|
|
bg:SetTexture(FILE_PATH.."StatusBar-ValueBlock-Purple.png");
|
||
|
|
|
||
|
|
f.Text = f:CreateFontString(nil, "OVERLAY", "DUIFont_AlertFont", 7);
|
||
|
|
f.Text:SetJustifyH("CENTER");
|
||
|
|
f.Text:SetTextColor(0.8, 0.8, 0.8);
|
||
|
|
f.Text:SetPoint("CENTER", f, "CENTER", 0, 2);
|
||
|
|
end
|
||
|
|
|
||
|
|
if not self.notchPool then
|
||
|
|
local function CreateNotch()
|
||
|
|
local texture = self:CreateTexture(nil, "OVERLAY");
|
||
|
|
texture:SetTexture(FILE_PATH.."StatusBar-Notch.png");
|
||
|
|
texture:SetVertexColor(0.25, 0.25, 0.25);
|
||
|
|
return texture
|
||
|
|
end
|
||
|
|
|
||
|
|
self.notchPool = API.CreateObjectPool(CreateNotch);
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetMinMaxValue(0, 100);
|
||
|
|
self:SetScript("OnShow", self.OnShow);
|
||
|
|
self:SetScript("OnHide", self.OnHide);
|
||
|
|
self:SetScript("OnEnter", self.OnEnter);
|
||
|
|
self:SetScript("OnLeave", self.OnLeave);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetBarWidth(width)
|
||
|
|
if width == self.width then return end;
|
||
|
|
|
||
|
|
self.width = width;
|
||
|
|
self:SetWidth(width);
|
||
|
|
self:UpdatePixel();
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function StatusBarMixin:SetNumCompartment(numCompartment, forceUpdate)
|
||
|
|
local numNotches = numCompartment - 1;
|
||
|
|
|
||
|
|
if (numNotches ~= self.numNotches) or forceUpdate then
|
||
|
|
self.numNotches = numNotches;
|
||
|
|
else
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self.notchPool:Release();
|
||
|
|
|
||
|
|
if numNotches <= 0 then return end;
|
||
|
|
|
||
|
|
local fullWidth = self:GetWidth();
|
||
|
|
local offset = fullWidth / numCompartment;
|
||
|
|
local lineWidth = self:GetNotchWidth();
|
||
|
|
local height = self:GetHeight() - 2;
|
||
|
|
|
||
|
|
local texture;
|
||
|
|
|
||
|
|
for i = 1, numNotches do
|
||
|
|
texture = self.notchPool:Acquire();
|
||
|
|
texture:SetSize(lineWidth, height);
|
||
|
|
texture:SetPoint("CENTER", self, "LEFT", i * offset, 0);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:UpdateNotches()
|
||
|
|
if self.numNotches then
|
||
|
|
self:SetNumCompartment(self.numNotches + 1, true);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:GetNotchWidth(scale)
|
||
|
|
if not scale then
|
||
|
|
scale = self:GetEffectiveScale();
|
||
|
|
end
|
||
|
|
|
||
|
|
local lineWeight = 4.0;
|
||
|
|
local width = API.GetPixelForScale(scale, lineWeight);
|
||
|
|
|
||
|
|
return width
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:UpdatePixel(scale)
|
||
|
|
self:UpdateNotches();
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetBorderColor(r, g, b)
|
||
|
|
self.Border:SetVertexColor(r, g, b);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetMinMaxValue(minVal, maxVal)
|
||
|
|
self.minVal = minVal;
|
||
|
|
self.maxVal = maxVal;
|
||
|
|
self.range = maxVal - minVal;
|
||
|
|
|
||
|
|
if self.value then
|
||
|
|
local value = Clamp(self.value, self.minVal, self.maxVal);
|
||
|
|
self:SetValue(value);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnOverflow()
|
||
|
|
if self.getRangeFunc then
|
||
|
|
local newValue = self.value - self.maxVal;
|
||
|
|
local minVal, maxVal = self:getRangeFunc();
|
||
|
|
self:SetMinMaxValue(minVal, maxVal);
|
||
|
|
self:SetValue(newValue);
|
||
|
|
self:AnimateBetweenValues(0, newValue);
|
||
|
|
end
|
||
|
|
|
||
|
|
if self.dataProvider then
|
||
|
|
self:Update(true);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetBarWidthByPercentage(a)
|
||
|
|
if a <= 0 then
|
||
|
|
a = 0;
|
||
|
|
self.Fill:Hide();
|
||
|
|
else
|
||
|
|
if a > 1 then
|
||
|
|
a = 1
|
||
|
|
end
|
||
|
|
self.Fill:Show();
|
||
|
|
self.Fill:SetWidth(self.width * a);
|
||
|
|
end
|
||
|
|
|
||
|
|
self.barProgress = a;
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:GetProgressEquivalentValue()
|
||
|
|
if self.barProgress then
|
||
|
|
return (1 - self.barProgress) * self.minVal + self.barProgress * self.maxVal
|
||
|
|
end
|
||
|
|
return self.value
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:CalculateValueRatio(value)
|
||
|
|
return (value - self.minVal) / self.range
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:AnimateBetweenValues(fromValue, toValue)
|
||
|
|
if toValue < fromValue then
|
||
|
|
toValue = self.maxVal;
|
||
|
|
end
|
||
|
|
self.fromRatio = self:CalculateValueRatio(fromValue);
|
||
|
|
self.toRatio = self:CalculateValueRatio(toValue);
|
||
|
|
self.t = 0;
|
||
|
|
self:SetScript("OnUpdate", AnimFill_OnUpdate);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetValue(value)
|
||
|
|
value = Clamp(value, self.minVal, self.maxVal);
|
||
|
|
self.value = value;
|
||
|
|
local a = (value - self.minVal)/self.range;
|
||
|
|
self:SetBarWidthByPercentage(a);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:AddValue(deltaValue)
|
||
|
|
--Show visual indicator
|
||
|
|
local deltaPercentage = deltaValue / self.range;
|
||
|
|
local blockWidth = self.width * deltaPercentage;
|
||
|
|
|
||
|
|
if blockWidth > 24 then
|
||
|
|
self.ValueBlock:SetWidth(self.width * deltaPercentage);
|
||
|
|
self.ValueBlock:ClearAllPoints();
|
||
|
|
self.ValueBlock:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", self:CalculateValueRatio(self.value) * self.width, 0);
|
||
|
|
self.ValueBlock.Text:SetText(deltaValue.." XP");
|
||
|
|
self.ValueBlock.t = 0;
|
||
|
|
self.ValueBlock.alpha = 0;
|
||
|
|
self.ValueBlock:SetScript("OnUpdate", CrossFade_OnUpdate);
|
||
|
|
self.ValueBlock:Show();
|
||
|
|
else
|
||
|
|
self.ValueBlock:Hide();
|
||
|
|
self.ValueBlock:SetScript("OnUpdate", nil);
|
||
|
|
end
|
||
|
|
|
||
|
|
local currentValue = self.value; --self:GetProgressEquivalentValue();
|
||
|
|
local newValue = currentValue + deltaValue;
|
||
|
|
self.value = newValue;
|
||
|
|
self:AnimateBetweenValues(currentValue, newValue);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetValueByPercentage(a)
|
||
|
|
local value = Lerp(self.minVal, self.maxVal, a);
|
||
|
|
self:SetValue(value);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:Update(animating)
|
||
|
|
--Overridden by DataProvider
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:SetDataProvider(dataProvider)
|
||
|
|
self:SetScript("OnEvent", nil);
|
||
|
|
self.dataProvider = dataProvider;
|
||
|
|
self.Update = StatusBarMixin.Update;
|
||
|
|
|
||
|
|
if dataProvider then
|
||
|
|
dataProvider:OnLoad(self);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:StopAnimation()
|
||
|
|
self:SetScript("OnUpdate", nil);
|
||
|
|
self.ValueBlock:Hide();
|
||
|
|
self.ValueBlock:SetScript("OnUpdate", nil);
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnShow()
|
||
|
|
if self.dataProvider then
|
||
|
|
self.dataProvider:OnShow(self);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnHide()
|
||
|
|
self:SetScript("OnEvent", nil);
|
||
|
|
self:StopAnimation();
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnMouseEnter()
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnEnter()
|
||
|
|
self:OnMouseEnter();
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarMixin:OnLeave()
|
||
|
|
TooltipFrame:Hide();
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
--[[
|
||
|
|
local StatusBarDataProvider = {};
|
||
|
|
|
||
|
|
function StatusBarDataProvider:OnLoad(bar)
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function StatusBarDataProvider:OnShow(bar)
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
--]]
|
||
|
|
|
||
|
|
local PlayerXPDataProvider = {};
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:OnLoad(bar)
|
||
|
|
self.owner = bar;
|
||
|
|
bar.Update = self.Update;
|
||
|
|
bar.OnMouseEnter = self.OnEnter;
|
||
|
|
bar.getRangeFunc = self.getRangeFunc;
|
||
|
|
end
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:OnShow(bar)
|
||
|
|
if self.isCapped then
|
||
|
|
bar:Hide();
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
self.isCapped = API.IsPlayerAtMaxLevel();
|
||
|
|
|
||
|
|
if self.isCapped then
|
||
|
|
bar:Hide();
|
||
|
|
--ChatFrame is anchored to this frame so we move it down
|
||
|
|
bar:ClearAllPoints();
|
||
|
|
bar:SetPoint("TOP", nil, "BOTTOM", 0, 0);
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
bar:RegisterUnitEvent("PLAYER_XP_UPDATE", "player");
|
||
|
|
bar:RegisterEvent("PLAYER_LEVEL_UP");
|
||
|
|
bar:SetScript("OnEvent", self.OnEvent);
|
||
|
|
bar:Update();
|
||
|
|
end
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:OnEvent(event, ...)
|
||
|
|
if event == "PLAYER_XP_UPDATE" then
|
||
|
|
self:Update(true);
|
||
|
|
elseif event == "PLAYER_LEVEL_UP" then
|
||
|
|
local newLevel = ...
|
||
|
|
self:Update(true, newLevel);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:Update(animating, newLevel)
|
||
|
|
local level, currentXP, maxXP = GetPlayerLevelXP();
|
||
|
|
|
||
|
|
if newLevel and type(newLevel) == "number" then
|
||
|
|
level = newLevel;
|
||
|
|
end
|
||
|
|
|
||
|
|
if animating then
|
||
|
|
local deltaValue;
|
||
|
|
|
||
|
|
if self.level and level > self.level then
|
||
|
|
deltaValue = currentXP + self.maxVal - self.value;
|
||
|
|
else
|
||
|
|
deltaValue = currentXP - self.value;
|
||
|
|
end
|
||
|
|
|
||
|
|
self:AddValue(deltaValue);
|
||
|
|
else
|
||
|
|
self.level = level;
|
||
|
|
self:StopAnimation();
|
||
|
|
self:SetMinMaxValue(0, maxXP);
|
||
|
|
self:SetValue(currentXP);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:OnEnter()
|
||
|
|
TooltipFrame:Hide();
|
||
|
|
TooltipFrame:SetOwner(self, "ANCHOR_NONE");
|
||
|
|
TooltipFrame:SetPoint("BOTTOMLEFT", self.Fill, "TOPRIGHT", 0, 4);
|
||
|
|
|
||
|
|
local level, currentXP, maxXP = GetPlayerLevelXP();
|
||
|
|
local percentage = API.GetXPPercentage(currentXP);
|
||
|
|
local diff = maxXP - currentXP;
|
||
|
|
local xpText = L["Format Player XP"]:format(BreakUpLargeNumbers(currentXP), BreakUpLargeNumbers(maxXP), percentage);
|
||
|
|
TooltipFrame:AddLeftLine(L["Format Unit Level"]:format(level), 1, 1, 1);
|
||
|
|
TooltipFrame:AddLeftLine(xpText, 1, 1, 1);
|
||
|
|
if diff > 0 then
|
||
|
|
TooltipFrame:AddLeftLine(L["To Next Level Label"]..": |cffffffff"..BreakUpLargeNumbers(diff).."|r", 1, 0.82, 0);
|
||
|
|
end
|
||
|
|
TooltipFrame:Show();
|
||
|
|
end
|
||
|
|
|
||
|
|
function PlayerXPDataProvider:getRangeFunc()
|
||
|
|
local level, currentXP, maxXP = GetPlayerLevelXP();
|
||
|
|
self.level = level;
|
||
|
|
|
||
|
|
if API.IsPlayerAtMaxLevel() then
|
||
|
|
self:Hide();
|
||
|
|
return 0, 100
|
||
|
|
end
|
||
|
|
|
||
|
|
return 0, maxXP
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
local DataProviderPresets = {
|
||
|
|
xp = PlayerXPDataProvider,
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
local function CreateStatusBar(parent, dataProviderName)
|
||
|
|
local frame = CreateFrame("Frame", nil, parent);
|
||
|
|
frame:Hide();
|
||
|
|
frame:SetFlattensRenderLayers(true);
|
||
|
|
|
||
|
|
API.Mixin(frame, StatusBarMixin);
|
||
|
|
|
||
|
|
if dataProviderName and DataProviderPresets[dataProviderName] then
|
||
|
|
frame:SetDataProvider(DataProviderPresets[dataProviderName]);
|
||
|
|
end
|
||
|
|
|
||
|
|
return frame
|
||
|
|
end
|
||
|
|
addon.CreateStatusBar = CreateStatusBar;
|