Browse Source

Tables: Try to report contents width to outer window, generally better auto-fit.

omar 5 years ago
parent
commit
dff26191bd
3 changed files with 63 additions and 30 deletions
  1. 18 0
      imgui_demo.cpp
  2. 2 2
      imgui_internal.h
  3. 43 28
      imgui_tables.cpp

+ 18 - 0
imgui_demo.cpp

@@ -3570,6 +3570,24 @@ static void ShowDemoWindowTables()
             }
             ImGui::EndTable();
         }
+
+        if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_SizingPolicyFixedX))
+        {
+            ImGui::TableSetupColumn("One");
+            ImGui::TableSetupColumn("Two");
+            ImGui::TableSetupColumn("Three");
+            ImGui::TableAutoHeaders();
+            for (int row = 0; row < 6; row++)
+            {
+                ImGui::TableNextRow();
+                for (int column = 0; column < 3; column++)
+                {
+                    ImGui::TableSetColumnIndex(column);
+                    ImGui::Text("Fixed %d,%d", row, column);
+                }
+            }
+            ImGui::EndTable();
+        }
         ImGui::TreePop();
     }
 

+ 2 - 2
imgui_internal.h

@@ -1981,9 +1981,9 @@ struct ImGuiTable
     float                       CellSpacingX;               // Spacing between non-bordered cells
     float                       LastOuterHeight;            // Outer height from last frame
     float                       LastFirstRowHeight;         // Height of first row from last frame
-    float                       ColumnsTotalWidth;
     float                       InnerWidth;                 // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
-    float                       IdealTotalWidth;            // Sum of ideal column width for nothing to be clipped
+    float                       ColumnsTotalWidth;          // Sum of current column width
+    float                       ColumnsAutoFitWidth;        // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window
     float                       ResizedColumnNextWidth;
     ImRect                      OuterRect;                  // Note: OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
     ImRect                      WorkRect;

+ 43 - 28
imgui_tables.cpp

@@ -558,13 +558,14 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table)
     // (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 spacing_auto_x = table->CellSpacingX * (1.0f + 2.0f); // CellSpacingX is >0.0f when there's no vertical border, in which case we add two extra CellSpacingX to make auto-fit look nice instead of cramped. We may want to expose this somehow.
     const float min_column_width = TableGetMinColumnWidth();
 
     int count_fixed = 0;
     float width_fixed = 0.0f;
     float total_weights = 0.0f;
     table->LeftMostStretchedColumnDisplayOrder = -1;
-    table->IdealTotalWidth = 0.0f;
+    table->ColumnsAutoFitWidth = 0.0f;
     for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
     {
         if (!(table->ActiveMaskByDisplayOrder & ((ImU64)1 << order_n)))
@@ -591,7 +592,7 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table)
         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);
-        table->IdealTotalWidth += column_width_ideal;
+        table->ColumnsAutoFitWidth += column_width_ideal;
 
         if (column->Flags & (ImGuiTableColumnFlags_WidthAlwaysAutoResize | ImGuiTableColumnFlags_WidthFixed))
         {
@@ -623,6 +624,10 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table)
         }
     }
 
+    // CellSpacingX is >0.0f when there's no vertical border, in which case we add two extra CellSpacingX to make auto-fit look nice instead of cramped.
+    // We may want to expose this somehow.
+    table->ColumnsAutoFitWidth += spacing_auto_x * (table->ColumnsActiveCount - 1);
+
     // Layout
     // Remove -1.0f to cancel out the +1.0f we are doing in EndTable() to make last column line visible
     const float width_spacings = table->CellSpacingX * (table->ColumnsActiveCount - 1);
@@ -956,28 +961,6 @@ void    ImGui::EndTable()
     table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
     table->LastOuterHeight = table->OuterRect.GetHeight();
 
-    // Store content width reference for each column
-    float max_pos_x = inner_window->DC.CursorMaxPos.x;
-    for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
-    {
-        ImGuiTableColumn* column = &table->Columns[column_n];
-
-        // Store content width (for both Headers and Rows)
-        //float ref_x = column->MinX;
-        float ref_x_rows = column->StartXRows - table->CellPaddingX1;
-        float ref_x_headers = column->StartXHeaders - table->CellPaddingX1;
-        column->ContentWidthRowsFrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsFrozen - ref_x_rows);
-        column->ContentWidthRowsUnfrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsUnfrozen - ref_x_rows);
-        column->ContentWidthHeadersUsed = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersUsed - ref_x_headers);
-        column->ContentWidthHeadersIdeal = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersIdeal - ref_x_headers);
-
-        // Add an extra 1 pixel so we can see the last column vertical line if it lies on the right-most edge.
-        if (table->ActiveMaskByIndex & ((ImU64)1 << column_n))
-            max_pos_x = ImMax(max_pos_x, column->MaxX + 1.0f);
-    }
-
-    inner_window->DC.CursorMaxPos.x = max_pos_x;
-
     if (!(flags & ImGuiTableFlags_NoClipX))
         inner_window->DrawList->PopClipRect();
     inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back();
@@ -1015,16 +998,16 @@ void    ImGui::EndTable()
     }
 
     // Layout in outer window
+    const float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
+    const float backup_outer_max_pos_x = outer_window->DC.CursorMaxPos.x;
+    const float backup_inner_max_pos_x = inner_window->DC.CursorMaxPos.x;
     inner_window->WorkRect = table->HostWorkRect;
     inner_window->SkipItems = table->HostSkipItems;
     outer_window->DC.CursorPos = table->OuterRect.Min;
     outer_window->DC.ColumnsOffset.x = 0.0f;
     if (inner_window != outer_window)
     {
-        // Override EndChild's ItemSize with our own to enable auto-resize on the X axis when possible
-        float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
         EndChild();
-        outer_window->DC.CursorMaxPos.x = backup_outer_cursor_pos_x + table->ColumnsTotalWidth + 1.0f + inner_window->ScrollbarSizes.x;
     }
     else
     {
@@ -1034,6 +1017,38 @@ void    ImGui::EndTable()
         ItemSize(item_size);
     }
 
+    // Store content width reference for each column
+    float max_pos_x = backup_inner_max_pos_x;
+    for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
+    {
+        ImGuiTableColumn* column = &table->Columns[column_n];
+
+        // Store content width (for both Headers and Rows)
+        //float ref_x = column->MinX;
+        float ref_x_rows = column->StartXRows - table->CellPaddingX1;
+        float ref_x_headers = column->StartXHeaders - table->CellPaddingX1;
+        column->ContentWidthRowsFrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsFrozen - ref_x_rows);
+        column->ContentWidthRowsUnfrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsUnfrozen - ref_x_rows);
+        column->ContentWidthHeadersUsed = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersUsed - ref_x_headers);
+        column->ContentWidthHeadersIdeal = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersIdeal - ref_x_headers);
+
+        // Add an extra 1 pixel so we can see the last column vertical line if it lies on the right-most edge.
+        if (table->ActiveMaskByIndex & ((ImU64)1 << column_n))
+            max_pos_x = ImMax(max_pos_x, column->MaxX + 1.0f);
+    }
+
+    // Override EndChild/ItemSize max extent with our own to enable auto-resize on the X axis when possible
+    // FIXME-TABLE: This can be improved (e.g. for Fixed columns we don't want to auto AutoFitWidth? or propagate window auto-fit to table?)
+    if (table->Flags & ImGuiTableFlags_ScrollX)
+    {
+        inner_window->DC.CursorMaxPos.x = max_pos_x; // Set contents width for scrolling
+        outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, backup_outer_cursor_pos_x + table->ColumnsTotalWidth + 1.0f + inner_window->ScrollbarSizes.x); // For auto-fit
+    }
+    else
+    {
+        outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, table->WorkRect.Min.x + table->ColumnsAutoFitWidth); // For auto-fit
+    }
+
     // Save settings
     if (table->IsSettingsDirty)
         TableSaveSettings(table);
@@ -2571,7 +2586,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
         GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));
     if (!open)
         return;
-    BulletText("OuterWidth: %.1f, InnerWidth: %.1f%s, IdealWidth: %.1f", table->OuterRect.GetWidth(), table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "", table->IdealTotalWidth);
+    BulletText("OuterWidth: %.1f, InnerWidth: %.1f%s, ColumnsWidth: %.1f, AutoFitWidth: %.1f", table->OuterRect.GetWidth(), table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth);
     for (int n = 0; n < table->ColumnsCount; n++)
     {
         ImGuiTableColumn* column = &table->Columns[n];