From 95c273618eb81a5e16a0b726d6b7846460b63ccd Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 May 2020 20:24:37 +0200 Subject: [PATCH] Tables: Allow hot-reload of settings (merge policy), tidying up settings code --- imgui.cpp | 10 +--- imgui_internal.h | 11 ++--- imgui_tables.cpp | 120 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 91 insertions(+), 50 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 55c67bbb..7ad7a547 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3970,15 +3970,7 @@ void ImGui::Initialize(ImGuiContext* context) #ifdef IMGUI_HAS_TABLE // 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 #ifdef IMGUI_HAS_DOCK diff --git a/imgui_internal.h b/imgui_internal.h index 03ad431b..bd29e343 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2066,9 +2066,10 @@ struct ImGuiTableColumnSettings struct ImGuiTableSettings { 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 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)); } ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } @@ -2271,10 +2272,8 @@ namespace ImGui IMGUI_API void PopTableBackground(); IMGUI_API void TableLoadSettings(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 IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 80c1f89b..b585f114 100644 --- a/imgui_tables.cpp +++ b/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. //------------------------------------------------------------------------- +// Clear and initialize empty settings instance +static void InitTableSettings(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max) +{ + IM_PLACEMENT_NEW(settings) ImGuiTableSettings(); + ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings(); + for (int n = 0; n < columns_count_max; n++, settings_column++) + IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings(); + settings->ID = id; + 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)); - IM_PLACEMENT_NEW(settings) ImGuiTableSettings(); - ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings(); - for (int n = 0; n < columns_count; n++, settings_column++) - IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings(); - settings->ID = id; - settings->ColumnsCount = settings->ColumnsCountMax = (ImS8)columns_count; + InitTableSettings(settings, id, columns_count, columns_count); return settings; } +// Find existing settings static ImGuiTableSettings* FindTableSettingsByID(ImGuiID id) { // FIXME-OPT: Might want to store a lookup map for this? @@ -2328,20 +2337,19 @@ static ImGuiTableSettings* FindTableSettingsByID(ImGuiID id) 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) @@ -2352,7 +2360,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table) // Bind or create settings data ImGuiContext& g = *GImGui; - ImGuiTableSettings* settings = TableFindSettings(table); + ImGuiTableSettings* settings = TableGetBoundSettings(table); if (settings == NULL) { settings = CreateTableSettings(table->ID, table->ColumnsCount); @@ -2370,7 +2378,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table) settings->SaveFlags = ImGuiTableFlags_Resizable; 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->DisplayOrder = column->DisplayOrder; column_settings->SortOrder = column->SortOrder; @@ -2378,7 +2386,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table) column_settings->Visible = column->IsActive; // 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) settings->SaveFlags |= ImGuiTableFlags_Reorderable; if (column_settings->SortOrder != -1) @@ -2409,9 +2417,10 @@ void ImGui::TableLoadSettings(ImGuiTable* table) } else { - settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); + settings = TableGetBoundSettings(table); } table->SettingsLoadedFlags = settings->SaveFlags; + IM_ASSERT(settings->ColumnsCount == table->ColumnsCount); // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); @@ -2422,14 +2431,13 @@ void ImGui::TableLoadSettings(ImGuiTable* table) continue; ImGuiTableColumn* column = &table->Columns[column_n]; //column->WidthRequested = column_settings->WidthOrWeight; // FIXME-WIP - if (column_settings->DisplayOrder != -1) + if (settings->SaveFlags & ImGuiTableFlags_Reorderable) 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->SortOrder = column_settings->SortOrder; + column->SortDirection = column_settings->SortDirection; } // 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; } -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; int columns_count = 0; if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2) 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); } -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" 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; } } -void ImGui::TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) { ImGuiContext& g = *ctx; 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++) { // "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_visible) buf->appendf(" Visible=%d", column->Visible); 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 //------------------------------------------------------------------------- @@ -2543,7 +2593,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table) (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) ? "WidthAlwaysAutoResize " : "", (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); } - if (ImGuiTableSettings* settings = TableFindSettings(table)) + if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) DebugNodeTableSettings(settings); TreePop(); }