Tables: Better preserve column data (mainly widths) when columns count changes. (#4046) + .ini skips columns with no data.
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index a1a4d7ef6..6e49763 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -44,6 +44,7 @@
 - Scrolling: Fix mouse wheel axis swap when using SHIFT on macOS (system already does it). (#4010)
 - Window: Fix IsWindowAppearing() from returning true twice in most cases. (#3982, #1497, #1061)
 - Tables: Expose TableSetColumnEnabled() in public api. (#3935)
+- Tables: Better preserve widths when columns count changes. (#4046)
 - TabBar: Fixed mouse reordering with very fast movements (e.g. crossing multiple tabs in a single
   frame and then immediately standling still (would only affect automation/bots). [@rokups]
 - Drags, Sliders, Inputs: Specifying a NULL format to Float functions default them to "%.3f" to be
diff --git a/imgui.h b/imgui.h
index 1caf932..44b9922 100644
--- a/imgui.h
+++ b/imgui.h
@@ -61,7 +61,7 @@
 // Version
 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
 #define IMGUI_VERSION               "1.83 WIP"
-#define IMGUI_VERSION_NUM           18203
+#define IMGUI_VERSION_NUM           18204
 #define IMGUI_CHECKVERSION()        ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
 #define IMGUI_HAS_TABLE
 
diff --git a/imgui_tables.cpp b/imgui_tables.cpp
index c01c708..3677f9e 100644
--- a/imgui_tables.cpp
+++ b/imgui_tables.cpp
@@ -470,10 +470,14 @@
     table->MemoryCompacted = false;
 
     // Setup memory buffer (clear data if columns count changed)
-    const int stored_size = table->Columns.size();
-    if (stored_size != 0 && stored_size != columns_count)
+    ImGuiTableColumn* old_columns_to_preserve = NULL;
+    void* old_columns_raw_data = NULL;
+    const int old_columns_count = table->Columns.size();
+    if (old_columns_count != 0 && old_columns_count != columns_count)
     {
-        IM_FREE(table->RawData);
+        // Attempt to preserve width on column count change (#4046)
+        old_columns_to_preserve = table->Columns.Data;
+        old_columns_raw_data = table->RawData;
         table->RawData = NULL;
     }
     if (table->RawData == NULL)
@@ -496,14 +500,24 @@
         for (int n = 0; n < columns_count; n++)
         {
             ImGuiTableColumn* column = &table->Columns[n];
-            float width_auto = column->WidthAuto;
-            *column = ImGuiTableColumn();
-            column->WidthAuto = width_auto;
-            column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
+            if (old_columns_to_preserve && n < old_columns_count)
+            {
+                // FIXME: We don't attempt to preserve column order in this path.
+                *column = old_columns_to_preserve[n];
+            }
+            else
+            {
+                float width_auto = column->WidthAuto;
+                *column = ImGuiTableColumn();
+                column->WidthAuto = width_auto;
+                column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
+                column->IsEnabled = column->IsEnabledNextFrame = true;
+            }
             column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
-            column->IsEnabled = column->IsEnabledNextFrame = true;
         }
     }
+    if (old_columns_raw_data)
+        IM_FREE(old_columns_raw_data);
 
     // Load settings
     if (table->IsSettingsRequestLoad)
@@ -3350,6 +3364,9 @@
         for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)
         {
             // "Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
+            bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1);
+            if (!save_column)
+                continue;
             buf->appendf("Column %-2d", column_n);
             if (column->UserID != 0)                    buf->appendf(" UserID=%08X", column->UserID);
             if (save_size && column->IsStretch)         buf->appendf(" Weight=%.4f", column->WidthOrWeight);