mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-03 22:51:06 +01:00 
			
		
		
		
	ImGuiListClipper new version, detect height automatically, fix compatibility with SetScrollPosHere (#662)
This commit is contained in:
		
							
								
								
									
										155
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								imgui.cpp
									
									
									
									
									
								
							@@ -1607,6 +1607,88 @@ float ImGuiSimpleColumns::CalcExtraSpace(float avail_w)
 | 
				
			|||||||
    return ImMax(0.0f, avail_w - Width);
 | 
					    return ImMax(0.0f, avail_w - Width);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//-----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// ImGuiListClipper
 | 
				
			||||||
 | 
					//-----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 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.
 | 
				
			||||||
 | 
					    ImGui::SetCursorPosY(pos_y);
 | 
				
			||||||
 | 
					    ImGuiWindow* window = ImGui::GetCurrentWindow();
 | 
				
			||||||
 | 
					    window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;
 | 
				
			||||||
 | 
					    window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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.
 | 
				
			||||||
 | 
					void ImGuiListClipper::Begin(int count, float items_height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    StartPosY = ImGui::GetCursorPosY();
 | 
				
			||||||
 | 
					    ItemsHeight = items_height;
 | 
				
			||||||
 | 
					    ItemsCount = count;
 | 
				
			||||||
 | 
					    StepNo = 0;
 | 
				
			||||||
 | 
					    DisplayEnd = DisplayStart = -1;
 | 
				
			||||||
 | 
					    if (ItemsHeight > 0.0f)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
 | 
				
			||||||
 | 
					        if (DisplayStart > 0)
 | 
				
			||||||
 | 
					            SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
 | 
				
			||||||
 | 
					        StepNo = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ImGuiListClipper::End()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ItemsCount < 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    float cur_y = ImGui::GetCursorPosY(); (void)cur_y;
 | 
				
			||||||
 | 
					    float expected_display_end_y = StartPosY + DisplayEnd * ItemsHeight;
 | 
				
			||||||
 | 
					    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 (ItemsCount < INT_MAX)
 | 
				
			||||||
 | 
					        SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
 | 
				
			||||||
 | 
					    ItemsCount = -1;
 | 
				
			||||||
 | 
					    StepNo = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ImGuiListClipper::Step()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ItemsCount = -1; 
 | 
				
			||||||
 | 
					        return false; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (ItemsCount == 1) { ItemsCount = -1; return false; }
 | 
				
			||||||
 | 
					        float items_height = ImGui::GetCursorPosY() - StartPosY;
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					        End();
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-----------------------------------------------------------------------------
 | 
					//-----------------------------------------------------------------------------
 | 
				
			||||||
// ImGuiWindow
 | 
					// ImGuiWindow
 | 
				
			||||||
//-----------------------------------------------------------------------------
 | 
					//-----------------------------------------------------------------------------
 | 
				
			||||||
@@ -2878,18 +2960,8 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Helper to calculate coarse clipping of large list of evenly sized items.
 | 
					// Helper to calculate coarse clipping of large list of evenly sized items.
 | 
				
			||||||
// NB: Prefer using the ImGuiListClipper higher-level helper if you can!
 | 
					// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
 | 
				
			||||||
// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
 | 
					// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
 | 
				
			||||||
// If you are displaying thousands of items and you have a random access to the list, you can perform clipping yourself to save on CPU.
 | 
					 | 
				
			||||||
// {
 | 
					 | 
				
			||||||
//    float item_height = ImGui::GetTextLineHeightWithSpacing();
 | 
					 | 
				
			||||||
//    int display_start, display_end;
 | 
					 | 
				
			||||||
//    ImGui::CalcListClipping(count, item_height, &display_start, &display_end);            // calculate how many to clip/display
 | 
					 | 
				
			||||||
//    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (display_start) * item_height);         // advance cursor
 | 
					 | 
				
			||||||
//    for (int i = display_start; i < display_end; i++)                                     // display only visible items
 | 
					 | 
				
			||||||
//        // TODO: display visible item
 | 
					 | 
				
			||||||
//    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (count - display_end) * item_height);   // advance cursor
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
 | 
					void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImGuiContext& g = *GImGui;
 | 
					    ImGuiContext& g = *GImGui;
 | 
				
			||||||
@@ -2901,6 +2973,11 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
 | 
				
			|||||||
        *out_items_display_end = items_count;
 | 
					        *out_items_display_end = items_count;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (window->SkipItems)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        *out_items_display_start = *out_items_display_end = 0;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const ImVec2 pos = window->DC.CursorPos;
 | 
					    const ImVec2 pos = window->DC.CursorPos;
 | 
				
			||||||
    int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
 | 
					    int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
 | 
				
			||||||
@@ -8492,22 +8569,22 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
 | 
				
			|||||||
    // 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.
 | 
					    // 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.
 | 
				
			||||||
    bool value_changed = false;
 | 
					    bool value_changed = false;
 | 
				
			||||||
    ImGuiListClipper clipper(items_count, ImGui::GetTextLineHeightWithSpacing());
 | 
					    ImGuiListClipper clipper(items_count, ImGui::GetTextLineHeightWithSpacing());
 | 
				
			||||||
    for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
 | 
					    while (clipper.Step())
 | 
				
			||||||
    {
 | 
					        for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
 | 
				
			||||||
        const bool item_selected = (i == *current_item);
 | 
					 | 
				
			||||||
        const char* item_text;
 | 
					 | 
				
			||||||
        if (!items_getter(data, i, &item_text))
 | 
					 | 
				
			||||||
            item_text = "*Unknown item*";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ImGui::PushID(i);
 | 
					 | 
				
			||||||
        if (ImGui::Selectable(item_text, item_selected))
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            *current_item = i;
 | 
					            const bool item_selected = (i == *current_item);
 | 
				
			||||||
            value_changed = true;
 | 
					            const char* item_text;
 | 
				
			||||||
 | 
					            if (!items_getter(data, i, &item_text))
 | 
				
			||||||
 | 
					                item_text = "*Unknown item*";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ImGui::PushID(i);
 | 
				
			||||||
 | 
					            if (ImGui::Selectable(item_text, item_selected))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                *current_item = i;
 | 
				
			||||||
 | 
					                value_changed = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ImGui::PopID();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ImGui::PopID();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    clipper.End();
 | 
					 | 
				
			||||||
    ImGui::ListBoxFooter();
 | 
					    ImGui::ListBoxFooter();
 | 
				
			||||||
    return value_changed;
 | 
					    return value_changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -9520,22 +9597,22 @@ void ImGui::ShowMetricsWindow(bool* p_open)
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (!pcmd_node_open)
 | 
					                    if (!pcmd_node_open)
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                    ImGuiListClipper clipper(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.
 | 
					                    ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
 | 
				
			||||||
                    for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
 | 
					                    while (clipper.Step())
 | 
				
			||||||
                    {
 | 
					                        for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
 | 
				
			||||||
                        char buf[300], *buf_p = buf;
 | 
					 | 
				
			||||||
                        ImVec2 triangles_pos[3];
 | 
					 | 
				
			||||||
                        for (int n = 0; n < 3; n++, vtx_i++)
 | 
					 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
 | 
					                            char buf[300], *buf_p = buf;
 | 
				
			||||||
                            triangles_pos[n] = v.pos;
 | 
					                            ImVec2 triangles_pos[3];
 | 
				
			||||||
                            buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : "   ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
 | 
					                            for (int n = 0; n < 3; n++, vtx_i++)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
 | 
				
			||||||
 | 
					                                triangles_pos[n] = v.pos;
 | 
				
			||||||
 | 
					                                buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : "   ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            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
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        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
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    clipper.End();
 | 
					 | 
				
			||||||
                    ImGui::TreePop();
 | 
					                    ImGui::TreePop();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                overlay_draw_list->PopClipRect();
 | 
					                overlay_draw_list->PopClipRect();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								imgui.h
									
									
									
									
									
								
							@@ -1049,36 +1049,32 @@ struct ImColor
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Helper: Manually clip large list of items.
 | 
					// Helper: Manually clip large list of items.
 | 
				
			||||||
// If you are displaying thousands of even spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU.
 | 
					// If you are displaying thousands of evenly spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU.
 | 
				
			||||||
 | 
					// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped.
 | 
				
			||||||
// Usage:
 | 
					// Usage:
 | 
				
			||||||
//    ImGuiListClipper clipper(count, ImGui::GetTextLineHeightWithSpacing());
 | 
					//     ImGuiListClipper clipper(1000);  // we have 1000 elements, evenly spaced.
 | 
				
			||||||
//    for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // display only visible items
 | 
					//     while (clipper.Step())
 | 
				
			||||||
//        ImGui::Text("line number %d", i);
 | 
					//         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
 | 
				
			||||||
//    clipper.End();
 | 
					//             ImGui::Text("line number %d", i);
 | 
				
			||||||
// NB: 'count' is only used to clamp the result, if you don't know your count you can use INT_MAX
 | 
					// - 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.
 | 
				
			||||||
struct ImGuiListClipper
 | 
					struct ImGuiListClipper
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    float   StartPosY;
 | 
				
			||||||
    float   ItemsHeight;
 | 
					    float   ItemsHeight;
 | 
				
			||||||
    int     ItemsCount, DisplayStart, DisplayEnd;
 | 
					    int     ItemsCount, StepNo, DisplayStart, DisplayEnd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImGuiListClipper()                         { ItemsHeight = 0.0f; ItemsCount = DisplayStart = DisplayEnd = -1; }
 | 
					    // 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).
 | 
				
			||||||
    ImGuiListClipper(int count, float height)  { ItemsCount = -1; Begin(count, height); }
 | 
					    // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing().
 | 
				
			||||||
    ~ImGuiListClipper()                        { IM_ASSERT(ItemsCount == -1); } // user forgot to call End()
 | 
					    // 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(int items_count = -1, float items_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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Begin(int count, float height)        // items_height: generally pass GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing()
 | 
					    IMGUI_API bool Step();                                              // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items.
 | 
				
			||||||
    {
 | 
					    IMGUI_API void Begin(int items_count, float items_height = -1.0f);  // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1.
 | 
				
			||||||
        IM_ASSERT(ItemsCount == -1);
 | 
					    IMGUI_API void End();                                               // Automatically called on the last call of Step() that returns false.
 | 
				
			||||||
        ItemsCount = count;
 | 
					 | 
				
			||||||
        ItemsHeight = height;
 | 
					 | 
				
			||||||
        ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
 | 
					 | 
				
			||||||
        ImGui::SetCursorPosY(ImGui::GetCursorPosY() + DisplayStart * ItemsHeight);    // advance cursor
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    void End()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IM_ASSERT(ItemsCount >= 0);
 | 
					 | 
				
			||||||
        ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ItemsCount - DisplayEnd) * ItemsHeight); // advance cursor
 | 
					 | 
				
			||||||
        ItemsCount = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//-----------------------------------------------------------------------------
 | 
					//-----------------------------------------------------------------------------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2014,24 +2014,33 @@ struct ExampleAppConsole
 | 
				
			|||||||
        ImGui::PopStyleVar();
 | 
					        ImGui::PopStyleVar();
 | 
				
			||||||
        ImGui::Separator();
 | 
					        ImGui::Separator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 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.
 | 
					 | 
				
			||||||
        ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
 | 
					        ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
 | 
				
			||||||
        if (ImGui::BeginPopupContextWindow())
 | 
					        if (ImGui::BeginPopupContextWindow())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ImGui::Selectable("Clear")) ClearLog();
 | 
					            if (ImGui::Selectable("Clear")) ClearLog();
 | 
				
			||||||
            ImGui::EndPopup();
 | 
					            ImGui::EndPopup();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 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.
 | 
				
			||||||
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
 | 
					        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
 | 
				
			||||||
        for (int i = 0; i < Items.Size; i++)
 | 
					        for (int i = 0; i < Items.Size; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const char* item = Items[i];
 | 
					            const char* item = Items[i];
 | 
				
			||||||
            if (!filter.PassFilter(item))
 | 
					            if (!filter.PassFilter(item))
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            ImVec4 col = ImColor(255,255,255); // A better implementation may store a type per-item. For the sample let's just parse the text.
 | 
					            ImVec4 col = ImVec4(1.0f,1.0f,1.0f,1.0f); // A better implementation may store a type per-item. For the sample let's just parse the text.
 | 
				
			||||||
            if (strstr(item, "[error]")) col = ImColor(255,100,100);
 | 
					            if (strstr(item, "[error]")) col = ImColor(1.0f,0.4f,0.4f,1.0f);
 | 
				
			||||||
            else if (strncmp(item, "# ", 2) == 0) col = ImColor(255,200,150);
 | 
					            else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f,0.78f,0.58f,1.0f);
 | 
				
			||||||
            ImGui::PushStyleColor(ImGuiCol_Text, col);
 | 
					            ImGui::PushStyleColor(ImGuiCol_Text, col);
 | 
				
			||||||
            ImGui::TextUnformatted(item);
 | 
					            ImGui::TextUnformatted(item);
 | 
				
			||||||
            ImGui::PopStyleColor();
 | 
					            ImGui::PopStyleColor();
 | 
				
			||||||
@@ -2441,10 +2450,10 @@ static void ShowExampleAppLongText(bool* p_open)
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
 | 
					            // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
 | 
				
			||||||
            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
 | 
					            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
 | 
				
			||||||
            ImGuiListClipper clipper(lines, ImGui::GetTextLineHeightWithSpacing()); // Here we changed spacing is zero anyway so we could use GetTextLineHeight(), but _WithSpacing() is typically more correct
 | 
					            ImGuiListClipper clipper(lines);
 | 
				
			||||||
            for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
 | 
					            while (clipper.Step())
 | 
				
			||||||
                ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i);
 | 
					                for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
 | 
				
			||||||
            clipper.End();
 | 
					                    ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
 | 
				
			||||||
            ImGui::PopStyleVar();
 | 
					            ImGui::PopStyleVar();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -2452,7 +2461,7 @@ static void ShowExampleAppLongText(bool* p_open)
 | 
				
			|||||||
        // Multiple calls to Text(), not clipped (slow)
 | 
					        // Multiple calls to Text(), not clipped (slow)
 | 
				
			||||||
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
 | 
					        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
 | 
				
			||||||
        for (int i = 0; i < lines; i++)
 | 
					        for (int i = 0; i < lines; i++)
 | 
				
			||||||
            ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i);
 | 
					            ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
 | 
				
			||||||
        ImGui::PopStyleVar();
 | 
					        ImGui::PopStyleVar();
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user