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

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;