Files
ElvUI_CoA/Modules/ExtraActionBar.lua
T
Narcasung 97c4defa51 Add Class Resources and Debuff Highlighting modules; migrate settings to AceDB profiles
Move CoA settings from E.global/E.private into a proper AceDB-3.0 database
(CoA.db, SavedVariables ElvUI_CoADB) with a Profiles options tab, since
ElvUI doesn't ship AceDBOptions-3.0 (vendored under Libraries/).

Add ClassResources.lua: hooks the custom-class resource frames (segment
bar, orb, bar, multi-cast bar) into ElvUI's Toggle Anchors, with a
per-frame hide checkbox in a new "Class Resources" options tab.

Add DispelHighlight.lua: highlights dispellable debuffs on unitframes,
with talent-aware filtering for custom classes.

Fix mover/anchor reliability for Class Resources and the Instance
(LayerPicker) button:
- Movers were only retried until the target frame existed, not until the
  mover was actually created, so frames that start at zero size (e.g. a
  resource bar before that resource is ever active) permanently lost
  their mover.
- Class resource frames re-anchor themselves on refresh, stomping the
  mover's anchor; hook SetPoint to snap back to the mover holder whenever
  something else repositions the frame.
- Native click-drag on these frames ends with the engine calling SetPoint
  directly, severing the mover anchor entirely. Permanently block drag
  (script and RegisterForDrag) instead of clearing it once.
2026-07-16 15:24:12 +02:00

220 lines
5.9 KiB
Lua

local E, L, V, P, G = unpack(ElvUI)
local LSM = E.Libs.LSM
local CoA = E:GetModule("CoA")
local CONTAINER_NAME = "ExtraActionBar"
local BUTTON_NAME = "ExtraActionBarPoolFrameExtraActionButtonTemplate1"
local BINDING_ACTION = "CLICK "..BUTTON_NAME..":LeftButton"
_G["BINDING_NAME_"..BINDING_ACTION] = "Extra Action Button"
local function SkinGlow(button, name)
local glow = _G[name.."SpellActivationAlert"]
if not glow or not glow.GetNumRegions then return end
for i = 1, glow:GetNumRegions() do
local region = select(i, glow:GetRegions())
if region and region.IsObjectType and region:IsObjectType("Texture") then
region:SetVertexColor(unpack(E.media.rgbvaluecolor))
end
end
end
local RIM_EDGE_RATIO = 6 / 52 -- 6px confirmed empirically at the native 52px size to fully hide the icon's baked-in vanilla border
local function UpdateRimEdge(button, size)
local rim = button and button.CoARim
if not rim then return end
rim:SetBackdrop({edgeFile = E.media.blankTex, edgeSize = size * RIM_EDGE_RATIO})
rim:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
local HOTKEY_MARGIN = 3
local function UpdateHotkeyPosition(button, size)
local hotkey = button and _G[button:GetName().."HotKey"]
if not hotkey then return end
local inset = -(size * RIM_EDGE_RATIO + HOTKEY_MARGIN)
hotkey:ClearAllPoints()
hotkey:Point("TOPRIGHT", inset, inset)
end
local function UpdateSize(button)
button = button or _G[BUTTON_NAME]
if button then
local size = CoA.db.profile.extraActionButtonSize or 52
button:SetSize(size, size)
UpdateRimEdge(button, size)
UpdateHotkeyPosition(button, size)
end
end
function CoA:UpdateExtraActionButtonSize()
UpdateSize()
end
local function UpdateHotkeyText(button)
button = button or _G[BUTTON_NAME]
local hotkey = button and _G[button:GetName().."HotKey"]
if not hotkey then return end
local key = GetBindingKey(BINDING_ACTION)
if key then
hotkey:SetText(GetBindingText(key, "KEY_"))
hotkey:Show()
else
hotkey:SetText("")
hotkey:Hide()
end
end
local function RecenterAnchor(button, container)
local x, y = button:GetCenter()
local cx, cy = container:GetCenter()
if not (x and y and cx and cy) then return end
button:ClearAllPoints()
button:SetPoint("CENTER", container, "CENTER", x - cx, y - cy)
end
local function SkinButton(button, container)
if button.CoASkinned then return end
button.CoASkinned = true
RecenterAnchor(button, container)
UpdateSize(button)
local name = button:GetName()
local icon = _G[name.."Icon"]
local hotkey = _G[name.."HotKey"]
local macroText = _G[name.."Name"]
local count = _G[name.."Count"]
local flash = _G[name.."Flash"]
local border = _G[name.."Border"]
local normal = _G[name.."NormalTexture"]
local normal2 = button:GetNormalTexture()
local cooldown = _G[name.."Cooldown"]
if flash then flash:SetTexture(nil) end
if border then border:Kill() end
if normal then normal:SetTexture(nil) normal:Hide() end
if normal2 then normal2:SetTexture(nil) normal2:Hide() end
for i = 1, button:GetNumRegions() do
local region = select(i, button:GetRegions())
if region and region.IsObjectType and region:IsObjectType("Texture") and region:GetTexture() == [[Interface\ExtraButton\Default]] then
region:SetTexture(nil)
region:Hide()
end
end
button:CreateBackdrop("Default")
button.backdrop:SetBackdropColor(0, 0, 0, 0)
button.backdrop:SetBackdropBorderColor(0, 0, 0, 0)
button:StyleButton()
if icon then
icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
icon:SetParent(button.backdrop)
button.backdrop:SetOutside(icon, 1, 1)
local rim = CreateFrame("Frame", nil, button.backdrop)
rim:SetAllPoints(icon)
rim:SetFrameLevel(button.backdrop:GetFrameLevel() + 10)
button.CoARim = rim
UpdateRimEdge(button, CoA.db.profile.extraActionButtonSize or 52)
button:SetFrameLevel(rim:GetFrameLevel() + 1)
end
if hotkey then
hotkey:FontTemplate(LSM:Fetch("font", E.db.actionbar.font), E.db.actionbar.fontSize, E.db.actionbar.fontOutline)
hotkey:SetTextColor(1, 1, 1)
UpdateHotkeyText(button)
CoA:RegisterEvent("UPDATE_BINDINGS", function() UpdateHotkeyText(button) end)
end
if macroText then
macroText:ClearAllPoints()
macroText:Point("BOTTOM", 0, 1)
macroText:FontTemplate()
end
if count then
count:ClearAllPoints()
count:Point("BOTTOMRIGHT", 0, 2)
count:FontTemplate()
end
if cooldown then
cooldown.CooldownOverride = "actionbar"
E:RegisterCooldown(cooldown)
end
SkinGlow(button, name)
end
local function SetupMover(container, button)
if CoA.extraActionBarMoverCreated then return true end
local width, height = button:GetSize()
if width == 0 or height == 0 then return false end
local left, bottom = button:GetLeft(), button:GetBottom()
if not left or not bottom then return false end
CoA.extraActionBarMoverCreated = true
container:StripTextures(true)
container:EnableMouse(false)
local holder = CreateFrame("Frame", "CoA_ExtraActionBarHolder", E.UIParent)
holder:Size(width, height)
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom)
E:CreateMover(holder, "CoA_ExtraActionBarMover", "Extra Action Bar", nil, nil, nil, "ALL,ACTIONBARS", nil, "CoA,skin,extraActionBar")
holder:SetAllPoints(_G["CoA_ExtraActionBarMover"])
local function Anchor()
container:ClearAllPoints()
container:SetPoint("CENTER", holder, "CENTER")
end
if InCombatLockdown() then
CoA:RegisterEvent("PLAYER_REGEN_ENABLED", function()
Anchor()
CoA:UnregisterEvent("PLAYER_REGEN_ENABLED")
end)
else
Anchor()
end
return true
end
local function TryHook()
local container = _G[CONTAINER_NAME]
local button = _G[BUTTON_NAME]
if container and button then
SkinButton(button, container)
return SetupMover(container, button)
end
return false
end
function CoA:InitializeExtraActionBar()
if TryHook() then return end
self.extraActionBarTimer = self:ScheduleRepeatingTimer(function()
if TryHook() then
self:CancelTimer(self.extraActionBarTimer)
self.extraActionBarTimer = nil
end
end, 0.5)
end