Tables: Avoid TableGetSortSpecs() having a side-effect on sort specs sanitization.

This commit is contained in:
ocornut 2020-06-03 19:42:43 +02:00
parent dc915c86ca
commit 58411f27cb
2 changed files with 47 additions and 32 deletions

View File

@ -1938,7 +1938,7 @@ struct ImGuiTableColumn
PrevVisibleColumn = NextVisibleColumn = -1; PrevVisibleColumn = NextVisibleColumn = -1;
AutoFitQueue = CannotSkipItemsQueue = (1 << 3) - 1; // Skip for three frames AutoFitQueue = CannotSkipItemsQueue = (1 << 3) - 1; // Skip for three frames
SortOrder = -1; SortOrder = -1;
SortDirection = ImGuiSortDirection_Ascending; SortDirection = ImGuiSortDirection_None;
} }
}; };
@ -2020,6 +2020,7 @@ struct ImGuiTable
bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow().
bool IsInitializing; bool IsInitializing;
bool IsSortSpecsDirty; 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 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 IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted).
bool IsSettingsRequestLoad; bool IsSettingsRequestLoad;
@ -2265,6 +2266,7 @@ namespace ImGui
IMGUI_API void TableDrawContextMenu(ImGuiTable* table, int column_n); 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 TableSortSpecsClickColumn(ImGuiTable* table, ImGuiTableColumn* column, bool add_to_existing_sort_orders);
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
IMGUI_API void TableBeginRow(ImGuiTable* table); IMGUI_API void TableBeginRow(ImGuiTable* table);
IMGUI_API void TableEndRow(ImGuiTable* table); IMGUI_API void TableEndRow(ImGuiTable* table);
IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n);

View File

@ -546,6 +546,10 @@ static ImGuiTableColumnFlags TableFixColumnFlags(ImGuiTable* table, ImGuiTableCo
static void TableFixColumnSortDirection(ImGuiTableColumn* column) 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 // Handle NoSortAscending/NoSortDescending
if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending)) if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending))
column->SortDirection = ImGuiSortDirection_Descending; column->SortDirection = ImGuiSortDirection_Descending;
@ -872,6 +876,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 1); table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 1);
else else
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); 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() // 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) if (column->SortOrder == -1 || !add_to_existing_sort_orders)
column->SortOrder = add_to_existing_sort_orders ? sort_order_max + 1 : 0; 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); TableFixColumnSortDirection(column);
} }
@ -2248,34 +2256,11 @@ const ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
if (!(table->Flags & ImGuiTableFlags_Sortable)) if (!(table->Flags & ImGuiTableFlags_Sortable))
return NULL; return NULL;
// Flatten sort specs into user facing data if (table->IsSortSpecsDirty)
const bool was_dirty = table->IsSortSpecsDirty; TableSortSpecsBuild(table);
if (was_dirty)
{
TableSortSpecsSanitize(table);
// Write output table->SortSpecs.SpecsChanged = table->IsSortSpecsChangedForUser;
table->SortSpecsData.resize(table->SortSpecsCount); table->IsSortSpecsChangedForUser = false;
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;
return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL; 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++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
ImGuiTableColumn* column = &table->Columns[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; sort_order_count = 1;
column->SortOrder = 0; column->SortOrder = 0;
TableFixColumnSortDirection(column);
break; break;
} }
} }
@ -2356,6 +2342,33 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
table->SortSpecsCount = (ImS8)sort_order_count; 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 // TABLE - .ini settings
//------------------------------------------------------------------------- //-------------------------------------------------------------------------