Skip to content

Commit 62b8f57

Browse files
authored
Merge pull request #2019 from LarryThiessen/fix-2018-pool-reset-styling
#2018 Reset styling, subframe art and frame flags on widget reuse
2 parents c84c820 + 6d04990 commit 62b8f57

2 files changed

Lines changed: 75 additions & 27 deletions

File tree

GSE_GUI/Editor.lua

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,20 @@ local MACRO_BOX_CHROME_SLACK = 6
607607
local MACRO_BOX_MIN_INNER = 40
608608
-- Rows -> pixels in the box's OWN font: a row is the measured line height, and
609609
-- every row after the first also carries the editbox's line spacing.
610+
-- Height meters, keyed by the box's frame rather than stored ON it.
611+
--
612+
-- A WoW FontString cannot be destroyed, so the meter has to be created once per
613+
-- frame and found again on reuse. It lived on the widget table first -- #2014's
614+
-- pool strips post-construction keys, so that leaked one FontString per reuse --
615+
-- and then on the frame, which this branch's reset now sweeps too, which would
616+
-- leak it again exactly the same way. Neither table is a safe home, so it lives
617+
-- here. Weak keys: the frame is the only thing that should keep an entry alive.
618+
--
619+
-- Left as a warning for the next caller that caches a region on a widget or its
620+
-- frame: the pool is now entitled to remove it, and the failure is silent and
621+
-- cumulative -- an orphan FontString per reuse, each one another entry in the
622+
-- GetRegions() walk that the reset itself runs on every reuse.
623+
local macroBoxHeightMeters = setmetatable({}, {__mode = "k"})
610624
local function MacroBoxRowsHeight(rows, oneRow, spacing)
611625
return rows * oneRow + math.max(rows - 1, 0) * spacing
612626
end
@@ -696,18 +710,11 @@ local function FitMacroEditBoxToContent(macroEditBox, text)
696710
-- MEASURE the rendered text height with a hidden FontString in the box's
697711
-- own font (wraps included) instead of estimating rows x font size --
698712
-- estimates drifted by about a row and showed a spare empty line.
699-
-- On the FRAME, not the widget table. Since #2014 MultiLineEditBox is a
700-
-- pooled type, and resetForReuse strips every key added after construction
701-
-- -- including this one. A FontString cannot be destroyed, so caching it on
702-
-- the widget meant a fresh one on every reuse, piling up hidden regions on a
703-
-- frame that is reused forever. That also slows the pool down: its reset
704-
-- walks {frame:GetRegions()} each time. The frame object survives reuse
705-
-- unchanged, so the meter parked on it is found again.
706-
local meter = macroEditBox.frame.gseHeightMeter
713+
local meter = macroBoxHeightMeters[macroEditBox.frame]
707714
if not meter then
708715
meter = macroEditBox.frame:CreateFontString(nil, "ARTWORK")
709716
meter:Hide()
710-
macroEditBox.frame.gseHeightMeter = meter
717+
macroBoxHeightMeters[macroEditBox.frame] = meter
711718
end
712719
local fontPath, fontSize, fontFlags = eb:GetFont()
713720
if fontPath then meter:SetFont(fontPath, fontSize or 14, fontFlags or "") end

GSE_GUI/NativeUI.lua

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5891,23 +5891,54 @@ local function snapshotPristine(widget)
58915891
scripts[#scripts + 1] = { v, rec }
58925892
end
58935893
end
5894-
-- Callers also hang REGIONS (FontStrings, Textures) and child FRAMES
5895-
-- directly off the widget's frame (frame:CreateFontString, CreateFrame
5896-
-- with the frame as parent). Those are invisible to the key sweep -- they
5897-
-- live on the frame, not in the widget table -- and a reused widget would
5898-
-- keep rendering them (e.g. a dependency header bleeding into a macro
5899-
-- block). Record what the frame owned at construction; anything else gets
5900-
-- hidden on reuse.
5901-
local owned = {}
5902-
for _, region in ipairs({ widget.frame:GetRegions() }) do owned[region] = true end
5903-
for _, child in ipairs({ widget.frame:GetChildren() }) do owned[child] = true end
5904-
widget.__gsePristineOwned = owned
5894+
-- Callers also hang REGIONS (FontStrings, Textures), child FRAMES and
5895+
-- plain FLAGS directly off the widget's frames -- the TOP frame and its
5896+
-- exposed subframes alike (frame:CreateFontString, CreateFrame with the
5897+
-- frame as parent, editBox.GSEMacroEditorColoring = true...). All of that
5898+
-- is invisible to the widget-table key sweep and survives into the next
5899+
-- life: dependency headers bled into macro blocks, block rail art bled
5900+
-- into the Config panel, and the macro-colouring flag turned the NOTES
5901+
-- box into a macro editor. Record, for every frame the widget exposes,
5902+
-- its construction-time key set, regions and children; on reuse, sweep
5903+
-- added keys and hide stranger regions/children.
5904+
local frames = {}
5905+
for _, v in pairs(widget) do
5906+
if type(v) == "table" and v.GetScript and v.SetScript and v.CreateFontString and not frames[v] then
5907+
local fkeys = {}
5908+
for k in pairs(v) do fkeys[k] = true end
5909+
local owned = {}
5910+
for _, region in ipairs({ v:GetRegions() }) do owned[region] = true end
5911+
for _, child in ipairs({ v:GetChildren() }) do owned[child] = true end
5912+
frames[v] = { keys = fkeys, owned = owned }
5913+
end
5914+
end
5915+
widget.__gsePristineFrames = frames
5916+
-- Callers also restyle the widget's FontStrings (class colours, heading
5917+
-- fonts, justification). Record each construction-time text region's font,
5918+
-- colour and justify so a reused label does not wear its previous life's
5919+
-- styling.
5920+
local texts = {}
5921+
for _, v in pairs(widget) do
5922+
-- FontStrings only: they carry SetFont/SetText but -- unlike Frames and
5923+
-- EditBoxes, which also have font APIs -- cannot CreateFontString.
5924+
-- (Filtering on "no SetScript" was wrong: FontStrings are ScriptRegions
5925+
-- and DO have SetScript, so nothing was ever captured.)
5926+
if type(v) == "table" and v.GetFont and v.SetText and not v.CreateFontString and not texts[v] then
5927+
texts[v] = {
5928+
font = { v:GetFont() },
5929+
color = { v:GetTextColor() },
5930+
justifyH = v.GetJustifyH and v:GetJustifyH() or nil,
5931+
justifyV = v.GetJustifyV and v:GetJustifyV() or nil,
5932+
}
5933+
end
5934+
end
5935+
widget.__gsePristineTexts = texts
59055936
widget.__gsePristineKeys = keys
59065937
widget.__gsePristineScripts = scripts
59075938
widget.__gsePristineW, widget.__gsePristineH = widget.frame:GetSize()
59085939
keys.__gsePristineKeys, keys.__gsePristineScripts = true, true
59095940
keys.__gsePristineW, keys.__gsePristineH = true, true
5910-
keys.__gsePristineOwned = true
5941+
keys.__gsePristineFrames, keys.__gsePristineTexts = true, true
59115942
end
59125943

59135944
local function resetForReuse(widget)
@@ -5924,13 +5955,17 @@ local function resetForReuse(widget)
59245955
end
59255956
end
59265957
local frame = widget.frame
5927-
local owned = widget.__gsePristineOwned
5928-
if owned then
5929-
for _, region in ipairs({ frame:GetRegions() }) do
5930-
if not owned[region] then region:Hide() end
5958+
for subframe, rec in pairs(widget.__gsePristineFrames or {}) do
5959+
-- Sweep caller-added fields off the frame itself ([0] is the engine
5960+
-- userdata; construction-time keys stay).
5961+
for k in pairs(subframe) do
5962+
if not rec.keys[k] and k ~= 0 then subframe[k] = nil end
59315963
end
5932-
for _, child in ipairs({ frame:GetChildren() }) do
5933-
if not owned[child] then child:Hide() end
5964+
for _, region in ipairs({ subframe:GetRegions() }) do
5965+
if not rec.owned[region] then region:Hide() end
5966+
end
5967+
for _, child in ipairs({ subframe:GetChildren() }) do
5968+
if not rec.owned[child] then child:Hide() end
59345969
end
59355970
end
59365971
frame:Hide()
@@ -5947,6 +5982,12 @@ local function resetForReuse(widget)
59475982
if widget.text and widget.text ~= widget.label and widget.text.SetText then
59485983
pcall(widget.text.SetText, widget.text, "")
59495984
end
5985+
for fontString, style in pairs(widget.__gsePristineTexts or {}) do
5986+
if style.font[1] then pcall(fontString.SetFont, fontString, unpack(style.font)) end
5987+
pcall(fontString.SetTextColor, fontString, unpack(style.color))
5988+
if style.justifyH then pcall(fontString.SetJustifyH, fontString, style.justifyH) end
5989+
if style.justifyV then pcall(fontString.SetJustifyV, fontString, style.justifyV) end
5990+
end
59505991
end
59515992

59525993
function UI:Create(typeName)

0 commit comments

Comments
 (0)