Draw unit frame bars with the native StatusBar

The custom bar sized its textures in Lua from GetWidth(), so it had to
track how ClassicAPI reports the UI scale (#71), and it stretched the bar
texture instead of cropping it. The engine's StatusBar does that layout
itself.

The background of the missing part is a second StatusBar that fills
from the other end (ClassicAPI's SetReverseFill), one frame level below
the fill, so the incoming-heal texture still draws between the two.
SetFrameLevel moves both, and the health and power bars now sit two
levels above their backdrops. SetStatusBarBackgroundTexture becomes
SetStatusBarBackgroundColor, as it only ever took a color.
This commit is contained in:
Brues
2026-10-29 11:06:02 -05:00
parent 35c32f365e
commit 6c76a88467
2 changed files with 43 additions and 73 deletions
+37 -69
View File
@@ -3,15 +3,19 @@ setfenv(1, pfUI:GetEnvironment())
do -- statusbars
local animations = {}
local stepsize, val
local width, height, point
local stepsize
-- native StatusBar methods the bar overrides
local statusbar = CreateFrame("StatusBar")
local SetValue, SetMinMaxValues = statusbar.SetValue, statusbar.SetMinMaxValues
local SetOrientation, SetFrameLevel = statusbar.SetOrientation, statusbar.SetFrameLevel
local animate = CreateFrame("Frame", "pfStatusBarAnimation", UIParent)
animate:SetScript("OnUpdate", function()
stepsize = tonumber(pfUI_config.unitframes.animation_speed)
for bar in pairs(animations) do
if not bar.val_ or abs(bar.val_ - bar.val) < stepsize or bar.instant then
if not bar.val_ or abs(bar.val_ - bar.val) < stepsize then
bar:DisplayValue(bar.val)
elseif bar.val ~= bar.val_ then
bar:DisplayValue(bar.val_ + min((bar.val-bar.val_) / stepsize, max(bar.val-bar.val_, 30 / GetFramerate())))
@@ -21,7 +25,8 @@ do -- statusbars
local handlers = {
["DisplayValue"] = function(self, val)
val = Clamp(val, self.min, self.max)
local smin, smax = self:GetMinMaxValues()
val = Clamp(val, smin, smax)
-- remove animation queue
if val == self.val_ then
@@ -30,51 +35,20 @@ do -- statusbars
-- set current visible value
self.val_ = val
SetValue(self, val)
if self.mode == "vertical" then
height = self:GetHeight()
point = height / (self.max - self.min) * (val - self.min)
-- keep values in limits
point = Clamp(point, 0, height)
-- set point to zero if value and max is zero
if val == 0 then point = 0 end
-- set status bar position/size
self.bar:SetPoint("TOPLEFT", self, "TOPLEFT", 0, - height + point)
self.bar:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0)
-- set background bar position/size
self.bg:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
self.bg:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, point)
else
width = self:GetWidth()
point = width / (self.max - self.min) * (val - self.min)
-- keep values in limits
point = Clamp(point, 0, width)
-- set point to zero if value and max is zero
if val == 0 then point = 0 end
-- set status bar position/size
self.bar:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
self.bar:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", - width + point, 0)
-- set background bar position/size
self.bg:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0)
self.bg:SetPoint("TOPLEFT", self, "TOPLEFT", point, 0)
end
-- the background fills the missing part, all of an empty range
self.bg:SetValue(smax > smin and (smax - val) / (smax - smin) or 1)
end,
["SetMinMaxValues"] = function(self, smin, smax, smooth)
-- smoothen the transition by keeping the value at the same percentage as before
if smooth and self.max and self.max > 0 and smax > 0 and self.max ~= smax then
self.val_ = (self.val_ or self.val) / self.max * smax
local _, oldmax = self:GetMinMaxValues()
if smooth and oldmax > 0 and smax > 0 and oldmax ~= smax then
self.val_ = (self.val_ or self.val) / oldmax * smax
end
self.min, self.max = smin, smax
SetMinMaxValues(self, smin, smax)
self:DisplayValue(self.val_ or self.val)
end,
@@ -87,41 +61,35 @@ do -- statusbars
end
end,
["SetStatusBarTexture"] = function(self, r, g, b, a)
self.bar:SetTexture(r, g, b, a)
end,
["SetStatusBarColor"] = function(self, r, g, b, a)
self.bar:SetVertexColor(r, g, b, a)
end,
["SetStatusBarBackgroundTexture"] = function(self, r, g, b, a)
self.bg:SetTexture(r, g, b, a)
end,
["SetStatusBarBackgroundColor"] = function(self, r, g, b, a)
self.bg:SetVertexColor(r, g, b, a)
self.bg:SetColorFill(r, g, b, a)
end,
["SetOrientation"] = function(self, mode)
self.mode = strlower(mode)
["SetOrientation"] = function(self, orientation)
SetOrientation(self, orientation)
self.bg:SetOrientation(orientation)
end,
-- the background stays one level below the fill, under anything else
-- drawn on the fill's frame
["SetFrameLevel"] = function(self, level)
SetFrameLevel(self, level)
self.bg:SetFrameLevel(level - 1)
end,
}
function pfUI.api.CreateStatusBar(name, parent)
local f = CreateFrame("Button", name, parent)
f:EnableMouse(false)
local f = CreateFrame("StatusBar", name, parent)
SetMinMaxValues(f, 0, 100)
SetValue(f, 0)
f.val = 0
f.bar = f:CreateTexture(nil, "NORMAL")
f.bar:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
f.bar:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
f.bg = f:CreateTexture(nil, "BACKGROUND")
f.bg:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
f.bg:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
-- set some default values
f.min, f.max, f.val = 0, 100, 0
f.bg = CreateFrame("StatusBar", nil, f)
f.bg:SetFrameLevel(f:GetFrameLevel() - 1)
f.bg:SetAllPoints(f)
f.bg:SetReverseFill(true)
f.bg:SetMinMaxValues(0, 1)
f.bg:SetValue(1)
-- add all handler functions to the object
for name, func in pairs(handlers) do
+6 -4
View File
@@ -508,6 +508,8 @@ function pfUI.uf:UpdateConfig()
if tonumber(f.config.height) < 0 then f.hp:Hide() end
pfUI.api.CreateBackdrop(f.hp, default_border)
-- one level above the backdrop for the bar's background, one more for its fill
f.hp.bar:SetFrameLevel(f.hp.backdrop:GetFrameLevel() + 2)
f.hp.bar:SetStatusBarTexture(pfUI.media[f.config.bartexture])
f.hp.bar:SetAllPoints(f.hp)
if f.config.verticalbar == "1" then
@@ -522,7 +524,7 @@ function pfUI.uf:UpdateConfig()
if custombg == "1" then
local cr, cg, cb, ca = GetStringColor(custombgcolor)
cr, cg, cb, ca = tonumber(cr), tonumber(cg), tonumber(cb), tonumber(ca)
f.hp.bar:SetStatusBarBackgroundTexture(cr,cg,cb,ca)
f.hp.bar:SetStatusBarBackgroundColor(cr,cg,cb,ca)
end
f.power:ClearAllPoints()
@@ -531,7 +533,7 @@ function pfUI.uf:UpdateConfig()
if tonumber(f.config.pheight) < 0 then f.power:Hide() end
pfUI.api.CreateBackdrop(f.power, default_border)
f.power.bar:SetFrameLevel(f.power.backdrop:GetFrameLevel() + 1)
f.power.bar:SetFrameLevel(f.power.backdrop:GetFrameLevel() + 2)
f.power.bar:SetStatusBarTexture(pfUI.media[f.config.pbartexture])
f.power.bar:SetAllPoints(f.power)
@@ -541,7 +543,7 @@ function pfUI.uf:UpdateConfig()
if custompbg == "1" then
local cr, cg, cb, ca = GetStringColor(custompbgcolor)
cr, cg, cb, ca = tonumber(cr), tonumber(cg), tonumber(cb), tonumber(ca)
f.power.bar:SetStatusBarBackgroundTexture(cr,cg,cb,ca)
f.power.bar:SetStatusBarBackgroundColor(cr,cg,cb,ca)
end
local fontname, fontsize, fontstyle
@@ -1490,7 +1492,7 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
f.incHeal = CreateFrame("Frame", nil, f.hp)
-- Texture lives on hp.bar for correct draw order:
-- hp.bar.bg (BACKGROUND) < incHeal (BORDER) < hp.bar.bar (NORMAL)
-- hp.bar.bg (a level below) < incHeal (BORDER) < hp.bar's fill (ARTWORK)
f.incHeal.texture = f.hp.bar:CreateTexture(nil, "BORDER")
f.incHeal.texture:SetAllPoints(f.incHeal)
-- Override Show/Hide since texture lives on hp.bar, not incHeal