Settings: added io.ConfigIniSettingsAutoDiscardMonths, trimming tool in in Metrics->Settings + internal CleanupIniSettings(). (#9460)

cc #437 #2564
This commit is contained in:
ocornut
2026-07-02 18:28:56 +02:00
parent f7e8343ee9
commit 5fb77dfde1
5 changed files with 107 additions and 5 deletions

View File

@@ -118,12 +118,15 @@ Other Changes:
- Scale the NavCursor border thickness when using large values with `ScallAllSizes()`.
- Settings:
- Windows/Tables settings entries can now record the last used date in YYYYMMDD format,
allowing cleanup tools to run to e.g. delete entries that haven't been used in X months.
- Added bool io.ConfigIniSettingsSaveLastUsedDate to disable saving that info.
allowing tools to run to e.g. delete entries that haven't been used in X months. (#9460)
- Added bool io.ConfigIniSettingsSaveLastUsedDate to disable saving that info. (#9460)
- Added int io.ConfigIniSettingsAutoDiscardMonths to enable a mode where unused settings
are automatically discard after xx months. (#9460)
- Added a trimming tool under Metrics->Settings, along with a yet-unexposed function.
- The current system date is fed through ImGuiPlatformIO::Platform_SessionDate,
which is automatically set by a call to time() done during context creation.
which is automatically set by a call to time() done during context creation. (#9460)
- Added IMGUI_DISABLE_TIME_FUNCTIONS to disable setting platform_io.Platform_SessionDate.
A custom backend may still set it manually.
A custom backend may still set it manually. (#9460)
- DrawList:
- Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091)
- Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText()

View File

@@ -1365,6 +1365,7 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted
// Settings
static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
static void WindowSettingsHandler_Cleanup(ImGuiContext*, ImGuiSettingsHandler*, ImGuiSettingsCleanupArgs* args);
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
@@ -1684,6 +1685,7 @@ ImGuiIO::ImGuiIO()
ConfigWindowsCopyContentsWithCtrlC = false;
ConfigScrollbarScrollByPage = true;
ConfigIniSettingsSaveLastUsedDate = true;
ConfigIniSettingsAutoDiscardMonths = 0;
ConfigMemoryCompactTimer = 60.0f;
ConfigDebugIsDebuggerPresent = false;
ConfigDebugHighlightIdConflicts = true;
@@ -4442,6 +4444,7 @@ void ImGui::Initialize()
ini_handler.TypeName = "Window";
ini_handler.TypeHash = ImHashStr("Window");
ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
ini_handler.CleanupFn = WindowSettingsHandler_Cleanup;
ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
@@ -15692,6 +15695,19 @@ void ImGui::ClearIniSettings()
handler.ClearAllFn(&g, &handler);
}
void ImGui::CleanupIniSettings(ImGuiSettingsCleanupArgs* args)
{
ImGuiContext& g = *GImGui;
if (g.PlatformIO.Platform_SessionDate == 0)
return;
ImGuiPackedDate discard_older_than_date_p = g.PlatformIO.Platform_SessionDate;
discard_older_than_date_p.SubtractMonths(args->DiscardOlderThanMonths);
args->_DiscardOlderThanDate = discard_older_than_date_p.Unpack();
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.CleanupFn != NULL)
handler.CleanupFn(&g, &handler, args);
}
void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
{
size_t file_data_size = 0;
@@ -15770,6 +15786,9 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
memcpy(buf, ini_data, ini_size);
// Call post-read handlers
ImGuiSettingsCleanupArgs cleanup_args;
if (g.IO.ConfigIniSettingsAutoDiscardMonths > 0)
cleanup_args.DiscardOlderThanMonths = g.IO.ConfigIniSettingsAutoDiscardMonths;
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (handler.ApplyAllFn != NULL)
handler.ApplyAllFn(&g, &handler);
@@ -15866,6 +15885,18 @@ static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandl
g.SettingsWindows.clear();
}
static void WindowSettingsHandler_Cleanup(ImGuiContext* ctx, ImGuiSettingsHandler*, ImGuiSettingsCleanupArgs* args)
{
ImGuiContext& g = *ctx;
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{
if (args->_DiscardOlderThanDate != 0 && settings->LastUsedDate.Unpack() < args->_DiscardOlderThanDate)
settings->WantDelete = true;
if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && settings->LastUsedDate.IsValid() == false))
settings->LastUsedDate = g.SessionDate;
}
}
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{
ImGuiID id = ImHashStr(name);
@@ -15918,6 +15949,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (!settings)
{
settings = ImGui::CreateNewWindowSettings(window->Name);
settings->LastUsedDate = g.SessionDate;
window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
}
IM_ASSERT(settings->ID == window->ID);
@@ -16724,6 +16756,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiPlatformIO& platform_io = g.PlatformIO;
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
if (cfg->ShowDebugLog)
ShowDebugLogWindow(&cfg->ShowDebugLog);
@@ -17056,8 +17089,36 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Text("\"%s\"", g.IO.IniFilename);
else
TextUnformatted("<NULL>");
Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
int highlight_older_than_date = 0;
Text("SessionDate: %d", platform_io.Platform_SessionDate);
BeginDisabled(platform_io.Platform_SessionDate == 0);
Checkbox("Highlight Entries Older Than", &cfg->SettingsHighlightOldEntries);
SetNextItemWidth(GetFontSize() * 8);
SameLine();
SliderInt("Months", &cfg->SettingsDiscardMonths, 1, 24);
if (cfg->SettingsHighlightOldEntries && cfg->SettingsDiscardMonths > 0)
{
ImGuiPackedDate cutoff_date = platform_io.Platform_SessionDate;
cutoff_date.SubtractMonths(cfg->SettingsDiscardMonths);
highlight_older_than_date = cutoff_date.Unpack();
SameLine();
ImGuiSettingsCleanupArgs cleanup_args;
cleanup_args.DiscardOlderThanMonths = cfg->SettingsDiscardMonths;
if (Button("Discard"))
CleanupIniSettings(&cleanup_args);
}
EndDisabled();
Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
struct ScopedHighlightOlderThan
{
bool Highlight;
ScopedHighlightOlderThan(int cutoff_date, ImGuiPackedDate in_date) { Highlight = cutoff_date != 0 && in_date.Unpack() < cutoff_date; if (Highlight) PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); }
~ScopedHighlightOlderThan() { if (Highlight) PopStyleColor(); }
};
if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
{
for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
@@ -17067,14 +17128,20 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
{
for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{
ScopedHighlightOlderThan scoped_highlight(highlight_older_than_date, settings->LastUsedDate);
DebugNodeWindowSettings(settings);
}
TreePop();
}
if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
{
for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
{
ScopedHighlightOlderThan scoped_highlight(highlight_older_than_date, settings->LastUsedDate);
DebugNodeTableSettings(settings, NULL);
}
TreePop();
}

View File

@@ -2438,6 +2438,7 @@ struct ImGuiIO
// Ini Settings
bool ConfigIniSettingsSaveLastUsedDate;// = true // Enable loading/saving last used day (YYYYMMDD) in some .ini struct, making things easier to audit and allowing custom tools to cleanup old data.
int ConfigIniSettingsAutoDiscardMonths; // = 0 // [BETA] Set number of months after which unused .ini entries are discarded on load. Require platform_io.Platform_SessionDate to be set. For systems supporting the feature, .ini entries without a LastUsed field will always be discarded! Please report if you are using this.
// Miscellaneous options
// (you can visualize and interact with all options in 'Demo->Configuration')

View File

@@ -98,6 +98,7 @@ Index of this file:
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn'
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
#elif defined(__GNUC__)
@@ -845,7 +846,9 @@ struct ImGuiPackedDate
ImGuiPackedDate() { Year = Month = Day = 0; }
ImGuiPackedDate(int yyyymmdd) { Year = (ImU16)((yyyymmdd / 10000) - 2000); Month = (ImU16)((yyyymmdd / 100) % 100); Day = (ImU16)(yyyymmdd % 100); } // Pack
bool IsValid() { return (Year && Month && Day); }
int Unpack() const { return (Year && Month && Day) ? ((Year + 2000) * 10000) + (Month * 100) + Day : 0; } // Unpack
void SubtractMonths(int m) { while (m > 0) { Year -= Month == 1; Month = (Month == 1) ? 12 : Month - 1; m--; } } // FIXME-OPT: Stupid but enough for what we do with it.
};
// Helper: ImGuiStorage
@@ -2043,6 +2046,14 @@ struct ImGuiWindowSettings
char* GetName() { return (char*)(this + 1); }
};
struct ImGuiSettingsCleanupArgs
{
int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months.
bool SetCurrentSessionDateToAll = false; // Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this.
bool SetCurrentSessionDateWhenMissingDate = false; // Enable to write current SessionDate to all supporting entries missing a date. // Let us know in #9460 if you use this.
int _DiscardOlderThanDate = 0; // [Internal]
};
struct ImGuiSettingsHandler
{
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
@@ -2053,6 +2064,7 @@ struct ImGuiSettingsHandler
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order)
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
void (*CleanupFn) (ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiSettingsCleanupArgs* args);// Cleanup/patch settings
void* UserData;
ImGuiSettingsHandler() { memset((void*)this, 0, sizeof(*this)); }
@@ -2166,6 +2178,8 @@ struct ImGuiMetricsConfig
int ShowTablesRectsType = -1;
int HighlightMonitorIdx = -1;
ImGuiID HighlightViewportID = 0;
int SettingsDiscardMonths = 6;
bool SettingsHighlightOldEntries = false;
bool ShowFontPreview = true;
};
@@ -3410,6 +3424,7 @@ namespace ImGui
IMGUI_API void MarkIniSettingsDirty();
IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window);
IMGUI_API void ClearIniSettings();
IMGUI_API void CleanupIniSettings(ImGuiSettingsCleanupArgs* args); // [BETA] Expected to turn into a public API. Please report if you are using this!
IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler);
IMGUI_API void RemoveSettingsHandler(const char* type_name);
IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);

View File

@@ -4126,6 +4126,21 @@ static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandle
g.SettingsTables.clear();
}
static void TableSettingsHandler_Cleanup(ImGuiContext* ctx, ImGuiSettingsHandler*, ImGuiSettingsCleanupArgs* args)
{
ImGuiContext& g = *ctx;
for (int i = 0; i != g.Tables.GetMapSize(); i++)
if (ImGuiTable* table = g.Tables.TryGetMapData(i))
table->SettingsOffset = -1;
for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
{
if (args->_DiscardOlderThanDate != 0 && settings->LastUsedDate.Unpack() < args->_DiscardOlderThanDate)
settings->ID = 0;
if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && settings->LastUsedDate.IsValid() == false))
settings->LastUsedDate = g.SessionDate;
}
}
// Apply to existing windows (if any)
static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{
@@ -4234,6 +4249,7 @@ void ImGui::TableSettingsAddSettingsHandler()
ini_handler.TypeName = "Table";
ini_handler.TypeHash = ImHashStr("Table");
ini_handler.ClearAllFn = TableSettingsHandler_ClearAll;
ini_handler.CleanupFn = TableSettingsHandler_Cleanup;
ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll;