From 931829f701143780d921b3478a8aef0df7b2d7bb Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Sep 2020 12:53:10 +0200 Subject: [PATCH] Tables: (Breaking change) Sorting: Made it users responsability to clear SpecsDirty back to false, so TableGetSortSpecs() doesn't have side-effect any more. + comments --- imgui.h | 28 ++++++++++++++++------------ imgui_demo.cpp | 15 ++++++++++----- imgui_internal.h | 1 - imgui_tables.cpp | 9 +++------ 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/imgui.h b/imgui.h index 019e87210..422297559 100644 --- a/imgui.h +++ b/imgui.h @@ -688,17 +688,19 @@ namespace ImGui IMGUI_API void TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. // Tables: Headers & Columns declaration // - Use TableSetupColumn() to specify label, resizing policy, default width, id, various other flags etc. - // - The name passed to TableSetupColumn() is used by TableAutoHeaders() and by the context-menu - // - Use TableAutoHeaders() to submit the whole header row, otherwise you may treat the header row as a regular row, manually call TableHeader() and other widgets. - // - Headers are required to perform some interactions: reordering, sorting, context menu (FIXME-TABLE: context menu should work without!) + // Important: this will not display anything! The name passed to TableSetupColumn() is used by TableAutoHeaders() and context-menus. + // - Use TableAutoHeaders() to create a row and automatically submit a TableHeader() for each column. + // Headers are required to perform some interactions: reordering, sorting, context menu (FIXME-TABLE: context menu should work without!) + // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in some advanced cases (e.g. adding custom widgets in header row). IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = -1.0f, ImU32 user_id = 0); IMGUI_API void TableAutoHeaders(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu - IMGUI_API void TableHeader(const char* label); // submit one header cell manually. + IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) // Tables: Sorting // - Call TableGetSortSpecs() to retrieve latest sort specs for the table. Return value will be NULL if no sorting. - // - You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since last call, or the first time. + // - When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. + // Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! // - Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! - IMGUI_API const ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). // Tab Bars, Tabs IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar @@ -1890,15 +1892,17 @@ struct ImGuiTableSortSpecsColumn }; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) -// Obtained by calling TableGetSortSpecs() +// Obtained by calling TableGetSortSpecs(). +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. +// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! struct ImGuiTableSortSpecs { - const ImGuiTableSortSpecsColumn* Specs; // Pointer to sort spec array. - int SpecsCount; // Sort spec count. Most often 1 unless e.g. ImGuiTableFlags_MultiSortable is enabled. - bool SpecsChanged; // Set to true by TableGetSortSpecs() call if the specs have changed since the previous call. Use this to sort again! - ImU64 ColumnsMask; // Set to the mask of column indexes included in the Specs array. e.g. (1 << N) when column N is sorted. + const ImGuiTableSortSpecsColumn* Specs; // Pointer to sort spec array. + int SpecsCount; // Sort spec count. Most often 1 unless e.g. ImGuiTableFlags_MultiSortable is enabled. + bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. + ImU64 ColumnsMask; // Set to the mask of column indexes included in the Specs array. e.g. (1 << N) when column N is sorted. - ImGuiTableSortSpecs() { Specs = NULL; SpecsCount = 0; SpecsChanged = false; ColumnsMask = 0x00; } + ImGuiTableSortSpecs() { Specs = NULL; SpecsCount = 0; SpecsDirty = false; ColumnsMask = 0x00; } }; //----------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 08005cbd8..54f58586f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3250,6 +3250,8 @@ struct MyItem // however qsort doesn't allow passing user data to comparing function. // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. + // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called + // very often by the sorting algorithm it would be a little wasteful. static const ImGuiTableSortSpecs* s_current_sort_specs; // Compare function to be used by qsort() @@ -4201,12 +4203,14 @@ static void ShowDemoWindowTables() ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, -1.0f, MyItemColumnID_Quantity); // Sort our data if sort specs have been changed! - if (const ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) - if (sorts_specs->SpecsChanged && items.Size > 1) + if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) + if (sorts_specs->SpecsDirty) { MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. - qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); + if (items.Size > 1) + qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; } // Display data @@ -4389,14 +4393,15 @@ static void ShowDemoWindowTables() ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); // Sort our data if sort specs have been changed! - const ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); - if (sorts_specs && sorts_specs->SpecsChanged) + ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); + if (sorts_specs && sorts_specs->SpecsDirty) items_need_sort = true; if (sorts_specs && items_need_sort && items.Size > 1) { MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); MyItem::s_current_sort_specs = NULL; + sorts_specs->SpecsDirty = false; } items_need_sort = false; diff --git a/imgui_internal.h b/imgui_internal.h index 3f733d623..261f1be1d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2033,7 +2033,6 @@ 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; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index a54a8f9ef..efa41dd91 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2298,7 +2298,7 @@ void ImGui::TableSortSpecsClickColumn(ImGuiTable* table, ImGuiTableColumn* click // You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since // last call, or the first time. // Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! -const ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() +ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; @@ -2310,8 +2310,6 @@ const ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() if (table->IsSortSpecsDirty) TableSortSpecsBuild(table); - table->SortSpecs.SpecsChanged = table->IsSortSpecsChangedForUser; - table->IsSortSpecsChangedForUser = false; return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL; } @@ -2466,9 +2464,8 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table) } table->SortSpecs.Specs = table->SortSpecsData.Data; table->SortSpecs.SpecsCount = table->SortSpecsData.Size; - - table->IsSortSpecsDirty = false; - table->IsSortSpecsChangedForUser = true; + table->SortSpecs.SpecsDirty = true; // Mark as dirty for user + table->IsSortSpecsDirty = false; // Mark as not dirty for us } //-------------------------------------------------------------------------