Internals: ImGuiListClipper using absolute coordinate (instead of relative one). Minor no-op tweaks + ImDrawListSplitter assert

This commit is contained in:
omar 2019-06-27 18:03:19 +02:00
parent 1dd322c6fb
commit 82711251b6
3 changed files with 22 additions and 13 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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()