B2: add Dalamud-free CardClipPlanner variable-height clip-plan helper
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HellionChat.Ui.Components;
|
||||
|
||||
// B2 (PERF-B2): variable-height clip plan for card mode. ImGuiListClipper needs
|
||||
// a constant row height, so card mode (rows wrap to arbitrary heights) computes
|
||||
// its own 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, spacing-inclusive height of row i in draw order.
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user