1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-11 00:04:24 +00:00

Clipper: added SeekCursorForItem() function, for use when using ImGuiListClipper::Begin(INT_MAX). (#1311)

Tagging #3609 just in case we made a mistake introducing a regression (but tests are passing and have been extended).
This commit is contained in:
ocornut 2024-07-17 18:14:01 +02:00
parent 74a1854db9
commit 8bab3eab6a
3 changed files with 30 additions and 14 deletions

View file

@ -2911,15 +2911,6 @@ static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_
}
}
static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)
{
// StartPosY starts from ItemsFrozen hence the subtraction
// Perform the add and multiply with double to allow seeking through larger ranges
ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight);
ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);
}
ImGuiListClipper::ImGuiListClipper()
{
memset(this, 0, sizeof(*this));
@ -2956,6 +2947,7 @@ void ImGuiListClipper::Begin(int items_count, float items_height)
data->Reset(this);
data->LossynessOffset = window->DC.CursorStartPosLossyness.y;
TempData = data;
StartSeekOffsetY = data->LossynessOffset;
}
void ImGuiListClipper::End()
@ -2966,7 +2958,7 @@ void ImGuiListClipper::End()
ImGuiContext& g = *Ctx;
IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name);
if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
SeekCursorForItem(ItemsCount);
// Restore temporary buffer and fix back pointers which may be invalidated when nesting
IM_ASSERT(data->ListClipper == this);
@ -2990,6 +2982,17 @@ void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end));
}
// This is already called while stepping.
// The ONLY reason you may want to call this is if you passed INT_MAX to ImGuiListClipper::Begin() because you couldn't step item count beforehand.
void ImGuiListClipper::SeekCursorForItem(int item_n)
{
// - Perform the add and multiply with double to allow seeking through larger ranges.
// - StartPosY starts from ItemsFrozen, by adding SeekOffsetY we generally cancel that out (SeekOffsetY == LossynessOffset - ItemsFrozen * ItemsHeight).
// - The reason we store SeekOffsetY instead of inferring it, is because we want to allow user to perform Seek after the last step, where ImGuiListClipperData is already done.
float pos_y = (float)((double)StartPosY + StartSeekOffsetY + (double)item_n * ItemsHeight);
ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, ItemsHeight);
}
static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
{
ImGuiContext& g = *clipper->Ctx;
@ -3053,6 +3056,9 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
const int already_submitted = clipper->DisplayEnd;
if (calc_clipping)
{
// Record seek offset, this is so ImGuiListClipper::Seek() can be called after ImGuiListClipperData is done
clipper->StartSeekOffsetY = (double)data->LossynessOffset - data->ItemsFrozen * (double)clipper->ItemsHeight;
if (g.LogEnabled)
{
// If logging is active, do not perform any clipping
@ -3100,7 +3106,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
if (clipper->DisplayStart > already_submitted) //-V1051
ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);
clipper->SeekCursorForItem(clipper->DisplayStart);
data->StepNo++;
if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)
continue;
@ -3110,7 +3116,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
// After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
// Advance the cursor to the end of the list and then returns 'false' to end the loop.
if (clipper->ItemsCount < INT_MAX)
ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount);
clipper->SeekCursorForItem(clipper->ItemsCount);
return false;
}