diff --git a/src/OmicronFrames.toc b/src/OmicronFrames.toc index 4ea0dcc..7940f13 100644 --- a/src/OmicronFrames.toc +++ b/src/OmicronFrames.toc @@ -17,6 +17,7 @@ types/statusbar.lua types/auralist.lua types/indicators/indicator.lua types/indicators/squareindicator.lua +types/indicators/iconindicator.lua types/indicators/borderindicator.lua types/unitgroup.lua types/unitframe.lua diff --git a/src/types/indicators/iconindicator.lua b/src/types/indicators/iconindicator.lua new file mode 100644 index 0000000..042f1b2 --- /dev/null +++ b/src/types/indicators/iconindicator.lua @@ -0,0 +1,173 @@ +-- Copyright 2025 +-- +-- This file is part of Omicron Frames +-- +-- Omicron Frames is free software: you can redistribute it and/or modify it +-- under the terms of the GNU General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) +-- any later version. +-- +-- Omicron Frames is distributed in the hope that it will be useful, but +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +-- more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- Omicron Frames. If not, see . +local omi = select(2, ...) +local types = omi.GetModule("types") + +local iconPool = CreateFramePool("Frame", nil, "BackdropTemplate") + +---IconIndicator is an indicator that displays an icon with border +---@class IconIndicator: Indicator +local IconIndicator = types.CreateClass("IconIndicator", Indicator) +types.IconIndicator = IconIndicator + +---@return IconIndicator +function IconIndicator.new(cls, ...) + --- I really dislike duplicating this everywhere but it makes + --lua-language-server able to deduce the type of Object:new calls and that + --is honestly worth it + return types.Object.new(cls, ...) +end + +--- Initialize a new IconIndicator +-- unitframe Unitframe it is attached to +-- size Size of the indicator square +-- point Attachment point to the unitframe's overlay frame +-- x, y x and y offset for the attachment point +-- color Color of the square +---@param unitframe UnitFrame +---@param size number +---@param point string +---@param x number +---@param y number +---@param showStacks boolean +---@param doFade nil|number +---@param doFlash nil|number +function IconIndicator:Init(unitframe, size, point, x, y, showStacks, fadeTime, flashTime) + self.unitframe = unitframe + self.frameParent = unitframe.overlays + self.size = size + self.point = point + self.x = x + self.y = y + self.icon = 134400 + self.showStacks = showStacks + self.fadeTime = fadeTime + self.flashTime = flashTime +end + +--- Show the square indicator +---@param data table +function IconIndicator:Show(data) + local frame, stacks = self:GetFrame() + local numStacks = data.stacks or 0 + self.frame = frame + self.stacks = stacks + if self.showStacks and numStacks > 0 then + stacks:SetText(numStacks) + stacks:Show() + end + if self.flashTime or self.fadeTime then + self.frame:SetScript("OnUpdate", function(frame, dt) + self:OnUpdate(dt) + end) + self.expirationTime = data.expirationTime + self.updateThrottle = 0 + end + if data.icon then + self:SetIcon(data.icon) + else + self:SetIcon(self.icon) + end + frame:Show() +end + +--- Set the icon of the Icon Indicator +function IconIndicator:SetIcon(icon) + self.icon = icon + local frame = self.frame + if frame then + frame.iconTexture:SetTexture(icon) + end +end + +function IconIndicator:GetFrame() + local frame, new = iconPool:Acquire() + local stacks + if new then + local iconTexture = frame:CreateTexture(nil, "BACKGROUND") + iconTexture:SetAllPoints() + frame.iconTexture = iconTexture + + frame.backdropInfo = { + bgFile = nil, + edgeFile = "Interface\\Addons\\OmicronFrames\\media\\textures\\pixel_edge", + edgeSize = 2, + insets = { left = 0, right = 0, top = 0, bottom = 0 }, + } + frame:ApplyBackdrop() + + stacks = frame:CreateFontString(nil, "OVERLAY") + frame.stacks = stacks + stacks:SetFont("Interface\\AddOns\\OmicronFrames\\media\\fonts\\roboto\\Roboto-Medium.ttf", 12, "OUTLINE") + stacks:SetPoint("CENTER") + stacks:SetTextColor(1, 1, 1) + end + + frame:SetSize(self.size, self.size) + frame:SetParent(self.frameParent) + frame:SetPoint(self.point, self.x, self.y) + frame:SetBackdropBorderColor(0, 0, 0, 1) + frame:SetAlpha(1) + stacks = frame.stacks + return frame, stacks +end + +---@param data table +function IconIndicator:Update(data) + if data.icon then + self:SetIcon(data.icon) + end + local numStacks = data.stacks or 0 + if numStacks > 0 then + self.stacks:SetText(numStacks) + self.stacks:Show() + end + self.expirationTime = data.expirationTime + self.frame:SetAlpha(1) +end + +function IconIndicator:OnUpdate(dt) + dt = self.updateThrottle + dt + if dt < 0.04 then + self.updateThrottle = dt + return + else + self.updateThrottle = 0 + end + + local timeLeft = self.expirationTime - GetTime() + local fadeTime = self.fadeTime or 0 + local flashTime = self.flashTime or 0 + + if timeLeft < flashTime then + local alpha = ((timeLeft * 4) % 1) + self.frame:SetAlpha(alpha) + elseif timeLeft < fadeTime then + local alpha = timeLeft / fadeTime + self.frame:SetAlpha(alpha) + end +end + +--- Hide the square indicator. +function IconIndicator:Hide() + local frame = self.frame + self.stacks:Hide() + self.frame = nil + self.stacks = nil + frame:SetScript("OnUpdate", nil) + iconPool:Release(frame) +end diff --git a/src/types/triggers/auratrigger.lua b/src/types/triggers/auratrigger.lua index e5636c8..e08ee59 100644 --- a/src/types/triggers/auratrigger.lua +++ b/src/types/triggers/auratrigger.lua @@ -92,7 +92,12 @@ function AuraTrigger:AddAura(aura) return end self.count = self.count + 1 - self:SetData({ stacks = aura.applications, duration = aura.duration, expirationTime = aura.expirationTime }) + self:SetData({ + stacks = aura.applications, + duration = aura.duration, + expirationTime = aura.expirationTime, + icon = aura.icon, + }) self:SetState(self.count >= self.requiredCount, false) end @@ -100,7 +105,12 @@ end ---@param before UnitAuraInfo ---@param after UnitAuraInfo function AuraTrigger:UpdateAura(before, after) - self:SetData({ stacks = after.applications, duration = after.duration, expirationTime = after.expirationTime }) + self:SetData({ + stacks = after.applications, + duration = after.duration, + expirationTime = after.expirationTime, + icon = after.icon, + }) if self.active then self.indicator:Update(self.data) end diff --git a/src/types/unitframe.lua b/src/types/unitframe.lua index 37d6b1f..123836f 100644 --- a/src/types/unitframe.lua +++ b/src/types/unitframe.lua @@ -26,6 +26,9 @@ local AuraList = types.AuraList ---@class SquareIndicator local SquareIndicator = types.SquareIndicator +---@class IconIndicator +local IconIndicator = types.IconIndicator + ---@class SquareIndicator local BorderIndicator = types.BorderIndicator @@ -148,12 +151,19 @@ function UnitFrame:CreateIndicator(indicator) indicator.fadeTime, indicator.flashTime ) - elseif kind == "BorderIndicator" then - return BorderIndicator:new( + elseif kind == "IconIndicator" then + return IconIndicator:new( self, - indicator.thickness, - indicator.color + indicator.size, + indicator.point, + indicator.x, + indicator.y, + indicator.showStacks, + indicator.fadeTime, + indicator.flashTime ) + elseif kind == "BorderIndicator" then + return BorderIndicator:new(self, indicator.thickness, indicator.color) else error(string.format("Invalid Indicator kind `%s` requested", indicator.kind)) end