From 557253e776298b9c7d9de807c737868ccfce6439 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 Oct 2020 20:30:53 +0100 Subject: [PATCH] Tables: create a separate background draw channel for rows below the frozen line. --- imgui_demo.cpp | 9 +++++---- imgui_internal.h | 1 + imgui_tables.cpp | 39 ++++++++++++++++++++++++++------------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 661ff3da..a392f85b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3803,6 +3803,7 @@ static void ShowDemoWindowTables() static int freeze_rows = 1; PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", (unsigned int*)&flags, ImGuiTableFlags_ScrollX); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", (unsigned int*)&flags, ImGuiTableFlags_ScrollY); ImGui::SetNextItemWidth(ImGui::GetFrameHeight()); ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput); @@ -4070,14 +4071,14 @@ static void ShowDemoWindowTables() ImGui::SetNextItemOpen(open_action != 0); if (ImGui::TreeNode("Background color")) { - static ImGuiTableFlags table_flags = ImGuiTableFlags_RowBg; + static ImGuiTableFlags flags = ImGuiTableFlags_RowBg; static int row_bg_type = 1; static int row_bg_target = 1; static int cell_bg_type = 1; PushStyleCompact(); - ImGui::CheckboxFlags("ImGuiTableFlags_Borders", (unsigned int*)&table_flags, ImGuiTableFlags_Borders); - ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", (unsigned int*)&table_flags, ImGuiTableFlags_RowBg); + ImGui::CheckboxFlags("ImGuiTableFlags_Borders", (unsigned int*)&flags, ImGuiTableFlags_Borders); + ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", (unsigned int*)&flags, ImGuiTableFlags_RowBg); ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style."); ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0"); ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them."); @@ -4087,7 +4088,7 @@ static void ShowDemoWindowTables() IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1); PopStyleCompact(); - if (ImGui::BeginTable("##Table", 5, table_flags)) + if (ImGui::BeginTable("##Table", 5, flags)) { for (int row = 0; row < 6; row++) { diff --git a/imgui_internal.h b/imgui_internal.h index b7ba309d..17488374 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2022,6 +2022,7 @@ struct ImGuiTable ImS8 LeftMostStretchedColumnDisplayOrder; // Display order of left-most stretched column. ImS8 ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot ImS8 DummyDrawChannel; // Redirect non-visible columns here. + ImS8 BgDrawChannelUnfrozen; // Index within DrawSplitter.Channels[] ImS8 FreezeRowsRequest; // Requested frozen rows count ImS8 FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset) ImS8 FreezeColumnsRequest; // Requested frozen columns count diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 68333fb9..4ba506bf 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1316,20 +1316,23 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f // - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels. // - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other // channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged. +// - We allocate 1 or 2 background draw channels. This is because we know PushTableBackground() is only used for +// horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4). // Draw channel allocation (before merging): // - NoClip --> 1+1 channels: background + foreground (same clip rect == 1 draw call) // - Clip --> 1+N channels -// - FreezeRows || FreezeColumns --> 1+N*2 (unless scrolling value is zero) -// - FreezeRows && FreezeColunns --> 2+N*2 (unless scrolling value is zero) +// - FreezeRows --> 1+N*2 (unless scrolling value is zero) +// - FreezeRows || FreezeColunns --> 2+N*2 (unless scrolling value is zero) void ImGui::TableUpdateDrawChannels(ImGuiTable* table) { const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsVisibleCount; - const int channels_for_background = 1; + const int channels_for_bg = 1 * freeze_row_multiplier; const int channels_for_dummy = (table->ColumnsVisibleCount < table->ColumnsCount || table->VisibleUnclippedMaskByIndex != table->VisibleMaskByIndex) ? +1 : 0; - const int channels_total = channels_for_background + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; + const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total); - table->DummyDrawChannel = channels_for_dummy ? (ImS8)(channels_total - 1) : -1; + table->DummyDrawChannel = (channels_for_dummy > 0) ? (ImS8)(channels_total - 1) : -1; + table->BgDrawChannelUnfrozen = (ImS8)((table->FreezeRowsCount > 0) ? channels_for_row + 1 : 0); int draw_channel_current = 1; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) @@ -1338,7 +1341,7 @@ void ImGui::TableUpdateDrawChannels(ImGuiTable* table) if (!column->IsClipped) { column->DrawChannelFrozen = (ImS8)(draw_channel_current); - column->DrawChannelUnfrozen = (ImS8)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row : 0)); + column->DrawChannelUnfrozen = (ImS8)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row + 1 : 0)); if (!(table->Flags & ImGuiTableFlags_NoClip)) draw_channel_current++; } @@ -1474,9 +1477,11 @@ void ImGui::TableReorderDrawChannelsForMerge(ImGuiTable* table) ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; ImBitArray remaining_mask; // We need 130-bit of storage remaining_mask.ClearBits(); - remaining_mask.SetBitRange(1, splitter->_Count - 1); // Background channel 0 not part of the merge (see channel allocation in TableUpdateDrawChannels) - int remaining_count = splitter->_Count - 1; + remaining_mask.SetBitRange(1, splitter->_Count - 1); // Background channel 0 == table->BgDrawChannlFrozen, not part of the merge (see channel allocation in TableUpdateDrawChannels) + remaining_mask.ClearBit(table->BgDrawChannelUnfrozen); + int remaining_count = splitter->_Count - ((table->BgDrawChannelUnfrozen == 0) ? 1 : 2); for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { if (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount) { MergeGroup* merge_group = &merge_groups[merge_group_n]; @@ -1520,6 +1525,11 @@ void ImGui::TableReorderDrawChannelsForMerge(ImGuiTable* table) } } + // BgDrawChannelFrozen is always channel 0, but make sure BgDrawChannelUnfrozen appears in the middle of our groups + if (merge_group_n == 1 && table->BgDrawChannelUnfrozen != 0) + memcpy(dst_tmp++, &splitter->_Channels[table->BgDrawChannelUnfrozen], sizeof(ImDrawChannel)); + } + // Append unmergeable channels that we didn't reorder at the end of the list for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) { @@ -1731,8 +1741,9 @@ void ImGui::TableEndRow(ImGuiTable* table) { // In theory we could call SetWindowClipRectBeforeSetChannel() 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); + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + window->DrawList->_CmdHeader.ClipRect = ((table->IsUnfrozen && table->BgDrawChannelUnfrozen != 0) ? table->BackgroundClipRect : table->HostClipRect).ToVec4(); + table->DrawSplitter.SetCurrentChannel(window->DrawList, table->IsUnfrozen ? table->BgDrawChannelUnfrozen : 0); } // Draw row background @@ -1784,7 +1795,7 @@ void ImGui::TableEndRow(ImGuiTable* table) { IM_ASSERT(table->IsUnfrozen == false); table->IsUnfrozen = true; - table->DrawSplitter.SetCurrentChannel(window->DrawList, 0); + table->DrawSplitter.SetCurrentChannel(window->DrawList, table->BgDrawChannelUnfrozen); // BackgroundClipRect starts as table->InnerClipRect, reduce it now float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); @@ -2007,8 +2018,9 @@ void ImGui::PushTableBackground() // Optimization: avoid SetCurrentChannel() + PushClipRect() table->HostBackupClipRect = window->ClipRect; - SetWindowClipRectBeforeSetChannel(window, table->HostClipRect); - table->DrawSplitter.SetCurrentChannel(window->DrawList, 0); + SetWindowClipRectBeforeSetChannel(window, table->BackgroundClipRect); + //SetWindowClipRectBeforeSetChannel(window, table->HostClipRect); + table->DrawSplitter.SetCurrentChannel(window->DrawList, table->IsUnfrozen ? table->BgDrawChannelUnfrozen : 0); } void ImGui::PopTableBackground() @@ -2855,6 +2867,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table) BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); + BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen); for (int n = 0; n < table->ColumnsCount; n++) { ImGuiTableColumn* column = &table->Columns[n];