Files
HellionChat/HellionChat/Ui/Components/CardClipPlanner.cs
T
JonKazama-Hellion 16557213cd chore: comments, second pass -- the task codes the first pass missed
The first sweep matched a character class that swallowed the digit, so a bare
B1 slipped through while B1-2 was caught. Searching the whole A-Z space instead
of guessing prefixes turned up 130-odd more: B0 through B6, C2, C3, D1, H2, M6,
P7, P8, T2, W2, plus GP-04, KB-01, OD-1, PM-1, PM-3, SEC-01, TR-4, TR-7, UI-11,
UI-12, XC-8 and API-3.

Kept deliberately: 41 B4 01 is a byte signature, "N0" a format string,
#L119-L128 a source anchor, LS4/LS6 are linkshells, and A=FF B=0C G=41 R=C2
explains a colour-channel order. Those look like codes and are not.

Also translated the eight German comments left in the theme files and
ImGuiUtil. Seven of them described what a palette does to which channel, which
is worth reading -- just not in a second language in an otherwise English
codebase.
2026-08-19 22:03:12 +02:00

78 lines
2.6 KiB
C#

using System.Collections.Generic;
namespace HellionChat.Ui.Components;
// Variable-height clip plan. ImGuiListClipper needs a constant
// row height, and since v1.10.0 neither density has one (compact rows wrap
// too), so both compute a plan from the cached per-row heights: a lead dummy
// for the rows above
// the viewport, the [first..last] index range that overlaps the viewport, and
// an end dummy for the rows below. This is the prefix-sum analogue of
// OtterGui's GetNecessarySkips, but for non-uniform heights — kept Dalamud-free
// so the Build Suite pins every edge case.
// TEST-MIRROR: ../../../../Hellion Build test/Ui/CardClipPlanTests.cs
internal readonly record struct CardClipPlan(
int FirstVisible,
int LastVisible,
float LeadDummyHeight,
float EndDummyHeight
);
internal static class CardClipPlanner
{
// heights[i] is the cached height of row i in draw order. It carries no
// trailing ItemSpacing: every row ends inside DrawChunks, where spacing is
// pushed to zero, and ImGui writes the advance at item submission time.
// A row overlaps the viewport iff rowTop < windowBottom && rowBottom >
// windowTop. FirstVisible/LastVisible are -1 when nothing overlaps (empty
// list); callers then submit a single end dummy of the full content height
// so the scrollbar stays correct.
internal static CardClipPlan Plan(
IReadOnlyList<float> heights,
float scrollY,
float viewportHeight
)
{
var count = heights.Count;
if (count == 0)
return new CardClipPlan(-1, -1, 0f, 0f);
var windowTop = scrollY;
var windowBottom = scrollY + viewportHeight;
var first = -1;
var last = -1;
var leadDummy = 0f;
var endDummy = 0f;
var cursor = 0f; // running prefix sum = top edge of the current row
for (var i = 0; i < count; i++)
{
var rowTop = cursor;
var rowBottom = cursor + heights[i];
var overlaps = rowTop < windowBottom && rowBottom > windowTop;
if (overlaps)
{
if (first < 0)
first = i;
last = i;
}
else if (first < 0)
{
// Still above the visible window -> grows the lead dummy.
leadDummy += heights[i];
}
else
{
// Already past the visible window -> grows the end dummy.
endDummy += heights[i];
}
cursor = rowBottom;
}
return new CardClipPlan(first, last, leadDummy, endDummy);
}
}