fix(settings): let the preview show what the log shows

The preview was four flat lines of text on a plain field. After this cycle the
real log has a channel header above it, a fixed timestamp column, and system
messages in italics -- so the preview had quietly become a picture of a window
that no longer exists. That is the same defect as a widget with no call site,
just pointing the other way: something on screen that stopped tracking what it
describes.

The reserved band grew with it. It is a fixed height that the sidebar mock also
divides by, so adding a row inside without raising it would have pushed the last
message out of the space -- the recurring drawing-into-unreserved-space mistake
this project keeps stepping on.

Preview stamps are fixed rather than live. A clock ticking inside a settings
panel pulls the eye away from the setting being changed.
This commit is contained in:
2026-08-19 11:50:19 +02:00
parent 63d1b34b00
commit 0399b68d8c
@@ -26,15 +26,25 @@ internal sealed class LivePreviewPanel : IDisposable
internal static int InstanceCount; internal static int InstanceCount;
// Plan-mandated mock strings — international tester-ready, do not localise. // Plan-mandated mock strings — international tester-ready, do not localise.
private const string MockSystem = "System: Connection established"; private const string MockSystem = "Connection established";
private const string MockSay = "Say: Hello, world!"; private const string MockSay = "Say: Hello, world!";
private const string MockTell = "Tell → Player: Hey, want to party?"; private const string MockTell = "Tell → Player: Hey, want to party?";
private const string MockFc = "FC: Welcome aboard."; private const string MockFc = "FC: Welcome aboard.";
// The stamps the preview shows against its own rows. Fixed rather than live:
// a clock ticking inside a settings preview draws the eye away from the
// setting being changed.
private static readonly string[] MockStamps = ["22:10", "22:14", "22:15", "22:17"];
private const string MockChannel = "GENERAL";
// Crown/cog render via the FontAwesome font (FontManager) so the preview // Crown/cog render via the FontAwesome font (FontManager) so the preview
// matches the real header glyphs; the bundled text font has no crown glyph. // matches the real header glyphs; the bundled text font has no crown glyph.
private const float MiddleBandHeight = 220f; // Grew with the channel header: the band is reserved as a fixed height and
// the sidebar mock divides by it, so a row added inside without raising this
// would have pushed the last message out of the reserved space.
private const float MiddleBandHeight = 248f;
private const float SidebarWidth = 70f; private const float SidebarWidth = 70f;
private readonly ThemeRegistry _themes; private readonly ThemeRegistry _themes;
@@ -259,6 +269,29 @@ internal sealed class LivePreviewPanel : IDisposable
draw.AddRectFilled(listOrigin, max, ColourUtil.RgbaToAbgr(theme.Colors.WindowBg)); draw.AddRectFilled(listOrigin, max, ColourUtil.RgbaToAbgr(theme.Colors.WindowBg));
// The channel header the real window now carries above its log. Tracked
// caps, same as the widget draws them.
var headerHeight = ImGui.GetTextLineHeight() + 8f;
draw.AddRectFilled(
listOrigin,
new Vector2(max.X, listOrigin.Y + headerHeight),
ColourUtil.RgbaToAbgr(theme.Colors.Surface)
);
draw.AddLine(
new Vector2(listOrigin.X, listOrigin.Y + headerHeight),
new Vector2(max.X, listOrigin.Y + headerHeight),
ColourUtil.RgbaToAbgr(theme.Colors.Border),
1f
);
draw.DrawTrackedText(
new Vector2(listOrigin.X + 6f, listOrigin.Y + 4f),
MockChannel,
ColourUtil.RgbaToAbgr(
ColourUtil.EnsureContrast(theme.Colors.Accent, theme.Colors.Surface, 4.5f)
),
1.8f
);
var padMin = new Vector2(listOrigin.X + 2f, max.Y - 6f); var padMin = new Vector2(listOrigin.X + 2f, max.Y - 6f);
draw.AddRectFilled( draw.AddRectFilled(
padMin, padMin,
@@ -274,11 +307,40 @@ internal sealed class LivePreviewPanel : IDisposable
(MockFc, theme.Colors.StatusSuccess), (MockFc, theme.Colors.StatusSuccess),
]; ];
// A fixed stamp column, like the log has, so the senders line up in the
// preview the same way they line up for real.
var stampWidth = ImGui.CalcTextSize(TimestampColumn.SampleFor(true)).X + 8f;
var lineHeight = ImGui.GetTextLineHeightWithSpacing(); var lineHeight = ImGui.GetTextLineHeightWithSpacing();
var textTop = listOrigin.Y + headerHeight + 4f;
var fonts = Plugin.Instance.FontManager;
var italic =
Plugin.Config.FontsEnabled && fonts.ItalicFont is not null
? fonts.ItalicFont
: fonts.AxisItalic;
for (var i = 0; i < rows.Length; i++) for (var i = 0; i < rows.Length; i++)
{ {
var pos = new Vector2(listOrigin.X + 6f, listOrigin.Y + 6f + i * lineHeight); var y = textTop + i * lineHeight;
draw.AddText(pos, ColourUtil.RgbaToAbgr(rows[i].Rgba), rows[i].Text); draw.AddText(
new Vector2(listOrigin.X + 6f, y),
ColourUtil.RgbaToAbgr(theme.Colors.TextDim),
MockStamps[i]
);
var textPos = new Vector2(listOrigin.X + 6f + stampWidth, y);
var colour = ColourUtil.RgbaToAbgr(rows[i].Rgba);
// Row zero is the system line, and the log draws those in italics.
if (i == 0)
{
using (italic.Push())
draw.AddText(textPos, colour, rows[i].Text);
}
else
{
draw.AddText(textPos, colour, rows[i].Text);
}
} }
draw.AddLine( draw.AddLine(