From 82711251b66a30b63a815ec6f9519c2cb6914cce Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 27 Jun 2019 18:03:19 +0200 Subject: [PATCH] Internals: ImGuiListClipper using absolute coordinate (instead of relative one). Minor no-op tweaks + ImDrawListSplitter assert --- imgui.cpp | 31 ++++++++++++++++++++----------- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79c2de90f..6096f5104 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2239,7 +2239,8 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) //----------------------------------------------------------------------------- // [SECTION] ImGuiListClipper -// This is currently not as flexible/powerful as it should be, needs some rework (see TODO) +// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed +// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) //----------------------------------------------------------------------------- static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) @@ -2247,12 +2248,14 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. // The clipper should probably have a 4th step to display the last item in a regular manner. - ImGui::SetCursorPosY(pos_y); - ImGuiWindow* window = ImGui::GetCurrentWindow(); - window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. - window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // 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. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos.y = pos_y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // 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. if (ImGuiColumns* columns = window->DC.CurrentColumns) - columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly + columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly } // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 @@ -2260,7 +2263,10 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) // 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(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + StartPosY = window->DC.CursorPos.y; ItemsHeight = items_height; ItemsCount = count; StepNo = 0; @@ -2287,7 +2293,10 @@ void ImGuiListClipper::End() bool ImGuiListClipper::Step() { - if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (ItemsCount == 0 || window->SkipItems) { ItemsCount = -1; return false; @@ -2296,16 +2305,16 @@ bool ImGuiListClipper::Step() { DisplayStart = 0; DisplayEnd = 1; - StartPosY = ImGui::GetCursorPosY(); + StartPosY = window->DC.CursorPos.y; 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; + float items_height = window->DC.CursorPos.y - StartPosY; IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically - Begin(ItemsCount-1, items_height); + Begin(ItemsCount - 1, items_height); DisplayStart++; DisplayEnd++; StepNo = 3; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 80c577719..afd2b894b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4022,7 +4022,7 @@ static void ShowExampleAppLongText(bool* p_open) static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7b20f2b16..51ff2cd9d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1304,7 +1304,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) { - IM_ASSERT(idx < _Count); + IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) return; // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()