using System; using System.Collections.Generic; namespace AcDream.App.UI.Layout; /// /// Shared text shaping for retail indicator detail pages. Retail /// UIElement_Text::SetText reflows newline-delimited strings into the /// authored field width; acdream's retained text seam carries already-shaped /// lines, so controllers perform the equivalent shaping before publication. /// internal static class IndicatorDetailText { public static IReadOnlyList Shape(UiText target, string text) { ArgumentNullException.ThrowIfNull(target); text ??= string.Empty; float maxWidth = Math.Max(1f, target.Width - (2f * target.Padding)); float Measure(string value) => target.DatFont?.MeasureWidth(value) ?? target.Font?.MeasureWidth(value) ?? value.Length * 8f; var lines = new List(); // DAT-resolved bodies (vitae, link status, effects) arrive with // real line breaks — escapes decode at the string source // (DatStringResolver → RetailStringEscapes, 2026-08-17 systemic // round). Wire-sourced text (the appraisal inscription) renders // verbatim, exactly like retail's ItemExamineUI::AddItemInfo // @ 0x004AC050 → UIElement_Text::AppendTextWithFont direct append. foreach (string paragraph in text.Split('\n')) { if (paragraph.Length == 0) { lines.Add(new UiText.Line(string.Empty, target.DefaultColor)); continue; } foreach (string line in ChatTranscriptRenderer.WrapText(paragraph, maxWidth, Measure)) lines.Add(new UiText.Line(line, target.DefaultColor)); } return lines; } }