Skip to content

Commit

Permalink
Refactor progress handling
Browse files Browse the repository at this point in the history
* Make progress data (that is expirationTime/duration/value/total/etc)
  far less special state properties
* Instead state metadata can now describe multiple properties as
  progress values and which other properties are relevant, e.g.

  charge = {
    display = "Charges",
    type = "number",
    total = "totalCharge"
  }

  will allow the user to select "charge" as progress source, which will
  automatically use state.totalCharge for the total value.

  Or

  someTime = {
    display = "X",
    type = "timer",
    total = "propertyName",
    modRate = "propertyName",
    inverse = "propertyName",
    paused = "propertyName",
    remaining = "propertyName"
  }

  All of the additional properties are optional.

  And lastly,

  someOtherTime = {
    display = "Y",
    type = "elapsedTimer"
  }

  For progress sources that are past time stamps.

* Stacks, Unit count, etc are all potential progress sources now.
* On the Display tab, the progress source can be selected from any
  trigger.
* Conditions can switch the progress source
* Ticks progress source is configurable and can be different from the
  main aura. This can be used via custom trigger to augment a main
  trigger
* state.autoHide can be a time point at which the state should
  automatically hide.
* Some behaviour changes, e.g. animations now observe the
  paused/remaining time and min/max progress settings

* Probably some regressions

Fixes: #4527
Fixes: #1449
Fixes: #4696
Fixes: #4719
  • Loading branch information
InfusOnWoW committed Feb 10, 2024
1 parent 9b3bee4 commit 193618e
Show file tree
Hide file tree
Showing 30 changed files with 2,173 additions and 1,286 deletions.
284 changes: 148 additions & 136 deletions WeakAuras/Animations.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,172 +12,182 @@ local function noopErrorHandler() end

local frame = Private.frames["WeakAuras Main Frame"]

local updatingAnimations;
local last_update = GetTime();
local function UpdateAnimations()
Private.StartProfileSystem("animations");

for groupUid, groupRegion in pairs(pending_controls) do
pending_controls[groupUid] = nil;
groupRegion:DoPositionChildren();
local function RunAnimation(key, anim, elapsed, time)
Private.StartProfileUID(anim.auraUID)
local finished = false
if(anim.duration_type == "seconds") then
if anim.duration > 0 then
anim.progress = anim.progress + (elapsed / anim.duration)
else
anim.progress = anim.progress + (elapsed / 1)
end
if(anim.progress >= 1) then
anim.progress = 1
finished = true
end
elseif(anim.duration_type == "relative") then
local region = anim.region
if ((region.progressType == "timed" and region.duration < 0.01)
or (region.progressType == "static" and region.value < 0.01))
then
anim.progress = 0
if(anim.type == "start" or anim.type == "finish") then
finished = true
end
else
local relativeProgress = 0
if(region.progressType == "static") then
relativeProgress = region.value / region.total
elseif (region.progressType == "timed") then
relativeProgress = 1 - ((region.expirationTime - time) / region.duration)
end
relativeProgress = region.inverse and (1 - relativeProgress) or relativeProgress
anim.progress = anim.duration > 0 and relativeProgress / anim.duration or 0
local iteration = math.floor(anim.progress)
--anim.progress = anim.progress - iteration
if not(anim.iteration) then
anim.iteration = iteration
elseif(anim.iteration ~= iteration) then
anim.iteration = nil
finished = true
end
end
else
anim.progress = 1
end

local time = GetTime();
local elapsed = time - last_update;
last_update = time;
local num = 0;
for key, anim in pairs(animations) do
Private.StartProfileUID(anim.auraUID);
num = num + 1;
local finished = false;
if(anim.duration_type == "seconds") then
if anim.duration > 0 then
anim.progress = anim.progress + (elapsed / anim.duration);
else
anim.progress = anim.progress + (elapsed / 1);
local progress = anim.inverse and (1 - anim.progress) or anim.progress
progress = anim.easeFunc(progress, anim.easeStrength or 3)
Private.ActivateAuraEnvironmentForRegion(anim.region)
if(anim.translateFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Slide Animation"])
if (anim.region.SetOffsetAnim) then
local ok, x, y = xpcall(anim.translateFunc, errorHandler, progress, 0, 0, anim.dX, anim.dY)
anim.region:SetOffsetAnim(x, y)
else
anim.region:ClearAllPoints()
local ok, x, y = xpcall(anim.translateFunc, errorHandler, progress, anim.startX, anim.startY, anim.dX, anim.dY)
if (ok) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y)
end
if(anim.progress >= 1) then
anim.progress = 1;
finished = true;
end
end
if(anim.alphaFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Fade Animation"])
local ok, alpha = xpcall(anim.alphaFunc, errorHandler, progress, anim.startAlpha, anim.dAlpha)
if (ok) then
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(alpha)
else
anim.region:SetAlpha(alpha)
end
elseif(anim.duration_type == "relative") then
local state = anim.region.state;
if (not state
or (state.progressType == "timed" and state.duration < 0.01)
or (state.progressType == "static" and state.value < 0.01)) then
anim.progress = 0;
if(anim.type == "start" or anim.type == "finish") then
finished = true;
end
end
end
if(anim.scaleFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Zoom Animation"])
local ok, scaleX, scaleY = xpcall(anim.scaleFunc, errorHandler, progress, 1, 1, anim.scaleX, anim.scaleY)
if (ok) then
if(anim.region.Scale) then
anim.region:Scale(scaleX, scaleY)
else
local relativeProgress = 0;
if(state.progressType == "static") then
relativeProgress = state.value / state.total;
elseif (state.progressType == "timed") then
relativeProgress = 1 - ((state.expirationTime - time) / state.duration);
end
relativeProgress = state.inverse and (1 - relativeProgress) or relativeProgress;
anim.progress = anim.duration > 0 and relativeProgress / anim.duration or 0
local iteration = math.floor(anim.progress);
--anim.progress = anim.progress - iteration;
if not(anim.iteration) then
anim.iteration = iteration;
elseif(anim.iteration ~= iteration) then
anim.iteration = nil;
finished = true;
end
anim.region:SetWidth(anim.startWidth * scaleX)
anim.region:SetHeight(anim.startHeight * scaleY)
end
else
anim.progress = 1;
end
local progress = anim.inverse and (1 - anim.progress) or anim.progress;
progress = anim.easeFunc(progress, anim.easeStrength or 3)
Private.ActivateAuraEnvironmentForRegion(anim.region)
if(anim.translateFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Slide Animation"])
end
if(anim.rotateFunc and anim.region.SetAnimRotation) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Rotate Animation"])
local ok, rotate = xpcall(anim.rotateFunc, errorHandler, progress, anim.region:GetBaseRotation(), anim.rotate)
if (ok) then
anim.region:SetAnimRotation(rotate)
end
end
if(anim.colorFunc and anim.region.ColorAnim) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Color Animation"])
local startR, startG, startB, startA = anim.region:GetColor()
startR, startG, startB, startA = startR or 1, startG or 1, startB or 1, startA or 1
local ok, r, g, b, a = xpcall(anim.colorFunc, errorHandler, progress, startR, startG, startB, startA,
anim.colorR, anim.colorG, anim.colorB, anim.colorA)
if (ok) then
local errorHandler = Private.GetErrorHandlerId(anim.region.id, "Custom Color")
xpcall(anim.region.ColorAnim, errorHandler, anim.region, r, g, b, a)
end
end
Private.ActivateAuraEnvironment(nil)
if(finished) then
if not(anim.loop) then
if (anim.region.SetOffsetAnim) then
local ok, x, y = xpcall(anim.translateFunc, errorHandler, progress, 0, 0, anim.dX, anim.dY);
anim.region:SetOffsetAnim(x, y);
anim.region:SetOffsetAnim(0, 0)
else
anim.region:ClearAllPoints();
local ok, x, y = xpcall(anim.translateFunc, errorHandler, progress, anim.startX, anim.startY, anim.dX, anim.dY);
if (ok) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y);
if(anim.startX) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, anim.startX, anim.startY)
end
end
end
if(anim.alphaFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Fade Animation"])
local ok, alpha = xpcall(anim.alphaFunc, errorHandler, progress, anim.startAlpha, anim.dAlpha);
if (ok) then
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(alpha);
else
anim.region:SetAlpha(alpha);
end
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(nil)
elseif(anim.startAlpha) then
anim.region:SetAlpha(anim.startAlpha)
end
end
if(anim.scaleFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Zoom Animation"])
local ok, scaleX, scaleY = xpcall(anim.scaleFunc, errorHandler, progress, 1, 1, anim.scaleX, anim.scaleY);
if (ok) then
if(anim.startWidth) then
if(anim.region.Scale) then
anim.region:Scale(scaleX, scaleY);
anim.region:Scale(1, 1)
else
anim.region:SetWidth(anim.startWidth * scaleX);
anim.region:SetHeight(anim.startHeight * scaleY);
anim.region:SetWidth(anim.startWidth)
anim.region:SetHeight(anim.startHeight)
end
end
end
if(anim.rotateFunc and anim.region.SetAnimRotation) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Rotate Animation"])
local ok, rotate = xpcall(anim.rotateFunc, errorHandler, progress, anim.region:GetBaseRotation(), anim.rotate);
if (ok) then
anim.region:SetAnimRotation(rotate);
if(anim.region.SetAnimRotation) then
anim.region:SetAnimRotation(nil)
end
end
if(anim.colorFunc and anim.region.ColorAnim) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Color Animation"])
local startR, startG, startB, startA = anim.region:GetColor();
startR, startG, startB, startA = startR or 1, startG or 1, startB or 1, startA or 1;
local ok, r, g, b, a = xpcall(anim.colorFunc, errorHandler, progress, startR, startG, startB, startA, anim.colorR, anim.colorG, anim.colorB, anim.colorA);
if (ok) then
local errorHandler = Private.GetErrorHandlerId(anim.region.id, "Custom Color")
xpcall(anim.region.ColorAnim, errorHandler, anim.region, r, g, b, a)
if(anim.region.ColorAnim) then
anim.region:ColorAnim(nil)
end
animations[key] = nil
end
Private.ActivateAuraEnvironment(nil);
if(finished) then
if not(anim.loop) then
if (anim.region.SetOffsetAnim) then
anim.region:SetOffsetAnim(0, 0);
else
if(anim.startX) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, anim.startX, anim.startY);
end
end
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(nil);
elseif(anim.startAlpha) then
anim.region:SetAlpha(anim.startAlpha);
end
if(anim.startWidth) then
if(anim.region.Scale) then
anim.region:Scale(1, 1);
else
anim.region:SetWidth(anim.startWidth);
anim.region:SetHeight(anim.startHeight);
end
end
if(anim.region.SetAnimRotation) then
anim.region:SetAnimRotation(nil)
end
if(anim.region.ColorAnim) then
anim.region:ColorAnim(nil);
end
animations[key] = nil;
end

if(anim.loop) then
Private.Animate(anim.namespace, anim.auraUID, anim.type, anim.anim, anim.region, anim.inverse, anim.onFinished, anim.loop, anim.region.cloneId);
elseif(anim.onFinished) then
anim.onFinished();
end
if(anim.loop) then
Private.Animate(anim.namespace, anim.auraUID, anim.type, anim.anim, anim.region, anim.inverse, anim.onFinished,
anim.loop, anim.region.cloneId)
elseif(anim.onFinished) then
anim.onFinished()
end
Private.StopProfileUID(anim.auraUID);
end
Private.StopProfileUID(anim.auraUID)
end

local updatingAnimations;
local last_update = GetTime();
local function UpdateAnimations()
Private.StartProfileSystem("animations");

for groupUid, groupRegion in pairs(pending_controls) do
pending_controls[groupUid] = nil;
groupRegion:DoPositionChildren();
end

local time = GetTime();
local elapsed = time - last_update;
last_update = time;

for key, anim in pairs(animations) do
RunAnimation(key, anim, elapsed, time)
end

Private.StopProfileSystem("animations");
end

function Private.RegisterGroupForPositioning(uid, region)
pending_controls[uid] = region
updatingAnimations = true
frame:SetScript("OnUpdate", UpdateAnimations)
if not updatingAnimations then
updatingAnimations = true
last_update = GetTime()
frame:SetScript("OnUpdate", UpdateAnimations)
end
end

function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished, loop, cloneId)
local auraDisplayName = Private.UIDtoID(uid)
local key = tostring(region);
local valid;
if(anim and anim.type == "custom" and (anim.use_translate or anim.use_alpha or (anim.use_scale and region.Scale) or (anim.use_rotate and region.SetAnimRotation) or (anim.use_color and region.Color))) then
Expand Down Expand Up @@ -369,8 +379,10 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished

if not(updatingAnimations) then
frame:SetScript("OnUpdate", UpdateAnimations);
last_update = GetTime()
updatingAnimations = true;
end
RunAnimation(key, animation, 0, GetTime())
return true;
else
if(animations[key]) then
Expand Down
Loading

0 comments on commit 193618e

Please sign in to comment.