fix(CT-GF1): UiLabel opts out of the self-clip — plugin markup text restored

CT7 gate regression (owner report): all MossTank plugin text vanished
except button captions. A markup <label> authors position only, so
UiLabel's box was degenerate (0x0) and CT-GF1's completed self-clip
(UIRegion::DrawHere @0x0069FA30 shape) cropped its glyphs to nothing;
markup buttons author w/h, which is why their captions survived.

UiLabel now opts out of the self-clip — it is ClickThrough pure text
whose real containment is its ancestors (the plugin panel/window, which
are properly sized), the effective retail behavior for a text region
whose box hugs its glyphs — and keeps a truthful box by measuring its
current text each draw. Mechanism pin: an unsized label's subtree must
render inside its sized parent (probe-child draw-capture test).

Gate note recorded by the owner in the same round: the Titles-page
divider IS visible inside the window in retail while scrolling — a
retail quirk our clipped rendering now reproduces exactly. CT7 gate
PASSED apart from this regression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-25 07:28:26 +02:00
parent 9e85d82325
commit 752782d0a9
2 changed files with 68 additions and 0 deletions

View file

@ -117,9 +117,31 @@ public class UiLabel : UiElement
public UiLabel() { ClickThrough = true; }
/// <summary>
/// CT7 gate regression (2026-08-25, MossTank plugin text vanished): a
/// markup <c>&lt;label&gt;</c> authors position only, so this element's
/// box is degenerate (0x0) — under CT-GF1's completed
/// <c>UIRegion::DrawHere @0x0069FA30</c> port the self-clip cropped the
/// glyphs to nothing. A label must not self-clip: it is
/// <see cref="UiElement.ClickThrough"/> pure text whose real clip is
/// its ancestors (the plugin panel/window, which ARE properly sized) —
/// the same effective containment retail gives a text region whose box
/// hugs its glyphs. <see cref="OnDraw"/> below also keeps the box
/// truthful by measuring the current text, so layout/hit consumers see
/// real extents (converges the frame after a bound text change).
/// </summary>
protected override bool ClipsChildren => false;
protected override void OnDraw(UiRenderContext ctx)
{
string text = TextSource?.Invoke() ?? Text;
float w = DatFont is { } df
? df.MeasureWidth(text)
: (ctx.DefaultFont?.MeasureWidth(text) ?? text.Length * 7f);
float h = DatFont?.LineHeight
?? ctx.DefaultFont?.LineHeight ?? 14f;
if (w != Width) Width = w;
if (h != Height) Height = h;
if (DatFont is { } dat)
ctx.DrawStringDat(dat, text, 0, 0, TextColor, Outline);
else