Tables: Fixed losing stored display order when reducing column count. (#9108, #4046)

Amend f2df804fcc
This commit is contained in:
ocornut
2025-12-08 19:29:41 +01:00
parent a726bded11
commit cf64b7fa72
4 changed files with 43 additions and 14 deletions

View File

@@ -67,6 +67,8 @@ Other Changes:
between hard minimum window size and table minimum size). between hard minimum window size and table minimum size).
- Fixed an issue where submitting non-integer row heights would eventually - Fixed an issue where submitting non-integer row heights would eventually
advance table parent layout by +0/+1 depending on its visibility. advance table parent layout by +0/+1 depending on its visibility.
- Fixed losing stored display order when reducing column count or when .ini
data has missing or duplicate values. (#9108, #4046)
- ColorEdit: - ColorEdit:
- Added R/G/B/A color markers next to each component (enabled by default). - Added R/G/B/A color markers next to each component (enabled by default).
- Added ImGuiColorEditFlags_NoColorMarkers to disable them. - Added ImGuiColorEditFlags_NoColorMarkers to disable them.

View File

@@ -30,7 +30,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.6 WIP" #define IMGUI_VERSION "1.92.6 WIP"
#define IMGUI_VERSION_NUM 19253 #define IMGUI_VERSION_NUM 19254
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@@ -2019,7 +2019,7 @@ enum ImGuiTableFlags_
ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu.
ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.
ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width, visibility and sort settings in the .ini file.
ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
// Decorations // Decorations
ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)

View File

@@ -3514,6 +3514,7 @@ namespace ImGui
IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; }
IMGUI_API void TableFixDisplayOrder(ImGuiTable* table);
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);

View File

@@ -566,7 +566,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
{ {
// Attempt to preserve width on column count change (#4046) // Attempt to preserve width on column count change (#4046)
old_columns_to_preserve = table->Columns.Data; old_columns_to_preserve = table->Columns.Data;
old_columns_raw_data = table->RawData; old_columns_raw_data = table->RawData; // Free at end of function
table->RawData = NULL; table->RawData = NULL;
} }
if (table->RawData == NULL) if (table->RawData == NULL)
@@ -592,7 +592,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
ImGuiTableColumn* column = &table->Columns[n]; ImGuiTableColumn* column = &table->Columns[n];
if (old_columns_to_preserve && n < old_columns_count) if (old_columns_to_preserve && n < old_columns_count)
{ {
// FIXME: We don't attempt to preserve column order in this path.
*column = old_columns_to_preserve[n]; *column = old_columns_to_preserve[n];
} }
else else
@@ -602,8 +601,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
column->WidthAuto = width_auto; column->WidthAuto = width_auto;
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true; column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true;
column->DisplayOrder = (ImGuiTableColumnIdx)n;
} }
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; table->DisplayOrderToIndex[n] = column->DisplayOrder;
} }
} }
if (old_columns_raw_data) if (old_columns_raw_data)
@@ -3792,7 +3792,6 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
ImU64 display_order_mask = 0;
for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++) for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++)
{ {
int column_n = column_settings->Index; int column_n = column_settings->Index;
@@ -3809,24 +3808,51 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
} }
if (settings->SaveFlags & ImGuiTableFlags_Reorderable) if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
column->DisplayOrder = column_settings->DisplayOrder; column->DisplayOrder = column_settings->DisplayOrder;
display_order_mask |= (ImU64)1 << column->DisplayOrder;
if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1) if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1; column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
column->SortOrder = column_settings->SortOrder; column->SortOrder = column_settings->SortOrder;
column->SortDirection = column_settings->SortDirection; column->SortDirection = column_settings->SortDirection;
} }
// Validate and fix invalid display order data // Fix display order and build index
const ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1; if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
if (display_order_mask != expected_display_order_mask) TableFixDisplayOrder(table);
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n;
// Rebuild index
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n;
} }
struct ImGuiTableFixDisplayOrderColumnData
{
ImGuiTableColumnIdx Idx;
ImGuiTable* Table; // This is unfortunate but we don't have userdata in qsort api.
};
// Sort by DisplayOrder and then Index
static int IMGUI_CDECL TableFixDisplayOrderComparer(const void* lhs, const void* rhs)
{
const ImGuiTable* table = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Table;
const ImGuiTableColumnIdx lhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Idx;
const ImGuiTableColumnIdx rhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)rhs)->Idx;
const int order_delta = (table->Columns[lhs_idx].DisplayOrder - table->Columns[rhs_idx].DisplayOrder);
return (order_delta > 0) ? +1 : (order_delta < 0) ? -1 : (lhs_idx > rhs_idx) ? +1 : -1;
}
// Fix invalid display order data: compact values (0,1,3 -> 0,1,2); preserve relative order (0,3,1 -> 0,2,1); deduplicate (0,4,1,1 -> 0,3,1,2)
void ImGui::TableFixDisplayOrder(ImGuiTable* table)
{
ImGuiContext& g = *GImGui;
g.TempBuffer.reserve((int)(sizeof(ImGuiTableFixDisplayOrderColumnData) * table->ColumnsCount)); // FIXME: Maybe wrap those two lines as a helper.
ImGuiTableFixDisplayOrderColumnData* fdo_columns = (ImGuiTableFixDisplayOrderColumnData*)g.TempBuffer.Data;
for (int n = 0; n < table->ColumnsCount; n++)
{
fdo_columns[n].Idx = (ImGuiTableColumnIdx)n;
fdo_columns[n].Table = table;
}
ImQsort(fdo_columns, (size_t)table->ColumnsCount, sizeof(ImGuiTableFixDisplayOrderColumnData), TableFixDisplayOrderComparer);
for (int n = 0; n < table->ColumnsCount; n++)
table->Columns[fdo_columns[n].Idx].DisplayOrder = (ImGuiTableColumnIdx)n;
}
static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;