Tables: Solved an ID conflict issue with multiple-instances of a same table. Storing instance id for convenience. (#6140)

TableGetColumnResizeID() are still using an incorrect table, but having only one-level left tends to cancel things out.
This commit is contained in:
ocornut 2023-02-03 19:20:18 +01:00
parent c75410e72c
commit f799a293c8
4 changed files with 40 additions and 20 deletions

View File

@ -59,6 +59,8 @@ All changes:
- Tables: Raised max Columns count from 64 to 512. (#6094, #5305, #4876, #3572) - Tables: Raised max Columns count from 64 to 512. (#6094, #5305, #4876, #3572)
The previous limit was due to using 64-bit integers but we moved to bits-array The previous limit was due to using 64-bit integers but we moved to bits-array
and tweaked the system enough to ensure no performance loss. and tweaked the system enough to ensure no performance loss.
- Tables: Solved an ID conflict issue with multiple-instances of a same table,
due to how unique table instance id was generated. (#6140) [@ocornut, @rodrigorc]
- Text: Fixed layouting of wrapped-text block skipping successive empty lines, - Text: Fixed layouting of wrapped-text block skipping successive empty lines,
regression from the fix in 1.89.2. (#5720, #5919) regression from the fix in 1.89.2. (#5720, #5919)
- Text: Fixed clipping of single-character "..." ellipsis (U+2026 or U+0085) when font - Text: Fixed clipping of single-character "..." ellipsis (U+2026 or U+0085) when font

View File

@ -23,7 +23,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.89.3 WIP" #define IMGUI_VERSION "1.89.3 WIP"
#define IMGUI_VERSION_NUM 18926 #define IMGUI_VERSION_NUM 18927
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*

View File

@ -2509,14 +2509,15 @@ struct ImGuiTableCellData
ImGuiTableColumnIdx Column; // Column number ImGuiTableColumnIdx Column; // Column number
}; };
// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs, does that needs they could be moved to ImGuiTableTempData ?) // Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?)
struct ImGuiTableInstanceData struct ImGuiTableInstanceData
{ {
ImGuiID TableInstanceID;
float LastOuterHeight; // Outer height from last frame float LastOuterHeight; // Outer height from last frame
float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked) float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked)
float LastFrozenHeight; // Height of frozen section from last frame float LastFrozenHeight; // Height of frozen section from last frame
ImGuiTableInstanceData() { LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; } ImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; }
}; };
// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData // FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData
@ -2997,6 +2998,7 @@ namespace ImGui
IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table);
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; }
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);
@ -3008,7 +3010,7 @@ namespace ImGui
IMGUI_API void TableEndCell(ImGuiTable* table); IMGUI_API void TableEndCell(ImGuiTable* table);
IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);
IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);

View File

@ -332,11 +332,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Acquire storage for the table // Acquire storage for the table
ImGuiTable* table = g.Tables.GetOrAddByKey(id); ImGuiTable* table = g.Tables.GetOrAddByKey(id);
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
const ImGuiID instance_id = id + instance_no;
const ImGuiTableFlags table_last_flags = table->Flags; const ImGuiTableFlags table_last_flags = table->Flags;
if (instance_no > 0)
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
// Acquire temporary buffers // Acquire temporary buffers
const int table_idx = g.Tables.GetIndex(table); const int table_idx = g.Tables.GetIndex(table);
@ -352,17 +348,34 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
flags = TableFixFlags(flags, outer_window); flags = TableFixFlags(flags, outer_window);
// Initialize // Initialize
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
table->ID = id; table->ID = id;
table->Flags = flags; table->Flags = flags;
table->InstanceCurrent = (ImS16)instance_no;
table->LastFrameActive = g.FrameCount; table->LastFrameActive = g.FrameCount;
table->OuterWindow = table->InnerWindow = outer_window; table->OuterWindow = table->InnerWindow = outer_window;
table->ColumnsCount = columns_count; table->ColumnsCount = columns_count;
table->IsLayoutLocked = false; table->IsLayoutLocked = false;
table->InnerWidth = inner_width; table->InnerWidth = inner_width;
temp_data->UserOuterSize = outer_size; temp_data->UserOuterSize = outer_size;
if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no)
// Instance data (for instance 0, TableID == TableInstanceID)
ImGuiID instance_id;
table->InstanceCurrent = (ImS16)instance_no;
if (instance_no > 0)
{
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
if (table->InstanceDataExtra.Size < instance_no)
table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); table->InstanceDataExtra.push_back(ImGuiTableInstanceData());
char instance_desc[12];
int instance_desc_len = ImFormatString(instance_desc, IM_ARRAYSIZE(instance_desc), "##Instance%d", instance_no);
instance_id = GetIDWithSeed(instance_desc, instance_desc + instance_desc_len, id);
}
else
{
instance_id = id;
}
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
table_instance->TableInstanceID = instance_id;
// When not using a child window, WorkRect.Max will grow as we append contents. // When not using a child window, WorkRect.Max will grow as we append contents.
if (use_child_window) if (use_child_window)
@ -412,7 +425,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
} }
// Push a standardized ID for both child-using and not-child-using tables // Push a standardized ID for both child-using and not-child-using tables
PushOverrideID(instance_id); PushOverrideID(id);
if (instance_no > 0)
PushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol.
// Backup a copy of host window members we will modify // Backup a copy of host window members we will modify
ImGuiWindow* inner_window = table->InnerWindow; ImGuiWindow* inner_window = table->InnerWindow;
@ -1348,8 +1363,10 @@ void ImGui::EndTable()
} }
// Pop from id stack // Pop from id stack
IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!"); IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!");
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
if (table->InstanceCurrent > 0)
PopID();
PopID(); PopID();
// Restore window data that we modified // Restore window data that we modified
@ -1619,11 +1636,11 @@ ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
} }
// Return the resizing ID for the right-side of the given column. // Return the resizing ID for the right-side of the given column.
ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) ImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no)
{ {
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; ImGuiID instance_id = TableGetInstanceID(table, instance_no);
return id; return instance_id + 1 + column_n; // FIXME: #6140: still not ideal
} }
// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. // Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
@ -2878,10 +2895,9 @@ void ImGui::TableHeadersRow()
continue; continue;
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
// - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.
// - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier.
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
PushID(table->InstanceCurrent * table->ColumnsCount + column_n); PushID(column_n);
TableHeader(name); TableHeader(name);
PopID(); PopID();
} }