From 956435768f2de89297bfb713465af1eb9fc92b85 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Dec 2020 22:32:30 +0100 Subject: [PATCH] Tables: (breaking) renamed ImGuiTableColumnFlags_WidthAutoResize to _WidthAuto., default to WidthFixed policy when host window has auto-resize. Fix edge case with TableSetColumnWidth on small windows (amend 972ca816) --- imgui.h | 31 +++++++++++++++++-------------- imgui_demo.cpp | 4 ++-- imgui_tables.cpp | 35 +++++++++++++++++++---------------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/imgui.h b/imgui.h index 94422644d..f3d05e62a 100644 --- a/imgui.h +++ b/imgui.h @@ -1035,22 +1035,25 @@ enum ImGuiTabItemFlags_ }; // Flags for ImGui::BeginTable() -// - Important! Sizing policies have particularly complex and subtle side effects, more so than you would expect. +// - Important! Sizing policies have complex and subtle side effects, more so than you would expect. // Read comments/demos carefully + experiment with live demos to get acquainted with them. -// - The default sizing policy for columns depends on whether the ScrollX flag is set on the table: -// When ScrollX is off: +// - The DEFAULT policy depends on whether the _ScrollX flag is set on the table, and whether _AlwaysAutoResize flag is set on window. +// - ImGuiTableFlags_ColumnsWidthStretch is the default if ScrollX if off. +// - ImGuiTableFlags_ColumnsWidthFixed is the default if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - When ScrollX is off: // - Table defaults to ImGuiTableFlags_ColumnsWidthStretch -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch. -// - Columns sizing policy allowed: Stretch (default) or Fixed/Auto. -// - Fixed Columns will generally obtain their requested width (unless the Table cannot fit them all). +// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. +// - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all). // - Stretch Columns will share the remaining width. -// When ScrollX is on: -// - Table defaults to ImGuiTableFlags_ColumnsWidthFixed -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed. -// - Columns sizing policy allowed: Fixed/Auto mostly! +// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// - When ScrollX is on: +// - Table defaults to ImGuiTableFlags_ColumnsWidthFixed -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed or ImGuiTableColumnFlags_WidthAuto +// - Columns sizing policy allowed: Fixed/Auto mostly. // - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed. // - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). -// - Mixing up columns with different sizing policy is possible BUT can be tricky and has some side-effects and restrictions. -// (their visible order and the scrolling state have subtle but necessary effects on how they can be manually resized). -// The typical use of mixing sizing policies is to have ScrollX disabled, first Fixed columns and then one or two TRAILING Stretch columns. +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. enum ImGuiTableFlags_ { // Features @@ -1076,7 +1079,7 @@ enum ImGuiTableFlags_ ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). // Sizing ImGuiTableFlags_ColumnsWidthStretch = 1 << 13, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details. - ImGuiTableFlags_ColumnsWidthFixed = 1 << 14, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details. + ImGuiTableFlags_ColumnsWidthFixed = 1 << 14, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAuto policy (if Resizable is off). Read description above for more details. ImGuiTableFlags_SameWidths = 1 << 15, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable. ImGuiTableFlags_NoHostExtendY = 1 << 16, // Disable extending table past the limit set by outer_size.y. Only meaningful when neither ScrollX nor ScrollY are set (data below the limit will be clipped and not visible) ImGuiTableFlags_NoKeepColumnsVisible = 1 << 17, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. @@ -1104,7 +1107,7 @@ enum ImGuiTableColumnFlags_ ImGuiTableColumnFlags_DefaultSort = 1 << 1, // Default as a sorting column. ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _ColumnsWidthStretch). ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _ColumnsWidthFixed and table is resizable). - ImGuiTableColumnFlags_WidthAutoResize = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _ColumnsWidthFixed and table is not resizable). + ImGuiTableColumnFlags_WidthAuto = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _ColumnsWidthFixed and table is not resizable). Generally compatible with using right-most fitting widgets (e.g. SetNextItemWidth(-FLT_MIN)) ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. @@ -1125,7 +1128,7 @@ enum ImGuiTableColumnFlags_ ImGuiTableColumnFlags_IsHovered = 1 << 23, // Status: is hovered by mouse // [Internal] Combinations and masks - ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize, + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto, ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30 // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6ef335919..804fa0848 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3357,8 +3357,8 @@ static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch); if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed)) *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed); - if (ImGui::CheckboxFlags("_WidthAutoResize", p_flags, ImGuiTableColumnFlags_WidthAutoResize)) - *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthAutoResize); + if (ImGui::CheckboxFlags("_WidthAuto", p_flags, ImGuiTableColumnFlags_WidthAuto)) + *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthAuto); ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize); ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder); ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 731063ba7..f03c99e6a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -98,12 +98,15 @@ Index of this file: //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -// TABLES CULLING +// TABLES CLIPPING/CULLING //----------------------------------------------------------------------------- // About clipping/culling of Rows in Tables: // - For large numbers of rows, it is recommended you use ImGuiListClipper to only submit visible rows. // ImGuiListClipper is reliant on the fact that rows are of equal height. // See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper. +// - Note that columns with the ImGuiTableColumnFlags_WidthAuto policy generally don't play well with using the clipper, +// and by default a table with _ScrollX but without _Resizable will have columns default to _WidthAuto. +// So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns explicitly with _WidthFixed. //----------------------------------------------------------------------------- // About clipping/culling of Columns in Tables: // - Case A: column is not hidden by user, and at least partially in sight (most common case). @@ -193,7 +196,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w { // Adjust flags: set default sizing policy if ((flags & (ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ColumnsWidthFixed)) == 0) - flags |= (flags & ImGuiTableFlags_ScrollX) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch; + flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch; // Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV) if (flags & ImGuiTableFlags_SameWidths) @@ -564,14 +567,14 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I // Sizing Policy if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) { - // FIXME-TABLE: Inconsistent to promote columns to WidthAutoResize + // FIXME-TABLE: Inconsistent to promote columns to WidthAuto if (table->Flags & ImGuiTableFlags_ColumnsWidthFixed) - flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAutoResize; + flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAuto; else flags |= ImGuiTableColumnFlags_WidthStretch; } IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. - if (flags & ImGuiTableColumnFlags_WidthAutoResize) + if (flags & ImGuiTableColumnFlags_WidthAuto) flags |= ImGuiTableColumnFlags_NoResize; // Sorting @@ -609,9 +612,8 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I // Layout columns for the frame. This is in essence the followup to BeginTable(). // Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first. -// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for WidthAutoResize -// columns, increase feedback side-effect with widgets relying on WorkRect.Max.x. Maybe provide a default distribution -// for WidthAutoResize columns? +// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns. +// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns? void ImGui::TableUpdateLayout(ImGuiTable* table) { ImGuiContext& g = *GImGui; @@ -657,7 +659,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->IsSortSpecsDirty = true; bool start_auto_fit = false; - if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize)) + if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) start_auto_fit = column->WidthRequest < 0.0f; else start_auto_fit = column->StretchWeight < 0.0f; @@ -739,11 +741,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) } column->IsPreserveWidthAuto = false; - if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize)) + if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) { // Process auto-fit for non-stretched columns // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) - if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAutoResize) && column->IsVisibleX)) + if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAuto) && column->IsVisibleX)) column->WidthRequest = column->WidthAuto; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets @@ -786,7 +788,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) continue; ImGuiTableColumn* column = &table->Columns[column_n]; - if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize)) + if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) { sum_width_fixed_requests += max_width_auto - column->WidthRequest; // Update old sum column->WidthRequest = max_width_auto; @@ -978,7 +980,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // [Part 8] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it) // Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either - // because of using _WidthAutoResize/_WidthStretch). This will hide the resizing option from the context menu. + // because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu. const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); if (is_hovering_table && table->HoveredColumnBody == -1) { @@ -1279,7 +1281,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo table->DeclColumnsCount++; // When passing a width automatically enforce WidthFixed policy - // (whereas TableSetupColumnFlags would default to WidthAutoResize) + // (whereas TableSetupColumnFlags would default to WidthAuto) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) if ((table->Flags & ImGuiTableFlags_ColumnsWidthFixed) && (init_width_or_weight > 0.0f)) flags |= ImGuiTableColumnFlags_WidthFixed; @@ -1871,7 +1873,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) // Apply constraints early // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) const float min_width = TableGetMinColumnWidth(); - const float max_width = TableGetMaxColumnWidth(table, column_n); + const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); column_0_width = ImClamp(column_0_width, min_width, max_width); if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) return; @@ -1931,6 +1933,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + IM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f); column_0->WidthRequest = column_0_width; column_1->WidthRequest = column_1_width; if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch) @@ -3321,7 +3324,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table) column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags, (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", - (column->Flags & ImGuiTableColumnFlags_WidthAutoResize) ? "WidthAutoResize " : "", + (column->Flags & ImGuiTableColumnFlags_WidthAuto) ? "WidthAuto " : "", (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); Bullet(); Selectable(buf);