mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 04:31:06 +01:00 
			
		
		
		
	Settings: Added LoadIniSettingsFromDisk(), LoadIniSettingsFromMemory(), SaveIniSettingsToDisk(), SaveIniSettingsToMemory(), io.WantSaveIniSettings. (#923, #993)
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										87
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								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()); | ||||
|         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) | ||||
|         { | ||||
|             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); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user