From 363eae94e6ccc73472f841f620ceb242cd20125b Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 13 Jun 2020 17:27:51 +0200 Subject: [PATCH] Tables: Further fix #3293, #3163 + fixed for row unfreezing border not always showing due to unset clip rect. --- imgui.h | 4 ++-- imgui_demo.cpp | 4 ++-- imgui_internal.h | 1 + imgui_tables.cpp | 46 +++++++++++++++++++--------------------------- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/imgui.h b/imgui.h index 122facf4..3d9898d6 100644 --- a/imgui.h +++ b/imgui.h @@ -1036,8 +1036,8 @@ enum ImGuiTableFlags_ ImGuiTableFlags_BordersVFullHeight = 1 << 11, // Borders covers all rows even when Headers are being used. Allow resizing from any rows. // Padding, Sizing ImGuiTableFlags_NoClipX = 1 << 12, // Disable pushing clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow) - ImGuiTableFlags_SizingPolicyFixedX = 1 << 13, // Default if ScrollX is on. Columns will default to use WidthFixed or WidthAlwaysAutoResize policy. Read description above for more details. - ImGuiTableFlags_SizingPolicyStretchX = 1 << 14, // Default if ScrollX is off. Columns will default to use WidthStretch policy. Read description above for more details. + ImGuiTableFlags_SizingPolicyFixedX = 1 << 13, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAlwaysAutoResize policy. Read description above for more details. + ImGuiTableFlags_SizingPolicyStretchX = 1 << 14, // Default if ScrollX is off. Columns will default to use _WidthStretch policy. Read description above for more details. ImGuiTableFlags_NoHeadersWidth = 1 << 15, // Disable header width contribution to automatic width calculation. ImGuiTableFlags_NoHostExtendY = 1 << 16, // (FIXME-TABLE: Reword as SizingPolicy?) Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) ImGuiTableFlags_NoKeepColumnsVisible = 1 << 17, // (FIXME-TABLE) Disable code that keeps column always minimally visible when table width gets too small. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b55d5492..fab06d81 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3790,10 +3790,10 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", (unsigned int*)&flags, ImGuiTableFlags_ScrollY); if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyStretchX", (unsigned int*)&flags, ImGuiTableFlags_SizingPolicyStretchX)) flags &= ~(ImGuiTableFlags_SizingPolicyMaskX_ ^ ImGuiTableFlags_SizingPolicyStretchX); // Can't specify both sizing polices so we clear the other - ImGui::SameLine(); HelpMarker("Default if _ScrollX if disabled."); + ImGui::SameLine(); HelpMarker("Default if _ScrollX if disabled. Makes columns use _WidthStretch policy by default."); if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyFixedX", (unsigned int*)&flags, ImGuiTableFlags_SizingPolicyFixedX)) flags &= ~(ImGuiTableFlags_SizingPolicyMaskX_ ^ ImGuiTableFlags_SizingPolicyFixedX); // Can't specify both sizing polices so we clear the other - ImGui::SameLine(); HelpMarker("Default if _ScrollX if enabled."); + ImGui::SameLine(); HelpMarker("Default if _ScrollX if enabled. Makes columns use _WidthFixed by default, or _WidthAlwaysAutoResize if _Resizable is not set."); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", (unsigned int*)&flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_NoClipX", (unsigned int*)&flags, ImGuiTableFlags_NoClipX); diff --git a/imgui_internal.h b/imgui_internal.h index 0112685d..989570e2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1992,6 +1992,7 @@ struct ImGuiTable ImRect BackgroundClipRect; // We use this to cpu-clip cell background color fill ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. ImRect HostWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() + ImRect HostBackupClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground() ImVec2 HostCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() ImGuiWindow* OuterWindow; // Parent window for the table ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index ba9fcabb..297c3ad4 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1626,6 +1626,8 @@ void ImGui::TableEndRow(ImGuiTable* table) const float bg_y1 = table->RowPosY1; const float bg_y2 = table->RowPosY2; + const bool unfreeze_rows = (table->CurrentRow + 1 == table->FreezeRowsCount && table->FreezeRowsCount > 0); + if (table->CurrentRow == 0) table->LastFirstRowHeight = bg_y2 - bg_y1; @@ -1657,8 +1659,11 @@ void ImGui::TableEndRow(ImGuiTable* table) } } - if (bg_col != 0 || border_col != 0) + const bool draw_stong_bottom_border = unfreeze_rows;// || (table->RowFlags & ImGuiTableRowFlags_Headers); + if (bg_col != 0 || border_col != 0 || draw_stong_bottom_border) { + // In theory we could call SetWindowClipRectBeforeChannelChange() but since we know TableEndRow() is + // always followed by a change of clipping rectangle we perform the smallest overwrite possible here. window->DrawList->_CmdHeader.ClipRect = table->HostClipRect.ToVec4(); table->DrawSplitter.SetCurrentChannel(window->DrawList, 0); } @@ -1674,19 +1679,15 @@ void ImGui::TableEndRow(ImGuiTable* table) } // Draw top border - const float border_y = bg_y1; - if (border_col && border_y >= table->BackgroundClipRect.Min.y && border_y < table->BackgroundClipRect.Max.y) - window->DrawList->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), border_col); + if (border_col && bg_y1 >= table->BackgroundClipRect.Min.y && bg_y1 < table->BackgroundClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), border_col); + + // Draw bottom border at the row unfreezing mark (always strong) + if (draw_stong_bottom_border) + if (bg_y2 >= table->BackgroundClipRect.Min.y && bg_y2 < table->BackgroundClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong); } - const bool unfreeze_rows = (table->CurrentRow + 1 == table->FreezeRowsCount && table->FreezeRowsCount > 0); - - // Draw bottom border (always strong) - const bool draw_separating_border = unfreeze_rows;// || (table->RowFlags & ImGuiTableRowFlags_Headers); - if (draw_separating_border) - if (bg_y2 >= table->BackgroundClipRect.Min.y && bg_y2 < table->BackgroundClipRect.Max.y) - window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong); - // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle) // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and // get the new cursor position. @@ -1755,15 +1756,8 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) } else { + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); - //window->ClipRect = column->ClipRect; - //IM_ASSERT(column->ClipRect.Max.x > column->ClipRect.Min.x && column->ClipRect.Max.y > column->ClipRect.Min.y); - //window->DrawList->_ClipRectStack.back() = ImVec4(column->ClipRect.Min.x, column->ClipRect.Min.y, column->ClipRect.Max.x, column->ClipRect.Max.y); - //window->DrawList->UpdateClipRect(); - window->DrawList->PopClipRect(); - window->DrawList->PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); - //IMGUI_DEBUG_LOG("%d (%.0f,%.0f)(%.0f,%.0f)\n", column_n, column->ClipRect.Min.x, column->ClipRect.Min.y, column->ClipRect.Max.x, column->ClipRect.Max.y); - window->ClipRect = window->DrawList->_ClipRectStack.back(); } } @@ -1900,10 +1894,10 @@ void ImGui::PushTableBackground() ImGuiWindow* window = g.CurrentWindow; ImGuiTable* table = g.CurrentTable; - // Set cmd header ahead to avoid SetCurrentChannel+PushClipRect doing an unnecessary AddDrawCmd/Pop - window->DrawList->_CmdHeader.ClipRect = table->HostClipRect.ToVec4(); + // Optimization: avoid SetCurrentChannel() + PushClipRect() + table->HostBackupClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, table->HostClipRect); table->DrawSplitter.SetCurrentChannel(window->DrawList, 0); - PushClipRect(table->HostClipRect.Min, table->HostClipRect.Max, false); } void ImGui::PopTableBackground() @@ -1913,11 +1907,9 @@ void ImGui::PopTableBackground() ImGuiTable* table = g.CurrentTable; ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; - // Set cmd header ahead to avoid SetCurrentChannel+PopClipRect doing an unnecessary AddDrawCmd/Pop - ImVec4 pop_clip_rect = window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 2]; - window->DrawList->_CmdHeader.ClipRect = pop_clip_rect; + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, table->HostBackupClipRect); table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); - PopClipRect(); } // Output context menu into current window (generally a popup)