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