Skip to content
This repository has been archived by the owner on Jan 12, 2023. It is now read-only.

Commit

Permalink
Smooth progress ported from retail
Browse files Browse the repository at this point in the history
Fixes #20
  • Loading branch information
Maczuga committed May 27, 2021
1 parent 858491f commit f32ede2
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 94 deletions.
89 changes: 89 additions & 0 deletions WeakAuras/Libs/LibRetail/C_Timer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
local lib = LibStub and LibStub("LibRetail", true)
if not lib then return end

local waitTable = {};
local waitFrame = nil;

function lib.After (delay, func, ...)
-- print("dupa")
if(type(delay)~="number" or type(func)~="function") then
return false;
end
if(waitFrame == nil) then
waitFrame = CreateFrame("Frame","WaitFrame", UIParent);
waitFrame:SetScript("onUpdate",function (self,elapse)
local count = #waitTable;
local i = 1;
while(i<=count) do
local waitRecord = tremove(waitTable,i);
local d = tremove(waitRecord,1);
local f = tremove(waitRecord,1);
local p = tremove(waitRecord,1);
if(d>elapse) then
tinsert(waitTable,i,{d-elapse,f,p});
i = i + 1;
else
count = count - 1;
f(unpack(p));
end
end
end);
end
tinsert(waitTable,{delay,func,{...}});
return true;
end

local TickerPrototype = {};
local TickerMetatable = {
__index = TickerPrototype,
__metatable = true, --Probably not needed, but if I don't put this here someone is going to mess with this metatable and end up tainting everything...
};

--Creates and starts a ticker that calls callback every duration seconds for N iterations.
--If iterations is nil, the ticker will loop until cancelled.
--
--If callback throws a Lua error, the ticker will stop firing.
function lib.NewTicker(duration, callback, iterations)
-- print("cnewticker")
local ticker = setmetatable({}, TickerMetatable);
ticker._remainingIterations = iterations;
ticker._callback = function()
if ( not ticker._cancelled ) then
callback(ticker);

--Make sure we weren't cancelled during the callback
if ( not ticker._cancelled ) then
if ( ticker._remainingIterations ) then
ticker._remainingIterations = ticker._remainingIterations - 1;
end
if ( not ticker._remainingIterations or ticker._remainingIterations > 0 ) then
lib.After(duration, ticker._callback);
end
end
end
end;

lib.After(duration, ticker._callback);
return ticker;
end

--Creates and starts a cancellable timer that calls callback after duration seconds.
--Note that C_Timer.NewTimer is significantly more expensive than C_Timer.After and should
--only be used if you actually need any of its additional functionality.
--
--While timers are currently just tickers with an iteration count of 1, this is likely
--to change in the future and shouldn't be relied on.
function lib.NewTimer(duration, callback)
return lib.NewTicker(duration, callback, 1);
end

--Cancels a ticker or timer. May be safely called within the ticker's callback in which
--case the ticker simply won't be started again.
--Cancel is guaranteed to be idempotent.
function TickerPrototype:Cancel()
self._cancelled = true;
end

function TickerPrototype:IsCancelled()
return self._cancelled;
end
90 changes: 1 addition & 89 deletions WeakAuras/Libs/LibRetail/LibRetail.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if not lib then return end
LibStub("AceTimer-3.0"):Embed(lib)

-- Lua APIs
local pairs, ipairs, next, select, CreateFrame, pcall = pairs, ipairs, next, select, CreateFrame, pcall
local pairs, ipairs, next, select, CreateFrame, pcall, print = pairs, ipairs, next, select, CreateFrame, pcall, print

local math_abs, math_ceil, math_floor = math.abs, math.ceil, math.floor

Expand Down Expand Up @@ -369,98 +369,10 @@ function lib.xpcall(func, errorHandler, ...)
-- errorHandler();
return pcall(func, ...)
end
-------------------------------------
local g_updatingBars = {};

local function IsCloseEnough(bar, newValue, targetValue)
local min, max = bar:GetMinMaxValues();
local range = max - min;
if range > 0.0 then
return math_abs((newValue - targetValue) / range) < .00001;
end

return true;
end

local function ProcessSmoothStatusBars()
for bar, targetValue in pairs(g_updatingBars) do
local effectiveTargetValue = lib.Clamp(targetValue, bar:GetMinMaxValues());
local newValue = lib.FrameDeltaLerp(bar:GetValue(), effectiveTargetValue, .25);

if IsCloseEnough(bar, newValue, effectiveTargetValue) then
g_updatingBars[bar] = nil;
bar:SetValue(effectiveTargetValue);
else
bar:SetValue(newValue);
end
end
end

lib:ScheduleRepeatingTimer(ProcessSmoothStatusBars, 0)
-- C_Timer.NewTicker(0, ProcessSmoothStatusBars);

lib.SmoothStatusBarMixin = {};

function lib.SmoothStatusBarMixin:ResetSmoothedValue(value) --If nil, tries to set to the last target value
local targetValue = g_updatingBars[self];
if targetValue then
g_updatingBars[self] = nil;
self:SetValue(value or targetValue);
elseif value then
self:SetValue(value);
end
end

function lib.SmoothStatusBarMixin:SetSmoothedValue(value)
g_updatingBars[self] = value;
end

function lib.SmoothStatusBarMixin:SetMinMaxSmoothedValue(min, max)
self:SetMinMaxValues(min, max);

local targetValue = g_updatingBars[self];
if targetValue then
local ratio = 1;
if max ~= 0 and self.lastSmoothedMax and self.lastSmoothedMax ~= 0 then
ratio = max / self.lastSmoothedMax;
end

g_updatingBars[self] = targetValue * ratio;
end

self.lastSmoothedMin = min;
self.lastSmoothedMax = max;
end

function lib.Round(value)
if value < 0.0 then
return math_ceil(value - .5);
end
return math_floor(value + .5);
end

function lib.Clamp(value, min, max)
if value > max then
return max;
elseif value < min then
return min;
end
return value;
end

function lib.Saturate(value)
return lib.Clamp(value, 0.0, 1.0);
end

function lib.Lerp(startValue, endValue, amount)
return (1 - amount) * startValue + amount * endValue;
end

local TARGET_FRAME_PER_SEC = 60.0;
function lib.DeltaLerp(startValue, endValue, amount, timeSec)
return lib.Lerp(startValue, endValue, lib.Saturate(amount * timeSec * TARGET_FRAME_PER_SEC));
end

function lib.FrameDeltaLerp(startValue, endValue, amount)
return lib.DeltaLerp(startValue, endValue, amount, 0.1);
end
4 changes: 3 additions & 1 deletion WeakAuras/Libs/LibRetail/LibRetail.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
..\FrameXML\UI.xsd">
<Include file ="lib\AceTimer-3.0\AceTimer-3.0.xml"/>
<Script file = "LibRetail.lua"/>
<Script file = "C_Timer.lua"/>
<Script file = "TimeUtil.lua"/>
</Ui>
<Script file = "SmoothStatusBar.lua"/>
</Ui>
97 changes: 97 additions & 0 deletions WeakAuras/Libs/LibRetail/SmoothStatusBar.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
local lib = LibStub and LibStub("LibRetail", true)
if not lib then return end

local g_updatingBars = {};

local TARGET_FRAME_PER_SEC = 120.0;
local LERP_AMOUNT = 0.25

local function Clamp(value, min, max)
min = min or 0
max = max or 1

if value > max then
return max;
elseif value < min then
return min;
end

return value;
end

local function Saturate(value)
return Clamp(value, 0.0, 1.0);
end

local function Lerp(startValue, endValue, amount)
return (1 - amount) * startValue + amount * endValue;
end

local function DeltaLerp(startValue, endValue, amount, timeSec)
return Lerp(startValue, endValue, Saturate(amount * timeSec * TARGET_FRAME_PER_SEC));
end

local function FrameDeltaLerp(startValue, endValue, amount)
return DeltaLerp(startValue, endValue, amount, 0.1);
end

local function IsCloseEnough(bar, newValue, targetValue)
local min, max = bar:GetMinMaxValues();
local range = max - min;
if range > 0.0 then
return math.abs((newValue - targetValue) / range) < .00001;
end

return true;
end

local function ProcessSmoothStatusBars(_, elapsed)
for bar, targetValue in pairs(g_updatingBars) do
local new = Lerp(bar:GetValue(), targetValue, Clamp(LERP_AMOUNT * elapsed * TARGET_FRAME_PER_SEC))

if IsCloseEnough(bar, new, targetValue) then
g_updatingBars[bar] = nil;
bar:SetValue(targetValue);
else
bar:SetValue(new);
end
end
end

local frame = CreateFrame("Frame");
if not frame:GetScript("OnUpdate") then
frame:SetScript("OnUpdate", ProcessSmoothStatusBars)
end

lib.SmoothStatusBarMixin = {};

function lib.SmoothStatusBarMixin:ResetSmoothedValue(value) --If nil, tries to set to the last target value
local targetValue = g_updatingBars[self];
if targetValue then
g_updatingBars[self] = nil;
self:SetValue(value or targetValue);
elseif value then
self:SetValue(value);
end
end

function lib.SmoothStatusBarMixin:SetSmoothedValue(value)
g_updatingBars[self] = value;
end

function lib.SmoothStatusBarMixin:SetMinMaxSmoothedValue(min, max)
self:SetMinMaxValues(min, max);

local targetValue = g_updatingBars[self];
if targetValue then
local ratio = 1;
if max ~= 0 and self.lastSmoothedMax and self.lastSmoothedMax ~= 0 then
ratio = max / self.lastSmoothedMax;
end

g_updatingBars[self] = targetValue * ratio;
end

self.lastSmoothedMin = min;
self.lastSmoothedMax = max;
end
13 changes: 9 additions & 4 deletions WeakAuras/RegionTypes/Icon.lua
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ local function modify(parent, region, data)

iconPath = iconPath or self.displayIcon or "Interface\\Icons\\INV_Misc_QuestionMark"
WeakAuras.SetTextureOrAtlas(self.icon, iconPath)
self.icon:SetDesaturated(data.desaturate)
-- self.icon:SetDesaturated(data.desaturate)
end

function region:Scale(scalex, scaley)
Expand Down Expand Up @@ -500,9 +500,14 @@ local function modify(parent, region, data)
cooldown:Hide()
if(data.cooldown) then
function region:SetValue(value, total)
cooldown.duration = 0
cooldown.expirationTime = math.huge
cooldown:Hide();
cooldown.value = value
cooldown.total = total
if (value >= 0 and value <= total) then
cooldown:Show()
cooldown:SetCooldown(GetTime() - (total - value), total)
else
cooldown:Hide();
end
end

function region:SetTime(duration, expirationTime)
Expand Down

0 comments on commit f32ede2

Please sign in to comment.