diff --git a/HellionChat/Ui/Components/Settings/LivePreviewPanel.cs b/HellionChat/Ui/Components/Settings/LivePreviewPanel.cs index 815db7f..1084f39 100644 --- a/HellionChat/Ui/Components/Settings/LivePreviewPanel.cs +++ b/HellionChat/Ui/Components/Settings/LivePreviewPanel.cs @@ -26,15 +26,25 @@ internal sealed class LivePreviewPanel : IDisposable internal static int InstanceCount; // 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 MockTell = "Tell → Player: Hey, want to party?"; 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 // 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 readonly ThemeRegistry _themes; @@ -259,6 +269,29 @@ internal sealed class LivePreviewPanel : IDisposable 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); draw.AddRectFilled( padMin, @@ -274,11 +307,40 @@ internal sealed class LivePreviewPanel : IDisposable (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 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++) { - var pos = new Vector2(listOrigin.X + 6f, listOrigin.Y + 6f + i * lineHeight); - draw.AddText(pos, ColourUtil.RgbaToAbgr(rows[i].Rgba), rows[i].Text); + var y = textTop + i * lineHeight; + 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(