From 0916f8d1fbac33f7f2f9ac64e2452de620441ab0 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Wed, 19 Aug 2026 09:49:21 +0200 Subject: [PATCH] feat(style): put mixed sizes on a shared baseline ImGui lines items up by their top edge. ItemSize only shifts anything when CurrLineTextBaseOffset is non-zero, and that stays zero unless AlignTextToFramePadding ran -- so a meta timestamp beside a body-sized name would sit flush at the top and float above the baseline. The correction is the difference of the two ascents, scaled. The scaling looks like it is applied twice and is not: Dalamud rasterises at SizePx * GlobalScale and then divides the metrics back down, so ImFont.Ascent comes out logical. Drawing multiplies it up again. The comment says so, because the first reviewer to see this file read it the other way. No call site yet -- the self-test in the next commit takes it, and the message list takes it in block C. --- HellionChat/Ui/StyleEngine/BaselineMath.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 HellionChat/Ui/StyleEngine/BaselineMath.cs diff --git a/HellionChat/Ui/StyleEngine/BaselineMath.cs b/HellionChat/Ui/StyleEngine/BaselineMath.cs new file mode 100644 index 0000000..4fdb87b --- /dev/null +++ b/HellionChat/Ui/StyleEngine/BaselineMath.cs @@ -0,0 +1,19 @@ +namespace HellionChat.Ui.StyleEngine; + +// TEST-MIRROR: Ui/BaselineMathTests.cs +// +// ImGui lines items up on a row by their top edge, not their baseline: ItemSize +// only shifts anything when CurrLineTextBaseOffset is non-zero, and that stays at +// zero unless AlignTextToFramePadding ran. So a smaller face beside a larger one +// hangs, flush at the top and floating above the baseline. +// +// The correction is the difference between the two ascents. It is easy to assume +// the display scale is applied twice here and it is not: Dalamud rasterises at +// SizePx * GlobalScale and then divides the metrics straight back down +// (ImGuiHelpers.AdjustGlyphMetrics(1 / scale, ...)), so ImFont.Ascent is a +// logical value. Drawing multiplies it up again -- and so must this. +internal static class BaselineMath +{ + internal static float OffsetFor(float ascentLarge, float ascentSmall, float uiScale) => + MathF.Max(0f, (ascentLarge - ascentSmall) * uiScale); +}