Settings, IO: added io.ConfigIniSettingsSaveLastUsedDate, platform_io.Platform_SessionDate, IMGUI_DISABLE_TIME_FUNCTIONS(). (#9460)

cc #437
This commit is contained in:
ocornut 2026-06-25 23:00:37 +02:00
parent 7d43c74b59
commit f7e8343ee9
7 changed files with 68 additions and 2 deletions

View file

@ -116,6 +116,14 @@ Other Changes:
The use of this is discouraged because it can easily create problems rendering e.g.
contiguous selection.
- 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.
- The current system date is fed through ImGuiPlatformIO::Platform_SessionDate,
which is automatically set by a call to time() done during context creation.
- Added IMGUI_DISABLE_TIME_FUNCTIONS to disable setting platform_io.Platform_SessionDate.
A custom backend may still set it manually.
- DrawList:
- Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091)
- Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText()

View file

@ -43,6 +43,7 @@
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_TIME_FUNCTIONS // Don't setup default platform_io.Platform_SessionDate value using time(), localtime_r().
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.

View file

@ -1243,6 +1243,12 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
// System includes
#include <stdio.h> // vsnprintf, sscanf, printf
#include <stdint.h> // intptr_t
#ifndef IMGUI_DISABLE_TIME_FUNCTIONS
#include <time.h> // time(), localtime_r()/localtime_s()
#if defined(_WIN32)
static tm* localtime_r(const time_t* timep, tm* result) { return localtime_s(result, timep) == 0 ? result : NULL; }
#endif
#endif
// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled
#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
@ -1677,6 +1683,7 @@ ImGuiIO::ImGuiIO()
ConfigWindowsMoveFromTitleBarOnly = false;
ConfigWindowsCopyContentsWithCtrlC = false;
ConfigScrollbarScrollByPage = true;
ConfigIniSettingsSaveLastUsedDate = true;
ConfigMemoryCompactTimer = 60.0f;
ConfigDebugIsDebuggerPresent = false;
ConfigDebugHighlightIdConflicts = true;
@ -4452,6 +4459,14 @@ void ImGui::Initialize()
g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl;
g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl;
// Setup session starting date
#ifndef IMGUI_DISABLE_TIME_FUNCTIONS
const time_t session_time = time(NULL);
struct tm session_datetime = {};
if (localtime_r(&session_time, &session_datetime))
g.PlatformIO.Platform_SessionDate = (session_datetime.tm_year + 1900) * 10000 + (session_datetime.tm_mon + 1) * 100 + session_datetime.tm_mday;
#endif
// Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID;
@ -5568,6 +5583,7 @@ void ImGui::NewFrame()
g.Time += g.IO.DeltaTime;
g.FrameCount += 1;
g.SessionDate = ImGuiPackedDate(g.PlatformIO.Platform_SessionDate);
g.TooltipOverrideCount = 0;
g.WindowsActiveCount = 0;
g.MenusIdSubmittedThisFrame.resize(0);
@ -6692,6 +6708,7 @@ static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* s
{
// Initial window state with e.g. default/arbitrary window position
// Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
ImGuiContext& g = *GImGui;
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
window->Pos = main_viewport->Pos + ImVec2(60, 60);
window->Size = window->SizeFull = ImVec2(0, 0);
@ -6699,6 +6716,7 @@ static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* s
if (settings != NULL)
{
settings->LastUsedDate = g.SessionDate;
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
ApplyWindowSettings(window, settings);
}
@ -15870,6 +15888,7 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }
else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
else if (sscanf(line, "IsChild=%d", &i) == 1) { settings->IsChild = (i != 0); }
else if (sscanf(line, "LastUsed=%d", &i) == 1) { settings->LastUsedDate = i; return; }
}
// Apply to existing windows (if any)
@ -15907,6 +15926,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
settings->IsChild = (window->Flags & ImGuiWindowFlags_ChildWindow) != 0;
settings->Collapsed = window->Collapsed;
settings->WantDelete = false;
settings->LastUsedDate = g.SessionDate;
}
// Write to text buffer
@ -15916,7 +15936,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (settings->WantDelete)
continue;
const char* settings_name = settings->GetName();
buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); // [Window][name]
if (settings->IsChild)
{
buf->appendf("IsChild=1\n");
@ -15929,6 +15949,9 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (settings->Collapsed)
buf->appendf("Collapsed=1\n");
}
if (g.IO.ConfigIniSettingsSaveLastUsedDate)
if (int last_used_date = settings->LastUsedDate.Unpack())
buf->appendf("LastUsed=%08d\n", last_used_date);
buf->append("\n");
}
}
@ -17866,7 +17889,7 @@ void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings)
{
if (settings->WantDelete)
BeginDisabled();
Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
BulletText("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
if (settings->WantDelete)
EndDisabled();

View file

@ -2436,6 +2436,9 @@ struct ImGuiIO
bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor.
bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible.
// 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.
// Miscellaneous options
// (you can visualize and interact with all options in 'Demo->Configuration')
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
@ -4039,6 +4042,10 @@ struct ImGuiPlatformIO
// [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
ImWchar Platform_LocaleDecimalPoint; // '.'
// Optional: Platform time/date
// This is automatically filled on startup. Used to store a "last used date" in some .ini structures. Facilitate creating tools to clean up old/unused data.
int Platform_SessionDate; // Integer storing YYYYMMDD e.g. 20261231 corresponding to the beginning of application session.
//------------------------------------------------------------------
// Input - Interface with Renderer Backend
//------------------------------------------------------------------

View file

@ -538,6 +538,9 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
ImGui::Text("Also see Style->Rendering for rendering options.");
ImGui::SeparatorText("Settings");
ImGui::Checkbox("io.ConfigIniSettingsSaveLastUsedDate", &io.ConfigIniSettingsSaveLastUsedDate);
// Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
ImGui::SeparatorText("Error Handling");

View file

@ -138,6 +138,7 @@ Index of this file:
struct ImBitVector; // Store 1-bit per value
struct ImRect; // An axis-aligned rectangle (2 points)
struct ImGuiTextIndex; // Maintain a line index for a text buffer.
struct ImGuiPackedDate; // A date in YYYYMMDD format packed into 16-bits
// ImDrawList/ImFontAtlas
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
@ -833,6 +834,20 @@ struct ImGuiTextIndex
void append(const char* base, int old_size, int new_size);
};
// Helper: ImGuiPackedDate (sizeof() == 2)
// Store a date in a way that is efficient to read/write in text form. If we stored e.g. number of days since Epoch we'd need costlier back and forth.
// This is specifically designed to be able to prune old .ini data.
struct ImGuiPackedDate
{
ImU16 Year : 7; // Year since 2000 // We can change to another offset e.g. 1970 but this is easier to watch in debugger.
ImU16 Month : 4; // Month (1-12)
ImU16 Day : 5; // Day (1-31)
ImGuiPackedDate() { Year = Month = Day = 0; }
ImGuiPackedDate(int yyyymmdd) { Year = (ImU16)((yyyymmdd / 10000) - 2000); Month = (ImU16)((yyyymmdd / 100) % 100); Day = (ImU16)(yyyymmdd % 100); } // Pack
int Unpack() const { return (Year && Month && Day) ? ((Year + 2000) * 10000) + (Month * 100) + Day : 0; } // Unpack
};
// Helper: ImGuiStorage
IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key);
@ -2018,6 +2033,7 @@ struct ImGuiWindowSettings
ImGuiID ID;
ImVec2ih Pos;
ImVec2ih Size;
ImGuiPackedDate LastUsedDate;
bool Collapsed : 1;
bool IsChild : 1;
bool WantApply : 1; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
@ -2533,6 +2549,7 @@ struct ImGuiContext
ImVector<ImTextureData*> UserTextures; // List of textures created/managed by user or third-party extension. Automatically appended into platform_io.Textures[].
// Settings
ImGuiPackedDate SessionDate; // Packed copy of platform_io.Platform_SessionDate, when valid.
bool SettingsLoaded;
float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
ImGuiTextBuffer SettingsIniData; // In memory .ini settings
@ -3208,6 +3225,7 @@ struct ImGuiTableSettings
float RefScale; // Reference scale to be able to rescale columns on font/dpi changes.
ImGuiTableColumnIdx ColumnsCount;
ImGuiTableColumnIdx ColumnsCountMax; // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher
ImGuiPackedDate LastUsedDate;
bool WantApply : 1; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
ImGuiTableSettings() { memset((void*)this, 0, sizeof(*this)); }

View file

@ -3933,6 +3933,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings);
}
settings->ColumnsCount = (ImGuiTableColumnIdx)table->ColumnsCount;
settings->LastUsedDate = g.SessionDate;
// Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings
IM_ASSERT(settings->ID == table->ID);
@ -4001,6 +4002,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
table->SettingsLoadedFlags = settings->SaveFlags;
table->RefScale = settings->RefScale;
settings->LastUsedDate = g.SessionDate;
// TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data.
}
@ -4163,6 +4165,7 @@ static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
int column_n = 0, r = 0, n = 0;
if (sscanf(line, "RefScale=%f", &f) == 1) { settings->RefScale = f; return; }
if (sscanf(line, "LastUsed=%d", &n) == 1) { settings->LastUsedDate = n; return; }
if (sscanf(line, "Column %d%n", &column_n, &r) == 1)
{
@ -4218,6 +4221,9 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
if (column->ID != 0) { buf->appendf(" ID=0x%08X", column->ID); }
buf->append("\n");
}
if (g.IO.ConfigIniSettingsSaveLastUsedDate)
if (int last_used_date = settings->LastUsedDate.Unpack())
buf->appendf("LastUsed=%08d\n", last_used_date);
buf->append("\n");
}
}