fix(ui): retail tooltip rendering — formula-first compose and the two-pass sizing every tooltip was missing
Two corrections from the owner's retail-render oracle at the CA5 re-check, both against readings the TS-85 register row had recorded as settled: Compose (skill tooltips): retail is formula + newline + description — GetTooltip @0x004f1fe0's operator+ has the InqSkillFormula output as the LEFT operand; the old '"\n" + formula, no separator' reading had the operand order backwards and produced a leading blank line with the formula and description glued on one line. A formula-less skill (Salvaging) shows the bare description, matching the failed-InqSkillFormula branch. Sizing (ALL tooltips, per the owner's direction): retail sizes a tooltip in TWO passes (StartTooltip @0x0045DE90) — measure-wrap at the max width, resize the root through the authored ResizeTo clamps, then RecalculateGlyphList RE-WRAPS the text at its final clamped width and a second resize grows the root's HEIGHT for the extra lines. The branch the register called 'a structural no-op' IS that second pass; without it a description longer than the clamped popup stayed one clipped line, where retail shows three. ApplyTooltipText now ports the full chain, so every tooltip surface (items, options rows, character panel, world hover, map) wraps and grows exactly as retail. Pinned by BuildTooltip_FormulaFirstThenNewlineThenDescription, BuildTooltip_FormulaLessSkillShowsBareDescription, and LongTooltip_RewrapsAtTheClampedPopupWidth_AndGrowsHeightForTheExtraLines. TS-85 carries both dated corrections. Owner visual re-check owed: skill tooltip shows formula on line one, description below, long descriptions wrapping to three-plus lines inside the parchment. Full hermetic suite 15,332 passed / 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
51a7c99b94
commit
1e8596a440
5 changed files with 174 additions and 18 deletions
|
|
@ -626,15 +626,27 @@ public sealed class RetailTooltipPresenter : IDisposable
|
|||
? bitmapFont.MeasureWidth
|
||||
: static s => s.Length * 8f;
|
||||
|
||||
float wrapWidth = MathF.Max(1f, _host.EffectiveCanvasSize.X);
|
||||
var wrapped = UiText.WrapWords(tooltipText, measure, wrapWidth);
|
||||
text.LinesProvider = () => wrapped
|
||||
.Select(line => new UiText.Line(line, text.DefaultColor))
|
||||
.ToArray();
|
||||
|
||||
float measuredWidth = wrapped.Count == 0 ? 0f : wrapped.Max(measure);
|
||||
// CA5-gate correction (2026-08-24, owner retail-render oracle):
|
||||
// retail sizes a tooltip in TWO passes, and the second is what makes
|
||||
// long tooltips multi-line. StartTooltip @0x0045DE90:
|
||||
// 1. MEASURE — InqSizewMargins(..., UITS_MAX_WIDTH): wrap at the
|
||||
// authored P0x3D max width, else the display width, producing
|
||||
// the measured extent.
|
||||
// 2. Resize the ROOT by the measured-vs-authored delta through
|
||||
// ResizeTo, where the popup skin's authored max/min CLAMP.
|
||||
// 3. RecalculateGlyphList — the text RE-WRAPS at its FINAL
|
||||
// (possibly clamped) width.
|
||||
// 4. A second ResizeTo grows the root's HEIGHT (width unchanged)
|
||||
// when the re-wrapped glyph extent needs more than the text
|
||||
// child's current height.
|
||||
// The pre-correction port did only pass 1, so a description longer
|
||||
// than the clamped popup stayed one clipped line.
|
||||
float lineHeight = text.DatFont?.LineHeight ?? text.Font?.LineHeight ?? 14f;
|
||||
float measuredHeight = wrapped.Count * lineHeight;
|
||||
|
||||
float measureWrapWidth = MathF.Max(1f, _host.EffectiveCanvasSize.X);
|
||||
var measured = UiText.WrapWords(tooltipText, measure, measureWrapWidth);
|
||||
float measuredWidth = measured.Count == 0 ? 0f : measured.Max(measure);
|
||||
float measuredHeight = measured.Count * lineHeight;
|
||||
|
||||
float requestedWidth = root.Width + (measuredWidth - authoredTextWidth);
|
||||
float requestedHeight = root.Height + (measuredHeight - authoredTextHeight);
|
||||
|
|
@ -651,10 +663,40 @@ public sealed class RetailTooltipPresenter : IDisposable
|
|||
if (root.AuthoredResizeMinWidth is { } minWidth && requestedWidth < minWidth)
|
||||
requestedWidth = minWidth;
|
||||
|
||||
float authoredRootWidth = root.Width;
|
||||
float authoredRootHeight = root.Height;
|
||||
root.Width = requestedWidth;
|
||||
root.Height = requestedHeight;
|
||||
text.Width = measuredWidth;
|
||||
text.Height = measuredHeight;
|
||||
|
||||
// The text child follows the root's ACTUAL growth (retail's
|
||||
// anchored resize) — the clamp is what makes these differ from the
|
||||
// measured extents.
|
||||
float textFinalWidth = MathF.Max(
|
||||
1f, authoredTextWidth + (requestedWidth - authoredRootWidth));
|
||||
float textFinalHeight =
|
||||
authoredTextHeight + (requestedHeight - authoredRootHeight);
|
||||
|
||||
// Pass 3: re-wrap at the final clamped width (RecalculateGlyphList).
|
||||
var wrapped = UiText.WrapWords(tooltipText, measure, textFinalWidth);
|
||||
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;
|
||||
|
||||
// Pass 4: grow the root's height by the re-wrap's overflow beyond
|
||||
// the text child's post-resize height (width unchanged), through
|
||||
// the same ResizeTo clamps.
|
||||
if (rewrappedHeight > textFinalHeight)
|
||||
{
|
||||
float grownHeight = root.Height + (rewrappedHeight - textFinalHeight);
|
||||
if (root.AuthoredResizeMaxHeight is { } maxH2 && grownHeight > maxH2)
|
||||
grownHeight = maxH2;
|
||||
if (root.AuthoredResizeMinHeight is { } minH2 && grownHeight < minH2)
|
||||
grownHeight = minH2;
|
||||
root.Height = grownHeight;
|
||||
}
|
||||
text.Height = rewrappedHeight;
|
||||
}
|
||||
|
||||
/// <summary>Retail <c>UIElementManager::StartTooltip @0x00459700</c>: the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue