Toggling OmniCC display
Rainrider opened this issue ยท 17 comments
I would like to toggle OmniCC display programmatically to show another timer for a short period. My current state is something like:
function overlayPrototype:ToggleOmniCC()
if not _G.OmniCC then return end
local display = _G.OmniCC.Display:Get(self:GetParent())
if self.Timer:IsShown() then
if display then
display:Hide()
end
-- prevent OmniCC from starting a new timer
self.button.cooldown.noCooldownCount = true
else
if display then
display:Show()
else
-- make OmniCC display the timer (ugly)
self.button.cooldown:SetCooldown(self.cooldownStart or 0, self.cooldownDuration or 0)
end
self.button.cooldown.noCooldownCount = nil
end
end
Problem 1:
The only way, unless I missed something, to make OmniCC display the timer is to re-set the cooldown. Could you please expose cooldown_OnSetCooldownDuration
as it would simplify this?
Problem 2:
I can't reliably track changes of the .noCooldownCount
option. Do you have a proposal on how to respect user settings here (currently I nil this to signal OmniCC it can now display its timers again, but this might not be wanted)?
What are you trying to do, exactly? It might be easier for me to add a third layer of cooldowns, like charges
It is showing the remaining duration of the buff from Double Tap on Rapid Fire. After the buff is consumed (here by Aimed Shot, not visible), the OmniCC timer is restored.
Thank you for the code, but I'm not sure I understand why there is need for a new cooldown frame on top of ABA's overlay. ABA's overlay (overlayPrototype) is laid on top of the action button's original cooldown frame (referenced by self.button.cooldown
in the code above). ABA's own timer is the small text at the bottom of the button in the gif from my previous post. The bigger yellow ones are the cooldowns of the abilities on the action bar drawn by OmniCC. I aim to hide OmniCC's timer for the abilities CDs when ABA's timer is shown. I'm sorry if I described it misleadingly the previous time.
If there's multiple cooldowns that share the same parent, OmniCC will display text for the one soonest to end. As an example, I've hacked in cooldowns for AdiButtonAuras. Both of these are modifications to Display.lua.
function overlayPrototype:InitializeDisplay()
self:SetFrameLevel(self.button.cooldown:GetFrameLevel()+1)
self.parentCount = _G[self.button:GetName().."Count"]
local highlight = self:CreateTexture(self:GetName().."Highlight", "BACKGROUND")
highlight:SetAllPoints(self)
highlight:Hide()
self.Highlight = highlight
local overlay = self:CreateTexture(self:GetName().."Overlay", "BACKGROUND")
overlay:SetColorTexture(0.4, 0.4, 0.4, 1)
overlay:SetAllPoints(self)
overlay:Hide()
self.Overlay = overlay
local timer = self:CreateFontString(self:GetName().."Timer", "OVERLAY")
timer:SetFont(fontFile, fontSize, fontFlag)
timer:SetPoint("BOTTOMLEFT", 2, 2)
timer:SetPoint("BOTTOMRIGHT", -2, 2)
timer:SetJustifyV("BOTTOM")
timer.Update = Timer_Update
timer:Hide()
hooksecurefunc(timer, "Show", Text_OnShowHide)
hooksecurefunc(timer, "Hide", Text_OnShowHide)
self.Timer = timer
local count = self:CreateFontString(self:GetName().."Count", "OVERLAY")
count:SetFont(fontFile, fontSize, fontFlag)
count:SetPoint("BOTTOMLEFT", 2, 2)
count:SetPoint("BOTTOMRIGHT", -2, 2)
count:SetJustifyV("BOTTOM")
count:Hide()
hooksecurefunc(count, "Show", Text_OnShowHide)
hooksecurefunc(count, "Hide", Text_OnShowHide)
self.Count = count
local cooldown = CreateFrame("Cooldown", "AdiCooldown_" .. self:GetName(), self.button, "CooldownFrameTemplate")
cooldown:SetEdgeTexture("Interface\\Cooldown\\edge")
cooldown:SetSwipeColor(0, 0, 0)
cooldown:SetDrawSwipe(false)
cooldown:SetDrawEdge(true)
cooldown:SetAllPoints(self.button)
cooldown:SetFrameLevel(self.button.cooldown:GetFrameLevel() + 5)
self.cooldown = cooldown
self:ApplySkin()
end
local function durationsEqual(x, y)
return floor(x or 0) == floor(y or 0)
end
function overlayPrototype:ApplyExpiration()
local expiration = self.expiration
self.Timer.expiration = expiration
self.Timer:Update()
if durationsEqual(expiration, self.oldExpiration) then return end
self.oldExpiration = expiration
local t = GetTime()
if (expiration or 0) > t then
self.cooldown:SetCooldownDuration(expiration - t)
else
self.cooldown:Clear()
end
end
I've also created a branch where I've made OmniCC.Cooldown accessible:
https://github.com/tullamods/OmniCC/tree/export-cooldown
This is what I ended up for now using the export-cooldown
branch:
function overlayPrototype:ToggleOmniCC()
if not _G.OmniCC then return end
-- TODO: Implement opt-in
local display = _G.OmniCC.Display:Get(self:GetParent())
local cooldown = self.button.cooldown
if self.Timer:IsShown() then
if display then
display:Hide()
end
-- prevent OmniCC from starting a new timer
if not cooldown.noCooldownCount then
cooldown.noCooldownCount = addonName
end
else
-- only re-enable OmniCC if we own the lock
if cooldown.noCooldownCount == addonName then
cooldown.noCooldownCount = nil
end
if display then
display:Show()
else
-- make OmniCC display the timer
_G.OmniCC.Cooldown.OnSetCooldownDuration(cooldown)
end
end
end
I have lingering cooldown counts sometimes but will have to figure this out later. Thanks a lot for your help!
I think I'll add the following to the API
function Cooldown:Refresh()
local start, duration = self:GetCooldownTimes()
start = (start or 0) / 1000
duration = (duration or 0) / 1000
Cooldown.Initialize(self)
Cooldown.SetTimer(self, start, duration)
end
function Cooldown:SetNoCooldownCount(disable)
disable = disable and true or nil
if self.noCooldownCount == disable then
return
end
if disable then
self.noCooldownCount = true
Cooldown.HideText(self)
else
self.noCooldownCount = nil
Cooldown.Refresh(self)
end
end
Note that action buttons can currently have two cooldown objects: the primary cd for the ability and a charge cooldown. With the API additions you'd want to do something like this:
Cooldown.SetNoCooldownCount(self.button.cooldown, true)
local chargeCooldown = self.button.chargeCooldown
if chargeCooldown then
Cooldown.SetNoCooldownCount(chargeCooldown true)
end
The problem with .noCooldownCount
being a boolean is that addons are not able to tell who set it and will override each others' preferences. This is why I use cooldown.noCooldownCount = addonName
in my code to know that I'm the one who flipped the switch and can thus restore it without overwriting someone else's state.
I proceeded to sit on this and then forget about it :P
function Cooldown:SetNoCooldownCount(disable, owner)
owner = owner or true
if disable then
if not self.noCooldownCount then
self.noCooldownCount = owner
Cooldown.HideText(self)
end
elseif self.noCooldownCount == owner then
self.noCooldownCount = nil
Cooldown.Refresh(self)
end
end
One problem with this approach is for how long the lock (.noCooldownCount
being truthy) should persist. Normally addons would require the lock at some event. If the lock is not owned by them, they can't guarantee it will remain locked for as long as they need it. The other problem is relying on others to release the lock once they are done.
A possibility would be to implement a queue per cooldown where addons can request a lock with a given expiration time point. The highest expiration wins the lock. Every time a new value is added to the queue or an old value is changed, the winner needs to be calculated anew. When the winning expiration is past, the queue is cleared and the cooldown display is refreshed.
I'm not sure if this is an overkill though. What do you think?
I think its overkill for the moment, as you're the first person ever to actually want to adjust this.
Then I would give your proposed API a try if you don't mind putting up a test branch for me.
It does not work because the SetCooldown hook calls Cooldown:SetTimer
which sets the _occ_start
and _occ_duration
fields on the cooldown object. Those are not reset when hiding/refreshing the timer thus Cooldown:SetTimer
bails out early on subsequent calls. A solution would be to nil one or both fields in Cooldown:Refresh
. In my limited testing this didn't have side effects.
This is the reason I suppose.
It works fine for me for now, so I'll close this. Thanks a lot for the implementation and the discussion, much appreciated!