From 58411f27cba505d1f4959ff3cde857f118a09911 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Jun 2020 19:42:43 +0200 Subject: [PATCH] Tables: Avoid TableGetSortSpecs() having a side-effect on sort specs sanitization. --- imgui_internal.h | 4 ++- imgui_tables.cpp | 75 ++++++++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index b9e1d8892..0112685d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1938,7 +1938,7 @@ struct ImGuiTableColumn PrevVisibleColumn = NextVisibleColumn = -1; AutoFitQueue = CannotSkipItemsQueue = (1 << 3) - 1; // Skip for three frames SortOrder = -1; - SortDirection = ImGuiSortDirection_Ascending; + SortDirection = ImGuiSortDirection_None; } }; @@ -2020,6 +2020,7 @@ struct ImGuiTable bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). bool IsInitializing; bool IsSortSpecsDirty; + bool IsSortSpecsChangedForUser; // Reported to end-user via TableGetSortSpecs()->SpecsChanged and then clear. bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). bool IsSettingsRequestLoad; @@ -2265,6 +2266,7 @@ namespace ImGui IMGUI_API void TableDrawContextMenu(ImGuiTable* table, int column_n); IMGUI_API void TableSortSpecsClickColumn(ImGuiTable* table, ImGuiTableColumn* column, bool add_to_existing_sort_orders); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); IMGUI_API void TableBeginRow(ImGuiTable* table); IMGUI_API void TableEndRow(ImGuiTable* table); IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 15287cd20..a34ba34e5 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -546,6 +546,10 @@ static ImGuiTableColumnFlags TableFixColumnFlags(ImGuiTable* table, ImGuiTableCo static void TableFixColumnSortDirection(ImGuiTableColumn* column) { + // Initial sort state + if (column->SortDirection == ImGuiSortDirection_None) + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + // Handle NoSortAscending/NoSortDescending if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending)) column->SortDirection = ImGuiSortDirection_Descending; @@ -872,6 +876,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 1); else inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); + + // Sanitize and build sort specs before we have a change to use them for display. + // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) + if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) + TableSortSpecsBuild(table); } // Process interaction on resizing borders. Actual size change will be applied in EndTable() @@ -2224,10 +2233,9 @@ void ImGui::TableSortSpecsClickColumn(ImGuiTable* table, ImGuiTableColumn* click if (column->SortOrder == -1 || !add_to_existing_sort_orders) column->SortOrder = add_to_existing_sort_orders ? sort_order_max + 1 : 0; } - else + else if (!add_to_existing_sort_orders) { - if (!add_to_existing_sort_orders) - column->SortOrder = -1; + column->SortOrder = -1; } TableFixColumnSortDirection(column); } @@ -2248,34 +2256,11 @@ const ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() if (!(table->Flags & ImGuiTableFlags_Sortable)) return NULL; - // Flatten sort specs into user facing data - const bool was_dirty = table->IsSortSpecsDirty; - if (was_dirty) - { - TableSortSpecsSanitize(table); + if (table->IsSortSpecsDirty) + TableSortSpecsBuild(table); - // Write output - table->SortSpecsData.resize(table->SortSpecsCount); - table->SortSpecs.ColumnsMask = 0x00; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - if (column->SortOrder == -1) - continue; - ImGuiTableSortSpecsColumn* sort_spec = &table->SortSpecsData[column->SortOrder]; - sort_spec->ColumnUserID = column->UserID; - sort_spec->ColumnIndex = (ImU8)column_n; - sort_spec->SortOrder = (ImU8)column->SortOrder; - sort_spec->SortDirection = column->SortDirection; - table->SortSpecs.ColumnsMask |= (ImU64)1 << column_n; - } - } - - // User facing data - table->SortSpecs.Specs = table->SortSpecsData.Data; - table->SortSpecs.SpecsCount = table->SortSpecsData.Size; - table->SortSpecs.SpecsChanged = was_dirty; - table->IsSortSpecsDirty = false; + table->SortSpecs.SpecsChanged = table->IsSortSpecsChangedForUser; + table->IsSortSpecsChangedForUser = false; return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL; } @@ -2345,10 +2330,11 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table) for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; - if (!(column->Flags & ImGuiTableColumnFlags_NoSort) && column->IsVisible) + if (column->IsVisible && !(column->Flags & ImGuiTableColumnFlags_NoSort)) { sort_order_count = 1; column->SortOrder = 0; + TableFixColumnSortDirection(column); break; } } @@ -2356,6 +2342,33 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table) table->SortSpecsCount = (ImS8)sort_order_count; } +void ImGui::TableSortSpecsBuild(ImGuiTable* table) +{ + IM_ASSERT(table->IsSortSpecsDirty); + TableSortSpecsSanitize(table); + + // Write output + table->SortSpecsData.resize(table->SortSpecsCount); + table->SortSpecs.ColumnsMask = 0x00; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder == -1) + continue; + ImGuiTableSortSpecsColumn* sort_spec = &table->SortSpecsData[column->SortOrder]; + sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnIndex = (ImU8)column_n; + sort_spec->SortOrder = (ImU8)column->SortOrder; + sort_spec->SortDirection = column->SortDirection; + table->SortSpecs.ColumnsMask |= (ImU64)1 << column_n; + } + table->SortSpecs.Specs = table->SortSpecsData.Data; + table->SortSpecs.SpecsCount = table->SortSpecsData.Size; + + table->IsSortSpecsDirty = false; + table->IsSortSpecsChangedForUser = true; +} + //------------------------------------------------------------------------- // TABLE - .ini settings //-------------------------------------------------------------------------