Animate unit frame bars with ClassicAPI's SmoothStatusBarMixin

Health and power bars take SmoothStatusBarMixin instead of pfUI's own OnUpdate animation, so the animation no longer runs faster at higher frame rates. The speed dropdown becomes an on/off checkbox, since the mixin's rate is fixed. A new range keeps the bar's filled share, so it doesn't jump before the animation moves on.
This commit is contained in:
Brues
2026-10-31 14:20:20 -05:00
parent 43f90751d6
commit e5a78c8d54
12 changed files with 37 additions and 102 deletions
+1 -20
View File
@@ -222,7 +222,7 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("unitframes", nil, "ragecolor", "1,.5,.5,1")
pfUI:UpdateConfig("unitframes", nil, "focuscolor", "1,1,.75,1")
pfUI:UpdateConfig("unitframes", nil, "animation_speed", "5")
pfUI:UpdateConfig("unitframes", nil, "animatebars", "1")
pfUI:UpdateConfig("unitframes", nil, "portraitalpha", "0.1")
pfUI:UpdateConfig("unitframes", nil, "always2dportrait", "0")
pfUI:UpdateConfig("unitframes", nil, "portraittexture", "1")
@@ -1143,25 +1143,6 @@ function pfUI:MigrateConfig()
end
end
-- migrating animation_speed (> 3.1.2)
if checkversion(3, 1, 2) then
if tonumber(pfUI_config.unitframes.animation_speed) >= 13 then
pfUI_config.unitframes.animation_speed = "13"
elseif tonumber(pfUI_config.unitframes.animation_speed) >= 8 then
pfUI_config.unitframes.animation_speed = "8"
elseif tonumber(pfUI_config.unitframes.animation_speed) >= 5 then
pfUI_config.unitframes.animation_speed = "5"
elseif tonumber(pfUI_config.unitframes.animation_speed) >= 3 then
pfUI_config.unitframes.animation_speed = "3"
elseif tonumber(pfUI_config.unitframes.animation_speed) >= 2 then
pfUI_config.unitframes.animation_speed = "2"
elseif tonumber(pfUI_config.unitframes.animation_speed) >= 1 then
pfUI_config.unitframes.animation_speed = "1"
else
pfUI_config.unitframes.animation_speed = "5"
end
end
-- migrating legacy buff/debuff naming (> 3.5.0)
if checkversion(3, 5, 0) then
local unitframes = { "player", "target", "focus", "group", "grouptarget", "grouppet", "raid", "ttarget", "pet", "ptarget", "fallback" }
+10 -49
View File
@@ -2,63 +2,30 @@
setfenv(1, pfUI:GetEnvironment())
do -- statusbars
local animations = {}
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 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())))
end
end
end)
-- SmoothStatusBarMixin animates the bar through SetValue, so this is the
-- shown value; SetSmoothedValue sets the target
local handlers = {
["DisplayValue"] = function(self, val)
["SetValue"] = function(self, val)
local smin, smax = self:GetMinMaxValues()
val = Clamp(val, smin, smax)
-- remove animation queue
if val == self.val_ then
animations[self] = nil
end
-- set current visible value
self.val_ = val
SetValue(self, val)
-- 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
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
-- the fill keeps its share of the bar, so a new range doesn't make it
-- jump before the smoothed value moves on from there
["SetMinMaxValues"] = function(self, smin, smax)
local oldmin, oldmax = self:GetMinMaxValues()
local share = oldmax > oldmin and (self:GetValue() - oldmin) / (oldmax - oldmin) or 0
SetMinMaxValues(self, smin, smax)
self:DisplayValue(self.val_ or self.val)
end,
["SetValue"] = function(self, val)
self.val = val or 0
-- start animation on difference
if self.val_ ~= self.val then
animations[self] = true
end
self:SetValue(smin + share * (smax - smin))
end,
["SetStatusBarBackgroundColor"] = function(self, r, g, b, a)
@@ -82,7 +49,6 @@ do -- statusbars
local f = CreateFrame("StatusBar", name, parent)
SetMinMaxValues(f, 0, 100)
SetValue(f, 0)
f.val = 0
f.bg = CreateFrame("StatusBar", nil, f)
f.bg:SetFrameLevel(f:GetFrameLevel() - 1)
@@ -91,12 +57,7 @@ do -- statusbars
f.bg:SetMinMaxValues(0, 1)
f.bg:SetValue(1)
-- add all handler functions to the object
for name, func in pairs(handlers) do
f[name] = func
end
return f
return Mixin(f, SmoothStatusBarMixin, handlers)
end
end
+17 -8
View File
@@ -1700,6 +1700,15 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
return f
end
-- animates a health or power bar to its new value, or sets it at once
local function SetBarValue(bar, value)
if C.unitframes.animatebars == "1" then
bar:SetSmoothedValue(value)
else
bar:ResetSmoothedValue(value)
end
end
function pfUI.uf:RefreshUnitState(unit)
local alpha = unit.alpha_visible
local unlock = pfUI.unlock and pfUI.unlock:IsShown() or nil
@@ -1707,10 +1716,10 @@ function pfUI.uf:RefreshUnitState(unit)
if not UnitIsConnected(unit.label .. unit.id) and not unlock then
-- offline
alpha = unit.alpha_offline
unit.hp.bar:SetMinMaxValues(0, 100, true)
unit.power.bar:SetMinMaxValues(0, 100, true)
unit.hp.bar:SetValue(0)
unit.power.bar:SetValue(0)
unit.hp.bar:SetMinMaxValues(0, 100)
unit.power.bar:SetMinMaxValues(0, 100)
SetBarValue(unit.hp.bar, 0)
SetBarValue(unit.power.bar, 0)
elseif unit.config.faderange == "1" and not pfUI.api.UnitInRange(unit.label .. unit.id, 4) and not unlock then
alpha = unit.alpha_outrange
end
@@ -2237,11 +2246,11 @@ function pfUI.uf:RefreshUnit(unit, component)
hp = hpmax - hp
end
unit.hp.bar:SetMinMaxValues(0, hpmax, true)
unit.hp.bar:SetValue(hp)
unit.hp.bar:SetMinMaxValues(0, hpmax)
SetBarValue(unit.hp.bar, hp)
unit.power.bar:SetMinMaxValues(0, powermax, true)
unit.power.bar:SetValue(power)
unit.power.bar:SetMinMaxValues(0, powermax)
SetBarValue(unit.power.bar, power)
-- Hide power bar text for NPCs without real power (power == 0)
local isNPC = not UnitIsPlayer(unitstr) and not UnitPlayerControlled(unitstr)