fix #430: tooltip wrap and draw honor the text child's authored margins
All checks were successful
CI / linux-portable (push) Successful in 3m29s
CI / windows-gate (push) Successful in 5m44s
CI / release (push) Successful in 2m19s

Third owner-screenshot round: acdream fit one more word per line than
retail and drew glyphs flush against the popup's right border. Retail's
InqSizewMargins @0x00469660 wraps the glyph list at
(bound - m_margL - m_margR) and adds the margins back into the measured
width; the popup skins' shared text child 0x10000396 authors margins
L=2/R=2 (U=2/D=2 on three of the four skins — live-DAT probed). The
presenter now subtracts the horizontal margins from both wrap passes,
re-adds them into the measured width used for root sizing, and counts
the vertical margins in the measured/re-wrapped heights; the widget's
own draw already insets by all four margins (UiText ContentOffsetX +
the top/bottom inset), so the right-side spacing returns for free.

TooltipSkinLiveDatTests pins the authored margins per skin alongside
the P0x3D=256 wrap bound; a new presenter test proves margins shrink
the wrap bound and survive onto the widget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-24 18:44:28 +02:00
parent d087b50aa3
commit 35abbe1d0d
3 changed files with 92 additions and 11 deletions

View file

@ -660,12 +660,25 @@ public sealed class RetailTooltipPresenter : IDisposable
text.Centered = false;
text.RightAligned = false;
float measureWrapWidth = text.AuthoredResizeMaxWidth is { } authoredMaxTextWidth
// (c) The text child's authored margins (P0x23-0x26 — L2/R2/U2/D2 on
// the popup skins) participate exactly as InqSizewMargins does:
// GlyphList::Recalculate wraps at (width margL margR) and
// the measured result adds the margins back
// (@0x00469762/@0x004697..: `Recalculate(..., w margL margR)`
// then `*out += margR + margL`). Without this, line one fit one
// more word than retail (256 vs retail's 252 wrap) and the text
// drew flush against the parchment's right border.
float marginsX = text.MarginLeft + text.MarginRight;
float marginsY = text.MarginTop + text.MarginBottom;
float wrapBound = text.AuthoredResizeMaxWidth is { } authoredMaxTextWidth
? MathF.Max(1f, authoredMaxTextWidth)
: MathF.Max(1f, _host.EffectiveCanvasSize.X);
float measureWrapWidth = MathF.Max(1f, wrapBound - marginsX);
var measured = UiText.WrapWords(tooltipText, measure, measureWrapWidth);
float measuredWidth = measured.Count == 0 ? 0f : measured.Max(measure);
float measuredHeight = measured.Count * lineHeight;
float measuredWidth =
(measured.Count == 0 ? 0f : measured.Max(measure)) + marginsX;
float measuredHeight = measured.Count * lineHeight + marginsY;
float requestedWidth = root.Width + (measuredWidth - authoredTextWidth);
float requestedHeight = root.Height + (measuredHeight - authoredTextHeight);
@ -697,13 +710,17 @@ public sealed class RetailTooltipPresenter : IDisposable
float textFinalHeight =
authoredTextHeight + (requestedHeight - authoredRootHeight);
// Pass 3: re-wrap at the final clamped width (RecalculateGlyphList).
var wrapped = UiText.WrapWords(tooltipText, measure, textFinalWidth);
// Pass 3: re-wrap at the final clamped width, inside the margins
// (RecalculateGlyphList wraps glyphs at width margL margR).
var wrapped = UiText.WrapWords(
tooltipText, measure, MathF.Max(1f, textFinalWidth - marginsX));
text.LinesProvider = () => wrapped
.Select(line => new UiText.Line(line, text.DefaultColor))
.ToArray();
text.Width = wrapped.Count == 0 ? 0f : MathF.Min(textFinalWidth, wrapped.Max(measure));
float rewrappedHeight = wrapped.Count * lineHeight;
text.Width = wrapped.Count == 0
? 0f
: MathF.Min(textFinalWidth, wrapped.Max(measure) + marginsX);
float rewrappedHeight = wrapped.Count * lineHeight + marginsY;
// Pass 4: grow the root's height by the re-wrap's overflow beyond
// the text child's post-resize height (width unchanged), through