mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-24 07:40:22 +01:00
Settings: Added LoadIniSettingsFromDisk(), LoadIniSettingsFromMemory(), SaveIniSettingsToDisk(), SaveIniSettingsToMemory(), io.WantSaveIniSettings. (#923, #993)
This commit is contained in:
parent
023cc25c7c
commit
0bf43b3a1b
@ -53,6 +53,8 @@ Other Changes:
|
||||
- Window: Fixed windows using the ImGuiWindowFlags_NoSavedSettings flag from not using the same default position as other windows. (#1760)
|
||||
- Window: Relaxed the internal stack size checker to allow Push/Begin/Pop/.../End patterns to be used with PushStyleColor, PushStyleVar, PushFont without causing a false positive assert. (#1767)
|
||||
- Columns: Fixed a bug introduced in 1.51 where columns would affect the contents size of their container, often creating feedback loops when ImGuiWindowFlags_AlwaysAutoResize was used. (#1760)
|
||||
- Settings: Added LoadIniSettingsFromDisk(), LoadIniSettingsFromMemory(), SaveIniSettingsToDisk(), SaveIniSettingsToMemory() to manually load/save .ini settings. (#923, #993)
|
||||
- Settings: Added io.WantSaveIniSettings flag, which is set to notify the application that e.g. SaveIniSettingsToMemory() should be called. (#923, #993)
|
||||
- MenuBar: Made BeginMainMenuBar() honor style.DisplaySafeAreaPadding so the text can be made visible on TV settings that don't display all pixels. (#1439) [@dougbinks]
|
||||
- InputText: On Mac OS X, filter out characters when the CMD modifier is held. (#1747) [@sivu]
|
||||
- InputText: On Mac OS X, support CMD+SHIFT+Z for Redo. CMD+Y is also supported as major apps seems to default to support both. (#1765) [@lfnoise]
|
||||
|
1
TODO.txt
1
TODO.txt
@ -183,7 +183,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
|
||||
- tree node: tweak color scheme to distinguish headers from selected tree node (#581)
|
||||
- tree node: leaf/non-leaf highlight mismatch.
|
||||
|
||||
!- settings: expose enough to save/load .ini from RAM instead of fopen
|
||||
- settings: write more decent code to allow saving/loading new fields: columns, selected tree nodes?
|
||||
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437)
|
||||
- stb: add defines to disable stb implementations
|
||||
|
91
imgui.cpp
91
imgui.cpp
@ -733,12 +733,6 @@ static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sort
|
||||
|
||||
static ImGuiWindowSettings* AddWindowSettings(const char* name);
|
||||
|
||||
static void LoadIniSettingsFromDisk(const char* ini_filename);
|
||||
static void LoadIniSettingsFromMemory(const char* buf);
|
||||
static void SaveIniSettingsToDisk(const char* ini_filename);
|
||||
static void SaveIniSettingsToMemory(ImVector<char>& out_buf);
|
||||
static void MarkIniSettingsDirty(ImGuiWindow* window);
|
||||
|
||||
static ImRect GetViewportRect();
|
||||
|
||||
static void ClosePopupToLevel(int remaining);
|
||||
@ -1455,7 +1449,7 @@ FILE* ImFileOpen(const char* filename, const char* mode)
|
||||
|
||||
// Load file content into memory
|
||||
// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
|
||||
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
|
||||
void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
|
||||
{
|
||||
IM_ASSERT(filename && file_open_mode);
|
||||
if (out_file_size)
|
||||
@ -1472,14 +1466,14 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int*
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int file_size = (int)file_size_signed;
|
||||
void* file_data = ImGui::MemAlloc((size_t)(file_size + padding_bytes));
|
||||
size_t file_size = (size_t)file_size_signed;
|
||||
void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
|
||||
if (file_data == NULL)
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
|
||||
if (fread(file_data, 1, file_size, f) != file_size)
|
||||
{
|
||||
fclose(f);
|
||||
ImGui::MemFree(file_data);
|
||||
@ -3444,20 +3438,27 @@ void ImGui::NewFrame()
|
||||
if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
|
||||
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
|
||||
|
||||
// Load settings on first frame
|
||||
// Load settings on first frame (if not explicitly loaded manually before)
|
||||
if (!g.SettingsLoaded)
|
||||
{
|
||||
IM_ASSERT(g.SettingsWindows.empty());
|
||||
LoadIniSettingsFromDisk(g.IO.IniFilename);
|
||||
if (g.IO.IniFilename)
|
||||
LoadIniSettingsFromDisk(g.IO.IniFilename);
|
||||
g.SettingsLoaded = true;
|
||||
}
|
||||
|
||||
// Save settings (with a delay so we don't spam disk too much)
|
||||
// Save settings (with a delay after the last modification, so we don't spam disk too much)
|
||||
if (g.SettingsDirtyTimer > 0.0f)
|
||||
{
|
||||
g.SettingsDirtyTimer -= g.IO.DeltaTime;
|
||||
if (g.SettingsDirtyTimer <= 0.0f)
|
||||
SaveIniSettingsToDisk(g.IO.IniFilename);
|
||||
{
|
||||
if (g.IO.IniFilename != NULL)
|
||||
SaveIniSettingsToDisk(g.IO.IniFilename);
|
||||
else
|
||||
g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
|
||||
g.SettingsDirtyTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
g.Time += g.IO.DeltaTime;
|
||||
@ -3685,19 +3686,18 @@ void ImGui::Initialize(ImGuiContext* context)
|
||||
// This function is merely here to free heap allocations.
|
||||
void ImGui::Shutdown(ImGuiContext* context)
|
||||
{
|
||||
ImGuiContext& g = *context;
|
||||
|
||||
// The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
|
||||
ImGuiContext& g = *context;
|
||||
if (g.IO.Fonts && g.FontAtlasOwnedByContext)
|
||||
IM_DELETE(g.IO.Fonts);
|
||||
g.IO.Fonts = NULL;
|
||||
|
||||
// Cleanup of other data are conditional on actually having initialize ImGui.
|
||||
// Cleanup of other data are conditional on actually having initialized ImGui.
|
||||
if (!g.Initialized)
|
||||
return;
|
||||
|
||||
// Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
|
||||
if (g.SettingsLoaded)
|
||||
if (g.SettingsLoaded && g.IO.IniFilename != NULL)
|
||||
SaveIniSettingsToDisk(g.IO.IniFilename);
|
||||
|
||||
// Clear everything else
|
||||
@ -3759,14 +3759,13 @@ static ImGuiWindowSettings* AddWindowSettings(const char* name)
|
||||
return settings;
|
||||
}
|
||||
|
||||
static void LoadIniSettingsFromDisk(const char* ini_filename)
|
||||
void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
|
||||
{
|
||||
if (!ini_filename)
|
||||
return;
|
||||
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", NULL, +1);
|
||||
size_t file_data_size = 0;
|
||||
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
|
||||
if (!file_data)
|
||||
return;
|
||||
LoadIniSettingsFromMemory(file_data);
|
||||
LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
|
||||
ImGui::MemFree(file_data);
|
||||
}
|
||||
|
||||
@ -3781,13 +3780,21 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
|
||||
}
|
||||
|
||||
// Zero-tolerance, no error reporting, cheap .ini parsing
|
||||
static void LoadIniSettingsFromMemory(const char* buf_readonly)
|
||||
void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
|
||||
{
|
||||
// For convenience and to make the code simpler, we'll write zero terminators inside the buffer. So let's create a writable copy.
|
||||
char* buf = ImStrdup(buf_readonly);
|
||||
char* buf_end = buf + strlen(buf);
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.Initialized);
|
||||
IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
|
||||
|
||||
// For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
|
||||
// For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
|
||||
if (ini_size == 0)
|
||||
ini_size = strlen(ini_data);
|
||||
char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
|
||||
char* buf_end = buf + ini_size;
|
||||
memcpy(buf, ini_data, ini_size);
|
||||
buf[ini_size] = 0;
|
||||
|
||||
void* entry_data = NULL;
|
||||
ImGuiSettingsHandler* entry_handler = NULL;
|
||||
|
||||
@ -3820,7 +3827,7 @@ static void LoadIniSettingsFromMemory(const char* buf_readonly)
|
||||
*type_end = 0; // Overwrite first ']'
|
||||
name_start++; // Skip second '['
|
||||
}
|
||||
entry_handler = ImGui::FindSettingsHandler(type_start);
|
||||
entry_handler = FindSettingsHandler(type_start);
|
||||
entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
|
||||
}
|
||||
else if (entry_handler != NULL && entry_data != NULL)
|
||||
@ -3833,37 +3840,37 @@ static void LoadIniSettingsFromMemory(const char* buf_readonly)
|
||||
g.SettingsLoaded = true;
|
||||
}
|
||||
|
||||
static void SaveIniSettingsToDisk(const char* ini_filename)
|
||||
void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.SettingsDirtyTimer = 0.0f;
|
||||
if (!ini_filename)
|
||||
return;
|
||||
|
||||
ImVector<char> buf;
|
||||
SaveIniSettingsToMemory(buf);
|
||||
|
||||
size_t ini_data_size = 0;
|
||||
const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
|
||||
FILE* f = ImFileOpen(ini_filename, "wt");
|
||||
if (!f)
|
||||
return;
|
||||
fwrite(buf.Data, sizeof(char), (size_t)buf.Size, f);
|
||||
fwrite(ini_data, sizeof(char), ini_data_size, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void SaveIniSettingsToMemory(ImVector<char>& out_buf)
|
||||
// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
|
||||
const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.SettingsDirtyTimer = 0.0f;
|
||||
|
||||
ImGuiTextBuffer buf;
|
||||
g.SettingsIniData.Buf.resize(0);
|
||||
g.SettingsIniData.Buf.push_back(0);
|
||||
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
|
||||
{
|
||||
ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
|
||||
handler->WriteAllFn(&g, handler, &buf);
|
||||
handler->WriteAllFn(&g, handler, &g.SettingsIniData);
|
||||
}
|
||||
|
||||
buf.Buf.pop_back(); // Remove extra zero-terminator used by ImGuiTextBuffer
|
||||
out_buf.swap(buf.Buf);
|
||||
if (out_size)
|
||||
*out_size = (size_t)g.SettingsIniData.size();
|
||||
return g.SettingsIniData.c_str();
|
||||
}
|
||||
|
||||
void ImGui::MarkIniSettingsDirty()
|
||||
@ -3873,7 +3880,7 @@ void ImGui::MarkIniSettingsDirty()
|
||||
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
||||
}
|
||||
|
||||
static void MarkIniSettingsDirty(ImGuiWindow* window)
|
||||
void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
|
||||
|
14
imgui.h
14
imgui.h
@ -542,6 +542,13 @@ namespace ImGui
|
||||
IMGUI_API const char* GetClipboardText();
|
||||
IMGUI_API void SetClipboardText(const char* text);
|
||||
|
||||
// Settings/.Ini Utilities
|
||||
// The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). Set io.IniFilename to NULL to load/save manually.
|
||||
IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
|
||||
IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
|
||||
IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename);
|
||||
IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean.
|
||||
|
||||
// Memory Utilities
|
||||
// All those functions are not reliant on the current context.
|
||||
// If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again.
|
||||
@ -1001,11 +1008,11 @@ struct ImGuiIO
|
||||
//------------------------------------------------------------------
|
||||
|
||||
ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
|
||||
ImGuiBackendFlags BackendFlags; // = 0 // Set ImGuiBackendFlags_ enum. Set by imgui_impl_xxx files or custom back-end.
|
||||
ImGuiBackendFlags BackendFlags; // = 0 // Set ImGuiBackendFlags_ enum. Set by imgui_impl_xxx files or custom back-end to communicate features supported by the back-end.
|
||||
ImVec2 DisplaySize; // <unset> // Display size, in pixels. For clamping windows positions.
|
||||
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
|
||||
float IniSavingRate; // = 5.0f // Maximum time between saving positions/sizes to .ini file, in seconds.
|
||||
const char* IniFilename; // = "imgui.ini" // Path to .ini file. NULL to disable .ini saving.
|
||||
float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds.
|
||||
const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
|
||||
const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
|
||||
float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
|
||||
float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
|
||||
@ -1081,6 +1088,7 @@ struct ImGuiIO
|
||||
bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).
|
||||
bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).
|
||||
bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.
|
||||
bool WantSaveIniSettings; // If io.IniFilename == NULL, this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself.
|
||||
bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
|
||||
bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
|
||||
float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames
|
||||
|
@ -1541,7 +1541,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
|
||||
|
||||
ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
|
||||
{
|
||||
int data_size = 0;
|
||||
size_t data_size = 0;
|
||||
void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
|
||||
if (!data)
|
||||
{
|
||||
@ -1556,7 +1556,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
|
||||
for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
|
||||
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
|
||||
}
|
||||
return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
|
||||
return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
|
||||
}
|
||||
|
||||
// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
|
||||
|
@ -96,7 +96,7 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons
|
||||
|
||||
// Helpers: Misc
|
||||
IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings
|
||||
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0);
|
||||
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0);
|
||||
IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode);
|
||||
static inline bool ImCharIsSpace(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
|
||||
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
@ -676,9 +676,10 @@ struct ImGuiContext
|
||||
|
||||
// Settings
|
||||
bool SettingsLoaded;
|
||||
float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero
|
||||
ImVector<ImGuiWindowSettings> SettingsWindows; // .ini settings for ImGuiWindow
|
||||
float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
|
||||
ImGuiTextBuffer SettingsIniData; // In memory .ini settings
|
||||
ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
|
||||
ImVector<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries (parsed from the last loaded .ini file and maintained on saving)
|
||||
|
||||
// Logging
|
||||
bool LogEnabled;
|
||||
@ -1022,6 +1023,7 @@ namespace ImGui
|
||||
IMGUI_API void NewFrameUpdateHoveredWindowAndCaptureFlags();
|
||||
|
||||
IMGUI_API void MarkIniSettingsDirty();
|
||||
IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window);
|
||||
IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);
|
||||
IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user