diff --git a/EUI__General_Options.lua b/EUI__General_Options.lua index e1c74fe7..7f408701 100644 --- a/EUI__General_Options.lua +++ b/EUI__General_Options.lua @@ -1698,6 +1698,68 @@ initFrame:SetScript("OnEvent", function(self) _, h = W:Spacer(parent, y, 20); y = y - h + ----------------------------------------------------------------------- + -- AURA SPELL ID FILTER + ----------------------------------------------------------------------- + _, h = W:SectionHeader(parent, "AURA SPELL ID FILTER", y); y = y - h + + local auraFilterModeValues = { + disabled = "Disabled", + whitelist = "Whitelist (Show Only These)", + blacklist = "Blacklist (Hide These)", + } + local auraFilterModeOrder = { "disabled", "whitelist", "blacklist" } + + _, h = W:DualRow(parent, y, + { type="dropdown", text="Filter Mode", + values=auraFilterModeValues, + order=auraFilterModeOrder, + getValue=function() + return EllesmereUI.GetAuraFilterMode() + end, + setValue=function(v) + if not EllesmereUIDB then EllesmereUIDB = {} end + if not EllesmereUIDB.auraFilter then + EllesmereUIDB.auraFilter = { mode = "disabled", spellIDs = "" } + end + EllesmereUIDB.auraFilter.mode = v + if EllesmereUI.NotifyAuraFilterChanged then + EllesmereUI.NotifyAuraFilterChanged() + end + end }, + { type="label", text="" }); y = y - h + + -- "Edit Spell ID List" button + do + local BTN_W, BTN_H = 220, 28 + local btn = CreateFrame("Button", nil, parent) + btn:SetSize(BTN_W, BTN_H) + btn:SetPoint("TOP", parent, "TOP", 0, y) + btn:SetFrameLevel(parent:GetFrameLevel() + 5) + EllesmereUI.MakeStyledButton(btn, "Edit Spell ID List", 11, + EllesmereUI.WB_COLOURS, function() + local currentIDs = "" + if EllesmereUIDB and EllesmereUIDB.auraFilter then + currentIDs = EllesmereUIDB.auraFilter.spellIDs or "" + end + EllesmereUI:ShowAuraFilterPopup(currentIDs) + end) + y = y - BTN_H - 4 + end + + -- Helper text + do + local helpFS = EllesmereUI.MakeFont(parent, 10, "", 1, 1, 1) + helpFS:SetAlpha(0.35) + helpFS:SetPoint("TOP", parent, "TOP", 0, y) + helpFS:SetWidth(360) + helpFS:SetJustifyH("CENTER") + helpFS:SetText("Enter spell IDs separated by commas. Enable 'Show Spell ID on Tooltip' above to find IDs.") + y = y - 18 + end + + _, h = W:Spacer(parent, y, 20); y = y - h + -- Reset ALL EUI Addon Settings (wide warning button) y = y - 30 -- spacer do diff --git a/EllesmereUI.lua b/EllesmereUI.lua index 688e516a..58e7e373 100644 --- a/EllesmereUI.lua +++ b/EllesmereUI.lua @@ -4973,6 +4973,7 @@ function EllesmereUI:ResetAllModules() EllesmereUIDB.profileOrder = nil EllesmereUIDB.specProfiles = nil EllesmereUIDB.activeProfile = nil + EllesmereUIDB.auraFilter = nil end end @@ -6132,6 +6133,196 @@ do end end +------------------------------------------------------------------------------- +-- Aura Spell ID Filter (shared across nameplates + unit frames) +------------------------------------------------------------------------------- +do + local auraFilterCache = {} -- { [spellID] = true } + local auraFilterCallbacks = {} -- registered refresh callbacks + + function EllesmereUI.RegisterAuraFilterCallback(fn) + auraFilterCallbacks[#auraFilterCallbacks + 1] = fn + end + + local function NotifyAuraFilterChanged() + for _, fn in ipairs(auraFilterCallbacks) do fn() end + end + + function EllesmereUI.RebuildAuraFilterCache() + wipe(auraFilterCache) + if not EllesmereUIDB or not EllesmereUIDB.auraFilter then return end + local str = EllesmereUIDB.auraFilter.spellIDs + if not str or str == "" then return end + for id in str:gmatch("%d+") do + local num = tonumber(id) + if num then auraFilterCache[num] = true end + end + NotifyAuraFilterChanged() + end + + function EllesmereUI.NotifyAuraFilterChanged() + NotifyAuraFilterChanged() + end + + function EllesmereUI.GetAuraFilterCache() + return auraFilterCache + end + + function EllesmereUI.GetAuraFilterMode() + if not EllesmereUIDB or not EllesmereUIDB.auraFilter then return "disabled" end + return EllesmereUIDB.auraFilter.mode or "disabled" + end + + function EllesmereUI.IsSpellFiltered(spellId) + if not spellId then return false end + local mode = EllesmereUI.GetAuraFilterMode() + if mode == "disabled" then return false end + local cache = auraFilterCache + if next(cache) == nil then return false end -- empty list = no filtering + if mode == "whitelist" then + return not cache[spellId] + else -- blacklist + return cache[spellId] == true + end + end + + -- Popup for editing the spell ID list (reuses the profile popup visual style) + local auraPopupDimmer, auraPopupEditBox, auraPopupRefreshH + function EllesmereUI:ShowAuraFilterPopup(currentText) + if not auraPopupDimmer then + local POPUP_W, POPUP_H = 520, 310 + local FONT = EllesmereUI.EXPRESSWAY + + local dimmer = CreateFrame("Frame", nil, UIParent) + dimmer:SetFrameStrata("FULLSCREEN_DIALOG") + dimmer:SetAllPoints(UIParent) + dimmer:EnableMouse(true) + dimmer:EnableMouseWheel(true) + dimmer:SetScript("OnMouseWheel", function() end) + local dimTex = dimmer:CreateTexture(nil, "BACKGROUND") + dimTex:SetAllPoints() + dimTex:SetColorTexture(0, 0, 0, 0.25) + + local popup = CreateFrame("Frame", nil, dimmer) + popup:SetSize(POPUP_W, POPUP_H) + popup:SetPoint("CENTER", UIParent, "CENTER", 0, 60) + popup:SetFrameStrata("FULLSCREEN_DIALOG") + popup:SetFrameLevel(dimmer:GetFrameLevel() + 10) + popup:EnableMouse(true) + local bg = popup:CreateTexture(nil, "BACKGROUND") + bg:SetAllPoints() + bg:SetColorTexture(0.06, 0.08, 0.10, 1) + EllesmereUI.MakeBorder(popup, 1, 1, 1, 0.15, EllesmereUI.PanelPP) + + local titleFS = EllesmereUI.MakeFont(popup, 15, "", 1, 1, 1) + titleFS:SetPoint("TOP", popup, "TOP", 0, -20) + titleFS:SetText("Edit Aura Spell ID List") + + local subFS = EllesmereUI.MakeFont(popup, 11, "", 1, 1, 1) + subFS:SetAlpha(0.45) + subFS:SetPoint("TOP", titleFS, "BOTTOM", 0, -4) + subFS:SetText("Enter spell IDs separated by commas (e.g. 12345, 67890)") + + local sf = CreateFrame("ScrollFrame", nil, popup) + sf:SetPoint("TOPLEFT", popup, "TOPLEFT", 20, -58) + sf:SetPoint("BOTTOMRIGHT", popup, "BOTTOMRIGHT", -20, 52) + sf:SetFrameLevel(popup:GetFrameLevel() + 1) + sf:EnableMouseWheel(true) + + local sc = CreateFrame("Frame", nil, sf) + sc:SetWidth(sf:GetWidth() or (POPUP_W - 40)) + sc:SetHeight(1) + sf:SetScrollChild(sc) + + local editBox = CreateFrame("EditBox", nil, sc) + editBox:SetMultiLine(true) + editBox:SetAutoFocus(false) + editBox:SetFont(FONT, 11, "") + editBox:SetTextColor(1, 1, 1, 0.75) + editBox:SetPoint("TOPLEFT", sc, "TOPLEFT", 0, 0) + editBox:SetPoint("TOPRIGHT", sc, "TOPRIGHT", -14, 0) + editBox:SetHeight(1) + + sf:SetScript("OnMouseWheel", function(self, delta) + local maxScroll = tonumber(self:GetVerticalScrollRange()) or 0 + if maxScroll <= 0 then return end + local cur = self:GetVerticalScroll() + self:SetVerticalScroll(math.max(0, math.min(maxScroll, cur - delta * 30))) + end) + + sf:SetScript("OnMouseDown", function() editBox:SetFocus() end) + + local function RefreshHeight() + C_Timer.After(0.01, function() + local lineH = (editBox.GetLineHeight and editBox:GetLineHeight()) or 14 + local h = editBox:GetNumLines() * lineH + local sfH = sf:GetHeight() or 100 + if h <= sfH then + sc:SetHeight(sfH) + editBox:SetHeight(sfH) + else + sc:SetHeight(h + 4) + editBox:SetHeight(h + 4) + end + end) + end + editBox:SetScript("OnTextChanged", function() RefreshHeight() end) + + -- Save button + local saveBtn = CreateFrame("Button", nil, popup) + saveBtn:SetSize(120, 26) + saveBtn:SetPoint("BOTTOMRIGHT", popup, "BOTTOM", -4, 14) + saveBtn:SetFrameLevel(popup:GetFrameLevel() + 2) + EllesmereUI.MakeStyledButton(saveBtn, "Save", 11, + EllesmereUI.WB_COLOURS, function() + local str = editBox:GetText() or "" + if not EllesmereUIDB then EllesmereUIDB = {} end + if not EllesmereUIDB.auraFilter then + EllesmereUIDB.auraFilter = { mode = "disabled", spellIDs = "" } + end + EllesmereUIDB.auraFilter.spellIDs = str + EllesmereUI.RebuildAuraFilterCache() + dimmer:Hide() + end) + + local cancelBtn = CreateFrame("Button", nil, popup) + cancelBtn:SetSize(120, 26) + cancelBtn:SetPoint("BOTTOMLEFT", popup, "BOTTOM", 4, 14) + cancelBtn:SetFrameLevel(popup:GetFrameLevel() + 2) + EllesmereUI.MakeStyledButton(cancelBtn, "Cancel", 11, + EllesmereUI.RB_COLOURS, function() dimmer:Hide() end) + + dimmer:SetScript("OnMouseDown", function() + if not popup:IsMouseOver() then dimmer:Hide() end + end) + + popup:EnableKeyboard(true) + popup:SetScript("OnKeyDown", function(self, key) + if key == "ESCAPE" then + self:SetPropagateKeyboardInput(false) + dimmer:Hide() + else + self:SetPropagateKeyboardInput(true) + end + end) + + dimmer:HookScript("OnHide", function() + editBox:ClearFocus() + sf:SetVerticalScroll(0) + end) + + auraPopupDimmer = dimmer + auraPopupEditBox = editBox + auraPopupRefreshH = RefreshHeight + end + + auraPopupEditBox:SetText(currentText or "") + auraPopupDimmer:Show() + auraPopupRefreshH() + C_Timer.After(0.05, function() auraPopupEditBox:SetFocus() end) + end +end + ------------------------------------------------------------------------------- -- Init + Demo Modules (temporary placeholder content) ------------------------------------------------------------------------------- @@ -6216,6 +6407,13 @@ initFrame:SetScript("OnEvent", function(self, event) if EllesmereUI._applyGuildChatPrivacy then EllesmereUI._applyGuildChatPrivacy() end if EllesmereUI._applySecondaryStats then EllesmereUI._applySecondaryStats() end + -- Initialize aura filter defaults and rebuild cache + if not EllesmereUIDB then EllesmereUIDB = {} end + if not EllesmereUIDB.auraFilter then + EllesmereUIDB.auraFilter = { mode = "disabled", spellIDs = "" } + end + EllesmereUI.RebuildAuraFilterCache() + -- Re-read theme settings from SavedVariables (belt-and-suspenders for persistence) if EllesmereUIDB then -- Migrate legacy keys to new activeTheme model diff --git a/EllesmereUINameplates/EUI_Nameplates_Options.lua b/EllesmereUINameplates/EUI_Nameplates_Options.lua index 6cb2a113..4f4c3c6b 100644 --- a/EllesmereUINameplates/EUI_Nameplates_Options.lua +++ b/EllesmereUINameplates/EUI_Nameplates_Options.lua @@ -2307,6 +2307,16 @@ initFrame:SetScript("OnEvent", function(self) end, tooltip="Scales enemy nameplates while they are casting. 100% = no change." }); y = y - h + _, h = W:DualRow(parent, y, + { type="toggle", text="Use Aura Spell ID Filter", + getValue=function() return DBVal("useAuraFilter") == true end, + setValue=function(v) + DB().useAuraFilter = v + RefreshAllAuras() + end, + tooltip="Apply the global Aura Spell ID Filter (configured in Global Settings) to nameplates." }, + { type="label", text="" }); y = y - h + -- Helper: pandemic glow is off when style is "None" local function pandemicOff() return DBVal("pandemicGlow") ~= true diff --git a/EllesmereUINameplates/EllesmereUINameplates.lua b/EllesmereUINameplates/EllesmereUINameplates.lua index 4200caca..9150f6e9 100644 --- a/EllesmereUINameplates/EllesmereUINameplates.lua +++ b/EllesmereUINameplates/EllesmereUINameplates.lua @@ -3629,6 +3629,7 @@ function NameplateFrame:UpdateAuras(updateInfo) local debuffSlotVal, buffSlotVal, ccSlotVal = GetAuraSlots() local dIdx = 1 local db = EllesmereUINameplatesDB + local npUseAuraFilter = db and db.useAuraFilter and EllesmereUI.IsSpellFiltered if debuffSlotVal ~= "none" then local showAll = db and db.showAllDebuffs -- Build the important set from Blizzard's debuffList synchronously. @@ -3652,7 +3653,8 @@ function NameplateFrame:UpdateAuras(updateInfo) for _, aura in ipairs(allDebuffs) do if dIdx > 4 then break end local id = aura and aura.auraInstanceID - if id and aura.icon and (showAll or (importantSet and importantSet[id])) then + if id and aura.icon and (showAll or (importantSet and importantSet[id])) + and not (npUseAuraFilter and npUseAuraFilter(aura.spellId)) then local slot = self.debuffs[dIdx] slot.icon:SetTexture(aura.icon) slot.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) @@ -3711,7 +3713,8 @@ function NameplateFrame:UpdateAuras(updateInfo) for _, aura in ipairs(allBuffs) do if bIdx > 4 then break end local id = aura and aura.auraInstanceID - if id and type(aura.dispelName) ~= "nil" and aura.icon then + if id and type(aura.dispelName) ~= "nil" and aura.icon + and not (npUseAuraFilter and npUseAuraFilter(aura.spellId)) then local slot = self.buffs[bIdx] slot.icon:SetTexture(aura.icon) slot.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) @@ -3743,7 +3746,8 @@ function NameplateFrame:UpdateAuras(updateInfo) local GetDur = C_UnitAuras.GetAuraDuration for _, aura in ipairs(ccAuras) do if ccShown >= 2 then break end - if aura and aura.auraInstanceID and aura.icon then + if aura and aura.auraInstanceID and aura.icon + and not (npUseAuraFilter and npUseAuraFilter(aura.spellId)) then ccShown = ccShown + 1 local slot = self.cc[ccShown] slot.icon:SetTexture(aura.icon) @@ -4201,6 +4205,16 @@ manager:RegisterEvent("PLAYER_REGEN_ENABLED") manager:RegisterEvent("DISPLAY_SIZE_CHANGED") manager:RegisterEvent("UI_SCALE_CHANGED") +-- Register for aura filter changes so nameplates refresh when mode/list changes +if EllesmereUI and EllesmereUI.RegisterAuraFilterCallback then + EllesmereUI.RegisterAuraFilterCallback(function() + local plates = ns.plates + for _, plate in pairs(plates) do + plate:UpdateAuras() + end + end) +end + local pendingUnits = {} ns.pendingUnits = pendingUnits local currentMouseoverPlate = nil diff --git a/EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua b/EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua index 31fbb7e4..593ab7cf 100644 --- a/EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua +++ b/EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua @@ -6180,6 +6180,9 @@ initFrame:SetScript("OnEvent", function(self) { type="toggle", label="Show Own Only", get=function() return SValSupported("onlyPlayerDebuffs", false) end, set=function(v) SSetSupported("onlyPlayerDebuffs", v) end }, + { type="toggle", label="Use Aura Spell ID Filter", + get=function() return SValSupported("useAuraFilter", false) end, + set=function(v) SSetSupported("useAuraFilter", v) end }, }, }) local debuffCogShow = debuffCogShowRaw diff --git a/EllesmereUIUnitFrames/EllesmereUIUnitFrames.lua b/EllesmereUIUnitFrames/EllesmereUIUnitFrames.lua index 342dbe82..f7b84c39 100644 --- a/EllesmereUIUnitFrames/EllesmereUIUnitFrames.lua +++ b/EllesmereUIUnitFrames/EllesmereUIUnitFrames.lua @@ -2517,6 +2517,12 @@ local function CreateUnifiedBorder(frame, unit) end +-- Shared oUF FilterAura for spell ID filtering +local function AuraSpellIDFilter(element, unit, data) + if not data or not data.spellId then return true end + return not EllesmereUI.IsSpellFiltered(data.spellId) +end + local function CreateTargetAuras(frame, unit) local function SetupAuraIcon(_, button) if not button then return end @@ -2584,6 +2590,9 @@ local function CreateTargetAuras(frame, unit) buffs:Hide() buffs.num = 0 end + if settings.useAuraFilter then + buffs.FilterAura = AuraSpellIDFilter + end frame.Buffs = buffs local maxDebuffs = (settings and settings.maxDebuffs) or 28 @@ -2612,6 +2621,9 @@ local function CreateTargetAuras(frame, unit) if settings and settings.onlyPlayerDebuffs then debuffs.onlyShowPlayer = true end + if settings.useAuraFilter then + debuffs.FilterAura = AuraSpellIDFilter + end frame.Debuffs = debuffs end @@ -2737,6 +2749,9 @@ local function StyleFullFrame(frame, unit) PP.CreateBorder(button.Border, 0, 0, 0, 1) end end + if settings.useAuraFilter then + buffs.FilterAura = AuraSpellIDFilter + end frame.Buffs = buffs end elseif unit == "target" then