From 1731ae5a0966b1fdcc3a165c9cf992bcc7c5438e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Oct 2020 22:44:02 +0200 Subject: [PATCH] Tables: Reworked padding/spacing/width. All widths are stored without padding. Decorelate padding from presence of border. Added ImGuiTableFlags_Pad/NoPad flags. Added demo. Merge StartXHeaders and StartXRows into StartX. Distinguish CellSpacingX1 and CellSpacingX2 for clarity and to avoid loss of width on non-even spacing values. --- imgui.h | 12 ++- imgui_demo.cpp | 96 ++++++++++++++------ imgui_internal.h | 22 +++-- imgui_tables.cpp | 232 ++++++++++++++++++++++++++++------------------- 4 files changed, 226 insertions(+), 136 deletions(-) diff --git a/imgui.h b/imgui.h index bec07372..bb230248 100644 --- a/imgui.h +++ b/imgui.h @@ -1077,9 +1077,13 @@ enum ImGuiTableFlags_ ImGuiTableFlags_NoHostExtendY = 1 << 17, // (FIXME-TABLE: Reword as SizingPolicy?) Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // (FIXME-TABLE) Disable code that keeps column always minimally visible when table width gets too small and horizontal scrolling is off. ImGuiTableFlags_NoClip = 1 << 19, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + // Padding + ImGuiTableFlags_PadOuterX = 1 << 20, // Default if BordersOuterV is on. Enable outer-most padding. + ImGuiTableFlags_NoPadOuterX = 1 << 21, // Default if BordersOuterV is off. Disable outer-most padding. + ImGuiTableFlags_NoPadInnerX = 1 << 22, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). // Scrolling - ImGuiTableFlags_ScrollX = 1 << 20, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. - ImGuiTableFlags_ScrollY = 1 << 21, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + ImGuiTableFlags_ScrollX = 1 << 23, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 24, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. ImGuiTableFlags_Scroll = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, // [Internal] Combinations and masks @@ -1134,8 +1138,8 @@ enum ImGuiTableRowFlags_ enum ImGuiTableBgTarget_ { ImGuiTableBgTarget_None = 0, - ImGuiTableBgTarget_ColumnBg0 = 1, // FIXME-TABLE: Todo. Set column background color 0 (generally used for background - ImGuiTableBgTarget_ColumnBg1 = 2, // FIXME-TABLE: Todo. Set column background color 1 (generally used for selection marking) + //ImGuiTableBgTarget_ColumnBg0 = 1, // FIXME-TABLE: Todo. Set column background color 0 (generally used for background + //ImGuiTableBgTarget_ColumnBg1 = 2, // FIXME-TABLE: Todo. Set column background color 1 (generally used for selection marking) ImGuiTableBgTarget_RowBg0 = 3, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) ImGuiTableBgTarget_RowBg1 = 4, // Set row background color 1 (generally used for selection marking) ImGuiTableBgTarget_CellBg = 5 // Set cell background color (top-most color) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5a8230ef..f00e68b3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3405,9 +3405,8 @@ static void ShowDemoWindowTables() { // Expose a few Borders related flags interactively enum ContentsType { CT_Text, CT_FillButton }; - static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg; + static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; static bool display_headers = false; - static bool display_width = false; static int contents_type = CT_Text; PushStyleCompact(); @@ -3438,7 +3437,6 @@ static void ShowDemoWindowTables() ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); ImGui::Checkbox("Display headers", &display_headers); - ImGui::Checkbox("Display debug width", &display_width); PopStyleCompact(); if (ImGui::BeginTable("##table1", 3, flags)) @@ -3458,28 +3456,11 @@ static void ShowDemoWindowTables() ImGui::TableNextRow(); for (int column = 0; column < 3; column++) { - ImGui::TableSetColumnIndex(column); - char buf[32]; - if (display_width) - { - // [DEBUG] Draw limits FIXME-TABLE: Move to Advanced section - ImVec2 p = ImGui::GetCursorScreenPos(); - float contents_x1 = p.x; - float contents_x2 = ImGui::GetWindowPos().x + ImGui::GetContentRegionMax().x; - float cliprect_x1 = ImGui::GetWindowDrawList()->GetClipRectMin().x; - float cliprect_x2 = ImGui::GetWindowDrawList()->GetClipRectMax().x; - float y1 = p.y; - float y2 = p.y + ImGui::GetTextLineHeight() + 2.0f; - ImDrawList* fg_draw_list = ImGui::GetForegroundDrawList(); - fg_draw_list->AddRect(ImVec2(contents_x1, y1 + 0.0f), ImVec2(contents_x2, y2 + 0.0f), IM_COL32(255, 0, 0, 255)); // Contents limit (e.g. Cell + Padding) - fg_draw_list->AddLine(ImVec2(cliprect_x1, y2 + 1.0f), ImVec2(cliprect_x2, y2 + 1.0f), IM_COL32(255, 255, 0, 255)); // Hard clipping limit - sprintf(buf, "w=%.2f", contents_x2 - contents_x1); - } - else - { - sprintf(buf, "Hello %d,%d", row, column); - } + if (!ImGui::TableSetColumnIndex(column)) + continue; + char buf[32]; + sprintf(buf, "Hello %d,%d", row, column); if (contents_type == CT_Text) ImGui::TextUnformatted(buf); else if (contents_type) @@ -3648,6 +3629,58 @@ static void ShowDemoWindowTables() ImGui::TreePop(); } + if (open_action != -1) + ImGui::SetNextItemOpen(open_action != 0); + if (ImGui::TreeNode("Padding")) + { + static ImGuiTableFlags flags = ImGuiTableFlags_BordersV; + + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" + "e.g.:\n" + "- BorderOuterV\n" + "- any form of row selection\n" + "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n"); + + PushStyleCompact(); + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", (unsigned int*)&flags, ImGuiTableFlags_PadOuterX); + ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", (unsigned int*)&flags, ImGuiTableFlags_NoPadOuterX); + ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)"); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", (unsigned int*)&flags, ImGuiTableFlags_NoPadInnerX); + ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)"); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", (unsigned int*)&flags, ImGuiTableFlags_BordersOuterV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", (unsigned int*)&flags, ImGuiTableFlags_BordersInnerV); + PopStyleCompact(); + + if (ImGui::BeginTable("##table1", 3, flags)) + { + for (int row = 0; row < 5; row++) + { + ImGui::TableNextRow(); + for (int column = 0; column < 3; column++) + { + ImGui::TableSetColumnIndex(column); + if (row == 0) + { + ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); + } + else + { + char buf[32]; + sprintf(buf, "Hello %d,%d", row, column); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + if (ImGui::TableGetHoveredColumn() == column) + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255)); + } + } + ImGui::EndTable(); + } + + ImGui::TreePop(); + } + if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); if (ImGui::TreeNode("Explicit widths")) @@ -3655,20 +3688,25 @@ static void ShowDemoWindowTables() static ImGuiTableFlags flags = ImGuiTableFlags_None; PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", (unsigned int*)&flags, ImGuiTableFlags_NoKeepColumnsVisible); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", (unsigned int*)&flags, ImGuiTableFlags_BordersInnerV); + ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", (unsigned int*)&flags, ImGuiTableFlags_BordersOuterV); PopStyleCompact(); - if (ImGui::BeginTable("##table1", 3, flags)) + if (ImGui::BeginTable("##table1", 4, flags)) { // We could also set ImGuiTableFlags_SizingPolicyFixedX on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); for (int row = 0; row < 5; row++) { ImGui::TableNextRow(); - for (int column = 0; column < 3; column++) + for (int column = 0; column < 4; column++) { ImGui::TableSetColumnIndex(column); + if (row == 0) + ImGui::Text("(%.2f)", ImGui::GetContentRegionAvail().x); ImGui::Text("Hello %d,%d", row, column); } } @@ -3679,7 +3717,7 @@ static void ShowDemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Vertical scrolling, with clipping")) + if (ImGui::TreeNode("Vertical scrolling")) { HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items."); static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; @@ -4356,6 +4394,7 @@ static void ShowDemoWindowTables() ImGui::TreePop(); } + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); if (ImGui::TreeNode("Advanced")) @@ -4415,6 +4454,9 @@ static void ShowDemoWindowTables() if (ImGui::TreeNodeEx("Sizing, Padding:", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", (unsigned int*)&flags, ImGuiTableFlags_PadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", (unsigned int*)&flags, ImGuiTableFlags_NoPadOuterX); + ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", (unsigned int*)&flags, ImGuiTableFlags_NoPadInnerX); if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyStretchX", (unsigned int*)&flags, ImGuiTableFlags_SizingPolicyStretchX)) flags &= ~(ImGuiTableFlags_SizingPolicyMaskX_ ^ ImGuiTableFlags_SizingPolicyStretchX); // Can't specify both sizing polices so we clear the other ImGui::SameLine(); HelpMarker("[Default if ScrollX is off]\nFit all columns within available width (or specified inner_width). Fixed and Stretch columns allowed."); diff --git a/imgui_internal.h b/imgui_internal.h index dc81fdfa..eeb8dd3f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1887,7 +1887,7 @@ struct ImGuiTabBar #define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. #define IMGUI_TABLE_MAX_DRAW_CHANNELS (2 + 64 * 2) // See TableUpdateDrawChannels() -// [Internal] sizeof() ~ 104 +// [Internal] sizeof() ~ 108 // We use the terminology "Visible" to refer to a column that is not Hidden by user or settings. However it may still be out of view and clipped (see IsClipped). struct ImGuiTableColumn { @@ -1897,10 +1897,11 @@ struct ImGuiTableColumn ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_ float MinX; // Absolute positions float MaxX; - float WidthOrWeightInitValue; // Value passed to TableSetupColumn() - float WidthStretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. - float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from WidthStretchWeight in TableUpdateLayout() - float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be >WidthRequest to honor minimum width, may be WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space. float StartX; // Start position for the frame, currently ~(MinX + CellPaddingX) float ContentMaxPosFrozen; // Submitted contents absolute maximum position, from which we can infer width. Kept as float because we need to manipulate those between each cell change. float ContentMaxPosUnfrozen; @@ -1931,7 +1932,7 @@ struct ImGuiTableColumn ImGuiTableColumn() { memset(this, 0, sizeof(*this)); - WidthStretchWeight = WidthRequest = WidthGiven = -1.0f; + StretchWeight = WidthRequest = -1.0f; NameOffset = -1; IsVisible = IsVisibleNextFrame = true; DisplayOrder = IndexWithinVisibleSet = -1; @@ -1985,10 +1986,11 @@ struct ImGuiTable float BorderX1; float BorderX2; float HostIndentX; - float CellPaddingX1; // Padding from each borders - float CellPaddingX2; + float OuterPaddingX; + float CellPaddingX; // Padding from each borders float CellPaddingY; - float CellSpacingX; // Spacing between non-bordered cells + float CellSpacingX1; // Spacing between non-bordered cells + float CellSpacingX2; float LastOuterHeight; // Outer height from last frame float LastFirstRowHeight; // Height of first row from last frame float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details. @@ -2285,7 +2287,7 @@ namespace ImGui IMGUI_API void TableEndRow(ImGuiTable* table); IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); IMGUI_API void TableEndCell(ImGuiTable* table); - IMGUI_API ImRect TableGetCellBgRect(); + IMGUI_API ImRect TableGetCellBgRect(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 void TableSetColumnAutofit(ImGuiTable* table, int column_n); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c00d0182..97e7cae7 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -290,17 +290,25 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->HostCursorMaxPos = inner_window->DC.CursorMaxPos; inner_window->ParentWorkRect = inner_window->WorkRect; - // Borders + // Padding and Spacing // - None ........Content..... Pad .....Content........ - // - OuterV | Pad ..Content..... Pad .....Content.. Pad | // FIXME-TABLE: Not handled properly - // - InnerV ........Content.. Pad | Pad ..Content........ // FIXME-TABLE: Not handled properly - // - OuterV+InnerV | Pad ..Content.. Pad | Pad ..Content.. Pad | - - const bool has_cell_padding_x = (flags & ImGuiTableFlags_BordersOuterV) != 0; - table->CellPaddingX1 = has_cell_padding_x ? g.Style.CellPadding.x + 1.0f : 0.0f; - table->CellPaddingX2 = has_cell_padding_x ? g.Style.CellPadding.x : 0.0f; + // - PadOuter | Pad ..Content..... Pad .....Content.. Pad | + // - PadInner ........Content.. Pad | Pad ..Content........ + // - PadOuter+PadInner | Pad ..Content.. Pad | Pad ..Content.. Pad | + const bool pad_outer_x = (flags & ImGuiTableFlags_NoPadOuterX) ? false : (flags & ImGuiTableFlags_PadOuterX) ? true : (flags & ImGuiTableFlags_BordersOuterV) != 0; + const bool pad_inner_x = (flags & ImGuiTableFlags_NoPadInnerX) ? false : true; + const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f; + const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f; + const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f; + const float inner_spacing = inner_spacing_for_border + inner_spacing_explicit; + table->CellSpacingX1 = ImCeil(inner_spacing * 0.5f); + table->CellSpacingX2 = inner_spacing - table->CellSpacingX1; + table->CellPaddingX = inner_padding_explicit; table->CellPaddingY = g.Style.CellPadding.y; - table->CellSpacingX = has_cell_padding_x ? 0.0f : g.Style.CellPadding.x; + + const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f; + table->OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table->CellPaddingX; table->CurrentColumn = -1; table->CurrentRow = -1; @@ -332,7 +340,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG outer_window->DC.CurrentTableIdx = table_idx; if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. inner_window->DC.CurrentTableIdx = table_idx; - if ((table_last_flags & ImGuiTableFlags_Reorderable) && !(flags & ImGuiTableFlags_Reorderable)) + if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) table->IsResetDisplayOrderRequest = true; // Setup memory buffer (clear data if columns count changed) @@ -591,11 +599,12 @@ static void TableFixColumnSortDirection(ImGuiTableColumn* column) column->SortDirection = ImGuiSortDirection_Ascending; } +// Minimum column content width (without padding) static float TableGetMinColumnWidth() { ImGuiContext& g = *GImGui; - // return g.Style.ColumnsMinSpacing; - return g.Style.FramePadding.x * 3.0f; + // return g.Style.ColumnsMinSpacing; // FIXME-TABLE + return g.Style.FramePadding.x * 1.0f; } // Layout columns for the frame @@ -614,14 +623,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // 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; - const float padding_auto_x = table->CellPaddingX2; const float min_column_width = TableGetMinColumnWidth(); + const float min_column_width_padded = min_column_width + table->CellPaddingX * 2.0f; int count_fixed = 0; float sum_weights_stretched = 0.0f; // Sum of all weights for weighted columns. float sum_width_fixed_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns. table->LeftMostStretchedColumnDisplayOrder = -1; - table->ColumnsAutoFitWidth = 0.0f; for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { if (!(table->VisibleMaskByDisplayOrder & ((ImU64)1 << order_n))) @@ -642,30 +650,26 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Calculate "ideal" column width for nothing to be clipped. // Combine width from regular rows + width from headers unless requested not to. - const float column_content_width_rows = (float)ImMax(column->ContentWidthFrozen, column->ContentWidthUnfrozen); - const float column_content_width_headers = (float)column->ContentWidthHeadersIdeal; - float column_width_ideal = column_content_width_rows; + const float content_width_body = (float)ImMax(column->ContentWidthFrozen, column->ContentWidthUnfrozen); + const float content_width_headers = (float)column->ContentWidthHeadersIdeal; + float width_auto = content_width_body; if (!(table->Flags & ImGuiTableFlags_NoHeadersWidth) && !(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth)) - column_width_ideal = ImMax(column_width_ideal, column_content_width_headers); - column_width_ideal = ImMax(column_width_ideal + padding_auto_x, min_column_width); + width_auto = ImMax(width_auto, content_width_headers); + width_auto = ImMax(width_auto, min_column_width); // Without padding // Non-resizable columns also submit their requested width - if (column->Flags & ImGuiTableColumnFlags_WidthFixed) - if (column->WidthOrWeightInitValue > 0.0f) - if (!(table->Flags & ImGuiTableFlags_Resizable) || !(column->Flags & ImGuiTableColumnFlags_NoResize)) - column_width_ideal = ImMax(column_width_ideal, column->WidthOrWeightInitValue); + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) + if (!(table->Flags & ImGuiTableFlags_Resizable) || !(column->Flags & ImGuiTableColumnFlags_NoResize)) + width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth); - // CellSpacingX is >0.0f when there's no vertical border - table->ColumnsAutoFitWidth += column_width_ideal; - if (column->PrevVisibleColumn != -1) - table->ColumnsAutoFitWidth += table->CellSpacingX; + column->WidthAuto = width_auto; if (column->Flags & (ImGuiTableColumnFlags_WidthAlwaysAutoResize | ImGuiTableColumnFlags_WidthFixed)) { // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) count_fixed += 1; if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) && !column->IsClipped)) - column->WidthRequest = column_width_ideal; + column->WidthRequest = width_auto; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very @@ -680,17 +684,18 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) else { IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); - const int init_size = (column->WidthStretchWeight < 0.0f); + const int init_size = (column->StretchWeight < 0.0f); if (init_size) - column->WidthStretchWeight = 1.0f; - sum_weights_stretched += column->WidthStretchWeight; + column->StretchWeight = 1.0f; + sum_weights_stretched += column->StretchWeight; if (table->LeftMostStretchedColumnDisplayOrder == -1) table->LeftMostStretchedColumnDisplayOrder = (ImS8)column->DisplayOrder; } + sum_width_fixed_requests += table->CellPaddingX * 2.0f; } // Layout - const float width_spacings = table->CellSpacingX * (table->ColumnsVisibleCount - 1); + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsVisibleCount - 1); float width_avail; if ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) width_avail = table->InnerClipRect.GetWidth() - width_spacings; @@ -703,6 +708,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Mark some columns as not resizable int count_resizable = 0; table->ColumnsTotalWidth = width_spacings; + table->ColumnsAutoFitWidth = width_spacings; for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { if (!(table->VisibleMaskByDisplayOrder & ((ImU64)1 << order_n))) @@ -712,8 +718,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Allocate width for stretched/weighted columns if (column->Flags & ImGuiTableColumnFlags_WidthStretch) { - // WidthStretchWeight gets converted into WidthRequest - float weight_ratio = column->WidthStretchWeight / sum_weights_stretched; + // StretchWeight gets converted into WidthRequest + float weight_ratio = column->StretchWeight / sum_weights_stretched; column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f); width_remaining_for_stretched_columns -= column->WidthRequest; @@ -735,7 +741,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Assign final width, record width in case we will need to shrink column->WidthGiven = ImFloor(ImMax(column->WidthRequest, min_column_width)); - table->ColumnsTotalWidth += column->WidthGiven; + table->ColumnsTotalWidth += column->WidthGiven + table->CellPaddingX * 2.0f; + table->ColumnsAutoFitWidth += column->WidthAuto + table->CellPaddingX * 2.0f; } #if 0 @@ -788,6 +795,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Setup final position, offset and clipping rectangles int visible_n = 0; float offset_x = (table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x; + offset_x += table->OuterPaddingX; ImRect host_clip_rect = table->InnerClipRect; for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { @@ -820,7 +828,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) { // Frozen columns can't reach beyond visible width else scrolling will naturally break. if (order_n < table->FreezeColumnsRequest) - max_x = table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - order_n) * min_column_width; + max_x = table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - order_n) * min_column_width_padded - table->OuterPaddingX; } else { @@ -828,18 +836,19 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // sure they are all visible. Because of this we also know that all of the columns will always fit in // table->WorkRect and therefore in table->InnerRect (because ScrollX is off) if (!(table->Flags & ImGuiTableFlags_NoKeepColumnsVisible)) - max_x = table->WorkRect.Max.x - (table->ColumnsVisibleCount - (column->IndexWithinVisibleSet + 1)) * min_column_width; + max_x = table->WorkRect.Max.x - (table->ColumnsVisibleCount - (column->IndexWithinVisibleSet + 1)) * min_column_width_padded - table->OuterPaddingX; } - if (offset_x + column->WidthGiven > max_x) - column->WidthGiven = ImMax(max_x - offset_x, min_column_width); + if (offset_x + column->WidthGiven + table->CellPaddingX * 2.0f > max_x) // FIXME-TABLE: CHECK + column->WidthGiven = ImMax(max_x - offset_x - table->CellPaddingX * 2.0f, min_column_width); - column->MinX = offset_x; - column->MaxX = column->MinX + column->WidthGiven; + // Min, Max, Starting positions + column->MinX = offset_x - table->CellSpacingX1; + column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + column->StartX = offset_x + table->CellPaddingX; - //// A one pixel padding on the right side makes clipping more noticeable and contents look less cramped. column->ClipRect.Min.x = column->MinX; column->ClipRect.Min.y = work_rect.Min.y; - column->ClipRect.Max.x = column->MaxX;// -1.0f; + column->ClipRect.Max.x = column->MaxX; column->ClipRect.Max.y = FLT_MAX; column->ClipRect.ClipWithFull(host_clip_rect); @@ -853,8 +862,23 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x) table->HoveredColumnBody = (ImS8)column_n; - // Starting cursor position - column->StartX = column->MinX + table->CellPaddingX1; + // [DEBUG] Display overlay +#if 0 + if (g.IO.KeyShift) + { + // Note that ClipRect should always cover MinX..MaxX (in order to guarantee that draw calls can be merged into parent) + float y1 = table->WorkRect.Min.y; + float y2 = table->WorkRect.Min.y + table->LastOuterHeight; + //GetForegroundDrawList()->AddLine(ImVec2(column->MinX, y1 - 5.0f), ImVec2(column->MinX, y2 + 5.0f), IM_COL32(0, 255, 50, 255)); + //GetForegroundDrawList()->AddLine(ImVec2(column->MaxX, y1 - 5.0f), ImVec2(column->MaxX, y2 + 5.0f), IM_COL32(0, 255, 50, 255)); + //GetForegroundDrawList()->AddRect(ImVec2(column->ClipRect.Min.x, y1), ImVec2(column->ClipRect.Max.x, y2), IM_COL32(255, 0, 0, 255), 0.0f, 0, 1.0f); + //GetForegroundDrawList()->AddRect(ImVec2(column->MinX + table->CellPaddingX, y1), ImVec2(column->MaxX - table->CellPaddingX, y2), IM_COL32(255, 255, 0, 255)); + char buf[128]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "(cont_w)\n%.2f\n(max-min)\n%.2f", column->MaxX - table->CellPaddingX - column->StartX, column->MaxX - column->MinX); + GetForegroundDrawList()->AddRectFilled(ImVec2(column->MinX, y1), ImVec2(column->MaxX, y2), IM_COL32(0, 0, 0, 200)); + GetForegroundDrawList()->AddText(ImVec2(column->StartX, y1), IM_COL32(255, 255, 255, 255), buf); + } +#endif // Alignment // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in @@ -866,9 +890,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // column->StartX = ImLerp(column->StartX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f); // Reset content width variables - const float initial_max_pos_x = column->MinX + table->CellPaddingX1; - column->ContentMaxPosFrozen = column->ContentMaxPosUnfrozen = initial_max_pos_x; - column->ContentMaxPosHeadersUsed = column->ContentMaxPosHeadersIdeal = initial_max_pos_x; + column->ContentMaxPosFrozen = column->ContentMaxPosUnfrozen = column->StartX; + column->ContentMaxPosHeadersUsed = column->ContentMaxPosHeadersIdeal = column->StartX; // Don't decrement auto-fit counters until container window got a chance to submit its items if (table->HostSkipItems == false) @@ -880,7 +903,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (visible_n < table->FreezeColumnsCount) host_clip_rect.Min.x = ImMax(host_clip_rect.Min.x, column->MaxX + 2.0f); - offset_x += column->WidthGiven + table->CellSpacingX; + offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; visible_n++; } @@ -1063,7 +1086,7 @@ void ImGui::EndTable() ImGuiTableColumn* column = &table->Columns[column_n]; // Store content width (for both Headers and Rows) - float ref_x = column->StartX - table->CellPaddingX1; + float ref_x = column->StartX; column->ContentWidthFrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosFrozen - ref_x); column->ContentWidthUnfrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosUnfrozen - ref_x); column->ContentWidthHeadersUsed = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersUsed - ref_x); @@ -1081,18 +1104,18 @@ void ImGui::EndTable() table->DrawSplitter.Merge(inner_window->DrawList); // When releasing a column being resized, scroll to keep the resulting column in sight - const float min_column_width = TableGetMinColumnWidth(); if (!(table->Flags & ImGuiTableFlags_ScrollX) && inner_window != outer_window) { inner_window->Scroll.x = 0.0f; } else if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent) { + const float min_column_width_padded = TableGetMinColumnWidth() + table->CellPaddingX * 2.0f; ImGuiTableColumn* column = &table->Columns[table->LastResizedColumn]; if (column->MaxX < table->InnerClipRect.Min.x) - SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - min_column_width, 1.0f); + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - min_column_width_padded, 1.0f); else if (column->MaxX > table->InnerClipRect.Max.x) - SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + min_column_width, 1.0f); + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + min_column_width_padded, 1.0f); } // Apply resizing/dragging at the end of the frame @@ -1100,7 +1123,7 @@ void ImGui::EndTable() { ImGuiTableColumn* column = &table->Columns[table->ResizedColumn]; const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS); - const float new_width = ImFloor(new_x2 - column->MinX); + const float new_width = ImFloor(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f); table->ResizedColumnNextWidth = new_width; } @@ -1177,7 +1200,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent); const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0; - if (column->MaxX > table->InnerClipRect.Max.x && !is_resized && is_hovered) + if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)// && is_hovered) continue; if (column->NextVisibleColumn == -1 && !is_resizable) continue; @@ -1222,6 +1245,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) } else if (table->Flags & ImGuiTableFlags_BordersOuterV) { + // FIXME-TABLE: could use AddRect or explicit VLine/HLine helper? outer_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size); outer_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size); } @@ -1234,6 +1258,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y) { // Draw bottom-most row border + // FIXME-TABLE: could use AddRect or explicit VLine/HLine helper? const float border_y = table->RowPosY2; if (border_y >= table->BackgroundClipRect.Min.y && border_y < table->BackgroundClipRect.Max.y) inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size); @@ -1252,7 +1277,7 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table) ImGuiTableColumn* column = &table->Columns[column_n]; if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) continue; - visible_weight += column->WidthStretchWeight; + visible_weight += column->StretchWeight; visible_width += column->WidthRequest; } IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); @@ -1263,11 +1288,12 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table) ImGuiTableColumn* column = &table->Columns[column_n]; if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) continue; - column->WidthStretchWeight = ((column->WidthRequest + 0.0f) / visible_width) * visible_weight; + column->StretchWeight = ((column->WidthRequest + 0.0f) / visible_width) * visible_weight; } } // Public wrapper +// 'width' = inner column width, without padding void ImGui::TableSetColumnWidth(int column_n, float width) { ImGuiContext& g = *GImGui; @@ -1282,7 +1308,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, float column_0_width) { // Constraints - float min_width = TableGetMinColumnWidth(); + const float min_width = TableGetMinColumnWidth(); float max_width_0 = FLT_MAX; if (!(table->Flags & ImGuiTableFlags_ScrollX)) max_width_0 = (table->WorkRect.Max.x - column_0->MinX) - (table->ColumnsVisibleCount - (column_0->IndexWithinVisibleSet + 1)) * min_width; @@ -1431,7 +1457,7 @@ void ImGui::TableReorderDrawChannelsForMerge(ImGuiTable* table) width_contents = ImMax(column->ContentWidthFrozen, column->ContentWidthHeadersUsed); else // Row freeze: use width after freeze width_contents = column->ContentWidthUnfrozen; - if (width_contents > column->WidthGiven) + if (width_contents > column->WidthGiven + table->CellPaddingX * 1.0f) continue; } @@ -1537,12 +1563,12 @@ void ImGui::TableReorderDrawChannelsForMerge(ImGuiTable* table) } } -// We use a default parameter of 'init_width_or_weight == -1' -// ImGuiTableColumnFlags_WidthFixed, width <= 0 --> init width == auto -// ImGuiTableColumnFlags_WidthFixed, width > 0 --> init width == manual -// ImGuiTableColumnFlags_WidthStretch, weight < 0 --> init weight == 1.0f -// ImGuiTableColumnFlags_WidthStretch, weight >= 0 --> init weight == custom -// Use a different API? +// We use a default parameter of 'init_width_or_weight == -1', +// - with ImGuiTableColumnFlags_WidthFixed, width <= 0 --> init width == auto +// - with ImGuiTableColumnFlags_WidthFixed, width > 0 --> init width == manual +// - with ImGuiTableColumnFlags_WidthStretch, weight < 0 --> init weight == 1.0f +// - with ImGuiTableColumnFlags_WidthStretch, weight >= 0 --> init weight == custom +// Widths are specified _without_ CellPadding. So if you specify a width of 100.0f the column will be 100.0f+Padding*2.0f and you can fit a 100.0-wide item in it. void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) { ImGuiContext& g = *GImGui; @@ -1573,8 +1599,8 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, if (init_width_or_weight < 0.0f) init_width_or_weight = 1.0f; } - column->WidthOrWeightInitValue = init_width_or_weight; - if (table->IsInitializing && column->WidthRequest < 0.0f && column->WidthStretchWeight < 0.0f) + column->InitStretchWeightOrWidth = init_width_or_weight; + if (table->IsInitializing && column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) { // Init width or weight if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) @@ -1584,9 +1610,9 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, column->AutoFitQueue = 0x00; } if (flags & ImGuiTableColumnFlags_WidthStretch) - column->WidthStretchWeight = init_width_or_weight; + column->StretchWeight = init_width_or_weight; else - column->WidthStretchWeight = 1.0f; + column->StretchWeight = 1.0f; } if (table->IsInitializing) { @@ -1740,10 +1766,9 @@ void ImGui::TableEndRow(ImGuiTable* table) ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) { - ImGuiTableColumn* column = &table->Columns[cell_data->Column]; - ImRect cell_rect(column->MinX - table->CellSpacingX, bg_y1, column->MaxX, bg_y2); // FIXME-TABLE: Padding currently wrong until we finish the padding refactor - cell_rect.ClipWith(table->BackgroundClipRect); - window->DrawList->AddRectFilled(cell_rect.Min, cell_rect.Max, cell_data->BgColor); + ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); + cell_bg_rect.ClipWith(table->BackgroundClipRect); + window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); } } @@ -1820,8 +1845,8 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) window->DC.NavLayerCurrent = column->NavLayerCurrent; window->WorkRect.Min.y = window->DC.CursorPos.y; - window->WorkRect.Min.x = column->MinX + table->CellPaddingX1; - window->WorkRect.Max.x = column->MaxX - table->CellPaddingX2; + window->WorkRect.Min.x = column->MinX + table->CellPaddingX + table->CellSpacingX1; + window->WorkRect.Max.x = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // To allow ImGuiListClipper to function we propagate our row height if (!column->IsVisible) @@ -1950,14 +1975,20 @@ int ImGui::TableGetColumnIndex() } // Return the cell rectangle based on currently known height. -// Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. -// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. -ImRect ImGui::TableGetCellBgRect() +// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. +// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right +// columns report a small offset so their CellBgRect can extend up to the outer border. +ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) { - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; - return ImRect(column->MinX, table->RowPosY1, column->MaxX, table->RowPosY2); + const ImGuiTableColumn* column = &table->Columns[column_n]; + float x1 = column->MinX; + float x2 = column->MaxX; + if (column->PrevVisibleColumn == -1) + x1 -= table->CellSpacingX1; + if (column->NextVisibleColumn == -1) + x2 += table->CellSpacingX2; + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); } const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) @@ -2206,12 +2237,10 @@ void ImGui::TableHeader(const char* label) ImVec2 label_pos = window->DC.CursorPos; // If we already got a row height, there's use that. - ImRect cell_r = TableGetCellBgRect(); - cell_r.Min.x -= table->CellSpacingX; // FIXME-TABLE: TableGetCellRect() is misleading. + // FIXME-TABLE-PADDING: Problem if the correct outer-padding CellBgRect strays off our ClipRect + ImRect cell_r = TableGetCellBgRect(table, column_n); float label_height = ImMax(label_size.y, table->RowMinHeight - g.Style.CellPadding.y * 2.0f); - //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] - // Keep header highlighted when context menu is open. // (FIXME-TABLE: however we cannot assume the ID of said popup if it has been created by the user...) const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent); @@ -2221,12 +2250,16 @@ void ImGui::TableHeader(const char* label) if (!ItemAdd(bb, id)) return; + //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); if (hovered || selected) { const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + //RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); } if (held) @@ -2611,7 +2644,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table) settings->SaveFlags = ImGuiTableFlags_None; for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) { - const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->WidthStretchWeight : column->WidthRequest; + const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; column_settings->WidthOrWeight = width_or_weight; column_settings->Index = (ImS8)n; column_settings->DisplayOrder = column->DisplayOrder; @@ -2623,9 +2656,9 @@ void ImGui::TableSaveSettings(ImGuiTable* table) save_ref_scale = true; // We skip saving some data in the .ini file when they are unnecessary to restore our state. - // Note that fixed width where initial width was derived from auto-fit will always be saved as WidthOrWeightInitValue will be 0.0f. + // Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f. // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present. - if (width_or_weight != column->WidthOrWeightInitValue) + if (width_or_weight != column->InitStretchWeightOrWidth) settings->SaveFlags |= ImGuiTableFlags_Resizable; if (column->DisplayOrder != n) settings->SaveFlags |= ImGuiTableFlags_Reorderable; @@ -2678,7 +2711,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table) if (settings->SaveFlags & ImGuiTableFlags_Resizable) { if (column_settings->IsStretch) - column->WidthStretchWeight = column_settings->WidthOrWeight; + column->StretchWeight = column_settings->WidthOrWeight; else column->WidthRequest = column_settings->WidthOrWeight; column->AutoFitQueue = 0x00; @@ -2824,7 +2857,7 @@ void ImGui::TableSettingsInstallHandler(ImGuiContext* context) void ImGui::DebugNodeTable(ImGuiTable* table) { - char buf[256]; + char buf[512]; char* p = buf; const char* buf_end = buf + IM_ARRAYSIZE(buf); const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2); @@ -2839,21 +2872,23 @@ void ImGui::DebugNodeTable(ImGuiTable* table) BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f)", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight()); BulletText("InnerWidth: %.1f%s", table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); BulletText("ColumnsWidth: %.1f, AutoFitWidth: %.1f", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth); + BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); for (int n = 0; n < table->ColumnsCount; n++) { ImGuiTableColumn* column = &table->Columns[n]; const char* name = TableGetColumnName(table, n); - BulletText("Column %d order %d name '%s': +%.1f to +%.1f\n" + ImFormatString(buf, IM_ARRAYSIZE(buf), + "Column %d order %d name '%s': +%.1f to +%.1f\n" "Visible: %d, Clipped: %d, DrawChannels: %d,%d\n" - "WidthGiven/Request: %.2f/%.2f, WidthWeight: %.3f\n" + "WidthGiven: %.2f, Request/Auto: %.2f/%.2f, StretchWeight: %.3f\n" "ContentWidth: Frozen %d, Unfrozen %d, HeadersUsed/Ideal %d/%d\n" "SortOrder: %d, SortDir: %s\n" "UserID: 0x%08X, Flags: 0x%04X: %s%s%s%s..", n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, column->IsVisible, column->IsClipped, column->DrawChannelFrozen, column->DrawChannelUnfrozen, - column->WidthGiven, column->WidthRequest, column->WidthStretchWeight, + column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->ContentWidthFrozen, column->ContentWidthUnfrozen, column->ContentWidthHeadersUsed, column->ContentWidthHeadersIdeal, column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? "Ascending" : (column->SortDirection == ImGuiSortDirection_Descending) ? "Descending" : "None", column->UserID, column->Flags, @@ -2861,6 +2896,13 @@ void ImGui::DebugNodeTable(ImGuiTable* table) (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) ? "WidthAlwaysAutoResize " : "", (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); + Bullet(); + Selectable(buf); + if (IsItemHovered()) + { + ImRect r(column->MinX, table->OuterRect.Min.y, column->MaxX, table->OuterRect.Max.y); + GetForegroundDrawList()->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255)); + } } if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) DebugNodeTableSettings(settings);