Browse Source

Tables: Allow hot-reload of settings (merge policy), tidying up settings code

omar 5 years ago
parent
commit
95c273618e
3 changed files with 90 additions and 49 deletions
  1. 1 9
      imgui.cpp
  2. 5 6
      imgui_internal.h
  3. 84 34
      imgui_tables.cpp

+ 1 - 9
imgui.cpp

@@ -3970,15 +3970,7 @@ void ImGui::Initialize(ImGuiContext* context)
 
 
 #ifdef IMGUI_HAS_TABLE
 #ifdef IMGUI_HAS_TABLE
     // Add .ini handle for ImGuiTable type
     // Add .ini handle for ImGuiTable type
-    {
-        ImGuiSettingsHandler ini_handler;
-        ini_handler.TypeName = "Table";
-        ini_handler.TypeHash = ImHashStr("Table");
-        ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
-        ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
-        ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
-        g.SettingsHandlers.push_back(ini_handler);
-    }
+    TableInstallSettingsHandler(context);
 #endif // #ifdef IMGUI_HAS_TABLE
 #endif // #ifdef IMGUI_HAS_TABLE
 
 
 #ifdef IMGUI_HAS_DOCK
 #ifdef IMGUI_HAS_DOCK

+ 5 - 6
imgui_internal.h

@@ -2066,9 +2066,10 @@ struct ImGuiTableColumnSettings
 struct ImGuiTableSettings
 struct ImGuiTableSettings
 {
 {
     ImGuiID                     ID;                     // Set to 0 to invalidate/delete the setting
     ImGuiID                     ID;                     // Set to 0 to invalidate/delete the setting
-    ImGuiTableFlags             SaveFlags;
+    ImGuiTableFlags             SaveFlags;              // Indicate data we want to save using the Resizable/Reorderable/Sortable/Hideable flags (could be using its own flags..)
     ImS8                        ColumnsCount;
     ImS8                        ColumnsCount;
-    ImS8                        ColumnsCountMax;
+    ImS8                        ColumnsCountMax;        // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher
+    bool                        WantApply;              // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
 
 
     ImGuiTableSettings()        { memset(this, 0, sizeof(*this)); }
     ImGuiTableSettings()        { memset(this, 0, sizeof(*this)); }
     ImGuiTableColumnSettings*   GetColumnSettings()     { return (ImGuiTableColumnSettings*)(this + 1); }
     ImGuiTableColumnSettings*   GetColumnSettings()     { return (ImGuiTableColumnSettings*)(this + 1); }
@@ -2271,10 +2272,8 @@ namespace ImGui
     IMGUI_API void          PopTableBackground();
     IMGUI_API void          PopTableBackground();
     IMGUI_API void          TableLoadSettings(ImGuiTable* table);
     IMGUI_API void          TableLoadSettings(ImGuiTable* table);
     IMGUI_API void          TableSaveSettings(ImGuiTable* table);
     IMGUI_API void          TableSaveSettings(ImGuiTable* table);
-    IMGUI_API ImGuiTableSettings* TableFindSettings(const ImGuiTable* table);
-    IMGUI_API void*         TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
-    IMGUI_API void          TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
-    IMGUI_API void          TableSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
+    IMGUI_API ImGuiTableSettings* TableGetBoundSettings(const ImGuiTable* table);
+    IMGUI_API void          TableInstallSettingsHandler(ImGuiContext* context);
 
 
     // Tab Bars
     // Tab Bars
     IMGUI_API bool          BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
     IMGUI_API bool          BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);

+ 84 - 34
imgui_tables.cpp

@@ -2305,19 +2305,28 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
 // [Main] 4: TableSettingsHandler_WriteAll()   When .ini file is dirty (which can come from other source), save TableSettings into .ini file.
 // [Main] 4: TableSettingsHandler_WriteAll()   When .ini file is dirty (which can come from other source), save TableSettings into .ini file.
 //-------------------------------------------------------------------------
 //-------------------------------------------------------------------------
 
 
-static ImGuiTableSettings* CreateTableSettings(ImGuiID id, int columns_count)
+// Clear and initialize empty settings instance
+static void InitTableSettings(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max)
 {
 {
-    ImGuiContext& g = *GImGui;
-    ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings));
     IM_PLACEMENT_NEW(settings) ImGuiTableSettings();
     IM_PLACEMENT_NEW(settings) ImGuiTableSettings();
     ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings();
     ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings();
-    for (int n = 0; n < columns_count; n++, settings_column++)
+    for (int n = 0; n < columns_count_max; n++, settings_column++)
         IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings();
         IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings();
     settings->ID = id;
     settings->ID = id;
-    settings->ColumnsCount = settings->ColumnsCountMax = (ImS8)columns_count;
+    settings->ColumnsCount = (ImS8)columns_count;
+    settings->ColumnsCountMax = (ImS8)columns_count_max;
+    settings->WantApply = true;
+}
+
+static ImGuiTableSettings* CreateTableSettings(ImGuiID id, int columns_count)
+{
+    ImGuiContext& g = *GImGui;
+    ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings));
+    InitTableSettings(settings, id, columns_count, columns_count);
     return settings;
     return settings;
 }
 }
 
 
+// Find existing settings
 static ImGuiTableSettings* FindTableSettingsByID(ImGuiID id)
 static ImGuiTableSettings* FindTableSettingsByID(ImGuiID id)
 {
 {
     // FIXME-OPT: Might want to store a lookup map for this?
     // FIXME-OPT: Might want to store a lookup map for this?
@@ -2328,20 +2337,19 @@ static ImGuiTableSettings* FindTableSettingsByID(ImGuiID id)
     return NULL;
     return NULL;
 }
 }
 
 
-ImGuiTableSettings* ImGui::TableFindSettings(const ImGuiTable* table)
+// Get settings for a given table, NULL if none
+ImGuiTableSettings* ImGui::TableGetBoundSettings(const ImGuiTable* table)
 {
 {
-    if (table->SettingsOffset == -1)
-        return NULL;
-
-    ImGuiContext& g = *GImGui;
-    ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);
-    IM_ASSERT(settings->ID == table->ID);
-    if (settings->ColumnsCountMax < table->ColumnsCount)
+    if (table->SettingsOffset != -1)
     {
     {
-        settings->ID = 0; // Ditch storage if we won't fit because of a count change
-        return NULL;
+        ImGuiContext& g = *GImGui;
+        ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);
+        IM_ASSERT(settings->ID == table->ID);
+        if (settings->ColumnsCountMax >= table->ColumnsCount)
+            return settings; // OK
+        settings->ID = 0; // Invalidate storage, we won't fit because of a count change
     }
     }
-    return settings;
+    return NULL;
 }
 }
 
 
 void ImGui::TableSaveSettings(ImGuiTable* table)
 void ImGui::TableSaveSettings(ImGuiTable* table)
@@ -2352,7 +2360,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
 
 
     // Bind or create settings data
     // Bind or create settings data
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
-    ImGuiTableSettings* settings = TableFindSettings(table);
+    ImGuiTableSettings* settings = TableGetBoundSettings(table);
     if (settings == NULL)
     if (settings == NULL)
     {
     {
         settings = CreateTableSettings(table->ID, table->ColumnsCount);
         settings = CreateTableSettings(table->ID, table->ColumnsCount);
@@ -2370,7 +2378,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
     settings->SaveFlags = ImGuiTableFlags_Resizable;
     settings->SaveFlags = ImGuiTableFlags_Resizable;
     for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++)
     for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++)
     {
     {
-        //column_settings->WidthOrWeight = column->WidthRequested; // FIXME-WIP
+        //column_settings->WidthOrWeight = column->WidthRequested; // FIXME-TABLE: Missing
         column_settings->Index = (ImS8)n;
         column_settings->Index = (ImS8)n;
         column_settings->DisplayOrder = column->DisplayOrder;
         column_settings->DisplayOrder = column->DisplayOrder;
         column_settings->SortOrder = column->SortOrder;
         column_settings->SortOrder = column->SortOrder;
@@ -2378,7 +2386,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
         column_settings->Visible = column->IsActive;
         column_settings->Visible = column->IsActive;
 
 
         // We skip saving some data in the .ini file when they are unnecessary to restore our state
         // We skip saving some data in the .ini file when they are unnecessary to restore our state
-        // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved.
+        // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present.
         if (column->DisplayOrder != n)
         if (column->DisplayOrder != n)
             settings->SaveFlags |= ImGuiTableFlags_Reorderable;
             settings->SaveFlags |= ImGuiTableFlags_Reorderable;
         if (column_settings->SortOrder != -1)
         if (column_settings->SortOrder != -1)
@@ -2409,9 +2417,10 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
     }
     }
     else
     else
     {
     {
-        settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);
+        settings = TableGetBoundSettings(table);
     }
     }
     table->SettingsLoadedFlags = settings->SaveFlags;
     table->SettingsLoadedFlags = settings->SaveFlags;
+    IM_ASSERT(settings->ColumnsCount == table->ColumnsCount);
 
 
     // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
     // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
     ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
     ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
@@ -2422,14 +2431,13 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
             continue;
             continue;
         ImGuiTableColumn* column = &table->Columns[column_n];
         ImGuiTableColumn* column = &table->Columns[column_n];
         //column->WidthRequested = column_settings->WidthOrWeight; // FIXME-WIP
         //column->WidthRequested = column_settings->WidthOrWeight; // FIXME-WIP
-        if (column_settings->DisplayOrder != -1)
+        if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
             column->DisplayOrder = column_settings->DisplayOrder;
             column->DisplayOrder = column_settings->DisplayOrder;
-        if (column_settings->SortOrder != -1)
-        {
-            column->SortOrder = column_settings->SortOrder;
-            column->SortDirection = column_settings->SortDirection;
-        }
+        else
+            column->DisplayOrder = (ImS8)column_n;
         column->IsActive = column->IsActiveNextFrame = column_settings->Visible;
         column->IsActive = column->IsActiveNextFrame = column_settings->Visible;
+        column->SortOrder = column_settings->SortOrder;
+        column->SortDirection = column_settings->SortDirection;
     }
     }
 
 
     // FIXME-TABLE: Need to validate .ini data
     // FIXME-TABLE: Need to validate .ini data
@@ -2437,16 +2445,46 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
         table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImS8)column_n;
         table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImS8)column_n;
 }
 }
 
 
-void*   ImGui::TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
+static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
+{
+    ImGuiContext& g = *ctx;
+    for (int i = 0; i != g.Tables.GetSize(); i++)
+        g.Tables.GetByIndex(i)->SettingsOffset = -1;
+    g.SettingsTables.clear();
+}
+
+// Apply to existing windows (if any)
+static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
+{
+    ImGuiContext& g = *ctx;
+    for (int i = 0; i != g.Tables.GetSize(); i++)
+    {
+        ImGuiTable* table = g.Tables.GetByIndex(i);
+        table->IsSettingsRequestLoad = true;
+        table->SettingsOffset = -1;
+    }
+}
+
+static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
 {
 {
     ImGuiID id = 0;
     ImGuiID id = 0;
     int columns_count = 0;
     int columns_count = 0;
     if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2)
     if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2)
         return NULL;
         return NULL;
+
+    if (ImGuiTableSettings* settings = FindTableSettingsByID(id))
+    {
+        if (settings->ColumnsCountMax >= columns_count)
+        {
+            InitTableSettings(settings, id, columns_count, settings->ColumnsCountMax); // Recycle
+            return settings;
+        }
+        settings->ID = 0; // Invalidate storage if we won't fit because of a count change
+    }
     return CreateTableSettings(id, columns_count);
     return CreateTableSettings(id, columns_count);
 }
 }
 
 
-void    ImGui::TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
+static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
 {
 {
     // "Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
     // "Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
     ImGuiTableSettings* settings = (ImGuiTableSettings*)entry;
     ImGuiTableSettings* settings = (ImGuiTableSettings*)entry;
@@ -2465,7 +2503,7 @@ void    ImGui::TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler
     if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2)           { line = ImStrSkipBlank(line + r); column->SortOrder = (ImS8)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; }
     if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2)           { line = ImStrSkipBlank(line + r); column->SortOrder = (ImS8)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; }
 }
 }
 
 
-void    ImGui::TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
+static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
 {
 {
     ImGuiContext& g = *ctx;
     ImGuiContext& g = *ctx;
     for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
     for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
@@ -2488,10 +2526,8 @@ void    ImGui::TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHan
         for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)
         for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)
         {
         {
             // "Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
             // "Column 0  UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
-            if (column->UserID != 0)
-                buf->appendf("Column %-2d UserID=%08X", column_n, column->UserID);
-            else
-                buf->appendf("Column %-2d", column_n);
+            buf->appendf("Column %-2d", column_n);
+            if (column->UserID != 0)                    buf->appendf(" UserID=%08X", column->UserID);
             if (save_size)                              buf->appendf(" Width=%d", 0);// (int)settings_column->WidthOrWeight);  // FIXME-TABLE
             if (save_size)                              buf->appendf(" Width=%d", 0);// (int)settings_column->WidthOrWeight);  // FIXME-TABLE
             if (save_visible)                           buf->appendf(" Visible=%d", column->Visible);
             if (save_visible)                           buf->appendf(" Visible=%d", column->Visible);
             if (save_order)                             buf->appendf(" Order=%d", column->DisplayOrder);
             if (save_order)                             buf->appendf(" Order=%d", column->DisplayOrder);
@@ -2502,6 +2538,20 @@ void    ImGui::TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHan
     }
     }
 }
 }
 
 
+void    ImGui::TableInstallSettingsHandler(ImGuiContext* context)
+{
+    ImGuiContext& g = *context;
+    ImGuiSettingsHandler ini_handler;
+    ini_handler.TypeName = "Table";
+    ini_handler.TypeHash = ImHashStr("Table");
+    ini_handler.ClearAllFn = TableSettingsHandler_ClearAll;
+    ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
+    ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
+    ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll;
+    ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
+    g.SettingsHandlers.push_back(ini_handler);
+}
+
 //-------------------------------------------------------------------------
 //-------------------------------------------------------------------------
 // TABLE - Debugging
 // TABLE - Debugging
 //-------------------------------------------------------------------------
 //-------------------------------------------------------------------------
@@ -2543,7 +2593,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
             (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) ? "WidthAlwaysAutoResize " : "",
             (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) ? "WidthAlwaysAutoResize " : "",
             (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : "");
             (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : "");
     }
     }
-    if (ImGuiTableSettings* settings = TableFindSettings(table))
+    if (ImGuiTableSettings* settings = TableGetBoundSettings(table))
         DebugNodeTableSettings(settings);
         DebugNodeTableSettings(settings);
     TreePop();
     TreePop();
 }
 }