From 858b1b4842c6bb91390ffadba595432c8c447060 Mon Sep 17 00:00:00 2001 From: Glyalith Date: Fri, 7 Aug 2026 18:25:25 -0600 Subject: [PATCH 1/3] Fix party Dispels settings writing to the shared raid values The party tab reuses the raid section builders and blocks each synced section with an overlay sized from that section's y-range, so a control is editable whenever the section it is DRAWN under is unsynced. Which value it writes is decided separately, by ns._PARTY_KEY_SECTION. When the two disagree the control is editable on the party tab but writes the shared raid key, so the edit shows up on the Frames tab and on the raid frames. Every control under the DISPELS header now files under "dispels": - The Dispellable Debuff Location row and its cog (location, growth, size, offset X/Y) were filed under "debuffDisplay". - Dispel Clock Border, its Extra Border Size, the 12.1 Debuff Icon Border and Private Dispel Overlay Position were in no section at all, so they could never be party-overridden. Frame Border was unaffected because dispelBorderSize was already filed correctly, which is why it was the one setting that did not leak. No existing override changes meaning: writing a party_dispellableDebuff* value already required "dispels" to be unsynced to reach the control, so every one of them stays live under the new section. The four previously unmapped keys have no stored party values at all, and their runtime reads already resolve through the party proxy. --- EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua b/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua index f86dcffa..6c95fa3e 100644 --- a/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua +++ b/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua @@ -10580,11 +10580,20 @@ do "hoverBorderEnabled", "hoverBorderSize", "hoverBorderColor", "hoverBorderAlpha", "targetBorderEnabled", "targetBorderSize", "targetBorderColor", "targetBorderAlpha", "threatBorderSize", }, + -- Must list every key the DISPELS section of the options page draws: + -- the party tab's blocking overlay is sized from that section's y-range, + -- so a control there is editable whenever "dispels" is unsynced. A key + -- filed under another section (or missing) is still editable but writes + -- the shared raid value. dispels = { "dispelBorderSize", "dispelOverlay", "dispelOverlayOpacity", "dispelShowAll", "showDispelIcons", "dispelIconPosition", "dispelIconOffsetX", "dispelIconOffsetY", "dispelIconSize", "dispelColorMagic", "dispelColorCurse", "dispelColorDisease", "dispelColorPoison", "dispelColorBleed", + "dispelIconBorderSize", "dispelOverlayPosition", + "dispelClockBorder", "dispelClockExtraBorder", + "dispellableDebuffLocation", "dispellableDebuffGrowDirection", + "dispellableDebuffOffsetX", "dispellableDebuffOffsetY", "dispellableDebuffSize", }, topNameBar = { "topNameBarEnabled", "topNameBarHeight", @@ -10610,8 +10619,8 @@ do "debuffPosition", "debuffOffsetX", "debuffOffsetY", "debuffGrowDirection", "debuffPerRow", "debuffWrapDirection", "debuffCap", "debuffHideTooltips", - "dispellableDebuffLocation", "dispellableDebuffGrowDirection", - "dispellableDebuffOffsetX", "dispellableDebuffOffsetY", "dispellableDebuffSize", + -- The dispellableDebuff* keys live in "dispels": that is the section + -- whose header their controls are drawn under. }, debuffStyle = { "debuffSize", "debuffIconZoom", "debuffBorderSize", "debuffBorderColor", "debuffSpacing", From 82cd05915ba73aeec2ef369ee919f5e2bdc6a88c Mon Sep 17 00:00:00 2001 From: Glyalith Date: Fri, 7 Aug 2026 19:32:26 -0600 Subject: [PATCH 2/3] Give dispelIconBorderSize an explicit default ReloadPartyFrames temp-swaps party overrides onto db.profile and restores from a table populated with saved[key] = raw[key]. A nil raid value stores no entry, so the restore loop skips that key and the party value stays on the shared raid key permanently. Every other key in the section has a default, which NewDB merges into the profile at load, so their raid value is never nil in memory. dispelIconBorderSize relied on an `or 2` read fallback instead, and it only became reachable as a party override in the previous commit. Store the same value as a real default so the swap always has something to restore. --- EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua b/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua index 6c95fa3e..526a4cbc 100644 --- a/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua +++ b/EllesmereUIRaidFrames/EllesmereUIRaidFrames.lua @@ -575,6 +575,12 @@ local defaults = { dispelIconOffsetX = 0, dispelIconOffsetY = 0, dispelIconSize = 16, + -- 12.1 dispel ring thickness in physical pixels (-1 follows the icon's own + -- Border, 0 hides it). Stored explicitly rather than left to the `or 2` + -- read fallback: ReloadPartyFrames temp-swaps party values onto db.profile + -- and restores from a table keyed by the raid value, so a key with no + -- default is absent from that table and its party value would stick. + dispelIconBorderSize = 2, dispelClockBorder = false, -- animated clock-style dispel border (erases clockwise) on dispellable debuff icons dispelClockExtraBorder = 0, -- extra physical pixels added to the clock border thickness (on top of debuffBorderSize) dispellableDebuffLocation = "same", -- "same" = use the main debuff layout; else a separate anchor for dispellable debuffs From 9c57a3d1e21864afc6897c2d7bf7b0124488fead Mon Sep 17 00:00:00 2001 From: Glyalith Date: Fri, 7 Aug 2026 19:48:06 -0600 Subject: [PATCH 3/3] Clear dispellableDebuff* party overrides whose sync gating would flip The no-migration claim was wrong. Writing one of these values required both Dispels and Debuff Display to be custom, but re-syncing Dispels afterwards only deleted keys mapped to "dispels", and these were mapped to "debuffDisplay". So a stored override could survive as LIVE under a custom Debuff Display with Dispels synced, and would go dormant under the new mapping. The mirror case, dormant under a synced Debuff Display and live once Dispels is custom, would switch on and change how party frames look. Clear the override whenever its live/dormant state flips. Flipping to live is the case that must be neutralized, and clearing preserves exactly what party renders today. Flipping to dormant renders the same either way, and clearing stops a zombie value reviving the next time Dispels is unsynced. An override live under both mappings is left untouched. --- EllesmereUI_Migration.lua | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/EllesmereUI_Migration.lua b/EllesmereUI_Migration.lua index 553a8134..48058763 100644 --- a/EllesmereUI_Migration.lua +++ b/EllesmereUI_Migration.lua @@ -4356,3 +4356,42 @@ EllesmereUI.RegisterMigration({ if type(p) == "table" then p.showCastTarget = false end end, }) + +-------------------------------------------------------------------------------- +-- Raid Frames: dispellableDebuff* keys moved party-sync sections +-- +-- Their controls are drawn under the DISPELS header but the keys were filed +-- under "debuffDisplay", so on the Party tab they were editable whenever +-- Dispels was unsynced while the write routed through Debuff Display. They now +-- file under "dispels". +-- +-- Writing one required BOTH sections custom, but re-syncing DISPELS afterwards +-- only deleted keys mapped to "dispels", so these could survive as a live +-- override under a custom Debuff Display with Dispels synced. Under the new +-- mapping that value would go dormant; the mirror case (dormant under a synced +-- Debuff Display, live once Dispels is custom) would switch on. +-- +-- Clear the override whenever its live/dormant state would flip. In the +-- flip-to-live case that preserves exactly what the party renders today; in +-- the flip-to-dormant case the party inherits raid either way, and clearing +-- stops the value reviving later. An override live in BOTH mappings (both +-- sections custom, the normal case) is left untouched. +-------------------------------------------------------------------------------- +EllesmereUI.RegisterMigration({ + id = "rf_dispellable_debuff_party_section_v1", + scope = "profile", + description = "Clear dispellableDebuff* party overrides whose live/dormant state would flip when the keys moved to the Dispels sync section.", + body = function(ctx) + local rf = ctx.profile.addons and ctx.profile.addons.EllesmereUIRaidFrames + if type(rf) ~= "table" then return end + local ss = type(rf.partySyncSections) == "table" and rf.partySyncSections or nil + local wasLive = (ss and ss.debuffDisplay == false) and true or false + local willBeLive = (ss and ss.dispels == false) and true or false + if wasLive == willBeLive then return end + rf.party_dispellableDebuffLocation = nil + rf.party_dispellableDebuffGrowDirection = nil + rf.party_dispellableDebuffOffsetX = nil + rf.party_dispellableDebuffOffsetY = nil + rf.party_dispellableDebuffSize = nil + end, +})