From 23c7da5ea6a2985ddbf71798b0a7089c81eefe86 Mon Sep 17 00:00:00 2001 From: NoM0Re Date: Wed, 22 Jan 2025 03:37:10 +0100 Subject: [PATCH] Refactor progress handling probably some regressions --- WeakAuras/Animations.lua | 334 ++++++------ WeakAuras/BossMods.lua | 61 ++- WeakAuras/BuffTrigger2.lua | 113 +++- WeakAuras/Conditions.lua | 116 ++++- WeakAuras/GenericTrigger.lua | 234 +++++---- WeakAuras/Modernize.lua | 23 + WeakAuras/Prototypes.lua | 113 ++-- WeakAuras/RegionTypes/AuraBar.lua | 173 ++----- WeakAuras/RegionTypes/Icon.lua | 134 ++--- WeakAuras/RegionTypes/ProgressTexture.lua | 157 ++---- WeakAuras/RegionTypes/RegionPrototype.lua | 488 +++++++++++------- WeakAuras/RegionTypes/StopMotion.lua | 243 +++++---- WeakAuras/RegionTypes/Text.lua | 22 +- WeakAuras/SubRegionTypes/SubText.lua | 15 +- WeakAuras/SubRegionTypes/Tick.lua | 260 ++++++---- WeakAuras/SubscribableObject.lua | 16 +- WeakAuras/Types.lua | 15 +- WeakAuras/WeakAuras.lua | 261 +++++++--- .../AceGUIWidget-WeakAurasDisplayButton.lua | 3 - ...ceGUIWidget-WeakAurasTwoColumnDropDown.lua | 15 +- WeakAurasOptions/AnimationOptions.lua | 28 +- WeakAurasOptions/CommonOptions.lua | 148 ++++++ WeakAurasOptions/ConditionOptions.lua | 139 ++++- WeakAurasOptions/GenericTrigger.lua | 4 + WeakAurasOptions/RegionOptions/AuraBar.lua | 11 +- WeakAurasOptions/RegionOptions/Icon.lua | 10 +- .../RegionOptions/ProgressTexture.lua | 7 +- WeakAurasOptions/RegionOptions/StopMotion.lua | 20 +- WeakAurasOptions/SubRegionOptions/Tick.lua | 137 ++++- 29 files changed, 2037 insertions(+), 1263 deletions(-) diff --git a/WeakAuras/Animations.lua b/WeakAuras/Animations.lua index b234022..956b16f 100644 --- a/WeakAuras/Animations.lua +++ b/WeakAuras/Animations.lua @@ -11,10 +11,175 @@ local function noopErrorHandler() end local frame = Private.frames["WeakAuras Main Frame"] +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 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 = pcall(anim.translateFunc, progress, 0, 0, anim.dX, anim.dY) + if not ok then + errorHandler() + else + anim.region:SetOffsetAnim(x, y) + end + else + anim.region:ClearAllPoints() + local ok, x, y = pcall(anim.translateFunc, progress, anim.startX, anim.startY, anim.dX, anim.dY) + if not ok then + errorHandler() + else + anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y) + end + end + end + if(anim.alphaFunc) then + local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Fade Animation"]) + local ok, alpha = pcall(anim.alphaFunc, progress, anim.startAlpha, anim.dAlpha) + if not ok then + errorHandler() + else + if (anim.region.SetAnimAlpha) then + anim.region:SetAnimAlpha(alpha) + else + anim.region:SetAlpha(alpha) + 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 = pcall(anim.scaleFunc, progress, 1, 1, anim.scaleX, anim.scaleY) + if not ok then + errorHandler() + else + if(anim.region.Scale) then + anim.region:Scale(scaleX, scaleY) + else + anim.region:SetWidth(anim.startWidth * scaleX) + anim.region:SetHeight(anim.startHeight * scaleY) + end + end + end + if(anim.rotateFunc and anim.region.Rotate) then + local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler + or Private.GetErrorHandlerUid(anim.auraUID, L["Rotate Animation"]) + local ok, rotate = pcall(anim.rotateFunc, anim.rotateFunc, progress, anim.startRotation, anim.rotate) + if not ok then + errorHandler() + else + anim.region:Rotate(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 = pcall(anim.colorFunc, progress, startR, startG, startB, startA, + anim.colorR, anim.colorG, anim.colorB, anim.colorA) + if not ok then + errorHandler() + else + local errorHandler = Private.GetErrorHandlerId(anim.region.id, "Custom Color") + local success = pcall(anim.region.ColorAnim, anim.region, r, g, b, a) + if not success then + errorHandler() + end + end + 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.startRotation) then + if(anim.region.Rotate) then + anim.region:Rotate(anim.startRotation); + end + 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 + 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(); @@ -23,164 +188,9 @@ local function UpdateAnimations() 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); - end - if(anim.progress >= 1) then - anim.progress = 1; - finished = true; - 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 - 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 - 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"]) - if (anim.region.SetOffsetAnim) then - local ok, x, y = pcall(anim.translateFunc, progress, 0, 0, anim.dX, anim.dY); - if not ok then - errorHandler(x) - else - anim.region:SetOffsetAnim(x, y); - end - else - anim.region:ClearAllPoints(); - local ok, x, y = pcall(anim.translateFunc, progress, anim.startX, anim.startY, anim.dX, anim.dY); - if not ok then - errorHandler(x) - else - anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y); - end - end - end - if(anim.alphaFunc) then - local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Fade Animation"]) - local ok, alpha = pcall(anim.alphaFunc, progress, anim.startAlpha, anim.dAlpha); - if not ok then - errorHandler(alpha) - else - if (anim.region.SetAnimAlpha) then - anim.region:SetAnimAlpha(alpha); - else - anim.region:SetAlpha(alpha); - 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 = pcall(anim.scaleFunc, progress, 1, 1, anim.scaleX, anim.scaleY); - if not ok then - errorHandler(scaleX) - else - if(anim.region.Scale) then - anim.region:Scale(scaleX, scaleY); - else - anim.region:SetWidth(anim.startWidth * scaleX); - anim.region:SetHeight(anim.startHeight * scaleY); - end - end - end - if(anim.rotateFunc and anim.region.Rotate) then - local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Rotate Animation"]) - local ok, rotate = pcall(anim.rotateFunc, progress, anim.startRotation, anim.rotate); - if not ok then - errorHandler(rotate) - else - anim.region:Rotate(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 = pcall(anim.colorFunc, progress, startR, startG, startB, startA, anim.colorR, anim.colorG, anim.colorB, anim.colorA); - if not ok then - errorHandler(r) - else - local success = pcall(anim.region.ColorAnim, errorHandler, anim.region, r, g, b, a) - if not success then - Private.GetErrorHandlerId(anim.region.id, "Custom Color") - end - end - 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.startRotation) then - if(anim.region.Rotate) then - anim.region:Rotate(anim.startRotation); - end - 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 - end - Private.StopProfileUID(anim.auraUID); + for key, anim in pairs(animations) do + RunAnimation(key, anim, elapsed, time) end Private.StopProfileSystem("animations"); @@ -188,12 +198,14 @@ 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.Rotate) or (anim.use_color and region.Color))) then @@ -388,8 +400,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 diff --git a/WeakAuras/BossMods.lua b/WeakAuras/BossMods.lua index c4da07c..f5ff989 100644 --- a/WeakAuras/BossMods.lua +++ b/WeakAuras/BossMods.lua @@ -150,7 +150,7 @@ Private.ExecEnv.BossMods.DBM = { end end if self.nextExpire then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, self.nextExpire - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, self.nextExpire - now, self) end end, @@ -214,11 +214,11 @@ Private.ExecEnv.BossMods.DBM = { WeakAuras.ScanEvents("BossMod_TimerStart", timerId) end if self.nextExpire == nil then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, expirationTime - now, self) self.nextExpire = expirationTime elseif expirationTime < self.nextExpire then timer:CancelTimer(self.recheckTimer) - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, expirationTime - now, self) self.nextExpire = expirationTime end elseif event == "DBM_TimerStop" then @@ -261,11 +261,11 @@ Private.ExecEnv.BossMods.DBM = { WeakAuras.ScanEvents("BossMod_TimerResume", timerId) end if self.nextExpire == nil then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - GetTime(), self) self.nextExpire = bar.expirationTime elseif bar.expirationTime < self.nextExpire then timer:CancelTimer(self.recheckTimer) - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - GetTime(), self) self.nextExpire = bar.expirationTime end end @@ -278,11 +278,11 @@ Private.ExecEnv.BossMods.DBM = { bar.duration = duration bar.expirationTime = expirationTime if self.nextExpire == nil then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - now, self) self.nextExpire = expirationTime elseif self.nextExpire == nil or expirationTime < self.nextExpire then timer:CancelTimer(self.recheckTimer) - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - now, self) self.nextExpire = expirationTime end end @@ -338,7 +338,7 @@ Private.ExecEnv.BossMods.DBM = { ScheduleCheck = function(self, fireTime) if not self.scheduled_scans[fireTime] then - self.scheduled_scans[fireTime] = timer:ScheduleTimerFixed(self.DoScan, fireTime - GetTime(), self, fireTime) + self.scheduled_scans[fireTime] = timer:ScheduleTimer(self.DoScan, fireTime - GetTime(), self, fireTime) end end } @@ -377,6 +377,7 @@ Private.event_prototypes["DBM Stage"] = { }, automaticrequired = true, statesParameter = "one", + progressType = "none" } Private.category_event_prototype.addons["DBM Stage"] = L["DBM Stage"] @@ -433,7 +434,8 @@ Private.event_prototypes["DBM Announce"] = { init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''" }, }, - timedrequired = true + timedrequired = true, + progressType = "timed" } Private.category_event_prototype.addons["DBM Announce"] = L["DBM Announce"] @@ -445,7 +447,7 @@ Private.event_prototypes["DBM Timer"] = { }, force_events = "DBM_TimerForce", name = L["DBM Timer"], - canHaveDuration = "timed", + progressType = "timed", triggerFunction = function(trigger) Private.ExecEnv.BossMods.DBM:RegisterTimer() local ret = [=[ @@ -681,6 +683,7 @@ Private.ExecEnv.BossMods.BigWigs = { state.addon = bar.addon state.spellId = bar.spellId state.text = bar.text + state.message = bar.text state.name = bar.text state.duration = bar.duration + extendTimer state.expirationTime = bar.expirationTime + extendTimer @@ -803,7 +806,7 @@ Private.ExecEnv.BossMods.BigWigs = { end if self.nextExpire then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, self.nextExpire - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, self.nextExpire - now, self) end end, @@ -843,11 +846,11 @@ Private.ExecEnv.BossMods.BigWigs = { WeakAuras.ScanEvents("BossMod_TimerStart", text) end if self.nextExpire == nil then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, expirationTime - now, self) self.nextExpire = expirationTime elseif expirationTime < self.nextExpire then timer:CancelTimer(self.recheckTimer) - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, expirationTime - now, self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, expirationTime - now, self) self.nextExpire = expirationTime end elseif event == "BigWigs_StopBar" then @@ -889,10 +892,10 @@ Private.ExecEnv.BossMods.BigWigs = { WeakAuras.ScanEvents("BossMod_TimerResume", text) end if self.nextExpire == nil then - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - GetTime(), self) elseif bar.expirationTime < self.nextExpire then timer:CancelTimer(self.recheckTimer) - self.recheckTimer = timer:ScheduleTimerFixed(self.RecheckTimers, bar.expirationTime - GetTime(), self) + self.recheckTimer = timer:ScheduleTimer(self.RecheckTimers, bar.expirationTime - GetTime(), self) self.nextExpire = bar.expirationTime end end @@ -979,7 +982,7 @@ Private.ExecEnv.BossMods.BigWigs = { ScheduleCheck = function(self, fireTime) if not self.scheduled_scans[fireTime] then - self.scheduled_scans[fireTime] = timer:ScheduleTimerFixed(self.DoScan, fireTime - GetTime(), self, fireTime) + self.scheduled_scans[fireTime] = timer:ScheduleTimer(self.DoScan, fireTime - GetTime(), self, fireTime) end end } @@ -1007,6 +1010,7 @@ Private.event_prototypes["BigWigs Stage"] = { }, automaticrequired = true, statesParameter = "one", + progressType = "none" } Private.category_event_prototype.addons["BigWigs Stage"] = L["BigWigs Stage"] @@ -1033,8 +1037,8 @@ Private.event_prototypes["BigWigs Message"] = { { name = "spellId", init = "arg", - display = L["Key"], - desc = L["The 'Key' value can be found in the BigWigs options of a specific spell"], + display = L["ID"], + desc = L["The 'ID' value can be found in the BigWigs options of a specific spell"], type = "spell", conditionType = "string", noValidation = true, @@ -1072,7 +1076,8 @@ Private.event_prototypes["BigWigs Message"] = { init = "use_cloneId and WeakAuras.GetUniqueCloneId() or ''" }, }, - timedrequired = true + timedrequired = true, + progressType = "timed" } Private.category_event_prototype.addons["BigWigs Message"] = L["BigWigs Message"] @@ -1084,7 +1089,7 @@ Private.event_prototypes["BigWigs Timer"] = { }, force_events = "BigWigs_Timer_Force", name = L["BigWigs Timer"], - canHaveDuration = "timed", + progressType = "timed", triggerFunction = function(trigger) Private.ExecEnv.BossMods.BigWigs:RegisterTimer() local ret = [=[ @@ -1237,8 +1242,8 @@ Private.event_prototypes["BigWigs Timer"] = { args = { { name = "spellId", - display = L["Key"], - desc = L["The 'Key' value can be found in the BigWigs options of a specific spell"], + display = L["ID"], + desc = L["The 'ID' value can be found in the BigWigs options of a specific spell"], type = "spell", conditionType = "string", noValidation = true, @@ -1350,6 +1355,7 @@ Private.event_prototypes["Boss Mod Stage"] = { }, automaticrequired = true, statesParameter = "one", + progressType = "none" } Private.category_event_prototype.addons["Boss Mod Stage"] = L["Boss Mod Stage"] @@ -1382,7 +1388,7 @@ Private.event_prototypes["Boss Mod Stage (Event)"] = { }, }, statesParameter = "one", - canHaveDuration = "timed", + progressType = "timed", delayEvents = true, timedrequired = true } @@ -1405,7 +1411,7 @@ Private.event_prototypes["Boss Mod Announce"] = { { name = "spellId", init = "arg", - display = L["Key"], + display = L["ID"], store = true, type = "spell", conditionType = "string", @@ -1463,7 +1469,8 @@ Private.event_prototypes["Boss Mod Announce"] = { text = ActiveBossModText }, }, - timedrequired = true + timedrequired = true, + progressType = "timed" } Private.category_event_prototype.addons["Boss Mod Announce"] = L["Boss Mod Announce"] @@ -1475,7 +1482,7 @@ Private.event_prototypes["Boss Mod Timer"] = { }, force_events = "BossMod_TimerForce", name = L["Boss Mod Timer"], - canHaveDuration = "timed", + progressType = "timed", triggerFunction = function(trigger) Private.ExecEnv.BossMods.Generic:RegisterTimer() local ret = [=[ @@ -1638,7 +1645,7 @@ Private.event_prototypes["Boss Mod Timer"] = { args = { { name = "spellId", - display = L["Key"], + display = L["ID"], store = true, type = "spell", conditionType = "string", diff --git a/WeakAuras/BuffTrigger2.lua b/WeakAuras/BuffTrigger2.lua index 46b6743..7977473 100644 --- a/WeakAuras/BuffTrigger2.lua +++ b/WeakAuras/BuffTrigger2.lua @@ -29,15 +29,9 @@ Updates all buff triggers in data. # Helper functions mainly for the WeakAuras Options # ##################################################### -CanHaveDuration(data, triggernum) -Returns whether the trigger can have a duration. - GetOverlayInfo(data, triggernum) Returns a table containing all overlays. Currently there aren't any -CanHaveClones(data, triggernum) -Returns whether the trigger can have clones. - CanHaveTooltip(data, triggernum) Returns the type of tooltip to show for the trigger. @@ -2525,13 +2519,6 @@ function BuffTrigger.Add(data) end end ---- Returns whether the trigger can have a duration. --- @param data --- @param triggernum -function BuffTrigger.CanHaveDuration(data, triggernum) - return "timed" -end - --- Returns a table containing the names of all overlays -- @param data -- @param triggernum @@ -2543,7 +2530,7 @@ end -- @param data -- @param triggernum -- @return -function BuffTrigger.CanHaveClones(data, triggernum) +local function CanHaveClones(data, triggernum) local trigger = data.triggers[triggernum].trigger if not IsSingleMissing(trigger) and trigger.showClones then return true @@ -2661,6 +2648,13 @@ function BuffTrigger.GetAdditionalProperties(data, triggernum) ret = ret .. "|cFFFFCC00%".. triggernum .. ".tooltip4|r - " .. L["Fourth Value of Tooltip Text"] .. "\n" end + if trigger.unit ~= "multi" then + ret = ret .. "|cFFFFCC00%".. triggernum .. ".stackGainTime|r - " .. L["Since Stack Gain"] .. "\n" + ret = ret .. "|cFFFFCC00%".. triggernum .. ".stackLostTime|r - " .. L["Since Stack Lost"] .. "\n" + ret = ret .. "|cFFFFCC00%".. triggernum .. ".initialTime|r - " .. L["Since Apply"] .. "\n" + ret = ret .. "|cFFFFCC00%".. triggernum .. ".refreshTime|r - " .. L["Since Apply/Refresh"] .. "\n" + end + if trigger.unit ~= "multi" and trigger.fetchRaidMark then ret = ret .. "|cFFFFCC00%".. triggernum .. ".raidMark|r - " .. L["Raid Mark"] .. "\n" end @@ -2675,6 +2669,95 @@ function BuffTrigger.GetAdditionalProperties(data, triggernum) return ret end +function BuffTrigger.GetProgressSources(data, triggernum, values) + local trigger = data.triggers[triggernum].trigger + tinsert(values, { + trigger = triggernum, + property = "matchCount", + type = "number", + display = L["Match Count"] + }) + tinsert(values, { + trigger = triggernum, + property = "matchCountPerUnit", + type = "number", + display = L["Match Count per Unit"] + }) + tinsert(values, { + trigger = triggernum, + property = "unitCount", + type = "number", + display = L["Units Affected"], + total = trigger.unit ~= "multi" and "maxUnitCount" or nil + }) + tinsert(values, { + trigger = triggernum, + property = "stacks", + type = "number", + display = L["Stacks"] + }) + tinsert(values, { + trigger = triggernum, + property = "totalStacks", + type = "number", + display = L["Total stacks over all matches"] + }) + if not IsSingleMissing(trigger) and trigger.unit ~= "multi" and trigger.fetchTooltip then + tinsert(values, { + trigger = triggernum, + property = "tooltip1", + type = "number", + display = L["Tooltip 1"] + }) + tinsert(values, { + trigger = triggernum, + property = "tooltip2", + type = "number", + display = L["Tooltip 2"] + }) + tinsert(values, { + trigger = triggernum, + property = "tooltip3", + type = "number", + display = L["Tooltip 3"] + }) + end + tinsert(values, { + trigger = triggernum, + property = "expirationTime", + type = "timer", + display = L["Timed Progress"], + total = "duration", + modRate = "modRate", + paused = "paused", + remaining = "remaining" + }) + tinsert(values, { + trigger = triggernum, + property = "stackGainTime", + type = "elapsedTimer", + display = L["Time since stack gain"], + }) + tinsert(values, { + trigger = triggernum, + property = "stackLostTime", + type = "elapsedTimer", + display = L["Time since stack lost"], + }) + tinsert(values, { + trigger = triggernum, + property = "initialTime", + type = "elapsedTimer", + display = L["Time since initial application"], + }) + tinsert(values, { + trigger = triggernum, + property = "refreshTime", + type = "elapsedTimer", + display = L["Time since last refresh"], + }) +end + function BuffTrigger.GetTriggerConditions(data, triggernum) local trigger = data.triggers[triggernum].trigger local result = {} @@ -3481,7 +3564,7 @@ function BuffTrigger.CreateFakeStates(id, triggernum) state.progressType = "timed" state.stacks = 1 allStates[""] = state - if BuffTrigger.CanHaveClones(data, triggernum) then + if CanHaveClones(data, triggernum) then for i = 1, 2 do local state = {} BuffTrigger.CreateFallbackState(data, triggernum, state) diff --git a/WeakAuras/Conditions.lua b/WeakAuras/Conditions.lua index 60044ee..627fcf3 100644 --- a/WeakAuras/Conditions.lua +++ b/WeakAuras/Conditions.lua @@ -34,7 +34,7 @@ end Private.callbacks:RegisterCallback("Delete", OnDelete) -local function formatValueForAssignment(vType, value, pathToCustomFunction, pathToFormatters) +local function formatValueForAssignment(vType, value, pathToCustomFunction, pathToFormatters, data) if (value == nil) then value = false; end @@ -49,6 +49,41 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path return tostring(value) end return "nil" + elseif vType == "progressSource" then + if type(value) == "table" then + local progressSource = Private.AddProgressSourceMetaData(data, value) + local trigger = progressSource[1] or -1 + local progressType = progressSource[2] or "auto" + local property = progressSource[3] + local totalProperty = progressSource[4] + local inverseProperty = progressSource[5] + local pausedProperty = progressSource[6] + local remainingProperty = progressSource[7] + + if trigger == 0 then + -- Manual progress + local serialized = string.format("{%s, %s, %s, %s}", + trigger, + Private.QuotedString(progressType), + property or "0", -- Actually: value + totalProperty or "100" -- Actually: total + ) + return serialized + else + local serialized = string.format("{%s, %s, %s, %s, %s, %s, %s, %s}", + trigger, + Private.QuotedString(progressType), + Private.QuotedString(property or "nil"), + totalProperty and Private.QuotedString(totalProperty) or "nil", + inverseProperty and Private.QuotedString(inverseProperty) or "nil", + pausedProperty and Private.QuotedString(pausedProperty) or "nil", + remainingProperty and Private.QuotedString(remainingProperty) or "nil" + ) + return serialized + end + else + return "nil" + end elseif (vType == "icon") then if type(value) == "string" then return string.format("%s", Private.QuotedString(value)) @@ -119,7 +154,9 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path end local function formatValueForCall(type, property) - if (type == "bool" or type == "number" or type == "list" or type == "icon" or type == "string") then + if type == "bool" or type == "number" or type == "list" or type == "icon" or type == "string" + or type == "progressSource" + then return "propertyChanges['" .. property .. "']"; elseif (type == "color") then local pcp = "propertyChanges['" .. property .. "']"; @@ -162,7 +199,8 @@ function Private.ExecEnv.CallCustomConditionTest(uid, testFunctionNumber, ...) end end -local function CreateTestForCondition(uid, input, allConditionsTemplate, usedStates) +local function CreateTestForCondition(data, input, allConditionsTemplate, usedStates) + local uid = data.uid local trigger = input and input.trigger; local variable = input and input.variable; local op = input and input.op; @@ -175,7 +213,7 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta local test = {}; if (input.checks) then for i, subcheck in ipairs(input.checks) do - local subtest, subrecheckCode = CreateTestForCondition(uid, subcheck, allConditionsTemplate, usedStates); + local subtest, subrecheckCode = CreateTestForCondition(data, subcheck, allConditionsTemplate, usedStates); if (subtest) then tinsert(test, "(" .. subtest .. ")"); end @@ -201,6 +239,14 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta local cType = conditionTemplate and conditionTemplate.type; local test = conditionTemplate and conditionTemplate.test; local preamble = conditionTemplate and conditionTemplate.preamble; + local progressSource + local pausedProperty + local remainingProperty + if cType == "timer" then + progressSource = Private.GetProgressSourceFor(data, trigger, variable) + pausedProperty = progressSource and progressSource[6] + remainingProperty = progressSource[7] + end local stateCheck = "state[" .. trigger .. "] and state[" .. trigger .. "].show and "; local stateVariableCheck = string.format("state[" .. trigger .. "][%q]", variable) .. "~= nil and "; @@ -247,10 +293,18 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. op .. v; end elseif (cType == "timer" and value and op) then + local triggerState = "state[" .. trigger .. "]" + local varString = triggerState .. string.format("[%q]", variable) + local remainingTime = "(" .. varString .. " - now)" + if pausedProperty and remainingProperty then + local pausedString = "state[" .. trigger .. "]" .. string.format("[%q]", pausedProperty) + local remainingString = "(state[" .. trigger .. "]" .. string.format("[%q]", remainingProperty) .. " or 0)" + remainingTime = "((" .. pausedString .. " and " .. remainingString .. ") or " .. remainingTime .. ")" + end if (op == "==") then - check = stateCheck .. stateVariableCheck .. "abs(state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "- now -" .. value .. ") < 0.05"; + check = stateCheck .. stateVariableCheck .. "abs((" .. remainingTime .. "-" .. value .. ")" .. " < 0.05" else - check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "- now" .. op .. value; + check = stateCheck .. stateVariableCheck .. remainingTime .. op .. value end elseif (cType == "elapsedTimer" and value and op) then if (op == "==") then @@ -341,9 +395,9 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta return check, recheckCode; end -local function CreateCheckCondition(uid, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug) +local function CreateCheckCondition(data, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug) local usedStates = {}; - local check, recheckCode = CreateTestForCondition(uid, condition.check, allConditionsTemplate, usedStates); + local check, recheckCode = CreateTestForCondition(data, condition.check, allConditionsTemplate, usedStates); if not check then check = "false" end @@ -401,8 +455,16 @@ local function CreateDeactivateCondition(ret, condition, conditionNumber, data, local propertyData = properties and properties[change.property] if (propertyData and propertyData.type and propertyData.setter) then usedProperties[change.property] = true; - ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property)) .. "\n"; - if (debug) then ret = ret .. " print('- " .. change.property .. " " ..formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property)) .. "')\n"; end + ret = ret .. " propertyChanges['" .. change.property .. "'] = " + .. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property), + nil, nil, data) + .. "\n"; + if (debug) then + ret = ret .. " print('- " .. change.property .. " " + .. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property), + nil, nil, data) + .. "')\n"; + end end end end @@ -412,7 +474,7 @@ local function CreateDeactivateCondition(ret, condition, conditionNumber, data, return ret; end -local function CreateActivateCondition(ret, id, condition, conditionNumber, properties, debug) +local function CreateActivateCondition(ret, id, condition, conditionNumber, data, properties, debug) if (condition.changes) then ret = ret .. " if (newActiveConditions[" .. conditionNumber .. "]) then\n" ret = ret .. " if (not activatedConditions[".. conditionNumber .. "]) then\n" @@ -423,8 +485,12 @@ local function CreateActivateCondition(ret, id, condition, conditionNumber, prop local propertyData = properties and properties[change.property] if (propertyData and propertyData.type) then if (propertyData.setter) then - ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, change.value) .. "\n"; - if (debug) then ret = ret .. " print('- " .. change.property .. " " .. formatValueForAssignment(propertyData.type, change.value) .. "')\n"; end + ret = ret .. " propertyChanges['" .. change.property .. "'] = " + .. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "\n" + if (debug) then + ret = ret .. " print('- " .. change.property .. " " + .. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "')\n" + end elseif (propertyData.action) then local pathToCustomFunction = "nil"; local pathToFormatter = "nil" @@ -440,8 +506,16 @@ local function CreateActivateCondition(ret, id, condition, conditionNumber, prop and Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes[changeNum] then pathToFormatter = string.format("Private.ExecEnv.conditionTextFormatters[%q][%s].changes[%s]", id, conditionNumber, changeNum); end - ret = ret .. " region:" .. propertyData.action .. "(" .. formatValueForAssignment(propertyData.type, change.value, pathToCustomFunction, pathToFormatter) .. ")" .. "\n"; - if (debug) then ret = ret .. " print('# " .. propertyData.action .. "(" .. formatValueForAssignment(propertyData.type, change.value, pathToCustomFunction, pathToFormatter) .. "')\n"; end + ret = ret .. " region:" .. propertyData.action .. "(" + .. formatValueForAssignment(propertyData.type, change.value, + pathToCustomFunction, pathToFormatter, data) + .. ")" .. "\n"; + if (debug) then + ret = ret .. " print('# " .. propertyData.action .. "(" + .. formatValueForAssignment(propertyData.type, change.value, + pathToCustomFunction, pathToFormatter, data) + .. "')\n"; + end end end end @@ -453,8 +527,10 @@ local function CreateActivateCondition(ret, id, condition, conditionNumber, prop local propertyData = properties and properties[change.property] if (propertyData and propertyData.type and propertyData.setter) then ret = ret .. " if(propertyChanges['" .. change.property .. "'] ~= nil) then\n" - ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, change.value) .. "\n"; - if (debug) then ret = ret .. " print('- " .. change.property .. " " .. formatValueForAssignment(propertyData.type, change.value) .. "')\n"; end + ret = ret .. " propertyChanges['" .. change.property .. "'] = " + .. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "\n" + if (debug) then ret = ret .. " print('- " .. change.property .. " " + .. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "')\n" end ret = ret .. " end\n" end end @@ -539,7 +615,7 @@ function Private.LoadConditionPropertyFunctions(data) end return change.value[fullKey] end - local formatters = change.value and Private.CreateFormatters(change.value.message, getter, true) + local formatters = change.value and Private.CreateFormatters(change.value.message, getter, true, data) Private.ExecEnv.conditionTextFormatters[id] = Private.ExecEnv.conditionTextFormatters[id] or {} Private.ExecEnv.conditionTextFormatters[id][conditionNumber] = Private.ExecEnv.conditionTextFormatters[id][conditionNumber] or {}; Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes = Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes or {}; @@ -631,7 +707,7 @@ local function ConstructConditionFunction(data) for conditionNumber, condition in ipairs(data.conditions) do local nextIsLinked = data.conditions[conditionNumber + 1] and data.conditions[conditionNumber + 1].linked local additionalRecheckCode - ret, additionalRecheckCode = CreateCheckCondition(data.uid, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug) + ret, additionalRecheckCode = CreateCheckCondition(data, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug) if additionalRecheckCode then recheckCode = recheckCode .. "\n" .. additionalRecheckCode end @@ -659,7 +735,7 @@ local function ConstructConditionFunction(data) -- Third Loop deals with conditions that are newly active if (data.conditions) then for conditionNumber, condition in ipairs(data.conditions) do - ret = CreateActivateCondition(ret, data.id, condition, conditionNumber, properties, debug) + ret = CreateActivateCondition(ret, data.id, condition, conditionNumber, data, properties, debug) end end diff --git a/WeakAuras/GenericTrigger.lua b/WeakAuras/GenericTrigger.lua index 96b2f48..8aea94f 100644 --- a/WeakAuras/GenericTrigger.lua +++ b/WeakAuras/GenericTrigger.lua @@ -28,15 +28,9 @@ Modernizes all generic triggers in data. # Helper functions mainly for the WeakAuras Options # ##################################################### -CanHaveDuration(data, triggernum) -Returns whether the trigger can have a duration. - GetOverlayInfo(data, triggernum) Returns a table containing the names of all overlays -CanHaveClones(data) -Returns whether the trigger can have clones. - CanHaveTooltip(data, triggernum) Returns the type of tooltip to show for the trigger. @@ -46,6 +40,9 @@ Returns the name and icon to show in the options. GetAdditionalProperties(data, triggernum) Returns the a tooltip for the additional properties. +GetProgressSources(data, triggernum, outValues) +Fills outValues with the potential progress sources + GetTriggerConditions(data, triggernum) Returns potential conditions that this trigger provides. ]]-- @@ -520,18 +517,20 @@ local function RunOverlayFuncs(event, state, id, errorHandler) state.changed = changed or state.changed; end -local function callFunctionForActivateEvent(func, trigger, fallback, errorHandler) +local function callFunctionForActivateEvent(func, trigger, state, property, errorHandler) if not func then - return fallback + return end local ok, value = pcall(func, trigger) - if ok and value then - return value + if ok then + if state[property] ~= value then + state[property] = value + state.changed = true + end else if not ok then errorHandler(value) end - return fallback end end @@ -638,32 +637,13 @@ function Private.ActivateEvent(id, triggernum, data, state, errorHandler) end end - local name = callFunctionForActivateEvent(data.nameFunc, data.trigger, state.name, errorHandler or Private.GetErrorHandlerId(id, L["Name Function"])) - local icon = callFunctionForActivateEvent(data.iconFunc, data.trigger, state.icon, errorHandler or Private.GetErrorHandlerId(id, L["Icon Function"])) - local texture = callFunctionForActivateEvent(data.textureFunc, data.trigger, state.texture, errorHandler or Private.GetErrorHandlerId(id, L["Texture Function"])) - local stacks = callFunctionForActivateEvent(data.stacksFunc, data.trigger, state.stacks, errorHandler or Private.GetErrorHandlerId(id, L["Stacks Function"])) - - if (state.name ~= name) then - state.name = name; - changed = true; - end - if (state.icon ~= icon) then - state.icon = icon; - changed = true; - end - if (state.texture ~= texture) then - state.texture = texture; - changed = true; - end - if (state.stacks ~= stacks) then - state.stacks = stacks; - changed = true; - end + callFunctionForActivateEvent(data.nameFunc, data.trigger, state, "name", errorHandler or Private.GetErrorHandlerId(id, L["Name Function"])) + callFunctionForActivateEvent(data.iconFunc, data.trigger, state, "icon", errorHandler or Private.GetErrorHandlerId(id, L["Icon Function"])) + callFunctionForActivateEvent(data.textureFunc, data.trigger, state, "texture", errorHandler or Private.GetErrorHandlerId(id, L["Texture Function"])) + callFunctionForActivateEvent(data.stacksFunc, data.trigger, state, "stacks", errorHandler or Private.GetErrorHandlerId(id, L["Stacks Function"])) if (data.overlayFuncs) then RunOverlayFuncs(data, state, id, errorHandler); - else - state.additionalProgress = nil; end state.changed = state.changed or changed; @@ -1016,10 +996,34 @@ function Private.ScanEventsWatchedTrigger(id, watchedTriggernums) Private.ActivateAuraEnvironment(nil) end -local function AddFakeInformation(state, eventData) +local function ProgressType(data, triggernum) + local trigger = data.triggers[triggernum].trigger + local prototype = GenericTrigger.GetPrototype(trigger) + if prototype then + if prototype.progressType then + local progressType = prototype.progressType + if type(progressType) == "function" then + progressType = progressType(trigger) + end + return progressType + elseif prototype.timedrequired then + return "timed" + end + elseif (trigger.type == "custom") then + if trigger.custom_type == "event" and trigger.custom_hide == "timed" and trigger.duration then + return "timed"; + elseif (trigger.customDuration and trigger.customDuration ~= "") then + return "timed"; + elseif (trigger.custom_type == "stateupdate") then + return "timed"; + end + end + return false +end + +local function AddFakeInformation(data, triggernum, state, eventData) state.autoHide = false - local canHaveDuration = eventData.prototype and eventData.prototype.canHaveDuration == "timed" - if canHaveDuration and state.expirationTime == nil then + if ProgressType(data, triggernum) == "timed" and state.expirationTime == nil then state.progressType = "timed" end if state.progressType == "timed" then @@ -1065,7 +1069,7 @@ function GenericTrigger.CreateFakeStates(id, triggernum) shown = shown + 1 end - AddFakeInformation(state, eventData) + AddFakeInformation(data, triggernum, state, eventData) end if shown == 0 then @@ -1073,7 +1077,7 @@ function GenericTrigger.CreateFakeStates(id, triggernum) GenericTrigger.CreateFallbackState(data, triggernum, state) allStates[""] = state - AddFakeInformation(state, eventData) + AddFakeInformation(data, triggernum, state, eventData) end Private.ActivateAuraEnvironment(nil); @@ -3550,40 +3554,6 @@ function GenericTrigger.GetPrototype(trigger) end end -function GenericTrigger.CanHaveDuration(data, triggernum) - local trigger = data.triggers[triggernum].trigger - - local prototype = GenericTrigger.GetPrototype(trigger) - if prototype then - if prototype.durationFunc then - if(type(prototype.init) == "function") then - prototype.init(trigger); - end - local current, maximum, custom = prototype.durationFunc(trigger); - current = type(current) ~= "number" and current or 0 - maximum = type(maximum) ~= "number" and maximum or 0 - if(custom) then - return {current = current, maximum = maximum}; - else - return "timed"; - end - elseif prototype.canHaveDuration then - return prototype.canHaveDuration, prototype.useModRate - elseif prototype.timedrequired then - return "timed" - end - elseif (trigger.type == "custom") then - if trigger.custom_type == "event" and trigger.custom_hide == "timed" and trigger.duration then - return "timed"; - elseif (trigger.customDuration and trigger.customDuration ~= "") then - return "timed"; - elseif (trigger.custom_type == "stateupdate") then - return "timed"; - end - end - return false -end - function GenericTrigger.GetDelay(data) if data.event then local prototype = GenericTrigger.GetPrototype(data.trigger) @@ -3670,10 +3640,6 @@ function GenericTrigger.GetOverlayInfo(data, triggernum) return result; end -function GenericTrigger.CanHaveClones(data) - return false; -end - function GenericTrigger.GetNameAndIcon(data, triggernum) local trigger = data.triggers[triggernum].trigger local icon, name @@ -3806,10 +3772,39 @@ function GenericTrigger.GetAdditionalProperties(data, triggernum) return ret; end +function GenericTrigger.GetProgressSources(data, triggernum, values) + local variables = GenericTrigger.GetTriggerConditions(data, triggernum) + if (type(variables) == "table") then + for var, varData in pairs(variables) do + if (type(varData) == "table") then + if (varData.type == "number" or varData.type == "timer" or varData.type == "elapsedTimer") + and not varData.noProgressSource + then + + tinsert(values, { + trigger = triggernum, + property = var, + type = varData.type, + display = varData.display, + total = varData.total, + inverse = varData.inverse, + paused = varData.paused, + remaining = varData.remaining + }) + end + end + end + end +end + local commonConditions = { expirationTime = { display = L["Remaining Duration"], type = "timer", + total = "duration", + inverse = "inverse", + paused = "paused", + remaining = "remaining", }, duration = { display = L["Total Duration"], @@ -3820,11 +3815,12 @@ local commonConditions = { type = "bool", test = function(state, needle) return (state.paused and 1 or 0) == needle - end + end, }, value = { display = L["Progress Value"], type = "number", + total = "total", }, total = { display = L["Progress Total"], @@ -3832,11 +3828,11 @@ local commonConditions = { }, stacks = { display = L["Stacks"], - type = "number" + type = "number", }, name = { display = L["Name"], - type = "string" + type = "string", } } @@ -3861,6 +3857,31 @@ function Private.ExpandCustomVariables(variables) end end +function Private.GetTsuConditionVariablesExpanded(id, triggernum) + if events[id][triggernum] and events[id][triggernum].tsuConditionVariables then + Private.ActivateAuraEnvironment(id, nil, nil, nil, true) + local result = GenericTrigger.GetTsuConditionVariables(id, triggernum) + Private.ActivateAuraEnvironment(nil) + if type(result) ~= "table" then + return nil + end + Private.ExpandCustomVariables(result) + -- Clean up, remove non table entries and check for a valid display name + for k, v in pairs(result) do + if type(v) ~= "table" then + result[k] = nil + elseif (v.display == nil or type(v.display) ~= "string") then + if type(k) == "string" then + v.display = k + else + result[k] = nil + end + end + end + return result + end +end + function GenericTrigger.GetTriggerConditions(data, triggernum) local trigger = data.triggers[triggernum].trigger @@ -3868,22 +3889,14 @@ function GenericTrigger.GetTriggerConditions(data, triggernum) if prototype then local result = {}; - local canHaveDuration = GenericTrigger.CanHaveDuration(data, triggernum); - local timedDuration = canHaveDuration; - local valueDuration = canHaveDuration; - if (canHaveDuration == "timed") then - valueDuration = false; - elseif (type(canHaveDuration) == "table") then - timedDuration = false; - end - - if (timedDuration) then + local progressType = ProgressType(data, triggernum); + if progressType == "timed" then result.expirationTime = commonConditions.expirationTime; result.duration = commonConditions.duration; result.paused = commonConditions.paused end - if (valueDuration) then + if progressType == "static" then result.value = commonConditions.value; result.total = commonConditions.total; end @@ -3935,6 +3948,22 @@ function GenericTrigger.GetTriggerConditions(data, triggernum) if (v.operator_types) then result[v.name].operator_types = v.operator_types; end + -- for ProgressSource + if v.noProgressSource then + result[v.name].noProgressSource = true + end + if v.progressTotal then + result[v.name].total = v.progressTotal + end + if v.progressInverse then + result[v.name].inverse = v.progressInverse + end + if v.progressPaused then + result[v.name].paused = v.progressPaused + end + if v.progressRemaining then + result[v.name].remaining = v.progressRemaining + end end end end @@ -3976,28 +4005,7 @@ function GenericTrigger.GetTriggerConditions(data, triggernum) return result; elseif (trigger.custom_type == "stateupdate") then - if (events[data.id][triggernum] and events[data.id][triggernum].tsuConditionVariables) then - Private.ActivateAuraEnvironment(data.id, nil, nil, nil, true) - local result = GenericTrigger.GetTsuConditionVariables(data.id, triggernum) - Private.ActivateAuraEnvironment(nil) - if (type(result)) ~= "table" then - return nil; - end - Private.ExpandCustomVariables(result) - for k, v in pairs(result) do - if (type(v) ~= "table") then - result[k] = nil; - elseif (v.display == nil or type(v.display) ~= "string") then - if (type(k) == "string") then - v.display = k; - else - result[k] = nil; - end - end - end - - return result; - end + return Private.GetTsuConditionVariablesExpanded(data.id, triggernum) end end diff --git a/WeakAuras/Modernize.lua b/WeakAuras/Modernize.lua index 1d8eab5..02ccb64 100644 --- a/WeakAuras/Modernize.lua +++ b/WeakAuras/Modernize.lua @@ -1469,5 +1469,28 @@ function Private.Modernize(data) migrateToTable(data.load, "itemequiped") end + --[[if data.internalVersion < 71 then + if data.regionType == 'icon' or data.regionType == 'aurabar' + or data.regionType == 'progresstexture' + or data.regionType == 'stopmotion' + then + data.progressSource = {-1, ""} + else + data.progressSource = nil + end + if data.subRegions then + for index, subRegionData in ipairs(data.subRegions) do + if subRegionData.type == "subtick" then + local tick_placement = subRegionData.tick_placement + subRegionData.tick_placements = {} + subRegionData.tick_placements[1] = tick_placement + subRegionData.progressSources = {{-2, ""}} + subRegionData.tick_placement = nil + end + end + end + + end]] + data.internalVersion = max(data.internalVersion or 0, WeakAuras.InternalVersion()) end diff --git a/WeakAuras/Prototypes.lua b/WeakAuras/Prototypes.lua index 93383b5..a593455 100644 --- a/WeakAuras/Prototypes.lua +++ b/WeakAuras/Prototypes.lua @@ -1662,11 +1662,12 @@ Private.event_prototypes = { test = "WeakAuras.UnitExistsFixed(unit, smart) and specificUnitCheck" } }, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Experience"] = { type = "unit", - canHaveDuration = false, + progressType = "static", events = { ["events"] = { "PLAYER_XP_UPDATE", @@ -1704,6 +1705,7 @@ Private.event_prototypes = { operator = "and", limit = 2 }, + progressTotal = "totalXP" }, { name = "totalXP", @@ -1805,7 +1807,7 @@ Private.event_prototypes = { ["Health"] = { type = "unit", includePets = "true", - canHaveDuration = true, + progressType = "static", events = function(trigger) local unit = trigger.unit local result = {} @@ -1872,6 +1874,7 @@ Private.event_prototypes = { operator = "and", limit = 2 }, + progressTotal = "maxhealth" }, { name = "value", @@ -1917,6 +1920,7 @@ Private.event_prototypes = { operator = "and", limit = 2 }, + progressTotal = "total" }, { name = "maxhealth", @@ -2111,7 +2115,7 @@ Private.event_prototypes = { }, ["Power"] = { type = "unit", - canHaveDuration = true, + progressType = "static", events = function(trigger) local unit = trigger.unit local result = {} @@ -2218,6 +2222,7 @@ Private.event_prototypes = { operator = "and", limit = 2 }, + progressTotal = "total" }, { name = "value", @@ -2270,6 +2275,7 @@ Private.event_prototypes = { operator = "and", limit = 2 }, + progressTotal = "total" }, { name = "maxpower", @@ -2899,12 +2905,13 @@ Private.event_prototypes = { display = WeakAuras.newFeatureString .. L["Extra Spell Id"], init = "arg", enable = function(trigger) - return trigger.subeventSuffix and (trigger.subeventSuffix == "_INTERRUPT" or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_DISPEL_FAILED" or trigger.subeventSuffix == "_STOLEN" or trigger.subeventSuffix == "_AURA_BROKEN_SPELL") + return trigger.subeventSuffix and (trigger.subeventSuffix == "_ABSORBED" or trigger.subeventSuffix == "_INTERRUPT" or trigger.subeventSuffix == "_DISPEL" or trigger.subeventSuffix == "_DISPEL_FAILED" or trigger.subeventSuffix == "_STOLEN" or trigger.subeventSuffix == "_AURA_BROKEN_SPELL") end, type = "spell", showExactOption = false, store = true, - conditionType = "number" + conditionType = "number", + noProgressSource = true }, { name = "extraSpellName", @@ -3106,6 +3113,7 @@ Private.event_prototypes = { countEvents = true, delayEvents = true, timedrequired = true, + progressType = "timed" }, ["Cooldown Progress (Spell)"] = { type = "spell", @@ -3206,7 +3214,7 @@ Private.event_prototypes = { return ret; end, statesParameter = "one", - canHaveDuration = "timed", + progressType = "timed", args = { { }, -- Ignore first argument (id) @@ -3266,7 +3274,8 @@ Private.event_prototypes = { display = L["Stacks"], type = "number", store = true, - conditionType = "number" + conditionType = "number", + progressTotal = "maxCharges" }, { name = "spellCount", @@ -3451,7 +3460,8 @@ Private.event_prototypes = { return icon; end, hasSpellID = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Charges Changed"] = { type = "spell", @@ -3535,7 +3545,8 @@ Private.event_prototypes = { return icon; end, hasSpellID = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Cooldown Progress (Item)"] = { type = "item", @@ -3701,6 +3712,7 @@ Private.event_prototypes = { end, hasItemID = true, automaticrequired = true, + progressType = "timed" }, ["Cooldown Progress (Equipment Slot)"] = { type = "item", @@ -3859,6 +3871,7 @@ Private.event_prototypes = { return GetInventoryItemTexture("player", trigger.itemSlot or 0) or "Interface\\Icons\\INV_Misc_QuestionMark"; end, automaticrequired = true, + progressType = "timed" }, ["Cooldown Ready (Item)"] = { type = "item", @@ -3896,7 +3909,8 @@ Private.event_prototypes = { return icon; end, hasItemID = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Cooldown Ready (Equipment Slot)"] = { type = "item", @@ -3927,7 +3941,8 @@ Private.event_prototypes = { return GetInventoryItemTexture("player", trigger.itemSlot or 0) or "Interface\\Icons\\INV_Misc_QuestionMark"; end, hasItemID = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["GTFO"] = { type = "addons", @@ -3947,7 +3962,8 @@ Private.event_prototypes = { conditionType = "select" }, }, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Global Cooldown"] = { type = "spell", @@ -3998,6 +4014,7 @@ Private.event_prototypes = { end, hasSpellID = true, automaticrequired = true, + progressType = "timed" }, ["Swing Timer"] = { type = "unit", @@ -4096,7 +4113,7 @@ Private.event_prototypes = { } }, automaticrequired = true, - canHaveDuration = true, + progressType = "timed", statesParameter = "one" }, ["Action Usable"] = { @@ -4184,7 +4201,7 @@ Private.event_prototypes = { type = "number", enable = function(trigger) return not(trigger.use_inverse) end, store = true, - conditionType = "number" + conditionType = "number", }, { name = "spellCount", @@ -4192,7 +4209,7 @@ Private.event_prototypes = { type = "number", enable = function(trigger) return not(trigger.use_inverse) end, store = true, - conditionType = "number" + conditionType = "number", }, { name = "inverse", @@ -4245,7 +4262,8 @@ Private.event_prototypes = { end end, hasSpellID = true, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Talent Known"] = { type = "unit", @@ -4351,6 +4369,7 @@ Private.event_prototypes = { }, automaticrequired = true, statesParameter = "one", + progressType = "none" }, ["Totem"] = { type = "spell", @@ -4366,7 +4385,7 @@ Private.event_prototypes = { force_events = "PLAYER_ENTERING_WORLD", name = L["Totem"], statesParameter = "full", - canHaveDuration = "timed", + progressType = "timed", triggerFunction = function(trigger) local ret = [[return function (states) @@ -4633,7 +4652,6 @@ Private.event_prototypes = { hidden = true, store = true, test = "true", - conditionType = "number" }, { name = "icon", @@ -4652,7 +4670,8 @@ Private.event_prototypes = { }, statesParameter = "one", hasItemID = true, - automaticrequired = true + automaticrequired = true, + progressType = "static" }, ["Stance/Form/Aura"] = { type = "unit", @@ -4751,7 +4770,8 @@ Private.event_prototypes = { end return icon or "Interface\\Icons\\Spell_Nature_WispSplode" end, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Weapon Enchant"] = { type = "item", @@ -4888,7 +4908,7 @@ Private.event_prototypes = { } }, automaticrequired = true, - canHaveDuration = true, + progressType = "timed", statesParameter = "one" }, ["Chat Message"] = { @@ -4993,7 +5013,8 @@ Private.event_prototypes = { }, countEvents = true, delayEvents = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, -- fixing later --[[["Spell Cast Succeeded"] = { @@ -5061,7 +5082,8 @@ Private.event_prototypes = { }, countEvents = true, delayEvents = true, - timedrequired = true + timedrequired = true, + progressType = "timed" },]] ["Ready Check"] = { type = "event", @@ -5072,7 +5094,8 @@ Private.event_prototypes = { args = {}, statesParameter = "one", delayEvents = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Combat Events"] = { type = "event", @@ -5096,7 +5119,8 @@ Private.event_prototypes = { statesParameter = "one", countEvents = true, delayEvents = true, - timedrequired = true + timedrequired = true, + progressType = "timed" }, ["Death Knight Rune"] = { type = "unit", @@ -5300,6 +5324,13 @@ Private.event_prototypes = { end end, automaticrequired = true, + progressType = function(trigger) + if trigger.use_rune then + return "timed" + else + return "static" + end + end }, ["Item Equipped"] = { type = "item", @@ -5351,7 +5382,8 @@ Private.event_prototypes = { return icon; end, hasItemID = true, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Equipment Set"] = { type = "item", @@ -5420,7 +5452,8 @@ Private.event_prototypes = { return numEquipped, numItems, true; end, hasItemID = true, - automaticrequired = true + automaticrequired = true, + progressType = "static" }, ["Threat Situation"] = { type = "unit", @@ -5468,7 +5501,7 @@ Private.event_prototypes = { ]]; return ret .. unitHelperFunctions.SpecificUnitCheck(trigger); end, - canHaveDuration = true, + progressType = "static", statesParameter = "unit", args = { { @@ -5667,7 +5700,7 @@ Private.event_prototypes = { AddWatchedUnits(trigger.unit, includePets) end, force_events = unitHelperFunctions.UnitChangedForceEventsWithPets, - canHaveDuration = "timed", + progressType = "timed", name = L["Cast"], init = function(trigger) trigger.unit = trigger.unit or "player"; @@ -6605,7 +6638,8 @@ Private.event_prototypes = { }, }, }, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Conditions"] = { type = "unit", @@ -6784,7 +6818,8 @@ Private.event_prototypes = { init = "WeakAuras.InstanceDifficulty()" }, }, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Spell Known"] = { @@ -6836,7 +6871,8 @@ Private.event_prototypes = { local _, _, icon = GetSpellInfo(trigger.spellId or 0); return icon; end, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Pet Behavior"] = { @@ -6910,7 +6946,8 @@ Private.event_prototypes = { test = "true" }, }, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Queued Action"] = { @@ -6951,7 +6988,8 @@ Private.event_prototypes = { local _, _, icon = GetSpellInfo(trigger.spellName or 0); return icon; end, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, ["Range Check"] = { @@ -7031,12 +7069,13 @@ Private.event_prototypes = { test = "UnitExists(unit)" } }, - automaticrequired = true + automaticrequired = true, + progressType = "none" }, --[[ Some day i will finish this, soonTM ["Currency"] = { type = "unit", - canHaveDuration = false, + progressType = "static", events = { ["events"] = { "CURRENCY_DISPLAY_UPDATE", diff --git a/WeakAuras/RegionTypes/AuraBar.lua b/WeakAuras/RegionTypes/AuraBar.lua index eb464a5..36063e8 100644 --- a/WeakAuras/RegionTypes/AuraBar.lua +++ b/WeakAuras/RegionTypes/AuraBar.lua @@ -9,6 +9,7 @@ local default = { icon = false, desaturate = false, iconSource = -1, + progressSource = {-1, "" }, texture = "Blizzard", width = 200, height = 15, @@ -38,7 +39,7 @@ local default = { zoom = 0 }; -Private.regionPrototype.AddAdjustedDurationToDefault(default); +Private.regionPrototype.AddProgressSourceToDefault(default) Private.regionPrototype.AddAlphaToDefault(default); local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; @@ -66,7 +67,7 @@ local properties = { values = {} }, displayIcon = { - display = {L["Icon"], L["Fallback"]}, + display = {L["Icon"], L["Manual"]}, setter = "SetIcon", type = "icon", }, @@ -149,6 +150,7 @@ local function GetProperties(data) end auraProperties.iconSource.values = Private.IconSources(data) + auraProperties.progressSource.values = Private.GetProgressSourcesForUi(data) return auraProperties; end @@ -725,6 +727,17 @@ local function GetTexCoordZoom(texWidth) return unpack(texCoord) end +local function FrameTick(self) + local expirationTime = self.expirationTime + local remaining = expirationTime - GetTime() + local duration = self.duration + local progress = duration ~= 0 and remaining / duration or 0; + if self.inverse then + progress = 1 - progress; + end + self:SetProgress(progress) +end + local funcs = { AnchorSubRegion = function(self, subRegion, anchorType, selfPoint, anchorPoint, anchorXOffset, anchorYOffset) if anchorType == "area" then @@ -816,12 +829,7 @@ local funcs = { self.height = height; self:Scale(self.scalex, self.scaley); end, - SetValue = function(self, value, total) - local progress = 0; - if (total ~= 0) then - progress = value / total; - end - + SetProgress = function(self, progress) if self.inverseDirection then progress = 1 - progress; end @@ -833,22 +841,31 @@ local funcs = { self.bar:SetValue(progress); end end, - SetTime = function(self, duration, expirationTime, inverse) - local remaining = expirationTime - GetTime(); - local progress = duration ~= 0 and remaining / duration or 0; - -- Need to invert? - if ( - (self.inverseDirection and not inverse) - or (inverse and not self.inverseDirection) - ) - then + UpdateValue = function(self) + local progress = 0; + if (self.total ~= 0) then + progress = self.value / self.total; + end + self:SetProgress(progress) + if self.FrameTick then + self.FrameTick = nil + self.subRegionEvents:RemoveSubscriber("FrameTick", self) + end + end, + UpdateTime = function(self) + local remaining = self.expirationTime - GetTime(); + local progress = self.duration ~= 0 and remaining / self.duration or 0; + if self.inverse then progress = 1 - progress; end - if (self.smoothProgress) then - self.bar.targetValue = progress - self.bar:SetSmoothedValue(progress); - else - self.bar:SetValue(progress); + self:SetProgress(progress) + if self.paused and self.FrameTick then + self.FrameTick = nil + self.subRegionEvents:RemoveSubscriber("FrameTick", self) + end + if not self.paused and not self.FrameTick then + self.FrameTick = FrameTick + self.subRegionEvents:AddSubscriber("FrameTick", self) end end, SetInverse = function(self, inverse) @@ -1061,14 +1078,6 @@ local function create(parent) return region; end -local function TimerTick(self) - local state = self.state - local duration = state.duration or 0 - local adjustMin = self.adjustedMin or self.adjustedMinRel or 0; - local expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; - self:SetTime((duration ~= 0 and (self.adjustedMax or self.adjustedMaxRel) or duration) - adjustMin, expirationTime - adjustMin, state.inverse); -end - -- Modify a given region/display local function modify(parent, region, data) region.timer = nil @@ -1201,107 +1210,15 @@ local function modify(parent, region, data) region.tooltipFrame:EnableMouse(false); end - function region:UpdateMinMax() - local state = region.state - local min - local max - if state.progressType == "timed" then - local duration = state.duration or 0 - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * duration - end - - min = region.adjustedMin or region.adjustedMinRel or 0; - - if duration == 0 then - max = 0 - elseif region.adjustedMax then - max = region.adjustedMax - elseif region.adjustedMaxRelPercent then - region.adjustedMaxRel = region.adjustedMaxRelPercent * duration - max = region.adjustedMaxRel - else - max = duration - end - elseif state.progressType == "static" then - local total = state.total or 0; - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * total - end - min = region.adjustedMin or region.adjustedMinRel or 0; - - if region.adjustedMax then - max = region.adjustedMax - elseif region.adjustedMaxRelPercent then - region.adjustedMaxRel = region.adjustedMaxRelPercent * total - max = region.adjustedMaxRel - else - max = total - end - end - region.currentMin, region.currentMax = min, max - end - - function region:GetMinMax() - return region.currentMin or 0, region.currentMax or 0 - end - - region.TimerTick = nil + region.FrameTick = nil function region:Update() - local state = region.state - region:UpdateMinMax() - if state.progressType == "timed" then - local expirationTime - if state.paused == true then - if not region.paused then - region:Pause() - end - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", self) - end - expirationTime = GetTime() + (state.remaining or 0) - else - if region.paused then - region:Resume() - end - if not region.TimerTick then - region.TimerTick = TimerTick - region.subRegionEvents:AddSubscriber("TimerTick", self, true) - end - expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; - end - local duration = state.duration or 0 - - region:SetTime(region.currentMax - region.currentMin, expirationTime - region.currentMin, state.inverse); - elseif state.progressType == "static" then - if region.paused then - region:Resume() - end - local value = state.value or 0; - local total = state.total or 0; - - region:SetValue(value - region.currentMin, region.currentMax - region.currentMin); - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", region) - end - else - if region.paused then - region:Resume() - end - region:SetTime(0, math.huge) - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", region) - end - end - + region:UpdateProgress() region:UpdateIcon() + end - local duration = state.duration or 0 - local effectiveInverse = (state.inverse and not region.inverseDirection) or (not state.inverse and region.inverseDirection); - region.bar:SetAdditionalBars(state.additionalProgress, region.overlays, region.overlaysTexture, region.currentMin, region.currentMax, effectiveInverse, region.overlayclip); + function region:SetAdditionalProgress(additionalProgress, currentMin, currentMax, inverse) + local effectiveInverse = (inverse and not region.inverseDirection) or (not inverse and region.inverseDirection); + region.bar:SetAdditionalBars(additionalProgress, region.overlays, region.overlaysTexture, currentMin, currentMax, effectiveInverse, region.overlayclip); end -- Scale update function diff --git a/WeakAuras/RegionTypes/Icon.lua b/WeakAuras/RegionTypes/Icon.lua index 567c47c..98df008 100644 --- a/WeakAuras/RegionTypes/Icon.lua +++ b/WeakAuras/RegionTypes/Icon.lua @@ -19,6 +19,7 @@ local default = { icon = true, desaturate = false, iconSource = -1, + progressSource = {-1, "" }, inverse = false, width = 64, height = 64, @@ -35,6 +36,7 @@ local default = { cooldownEdge = false }; +Private.regionPrototype.AddProgressSourceToDefault(default) Private.regionPrototype.AddAlphaToDefault(default); local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; @@ -95,7 +97,7 @@ local properties = { values = {} }, displayIcon = { - display = {L["Icon"], L["Fallback"]}, + display = {L["Icon"], L["Manual"]}, setter = "SetIcon", type = "icon", } @@ -106,12 +108,11 @@ Private.regionPrototype.AddProperties(properties, default); local function GetProperties(data) local result = CopyTable(properties) result.iconSource.values = Private.IconSources(data) + result.progressSource.values = Private.GetProgressSourcesForUi(data) return result end local function GetTexCoord(region, texWidth, aspectRatio, xOffset, yOffset) - xOffset = xOffset or 0 - yOffset = yOffset or 0 region.currentCoord = region.currentCoord or {} local usesMasque = false if region.MSQGroup then @@ -430,8 +431,8 @@ local function modify(parent, region, data) region.scaley = 1; region.keepAspectRatio = data.keepAspectRatio; region.zoom = data.zoom; - region.texXOffset = data.texXOffset - region.texYOffset = data.texYOffset + region.texXOffset = data.texXOffset or 0 + region.texYOffset = data.texYOffset or 0 region:UpdateSize() icon:SetDesaturated(data.desaturate); @@ -451,7 +452,27 @@ local function modify(parent, region, data) region.tooltipFrame:EnableMouse(false); end - cooldown:SetReverse(not data.inverse); + function region:SetInverse(inverse) + if region.inverse == inverse then + return + end + region.inverse = inverse + region:UpdateEffectiveInverse() + end + function region:UpdateEffectiveInverse() + -- If cooldown.inverse == false then effectiveReverse = not inverse + -- If cooldown.inverse == true then effectiveReverse = inverse + local effectiveReverse = not region.inverse == not cooldown.inverse + cooldown:SetReverse(effectiveReverse) + if (cooldown.expirationTime and cooldown.duration and cooldown:IsShown()) then + -- WORKAROUND SetReverse not applying until next frame + cooldown:SetCooldown(0, 0) + cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration, + cooldown.duration, + cooldown.useCooldownModRate and cooldown.modRate or nil) + end + end + region:SetInverse(data.inverse) function region:Color(r, g, b, a) region.color_r = r; @@ -545,15 +566,6 @@ local function modify(parent, region, data) region:UpdateSize(); end - function region:SetInverse(inverse) - cooldown:SetReverse(not inverse); - if (cooldown.expirationTime and cooldown.duration and cooldown:IsShown()) then - -- WORKAROUND SetReverse not applying until next frame - cooldown:SetCooldown(0, 0); - cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration, cooldown.duration); - end - end - function region:SetCooldownEdge(cooldownEdge) region.cooldownEdge = cooldownEdge; cooldown:SetDrawEdge(cooldownEdge); @@ -570,32 +582,40 @@ local function modify(parent, region, data) cooldown.duration = nil; cooldown:Hide() if(data.cooldown) then - function region:SetValue(value, total) - cooldown.value = value - cooldown.total = total - if (value >= 0 and value <= total) then + function region:UpdateValue() + cooldown.value = self.value + cooldown.total = self.total + if (self.value >= 0 and self.value <= self.total) then cooldown:Show() - cooldown:SetCooldown(GetTime() - (total - value), total) + cooldown:SetCooldown(GetTime() - (self.total - self.value), self.total) + cooldown:Pause() else cooldown:Hide(); end end - function region:SetTime(duration, expirationTime) - if (duration > 0 and expirationTime > GetTime()) then - cooldown:Show(); - cooldown.expirationTime = expirationTime; - cooldown.duration = duration; - cooldown:SetCooldown(expirationTime - duration, duration); + function region:UpdateTime() + if self.paused then + cooldown:Pause() else - cooldown.expirationTime = expirationTime; - cooldown.duration = duration; + cooldown:Resume() + end + if (self.duration > 0 and self.expirationTime > GetTime() and self.expirationTime ~= math.huge) then + cooldown:Show(); + cooldown.expirationTime = self.expirationTime + cooldown.duration = self.duration + cooldown.inverse = self.inverse + region:UpdateEffectiveInverse() + cooldown:SetCooldown(self.expirationTime - self.duration, self.duration) + else + cooldown.expirationTime = self.expirationTime + cooldown.duration = self.duration cooldown:Hide(); end end function region:PreShow() - if (cooldown.duration and cooldown.duration > 0.01) then + if (cooldown.duration and cooldown.duration > 0.01 and cooldown.duration ~= math.huge and cooldown.expirationTime ~= math.huge) then cooldown:Show(); cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration, cooldown.duration); cooldown:Resume() @@ -603,64 +623,14 @@ local function modify(parent, region, data) end function region:Update() - local state = region.state - if state.progressType == "timed" then - local expirationTime - if state.paused == true then - if not region.paused then - region:Pause() - end - cooldown:Pause() - expirationTime = GetTime() + (state.remaining or 0) - else - if region.paused then - region:Resume() - end - cooldown:Resume() - expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; - end - - local duration = state.duration or 0 - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * duration - end - local adjustMin = region.adjustedMin or region.adjustedMinRel or 0; - - local max - if duration == 0 then - max = 0 - elseif region.adjustedMax then - max = region.adjustedMax - elseif region.adjustedMaxRelPercent then - region.adjustedMaxRel = region.adjustedMaxRelPercent * duration - max = region.adjustedMaxRel - else - max = duration - end - - region:SetTime(max - adjustMin, expirationTime - adjustMin, state.inverse); - elseif state.progressType == "static" then - local value = state.value or 0; - local total = state.total or 0; - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * total - end - local adjustMin = region.adjustedMin or region.adjustedMinRel or 0; - local max = region.adjustedMax or region.adjustedMaxRel or total; - region:SetValue(value - adjustMin, max - adjustMin); - cooldown:Pause() - else - region:SetTime(0, math.huge) - end - + region:UpdateProgress() region:UpdateIcon() end else - region.SetValue = nil - region.SetTime = nil + region.UpdateValue = nil + region.UpdateTime = nil function region:Update() - local state = region.state region:UpdateIcon() end end diff --git a/WeakAuras/RegionTypes/ProgressTexture.lua b/WeakAuras/RegionTypes/ProgressTexture.lua index 8fc2176..44f1887 100644 --- a/WeakAuras/RegionTypes/ProgressTexture.lua +++ b/WeakAuras/RegionTypes/ProgressTexture.lua @@ -80,6 +80,7 @@ local function Transform(tx, x, y, angle, aspect) -- Translates texture to x, y end local default = { + progressSource = {-1, "" }, foregroundTexture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3", backgroundTexture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3", desaturateBackground = false, @@ -115,7 +116,7 @@ local default = { Private.regionPrototype.AddAlphaToDefault(default); -Private.regionPrototype.AddAdjustedDurationToDefault(default); +Private.regionPrototype.AddProgressSourceToDefault(default) local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; @@ -180,9 +181,9 @@ Private.regionPrototype.AddProperties(properties, default); local function GetProperties(data) local overlayInfo = Private.GetOverlayInfo(data); + local auraProperties = CopyTable(properties) + auraProperties.progressSource.values = Private.GetProgressSourcesForUi(data) if (overlayInfo and next(overlayInfo)) then - local auraProperties = CopyTable(properties); - for id, display in ipairs(overlayInfo) do auraProperties["overlays." .. id] = { display = string.format(L["%s Overlay Color"], display), @@ -191,10 +192,9 @@ local function GetProperties(data) type = "color", } end - - return auraProperties; + return auraProperties else - return CopyTable(properties); + return auraProperties end end @@ -467,10 +467,27 @@ local function create(parent) return region; end -local function TimerTick(self) - local adjustMin = self.adjustedMin or self.adjustedMinRel or 0; - local duration = self.state.duration - self:SetTime( (duration ~= 0 and (self.adjustedMax or self.adjustedMaxRel) or duration) - adjustMin, self.state.expirationTime - adjustMin, self.state.inverse); +local function FrameTick(self) + local duration = self.duration + local expirationTime = self.expirationTime + local inverse = self.inverse + + local progress = 1; + if (duration ~= 0) then + local remaining = expirationTime - GetTime(); + progress = remaining / duration; + local inversed = (not inverse and self.inverseDirection) or (inverse and not self.inverseDirection); + if(inversed) then + progress = 1 - progress; + end + end + + progress = progress > 0.0001 and progress or 0.0001; + if (self.useSmoothProgress) then + self.smoothProgress:SetSmoothedValue(progress); + else + self:SetValueOnTexture(progress); + end end local function modify(parent, region, data) @@ -486,6 +503,7 @@ local function modify(parent, region, data) region.scalex = 1; region.scaley = 1; region.aspect = data.width / data.height; + region.useSmoothProgress = data.smoothProgress foreground:SetWidth(data.width); foreground:SetHeight(data.height); local scaleWedge = 1 / 1.4142 * (1 + (data.crop or 0.41)); @@ -843,123 +861,62 @@ local function modify(parent, region, data) region:Color(data.foregroundColor[1], data.foregroundColor[2], data.foregroundColor[3], data.foregroundColor[4]); - function region:SetTime(duration, expirationTime, inverse) + function region:UpdateTime() local progress = 1; - if (duration ~= 0) then - local remaining = expirationTime - GetTime(); - progress = remaining / duration; - local inversed = (not inverse and region.inverseDirection) or (inverse and not region.inverseDirection); + if (self.duration ~= 0) then + local remaining = self.expirationTime - GetTime() + progress = remaining / self.duration + local inversed = self.inverse ~= region.inverseDirection if(inversed) then progress = 1 - progress; end end progress = progress > 0.0001 and progress or 0.0001; - if (data.smoothProgress) then + if (region.useSmoothProgress) then region.smoothProgress:SetSmoothedValue(progress); else region:SetValueOnTexture(progress); end + + if self.paused and self.FrameTick then + self.FrameTick = nil + self.subRegionEvents:RemoveSubscriber("FrameTick", region) + end + if not self.paused and not self.FrameTick then + self.FrameTick = FrameTick + self.subRegionEvents:AddSubscriber("FrameTick", region) + end end - function region:SetValue(value, total) + function region:UpdateValue() local progress = 1 - if(total > 0) then - progress = value / total; + if(self.total > 0) then + progress = self.value / self.total; if(region.inverseDirection) then progress = 1 - progress; end end progress = progress > 0.0001 and progress or 0.0001; - if (data.smoothProgress) then + if (region.useSmoothProgress) then region.smoothProgress:SetSmoothedValue(progress); else region:SetValueOnTexture(progress); end end - region.TimerTick = nil - function region:Update() - local state = region.state - - local max - if state.progressType == "timed" then - local expirationTime - if state.paused == true then - if not region.paused then - region:Pause() - end - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", region) - end - expirationTime = GetTime() + (state.remaining or 0) - else - if region.paused then - region:Resume() - end - if not region.TimerTick then - region.TimerTick = TimerTick - region.subRegionEvents:AddSubscriber("TimerTick", region, true) - end - expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; - end - - local duration = state.duration or 0 - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * duration - end - local adjustMin = region.adjustedMin or region.adjustedMinRel or 0; - if duration == 0 then - max = 0 - elseif region.adjustedMax then - max = region.adjustedMax - elseif region.adjustedMaxRelPercent then - region.adjustedMaxRel = region.adjustedMaxRelPercent * duration - max = region.adjustedMaxRel - else - max = duration - end - - region:SetTime(max - adjustMin, expirationTime - adjustMin, state.inverse); - elseif state.progressType == "static" then - if region.paused then - region:Resume() - end - - local value = state.value or 0; - local total = state.total or 0; - if region.adjustedMinRelPercent then - region.adjustedMinRel = region.adjustedMinRelPercent * total - end - local adjustMin = region.adjustedMin or region.adjustedMinRel or 0; - - if region.adjustedMax then - max = region.adjustedMax - elseif region.adjustedMaxRelPercent then - region.adjustedMaxRel = region.adjustedMaxRelPercent * total - max = region.adjustedMaxRel - else - max = total - end - - region:SetValue(value - adjustMin, max - adjustMin); - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", region) - end - else - if region.paused then - region:Resume() - end - region:SetTime(0, math.huge) - if region.TimerTick then - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", region) - end + if region.useSmoothProgress then + region.PreShow = function() + region.smoothProgress:ResetSmoothedValue(); end + else + region.PreShow = nil + end - max = max or 0 + region.FrameTick = nil + function region:Update() + region:UpdateProgress() + local state = region.state if state.texture then region:SetTexture(state.texture) diff --git a/WeakAuras/RegionTypes/RegionPrototype.lua b/WeakAuras/RegionTypes/RegionPrototype.lua index 5fbd1f5..edc9c18 100644 --- a/WeakAuras/RegionTypes/RegionPrototype.lua +++ b/WeakAuras/RegionTypes/RegionPrototype.lua @@ -11,67 +11,11 @@ function Private.regionPrototype.AddAlphaToDefault(default) default.alpha = 1.0; end --- Adjusted Duration - -function Private.regionPrototype.AddAdjustedDurationToDefault(default) - default.useAdjustededMax = false; - default.useAdjustededMin = false; -end - -function Private.regionPrototype.AddAdjustedDurationOptions(options, data, order) - options.useAdjustededMin = { - type = "toggle", - width = WeakAuras.normalWidth, - name = L["Set Minimum Progress"], - desc = L["Values/Remaining Time below this value are displayed as no progress."], - order = order - }; - - options.adjustedMin = { - type = "input", - validate = WeakAuras.ValidateNumericOrPercent, - width = WeakAuras.normalWidth, - order = order + 0.01, - name = L["Minimum"], - hidden = function() return not data.useAdjustededMin end, - desc = L["Enter static or relative values with %"] - }; - - options.useAdjustedMinSpacer = { - type = "description", - width = WeakAuras.normalWidth, - name = "", - order = order + 0.02, - hidden = function() return not (not data.useAdjustededMin and data.useAdjustededMax) end, - }; - - options.useAdjustededMax = { - type = "toggle", - width = WeakAuras.normalWidth, - name = L["Set Maximum Progress"], - desc = L["Values/Remaining Time above this value are displayed as full progress."], - order = order + 0.03 - }; - - options.adjustedMax = { - type = "input", - width = WeakAuras.normalWidth, - validate = WeakAuras.ValidateNumericOrPercent, - order = order + 0.04, - name = L["Maximum"], - hidden = function() return not data.useAdjustededMax end, - desc = L["Enter static or relative values with %"] - }; - - options.useAdjustedMaxSpacer = { - type = "description", - width = WeakAuras.normalWidth, - name = "", - order = order + 0.05, - hidden = function() return not (data.useAdjustededMin and not data.useAdjustededMax) end, - }; - - return options; +-- Progress Sources +function Private.regionPrototype.AddProgressSourceToDefault(default) + default.progressSource = {-1, ""} + default.useAdjustededMax = false + default.useAdjustededMin = false end local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; @@ -149,6 +93,28 @@ function Private.regionPrototype.AddProperties(properties, defaultsForRegion) isPercent = true } end + if defaultsForRegion and defaultsForRegion.progressSource then + properties["progressSource"] = { + display = L["Progress Source"], + setter = "SetProgressSource", + type = "progressSource", + values = {}, + } + + properties["adjustedMin"] = { + display = L["Minimum Progress"], + setter = "SetAdjustedMin", + type = "string", + validate = WeakAuras.ValidateNumericOrPercent, + } + + properties["adjustedMax"] = { + display = L["Maximum Progress"], + setter = "SetAdjustedMax", + type = "string", + validate = WeakAuras.ValidateNumericOrPercent, + } + end end local function SoundRepeatStop(self) @@ -373,62 +339,253 @@ local function GetRegionAlpha(self) return self.animAlpha or self.alpha or 1; end +local function SetProgressSource(self, progressSource) + self.progressSource = progressSource + self:UpdateProgress() +end +local function SetAdjustedMin(self, adjustedMin) + local percent = string.match(adjustedMin, "(%d+)%%") + if percent then + self.adjustedMinRelPercent = tonumber(percent) / 100 + self.adjustedMin = nil + else + self.adjustedMin = tonumber(adjustedMin) + self.adjustedMinRelPercent = nil + end + self:UpdateProgress() +end +local function SetAdjustedMax(self, adjustedMax) + local percent = string.match(adjustedMax, "(%d+)%%") + if percent then + self.adjustedMaxRelPercent = tonumber(percent) / 100 + else + self.adjustedMax = tonumber(adjustedMax) + end + self:UpdateProgress() +end + +local function GetProgressSource(self) + return self.progressSource +end + +local function GetMinMaxProgress(self) + return self.minProgress or 0, self.maxProgress or 0 +end +local function UpdateProgressFromState(self, minMaxConfig, state, progressSource) + local progressType = progressSource[2] + local property = progressSource[3] + local totalProperty = progressSource[4] + local inverseProperty = progressSource[5] + local pausedProperty = progressSource[6] + local remainingProperty = progressSource[7] + if progressType == "number" then + local value = state[property] or 0 + local total = totalProperty and state[totalProperty] or 0 + -- We don't care about inverse or paused + local adjustMin + if minMaxConfig.adjustedMin then + adjustMin = minMaxConfig.adjustedMin + elseif minMaxConfig.adjustedMinRelPercent then + adjustMin = minMaxConfig.adjustedMinRelPercent * total + else + adjustMin = 0 + end + local max + if minMaxConfig.adjustedMax then + max = minMaxConfig.adjustedMax + elseif minMaxConfig.adjustedMaxRelPercent then + max = minMaxConfig.adjustedMaxRelPercent * total + else + max = total + end + -- The output of UpdateProgress is setting various values on self + -- and calling UpdateTime/UpdateValue. Not an ideal interface, but + -- the animation code/sub elements needs those values in some convenient place + self.minProgress, self.maxProgress = adjustMin, max + self.progressType = "static" + self.value = value - adjustMin + self.total = max - adjustMin + if self.UpdateValue then + self:UpdateValue() + end + elseif progressType == "timer" then + local expirationTime + local paused = pausedProperty and state[pausedProperty] + local inverse = inverseProperty and state[inverseProperty] + local remaining + if paused then + remaining = remainingProperty and state[remainingProperty] + expirationTime = GetTime() + (remaining or 0) + else + expirationTime = state[property] or math.huge + end + local duration = totalProperty and state[totalProperty] or 0 + local adjustMin + if minMaxConfig.adjustedMin then + adjustMin = minMaxConfig.adjustedMin + elseif minMaxConfig.adjustedMinRelPercent then + adjustMin = minMaxConfig.adjustedMinRelPercent * duration + else + adjustMin = 0 + end + local max + if minMaxConfig.adjustedMax then + max = minMaxConfig.adjustedMax + elseif minMaxConfig.adjustedMaxRelPercent then + max = minMaxConfig.adjustedMaxRelPercent * duration + else + max = duration + end + self.minProgress, self.maxProgress = adjustMin, max + self.progressType = "timed" + self.duration = max - adjustMin + self.expirationTime = expirationTime - adjustMin + self.remaining = remaining + self.inverse = inverse + self.paused = paused + if self.UpdateTime then + self:UpdateTime() + end + elseif progressType == "elapsedTimer" then + local startTime = state[property] or math.huge + local duration = totalProperty and state[totalProperty] or 0 + local adjustMin + if minMaxConfig.adjustedMin then + adjustMin = minMaxConfig.adjustedMin + elseif minMaxConfig.adjustedMinRelPercent then + adjustMin = minMaxConfig.adjustedMinRelPercent * duration + else + adjustMin = 0 + end + local max + if minMaxConfig.adjustedMax then + max = minMaxConfig.adjustedMax + elseif minMaxConfig.adjustedMaxRelPercent then + max = minMaxConfig.adjustedMaxRelPercent * duration + else + max = duration + end + self.minProgress, self.maxProgress = adjustMin, max + self.progressType = "timed" + self.duration = max - adjustMin + self.expirationTime = startTime + adjustMin + self.duration + self.inverse = true + self.paused = false + self.remaining = nil + if self.UpdateTime then + self:UpdateTime() + end + end +end + +local autoTimedProgressSource = {-1, "timer", "expirationTime", "duration", "inverse", "paused", "remaining"} +local autoStaticProgressSource = {-1, "number", "value", "total", nil, nil, nil, nil} +local function UpdateProgressFromAuto(self, minMaxConfig, state) + if state.progressType == "timed" then + UpdateProgressFromState(self, minMaxConfig, state, autoTimedProgressSource) + elseif state.progressType == "static"then + UpdateProgressFromState(self, minMaxConfig, state, autoStaticProgressSource) + else + self.minProgress, self.maxProgress = nil, nil + self.progressType = "timed" + self.duration = 0 + self.expirationTime = math.huge + self.inverse = false + self.paused = true + self.remaining = math.huge + if self.UpdateTime then + self:UpdateTime() + end + end +end + +local function UpdateProgressFromManual(self, minMaxConfig, state, value, total) + value = type(value) == "number" and value or 0 + total = type(total) == "number" and total or 0 + local adjustMin + if minMaxConfig.adjustedMin then + adjustMin = minMaxConfig.adjustedMin + elseif minMaxConfig.adjustedMinRelPercent then + adjustMin = minMaxConfig.adjustedMinRelPercent * total + else + adjustMin = 0 + end + local max + if minMaxConfig.adjustedMax then + max = minMaxConfig.adjustedMax + elseif minMaxConfig.adjustedMaxRelPercent then + max = minMaxConfig.adjustedMaxRelPercent * total + else + max = total + end + self.minProgress, self.maxProgress = adjustMin, max + self.progressType = "static" + self.value = value - adjustMin + self.total = max - adjustMin + if self.UpdateValue then + self:UpdateValue() + end +end + +local function UpdateProgressFrom(self, progressSource, minMaxConfig, state, states, parent) + local trigger = progressSource and progressSource[1] or -1 + + if trigger == -2 then + -- sub element'a auto uses the whatever progress the main region has + UpdateProgressFromAuto(self, minMaxConfig, parent) + elseif trigger == -1 then + -- auto for regions uses the state + UpdateProgressFromAuto(self, minMaxConfig, state) + elseif trigger == 0 then + UpdateProgressFromManual(self, minMaxConfig, state, progressSource[3], progressSource[4]) + else + UpdateProgressFromState(self, minMaxConfig, states[trigger] or {}, progressSource) + end +end + +-- For regions +local function UpdateProgress(self) + UpdateProgressFrom(self, self.progressSource, self, self.state, self.states) +end + +Private.UpdateProgressFrom = UpdateProgressFrom + local function SetAnimAlpha(self, alpha) + if alpha then + if alpha > 1 then + alpha = 1 + elseif alpha < 0 then + alpha = 0 + end + end if (self.animAlpha == alpha) then return; end self.animAlpha = alpha; + local errorHandler = Private.GetErrorHandlerId(self.id, L["Custom Fade Animation"]) if (WeakAuras.IsOptionsOpen()) then local ok = pcall(self.SetAlpha, self, max(self.animAlpha or self.alpha or 1, 0.5)) if not ok then - Private.GetErrorHandlerId(self.id, L["Custom Fade Animation"]) + errorHandler() end else local ok = pcall(self.SetAlpha, self, self.animAlpha or self.alpha or 1) if not ok then - Private.GetErrorHandlerId(self.id, L["Custom Fade Animation"]) + errorHandler() end end self.subRegionEvents:Notify("AlphaChanged") end -local function SetTriggerProvidesTimer(self, timerTick) - self.triggerProvidesTimer = timerTick - self:UpdateTimerTick() -end - -local function TimerTickForRegion(region) - Private.StartProfileSystem("timer tick") - Private.StartProfileAura(region.id); - - region.subRegionEvents:Notify("TimerTick") - Private.StopProfileAura(region.id); - Private.StopProfileSystem("timer tick") -end - -local function UpdateTimerTick(self) - if self.triggerProvidesTimer and self.subRegionEvents:HasSubscribers("TimerTick") and self.toShow then - if not self:GetScript("OnUpdate") then - self:SetScript("OnUpdate", function() - TimerTickForRegion(self) - end); - end - else - if self:GetScript("OnUpdate") then - self:SetScript("OnUpdate", nil); - end - end -end - -local function UpdateFrameTick(self) +local function UpdateTick(self) if self.subRegionEvents:HasSubscribers("FrameTick") and self.toShow then - Private.FrameTick:AddSubscriber("FrameTick", self) + Private.FrameTick:AddSubscriber("Tick", self) else - Private.FrameTick:RemoveSubscriber("FrameTick", self) + Private.FrameTick:RemoveSubscriber("Tick", self) end end -local function FrameTick(self) +local function Tick(self) Private.StartProfileAura(self.id) self.values.lastCustomTextUpdate = nil self.subRegionEvents:Notify("FrameTick") @@ -484,12 +641,18 @@ function Private.regionPrototype.create(region) region.SetRegionAlpha = SetRegionAlpha; region.GetRegionAlpha = GetRegionAlpha; end + if defaultsForRegion and defaultsForRegion.progressSource then + region.SetProgressSource = SetProgressSource + region.GetProgressSource = GetProgressSource + region.SetAdjustedMin = SetAdjustedMin + region.SetAdjustedMax = SetAdjustedMax + end + region.UpdateProgress = UpdateProgress + region.GetMinMaxProgress = GetMinMaxProgress region.SetAnimAlpha = SetAnimAlpha; - region.SetTriggerProvidesTimer = SetTriggerProvidesTimer - region.UpdateTimerTick = UpdateTimerTick - region.UpdateFrameTick = UpdateFrameTick - region.FrameTick = FrameTick + region.UpdateTick = UpdateTick + region.Tick = Tick region.subRegionEvents = Private.CreateSubscribableObject() region.AnchorSubRegion = AnchorSubRegion @@ -498,14 +661,12 @@ function Private.regionPrototype.create(region) region:SetPoint("CENTER", UIParent, "CENTER") end --- SetDurationInfo - function Private.regionPrototype.modify(parent, region, data) region.state = nil region.states = nil region.subRegionEvents:ClearSubscribers() region.subRegionEvents:ClearCallbacks() - Private.FrameTick:RemoveSubscriber("FrameTick", region) + Private.FrameTick:RemoveSubscriber("Tick", region) local defaultsForRegion = Private.regionTypes[data.regionType] and Private.regionTypes[data.regionType].default; @@ -513,18 +674,20 @@ function Private.regionPrototype.modify(parent, region, data) region:SetRegionAlpha(data.alpha) end - local hasAdjustedMin = defaultsForRegion and defaultsForRegion.useAdjustededMin ~= nil and data.useAdjustededMin - and data.adjustedMin; - local hasAdjustedMax = defaultsForRegion and defaultsForRegion.useAdjustededMax ~= nil and data.useAdjustededMax - and data.adjustedMax; + local hasProgressSource = defaultsForRegion and defaultsForRegion.progressSource + local hasAdjustedMin = hasProgressSource and data.useAdjustededMin and data.adjustedMin + local hasAdjustedMax = hasProgressSource and data.useAdjustededMax and data.adjustedMax + region.progressSource = nil region.adjustedMin = nil - region.adjustedMinRel = nil region.adjustedMinRelPercent = nil region.adjustedMax = nil - region.adjustedMaxRel = nil region.adjustedMaxRelPercent = nil + if hasProgressSource then + region.progressSource = Private.AddProgressSourceMetaData(data, data.progressSource) + end + if (hasAdjustedMin) then local percent = string.match(data.adjustedMin, "(%d+)%%") if percent then @@ -576,7 +739,7 @@ function Private.regionPrototype.modify(parent, region, data) data.actions.start[fullKey] = default end return data.actions.start[fullKey] - end, true) + end, true, data) region.finishFormatters = Private.CreateFormatters(data.actions.finish.message, function(key, default) local fullKey = "message_format_" .. key @@ -584,7 +747,7 @@ function Private.regionPrototype.modify(parent, region, data) data.actions.finish[fullKey] = default end return data.actions.finish[fullKey] - end, true) + end, true, data) end function Private.regionPrototype.modifyFinish(parent, region, data) @@ -615,91 +778,56 @@ function Private.regionPrototype.modifyFinish(parent, region, data) end end - region.subRegionEvents:SetOnSubscriptionStatusChanged("TimerTick", function() - region:UpdateTimerTick() - end) - region:UpdateTimerTick() - region.subRegionEvents:SetOnSubscriptionStatusChanged("FrameTick", function() - region:UpdateFrameTick() + region:UpdateTick() end) - region:UpdateFrameTick() + region:UpdateTick() Private.ApplyFrameLevel(region) end -local function SetProgressValue(region, value, total) - local adjustMin = region.adjustedMin or 0; - local max = region.adjustedMax or total; - - region:SetValue(value - adjustMin, max - adjustMin); -end - -local regionsForFrameTick = {} - local frameForFrameTick = CreateFrame("Frame"); Private.frames["Frame Tick Frame"] = frameForFrameTick Private.FrameTick = Private.CreateSubscribableObject() Private.FrameTick.OnUpdateHandler = function() - if WeakAuras.IsOptionsOpen() then - return - end Private.StartProfileSystem("frame tick") - Private.FrameTick:Notify("FrameTick") + Private.FrameTick:Notify("Tick") Private.StopProfileSystem("frame tick") end -Private.FrameTick:SetOnSubscriptionStatusChanged("FrameTick", function() - if Private.FrameTick:HasSubscribers("FrameTick") then +Private.FrameTick:SetOnSubscriptionStatusChanged("Tick", function() + if Private.FrameTick:HasSubscribers("Tick") then frameForFrameTick:SetScript("OnUpdate", Private.FrameTick.OnUpdateHandler); else frameForFrameTick:SetScript("OnUpdate", nil) end end) -local function TimerTickForSetDuration(self) - local duration = self.duration - local adjustMin = self.adjustedMin or 0; - - local max - if duration == 0 then - max = 0 - elseif self.adjustedMax then - max = self.adjustedMax - else - max = duration - end - - self:SetTime(max - adjustMin, self.expirationTime - adjustMin, self.inverse); -end - -function Private.regionPrototype.AddSetDurationInfo(region) - if (region.SetValue and region.SetTime) then - region.generatedSetDurationInfo = true; - - -- WeakAuras no longer calls SetDurationInfo, but some people do that, - -- In that case we also need to overwrite TimerTick +function Private.regionPrototype.AddSetDurationInfo(region, uid) + if (region.UpdateValue and region.UpdateTime) then + -- WeakAuras no longer calls SetDurationInfo, but some people do that region.SetDurationInfo = function(self, duration, expirationTime, customValue, inverse) - self.duration = duration or 0 - self.expirationTime = expirationTime; - self.inverse = inverse; - + -- For now don't warn against SetDurationInfo + -- Private.AuraWarnings.UpdateWarning(uid, "SetDurationInfo", "warning", L["Aura is using deprecated SetDurationInfo"]) if customValue then - SetProgressValue(region, duration, expirationTime); - region.TimerTick = nil - region.subRegionEvents:RemoveSubscriber("TimerTick", self) - else local adjustMin = region.adjustedMin or 0; - region:SetTime((duration ~= 0 and region.adjustedMax or duration) - adjustMin, expirationTime - adjustMin, inverse); - - region.TimerTick = TimerTickForSetDuration - region.subRegionEvents:AddSubscriber("TimerTick", self, true) + local max = self.adjustedMax or expirationTime + region.progressType = "static" + region.value = duration - adjustMin + region.total = max - adjustMin + region:UpdateValue() + else + local adjustMin = self.adjustedMin or 0; + self.progressType = "timed" + self.duration = (duration ~= 0 and self.adjustedMax or duration) - adjustMin + self.expirationTime = expirationTime - adjustMin + self.inverse = inverse + self.paused = false + self.remaining = nil + self:UpdateTime() end end - elseif (region.generatedSetDurationInfo) then - region.generatedSetDurationInfo = nil; - region.SetDurationInfo = nil; end end @@ -808,8 +936,7 @@ function Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent region:SoundRepeatStop(); end - region:UpdateFrameTick() - region:UpdateTimerTick() + region:UpdateTick() end function region:Expand() if (region.toShow) then @@ -844,8 +971,7 @@ function Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent end parent:ActivateChild(data.id, cloneId); - region:UpdateFrameTick() - region:UpdateTimerTick() + region:UpdateTick() end elseif not(data.controlledChildren) then function region:Collapse() @@ -867,8 +993,7 @@ function Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent region:SoundRepeatStop(); end - region:UpdateFrameTick() - region:UpdateTimerTick() + region:UpdateTick() end function region:Expand() if data.anchorFrameType == "SELECTFRAME" @@ -915,8 +1040,7 @@ function Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent parent:UpdateBorder(region); end - region:UpdateFrameTick() - region:UpdateTimerTick() + region:UpdateTick() end end -- Stubs that allow for polymorphism @@ -926,16 +1050,6 @@ function Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent if not region.Expand then function region:Expand() end end - if not region.Pause then - function region:Pause() - self.paused = true - end - end - if not region.Resume then - function region:Resume() - self.paused = nil - end - end end do diff --git a/WeakAuras/RegionTypes/StopMotion.lua b/WeakAuras/RegionTypes/StopMotion.lua index 6b70798..df1e60c 100644 --- a/WeakAuras/RegionTypes/StopMotion.lua +++ b/WeakAuras/RegionTypes/StopMotion.lua @@ -5,6 +5,7 @@ local texture_data = WeakAuras.StopMotion.texture_data; local L = WeakAuras.L; local default = { + progressSource = {-1, "" }, foregroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion", backgroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion", desaturateBackground = false, @@ -44,6 +45,8 @@ local default = { hideBackground = true }; +Private.regionPrototype.AddProgressSourceToDefault(default) + local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; local properties = { @@ -87,6 +90,12 @@ local properties = { Private.regionPrototype.AddProperties(properties, default); +local function GetProperties(data) + local result = CopyTable(properties) + result.progressSource.values = Private.GetProgressSourcesForUi(data) + return result +end + local function create(parent) local frame = CreateFrame("Frame", nil, UIParent); frame.regionType = "stopmotion" @@ -150,10 +159,117 @@ local function SetFrameViaFrames(self, texture, frame) self:SetTexture(texture .. format("%03d", frame)); end +local function SetProgress(self, progress) + local frames + local startFrame = self.startFrame + local endFrame = self.endFrame + local inverse = self.inverseDirection + if (endFrame >= startFrame) then + frames = endFrame - startFrame + 1 + else + frames = startFrame - endFrame + 1 + startFrame, endFrame = endFrame, startFrame + inverse = not inverse + end + local frame = floor( (frames - 1) * progress) + startFrame + + if (inverse) then + frame = endFrame - frame + startFrame; + end + + if (frame > endFrame) then + frame = endFrame + end + + if (frame < startFrame) then + frame = startFrame + end + self.foreground:SetFrame(self.foregroundTexture, frame); +end + +local FrameTickFunctions = { + progressTimer = function(self) + Private.StartProfileSystem("stopmotion") + Private.StartProfileAura(self.id) + local remaining = self.expirationTime - GetTime() + local progress = 1 - (remaining / self.duration) + + self:SetProgress(progress) + + Private.StopProfileAura(self.id) + Private.StopProfileSystem("stopmotion") + end, + timed = function(self) + if (not self.startTime) then return end + + Private.StartProfileSystem("stopmotion") + Private.StartProfileAura(self.id) + + local timeSinceStart = (GetTime() - self.startTime) + local newCurrentFrame = floor(timeSinceStart * (self.frameRate or 15)) + if (newCurrentFrame == self.currentFrame) then + Private.StopProfileAura(self.id) + Private.StopProfileSystem("stopmotion") + return + end + + self.currentFrame = newCurrentFrame + + local frames + local startFrame = self.startFrame + local endFrame = self.endFrame + local inverse = self.inverseDirection + if (endFrame >= startFrame) then + frames = endFrame - startFrame + 1 + else + frames = startFrame - endFrame + 1 + startFrame, endFrame = endFrame, startFrame + inverse = not inverse + end + + local frame = 0 + if (self.animationType == "loop") then + frame = (newCurrentFrame % frames) + startFrame + elseif (self.animationType == "bounce") then + local direction = floor(newCurrentFrame / frames) % 2 + if (direction == 0) then + frame = (newCurrentFrame % frames) + startFrame + else + frame = endFrame - (newCurrentFrame % frames) + end + elseif (self.animationType == "once") then + frame = newCurrentFrame + startFrame + if (frame > endFrame) then + frame = endFrame + end + end + if (inverse) then + frame = endFrame - frame + startFrame + end + + if (frame > endFrame) then + frame = endFrame + end + + if (frame < startFrame) then + frame = startFrame + end + self.foreground:SetFrame(self.foregroundTexture, frame) + + Private.StopProfileAura(self.id) + Private.StopProfileSystem("stopmotion") + end, +} + local function modify(parent, region, data) Private.regionPrototype.modify(parent, region, data); region.foreground = region.foreground or {} region.background = region.background or {} + region.frameRate = data.frameRate + region.inverseDirection = data.inverse + region.animationType = data.animationType + region.foregroundTexture = data.foregroundTexture + region.FrameTick = nil local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]" local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]" @@ -364,101 +480,52 @@ local function modify(parent, region, data) function region:PreShow() region.startTime = GetTime(); + if region.FrameTick then + region:FrameTick() + end end - local function onUpdate() - if (not region.startTime) then return end + region.SetProgress = SetProgress - Private.StartProfileAura(region.id); - Private.StartProfileSystem("stopmotion") - local timeSinceStart = (GetTime() - region.startTime); - local newCurrentFrame = floor(timeSinceStart * (data.frameRate or 15)); - if (newCurrentFrame == region.currentFrame) then - Private.StopProfileAura(region.id); - Private.StopProfileSystem("stopmotion") - return; - end - - region.currentFrame = newCurrentFrame; - - local frames; - local startFrame = region.startFrame; - local endFrame = region.endFrame; - local inverse = data.inverse; - if (endFrame >= startFrame) then - frames = endFrame - startFrame + 1; - else - frames = startFrame - endFrame + 1; - startFrame, endFrame = endFrame, startFrame; - inverse = not inverse; - end - - local frame = 0; - if (data.animationType == "loop") then - frame = (newCurrentFrame % frames) + startFrame; - elseif (data.animationType == "bounce") then - local direction = floor(newCurrentFrame / frames) % 2; - if (direction == 0) then - frame = (newCurrentFrame % frames) + startFrame; - else - frame = endFrame - (newCurrentFrame % frames); - end - elseif (data.animationType == "once") then - frame = newCurrentFrame + startFrame - if (frame > endFrame) then - frame = endFrame; - end - elseif (data.animationType == "progress") then - if (not region.state) then - -- Do nothing - elseif (region.state.progressType == "static") then - local value = region.state.value or 0 - local total = region.state.total ~= 0 and region.state.total or 1 - frame = floor((frames - 1) * value / total) + startFrame; - else - local remaining - if region.state.paused then - remaining = region.state.remaining or 0; - else - remaining = region.state.expirationTime and (region.state.expirationTime - GetTime()) or 0; - end - local progress = region.state.duration and region.state.duration > 0 and (1 - (remaining / region.state.duration)) or 0; - frame = floor( (frames - 1) * progress) + startFrame; - end - end - - if (inverse) then - frame = endFrame - frame + startFrame; - end - - if (frame > endFrame) then - frame = endFrame - end - if (frame < startFrame) then - frame = startFrame - end - region.foreground:SetFrame(data.foregroundTexture, frame); - - Private.StopProfileAura(region.id); - Private.StopProfileSystem("stopmotion") - end; - - region.FrameTick = onUpdate; - if region.FrameTick then + if data.animationType == "loop" or data.animationType == "bounce" or data.animationType == "once" then + region.FrameTick = FrameTickFunctions.timed region.subRegionEvents:AddSubscriber("FrameTick", region, true) - end + function region:Update() + end - function region:Update() - if region.state.paused then - if not region.paused then - region:Pause() + elseif data.animationType == "progress" then + function region:Update() + region:UpdateProgress() + end + + function region:UpdateValue() + local progress = 0; + if (self.total ~= 0) then + progress = self.value / self.total end - else - if region.paused then - region:Resume() + self:SetProgress(progress) + if self.FrameTick then + self.FrameTick = nil + self.subRegionEvents:RemoveSubscriber("FrameTick", self) end end - onUpdate(); + + function region:UpdateTime() + if self.paused and self.FrameTick then + self.FrameTick = nil + self.subRegionEvents:RemoveSubscriber("FrameTick", self) + end + self.expirationTime = self.expirationTime + self.duration = self.duration + if not self.paused then + if not self.FrameTick then + self.FrameTick = FrameTickFunctions.progressTimer + self.subRegionEvents:AddSubscriber("FrameTick", self) + end + self:FrameTick() + end + + end end function region:SetForegroundDesaturated(b) @@ -488,4 +555,4 @@ local function validate(data) Private.EnforceSubregionExists(data, "subbackground") end -Private.RegisterRegionType("stopmotion", create, modify, default, properties, validate); +Private.RegisterRegionType("stopmotion", create, modify, default, GetProperties, validate); diff --git a/WeakAuras/RegionTypes/Text.lua b/WeakAuras/RegionTypes/Text.lua index 2b92c01..8948001 100644 --- a/WeakAuras/RegionTypes/Text.lua +++ b/WeakAuras/RegionTypes/Text.lua @@ -54,10 +54,6 @@ local properties = { Private.regionPrototype.AddProperties(properties, default); -local function GetProperties(data) - return properties; -end - local function create(parent) local region = CreateFrame("Frame", nil, parent); region.regionType = "text" @@ -68,9 +64,6 @@ local function create(parent) text:SetWordWrap(true); text:SetNonSpaceWrap(true); - region.duration = 0; - region.expirationTime = math.huge; - Private.regionPrototype.create(region); return region; @@ -220,7 +213,7 @@ local function modify(parent, region, data) end end - formatters = Private.CreateFormatters(texts, getter) + formatters = Private.CreateFormatters(texts, getter, false, data) end local customTextFunc = nil @@ -252,12 +245,11 @@ local function modify(parent, region, data) Update = UpdateText or function() end end - local TimerTick + local FrameTick if Private.ContainsPlaceHolders(self.displayText, "p") then - TimerTick = UpdateText + FrameTick = UpdateText end - local FrameTick if customTextFunc and data.customTextUpdate == "update" then if Private.ContainsCustomPlaceHolder(self.displayText) then FrameTick = function() @@ -269,7 +261,6 @@ local function modify(parent, region, data) self.Update = Update self.FrameTick = FrameTick - self.TimerTick = TimerTick if not UpdateText then local textStr = self.displayText @@ -285,11 +276,6 @@ local function modify(parent, region, data) self.subRegionEvents:RemoveSubscriber("FrameTick", self) end - if self.TimerTick then - self.subRegionEvents:AddSubscriber("TimerTick", self, true) - else - self.subRegionEvents:RemoveSubscriber("TimerTick", self) - end if self.Update and self.state then self:Update() end @@ -347,7 +333,7 @@ local function validate(data) Private.EnforceSubregionExists(data, "subbackground") end -Private.RegisterRegionType("text", create, modify, default, GetProperties, validate); +Private.RegisterRegionType("text", create, modify, default, properties, validate); -- Fallback region type diff --git a/WeakAuras/SubRegionTypes/SubText.lua b/WeakAuras/SubRegionTypes/SubText.lua index 1f41614..ba49f24 100644 --- a/WeakAuras/SubRegionTypes/SubText.lua +++ b/WeakAuras/SubRegionTypes/SubText.lua @@ -244,7 +244,7 @@ local function modify(parent, region, parentData, data, first) end return data[fullKey] end - region.subTextFormatters = Private.CreateFormatters(texts, getter) + region.subTextFormatters = Private.CreateFormatters(texts, getter, false, parentData) function region:ConfigureTextUpdate() local UpdateText @@ -273,12 +273,11 @@ local function modify(parent, region, parentData, data, first) Update = UpdateText end - local TimerTick + local FrameTick if Private.ContainsPlaceHolders(region.text_text, "p") then - TimerTick = UpdateText + FrameTick = UpdateText end - local FrameTick if parent.customTextFunc and parentData.customTextUpdate == "update" then if Private.ContainsCustomPlaceHolder(region.text_text) then FrameTick = function() @@ -293,7 +292,6 @@ local function modify(parent, region, parentData, data, first) region.Update = Update region.FrameTick = FrameTick - region.TimerTick = TimerTick if not UpdateText then if text:GetFont() then @@ -320,13 +318,6 @@ local function modify(parent, region, parentData, data, first) else parent.subRegionEvents:RemoveSubscriber("FrameTick", region) end - if self.TimerTick then - if visible then - parent.subRegionEvents:AddSubscriber("TimerTick", region) - end - else - parent.subRegionEvents:RemoveSubscriber("TimerTick", region) - end if self.Update and parent.state and visible then self:Update() end diff --git a/WeakAuras/SubRegionTypes/Tick.lua b/WeakAuras/SubRegionTypes/Tick.lua index 8737d94..04c9064 100644 --- a/WeakAuras/SubRegionTypes/Tick.lua +++ b/WeakAuras/SubRegionTypes/Tick.lua @@ -8,7 +8,8 @@ local default = function() tick_visible = true, tick_color = {1, 1, 1, 1}, tick_placement_mode = "AtValue", - tick_placement = "50", + tick_placements = {"50"}, + progressSources = {{-2, ""}}, automatic_length = true, tick_thickness = 2, tick_length = 30, @@ -41,12 +42,6 @@ local properties = { type = "list", values = Private.tick_placement_modes, }, - tick_placement = { - display = L["Placement"], - setter = "SetTickPlacement", - type = "number", - validate = WeakAuras.ValidateNumeric, - }, automatic_length = { display = L["Automatic Length"], setter = "SetAutomaticLength", @@ -91,6 +86,22 @@ local properties = { }, } +local function GetProperties(parentData, data) + local result = CopyTable(properties) + for i in ipairs(data.tick_placements) do + + result["tick_placement" .. i] = { + display = #data.tick_placements > 1 and L["Placement %i"]:format(i) or L["Placement"], + setter = "SetTickPlacementAt", + type = "number", + arg1 = i, + validate = WeakAuras.ValidateNumeric, + } + end + + return result +end + local auraBarAnchor = { ["HORIZONTAL"] = "LEFT", ["HORIZONTAL_INVERSE"] = "RIGHT", @@ -107,9 +118,7 @@ local auraBarAnchorInverse = { local function create() local subRegion = CreateFrame("Frame", nil, UIParent) - subRegion.texture = subRegion:CreateTexture() - subRegion.texture:SetDrawLayer("ARTWORK", 3) - subRegion.texture:SetAllPoints(subRegion) + subRegion.ticks = {} return subRegion end @@ -129,19 +138,14 @@ local function getRotatedPoints(degrees) end local funcs = { - Update = function(self, state) - self.trigger_inverse = state.inverse - self.state = state - if state.progressType == "timed" then - self.trigger_total = state.duration - elseif state.progressType == "static" then - self.trigger_total = state.total - else - self.trigger_total = nil + Update = function(self, state, states) + for i, progressSource in ipairs(self.progressSources) do + self.progressData[i] = {} + Private.UpdateProgressFrom(self.progressData[i], progressSource, {}, state, states, self.parent) end self:UpdateVisible() self:UpdateTickPlacement(); - self:UpdateTimerTick() + self:UpdateFrameTick() end, OrientationChanged = function(self) self.orientation = self.parent:GetEffectiveOrientation() @@ -161,7 +165,7 @@ local funcs = { self:UpdateTickSize() end, InverseChanged = function(self) - self.inverse = self.parent:GetInverse() + self.inverse_direction = self.parent:GetInverse() self:UpdateTickPlacement() end, SetVisible = function(self, visible) @@ -170,21 +174,29 @@ local funcs = { self:UpdateVisible() end end, - UpdateVisible = function(self) - local missingProgress = self.tick_placement_mode ~= "AtPercent" and not self.trigger_total - if self.tick_visible and not missingProgress then - self:Show() + UpdateVisibleOne = function(self, i) + if self.tick_visible and self.hasProgress[i] then + self.ticks[i]:Show() else - self:Hide() + self.ticks[i]:Hide() + end + end, + UpdateVisible = function(self) + for i in ipairs(self.ticks) do + self:UpdateVisibleOne(i) end end, SetTickColor = function(self, r, g, b, a) self.tick_color[1], self.tick_color[2], self.tick_color[3], self.tick_color[4] = r, g, b, a or 1 if self.use_texture then - self.texture:SetVertexColor(r, g, b, a or 1) + for _, tick in ipairs(self.ticks) do + tick:SetVertexColor(r, g, b, a or 1) + end self:UpdateTickDesaturated() else - self.texture:SetTexture(r, g, b, a or 1) + for _, tick in ipairs(self.ticks) do + tick:SetTexture(r, g, b, a or 1) + end end end, SetTickPlacementMode = function(self, placement_mode) @@ -192,74 +204,93 @@ local funcs = { self.tick_placement_mode = placement_mode self:UpdateTickPlacement() self:UpdateVisible() - self:UpdateTimerTick() + self:UpdateFrameTick() end end, - UpdateTimerTick = function(self) - if self.tick_placement_mode == "ValueOffset" and self.state and self.state.progressType == "timed" and not self.paused then - if not self.TimerTick then - self.TimerTick = self.UpdateTickPlacement - self.parent.subRegionEvents:AddSubscriber("TimerTick", self) + UpdateFrameTick = function(self) + local requiresFrameTick = false + if self.tick_placement_mode == "ValueOffset" then + for i, progress in ipairs(self.progressData) do + if progress.progressType == "timed" and not progress.paused then + requiresFrameTick = true + break + end + end + end + if requiresFrameTick then + if not self.FrameTick then + self.FrameTick = self.UpdateTickPlacement + self.parent.subRegionEvents:AddSubscriber("FrameTick", self) end else - if self.TimerTick then - self.TimerTick = nil - self.parent.subRegionEvents:RemoveSubscriber("TimerTick", self) + if self.FrameTick then + self.FrameTick = nil + self.parent.subRegionEvents:RemoveSubscriber("FrameTick", self) end end end, - SetTickPlacement = function(self, placement) + SetTickPlacementAt = function(self, tick, placement) placement = tonumber(placement) - if self.tick_placement ~= placement then - self.tick_placement = placement - self:UpdateTickPlacement() + if self.tick_placements[tick] ~= placement then + self.tick_placements[tick] = placement + self:UpdateTickPlacementOne(tick) end end, + -- For backwards compability + SetTickPlacement = function(self, placement) + self:SetTickPlacementAt(1, placement) + end, UpdateTickPlacement = function(self) - local offset, offsetx, offsety = self.tick_placement, 0, 0 + for i in ipairs(self.tick_placements) do + self:UpdateTickPlacementOne(i) + end + end, + UpdateTickPlacementOne = function(self, i) + local offsetx, offsety = 0, 0 local width = self.parentMajorSize - local minValue, maxValue = self.parent:GetMinMax() + local minValue, maxValue = self.parent:GetMinMaxProgress() local valueRange = maxValue - minValue + local inverse = self.inverse_direction + if self.parent.inverse then + inverse = not inverse + end local tick_placement if self.tick_placement_mode == "AtValue" then - tick_placement = self.tick_placement + tick_placement = self.tick_placements[i] elseif self.tick_placement_mode == "AtMissingValue" then - tick_placement = self.trigger_total and self.trigger_total - self.tick_placement + tick_placement = maxValue - self.tick_placements[i] elseif self.tick_placement_mode == "AtPercent" then - if self.tick_placement >= 0 and self.tick_placement <= 100 and self.trigger_total then - tick_placement = self.tick_placement * self.trigger_total / 100 + if self.tick_placements[i] >= 0 and self.tick_placements[i] <= 100 and maxValue then + tick_placement = minValue + self.tick_placements[i] * valueRange / 100 end elseif self.tick_placement_mode == "ValueOffset" then - if self.trigger_total and self.trigger_total ~= 0 then - if self.state.progressType == "timed" then - if self.state.paused then - if self.state.remaining then - tick_placement = self.state.remaining + self.tick_placement + if maxValue ~= 0 and self.progressData[i] then + if self.progressData[i].progressType == "timed" then + if self.progressData[i].paused then + if self.progressData[i].remaining then + tick_placement = self.progressData[i].remaining + self.tick_placements[i] end else - tick_placement = self.state.expirationTime - GetTime() + self.tick_placement + tick_placement = self.progressData[i].expirationTime - GetTime() + self.tick_placements[i] end - else - tick_placement = self.state.value + self.tick_placement + elseif self.progressType == "static" then + tick_placement = self.progressData[i].value + self.progressData[i].tick_placements[i] end end end + local offset local percent = valueRange ~= 0 and tick_placement and (tick_placement - minValue) / valueRange if not percent or (percent and percent < 0 or percent > 1) then - self.texture:Hide() offset = 0 + self.hasProgress[i] = false else - self.texture:Show() offset = percent * width + self.hasProgress[i] = true end - - local inverse = self.inverse - if self.trigger_inverse then - inverse = not inverse - end + self:UpdateVisible(i) if (self.orientation == "HORIZONTAL_INVERSE") or (self.orientation == "VERTICAL") then offset = -offset @@ -275,8 +306,10 @@ local funcs = { offsetx = offset end local side = inverse and auraBarAnchorInverse or auraBarAnchor - self:ClearAllPoints() - self:SetPoint("CENTER", self.parent.bar, side[self.orientation], offsetx + self.tick_xOffset, offsety + self.tick_yOffset) + self.ticks[i]:ClearAllPoints() + self.ticks[i]:SetPoint("CENTER", self.parent.bar, side[self.orientation], + offsetx + self.tick_xOffset, + offsety + self.tick_yOffset) end, SetAutomaticLength = function(self, automatic_length) if self.automatic_length ~= automatic_length then @@ -298,16 +331,24 @@ local funcs = { end, UpdateTickSize = function(self) if self.vertical then - self:SetHeight(self.tick_thickness) + for i, tick in ipairs(self.ticks) do + tick:SetHeight(self.tick_thickness) + end else - self:SetWidth(self.tick_thickness) + for i, tick in ipairs(self.ticks) do + tick:SetWidth(self.tick_thickness) + end end local length = self.automatic_length and self.parentMinorSize or self.tick_length if self.vertical then - self:SetWidth(length) + for i, tick in ipairs(self.ticks) do + tick:SetWidth(length) + end else - self:SetHeight(length) + for i, tick in ipairs(self.ticks) do + tick:SetHeight(length) + end end end, SetTickDesaturated = function(self, desaturate) @@ -317,7 +358,9 @@ local funcs = { end end, UpdateTickDesaturated = function(self) - self.texture:SetDesaturated(self.tick_desaturate) + for i, tick in ipairs(self.ticks) do + tick:SetDesaturated(self.tick_desaturate) + end end, SetTickRotation = function(self, degrees) if self.tick_rotation ~= degrees then @@ -326,7 +369,10 @@ local funcs = { end end, UpdateTickRotation = function(self) - self:UpdateTexCoord() + local rad = math.rad(self.tick_rotation) + for _, tick in ipairs(self.ticks) do + tick:SetRotation(rad) + end end, SetTickMirror = function(self, mirror) if self.mirror ~= mirror then @@ -335,7 +381,15 @@ local funcs = { end end, UpdateTickMirror = function(self) - self:UpdateTexCoord() + if self.mirror then + for _, tick in ipairs(self.ticks) do + tick:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0) + end + else + for _, tick in ipairs(self.ticks) do + tick:SetTexCoord(0, 0, 1, 0, 0, 1, 1, 1) + end + end end, SetTickBlendMode = function(self, mode) if self.tick_blend_mode ~= mode then @@ -345,27 +399,22 @@ local funcs = { end, UpdateTickBlendMode = function(self) if self.use_texture then - self.texture:SetBlendMode(self.tick_blend_mode) + for _, tick in ipairs(self.ticks) do + tick:SetBlendMode(self.tick_blend_mode) + end else - self.texture:SetBlendMode("BLEND") - end - end, - UpdateTexCoord = function(self) - local ulx, uly, llx, lly, urx, ury, lrx, lry = getRotatedPoints(self.tick_rotation); - if self.mirror then - self.texture:SetTexCoord(urx, ury, lrx, lry, ulx, uly, llx, lly); - else - self.texture:SetTexCoord(ulx, uly, llx, lly, urx, ury, lrx, lry); + for _, tick in ipairs(self.ticks) do + tick:SetBlendMode("BLEND") + end end end, } local function modify(parent, region, parentData, data, first) - region:SetParent(parent) region.orientation = parent.effectiveOrientation - region.inverse = parentData.inverse - region.trigger_inverse = false + region.inverse_direction = parentData.inverse + region.inverse = false region.vertical = region.orientation == "VERTICAL" or region.orientation == "VERTICAL_INVERSE" if (region.vertical) then region.parentMinorSize, region.parentMajorSize = parent.bar:GetRealSize() @@ -378,7 +427,35 @@ local function modify(parent, region, parentData, data, first) region.tick_visible = data.tick_visible region.tick_color = CopyTable(data.tick_color) region.tick_placement_mode = data.tick_placement_mode - region.tick_placement = tonumber(data.tick_placement) + region.tick_placements = {} + region.progressSources = {} + region.progressData = {} + for i, tick_placement in ipairs(data.tick_placements) do + local value = tonumber(tick_placement) + if region.tick_placement_mode == "ValueOffset" then + local progressSource = Private.AddProgressSourceMetaData(parentData, data.progressSources[i] or {-2, ""}) + if value and progressSource then + tinsert(region.tick_placements, value) + tinsert(region.progressSources, progressSource or {}) + end + else + if value then + tinsert(region.tick_placements, value) + end + end + + if region.ticks[i] == nil then + local texture = region:CreateTexture() + texture:SetDrawLayer("ARTWORK", 3) + texture:SetAllPoints(region) + region.ticks[i] = texture + end + end + + for i = #data.tick_placements + 1, #region.ticks do + region.ticks[i]:Hide() + end + region.automatic_length = data.automatic_length region.tick_thickness = data.tick_thickness region.tick_length = data.tick_length @@ -388,12 +465,16 @@ local function modify(parent, region, parentData, data, first) region.tick_xOffset = data.tick_xOffset region.tick_yOffset = data.tick_yOffset + region.hasProgress = {} + for k, v in pairs(funcs) do region[k] = v end if data.use_texture then - region.texture:SetTexture(data.tick_texture) + for _, tick in ipairs(region.ticks) do + tick:SetTexture(data.tick_texture) + end end region:SetVisible(data.tick_visible) @@ -410,11 +491,14 @@ local function modify(parent, region, parentData, data, first) parent.subRegionEvents:AddSubscriber("InverseChanged", region) parent.subRegionEvents:AddSubscriber("OnRegionSizeChanged", region) - region.TimerTick = nil + region.FrameTick = nil + region:ClearAllPoints() + region:SetAllPoints(parent.bar) end local function supports(regionType) return regionType == "aurabar" end -WeakAuras.RegisterSubRegionType("subtick", L["Tick"], supports, create, modify, onAcquire, onRelease, default, nil, properties); +WeakAuras.RegisterSubRegionType("subtick", L["Tick"], supports, create, modify, onAcquire, onRelease, + default, nil, GetProperties); diff --git a/WeakAuras/SubscribableObject.lua b/WeakAuras/SubscribableObject.lua index 614e334..092b001 100644 --- a/WeakAuras/SubscribableObject.lua +++ b/WeakAuras/SubscribableObject.lua @@ -4,7 +4,12 @@ local AddonName, Private = ... local WeakAuras = WeakAuras local L = WeakAuras.L -local SubscribableObject ={ +local SubscribableObject = +{ + events = {}, + subscribers = {}, + callbacks = {}, + ClearSubscribers = function(self) self.events = {} self.subscribers = {} @@ -76,12 +81,5 @@ local SubscribableObject ={ } function Private.CreateSubscribableObject() - local system = {} - for f, func in pairs(SubscribableObject) do - system[f] = func - system.events = {} - system.subscribers = {} - system.callbacks = {} - end - return system + return CopyTable(SubscribableObject) end diff --git a/WeakAuras/Types.lua b/WeakAuras/Types.lua index 30d44db..1c6862e 100644 --- a/WeakAuras/Types.lua +++ b/WeakAuras/Types.lua @@ -226,7 +226,7 @@ Private.format_types = { disabled = function() return get(symbol .. "_time_dynamic_threshold") == 0 end }) end, - CreateFormatter = function(symbol, get) + CreateFormatter = function(symbol, get, wihoutColor, data) local format = get(symbol .. "_time_format", 0) local threshold = get(symbol .. "_time_dynamic_threshold", 60) local precision = get(symbol .. "_time_precision", 1) @@ -237,7 +237,7 @@ Private.format_types = { end local formatter if threshold == 0 then - formatter = function(value, state) + formatter = function(value, state, trigger) if type(value) ~= 'number' or value == math.huge then return "" end @@ -248,7 +248,7 @@ Private.format_types = { end else local formatString = "%." .. precision .. "f" - formatter = function(value, state) + formatter = function(value, state, trigger) if type(value) ~= 'number' or value == math.huge then return "" end @@ -269,11 +269,11 @@ Private.format_types = { -- Special case %p and %t. Since due to how the formatting -- work previously, the time formatter only formats %p and %t -- if the progress type is timed! - return function(value, state) + return function(value, state, trigger) if not state or state.progressType ~= "timed" then return value end - return formatter(value, state) + return formatter(value, state, trigger) end else return formatter @@ -1290,6 +1290,11 @@ Private.orientation_with_circle_types = { ANTICLOCKWISE = L["Anticlockwise"] } +Private.gradient_orientations = { + HORIZONTAL = L["Horizontal"], + VERTICAL = L["Vertical"] +} + Private.talent_types = {} for tab = 1, 5 do for num_talent = 1, MAX_NUM_TALENTS do diff --git a/WeakAuras/WeakAuras.lua b/WeakAuras/WeakAuras.lua index 57d19b4..9ecfeae 100644 --- a/WeakAuras/WeakAuras.lua +++ b/WeakAuras/WeakAuras.lua @@ -1,6 +1,6 @@ local AddonName, Private = ... -local internalVersion = 69 +local internalVersion = 71 -- Lua APIs local insert = table.insert @@ -2874,22 +2874,16 @@ function Private.SetRegion(data, cloneId) local anim_cancelled = loginFinished and Private.CancelAnimation(region, true, true, true, true, true, true); regionTypes[regionType].modify(parent, region, data); - Private.regionPrototype.AddSetDurationInfo(region); + Private.regionPrototype.AddSetDurationInfo(region, data.uid) Private.regionPrototype.AddExpandFunction(data, region, cloneId, parent, parent.regionType) data.animation = data.animation or {}; data.animation.start = data.animation.start or {type = "none"}; data.animation.main = data.animation.main or {type = "none"}; data.animation.finish = data.animation.finish or {type = "none"}; - if(Private.CanHaveDuration(data)) then - data.animation.start.duration_type = data.animation.start.duration_type or "seconds"; - data.animation.main.duration_type = data.animation.main.duration_type or "seconds"; - data.animation.finish.duration_type = data.animation.finish.duration_type or "seconds"; - else - data.animation.start.duration_type = "seconds"; - data.animation.main.duration_type = "seconds"; - data.animation.finish.duration_type = "seconds"; - end + data.animation.start.duration_type = data.animation.start.duration_type or "seconds" + data.animation.main.duration_type = data.animation.main.duration_type or "seconds" + data.animation.finish.duration_type = data.animation.finish.duration_type or "seconds" if(cloneId) then clonePool[regionType] = clonePool[regionType] or {}; @@ -3395,8 +3389,6 @@ local function wrapTriggerSystemFunction(functionName, mode) return func; end -Private.CanHaveDuration = wrapTriggerSystemFunction("CanHaveDuration", "firstValue"); -Private.CanHaveClones = wrapTriggerSystemFunction("CanHaveClones", "or"); Private.CanHaveTooltip = wrapTriggerSystemFunction("CanHaveTooltip", "or"); -- This has to be in WeakAuras for now, because GetNameAndIcon can be called from the options -- before the Options has access to Private @@ -3405,7 +3397,7 @@ Private.GetTriggerDescription = wrapTriggerSystemFunction("GetTriggerDescription local wrappedGetOverlayInfo = wrapTriggerSystemFunction("GetOverlayInfo", "table"); -Private.GetAdditionalProperties = function(data, triggernum, ...) +Private.GetAdditionalProperties = function(data) local additionalProperties = "" for i = 1, #data.triggers do local triggerSystem = GetTriggerSystem(data, i); @@ -3429,6 +3421,121 @@ Private.GetAdditionalProperties = function(data, triggernum, ...) return additionalProperties end +Private.GetProgressSources = function(data) + local values = {} + if Private.IsGroupType(data) then + return values + end + for i = 1, #data.triggers do + local triggerSystem = GetTriggerSystem(data, i); + if (triggerSystem) then + triggerSystem.GetProgressSources(data, i, values) + end + end + return values +end + +Private.GetProgressSourceFor = function(data, trigger, property) + local values = {} + local triggerSystem = GetTriggerSystem(data, trigger); + if (triggerSystem) then + triggerSystem.GetProgressSources(data, trigger, values) + for _, v in ipairs(values) do + if v.property == property then + return {trigger, v.type, v.property, v.total, v.inverse, v.paused, v.remaining} + end + end + end + return nil +end + +-- In the aura data we only store trigger + property +-- But for the region we don't want to gather necessary meta data all the time +-- So we collect that in region:modify + on creation of the conditions function +Private.AddProgressSourceMetaData = function(data, progressSource) + if not progressSource then + return {} + end + local trigger = progressSource[1] + local property = progressSource[2] + if trigger == -2 then + return {-2, "auto", ""} + elseif trigger == -1 then + return {-1, "auto", ""} + elseif trigger == 0 then + return {0, "manual", progressSource[3], progressSource[4]} + else + return Private.GetProgressSourceFor(data, trigger, property) + end +end + +-- ProgressSource values +-- For AceOptions to work correctly progress sources need to be comparable +-- via ==. We use a constants table so that identical tables use the same table +-- Additional while data.progressSource does contain additional data e.g. for manual progress +-- This is only for the progress source combobox, which only cares about the first or first two values +-- The greatness of the hacks knows no bounds +-- The constants table has weak keys +do + local function CompareProgressValueTables(a, b) + -- For auto/manual progreess, only compare a[] with b[1] + if a[1] == -1 or a[1] == 0 then + return a[1] == b[1] + end + -- Only care about trigger + property + return a[1] == b[1] and a[2] == b[2] + end + + local progressValueConstants = {} + setmetatable(progressValueConstants, {_mode = "v"}) + + function Private.GetProgressValueConstant(v) + if v == nil then + return v + end + + -- This uses pairs because there could be empty slots + for _, constant in pairs(progressValueConstants) do + if CompareProgressValueTables(v, constant) then + return constant + end + end + -- And this inserts into the first empty slot for the array + tinsert(progressValueConstants, v) + return v + end +end + +function Private.GetProgressSourcesForUi(data, subelement) + local values + + if subelement then + -- Sub elements Automatic means to use the main auras' progress + values = { + [{-2, ""}] = L["Automatic"] + } + else + values = { + [{-1, ""}] = L["Automatic"], + [{0, ""}] = L["Manual"], + } + end + + local triggerValues = Private.GetProgressSources(data) + for _, e in ipairs(triggerValues) do + if e.trigger and e.property then + values[{e.trigger, e.property}] = {L["Trigger %s"]:format(e.trigger), e.display} + end + end + + local result = {} + for k, v in pairs(values) do + result[Private.GetProgressValueConstant(k)] = v + end + + return result +end + function Private.GetOverlayInfo(data, triggernum) local overlayInfo; if (data.controlledChildren) then @@ -3926,59 +4033,65 @@ do end end +local function stopAutoHideTimer(id, triggernum, cloneId) + if(timers[id] and timers[id][triggernum] and timers[id][triggernum][cloneId]) then + local record = timers[id][triggernum][cloneId]; + if (record.handle) then + timer:CancelTimer(record.handle); + end + record.handle = nil; + record.expirationTime = nil; + record.state = nil + end +end + local function startStopTimers(id, cloneId, triggernum, state) - if (state.show) then - if (state.autoHide and state.duration and state.duration > 0 and not state.paused) then -- autohide, update timer - timers[id] = timers[id] or {}; - timers[id][triggernum] = timers[id][triggernum] or {}; - timers[id][triggernum][cloneId] = timers[id][triggernum][cloneId] or {}; - local record = timers[id][triggernum][cloneId]; - if (state.expirationTime == nil) then - state.expirationTime = GetTime() + state.duration; - end - if (record.expirationTime ~= state.expirationTime or record.state ~= state) then - if (record.handle ~= nil) then - timer:CancelTimer(record.handle); - end + if not state.show or not state.autoHide then + stopAutoHideTimer(id, triggernum, cloneId) + return + end - record.handle = timer:ScheduleTimer( - function() - if (state.show ~= false and state.show ~= nil) then - state.show = false; - state.changed = true; + -- state.autoHide can be a timer, or a boolean + -- if it's a bool, for backwards compability we look at paused + local expirationTime + if type(state.autoHide) == "boolean" then + if state.paused then + stopAutoHideTimer(id, triggernum, cloneId) + return + else + expirationTime = state.expirationTime + end + elseif type(state.autoHide) == "number" then + expirationTime = state.autoHide + end - -- if the trigger has updated then check to see if it is flagged for WatchedTrigger and send to queue if it is + timers[id] = timers[id] or {}; + timers[id][triggernum] = timers[id][triggernum] or {}; + timers[id][triggernum][cloneId] = timers[id][triggernum][cloneId] or {}; + local record = timers[id][triggernum][cloneId]; + if (record.expirationTime ~= expirationTime or record.state ~= state) then + if (record.handle ~= nil) then + timer:CancelTimer(record.handle); + end + + if expirationTime then + record.handle = timer:ScheduleTimer( + function() + if (state.show ~= false and state.show ~= nil) then + state.show = false; + state.changed = true; + + -- if the trigger has updated then check to see if it is flagged for WatchedTrigger and send to queue if it is if Private.watched_trigger_events[id] and Private.watched_trigger_events[id][triggernum] then Private.AddToWatchedTriggerDelay(id, triggernum) - end - - Private.UpdatedTriggerState(id); end - end, - state.expirationTime - GetTime()); - record.expirationTime = state.expirationTime; - record.state = state - end - else -- no auto hide, delete timer - if (timers[id] and timers[id][triggernum] and timers[id][triggernum][cloneId]) then - local record = timers[id][triggernum][cloneId]; - if (record.handle) then - timer:CancelTimer(record.handle); - end - record.handle = nil; - record.expirationTime = nil; - record.state = nil - end - end - else -- not shown - if(timers[id] and timers[id][triggernum] and timers[id][triggernum][cloneId]) then - local record = timers[id][triggernum][cloneId]; - if (record.handle) then - timer:CancelTimer(record.handle); - end - record.handle = nil; - record.expirationTime = nil; - record.state = nil + + Private.UpdatedTriggerState(id); + end + end, + expirationTime - GetTime()); + record.expirationTime = expirationTime; + record.state = state end end end @@ -4062,7 +4175,6 @@ local function ApplyStatesToRegions(id, activeTrigger, states) local applyChanges = not region.toShow or state.changed or region.state ~= state region.state = state region.states = region.states or {} - local needsTimerTick = false for triggernum = -1, triggerState[id].numTriggers do local triggerState if triggernum == activeTrigger then @@ -4078,11 +4190,8 @@ local function ApplyStatesToRegions(id, activeTrigger, states) end region.states[triggernum] = triggerState - needsTimerTick = needsTimerTick or (triggerState and triggerState.show and triggerState.progressType == "timed") end - region:SetTriggerProvidesTimer(needsTimerTick) - if (applyChanges) then ApplyStateToRegion(id, cloneId, region, parent); Private.RunConditions(region, data.uid, not state.show) @@ -4272,7 +4381,7 @@ function Private.RunCustomTextFunc(region, customFunc) return custom end -local function ReplaceValuePlaceHolders(textStr, region, customFunc, state, formatter) +local function ReplaceValuePlaceHolders(textStr, region, customFunc, state, formatter, trigger) local value; if string.sub(textStr, 1, 1) == "c" then local custom @@ -4297,7 +4406,7 @@ local function ReplaceValuePlaceHolders(textStr, region, customFunc, state, form end value = variable.get(state) if formatter then - value = formatter(value, state) + value = formatter(value, state, trigger) elseif variable.func then value = variable.func(value) end @@ -4431,12 +4540,12 @@ local function ValueForSymbol(symbol, region, customFunc, regionState, regionSta if regionStates[triggerNum][sym] then local value = regionStates[triggerNum][sym] if formatters[symbol] then - return tostring(formatters[symbol](value, regionStates[triggerNum]) or "") or "" + return tostring(formatters[symbol](value, regionStates[triggerNum], triggerNum) or "") or "" else return tostring(value) or "" end else - local value = ReplaceValuePlaceHolders(sym, region, customFunc, regionStates[triggerNum], formatters[symbol]); + local value = ReplaceValuePlaceHolders(sym, region, customFunc, regionStates[triggerNum], formatters[symbol], triggerNum); return value or "" end end @@ -4446,14 +4555,16 @@ local function ValueForSymbol(symbol, region, customFunc, regionState, regionSta if(useHiddenStates or regionState.show) then local value = regionState[symbol] if formatters[symbol] then - return tostring(formatters[symbol](value, regionState) or "") or "" + return tostring(formatters[symbol](value, regionState, triggerState[regionState.id].activeTrigger) or "") or "" else return tostring(value) or "" end end return "" else - local value = (useHiddenStates or regionState.show) and ReplaceValuePlaceHolders(symbol, region, customFunc, regionState, formatters[symbol]); + local activeTrigger = triggerState[regionState.id].activeTrigger + local value = (useHiddenStates or regionState.show) + and ReplaceValuePlaceHolders(symbol, region, customFunc, regionState, formatters[symbol], activeTrigger) return value or "" end end @@ -4589,7 +4700,7 @@ function Private.ParseTextStr(textStr, symbolCallback) end end -function Private.CreateFormatters(input, getter, withoutColor) +function Private.CreateFormatters(input, getter, withoutColor, data) local seenSymbols = {} local formatters = {} @@ -4603,7 +4714,7 @@ function Private.CreateFormatters(input, getter, withoutColor) local default = (sym == "p" or sym == "t") and "timed" or "none" local selectedFormat = getter(symbol .. "_format", default) if (Private.format_types[selectedFormat]) then - formatters[symbol] = Private.format_types[selectedFormat].CreateFormatter(symbol, getter, withoutColor) + formatters[symbol] = Private.format_types[selectedFormat].CreateFormatter(symbol, getter, withoutColor, data) end end end @@ -5492,8 +5603,8 @@ end function Private.IconSources(data) local values = { - [-1] = L["Dynamic Information"], - [0] = L["Fallback Icon"], + [-1] = L["Automatic"], + [0] = L["Manual Icon"], } for i = 1, #data.triggers do diff --git a/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasDisplayButton.lua b/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasDisplayButton.lua index cae4661..f6ba80b 100644 --- a/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasDisplayButton.lua +++ b/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasDisplayButton.lua @@ -990,9 +990,6 @@ local methods = { else OptionsPrivate.Private.GetTriggerDescription(data, -1, namestable) end - if(OptionsPrivate.Private.CanHaveClones(data)) then - tinsert(namestable, {" ", "|cFF00FF00"..L["Auto-cloning enabled"]}) - end local hasDescription = data.desc and data.desc ~= ""; local hasUrl = data.url and data.url ~= ""; diff --git a/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasTwoColumnDropDown.lua b/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasTwoColumnDropDown.lua index 59491e9..251b8d2 100644 --- a/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasTwoColumnDropDown.lua +++ b/WeakAurasOptions/AceGUI-Widgets/AceGUIWidget-WeakAurasTwoColumnDropDown.lua @@ -39,16 +39,18 @@ local methods = { if mode == "one" then self.firstDropdown.frame:Show() self.secondDropDown.frame:Hide() - self.firstDropdown.frame:SetAllPoints(self.frame) + self.firstDropdown.frame:ClearAllPoints() + self.firstDropdown.frame:SetPoint("TOPLEFT", self.frame) + self.firstDropdown.frame:SetPoint("TOPRIGHT", self.frame) else local halfWidth = self.frame:GetWidth() / 2 self.firstDropdown.frame:Show() self.secondDropDown.frame:Show() self.firstDropdown.frame:ClearAllPoints() self.firstDropdown.frame:SetPoint("TOPLEFT", self.frame) - self.firstDropdown.frame:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMLEFT", halfWidth, 0) + self.firstDropdown.frame:SetPoint("TOPRIGHT", self.frame, "TOPLEFT", halfWidth, 0) self.secondDropDown.frame:SetPoint("TOPLEFT", self.frame, halfWidth, 0) - self.secondDropDown.frame:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT") + self.secondDropDown.frame:SetPoint("TOPRIGHT", self.frame, "TOPRIGHT") end end, ["OnAcquire"] = function(widget) @@ -154,8 +156,11 @@ local methods = { self.firstDropdown = nil self.secondDropDown = nil end, - ["SetLabel"] = function(self, ...) - self.firstDropdown:SetLabel(...) + ["SetLabel"] = function(self, v) + if v == "" then + v = " " + end + self.firstDropdown:SetLabel(v) end, ["SetValue"] = function(self, value) for displayName, treeValue in pairs(self.userdata.tree) do diff --git a/WeakAurasOptions/AnimationOptions.lua b/WeakAurasOptions/AnimationOptions.lua index bc76cbf..20c7b2c 100644 --- a/WeakAurasOptions/AnimationOptions.lua +++ b/WeakAurasOptions/AnimationOptions.lua @@ -143,18 +143,6 @@ function OptionsPrivate.GetAnimationOptions(data) values = function() return filterAnimPresetTypes(anim_start_preset_types, id) end, hidden = function() return data.animation.start.type ~= "preset" end }, - start_duration_type_no_choice = { - type = "select", - width = WeakAuras.halfWidth, - name = L["Time in"], - order = 33, - values = duration_types_no_choice, - disabled = true, - hidden = function() - return data.animation.start.type ~= "custom" or OptionsPrivate.Private.CanHaveDuration(data) - end, - get = function() return "seconds" end - }, start_duration_type = { type = "select", width = WeakAuras.halfWidth, @@ -162,7 +150,7 @@ function OptionsPrivate.GetAnimationOptions(data) order = 33, values = duration_types, hidden = function() - return data.animation.start.type ~= "custom" or not OptionsPrivate.Private.CanHaveDuration(data) + return data.animation.start.type ~= "custom" end }, start_duration = { @@ -418,18 +406,6 @@ function OptionsPrivate.GetAnimationOptions(data) values = function() return filterAnimPresetTypes(anim_main_preset_types, id) end, hidden = function() return data.animation.main.type ~= "preset" end }, - main_duration_type_no_choice = { - type = "select", - width = WeakAuras.halfWidth, - name = L["Time in"], - order = 53, - values = duration_types_no_choice, - disabled = true, - hidden = function() - return data.animation.main.type ~= "custom" or OptionsPrivate.Private.CanHaveDuration(data) - end, - get = function() return "seconds" end - }, main_duration_type = { type = "select", width = WeakAuras.halfWidth, @@ -437,7 +413,7 @@ function OptionsPrivate.GetAnimationOptions(data) order = 53, values = duration_types, hidden = function() - return data.animation.main.type ~= "custom" or not OptionsPrivate.Private.CanHaveDuration(data) + return data.animation.main.type ~= "custom" end }, main_duration = { diff --git a/WeakAurasOptions/CommonOptions.lua b/WeakAurasOptions/CommonOptions.lua index 4b2af34..cb59f9d 100644 --- a/WeakAurasOptions/CommonOptions.lua +++ b/WeakAurasOptions/CommonOptions.lua @@ -1038,6 +1038,153 @@ local function CreateExecuteAll(subOption) end end +local function ProgressOptions(data) + local order = 1 + local options = { + __title = L["Progress Settings"], + __order = 98, + } + + options.progressSource = { + type = "select", + width = WeakAuras.doubleWidth, + name = L["Progress Source"], + order = order, + control = "WeakAurasTwoColumnDropdown", + values = OptionsPrivate.Private.GetProgressSourcesForUi(data), + get = function(info) + return OptionsPrivate.Private.GetProgressValueConstant(data.progressSource) + end, + set = function(info, value) + if value then + data.progressSource = data.progressSource or {} + -- Copy only trigger + property + data.progressSource[1] = value[1] + data.progressSource[2] = value[2] + else + data.progressSource = nil + end + WeakAuras.Add(data) + end + } + + options.progressSourceWarning = { + type = "description", + width = WeakAuras.doubleWidth, + name = L["Note: This progress source does not provide a total value/duration. A total value/duration must be set via \"Set Maximum Progress\""], + order = order + 0.5, + hidden = function() + local progressSource = OptionsPrivate.Private.AddProgressSourceMetaData(data, data.progressSource) + -- Auto progress, Manual Progress or the progress source has a total property + if not progressSource or progressSource[2] == "auto" or progressSource[1] == 0 or progressSource[4] ~= nil then + return true + end + return false + end + } + + local function hiddenManual() + if data.progressSource and data.progressSource[1] == 0 then + return false + end + return true + end + + options.progressSourceManualValue = { + type = "range", + control = "WeakAurasSpinBox", + width = WeakAuras.normalWidth, + name = L["Value"], + order = order + 0.7, + min = 0, + softMax = 100, + bigStep = 1, + hidden = hiddenManual, + get = function(info) + return data.progressSource and data.progressSource[3] or 0 + end, + set = function(info, value) + data.progressSource = data.progressSource or {} + data.progressSource[3] = value + WeakAuras.Add(data) + end + } + + options.progressSourceManualTotal = { + type = "range", + control = "WeakAurasSpinBox", + width = WeakAuras.normalWidth, + name = L["Total"], + order = order + 0.8, + min = 0, + softMax = 100, + bigStep = 1, + hidden = hiddenManual, + get = function(info) + return data.progressSource and data.progressSource[4] or 100 + end, + set = function(info, value) + data.progressSource = data.progressSource or {} + data.progressSource[4] = value + WeakAuras.Add(data) + end + } + + options.useAdjustededMin = { + type = "toggle", + width = WeakAuras.normalWidth, + name = L["Set Minimum Progress"], + desc = L["Values/Remaining Time below this value are displayed as zero progress."], + order = order + 1 + }; + + options.adjustedMin = { + type = "input", + validate = WeakAuras.ValidateNumericOrPercent, + width = WeakAuras.normalWidth, + order = order + 2, + name = L["Minimum"], + hidden = function() return not data.useAdjustededMin end, + desc = L["Enter static or relative values with %"] + }; + + options.useAdjustedMinSpacer = { + type = "description", + width = WeakAuras.normalWidth, + name = "", + order = order + 3, + hidden = function() return not (not data.useAdjustededMin and data.useAdjustededMax) end, + } + + options.useAdjustededMax = { + type = "toggle", + width = WeakAuras.normalWidth, + name = L["Set Maximum Progress"], + desc = L["Values/Remaining Time above this value are displayed as full progress."], + order = order + 4 + } + + options.adjustedMax = { + type = "input", + width = WeakAuras.normalWidth, + validate = WeakAuras.ValidateNumericOrPercent, + order = order + 5, + name = L["Maximum"], + hidden = function() return not data.useAdjustededMax end, + desc = L["Enter static or relative values with %"] + } + + options.useAdjustedMaxSpacer = { + type = "description", + width = WeakAuras.normalWidth, + name = "", + order = order + 6, + hidden = function() return not (data.useAdjustededMin and not data.useAdjustededMax) end, + } + + return options +end + local function PositionOptions(id, data, _, hideWidthHeight, disableSelfPoint, group) local metaOrder = 99 local function IsParentDynamicGroup() @@ -1617,6 +1764,7 @@ OptionsPrivate.commonOptions.CreateSetAll = CreateSetAll OptionsPrivate.commonOptions.CreateExecuteAll = CreateExecuteAll OptionsPrivate.commonOptions.PositionOptions = PositionOptions +OptionsPrivate.commonOptions.ProgressOptions = ProgressOptions OptionsPrivate.commonOptions.BorderOptions = BorderOptions OptionsPrivate.commonOptions.AddCodeOption = AddCodeOption diff --git a/WeakAurasOptions/ConditionOptions.lua b/WeakAurasOptions/ConditionOptions.lua index 2e9af6f..200090c 100644 --- a/WeakAurasOptions/ConditionOptions.lua +++ b/WeakAurasOptions/ConditionOptions.lua @@ -71,6 +71,17 @@ local function compareValues(a, b, propertytype) and a[2] == b[2] and a[3] == b[3] and a[4] == b[4]; + elseif propertytype == "progressSource" then + if type(a) == "table" and type(b) == "table" then + local triggerA, propertyA, triggerB, propertyB = a[1], a[2], b[1], b[2] + if triggerA ~= triggerB or propertyA ~= propertyB then + return false + end + if triggerA == 0 then + return a[3] == b[3] and a[4] == b[4] + end + return true + end end return a == b; end @@ -139,15 +150,36 @@ local function descIfSubset(data, reference, totalAuraCount) return ""; end -local function descIfNoValue(data, object, variable, type, values) +local function descIfNoValue(data, object, variable, propertyType, values) if (data.controlledChildren) then if (object["same" .. variable] == false) then local desc = ""; for id, reference in pairs(object.references) do - if (type == "list" and values) then + if propertyType == "list" and values then desc = desc .."|cFFE0E000".. id .. ": |r" .. (values[reference[variable]] or "") .. "\n"; + elseif propertyType == "progressSource" then + desc = desc .."|cFFE0E000".. id .. ": |r" + local progressSource = reference[variable] + if type(progressSource) == "table" then + local trigger = progressSource[1] + if trigger == 0 then + desc = desc .. L["Manual with %i/%i"]:format(progressSource[3] or 0, progressSource[4] or 100) + else + local p = OptionsPrivate.Private.GetProgressValueConstant(progressSource) + local description = values[p] or "" + if type(description) == "string" then + desc = desc .. description + elseif type(description) == "table" + and type(description[1]) == "string" + and type(description[2]) == "string" + then + desc = desc .. description[1] .. " " .. description[2] + end + end + end + desc = desc .."\n" else - desc = desc .."|cFFE0E000".. id .. ": |r" .. (valueToString(reference[variable], type) or "") .. "\n"; + desc = desc .."|cFFE0E000".. id .. ": |r" .. (valueToString(reference[variable], propertyType) or "") .. "\n"; end end return desc; @@ -298,6 +330,7 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA order = order + 1; local setValue; + local setValueTable local setValueColor; local setValueComplex; local setValueColorComplex; @@ -313,6 +346,17 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA conditions[i].changes[j].value = v; WeakAuras.ClearAndUpdateOptions(data.id) end + setValueTable = function(info, v) + for id, reference in pairs(conditions[i].changes[j].references) do + local auraData = WeakAuras.GetData(id) + local conditionIndex = conditions[i].check.references[id].conditionIndex + auraData[conditionVariable][conditionIndex].changes[reference.changeIndex].value = CopyTable(v) + WeakAuras.Add(auraData) + OptionsPrivate.ClearOptions(auraData.id) + end + conditions[i].changes[j].value = CopyTable(v) + WeakAuras.ClearAndUpdateOptions(data.id) + end setValueColor = function(info, r, g, b, a) for id, reference in pairs(conditions[i].changes[j].references) do local auraData = WeakAuras.GetData(id); @@ -332,7 +376,11 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA conditions[i].changes[j].value[4] = a; WeakAuras.ClearAndUpdateOptions(data.id) end - + setValueTable = function(info, v) + conditions[i].changes[j].value = CopyTable(v) + WeakAuras.Add(data) + WeakAuras.ClearAndUpdateOptions(data.id) + end setValueComplex = function(property) return function(info, v) for id, reference in pairs(conditions[i].changes[j].references) do @@ -531,21 +579,92 @@ local function addControlsForChange(args, order, data, conditionVariable, totalA set = setValueColor } order = order + 1; - elseif (propertyType == "list") then + elseif (propertyType == "list" or property == "progressSource") then local values = property and allProperties.propertyMap[property] and allProperties.propertyMap[property].values; args["condition" .. i .. "value" .. j] = { type = "select", width = WeakAuras.normalWidth, values = values, - name = blueIfNoValue(data, conditions[i].changes[j], "value", L["Differences"]), - desc = descIfNoValue(data, conditions[i].changes[j], "value", propertyType, values), + name = blueIfNoValue(data, conditions[i].changes[j], "value", L["Differences"], ""), + desc = descIfNoValue(data, conditions[i].changes[j], "value", propertyType, values), order = order, get = function() return conditions[i].changes[j].value; end, - set = setValue + set = setValue, } - order = order + 1; + order = order + 1 + + if propertyType == "progressSource" then + args["condition" .. i .. "value" .. j].control = "WeakAurasTwoColumnDropdown" + args["condition" .. i .. "value" .. j].set = setValueTable + args["condition" .. i .. "value" .. j].get = function() + local v = conditions[i].changes[j].value + return OptionsPrivate.Private.GetProgressValueConstant(v) + end + + args["condition" .. i .. "progressSourceWarning" .. j] = { + type = "description", + width = WeakAuras.doubleWidth, + name = L["Note: This progress source does not provide a total value/duration. A total value/duration must be set via \"Set Maximum Progress\""], + order = order, + hidden = function() + local v = conditions[i].changes[j].value + local progressSource = OptionsPrivate.Private.AddProgressSourceMetaData(data, v) + -- Auto progress, Manual Progress or the progress source has a total property + if progressSource[2] == "auto" or progressSource[1] == 0 or progressSource[4] ~= nil then + return true + end + return false + end + } + order = order + 1 + + local function hiddenManual() + local v = conditions[i].changes[j].value + local progressSource = OptionsPrivate.Private.AddProgressSourceMetaData(data, v) + if progressSource[1] == 0 then + return false + end + return true + end + + args["condition" .. i .. "progressSoruceManualValue" .. j] = { + type = "range", + control = "WeakAurasSpinBox", + width = WeakAuras.normalWidth, + name = L["Value"], + order = order, + min = 0, + softMax = 100, + bigStep = 1, + hidden = hiddenManual, + get = function() + local v = conditions[i].changes[j].value + return v and type(v[3]) == "number" and v[3] or 0 + end, + set = setValueComplex(3) + } + order = order + 1 + + args["condition" .. i .. "progressSoruceManualTotal" .. j] = { + type = "range", + control = "WeakAurasSpinBox", + width = WeakAuras.normalWidth, + name = L["Total"], + order = order, + min = 0, + softMax = 100, + bigStep = 1, + hidden = hiddenManual, + get = function() + local v = conditions[i].changes[j].value + return v and type(v[4]) == "number" and v[4] or 100 + end, + set = setValueComplex(4) + } + order = order + 1 + end elseif (propertyType == "sound") then args["condition" .. i .. "value" .. j .. "sound_type"] = { type = "select", @@ -2455,7 +2574,7 @@ local function buildAllPotentialProperties(data, category) allProperties.propertyMap[k].type = "incompatible"; end - if (allProperties.propertyMap[k].type == "list") then + if (allProperties.propertyMap[k].type == "list" or allProperties.propertyMap[k].type == "progressSource" ) then -- Merge value lists for key, value in pairs(v.values) do if (allProperties.propertyMap[k].values[key] == nil) then diff --git a/WeakAurasOptions/GenericTrigger.lua b/WeakAurasOptions/GenericTrigger.lua index 883f924..91a6882 100644 --- a/WeakAurasOptions/GenericTrigger.lua +++ b/WeakAurasOptions/GenericTrigger.lua @@ -317,6 +317,10 @@ local function GetCustomTriggerOptions(data, triggernum) test = "function", events = "table", values = "table", + total = "string", + inverse = "string", + paused = "string", + remaining = "string", } local function validateCustomVariables(variables) diff --git a/WeakAurasOptions/RegionOptions/AuraBar.lua b/WeakAurasOptions/RegionOptions/AuraBar.lua index 9d9bdb0..0929ac0 100644 --- a/WeakAurasOptions/RegionOptions/AuraBar.lua +++ b/WeakAurasOptions/RegionOptions/AuraBar.lua @@ -91,21 +91,21 @@ local function createOptions(id, data) width = WeakAuras.normalWidth, name = L["Bar Color"], hasAlpha = true, - order = 39.1 + order = 39.3 }, backgroundColor = { type = "color", width = WeakAuras.normalWidth, name = L["Background Color"], hasAlpha = true, - order = 39.2 + order = 39.5 }, alpha = { type = "range", control = "WeakAurasSpinBox", width = WeakAuras.normalWidth, name = L["Bar Alpha"], - order = 39.3, + order = 39.6, min = 0, max = 1, bigStep = 0.01, @@ -157,7 +157,7 @@ local function createOptions(id, data) displayIcon = { type = "input", width = WeakAuras.normalWidth - 0.15, - name = L["Fallback"], + name = L["Manual"], disabled = function() return not data.icon end, order = 40.5, get = function() @@ -385,8 +385,6 @@ local function createOptions(id, data) }, }; - options = OptionsPrivate.Private.regionPrototype.AddAdjustedDurationOptions(options, data, 36.5); - local overlayInfo = OptionsPrivate.Private.GetOverlayInfo(data); if (overlayInfo and next(overlayInfo)) then options["overlayheader"] = { @@ -450,6 +448,7 @@ local function createOptions(id, data) return { aurabar = options, + progressOptions = OptionsPrivate.commonOptions.ProgressOptions(data), position = OptionsPrivate.commonOptions.PositionOptions(id, data), }; end diff --git a/WeakAurasOptions/RegionOptions/Icon.lua b/WeakAurasOptions/RegionOptions/Icon.lua index ced05d2..5708a01 100644 --- a/WeakAurasOptions/RegionOptions/Icon.lua +++ b/WeakAurasOptions/RegionOptions/Icon.lua @@ -36,7 +36,7 @@ local function createOptions(id, data) displayIcon = { type = "input", width = WeakAuras.normalWidth - 0.15, - name = L["Fallback Icon"], + name = L["Manual Icon"], order = 4, get = function() return data.displayIcon and tostring(data.displayIcon) or ""; @@ -230,8 +230,7 @@ local function createOptions(id, data) name = L["Enable Swipe"], order = 11.1, desc = L["Enable the \"Swipe\" radial overlay"], - disabled = function() return not OptionsPrivate.Private.CanHaveDuration(data); end, - get = function() return OptionsPrivate.Private.CanHaveDuration(data) and data.cooldown; end + get = function() return data.cooldown; end }, inverse = { type = "toggle", @@ -239,8 +238,7 @@ local function createOptions(id, data) name = L["Inverse"], order = 11.2, desc = L["Invert the direction of progress"], - disabled = function() return not (OptionsPrivate.Private.CanHaveDuration(data) and data.cooldown); end, - get = function() return data.inverse and OptionsPrivate.Private.CanHaveDuration(data) and data.cooldown; end, + get = function() return data.inverse and data.cooldown; end, hidden = function() return not data.cooldown end }, cooldownEdge = { @@ -249,7 +247,6 @@ local function createOptions(id, data) name = L["Show \"Edge\""], order = 11.4, desc = "|TInterface\\AddOns\\WeakAuras\\Media\\Textures\\edge-example:30|t\n"..L["Enable \"Edge\" part of the overlay"], - disabled = function() return not OptionsPrivate.Private.CanHaveDuration(data) end, hidden = function() return not data.cooldown end, }, endHeader = { @@ -276,6 +273,7 @@ local function createOptions(id, data) return { icon = options, + progressOptions = OptionsPrivate.commonOptions.ProgressOptions(data), position = OptionsPrivate.commonOptions.PositionOptions(id, data), }; end diff --git a/WeakAurasOptions/RegionOptions/ProgressTexture.lua b/WeakAurasOptions/RegionOptions/ProgressTexture.lua index 442a456..48f1302 100644 --- a/WeakAurasOptions/RegionOptions/ProgressTexture.lua +++ b/WeakAurasOptions/RegionOptions/ProgressTexture.lua @@ -277,18 +277,12 @@ local function createOptions(id, data) hidden = function() return not data.slanted or data.orientation == "CLOCKWISE" or data.orientation == "ANTICLOCKWISE" end, values = OptionsPrivate.Private.slant_mode }, - spacer = { - type = "header", - name = "", - order = 56 - }, endHeader = { type = "header", order = 100, name = "", }, }; - options = OptionsPrivate.Private.regionPrototype.AddAdjustedDurationOptions(options, data, 57); local overlayInfo = OptionsPrivate.Private.GetOverlayInfo(data); if (overlayInfo and next(overlayInfo)) then @@ -332,6 +326,7 @@ local function createOptions(id, data) return { progresstexture = options, + progressOptions = OptionsPrivate.commonOptions.ProgressOptions(data), position = OptionsPrivate.commonOptions.PositionOptions(id, data), }; end diff --git a/WeakAurasOptions/RegionOptions/StopMotion.lua b/WeakAurasOptions/RegionOptions/StopMotion.lua index b232cf3..682d709 100644 --- a/WeakAurasOptions/RegionOptions/StopMotion.lua +++ b/WeakAurasOptions/RegionOptions/StopMotion.lua @@ -288,7 +288,7 @@ local function createOptions(id, data) name = L["Animation Start"], min = 0, max = 1, - --bigStep = 0.01, + bigStep = 0.01, order = 13, isPercent = true }, @@ -299,7 +299,7 @@ local function createOptions(id, data) name = L["Animation End"], min = 0, max = 1, - --bigStep = 0.01, + bigStep = 0.01, order = 14, isPercent = true }, @@ -534,17 +534,11 @@ local function createOptions(id, data) } }; - if OptionsPrivate.commonOptions then - return { - stopmotion = options, - position = OptionsPrivate.commonOptions.PositionOptions(id, data, 2), - }; - else - return { - stopmotion = options, - position = WeakAuras.PositionOptions(id, data, 2), - }; - end + return { + stopmotion = options, + progressOptions = OptionsPrivate.commonOptions.ProgressOptions(data), + position = OptionsPrivate.commonOptions.PositionOptions(id, data, 2), + } end local function createThumbnail() diff --git a/WeakAurasOptions/SubRegionOptions/Tick.lua b/WeakAurasOptions/SubRegionOptions/Tick.lua index fd88de7..49fb190 100644 --- a/WeakAurasOptions/SubRegionOptions/Tick.lua +++ b/WeakAurasOptions/SubRegionOptions/Tick.lua @@ -23,31 +23,51 @@ local function createOptions(parentData, data, index, subIndex) order = 2, hasAlpha = true, }, - tick_placement_mode = { - type = "select", - width = WeakAuras.normalWidth, - name = L["Tick Mode"], - order = 3, - values = OptionsPrivate.Private.tick_placement_modes, - }, - tick_placement = { - type = "input", - width = WeakAuras.normalWidth, - name = L["Tick Placement"], - order = 4, - validate = WeakAuras.ValidateNumeric, - desc = L["Enter in a value for the tick's placement."], - }, + tick_thickness = { type = "range", control = "WeakAurasSpinBox", width = WeakAuras.normalWidth, name = L["Thickness"], - order = 5, + order = 2.5, min = 0, softMax = 20, step = 1, }, + tick_progress_source_space = { + type = "description", + name = "", + order = 3, + width = WeakAuras.normalWidth, + }, + + tick_placement_mode = { + type = "select", + width = WeakAuras.normalWidth, + name = L["Tick Mode"], + order = 3.1, + values = OptionsPrivate.Private.tick_placement_modes, + }, + + tick_progress_source_space_2 = { + type = "description", + name = "", + order = 3.2, + width = WeakAuras.normalWidth, + }, + + tick_add = { + type = "execute", + name = L["Add"], + order = 5, + width = WeakAuras.normalWidth, + func = function() + tinsert(data.tick_placements, 0) + WeakAuras.Add(parentData) + WeakAuras.ClearAndUpdateOptions(parentData.id) + end + }, + tick_extrasDescription = { type = "execute", control = "WeakAurasExpandSmall", @@ -80,7 +100,7 @@ local function createOptions(parentData, data, index, subIndex) return description end, width = WeakAuras.doubleWidth, - order = 6, + order = 7, func = function(info, button) local collapsed = OptionsPrivate.IsCollapsed("subtext", "subtext", "tickextras" .. index, true) OptionsPrivate.SetCollapsed("subtext", "subtext", "tickextras" .. index, not collapsed) @@ -99,7 +119,7 @@ local function createOptions(parentData, data, index, subIndex) type = "toggle", width = WeakAuras.normalWidth, name = L["Automatic length"], - order = 7, + order = 8, desc = L["Matches the height setting of a horizontal bar or width for a vertical bar."], hidden = hiddentickextras, }, @@ -108,7 +128,7 @@ local function createOptions(parentData, data, index, subIndex) control = "WeakAurasSpinBox", width = WeakAuras.normalWidth, name = L["Length"], - order = 8, + order = 9, min = 0, softMax = 50, step = 1, @@ -119,14 +139,14 @@ local function createOptions(parentData, data, index, subIndex) type = "toggle", width = WeakAuras.normalWidth, name = L["Use Texture"], - order = 9, + order = 10, hidden = hiddentickextras, }, tick_blend_mode = { type = "select", width = WeakAuras.normalWidth, name = L["Blend Mode"], - order = 10, + order = 11, values = OptionsPrivate.Private.blend_types, disabled = function() return not data.use_texture end, hidden = hiddentickextras, @@ -134,7 +154,7 @@ local function createOptions(parentData, data, index, subIndex) tick_texture = { type = "input", name = L["Texture"], - order = 11, + order = 12, width = WeakAuras.doubleWidth - 0.15, disabled = function() return not data.use_texture end, hidden = hiddentickextras, @@ -143,7 +163,7 @@ local function createOptions(parentData, data, index, subIndex) type = "execute", name = L["Choose"], width = 0.15, - order = 11.5, + order = 12.5, func = function() OptionsPrivate.OpenTexturePicker(parentData, { "subRegions", index @@ -164,7 +184,7 @@ local function createOptions(parentData, data, index, subIndex) type = "toggle", width = WeakAuras.doubleWidth, name = L["Desaturate"], - order = 12, + order = 13, hidden = hiddentickextras, }, tick_rotation = { @@ -174,6 +194,7 @@ local function createOptions(parentData, data, index, subIndex) name = L["Rotation"], min = 0, max = 360, + step = 1, order = 14, hidden = hiddentickextras, }, @@ -193,6 +214,7 @@ local function createOptions(parentData, data, index, subIndex) order = 16, softMin = -200, softMax = 200, + step = 1, hidden = hiddentickextras, }, tick_yOffset = { @@ -203,6 +225,7 @@ local function createOptions(parentData, data, index, subIndex) order = 17, softMin = -200, softMax = 200, + step = 1, hidden = hiddentickextras, }, @@ -218,6 +241,72 @@ local function createOptions(parentData, data, index, subIndex) } } + if data then + for i in ipairs(data.tick_placements) do + options["tick_progress_source" .. i] = { + type = "select", + width = WeakAuras.normalWidth, + name = L["Progress Source"], + order = 4 + i / 100, + control = "WeakAurasTwoColumnDropdown", + values = OptionsPrivate.Private.GetProgressSourcesForUi(parentData, true), + get = function(info) + return OptionsPrivate.Private.GetProgressValueConstant(data.progressSources[i] or {-2, ""}) + end, + set = function(info, value) + if value then + data.progressSources = data.progressSources or {} + data.progressSources[i] = data.progressSources[i] or {} + -- Copy only trigger + property + data.progressSources[i][1] = value[1] + data.progressSources[i][2] = value[2] + else + data.progressSources[i] = nil + end + WeakAuras.Add(parentData) + end, + hidden = function() + return not(data.tick_placement_mode == "ValueOffset") + end + } + + options["tick_placement" .. i] = { + type = "input", + width = WeakAuras.normalWidth - 0.15, + name = L["Tick Placement"], + order = 4 + i / 100 + 0.001, + validate = WeakAuras.ValidateNumeric, + desc = L["Enter in a value for the tick's placement."], + get = function(info) + return data.tick_placements[i] or "" + end, + set = function(info, value) + data.tick_placements[i] = value + WeakAuras.Add(parentData) + end + } + + options["tick_placement_delete" .. i] = { + type = "execute", + width = 0.15, + name = L["Delete"], + order = 4 + i / 100 + 0.002, + func = function() + tremove(data.tick_placements, i) + WeakAuras.Add(parentData) + WeakAuras.ClearAndUpdateOptions(parentData.id) + end, + image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\delete", + imageWidth = 24, + imageHeight = 24, + control = "WeakAurasIcon", + disabled = function() + return #data.tick_placements < 2 + end + } + end + end + OptionsPrivate.AddUpDownDeleteDuplicate(options, parentData, index, "subtick") return options