// Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
// If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
// Use case B: Begin() called from constructor with items_height>0
// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
IM_ASSERT(fabsf(cur_y-expected_display_end_y)<1.0f);// if this triggers, it probably means your items have varying height (in which case you can't use this helper) or the explicit height you have passed was incorrect.
if(StepNo==0)// Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
{
DisplayStart=0;
DisplayEnd=1;
StartPosY=ImGui::GetCursorPosY();
StepNo=1;
returntrue;
}
if(StepNo==1)// Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
IM_ASSERT(items_height>0.0f);// If this triggers, it means Item 0 hasn't moved the cursor vertically
ImGui::SetCursorPosY(StartPosY);// Rewind cursor so we can Begin() again, this time with a known height.
Begin(ItemsCount,items_height);
StepNo=3;
returntrue;
}
if(StepNo==2)// Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
{
IM_ASSERT(DisplayStart>=0&&DisplayEnd>=0);
StepNo=3;
returntrue;
}
if(StepNo==3)// Step 3: 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.
// Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper.
ImGuiListClipperclipper(pcmd->ElemCount/3,ImGui::GetTextLineHeight()*3+ImGui::GetStyle().ItemSpacing.y);// Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
overlay_draw_list->AddPolyline(triangles_pos,3,IM_COL32(255,255,0,255),true,1.0f,false);// Add triangle without AA, more readable for large-thin triangle
}
ImGui::Selectable(buf,false);
if(ImGui::IsItemHovered())
overlay_draw_list->AddPolyline(triangles_pos,3,IM_COL32(255,255,0,255),true,1.0f,false);// Add triangle without AA, more readable for large-thin triangle
// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // display only visible items
// ImGui::Text("line number %d", i);
// clipper.End();
// NB: 'count' is only used to clamp the result, if you don't know your count you can use INT_MAX
// ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced.
// while (clipper.Step())
// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
// ImGui::Text("line number %d", i);
// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
// - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
// - Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
// - Step 3: 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.
~ImGuiListClipper(){IM_ASSERT(ItemsCount==-1);}// user forgot to call End()
// items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step).
// items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing().
// If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step().
ImGuiListClipper(intitems_count=-1,floatitems_height=-1.0f){Begin(items_count,items_height);}// NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want).
~ImGuiListClipper(){IM_ASSERT(ItemsCount==-1);}// Assert if user forgot to call End() or Step() until false.
voidBegin(intcount,floatheight)// items_height: generally pass GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing()
{
IM_ASSERT(ItemsCount==-1);
ItemsCount=count;
ItemsHeight=height;
ImGui::CalcListClipping(ItemsCount,ItemsHeight,&DisplayStart,&DisplayEnd);// calculate how many to clip/display
// Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
// NB- if you have thousands of entries this approach may be too inefficient. You can seek and display only the lines that are visible - CalcListClipping() is a helper to compute this information.
// If your items are of variable size you may want to implement code similar to what CalcListClipping() does. Or split your data into fixed height items to allow random-seeking into your list.
// Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
// NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.
// You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements.
// To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:
// ImGuiListClipper clipper(Items.Size);
// while (clipper.Step())
// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
// However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list.
// A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter,
// and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code!
// If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list.
ImGuiListClipperclipper(lines, ImGui::GetTextLineHeightWithSpacing());// Here we changed spacing is zero anyway so we could use GetTextLineHeight(), but _WithSpacing() is typically more correct
for (inti=clipper.DisplayStart;i<clipper.DisplayEnd;i++)
ImGui::Text("%i The quick brown fox jumps over the lazy dog\n",i);