diff --git a/imgui_internal.h b/imgui_internal.h index 498319df..f767da13 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2282,7 +2282,7 @@ namespace ImGui // Tables: Internals IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); - IMGUI_API void TableBeginUpdateColumns(ImGuiTable* table); + IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); IMGUI_API void TableUpdateDrawChannels(ImGuiTable* table); IMGUI_API void TableUpdateLayout(ImGuiTable* table); IMGUI_API void TableUpdateBorders(ImGuiTable* table); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b1e6cffb..94e51ba6 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -64,7 +64,7 @@ // Typical call flow: (root level is public API): // - BeginTable() user begin into a table // | BeginChild() - (if ScrollX/ScrollY is set) -// | TableBeginUpdateColumns() - apply resize/order requests, lock columns active state, order +// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests // | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) // | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width // - TableSetupColumn() user submit columns details (optional) @@ -273,7 +273,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->LastFrameActive = g.FrameCount; table->OuterWindow = table->InnerWindow = outer_window; table->ColumnsCount = columns_count; - table->ColumnsNames.Buf.resize(0); table->IsInitializing = false; table->IsLayoutLocked = false; table->InnerWidth = inner_width; @@ -431,13 +430,26 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. inner_window->SkipItems = true; - // Update/lock which columns will be Visible for the frame - TableBeginUpdateColumns(table); + // Clear names + // FIXME-TABLES: probably could be done differently... + if (table->ColumnsNames.Buf.Size > 0) + { + table->ColumnsNames.Buf.resize(0); + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->NameOffset = -1; + } + } + + // Apply queued resizing/reordering/hiding requests + TableBeginApplyRequests(table); return true; } -void ImGui::TableBeginUpdateColumns(ImGuiTable* table) +// Apply queued resizing/reordering/hiding requests +void ImGui::TableBeginApplyRequests(ImGuiTable* table) { // Handle resizing request // (We process this at the first TableBegin of the frame) @@ -504,67 +516,6 @@ void ImGui::TableBeginUpdateColumns(ImGuiTable* table) table->IsResetDisplayOrderRequest = false; table->IsSettingsDirty = true; } - - // Lock Visible state and Order - table->ColumnsEnabledCount = 0; - table->IsDefaultDisplayOrder = true; - ImGuiTableColumn* last_visible_column = NULL; - bool want_column_auto_fit = false; - for (int order_n = 0; order_n < table->ColumnsCount; order_n++) - { - const int column_n = table->DisplayOrderToIndex[order_n]; - if (column_n != order_n) - table->IsDefaultDisplayOrder = false; - ImGuiTableColumn* column = &table->Columns[column_n]; - column->NameOffset = -1; - if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) - column->IsEnabledNextFrame = true; - if (column->IsEnabled != column->IsEnabledNextFrame) - { - column->IsEnabled = column->IsEnabledNextFrame; - table->IsSettingsDirty = true; - if (!column->IsEnabled && column->SortOrder != -1) - table->IsSortSpecsDirty = true; - } - if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable)) - table->IsSortSpecsDirty = true; - if (column->AutoFitQueue != 0x00) - want_column_auto_fit = true; - - ImU64 index_mask = (ImU64)1 << column_n; - ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder; - if (column->IsEnabled) - { - column->PrevEnabledColumn = column->NextEnabledColumn = -1; - if (last_visible_column) - { - last_visible_column->NextEnabledColumn = (ImS8)column_n; - column->PrevEnabledColumn = (ImS8)table->Columns.index_from_ptr(last_visible_column); - } - column->IndexWithinEnabledSet = table->ColumnsEnabledCount; - table->ColumnsEnabledCount++; - table->EnabledMaskByIndex |= index_mask; - table->EnabledMaskByDisplayOrder |= display_order_mask; - last_visible_column = column; - } - else - { - column->IndexWithinEnabledSet = -1; - table->EnabledMaskByIndex &= ~index_mask; - table->EnabledMaskByDisplayOrder &= ~display_order_mask; - } - IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); - } - table->EnabledUnclippedMaskByIndex = table->EnabledMaskByIndex; // Columns will be masked out by TableUpdateLayout() when Clipped - table->RightMostEnabledColumn = (ImS8)(last_visible_column ? table->Columns.index_from_ptr(last_visible_column) : -1); - - // Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible to avoid - // the column fitting to wait until the first visible frame of the child container (may or not be a good thing). - if (want_column_auto_fit && table->OuterWindow != table->InnerWindow) - table->InnerWindow->SkipItems = false; - - if (want_column_auto_fit) - table->IsSettingsDirty = true; } // Adjust flags: default width mode + stretch columns are not allowed when auto extending @@ -629,6 +580,65 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->HoveredColumnBody = -1; table->HoveredColumnBorder = -1; + // Lock Enabled state and Order + ImGuiTableColumn* last_visible_column = NULL; + bool want_column_auto_fit = false; + table->IsDefaultDisplayOrder = true; + table->ColumnsEnabledCount = 0; + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + if (column_n != order_n) + table->IsDefaultDisplayOrder = false; + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) + column->IsEnabledNextFrame = true; + if (column->IsEnabled != column->IsEnabledNextFrame) + { + column->IsEnabled = column->IsEnabledNextFrame; + table->IsSettingsDirty = true; + if (!column->IsEnabled && column->SortOrder != -1) + table->IsSortSpecsDirty = true; + } + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable)) + table->IsSortSpecsDirty = true; + if (column->AutoFitQueue != 0x00) + want_column_auto_fit = true; + + ImU64 index_mask = (ImU64)1 << column_n; + ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder; + if (column->IsEnabled) + { + column->PrevEnabledColumn = column->NextEnabledColumn = -1; + if (last_visible_column) + { + last_visible_column->NextEnabledColumn = (ImS8)column_n; + column->PrevEnabledColumn = (ImS8)table->Columns.index_from_ptr(last_visible_column); + } + column->IndexWithinEnabledSet = table->ColumnsEnabledCount; + table->ColumnsEnabledCount++; + table->EnabledMaskByIndex |= index_mask; + table->EnabledMaskByDisplayOrder |= display_order_mask; + last_visible_column = column; + } + else + { + column->IndexWithinEnabledSet = -1; + table->EnabledMaskByIndex &= ~index_mask; + table->EnabledMaskByDisplayOrder &= ~display_order_mask; + } + IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); + } + table->EnabledUnclippedMaskByIndex = table->EnabledMaskByIndex; // Columns will be masked out below when Clipped + table->RightMostEnabledColumn = (ImS8)(last_visible_column ? table->Columns.index_from_ptr(last_visible_column) : -1); + + // Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible to avoid + // the column fitting to wait until the first visible frame of the child container (may or not be a good thing). + if (want_column_auto_fit && table->OuterWindow != table->InnerWindow) + table->InnerWindow->SkipItems = false; + if (want_column_auto_fit) + table->IsSettingsDirty = true; + // Compute offset, clip rect for the frame // (can't make auto padding larger than what WorkRect knows about so right-alignment matches) const ImRect work_rect = table->WorkRect; @@ -1715,7 +1725,7 @@ void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height) ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table->CurrentRow == -1) + if (!table->IsLayoutLocked) TableUpdateLayout(table); if (table->IsInsideRow) TableEndRow(table); @@ -2509,6 +2519,10 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() if (!(table->Flags & ImGuiTableFlags_Sortable)) return NULL; + // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + if (table->IsSortSpecsDirty) TableSortSpecsBuild(table);