Browse Source

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.
ocornut 4 years ago
parent
commit
1731ae5a09
4 changed files with 226 additions and 136 deletions
  1. 8 4
      imgui.h
  2. 69 27
      imgui_demo.cpp
  3. 12 10
      imgui_internal.h
  4. 137 95
      imgui_tables.cpp

+ 8 - 4
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)

+ 69 - 27
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.");

+ 12 - 10
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 shrinking columns down in tight space.
+    float                   InitStretchWeightOrWidth;       // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
+    float                   StretchWeight;                  // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
+    float                   WidthAuto;                      // Automatic width
+    float                   WidthRequest;                   // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight 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 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);

+ 137 - 95
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);