From 2546d0a0dbe4a5088b5d5627e12760bb2cb50f84 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 19 Jul 2024 12:35:57 +0200 Subject: [PATCH 001/136] Demo: moved ExampleTreeNode, ExampleMemberInfo above in the demo file. Tidying up index. + change ExampleTreeNode::UID from ImGuiID to int to not suggest that the user ID needs to be of a certain type --- docs/CHANGELOG.txt | 2 +- imgui_demo.cpp | 213 ++++++++++++++++++++++++--------------------- 2 files changed, 116 insertions(+), 99 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ab1f0d806..9d919b6b9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,7 +77,7 @@ Other changes: Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). (#1379, #1468, #2200, #4936, #5216, #7302, #7573) - This was mostly all previously in imgui_internal.h. -- Multi-Select: added multi-select API and demos. (#1861) +- Multi-Select: added multi-select API and demos. (#1861, #6518) - This system implements standard multi-selection idioms (CTRL+mouse click, CTRL+keyboard moves, SHIFT+mouse click, SHIFT+keyboard moves, etc.) with support for clipper (not submitting non-visible items), box-selection with scrolling, and many other details. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 88ccce1f0..b31443141 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -11,7 +11,7 @@ // Get the latest version at https://github.com/ocornut/imgui // How to easily locate code? -// - Use the Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools +// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools // - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html // - Find a visible string and search for it in the code! @@ -62,6 +62,7 @@ // - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. // - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. +// - You can search/grep for all sections listed in the index to find the section. /* @@ -69,14 +70,14 @@ Index of this file: // [SECTION] Forward Declarations // [SECTION] Helpers +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] Demo Window / ShowDemoWindow() -// - ShowDemoWindow() -// - sub section: ShowDemoWindowWidgets() -// - sub section: ShowDemoWindowMultiSelect() -// - sub section: ShowDemoWindowLayout() -// - sub section: ShowDemoWindowPopups() -// - sub section: ShowDemoWindowTables() -// - sub section: ShowDemoWindowInputs() +// [SECTION] ShowDemoWindowWidgets() +// [SECTION] ShowDemoWindowMultiSelect() +// [SECTION] ShowDemoWindowLayout() +// [SECTION] ShowDemoWindowPopups() +// [SECTION] ShowDemoWindowTables() +// [SECTION] ShowDemoWindowInputs() // [SECTION] About Window / ShowAboutWindow() // [SECTION] Style Editor / ShowStyleEditor() // [SECTION] User Guide / ShowUserGuide() @@ -84,7 +85,6 @@ Index of this file: // [SECTION] Example App: Debug Console / ShowExampleAppConsole() // [SECTION] Example App: Debug Log / ShowExampleAppLog() // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() -// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.) // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() // [SECTION] Example App: Long Text / ShowExampleAppLongText() // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() @@ -192,7 +192,7 @@ Index of this file: #endif //----------------------------------------------------------------------------- -// [SECTION] Forward Declarations, Helpers +// [SECTION] Forward Declarations //----------------------------------------------------------------------------- #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) @@ -215,7 +215,7 @@ static void ShowExampleAppWindowTitles(bool* p_open); static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions -// (because the link time of very large functions grow non-linearly) +// (because the link time of very large functions tends to grow non-linearly) static void ShowDemoWindowWidgets(); static void ShowDemoWindowMultiSelect(); static void ShowDemoWindowLayout(); @@ -251,16 +251,85 @@ void* GImGuiDemoMarkerCallbackUserData = NULL; #define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) //----------------------------------------------------------------------------- -// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.) //----------------------------------------------------------------------------- -// - ShowDemoWindow() -// - ShowDemoWindowWidgets() -// - ShowDemoWindowMultiSelect() -// - ShowDemoWindowLayout() -// - ShowDemoWindowPopups() -// - ShowDemoWindowTables() -// - ShowDemoWindowColumns() -// - ShowDemoWindowInputs() + +// Simple representation for a tree +// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.) +struct ExampleTreeNode +{ + // Tree structure + char Name[28]; + int UID = 0; + ExampleTreeNode* Parent = NULL; + ImVector Childs; + + // Leaf Data + bool HasData = false; // All leaves have data + bool DataMyBool = false; + int DataMyInt = 128; + ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); +}; + +// Simple representation of struct metadata/serialization data. +// (this is a minimal version of what a typical advanced application may provide) +struct ExampleMemberInfo +{ + const char* Name; // Member name + ImGuiDataType DataType; // Member type + int DataCount; // Member count (1 when scalar) + int Offset; // Offset inside parent structure +}; + +// Metadata description of ExampleTreeNode struct. +static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] +{ + { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, + { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, + { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, +}; + +static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent) +{ + ExampleTreeNode* node = IM_NEW(ExampleTreeNode); + snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); + node->UID = uid; + node->Parent = parent; + if (parent) + parent->Childs.push_back(node); + return node; +} + +// Create example tree data +static ExampleTreeNode* ExampleTree_CreateDemoTree() +{ + static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + char name_buf[32]; + int uid = 0; + ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); + for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * 2; idx_L0++) + { + snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / 2], idx_L0 % 2); + ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); + const int number_of_childs = (int)strlen(node_L1->Name); + for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) + { + snprintf(name_buf, 32, "Child %d", idx_L1); + ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); + node_L2->HasData = true; + if (idx_L1 == 0) + { + snprintf(name_buf, 32, "Sub-child %d", 0); + ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); + node_L3->HasData = true; + } + } + } + return node_L0; +} + +//----------------------------------------------------------------------------- +// [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- // Demonstrate most Dear ImGui features (this is big function!) @@ -610,6 +679,10 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::End(); } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowWidgets() +//----------------------------------------------------------------------------- + static void ShowDemoWindowWidgets() { IMGUI_DEMO_MARKER("Widgets"); @@ -2991,8 +3064,13 @@ struct ExampleDualListBox } }; +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowMultiSelect() +//----------------------------------------------------------------------------- // Multi-selection demos // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select +//----------------------------------------------------------------------------- + static void ShowDemoWindowMultiSelect() { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); @@ -3525,6 +3603,10 @@ static void ShowDemoWindowMultiSelect() } } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowLayout() +//----------------------------------------------------------------------------- + static void ShowDemoWindowLayout() { IMGUI_DEMO_MARKER("Layout"); @@ -4384,6 +4466,10 @@ static void ShowDemoWindowLayout() } } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowPopups() +//----------------------------------------------------------------------------- + static void ShowDemoWindowPopups() { IMGUI_DEMO_MARKER("Popups"); @@ -4844,6 +4930,10 @@ static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered); } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowTables() +//----------------------------------------------------------------------------- + static void ShowDemoWindowTables() { //ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -6937,6 +7027,10 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowInputs() +//----------------------------------------------------------------------------- + static void ShowDemoWindowInputs() { IMGUI_DEMO_MARKER("Inputs & Focus"); @@ -8484,83 +8578,6 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::End(); } -//----------------------------------------------------------------------------- -// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.) -//----------------------------------------------------------------------------- - -// Simple representation for a tree -// (this is designed to be simple to understand for our demos, not to be efficient etc.) -struct ExampleTreeNode -{ - char Name[28]; - ImGuiID UID = 0; - ExampleTreeNode* Parent = NULL; - ImVector Childs; - - // Data - bool HasData = false; // All leaves have data - bool DataIsEnabled = false; - int DataInt = 128; - ImVec2 DataVec2 = ImVec2(0.0f, 3.141592f); -}; - -// Simple representation of struct metadata/serialization data. -// (this is a minimal version of what a typical advanced application may provide) -struct ExampleMemberInfo -{ - const char* Name; - ImGuiDataType DataType; - int DataCount; - int Offset; -}; - -// Metadata description of ExampleTreeNode struct. -static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] -{ - { "Enabled", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataIsEnabled) }, - { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataInt) }, - { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataVec2) }, -}; - -static ExampleTreeNode* ExampleTree_CreateNode(const char* name, const ImGuiID uid, ExampleTreeNode* parent) -{ - ExampleTreeNode* node = IM_NEW(ExampleTreeNode); - snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); - node->UID = uid; - node->Parent = parent; - if (parent) - parent->Childs.push_back(node); - return node; -} - -// Create example tree data -static ExampleTreeNode* ExampleTree_CreateDemoTree() -{ - static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; - char name_buf[32]; - ImGuiID uid = 0; - ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); - for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * 2; idx_L0++) - { - snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / 2], idx_L0 % 2); - ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); - const int number_of_childs = (int)strlen(node_L1->Name); - for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) - { - snprintf(name_buf, 32, "Child %d", idx_L1); - ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); - node_L2->HasData = true; - if (idx_L1 == 0) - { - snprintf(name_buf, 32, "Sub-child %d", 0); - ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); - node_L3->HasData = true; - } - } - } - return node_L0; -} - //----------------------------------------------------------------------------- // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() //----------------------------------------------------------------------------- @@ -8601,7 +8618,7 @@ struct ExampleAppPropertyEditor void DrawTreeNode(ExampleTreeNode* node) { // Object tree node - ImGui::PushID((int)node->UID); + ImGui::PushID(node->UID); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::AlignTextToFramePadding(); From 57eea6746e6bee19a308ba9dac1764bbf052714e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 19 Jul 2024 15:34:48 +0200 Subject: [PATCH 002/136] Demo: moved some fields inside a struct. --- imgui_demo.cpp | 150 +++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 72 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b31443141..7d0cf5ee8 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -216,8 +216,9 @@ static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) -static void ShowDemoWindowWidgets(); -static void ShowDemoWindowMultiSelect(); +struct DemoWindowData; +static void ShowDemoWindowWidgets(DemoWindowData* demo_data); +static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data); static void ShowDemoWindowLayout(); static void ShowDemoWindowPopups(); static void ShowDemoWindowTables(); @@ -332,6 +333,32 @@ static ExampleTreeNode* ExampleTree_CreateDemoTree() // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- +struct DemoWindowData +{ + // Examples Apps (accessible from the "Examples" menu) + bool ShowMainMenuBar = false; + bool ShowAppAssetsBrowser = false; + bool ShowAppConsole = false; + bool ShowAppCustomRendering = false; + bool ShowAppDocuments = false; + bool ShowAppLog = false; + bool ShowAppLayout = false; + bool ShowAppPropertyEditor = false; + bool ShowAppSimpleOverlay = false; + bool ShowAppAutoResize = false; + bool ShowAppConstrainedResize = false; + bool ShowAppFullscreen = false; + bool ShowAppLongText = false; + bool ShowAppWindowTitles = false; + + // Dear ImGui Tools (accessible from the "Tools" menu) + bool ShowMetrics = false; + bool ShowDebugLog = false; + bool ShowIDStackTool = false; + bool ShowStyleEditor = false; + bool ShowAbout = false; +}; + // Demonstrate most Dear ImGui features (this is big function!) // You may execute this function to experiment with the UI and understand what it does. // You may then search for keywords in the code when you are interested by a specific feature. @@ -344,58 +371,36 @@ void ImGui::ShowDemoWindow(bool* p_open) // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. IMGUI_CHECKVERSION(); - // Examples Apps (accessible from the "Examples" menu) - static bool show_app_main_menu_bar = false; - static bool show_app_assets_browser = false; - static bool show_app_console = false; - static bool show_app_custom_rendering = false; - static bool show_app_documents = false; - static bool show_app_log = false; - static bool show_app_layout = false; - static bool show_app_property_editor = false; - static bool show_app_simple_overlay = false; - static bool show_app_auto_resize = false; - static bool show_app_constrained_resize = false; - static bool show_app_fullscreen = false; - static bool show_app_long_text = false; - static bool show_app_window_titles = false; + // Stored data + static DemoWindowData demo; - if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); - if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); - if (show_app_assets_browser) ShowExampleAppAssetsBrowser(&show_app_assets_browser); - if (show_app_console) ShowExampleAppConsole(&show_app_console); - if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); - if (show_app_log) ShowExampleAppLog(&show_app_log); - if (show_app_layout) ShowExampleAppLayout(&show_app_layout); - if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); - if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); - if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); - if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); - if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); - if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); - if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); + // Examples Apps (accessible from the "Examples" menu) + if (demo.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } + if (demo.ShowAppDocuments) { ShowExampleAppDocuments(&demo.ShowAppDocuments); } + if (demo.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo.ShowAppAssetsBrowser); } + if (demo.ShowAppConsole) { ShowExampleAppConsole(&demo.ShowAppConsole); } + if (demo.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo.ShowAppCustomRendering); } + if (demo.ShowAppLog) { ShowExampleAppLog(&demo.ShowAppLog); } + if (demo.ShowAppLayout) { ShowExampleAppLayout(&demo.ShowAppLayout); } + if (demo.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo.ShowAppPropertyEditor); } + if (demo.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo.ShowAppSimpleOverlay); } + if (demo.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo.ShowAppAutoResize); } + if (demo.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo.ShowAppConstrainedResize); } + if (demo.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo.ShowAppFullscreen); } + if (demo.ShowAppLongText) { ShowExampleAppLongText(&demo.ShowAppLongText); } + if (demo.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo.ShowAppWindowTitles); } // Dear ImGui Tools (accessible from the "Tools" menu) - static bool show_tool_metrics = false; - static bool show_tool_debug_log = false; - static bool show_tool_id_stack_tool = false; - static bool show_tool_style_editor = false; - static bool show_tool_about = false; - - if (show_tool_metrics) - ImGui::ShowMetricsWindow(&show_tool_metrics); - if (show_tool_debug_log) - ImGui::ShowDebugLogWindow(&show_tool_debug_log); - if (show_tool_id_stack_tool) - ImGui::ShowIDStackToolWindow(&show_tool_id_stack_tool); - if (show_tool_style_editor) + if (demo.ShowMetrics) { ImGui::ShowMetricsWindow(&demo.ShowMetrics); } + if (demo.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo.ShowDebugLog); } + if (demo.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo.ShowIDStackTool); } + if (demo.ShowAbout) { ImGui::ShowAboutWindow(&demo.ShowAbout); } + if (demo.ShowStyleEditor) { - ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor); + ImGui::Begin("Dear ImGui Style Editor", &demo.ShowStyleEditor); ImGui::ShowStyleEditor(); ImGui::End(); } - if (show_tool_about) - ImGui::ShowAboutWindow(&show_tool_about); // Demonstrate the various window flags. Typically you would just use the default! static bool no_titlebar = false; @@ -455,24 +460,24 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::BeginMenu("Examples")) { IMGUI_DEMO_MARKER("Menu/Examples"); - ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); + ImGui::MenuItem("Main menu bar", NULL, &demo.ShowMainMenuBar); ImGui::SeparatorText("Mini apps"); - ImGui::MenuItem("Assets Browser", NULL, &show_app_assets_browser); - ImGui::MenuItem("Console", NULL, &show_app_console); - ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); - ImGui::MenuItem("Documents", NULL, &show_app_documents); - ImGui::MenuItem("Log", NULL, &show_app_log); - ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); - ImGui::MenuItem("Simple layout", NULL, &show_app_layout); - ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Assets Browser", NULL, &demo.ShowAppAssetsBrowser); + ImGui::MenuItem("Console", NULL, &demo.ShowAppConsole); + ImGui::MenuItem("Custom rendering", NULL, &demo.ShowAppCustomRendering); + ImGui::MenuItem("Documents", NULL, &demo.ShowAppDocuments); + ImGui::MenuItem("Log", NULL, &demo.ShowAppLog); + ImGui::MenuItem("Property editor", NULL, &demo.ShowAppPropertyEditor); + ImGui::MenuItem("Simple layout", NULL, &demo.ShowAppLayout); + ImGui::MenuItem("Simple overlay", NULL, &demo.ShowAppSimpleOverlay); ImGui::SeparatorText("Concepts"); - ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); - ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); - ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); - ImGui::MenuItem("Long text display", NULL, &show_app_long_text); - ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); + ImGui::MenuItem("Auto-resizing window", NULL, &demo.ShowAppAutoResize); + ImGui::MenuItem("Constrained-resizing window", NULL, &demo.ShowAppConstrainedResize); + ImGui::MenuItem("Fullscreen window", NULL, &demo.ShowAppFullscreen); + ImGui::MenuItem("Long text display", NULL, &demo.ShowAppLongText); + ImGui::MenuItem("Manipulating window titles", NULL, &demo.ShowAppWindowTitles); ImGui::EndMenu(); } @@ -485,17 +490,17 @@ void ImGui::ShowDemoWindow(bool* p_open) #else const bool has_debug_tools = false; #endif - ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools); - ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools); - ImGui::MenuItem("ID Stack Tool", NULL, &show_tool_id_stack_tool, has_debug_tools); - ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor); + ImGui::MenuItem("Metrics/Debugger", NULL, &demo.ShowMetrics, has_debug_tools); + ImGui::MenuItem("Debug Log", NULL, &demo.ShowDebugLog, has_debug_tools); + ImGui::MenuItem("ID Stack Tool", NULL, &demo.ShowIDStackTool, has_debug_tools); + ImGui::MenuItem("Style Editor", NULL, &demo.ShowStyleEditor); bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent; if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) ImGui::DebugStartItemPicker(); if (!is_debugger_present) ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); ImGui::Separator(); - ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about); + ImGui::MenuItem("About Dear ImGui", NULL, &demo.ShowAbout); ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -620,7 +625,7 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Configuration/Style"); if (ImGui::TreeNode("Style")) { - ImGui::Checkbox("Style Editor", &show_tool_style_editor); + ImGui::Checkbox("Style Editor", &demo.ShowStyleEditor); ImGui::SameLine(); HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::TreePop(); @@ -668,7 +673,7 @@ void ImGui::ShowDemoWindow(bool* p_open) } // All demo contents - ShowDemoWindowWidgets(); + ShowDemoWindowWidgets(&demo); ShowDemoWindowLayout(); ShowDemoWindowPopups(); ShowDemoWindowTables(); @@ -683,7 +688,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // [SECTION] ShowDemoWindowWidgets() //----------------------------------------------------------------------------- -static void ShowDemoWindowWidgets() +static void ShowDemoWindowWidgets(DemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets"); //ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -1561,7 +1566,7 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } - ShowDemoWindowMultiSelect(); + ShowDemoWindowMultiSelect(demo_data); // To wire InputText() with std::string or any other custom string type, // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. @@ -3071,7 +3076,7 @@ struct ExampleDualListBox // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- -static void ShowDemoWindowMultiSelect() +static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) @@ -3366,7 +3371,8 @@ static void ShowDemoWindowMultiSelect() // See ShowExampleAppAssetsBrowser() if (ImGui::TreeNode("Multi-Select (tiled assets browser)")) { - ImGui::BulletText("See 'Examples->Assets Browser' in menu"); + ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser); + ImGui::Text("(also access from 'Examples->Assets Browser' in menu)"); ImGui::TreePop(); } From 168ef39984c735ee954750ed0765c70c9fcf841b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 19 Jul 2024 15:46:51 +0200 Subject: [PATCH 003/136] Demo: moved menu bar code to its own function. --- imgui_demo.cpp | 130 ++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7d0cf5ee8..fb28e3d54 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -72,6 +72,7 @@ Index of this file: // [SECTION] Helpers // [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] ShowDemoWindowMenuBar() // [SECTION] ShowDemoWindowWidgets() // [SECTION] ShowDemoWindowMultiSelect() // [SECTION] ShowDemoWindowLayout() @@ -217,6 +218,7 @@ static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) struct DemoWindowData; +static void ShowDemoWindowMenuBar(DemoWindowData* demo_data); static void ShowDemoWindowWidgets(DemoWindowData* demo_data); static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data); static void ShowDemoWindowLayout(); @@ -443,68 +445,11 @@ void ImGui::ShowDemoWindow(bool* p_open) } // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. - // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) - //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); - // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. - ImGui::PushItemWidth(ImGui::GetFontSize() * -12); + ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. + //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) // Menu Bar - if (ImGui::BeginMenuBar()) - { - if (ImGui::BeginMenu("Menu")) - { - IMGUI_DEMO_MARKER("Menu/File"); - ShowExampleMenuFile(); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Examples")) - { - IMGUI_DEMO_MARKER("Menu/Examples"); - ImGui::MenuItem("Main menu bar", NULL, &demo.ShowMainMenuBar); - - ImGui::SeparatorText("Mini apps"); - ImGui::MenuItem("Assets Browser", NULL, &demo.ShowAppAssetsBrowser); - ImGui::MenuItem("Console", NULL, &demo.ShowAppConsole); - ImGui::MenuItem("Custom rendering", NULL, &demo.ShowAppCustomRendering); - ImGui::MenuItem("Documents", NULL, &demo.ShowAppDocuments); - ImGui::MenuItem("Log", NULL, &demo.ShowAppLog); - ImGui::MenuItem("Property editor", NULL, &demo.ShowAppPropertyEditor); - ImGui::MenuItem("Simple layout", NULL, &demo.ShowAppLayout); - ImGui::MenuItem("Simple overlay", NULL, &demo.ShowAppSimpleOverlay); - - ImGui::SeparatorText("Concepts"); - ImGui::MenuItem("Auto-resizing window", NULL, &demo.ShowAppAutoResize); - ImGui::MenuItem("Constrained-resizing window", NULL, &demo.ShowAppConstrainedResize); - ImGui::MenuItem("Fullscreen window", NULL, &demo.ShowAppFullscreen); - ImGui::MenuItem("Long text display", NULL, &demo.ShowAppLongText); - ImGui::MenuItem("Manipulating window titles", NULL, &demo.ShowAppWindowTitles); - - ImGui::EndMenu(); - } - //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! - if (ImGui::BeginMenu("Tools")) - { - IMGUI_DEMO_MARKER("Menu/Tools"); -#ifndef IMGUI_DISABLE_DEBUG_TOOLS - const bool has_debug_tools = true; -#else - const bool has_debug_tools = false; -#endif - ImGui::MenuItem("Metrics/Debugger", NULL, &demo.ShowMetrics, has_debug_tools); - ImGui::MenuItem("Debug Log", NULL, &demo.ShowDebugLog, has_debug_tools); - ImGui::MenuItem("ID Stack Tool", NULL, &demo.ShowIDStackTool, has_debug_tools); - ImGui::MenuItem("Style Editor", NULL, &demo.ShowStyleEditor); - bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent; - if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) - ImGui::DebugStartItemPicker(); - if (!is_debugger_present) - ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); - ImGui::Separator(); - ImGui::MenuItem("About Dear ImGui", NULL, &demo.ShowAbout); - ImGui::EndMenu(); - } - ImGui::EndMenuBar(); - } + ShowDemoWindowMenuBar(&demo); ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); @@ -684,6 +629,71 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::End(); } +//----------------------------------------------------------------------------- +// [SECTION] ShowDemoWindowMenuBar() +//----------------------------------------------------------------------------- + +static void ShowDemoWindowMenuBar(DemoWindowData* demo_data) +{ + IMGUI_DEMO_MARKER("Menu"); + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + IMGUI_DEMO_MARKER("Menu/File"); + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Examples")) + { + IMGUI_DEMO_MARKER("Menu/Examples"); + ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar); + + ImGui::SeparatorText("Mini apps"); + ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser); + ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole); + ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering); + ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments); + ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog); + ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor); + ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout); + ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay); + + ImGui::SeparatorText("Concepts"); + ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize); + ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize); + ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen); + ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText); + ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles); + + ImGui::EndMenu(); + } + //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! + if (ImGui::BeginMenu("Tools")) + { + IMGUI_DEMO_MARKER("Menu/Tools"); +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + const bool has_debug_tools = true; +#else + const bool has_debug_tools = false; +#endif + ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); + ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); + ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); + ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); + bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent; + if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) + ImGui::DebugStartItemPicker(); + if (!is_debugger_present) + ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); + ImGui::Separator(); + ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } +} + //----------------------------------------------------------------------------- // [SECTION] ShowDemoWindowWidgets() //----------------------------------------------------------------------------- From b6e313bc05db184a8cb2382227cddaaf2cb7f51d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 19 Jul 2024 16:42:06 +0200 Subject: [PATCH 004/136] MultiSelect: using ImGuiMultiSelectFlags_NoRangeSelect ensure never having to interpolate between two ImGuiSelectionUserData. --- imgui.h | 4 +++- imgui_widgets.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/imgui.h b/imgui.h index 5550f1106..87c5ba50e 100644 --- a/imgui.h +++ b/imgui.h @@ -2760,6 +2760,8 @@ struct ImColor // SetRange requests will give you two end-points and you will need to iterate/interpolate between them to update your selection. // - However it is perfectly possible to store a POINTER or another IDENTIFIER inside ImGuiSelectionUserData. // Our system never assume that you identify items by indices, it never attempts to interpolate between two values. +// - If you enable ImGuiMultiSelectFlags_NoRangeSelect then it is guaranteed that you will never have to interpolate +// between two ImGuiSelectionUserData, which may be a convenient way to use part of the feature with less code work. // - As most users will want to store an index, for convenience and to reduce confusion we use ImS64 instead of void*, // being syntactically easier to downcast. Feel free to reinterpret_cast and store a pointer inside. @@ -2769,7 +2771,7 @@ enum ImGuiMultiSelectFlags_ ImGuiMultiSelectFlags_None = 0, ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all. - ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). + ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests. ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes) ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes) ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 637295e7a..29635d3eb 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7680,9 +7680,10 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) { selected = !selected; ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, +1, item_data, item_data }; - ImGuiSelectionRequest* prev_req = (ms->IO.Requests.Size > 0) ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL; - if (prev_req && prev_req->Type == ImGuiSelectionRequestType_SetRange && prev_req->RangeLastItem == ms->BoxSelectLastitem && prev_req->Selected == selected) - prev_req->RangeLastItem = item_data; // Merge span into same request + // Merge continuous ranges (unless NoRangeSelect is set) + ImGuiSelectionRequest* prev = ms->IO.Requests.Size > 0 ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL; + if (prev && prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->BoxSelectLastitem && prev->Selected == selected && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) + prev->RangeLastItem = item_data; // Merge span into same request else ms->IO.Requests.push_back(req); } From f9cda1fa245b361a0e98428d88470eebaa187e5b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 19 Jul 2024 18:39:07 +0200 Subject: [PATCH 005/136] Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) --- docs/CHANGELOG.txt | 7 +++++++ imgui.cpp | 5 +++++ imgui.h | 10 +++++++++- imgui_internal.h | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9d919b6b9..2e620f79b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,13 @@ Other changes: Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). (#1379, #1468, #2200, #4936, #5216, #7302, #7573) - This was mostly all previously in imgui_internal.h. +- Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. This is a simplified version of a more + complete set of function available in imgui_internal.h. One common use-case for this is to allow + your items to disable standard inputs behaviors such as Tab or Alt handling, Mouse Wheel scrolling, + etc. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) + // Hovering or activating the button will disable mouse wheel default behavior to scroll + InvisibleButton(...); + SetItemKeyOwner(ImGuiKey_MouseWheelY); - Multi-Select: added multi-select API and demos. (#1861, #6518) - This system implements standard multi-selection idioms (CTRL+mouse click, CTRL+keyboard moves, SHIFT+mouse click, SHIFT+keyboard moves, etc.) with support for clipper (not submitting non-visible diff --git a/imgui.cpp b/imgui.cpp index 0fb4e34ca..6eb38f708 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9805,6 +9805,11 @@ void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags) } } +void ImGui::SetItemKeyOwner(ImGuiKey key) +{ + SetItemKeyOwner(key, ImGuiInputFlags_None); +} + // This is the only public API until we expose owner_id versions of the API as replacements. bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord) { diff --git a/imgui.h b/imgui.h index 87c5ba50e..6c49460e1 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.0 WIP" -#define IMGUI_VERSION_NUM 19096 +#define IMGUI_VERSION_NUM 19097 #define IMGUI_HAS_TABLE /* @@ -984,6 +984,14 @@ namespace ImGui IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); + // Inputs Utilities: Key/Input Ownership [BETA] + // - One common use case would be to allow your items to disable standard inputs behaviors such + // as Tab or Alt key handling, Mouse Wheel scrolling, etc. + // e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for scrolling. + // - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them. + // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. + IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. + // Inputs Utilities: Mouse specific // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. diff --git a/imgui_internal.h b/imgui_internal.h index b44d7b258..f2c5312ea 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3337,7 +3337,7 @@ namespace ImGui IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key); IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0); - IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. + IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id' inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } From eb72b5a8eeefd41e845dadbb4758e6f341f3f4a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Jul 2024 10:49:22 +0200 Subject: [PATCH 006/136] Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (#7807) --- backends/imgui_impl_sdl3.cpp | 6 +++--- docs/CHANGELOG.txt | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 5cd852599..05718d21c 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,7 +21,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() string ownership change. (#7801) +// 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) +// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) // 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) // 2024-07-02: Update for SDL3 api changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762). // 2024-07-01: Update for SDL3 api changes: SDL_SetTextInputRect() changed to SDL_SetTextInputArea(). @@ -639,7 +640,7 @@ static void ImGui_ImplSDL3_UpdateGamepads() { ImGui_ImplSDL3_CloseGamepads(); int sdl_gamepads_count = 0; - SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count); + const SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count); for (int n = 0; n < sdl_gamepads_count; n++) if (SDL_Gamepad* gamepad = SDL_OpenGamepad(sdl_gamepads[n])) { @@ -647,7 +648,6 @@ static void ImGui_ImplSDL3_UpdateGamepads() if (bd->GamepadMode == ImGui_ImplSDL3_GamepadMode_AutoFirst) break; } - SDL_free(sdl_gamepads); bd->WantUpdateGamepadsList = false; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2e620f79b..49206df8e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -148,7 +148,8 @@ Other changes: struct description data that a real application would want to use. - Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768, #4858, #2622) [@Aemony] -- Backends: SDL3: Update for API changes: SDL_GetClipboardText() string ownership change. (#7801) +- Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (#7807) +- Backends: SDL3: Update for API changes: SDL_GetClipboardText() memory ownership change. (#7801) - Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762) - Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) [@wermipls] - Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. From da3633632191d52f40d4dc26184c3cd9c2a0d0a7 Mon Sep 17 00:00:00 2001 From: Thomas Stehle Date: Mon, 22 Jul 2024 10:52:53 +0200 Subject: [PATCH 007/136] TabBar, Style: added style option for the size of the Tab-Bar Overline (#7804) Amend 21bda2e. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 ++++- imgui.h | 4 +++- imgui_demo.cpp | 2 ++ imgui_widgets.cpp | 4 ++-- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 49206df8e..22f2b5e22 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -139,6 +139,8 @@ Other changes: can use the clipper without knowing the amount of items beforehand. (#1311) In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration loop to position the layout cursor correctly. This is done automatically if provided a count to Begin(). +- TabBar, Style: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate + thickness of the horizontal line over selectable tabs. [@DctrNoob] - Style: close button and collapse/window-menu button hover highlight made rectangular instead of round. - Debug Tools: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) Debug log entries add a imgui frame counter prefix + are redirected to ShowDebugLogWindow() and diff --git a/imgui.cpp b/imgui.cpp index 6eb38f708..21b1cf14a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1269,12 +1269,13 @@ ImGuiStyle::ImGuiStyle() TabBorderSize = 0.0f; // Thickness of border around tabs. TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. + TabBarOverlineSize = 2.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees). TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText() + SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText() SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. @@ -1321,6 +1322,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImTrunc(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor); @@ -3274,6 +3276,7 @@ static const ImGuiDataVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize + { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign diff --git a/imgui.h b/imgui.h index 6c49460e1..993906a00 100644 --- a/imgui.h +++ b/imgui.h @@ -1711,6 +1711,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabBorderSize, // float TabBorderSize ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize + ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign @@ -2154,12 +2155,13 @@ struct ImGuiStyle float TabBorderSize; // Thickness of border around tabs. float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. + float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - float SeparatorTextBorderSize; // Thickkness of border in SeparatorText() + float SeparatorTextBorderSize; // Thickness of border in SeparatorText() ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fb28e3d54..e43bdc2b3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7633,6 +7633,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); + ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f"); + ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 29635d3eb..e41f2f3cd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -9917,13 +9917,13 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImDrawList* display_draw_list = window->DrawList; const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); TabItemBackground(display_draw_list, bb, flags, tab_col); - if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline)) + if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) { float x_offset = IM_TRUNC(0.4f * style.TabRounding); if (x_offset < 2.0f * g.CurrentDpiScale) x_offset = 0.0f; float y_offset = 1.0f * g.CurrentDpiScale; - display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), 2.0f * g.CurrentDpiScale); + display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), style.TabBarOverlineSize); } RenderNavHighlight(bb, id); From fd994943c2dd70978d3c89c98d03fe5124e6a503 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Jul 2024 11:05:46 +0200 Subject: [PATCH 008/136] Added a comment hinting at how to set IMGUI_API for shared librairies on e.g. Linux, macOS (#7806) --- imconfig.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imconfig.h b/imconfig.h index 62365fb9b..6e4c743d4 100644 --- a/imconfig.h +++ b/imconfig.h @@ -21,10 +21,11 @@ //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. -// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() -// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. -//#define IMGUI_API __declspec( dllexport ) -//#define IMGUI_API __declspec( dllimport ) +// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export +//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import +//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS From c3dca77a19722d7ec0d2f7dfc1238b5166af2d46 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Jul 2024 14:06:14 +0200 Subject: [PATCH 009/136] Demo: rework Property Editor. --- docs/CHANGELOG.txt | 3 +- imgui.cpp | 6 ++ imgui.h | 4 +- imgui_demo.cpp | 165 +++++++++++++++++++++++++-------------------- 4 files changed, 102 insertions(+), 76 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 22f2b5e22..aad367e50 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -98,8 +98,7 @@ Other changes: - A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app. - Documentation: - Wiki page https://github.com/ocornut/imgui/wiki/Multi-Select for API overview. - - Demo code. - - Headers are well commented. + - Demo code + headers are well commented. - Added BeginMultiSelect(), EndMultiSelect(), SetNextItemSelectionUserData(). - Added IsItemToggledSelection() for use if you need latest selection update during currnet iteration. - Added ImGuiMultiSelectIO and ImGuiSelectionRequest structures: diff --git a/imgui.cpp b/imgui.cpp index 21b1cf14a..c7b83d849 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15710,6 +15710,12 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + if (flags & ImGuiWindowFlags_ChildWindow) + BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags, + (window->ChildFlags & ImGuiChildFlags_Border) ? "Border " : "", + (window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "", + (window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "", + (window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : ""); BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); diff --git a/imgui.h b/imgui.h index 993906a00..0bf02b046 100644 --- a/imgui.h +++ b/imgui.h @@ -1090,7 +1090,7 @@ enum ImGuiWindowFlags_ // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. #endif }; @@ -1115,7 +1115,7 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. - ImGuiChildFlags_NavFlattened = 1 << 8, // Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. + ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. }; // Flags for ImGui::PushItemFlag() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e43bdc2b3..f91cc8532 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -269,7 +269,7 @@ struct ExampleTreeNode // Leaf Data bool HasData = false; // All leaves have data - bool DataMyBool = false; + bool DataMyBool = true; int DataMyInt = 128; ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); }; @@ -304,6 +304,7 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl } // Create example tree data +// (this allocates _many_ more times than most other code in either Dear ImGui or others demo) static ExampleTreeNode* ExampleTree_CreateDemoTree() { static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; @@ -8600,101 +8601,121 @@ static void ShowExampleAppLayout(bool* p_open) // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() //----------------------------------------------------------------------------- // Some of the interactions are a bit lack-luster: -// - We would want the table scrolling window to use NavFlattened. // - We would want pressing validating or leaving the filter to somehow restore focus. // - We may want more advanced filtering (child nodes) and clipper support: both will need extra work. +// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. //----------------------------------------------------------------------------- struct ExampleAppPropertyEditor { ImGuiTextFilter Filter; + ExampleTreeNode* VisibleNode = NULL; void Draw(ExampleTreeNode* root_node) { - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); - ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); - if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) - Filter.Build(); - ImGui::PopItemFlag(); - - ImGuiTableFlags table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg; - if (ImGui::BeginTable("##split", 2, table_flags)) + // Left side: draw tree + // - Currently using a table to benefit from RowBg feature + // - Using ImGuiChildFlags_NavFlattened exhibit a bug where clicking on root window decoration sets focus to root window + if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Border)) { - ImGui::TableSetupColumn("Object", ImGuiTableColumnFlags_WidthStretch, 1.0f); - ImGui::TableSetupColumn("Contents", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger - //ImGui::TableSetupScrollFreeze(0, 1); - //ImGui::TableHeadersRow(); + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); + ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) + Filter.Build(); + ImGui::PopItemFlag(); - for (ExampleTreeNode* node : root_node->Childs) - if (Filter.PassFilter(node->Name)) // Filter root node - DrawTreeNode(node); - ImGui::EndTable(); + if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg)) + { + for (ExampleTreeNode* node : root_node->Childs) + if (Filter.PassFilter(node->Name)) // Filter root node + DrawTreeNode(node); + ImGui::EndTable(); + } } + ImGui::EndChild(); + + // Right side: draw properties + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + if (ExampleTreeNode* node = VisibleNode) + { + ImGui::Text("%s", node->Name); + ImGui::TextDisabled("UID: 0x%08X", node->UID); + ImGui::Separator(); + if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) + { + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger + + if (node && node->HasData) + { + // In a typical application, the structure description would be derived from a data-driven system. + // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. + // - Limits and some details are hard-coded to simplify the demo. + for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) + { + ImGui::TableNextRow(); + ImGui::PushID(field_desc.Name); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(field_desc.Name); + ImGui::TableNextColumn(); + void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); + switch (field_desc.DataType) + { + case ImGuiDataType_Bool: + { + IM_ASSERT(field_desc.DataCount == 1); + ImGui::Checkbox("##Editor", (bool*)field_ptr); + break; + } + case ImGuiDataType_S32: + { + int v_min = INT_MIN, v_max = INT_MAX; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max); + break; + } + case ImGuiDataType_Float: + { + float v_min = 0.0f, v_max = 1.0f; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); + break; + } + } + ImGui::PopID(); + } + } + ImGui::EndTable(); + } + } + ImGui::EndGroup(); } void DrawTreeNode(ExampleTreeNode* node) { - // Object tree node - ImGui::PushID(node->UID); ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::AlignTextToFramePadding(); + ImGui::TableNextColumn(); + ImGui::PushID(node->UID); ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None; - tree_flags |= ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_AllowOverlap; // Highlight whole row for visibility tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support - bool node_open = ImGui::TreeNodeEx("##Object", tree_flags, "%s", node->Name); - ImGui::TableSetColumnIndex(1); - ImGui::TextDisabled("UID: 0x%08X", node->UID); - - // Display child and data + if (node == VisibleNode) + tree_flags |= ImGuiTreeNodeFlags_Selected; + if (node->Childs.Size == 0) + tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet; + if (node->DataMyBool == false) + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); + bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name); + if (node->DataMyBool == false) + ImGui::PopStyleColor(); + if (ImGui::IsItemFocused()) + VisibleNode = node; if (node_open) for (ExampleTreeNode* child : node->Childs) DrawTreeNode(child); - if (node_open && node->HasData) - { - // In a typical application, the structure description would be derived from a data-driven system. - // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. - // - Limits and some details are hard-coded to simplify the demo. - // - Text and Selectable are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the selectable lines equal high. - for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) - { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::AlignTextToFramePadding(); - ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop | ImGuiItemFlags_NoNav, true); - ImGui::Selectable(field_desc.Name, false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); - ImGui::PopItemFlag(); - ImGui::TableSetColumnIndex(1); - ImGui::PushID(field_desc.Name); - void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); - switch (field_desc.DataType) - { - case ImGuiDataType_Bool: - { - IM_ASSERT(field_desc.DataCount == 1); - ImGui::Checkbox("##Editor", (bool*)field_ptr); - break; - } - case ImGuiDataType_S32: - { - int v_min = INT_MIN, v_max = INT_MAX; - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max); - break; - } - case ImGuiDataType_Float: - { - float v_min = 0.0f, v_max = 1.0f; - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); - break; - } - } - ImGui::PopID(); - } - } if (node_open) ImGui::TreePop(); ImGui::PopID(); From 97ff9bd37038d2c00372eeb7438964e59cc53c7e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Jul 2024 15:04:25 +0200 Subject: [PATCH 010/136] Nav: fixed c licking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened. In essence, using ImGuiFocusRequestFlags_RestoreFocusedChild here is a way to reduce changes caused by FocusWindow(), but it could be done more neatly. See amended "nav_flattened" test. --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_widgets.cpp | 20 ++++++++++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aad367e50..150c2b609 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -134,6 +134,8 @@ Other changes: - Multi-Select (checkboxes) - Multi-Select (multiple scopes) - Multi-Select (advanced) +- Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when + within a child window using ImGuiChildFlags_NavFlattened. - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can can use the clipper without knowing the amount of items beforehand. (#1311) In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration diff --git a/imgui.h b/imgui.h index 0bf02b046..fd0768a22 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.0 WIP" -#define IMGUI_VERSION_NUM 19097 +#define IMGUI_VERSION_NUM 19098 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e41f2f3cd..9a63a59bf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -567,8 +567,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetActiveID(id, window); g.ActiveIdMouseButton = mouse_button_clicked; if (!(flags & ImGuiButtonFlags_NoNavFocus)) + { SetFocusID(id, window); - FocusWindow(window); + FocusWindow(window); + } + else + { + FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child + } } if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) { @@ -577,10 +583,16 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ClearActiveID(); else SetActiveID(id, window); // Hold on ID - if (!(flags & ImGuiButtonFlags_NoNavFocus)) - SetFocusID(id, window); g.ActiveIdMouseButton = mouse_button_clicked; - FocusWindow(window); + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + { + SetFocusID(id, window); + FocusWindow(window); + } + else + { + FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child + } } } if (flags & ImGuiButtonFlags_PressedOnRelease) From 605c8d711019dd6eb98e8e1fbfe1b844410dda52 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Jul 2024 15:05:15 +0200 Subject: [PATCH 011/136] Demo: Property Editor: using ImGuiChildFlags_NavFlattened now that a bug is fixed. Fixed static analyzer. --- imgui_demo.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f91cc8532..7a3cdf0f4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8615,8 +8615,7 @@ struct ExampleAppPropertyEditor { // Left side: draw tree // - Currently using a table to benefit from RowBg feature - // - Using ImGuiChildFlags_NavFlattened exhibit a bug where clicking on root window decoration sets focus to root window - if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Border)) + if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Border | ImGuiChildFlags_NavFlattened)) { ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); @@ -8648,8 +8647,7 @@ struct ExampleAppPropertyEditor { ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger - - if (node && node->HasData) + if (node->HasData) { // In a typical application, the structure description would be derived from a data-driven system. // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. @@ -8714,10 +8712,11 @@ struct ExampleAppPropertyEditor if (ImGui::IsItemFocused()) VisibleNode = node; if (node_open) + { for (ExampleTreeNode* child : node->Childs) DrawTreeNode(child); - if (node_open) ImGui::TreePop(); + } ImGui::PopID(); } }; From fe09ebbe0a1c8bb5f39f326658faa6bde75bb568 Mon Sep 17 00:00:00 2001 From: Cyao <94928179+cheyao@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:10:35 +0200 Subject: [PATCH 012/136] Backends: OpenGL3: Fixed unsupported option warning with apple clang (#7810) --- backends/imgui_impl_opengl3.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index bbe96c420..7087a7c57 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -124,6 +124,7 @@ // Clang/GCC warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: ignore unknown flags #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used From 4d8c56c8133511b467bcba6483bc75b5a63ab985 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 13:40:23 +0200 Subject: [PATCH 013/136] Internals, TreeNode: indent all render block into its own scope (aim is to add a is_visible test there later) --- imgui.cpp | 1 + imgui_widgets.cpp | 99 ++++++++++++++++++++++++----------------------- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c7b83d849..52fa2f16f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12048,6 +12048,7 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM { ImGuiContext& g = *GImGui; IM_ASSERT(g.NavWindow != NULL); + //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestSubmit: dir %c, window \"%s\"\n", "-WENS"[move_dir + 1], g.NavWindow->Name); if (move_flags & ImGuiNavMoveFlags_IsTabbing) move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9a63a59bf..70ff174c2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6410,6 +6410,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanTextWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); + // Compute open and multi-select states before ItemAdd() as it clear NextItem data. + bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. const float backup_clip_rect_min_x = window->ClipRect.Min.x; const float backup_clip_rect_max_x = window->ClipRect.Max.x; @@ -6418,18 +6421,14 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags window->ClipRect.Min.x = window->ParentWorkRect.Min.x; window->ClipRect.Max.x = window->ParentWorkRect.Max.x; } - - // Compute open and multi-select states before ItemAdd() as it clear NextItem data. - bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); - bool item_add = ItemAdd(interact_bb, id); - g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; - g.LastItemData.DisplayRect = frame_bb; - + const bool is_visible = ItemAdd(interact_bb, id); if (span_all_columns) { window->ClipRect.Min.x = backup_clip_rect_min_x; window->ClipRect.Max.x = backup_clip_rect_max_x; } + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + g.LastItemData.DisplayRect = frame_bb; // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled: // Store data for the current depth to allow returning to this node from any child item. @@ -6444,7 +6443,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags } const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; - if (!item_add) + if (!is_visible) { if (store_tree_node_stack_data && is_open) TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() @@ -6566,53 +6565,55 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; // Render - const ImU32 text_col = GetColorU32(ImGuiCol_Text); - ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact; - if (is_multi_select) - nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle - if (display_frame) { - // Framed type - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); - RenderNavHighlight(frame_bb, id, nav_highlight_flags); - if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); - else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); - else // Leaf without bullet, left-adjusted text - text_pos.x -= text_offset_x -padding.x; - if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) - frame_bb.Max.x -= g.FontSize + style.FramePadding.x; - if (g.LogEnabled) - LogSetNextTextDecoration("###", "###"); - } - else - { - // Unframed typed for tree nodes - if (hovered || selected) + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact; + if (is_multi_select) + nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle + if (display_frame) { + // Framed type const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + else // Leaf without bullet, left-adjusted text + text_pos.x -= text_offset_x - padding.x; + if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) + frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) + LogSetNextTextDecoration("###", "###"); } - RenderNavHighlight(frame_bb, id, nav_highlight_flags); - if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); - else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); - if (g.LogEnabled) - LogSetNextTextDecoration(">", NULL); + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogSetNextTextDecoration(">", NULL); + } + + if (span_all_columns) + TablePopBackgroundChannel(); + + // Label + if (display_frame) + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + else + RenderText(text_pos, label, label_end, false); } - if (span_all_columns) - TablePopBackgroundChannel(); - - // Label - if (display_frame) - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - else - RenderText(text_pos, label, label_end, false); - if (store_tree_node_stack_data && is_open) TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) From 1230b4410cd0e0111dd85f7c20e2606208dc1a99 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 14:11:26 +0200 Subject: [PATCH 014/136] Internals, TreeNode, Selectable: tweak span_all_columns paths for clarity. --- imgui_widgets.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 70ff174c2..c01a89460 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6413,20 +6413,22 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags // Compute open and multi-select states before ItemAdd() as it clear NextItem data. bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. - const float backup_clip_rect_min_x = window->ClipRect.Min.x; - const float backup_clip_rect_max_x = window->ClipRect.Max.x; + bool is_visible; if (span_all_columns) { + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; window->ClipRect.Max.x = window->ParentWorkRect.Max.x; - } - const bool is_visible = ItemAdd(interact_bb, id); - if (span_all_columns) - { + is_visible = ItemAdd(interact_bb, id); window->ClipRect.Min.x = backup_clip_rect_min_x; window->ClipRect.Max.x = backup_clip_rect_max_x; } + else + { + is_visible = ItemAdd(interact_bb, id); + } g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; g.LastItemData.DisplayRect = frame_bb; @@ -6796,23 +6798,24 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. - const float backup_clip_rect_min_x = window->ClipRect.Min.x; - const float backup_clip_rect_max_x = window->ClipRect.Max.x; + const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; + const ImGuiItemFlags extra_item_flags = disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None; + bool is_visible; if (span_all_columns) { + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; window->ClipRect.Max.x = window->ParentWorkRect.Max.x; - } - - const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; - const bool is_visible = ItemAdd(bb, id, NULL, disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None); - - if (span_all_columns) - { + is_visible = ItemAdd(bb, id, NULL, extra_item_flags); window->ClipRect.Min.x = backup_clip_rect_min_x; window->ClipRect.Max.x = backup_clip_rect_max_x; } + else + { + is_visible = ItemAdd(bb, id, NULL, extra_item_flags); + } const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) From 97c6f4047ccc01367e29f6852e9cecf1e157d26b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 14:16:41 +0200 Subject: [PATCH 015/136] CollapsingHeader: left-side outer extend matches right-side one (moved left by one pixel) Amend c3a348aa2 --- imgui_widgets.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c01a89460..068337e9c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6396,10 +6396,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags frame_bb.Max.y = window->DC.CursorPos.y + frame_height; if (display_frame) { - // Framed header expand a little outside the default padding, to the edge of InnerClipRect - // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f) - frame_bb.Min.x -= IM_TRUNC(window->WindowPadding.x * 0.5f - 1.0f); - frame_bb.Max.x += IM_TRUNC(window->WindowPadding.x * 0.5f); + const float outer_extend = IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits + frame_bb.Min.x -= outer_extend; + frame_bb.Max.x += outer_extend; } ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); @@ -6783,7 +6782,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl const ImVec2 text_max(min_x + size.x, pos.y + size.y); // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. - // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currenty doesn't allow offsetting CursorPos. + // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos. ImRect bb(min_x, pos.y, text_max.x, text_max.y); if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { From b67b375ae693072ba23963f7897057e76f3a7327 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 15:28:03 +0200 Subject: [PATCH 016/136] Debug Log: fixed incorrect checkbox layout when partially clipped., doesn't parse 64-bits hex value as ImGuiID lookups. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 4 ++-- imgui_internal.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 150c2b609..1247ef94a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -147,6 +147,7 @@ Other changes: Debug log entries add a imgui frame counter prefix + are redirected to ShowDebugLogWindow() and other configurable locations. Always call IMGUI_DEBUG_LOG() for maximum stripping in caller code. - Debug Tools: Debug Log: Added "Configure Outputs.." button. (#5855) +- Debug Tools: Debug Log: Fixed incorrect checkbox layout when partially clipped. - Demo: Reworked "Property Editor" demo in a manner that more ressemble the tree data and struct description data that a real application would want to use. - Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. diff --git a/imgui.cpp b/imgui.cpp index 52fa2f16f..7b922fdd7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15827,7 +15827,7 @@ static void SameLineOrWrap(const ImVec2& size) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImVec2 pos(window->DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window->DC.CursorPosPrevLine.y); - if (window->ClipRect.Contains(ImRect(pos, pos + size))) + if (window->WorkRect.Contains(ImRect(pos, pos + size))) ImGui::SameLine(); } @@ -15921,7 +15921,7 @@ void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const cha for (const char* p = line_begin; p <= line_end - 10; p++) { ImGuiID id = 0; - if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) + if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1 || ImCharIsXdigitA(p[10])) continue; ImVec2 p0 = CalcTextSize(line_begin, p); ImVec2 p1 = CalcTextSize(p, p + 10); diff --git a/imgui_internal.h b/imgui_internal.h index f2c5312ea..b307adcde 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -388,6 +388,7 @@ IM_MSVC_RUNTIME_CHECKS_OFF static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +static inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Formatting From e3da939b86f8cbf30a4d3e39b0cab2413c67dd03 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 18:41:51 +0200 Subject: [PATCH 017/136] Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (#7543) See "layout_group_endtable" test. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 8 ++++---- imgui.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1247ef94a..fde5c5144 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -140,6 +140,7 @@ Other changes: can use the clipper without knowing the amount of items beforehand. (#1311) In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration loop to position the layout cursor correctly. This is done automatically if provided a count to Begin(). +- Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (#7543) - TabBar, Style: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate thickness of the horizontal line over selectable tabs. [@DctrNoob] - Style: close button and collapse/window-menu button hover highlight made rectangular instead of round. diff --git a/imgui.cpp b/imgui.cpp index 7b922fdd7..31f65a9d4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10686,11 +10686,11 @@ void ImGui::EndGroup() if (window->DC.IsSetPos) ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); - ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); - + // Include LastItemData.Rect.Max as a workaround for e.g. EndTable() undershooting with CursorMaxPos report. (#7543) + ImRect group_bb(group_data.BackupCursorPos, ImMax(ImMax(window->DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos)); window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorPosPrevLine = group_data.BackupCursorPosPrevLine; - window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, group_bb.Max); window->DC.Indent = group_data.BackupIndent; window->DC.GroupOffset = group_data.BackupGroupOffset; window->DC.CurrLineSize = group_data.BackupCurrLineSize; @@ -10705,7 +10705,7 @@ void ImGui::EndGroup() return; } - window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. ItemSize(group_bb.GetSize()); ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); diff --git a/imgui.h b/imgui.h index fd0768a22..47626ad6f 100644 --- a/imgui.h +++ b/imgui.h @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.0 WIP" -#define IMGUI_VERSION_NUM 19098 +#define IMGUI_VERSION_NUM 19099 #define IMGUI_HAS_TABLE /* From 79b77d91c98e36c1dd487516564cec716ddd94f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 18:43:54 +0200 Subject: [PATCH 018/136] MultiSelect: sequential SetRange merging not generally handled by box-select path, useful for others. --- imgui_internal.h | 3 ++- imgui_widgets.cpp | 35 ++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index b307adcde..85aaa19bc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1751,6 +1751,7 @@ struct IMGUI_API ImGuiMultiSelectTempData ImGuiMultiSelectFlags Flags; ImVec2 ScopeRectMin; ImVec2 BackupCursorMaxPos; + ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges. ImGuiID BoxSelectId; ImGuiKeyChord KeyMods; ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all. @@ -1760,7 +1761,6 @@ struct IMGUI_API ImGuiMultiSelectTempData bool NavIdPassedBy; bool RangeSrcPassedBy; // Set by the item that matches RangeSrcItem. bool RangeDstPassedBy; // Set by the item that matches NavJustMovedToId when IsSetRange is set. - ImGuiSelectionUserData BoxSelectLastitem; // Copy of last submitted item data, used to merge output ranges. ImGuiMultiSelectTempData() { Clear(); } void Clear() { size_t io_sz = sizeof(IO); ClearIO(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); } // Zero-clear except IO as we preserve IO.Requests[] buffer allocation. @@ -3408,6 +3408,7 @@ namespace ImGui // Multi-Select API IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags); IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed); + IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item); inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 068337e9c..183c7fbe2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7069,7 +7069,7 @@ static int ImStrimatchlen(const char* s1, const char* s1_end, const char* s2) // When SingleCharMode is set: // - it is better to NOT display a tooltip of other on-screen display indicator. // - the index of the currently focused item is required. -// if your SetNextItemSelectionData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, otherwise from g.NavLastValidSelectionUserData. +// if your SetNextItemSelectionUserData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, otherwise from g.NavLastValidSelectionUserData. int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx) { if (req == NULL || req->SelectRequest == false) // Support NULL parameter so both calls can be done from same spot. @@ -7397,7 +7397,6 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) { ms->BoxSelectId = GetID("##BoxSelect"); - ms->BoxSelectLastitem = ImGuiSelectionUserData_Invalid; if (BeginBoxSelect(window, ms->BoxSelectId, flags)) request_clear |= bs->RequestClear; } @@ -7432,6 +7431,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel ms->IO.Requests.push_back(req); } ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; + ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO); @@ -7694,17 +7694,10 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) else { selected = !selected; - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, +1, item_data, item_data }; - // Merge continuous ranges (unless NoRangeSelect is set) - ImGuiSelectionRequest* prev = ms->IO.Requests.Size > 0 ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL; - if (prev && prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->BoxSelectLastitem && prev->Selected == selected && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) - prev->RangeLastItem = item_data; // Merge span into same request - else - ms->IO.Requests.push_back(req); + MultiSelectAddSetRange(ms, selected, +1, item_data, item_data); } storage->LastSelectionSize = ImMax(storage->LastSelectionSize + 1, 1); } - ms->BoxSelectLastitem = item_data; } // Right-click handling. @@ -7804,9 +7797,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) range_selected = selected; range_direction = +1; } - ImGuiSelectionUserData range_dst_item = item_data; - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, range_selected, (ImS8)range_direction, (range_direction > 0) ? storage->RangeSrcItem : range_dst_item, (range_direction > 0) ? range_dst_item : storage->RangeSrcItem }; - ms->IO.Requests.push_back(req); + MultiSelectAddSetRange(ms, range_selected, range_direction, storage->RangeSrcItem, item_data); } // Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a range unselect) @@ -7821,11 +7812,29 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) } if (storage->NavIdItem == item_data) ms->NavIdPassedBy = true; + ms->LastSubmittedItem = item_data; *p_selected = selected; *p_pressed = pressed; } +void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) +{ + // Merge contiguous spans into same request (unless NoRangeSelect is set which guarantees single-item ranges) + if (ms->IO.Requests.Size > 0 && first_item == last_item && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) + { + ImGuiSelectionRequest* prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1]; + if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && prev->Selected == selected) + { + prev->RangeLastItem = last_item; + return; + } + } + + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, (ImS8)range_dir, (range_dir > 0) ? first_item : last_item, (range_dir > 0) ? last_item : first_item }; + ms->IO.Requests.push_back(req); // Add new request +} + void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS From a285835ac4a293831852b0d5dd671401fd2c7412 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 19:00:09 +0200 Subject: [PATCH 019/136] MultiSelect: add internal MultiSelectAddSetAll() helper. --- imgui_internal.h | 1 + imgui_widgets.cpp | 28 ++++++++++++---------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 85aaa19bc..3bcca8500 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3408,6 +3408,7 @@ namespace ImGui // Multi-Select API IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags); IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed); + IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected); IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item); inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 183c7fbe2..e9cf6f0f7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7424,12 +7424,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel } if (request_clear || request_select_all) - { - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, request_select_all, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; - if (!request_select_all) - storage->LastSelectionSize = 0; - ms->IO.Requests.push_back(req); - } + MultiSelectAddSetAll(ms, request_select_all); ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; @@ -7496,11 +7491,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickVoid) if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None) - { - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; - ms->IO.Requests.resize(0); - ms->IO.Requests.push_back(req); - } + MultiSelectAddSetAll(ms, false); } // Courtesy nav wrapping helper flag @@ -7755,11 +7746,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) else if ((input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Gamepad) && is_shift && !is_ctrl) request_clear = true; // With is_shift==false the RequestClear was done in BeginIO, not necessary to do again. if (request_clear) - { - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; - ms->IO.Requests.resize(0); - ms->IO.Requests.push_back(req); - } + MultiSelectAddSetAll(ms, false); } int range_direction; @@ -7818,6 +7805,15 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) *p_pressed = pressed; } +void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected) +{ + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, selected, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; + ms->IO.Requests.resize(0); // Can always clear previous requests + ms->IO.Requests.push_back(req); // Add new request + if (selected == false) + ms->Storage->LastSelectionSize = 0; +} + void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) { // Merge contiguous spans into same request (unless NoRangeSelect is set which guarantees single-item ranges) From 237165a9359518573f67cabf2e2f6d648f351244 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Jul 2024 19:14:54 +0200 Subject: [PATCH 020/136] MultiSelect: fixed an issue caused by previous commit. Amend a285835. Breaks box-select. --- imgui_widgets.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e9cf6f0f7..7739f3036 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7424,7 +7424,11 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel } if (request_clear || request_select_all) + { MultiSelectAddSetAll(ms, request_select_all); + if (!request_select_all) + storage->LastSelectionSize = 0; + } ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; @@ -7810,8 +7814,6 @@ void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected) ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, selected, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; ms->IO.Requests.resize(0); // Can always clear previous requests ms->IO.Requests.push_back(req); // Add new request - if (selected == false) - ms->Storage->LastSelectionSize = 0; } void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) From ed356dc181217439af31e5883fbe58906d0ec1cb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 14:46:25 +0200 Subject: [PATCH 021/136] MultiSelect: BoxSelect: fixed box-select from void setting nav id multiple times. --- imgui_internal.h | 1 + imgui_widgets.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 3bcca8500..29420b6b6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1719,6 +1719,7 @@ struct ImGuiBoxSelectState bool IsActive; bool IsStarting; bool IsStartedFromVoid; // Starting click was not from an item. + bool IsStartedSetNavIdOnce; bool RequestClear; ImGuiKeyChord KeyMods : 16; // Latched key-mods for box-select logic. ImVec2 StartPosRel; // Start position in window-contents relative space (to support scrolling) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7739f3036..1a11e3834 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7161,6 +7161,7 @@ static void BoxSelectPreStartDrag(ImGuiID id, ImGuiSelectionUserData clicked_ite bs->ID = id; bs->IsStarting = true; // Consider starting box-select. bs->IsStartedFromVoid = (clicked_item == ImGuiSelectionUserData_Invalid); + bs->IsStartedSetNavIdOnce = bs->IsStartedFromVoid; bs->KeyMods = g.IO.KeyMods; bs->StartPosRel = bs->EndPosRel = ImGui::WindowPosAbsToRel(g.CurrentWindow, g.IO.MousePos); bs->ScrollAccum = ImVec2(0.0f, 0.0f); @@ -7682,9 +7683,10 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect); if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr)) { - if (storage->LastSelectionSize <= 0 && bs->IsStartedFromVoid) + if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce) { pressed = true; // First item act as a pressed: code below will emit selection request and set NavId (whatever we emit here will be overridden anyway) + bs->IsStartedSetNavIdOnce = false; } else { From 55f54fa512f81885cafcd2c701dcff26c328b146 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 15:10:04 +0200 Subject: [PATCH 022/136] Internals: comment out obsolete g.ActiveIdUsingNavInputMask obsoleted two years ago. (#4921, #4858, #787, #1599, #323) Use SetKeyOwner(ImGuiKey_Escape, g.ActiveId); instead. Amend 8b8a61bd --- imgui.cpp | 20 -------------------- imgui_internal.h | 9 ++------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 31f65a9d4..9e93b8434 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4040,9 +4040,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingAllKeyboardKeys = false; -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - g.ActiveIdUsingNavInputMask = 0x00; -#endif } void ImGui::ClearActiveID() @@ -4806,25 +4803,8 @@ void ImGui::NewFrame() { g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingAllKeyboardKeys = false; -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - g.ActiveIdUsingNavInputMask = 0x00; -#endif } -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - if (g.ActiveId == 0) - g.ActiveIdUsingNavInputMask = 0; - else if (g.ActiveIdUsingNavInputMask != 0) - { - // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); } - // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); } - if (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel)) - SetKeyOwner(ImGuiKey_Escape, g.ActiveId); - if (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel)) - IM_ASSERT(0); // Other values unsupported - } -#endif - // Record when we have been stationary as this state is preserved while over same item. // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. // To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function. diff --git a/imgui_internal.h b/imgui_internal.h index 29420b6b6..6fa1ee799 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2081,9 +2081,7 @@ struct ImGuiContext ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (this is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations) ImGuiKeyChord DebugBreakInShortcutRouting; // Set to break in SetShortcutRouting()/Shortcut() calls. -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' -#endif + //ImU32 ActiveIdUsingNavInputMask; // [OBSOLETE] Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes --> 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' // Next window/item data ImGuiID CurrentFocusScopeId; // Value for currently appending items == g.FocusScopeStack.back(). Not to be mistaken with g.NavFocusScopeId. @@ -2395,9 +2393,6 @@ struct ImGuiContext ActiveIdUsingNavDirMask = 0x00; ActiveIdUsingAllKeyboardKeys = false; -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - ActiveIdUsingNavInputMask = 0x00; -#endif CurrentFocusScopeId = 0; CurrentItemFlags = ImGuiItemFlags_None; @@ -3196,7 +3191,7 @@ namespace ImGui //#endif // Basic Accessors - inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } + inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } From aad86b8756b7cde30fd70ac87e6325257e1a3e27 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 15:50:30 +0200 Subject: [PATCH 023/136] Obsoleted GetWindowContentRegionMin() and GetWindowContentRegionMax(). You should never need those functions. You can do everything with GetCursorScreenPos() and GetContentRegionAvail(). --- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 10 +++++++++- imgui.h | 13 +++++++------ imgui_demo.cpp | 2 +- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fde5c5144..42c2cea37 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,12 @@ Breaking changes: - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); It is expected that for a vast majority of users this is automatically set by core library and/or platform backend so it won't have any effect. +- Obsoleted GetWindowContentRegionMin() and GetWindowContentRegionMax(). + You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail(). + Also consider that if you are using GetWindowPos() and GetCursorPos() you may also be making things + unnecessarily complicated. You can do everything with GetCursorScreenPos() and GetContentRegionAvail()!! + - GetWindowContentRegionMax().x - GetCursorPos().x --> GetContentRegionAvail().x + - GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x - Item flag changes: - Obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_ButtonRepeat. Kept inline redirecting functions (will obsolete). diff --git a/imgui.cpp b/imgui.cpp index 9e93b8434..626031514 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,11 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/07/25 (1.91.0) - obsoleted GetWindowContentRegionMin() and GetWindowContentRegionMax(). You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail(). + - instead of: GetWindowContentRegionMax().x - GetCursorPos().x + - you can use: GetContentRegionAvail().x + - instead of: GetWindowContentRegionMax().x + GetWindowPos().x + - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x (from left edge of window) - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573) (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors) - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag(). @@ -10609,7 +10614,9 @@ ImVec2 ImGui::GetContentRegionAvail() return GetContentRegionMaxAbs() - window->DC.CursorPos; } -// In window space (not screen space!) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()! +// They are bizarre local-coordinates which don't play well with scrolling. ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -10621,6 +10628,7 @@ ImVec2 ImGui::GetWindowContentRegionMax() ImGuiWindow* window = GImGui->CurrentWindow; return window->ContentRegionRect.Max - window->Pos; } +#endif // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. diff --git a/imgui.h b/imgui.h index 47626ad6f..26aed79bb 100644 --- a/imgui.h +++ b/imgui.h @@ -392,10 +392,10 @@ namespace ImGui IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives - IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetCursorScreenPos()) - IMGUI_API ImVec2 GetWindowSize(); // get current window size (note: it is unlikely you need to use this. Consider using GetCursorScreenPos() and e.g. GetContentRegionAvail() instead) - IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) - IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) + IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) + IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x. + IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y. // Window manipulation // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). @@ -422,8 +422,6 @@ namespace ImGui // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates - IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates - IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates // Windows Scrolling // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). @@ -473,6 +471,7 @@ namespace ImGui // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. + // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: // - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. // - Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() @@ -3504,6 +3503,8 @@ namespace ImGui static inline void PopButtonRepeat() { PopItemFlag(); } static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopTabStop() { PopItemFlag(); } + IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! + IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! // OBSOLETED in 1.90.0 (from September 2023) static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } static inline void EndChildFrame() { EndChild(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7a3cdf0f4..8684bd0c6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3918,7 +3918,7 @@ static void ShowDemoWindowLayout() ImGui::Text("Manual wrapping:"); ImGuiStyle& style = ImGui::GetStyle(); int buttons_count = 20; - float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; + float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x; for (int n = 0; n < buttons_count; n++) { ImGui::PushID(n); From 055b2e80fbe1f13b81ef6e092381530eaf68fc36 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 16:02:59 +0200 Subject: [PATCH 024/136] Moved everyone's best friend GetContentRegionAvail() to a more prominent position. --- imgui.cpp | 1 - imgui.h | 14 +++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 626031514..ace1d0276 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10315,7 +10315,6 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - GetContentRegionMax() // - GetContentRegionMaxAbs() [Internal] // - GetContentRegionAvail(), -// - GetWindowContentRegionMin(), GetWindowContentRegionMax() // - BeginGroup() // - EndGroup() // Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns. diff --git a/imgui.h b/imgui.h index 26aed79bb..e98399371 100644 --- a/imgui.h +++ b/imgui.h @@ -417,12 +417,6 @@ namespace ImGui IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. - // Content region - // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful. - // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) - IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() - IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates - // Windows Scrolling // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). // - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). @@ -474,10 +468,12 @@ namespace ImGui // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: // - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. - // - Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() - // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (prefer using this, also more useful to work with ImDrawList API). + // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), PushTextWrapPos() + // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it. + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API). IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates + IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND. + IMGUI_API ImVec2 GetContentRegionMax(); // [window-local] current content boundaries (e.g. window boundaries including scrolling, or current column boundaries) IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window coordinates (relative to window position) IMGUI_API float GetCursorPosX(); // [window-local] " IMGUI_API float GetCursorPosY(); // [window-local] " From 4227402b2fe46a24663fd16efd042a8527d2bbed Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 16:10:18 +0200 Subject: [PATCH 025/136] Internals: removed GetContentRegionMaxAbs() which was only meaningfully used in place of GetContentRegionAvail(). --- imgui.cpp | 40 ++++++++++++++-------------------------- imgui_internal.h | 1 - 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ace1d0276..40de62165 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10313,7 +10313,6 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - GetFrameHeight() // - GetFrameHeightWithSpacing() // - GetContentRegionMax() -// - GetContentRegionMaxAbs() [Internal] // - GetContentRegionAvail(), // - BeginGroup() // - EndGroup() @@ -10530,8 +10529,8 @@ float ImGui::CalcItemWidth() w = window->DC.ItemWidth; if (w < 0.0f) { - float region_max_x = GetContentRegionMaxAbs().x; - w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + float region_avail_x = GetContentRegionAvail().x; + w = ImMax(1.0f, region_avail_x + w); } w = IM_TRUNC(w); return w; @@ -10543,22 +10542,19 @@ float ImGui::CalcItemWidth() // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - - ImVec2 region_max; + ImVec2 avail; if (size.x < 0.0f || size.y < 0.0f) - region_max = GetContentRegionMaxAbs(); + avail = GetContentRegionAvail(); if (size.x == 0.0f) size.x = default_w; else if (size.x < 0.0f) - size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); + size.x = ImMax(4.0f, avail.x + size.x); // <-- size.x is negative here so we are subtracting if (size.y == 0.0f) size.y = default_h; else if (size.y < 0.0f) - size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); + size.y = ImMax(4.0f, avail.y + size.y); // <-- size.y is negative here so we are subtracting return size; } @@ -10587,8 +10583,15 @@ float ImGui::GetFrameHeightWithSpacing() return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; } -// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; + return mx - window->DC.CursorPos; +} +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! // FIXME: This is in window space (not screen space!). ImVec2 ImGui::GetContentRegionMax() { @@ -10598,21 +10601,6 @@ ImVec2 ImGui::GetContentRegionMax() return mx - window->Pos; } -// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. -ImVec2 ImGui::GetContentRegionMaxAbs() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; - return mx; -} - -ImVec2 ImGui::GetContentRegionAvail() -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return GetContentRegionMaxAbs() - window->DC.CursorPos; -} - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()! // They are bizarre local-coordinates which don't play well with scrolling. diff --git a/imgui_internal.h b/imgui_internal.h index 6fa1ee799..6cee07857 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3217,7 +3217,6 @@ namespace ImGui IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); - IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); // Parameter stacks (shared) From b20f62b162e5f1e44748eb768f6b126a25ec29de Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 16:18:46 +0200 Subject: [PATCH 026/136] Obsoleted GetContentRegionMax(). --- docs/CHANGELOG.txt | 10 ++++++---- imgui.cpp | 21 ++++++++++----------- imgui.h | 13 +++++++------ 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42c2cea37..eb98554ce 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,12 +46,14 @@ Breaking changes: - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); It is expected that for a vast majority of users this is automatically set by core library and/or platform backend so it won't have any effect. -- Obsoleted GetWindowContentRegionMin() and GetWindowContentRegionMax(). - You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail(). - Also consider that if you are using GetWindowPos() and GetCursorPos() you may also be making things - unnecessarily complicated. You can do everything with GetCursorScreenPos() and GetContentRegionAvail()!! +- Obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). + You should never need those functions! You can do everything in less a confusing manner by only + using GetCursorScreenPos() and GetContentRegionAvail(). Also always consider that if you are using + GetWindowPos() and GetCursorPos() you may also be making things unnecessarily complicated. + I repeat: You can do everything with GetCursorScreenPos() and GetContentRegionAvail()!! - GetWindowContentRegionMax().x - GetCursorPos().x --> GetContentRegionAvail().x - GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x + - GetContentRegionMax() --> GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in weird local coordinates - Item flag changes: - Obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_ButtonRepeat. Kept inline redirecting functions (will obsolete). diff --git a/imgui.cpp b/imgui.cpp index 40de62165..a74ae56c1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,11 +430,14 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2024/07/25 (1.91.0) - obsoleted GetWindowContentRegionMin() and GetWindowContentRegionMax(). You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail(). + - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). + you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way. - instead of: GetWindowContentRegionMax().x - GetCursorPos().x - you can use: GetContentRegionAvail().x - instead of: GetWindowContentRegionMax().x + GetWindowPos().x - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x (from left edge of window) + - instead of: GetContentRegionMax() + - you cna use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in weird local coordinates - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573) (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors) - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag(). @@ -10591,19 +10594,15 @@ ImVec2 ImGui::GetContentRegionAvail() return mx - window->DC.CursorPos; } -// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! -// FIXME: This is in window space (not screen space!). -ImVec2 ImGui::GetContentRegionMax() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; - return mx - window->Pos; -} - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()! // They are bizarre local-coordinates which don't play well with scrolling. +ImVec2 ImGui::GetContentRegionMax() +{ + return GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos(); +} + ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GImGui->CurrentWindow; diff --git a/imgui.h b/imgui.h index e98399371..0686be2ab 100644 --- a/imgui.h +++ b/imgui.h @@ -468,19 +468,19 @@ namespace ImGui // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: // - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. - // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), PushTextWrapPos() + // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), PushTextWrapPos() + // - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> all obsoleted. YOU DON'T NEED THEM. // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it. - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API). - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API). + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND. IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND. - IMGUI_API ImVec2 GetContentRegionMax(); // [window-local] current content boundaries (e.g. window boundaries including scrolling, or current column boundaries) - IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window coordinates (relative to window position) + IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window-local coordinates. This is not your best friend. IMGUI_API float GetCursorPosX(); // [window-local] " IMGUI_API float GetCursorPosY(); // [window-local] " IMGUI_API void SetCursorPos(const ImVec2& local_pos); // [window-local] " IMGUI_API void SetCursorPosX(float local_x); // [window-local] " IMGUI_API void SetCursorPosY(float local_y); // [window-local] " - IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window coordinates + IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates // Other layout functions IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. @@ -3499,6 +3499,7 @@ namespace ImGui static inline void PopButtonRepeat() { PopItemFlag(); } static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopTabStop() { PopItemFlag(); } + IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! // OBSOLETED in 1.90.0 (from September 2023) From 3f9a90e2a3c5a4662e57b5b9dec3042d3b5715ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jul 2024 16:59:34 +0200 Subject: [PATCH 027/136] Docs: added extraneous link to Getting Started section. --- backends/imgui_impl_allegro5.h | 1 + backends/imgui_impl_android.h | 1 + backends/imgui_impl_dx10.h | 1 + backends/imgui_impl_dx11.h | 1 + backends/imgui_impl_dx12.h | 2 ++ backends/imgui_impl_dx9.h | 1 + backends/imgui_impl_glfw.h | 1 + backends/imgui_impl_glut.h | 1 + backends/imgui_impl_metal.h | 2 ++ backends/imgui_impl_opengl2.h | 1 + backends/imgui_impl_opengl3.h | 2 +- backends/imgui_impl_osx.h | 2 ++ backends/imgui_impl_sdl2.h | 1 + backends/imgui_impl_sdl3.h | 1 + backends/imgui_impl_sdlrenderer2.h | 1 + backends/imgui_impl_sdlrenderer3.h | 1 + backends/imgui_impl_vulkan.h | 2 +- backends/imgui_impl_wgpu.h | 1 + backends/imgui_impl_win32.h | 1 + 19 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 5b63654ef..f1501eca8 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -25,6 +25,7 @@ struct ALLEGRO_DISPLAY; union ALLEGRO_EVENT; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display); IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown(); IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame(); diff --git a/backends/imgui_impl_android.h b/backends/imgui_impl_android.h index 557bf0e09..92a044db0 100644 --- a/backends/imgui_impl_android.h +++ b/backends/imgui_impl_android.h @@ -28,6 +28,7 @@ struct ANativeWindow; struct AInputEvent; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window); IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event); IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown(); diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index e7e798aa4..95759737b 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -19,6 +19,7 @@ struct ID3D10Device; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device); IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame(); diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 20887f370..cde64ee96 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -20,6 +20,7 @@ struct ID3D11Device; struct ID3D11DeviceContext; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 8710910b4..e1fd07d6d 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -27,6 +27,8 @@ struct ID3D12GraphicsCommandList; struct D3D12_CPU_DESCRIPTOR_HANDLE; struct D3D12_GPU_DESCRIPTOR_HANDLE; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! + // cmd_list is the command list that the implementation will use to render imgui draw lists. // Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate // render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle. diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index 3965583bd..df6a0a012 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -19,6 +19,7 @@ struct IDirect3DDevice9; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device); IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame(); diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index a30ed64ca..c0eac1134 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -24,6 +24,7 @@ struct GLFWwindow; struct GLFWmonitor; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks); diff --git a/backends/imgui_impl_glut.h b/backends/imgui_impl_glut.h index 062110edd..a7479e1d7 100644 --- a/backends/imgui_impl_glut.h +++ b/backends/imgui_impl_glut.h @@ -26,6 +26,7 @@ #ifndef IMGUI_DISABLE #include "imgui.h" // IMGUI_IMPL_API +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplGLUT_Init(); IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs(); IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown(); diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 53706d1f7..2402c02c6 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -25,6 +25,7 @@ @class MTLRenderPassDescriptor; @protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id device); IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor); @@ -51,6 +52,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); #include #ifndef __OBJC__ +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor); diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index 9c756c71d..e7f7a58c1 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -24,6 +24,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame(); diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index d66a15ebf..54545f957 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -29,7 +29,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE -// Backend API +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 4033ad93e..28e133128 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -27,6 +27,7 @@ @class NSEvent; @class NSView; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view); IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view); @@ -41,6 +42,7 @@ IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view); // #include #ifndef __OBJC__ +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOSX_Init(void* _Nonnull view); IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view); diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 7020a29e0..e551e52a2 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -27,6 +27,7 @@ struct SDL_Renderer; struct _SDL_GameController; typedef union SDL_Event SDL_Event; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index f1c06db5d..39b7839d8 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -28,6 +28,7 @@ struct SDL_Renderer; struct SDL_Gamepad; typedef union SDL_Event SDL_Event; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index aee40524d..c067eaeea 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -25,6 +25,7 @@ struct SDL_Renderer; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame(); diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 968ec0825..1a730208a 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -25,6 +25,7 @@ struct SDL_Renderer; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame(); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index fb98bfbc4..1c7f76951 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -98,7 +98,7 @@ struct ImGui_ImplVulkan_InitInfo VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; -// Called by user code +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 2e19ea36e..87d9580bf 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -37,6 +37,7 @@ struct ImGui_ImplWGPU_InitInfo } }; +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info); IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame(); diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index be5627142..3ad1a7eaf 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -20,6 +20,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); From b3ba6b30952961bb9ec5fc6f46361c72530ff67c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 26 Jul 2024 14:07:29 +0200 Subject: [PATCH 028/136] Added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match the typical "Nintendo/Japanese consoles" button layout when using Gamepad navigation. (#787, #5723) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 1 + imgui.h | 1 + imgui_internal.h | 4 ++-- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eb98554ce..cdb136029 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - IO: added io.PlatformOpenInShellFn handler to open a link/folder/file in OS shell. (#7660) Default to use ShellExecute() under Windows, and system("") under Mac/Linux/etc. Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default implementation. +- IO: added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match tye + typical "Nintendo/Japanese consoles" button layout when using Gamepad navigation. (#787, #5723) - Added PushItemFlag()/PopItemFlags(), ImGuiItemFlags to modify shared item flags: - Added ImGuiItemFlags_NoTabStop to disable tabbing through items. - Added ImGuiItemFlags_NoNav to disable any navigation and focus of items. (#787) diff --git a/imgui.cpp b/imgui.cpp index a74ae56c1..db7964b8a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1376,6 +1376,7 @@ ImGuiIO::ImGuiIO() #else ConfigMacOSXBehaviors = false; #endif + ConfigNavSwapGamepadButtons = false; ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; ConfigInputTextEnterKeepActive = false; diff --git a/imgui.h b/imgui.h index 0686be2ab..09db7b1fe 100644 --- a/imgui.h +++ b/imgui.h @@ -2225,6 +2225,7 @@ struct ImGuiIO // Miscellaneous options 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. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). diff --git a/imgui_internal.h b/imgui_internal.h index 6cee07857..0eaaa0f77 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1355,8 +1355,8 @@ typedef ImBitArray ImBitAr #define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift #define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1 #define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1 -#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown -#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight +#define ImGuiKey_NavGamepadActivate (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceRight : ImGuiKey_GamepadFaceDown) +#define ImGuiKey_NavGamepadCancel (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceDown : ImGuiKey_GamepadFaceRight) #define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft #define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp From 692bee5f2211952b8a732616b7714f95ca1ef639 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 26 Jul 2024 15:14:37 +0200 Subject: [PATCH 029/136] Added GetID(int) variant for consistency. (#7111) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 5 +++++ imgui.h | 1 + 3 files changed, 7 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cdb136029..f47d7d7d2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -153,6 +153,7 @@ Other changes: - Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (#7543) - TabBar, Style: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate thickness of the horizontal line over selectable tabs. [@DctrNoob] +- Misc: added GetID(int) variant for consistency. (#7111) - Style: close button and collapse/window-menu button hover highlight made rectangular instead of round. - Debug Tools: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) Debug log entries add a imgui frame counter prefix + are redirected to ShowDebugLogWindow() and diff --git a/imgui.cpp b/imgui.cpp index db7964b8a..8640eda1a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8380,6 +8380,11 @@ ImGuiID ImGui::GetID(const void* ptr_id) return window->GetID(ptr_id); } +ImGuiID ImGui::GetID(int int_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(int_id); +} //----------------------------------------------------------------------------- // [SECTION] INPUTS //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 09db7b1fe..db9e59dad 100644 --- a/imgui.h +++ b/imgui.h @@ -517,6 +517,7 @@ namespace ImGui IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); IMGUI_API ImGuiID GetID(const void* ptr_id); + IMGUI_API ImGuiID GetID(int int_id); // Widgets: Text IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. From d42fa46dc6b68863046c22467297933dbe39bb55 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 26 Jul 2024 15:15:46 +0200 Subject: [PATCH 030/136] Misc micro-optimizations related to hot-path of dealing with a large clipped tree. Halved times by two in MSVC Debug x64. --- imgui.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8640eda1a..6b545d67d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2583,12 +2583,11 @@ void ImGuiStorage::BuildSortByKey() { ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID); } -IM_MSVC_RUNTIME_CHECKS_RESTORE int ImGuiStorage::GetInt(ImGuiID key, int default_val) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) return default_val; return it->val_i; } @@ -2601,7 +2600,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) return default_val; return it->val_f; } @@ -2609,7 +2608,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const void* ImGuiStorage::GetVoidPtr(ImGuiID key) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) return NULL; return it->val_p; } @@ -2618,7 +2617,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_i; } @@ -2631,7 +2630,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_f; } @@ -2639,7 +2638,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_p; } @@ -2648,7 +2647,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) void ImGuiStorage::SetInt(ImGuiID key, int val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_i = val; @@ -2662,7 +2661,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val) void ImGuiStorage::SetFloat(ImGuiID key, float val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_f = val; @@ -2671,7 +2670,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val) void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.end() || it->key != key) + if (it == Data.Data + Data.Size || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_p = val; @@ -2682,6 +2681,7 @@ void ImGuiStorage::SetAllInt(int v) for (int i = 0; i < Data.Size; i++) Data[i].val_i = v; } +IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] ImGuiTextFilter @@ -2749,7 +2749,7 @@ void ImGuiTextFilter::Build() bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { - if (Filters.empty()) + if (Filters.Size == 0) return true; if (text == NULL) @@ -8241,6 +8241,7 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // This is one of the very rare legacy case where we use ImGuiWindow methods, // it should ideally be flattened at some point but it's been used a lots by widgets. +IM_MSVC_RUNTIME_CHECKS_OFF ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { ImGuiID seed = IDStack.back(); @@ -8385,6 +8386,8 @@ ImGuiID ImGui::GetID(int int_id) ImGuiWindow* window = GImGui->CurrentWindow; return window->GetID(int_id); } +IM_MSVC_RUNTIME_CHECKS_RESTORE + //----------------------------------------------------------------------------- // [SECTION] INPUTS //----------------------------------------------------------------------------- From 79e83d6535291f41430d900c8d71d7fd0e9b47f0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Jul 2024 11:17:31 +0200 Subject: [PATCH 031/136] Docs: misc update. --- docs/BACKENDS.md | 38 +++++++++++++++++++------------------- docs/EXAMPLES.md | 45 ++++++--------------------------------------- docs/README.md | 6 +++--- 3 files changed, 28 insertions(+), 61 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 88a96a6bd..55a0983dd 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -2,23 +2,10 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE ## Dear ImGui: Backends -**The backends/ folder contains backends for popular platforms/graphics API, which you can use in -your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. - -- The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
- e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. - -- The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
- e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. - -- For some high-level frameworks, a single backend usually handles both 'Platform' and 'Renderer' parts.
- e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. - -An application usually combines one Platform backend + one Renderer backend + main Dear ImGui sources. -For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. - -**Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** +### Integrating backends +💡 The **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** has examples of how to integrate Dear ImGui into an existing application. +
The [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) documentation may also be worth a read. ### What are backends? @@ -38,7 +25,7 @@ Dear ImGui is highly portable and only requires a few things to run and render, - Optional: multi-viewports support. etc. -This is essentially what each backend is doing + obligatory portability cruft. Using default backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support). +This is essentially what each backend is doing + obligatory portability cruft. Using standard backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support). It is important to understand the difference between the core Dear ImGui library (files in the root folder) and the backends which we are describing here (backends/ folder). @@ -47,11 +34,24 @@ and the backends which we are describing here (backends/ folder). - You should be able to write backends for pretty much any platform and any 3D graphics API. e.g. you can get creative and use software rendering or render remotely on a different machine. +### Standard backends -### Integrating a backend +**The [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder contains backends for popular platforms/graphics API, which you can use in +your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. -See "Getting Started" section of [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for more details. +- The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
+ e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. +- The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
+ e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. + +- For some high-level frameworks, a single backend usually handles both 'Platform' and 'Renderer' parts.
+ e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. + +An application usually combines one Platform backend + one Renderer backend + main Dear ImGui sources. +For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. + +**Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** ### List of backends diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 4aa69a671..66ad24ef7 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -35,46 +35,13 @@ At shutdown: call ImGui::DestroyContext() ``` -Example (using [backends/imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp) + [backends/imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)): +Main resource: +- Read **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** for detailed examples of how to integrate Dear ImGui in an existing application. -```cpp -// Create a Dear ImGui context, setup some options -ImGui::CreateContext(); -ImGuiIO& io = ImGui::GetIO(); -io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable some options - -// Initialize Platform + Renderer backends (here: using imgui_impl_win32.cpp + imgui_impl_dx11.cpp) -ImGui_ImplWin32_Init(my_hwnd); -ImGui_ImplDX11_Init(my_d3d_device, my_d3d_device_context); - -// Application main loop -while (true) -{ - // Beginning of frame: update Renderer + Platform backend, start Dear ImGui frame - ImGui_ImplDX11_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); - - // Any application code here - ImGui::Text("Hello, world!"); - - // End of frame: render Dear ImGui - ImGui::Render(); - ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); - - // Swap - g_pSwapChain->Present(1, 0); -} - -// Shutdown -ImGui_ImplDX11_Shutdown(); -ImGui_ImplWin32_Shutdown(); -ImGui::DestroyContext(); -``` - -Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. -Please read the comments and instruction at the top of each file. -Please read FAQ at https://www.dearimgui.com/faq +Additional resources: +- Read FAQ at https://www.dearimgui.com/faq +- Read 'PROGRAMMER GUIDE' section in imgui.cpp. +- Read the comments and instruction at the top of each file. If you are using any of the backends provided here, you can add the backends/imgui_impl_xxxx(.cpp,.h) files to your project and use as-in. Each imgui_impl_xxxx.cpp file comes with its own individual diff --git a/docs/README.md b/docs/README.md index 78cf2fea0..2c976341c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,7 +13,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin
  _E-mail: contact @ dearimgui dot com_
Individuals: support continued development and maintenance [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). Also see [Funding](https://github.com/ocornut/imgui/wiki/Funding) page. -| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Integration](#integration) | +| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration) | :----------------------------------------------------------: | | [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - **[Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)** - [Credits](#credits) - [License](#license) | | [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Languages bindings & frameworks backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | @@ -43,7 +43,7 @@ Dear ImGui is particularly suited to integration in game engines (for tooling), **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. -See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide and [Integration](#integration) section of this document for more details. +See the [Getting Started & Integration](#getting-started--integration) section of this document for more details. After Dear ImGui is set up in your application, you can use it from \_anywhere\_ in your program loop: ```cpp @@ -114,7 +114,7 @@ You should be able to build the examples from sources. If you don't, let us know The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). -### Integration +### Getting Started & Integration See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide for details. From 96460a8a12615f3138173996f7481cc86c70a9f1 Mon Sep 17 00:00:00 2001 From: Laurent Dufresne Date: Sun, 28 Jul 2024 09:51:20 +0200 Subject: [PATCH 032/136] InputText: Added '\' and '/' as word seperator. (#7824, #7704) Adding those seperators means that ctrl+(left|right)-arrows and ctrl+backspace will stop at slashes, which is more inline with how most software works and generally is very convenient when dealing with paths or urls. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f47d7d7d2..dca2d3259 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -146,6 +146,7 @@ Other changes: - Multi-Select (advanced) - Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened. +- InputText: added '\' and '/' as word seperator. (#7824, #7704) [@reduf] - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can can use the clipper without knowing the amount of items beforehand. (#1311) In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1a11e3834..b1ee63ce5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3897,7 +3897,7 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob static bool is_separator(unsigned int c) { - return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!'; + return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!' || c=='\\' || c=='/'; } static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) From c7b925609777aec45326791c5105a433b3e4e3a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20H=C3=A9rilier?= Date: Fri, 26 Jul 2024 13:19:22 +0200 Subject: [PATCH 033/136] Selectable: added ImGuiSelectableFlags_Highlight flag to highlight items independently from the hovered state. (#7820) Demo: Make the Widget/List boxes show how to use forced highlighting. --- docs/CHANGELOG.txt | 2 ++ imgui.h | 1 + imgui_demo.cpp | 33 +++++++++++++++++++++------------ imgui_widgets.cpp | 7 ++++--- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dca2d3259..2ac60cd72 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -147,6 +147,8 @@ Other changes: - Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened. - InputText: added '\' and '/' as word seperator. (#7824, #7704) [@reduf] +- Selectable: added ImGuiSelectableFlags_Highlight flag to highlight items independently from + the hovered state. (#7820) [@rerilier] - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can can use the clipper without knowing the amount of items beforehand. (#1311) In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration diff --git a/imgui.h b/imgui.h index db9e59dad..de7a4d2bc 100644 --- a/imgui.h +++ b/imgui.h @@ -1228,6 +1228,7 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one + ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8684bd0c6..0c61352d7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1357,18 +1357,18 @@ static void ShowDemoWindowWidgets(DemoWindowData* demo_data) // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_current_idx = 0; // Here we store our selection data as an index. + static int item_selected_idx = 0; // Here we store our selection data as an index. // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - const char* combo_preview_value = items[item_current_idx]; + const char* combo_preview_value = items[item_selected_idx]; if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - const bool is_selected = (item_current_idx == n); + const bool is_selected = (item_selected_idx == n); if (ImGui::Selectable(items[n], is_selected)) - item_current_idx = n; + item_selected_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1410,14 +1410,22 @@ static void ShowDemoWindowWidgets(DemoWindowData* demo_data) // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_current_idx = 0; // Here we store our selection data as an index. + static int item_selected_idx = 0; // Here we store our selected data as an index. + + static bool item_highlight = false; + int item_highlighted_idx = -1; // Here we store our highlighted data as an index. + ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight); + if (ImGui::BeginListBox("listbox 1")) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - const bool is_selected = (item_current_idx == n); + const bool is_selected = (item_selected_idx == n); if (ImGui::Selectable(items[n], is_selected)) - item_current_idx = n; + item_selected_idx = n; + + if (item_highlight && ImGui::IsItemHovered()) + item_highlighted_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1433,9 +1441,10 @@ static void ShowDemoWindowWidgets(DemoWindowData* demo_data) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - const bool is_selected = (item_current_idx == n); - if (ImGui::Selectable(items[n], is_selected)) - item_current_idx = n; + bool is_selected = (item_selected_idx == n); + ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0; + if (ImGui::Selectable(items[n], is_selected, flags)) + item_selected_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1482,8 +1491,8 @@ static void ShowDemoWindowWidgets(DemoWindowData* demo_data) ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/In columns"); - if (ImGui::TreeNode("In columns")) + IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables"); + if (ImGui::TreeNode("In Tables")) { static bool selected[10] = {}; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b1ee63ce5..31ba7d5c7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6894,14 +6894,15 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Render if (is_visible) { - if (hovered || selected) + const bool highlighted = hovered || (flags & ImGuiSelectableFlags_Highlight); + if (highlighted || selected) { // FIXME-MULTISELECT: Styling: Color for 'selected' elements? ImGuiCol_HeaderSelected ImU32 col; - if (selected && !hovered) + if (selected && !highlighted) col = GetColorU32(ImLerp(GetStyleColorVec4(ImGuiCol_Header), GetStyleColorVec4(ImGuiCol_HeaderHovered), 0.5f)); else - col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); } if (g.NavId == id) From 249d5caedbe6e598958b4987141ce5a197703173 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Jul 2024 15:19:42 +0200 Subject: [PATCH 034/136] Tables: storing LastFrozenHeight for frozen requests that don't have actual freezing due to zero scrolling. (#7821, #5143) Amend 0b4a1a40 (ignore whitespace to view this patch easily) --- imgui_tables.cpp | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index ce6fed1ea..9c8262ff8 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1996,34 +1996,37 @@ void ImGui::TableEndRow(ImGuiTable* table) // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and // get the new cursor position. if (unfreeze_rows_request) + { for (int column_n = 0; column_n < table->ColumnsCount; column_n++) table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; - if (unfreeze_rows_actual) - { - IM_ASSERT(table->IsUnfrozenRows == false); const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); - table->IsUnfrozenRows = true; table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y; - // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect - table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); - table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; - table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; - IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); - - float row_height = table->RowPosY2 - table->RowPosY1; - table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; - table->RowPosY1 = table->RowPosY2 - row_height; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (unfreeze_rows_actual) { - ImGuiTableColumn* column = &table->Columns[column_n]; - column->DrawChannelCurrent = column->DrawChannelUnfrozen; - column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; - } + IM_ASSERT(table->IsUnfrozenRows == false); + table->IsUnfrozenRows = true; - // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y - SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); - table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); + table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; + table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; + IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); + + float row_height = table->RowPosY2 - table->RowPosY1; + table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; + table->RowPosY1 = table->RowPosY2 - row_height; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->DrawChannelCurrent = column->DrawChannelUnfrozen; + column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; + } + + // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y + SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + } } if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) From b847c414372928b6b919bc93d573adb1ff950c47 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Jul 2024 15:23:24 +0200 Subject: [PATCH 035/136] MultiSelect: BoxSelect: fixed using in frozen table. (#7821, #5143) + added Demo. Amend 0b4a1a40 --- imgui_demo.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 2 +- imgui_widgets.cpp | 26 +++++++++++++++++++++----- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0c61352d7..eba615e12 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3306,6 +3306,52 @@ static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) ImGui::TreePop(); } + // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect() + IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)"); + if (ImGui::TreeNode("Multi-Select (in a table)")) + { + static ImGuiSelectionBasicStorage selection; + + const int ITEMS_COUNT = 10000; + ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); + if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) + { + ImGui::TableSetupColumn("Object"); + ImGui::TableSetupColumn("Action"); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + + ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; + ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); + selection.ApplyRequests(ms_io); + + ImGuiListClipper clipper; + clipper.Begin(ITEMS_COUNT); + if (ms_io->RangeSrcItem != -1) + clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. + while (clipper.Step()) + { + for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + char label[64]; + sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]); + bool item_is_selected = selection.Contains((ImGuiID)n); + ImGui::SetNextItemSelectionUserData(n); + ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); + ImGui::TableNextColumn(); + ImGui::SmallButton("hello"); + } + } + + ms_io = ImGui::EndMultiSelect(); + selection.ApplyRequests(ms_io); + ImGui::EndTable(); + } + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)"); if (ImGui::TreeNode("Multi-Select (checkboxes)")) { diff --git a/imgui_internal.h b/imgui_internal.h index 0eaaa0f77..db10a9468 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3397,7 +3397,7 @@ namespace ImGui IMGUI_API int TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data); // Box-Select API - IMGUI_API bool BeginBoxSelect(ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags); + IMGUI_API bool BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags); IMGUI_API void EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flags); // Multi-Select API diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 31ba7d5c7..970bb067b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7221,7 +7221,7 @@ static void BoxSelectScrollWithMouseDrag(ImGuiBoxSelectState* bs, ImGuiWindow* w } } -bool ImGui::BeginBoxSelect(ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags) +bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags) { ImGuiContext& g = *GImGui; ImGuiBoxSelectState* bs = &g.BoxSelectState; @@ -7241,11 +7241,10 @@ bool ImGui::BeginBoxSelect(ImGuiWindow* window, ImGuiID box_select_id, ImGuiMult // Current frame absolute prev/current rectangles are used to toggle selection. // They are derived from positions relative to scrolling space. - const ImRect scope_rect = window->InnerClipRect; ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->StartPosRel); ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->EndPosRel); // Clamped already ImVec2 curr_end_pos_abs = g.IO.MousePos; - if (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) // Box-select scrolling only happens with ScopeWindow + if (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) // Box-select scrolling only happens with ScopeWindow curr_end_pos_abs = ImClamp(curr_end_pos_abs, scope_rect.Min, scope_rect.Max); bs->BoxSelectRectPrev.Min = ImMin(start_pos_abs, prev_end_pos_abs); bs->BoxSelectRectPrev.Max = ImMax(start_pos_abs, prev_end_pos_abs); @@ -7299,6 +7298,7 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag // [SECTION] Widgets: Multi-Select support //------------------------------------------------------------------------- // - DebugLogMultiSelectRequests() [Internal] +// - CalcScopeRect() [Internal] // - BeginMultiSelect() // - EndMultiSelect() // - SetNextItemSelectionUserData() @@ -7317,6 +7317,22 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe } } +static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) +{ + if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) + { + // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only + return ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)); + } + else + { + // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect? + ImRect scope_rect = window->InnerClipRect; + scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max); + return scope_rect; + } +} + // Return ImGuiMultiSelectIO structure. // Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). // Passing 'selection_size' and 'items_count' parameters is currently optional. @@ -7399,7 +7415,7 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) { ms->BoxSelectId = GetID("##BoxSelect"); - if (BeginBoxSelect(window, ms->BoxSelectId, flags)) + if (BeginBoxSelect(CalcScopeRect(ms, window), window, ms->BoxSelectId, flags)) request_clear |= bs->RequestClear; } @@ -7452,7 +7468,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() IM_ASSERT(g.CurrentMultiSelect != NULL && storage->Window == g.CurrentWindow); IM_ASSERT(g.MultiSelectTempDataStacked > 0 && &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] == g.CurrentMultiSelect); - const ImRect scope_rect = (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) ? ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)) : window->InnerClipRect; + ImRect scope_rect = CalcScopeRect(ms, window); if (ms->IsFocused) { // We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be an easy change here. From df387049268775acb9b69438632a5f5fce58a674 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Jul 2024 22:08:06 +0200 Subject: [PATCH 036/136] Added SetNextItemStorageID() for tree nodes. (#7553, #6990, #3823, #1131) Undo/amend 7c6d4ff. --- docs/CHANGELOG.txt | 3 +++ imgui.h | 1 + imgui_internal.h | 4 +++- imgui_widgets.cpp | 25 ++++++++++++++++++------- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2ac60cd72..9fbd8b4f2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -147,6 +147,9 @@ Other changes: - Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened. - InputText: added '\' and '/' as word seperator. (#7824, #7704) [@reduf] +- TreeNode: added SetNextItemStorageID() to specify/override the identifier used for persisting + open/close storage. Useful if needing to often read/write from storage without manipulating + the ID stack. (#7553, #6990, #3823, #1131) - Selectable: added ImGuiSelectableFlags_Highlight flag to highlight items independently from the hovered state. (#7820) [@rerilier] - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can diff --git a/imgui.h b/imgui.h index de7a4d2bc..898308bb5 100644 --- a/imgui.h +++ b/imgui.h @@ -661,6 +661,7 @@ namespace ImGui IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. + IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id). // Widgets: Selectables // - A selectable highlights when hovered, and can display another color when selected. diff --git a/imgui_internal.h b/imgui_internal.h index db10a9468..7e9b22607 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1215,6 +1215,7 @@ enum ImGuiNextItemDataFlags_ ImGuiNextItemDataFlags_HasOpen = 1 << 1, ImGuiNextItemDataFlags_HasShortcut = 1 << 2, ImGuiNextItemDataFlags_HasRefVal = 1 << 3, + ImGuiNextItemDataFlags_HasStorageID = 1 << 4, }; struct ImGuiNextItemData @@ -1230,6 +1231,7 @@ struct ImGuiNextItemData bool OpenVal; // Set by SetNextItemOpen() ImU8 OpenCond; // Set by SetNextItemOpen() ImGuiDataTypeStorage RefVal; // Not exposed yet, for ImGuiInputTextFlags_ParseEmptyAsRefVal + ImGuiID StorageId; // Set by SetNextItemStorageID() ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; } inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! @@ -3546,7 +3548,7 @@ namespace ImGui IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0); // Widgets: Tree Nodes - IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 970bb067b..8e35df662 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6226,7 +6226,7 @@ bool ImGui::TreeNode(const char* label) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, id, ImGuiTreeNodeFlags_None, label, NULL); + return TreeNodeBehavior(id, ImGuiTreeNodeFlags_None, label, NULL); } bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) @@ -6245,7 +6245,7 @@ bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, id, flags, label, NULL); + return TreeNodeBehavior(id, flags, label, NULL); } bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) @@ -6275,7 +6275,7 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char ImGuiID id = window->GetID(str_id); const char* label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); - return TreeNodeBehavior(id, id, flags, label, label_end); + return TreeNodeBehavior(id, flags, label, label_end); } bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) @@ -6287,7 +6287,7 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char ImGuiID id = window->GetID(ptr_id); const char* label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); - return TreeNodeBehavior(id, id, flags, label, label_end); + return TreeNodeBehavior(id, flags, label, label_end); } bool ImGui::TreeNodeGetOpen(ImGuiID storage_id) @@ -6367,7 +6367,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags) } // When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop. -bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -6410,6 +6410,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); // Compute open and multi-select states before ItemAdd() as it clear NextItem data. + ImGuiID storage_id = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); bool is_visible; @@ -6694,6 +6695,16 @@ void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) g.NextItemData.OpenCond = (ImU8)(cond ? cond : ImGuiCond_Always); } +// Set next TreeNode/CollapsingHeader storage id. +void ImGui::SetNextItemStorageID(ImGuiID storage_id) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasStorageID; + g.NextItemData.StorageId = storage_id; +} + // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) @@ -6702,7 +6713,7 @@ bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label); + return TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label); } // p_visible == NULL : regular collapsing header @@ -6722,7 +6733,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl flags |= ImGuiTreeNodeFlags_CollapsingHeader; if (p_visible) flags |= ImGuiTreeNodeFlags_AllowOverlap | (ImGuiTreeNodeFlags)ImGuiTreeNodeFlags_ClipLabelForTrailingButton; - bool is_open = TreeNodeBehavior(id, id, flags, label); + bool is_open = TreeNodeBehavior(id, flags, label); if (p_visible != NULL) { // Create a small overlapping close button From c2a3d5e47b08d7900b0fc7a12f1761510022a4d8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Jul 2024 22:34:34 +0200 Subject: [PATCH 037/136] Comments, minor tweaks to ImGuiTextFilter. --- docs/CHANGELOG.txt | 9 +++++---- imgui.cpp | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9fbd8b4f2..1c4bd71a1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,10 +50,11 @@ Breaking changes: You should never need those functions! You can do everything in less a confusing manner by only using GetCursorScreenPos() and GetContentRegionAvail(). Also always consider that if you are using GetWindowPos() and GetCursorPos() you may also be making things unnecessarily complicated. - I repeat: You can do everything with GetCursorScreenPos() and GetContentRegionAvail()!! - - GetWindowContentRegionMax().x - GetCursorPos().x --> GetContentRegionAvail().x - - GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x - - GetContentRegionMax() --> GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in weird local coordinates + I repeat: You can do everything with GetCursorScreenPos() and GetContentRegionAvail()! + - GetWindowContentRegionMax().x - GetCursorPos().x --> GetContentRegionAvail().x + - GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window + - GetContentRegionMax() --> GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates + - GetWindowContentRegionMax().x - GetWindowContentRegionMin().x --> GetContentRegionAvail() // when called from left edge of window - Item flag changes: - Obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_ButtonRepeat. Kept inline redirecting functions (will obsolete). diff --git a/imgui.cpp b/imgui.cpp index 6b545d67d..6bd0c052a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -435,9 +435,11 @@ CODE - instead of: GetWindowContentRegionMax().x - GetCursorPos().x - you can use: GetContentRegionAvail().x - instead of: GetWindowContentRegionMax().x + GetWindowPos().x - - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x (from left edge of window) + - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window - instead of: GetContentRegionMax() - - you cna use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in weird local coordinates + - you can use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates + - instead of: GetWindowContentRegionMax().x - GetWindowContentRegionMin().x + - you can use: GetContentRegionAvail() // when called from left edge of window - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573) (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors) - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag(). @@ -2753,11 +2755,11 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const return true; if (text == NULL) - text = ""; + text = text_end = ""; for (const ImGuiTextRange& f : Filters) { - if (f.empty()) + if (f.b == f.e) continue; if (f.b[0] == '-') { From ce3a8d7c79f2490b7db1a55f19030654f9a6f600 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Aug 2023 11:26:19 +0200 Subject: [PATCH 038/136] Demo: MultiSelect: added tree demo. (#6990, #3823, #1861) --- imgui_demo.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index eba615e12..08798e181 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -262,13 +262,14 @@ void* GImGuiDemoMarkerCallbackUserData = NULL; struct ExampleTreeNode { // Tree structure - char Name[28]; + char Name[28] = ""; int UID = 0; ExampleTreeNode* Parent = NULL; ImVector Childs; + unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily // Leaf Data - bool HasData = false; // All leaves have data + bool HasData = false; // All leaves have data bool DataMyBool = true; int DataMyInt = 128; ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); @@ -298,6 +299,7 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); node->UID = uid; node->Parent = parent; + node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0; if (parent) parent->Childs.push_back(node); return node; @@ -3442,6 +3444,160 @@ static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) ImGui::TreePop(); } + // Demonstrate supporting multiple-selection in a tree. + // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly! + // This showcase how SetNextItemSelectionUserData() never assume indices! + // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request. + // We want this interpolation to match what the user sees: in visible order, skipping closed nodes. + // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper. + // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you + // are more likely to build an array mapping sequential indices to visible tree nodes, since your + // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier. + // - Consider this a prototype: we are working toward simplifying some of it. + IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)"); + if (ImGui::TreeNode("Multi-Select (trees)")) + { + HelpMarker( + "This is rather advanced and experimental. If you are getting started with multi-select," + "please don't start by looking at how to use it for a tree!\n\n" + "Future versions will try to simplify and formalize some of this."); + + struct ExampleTreeFuncs + { + static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection) + { + ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent + if (node->Childs.Size == 0) + tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf; + if (selection->Contains((ImGuiID)node->UID)) + tree_node_flags |= ImGuiTreeNodeFlags_Selected; + + // Using SetNextItemStorageID() to specify storage id, so we can easily peek into + // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions. + ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node); + ImGui::SetNextItemStorageID((ImGuiID)node->UID); + if (ImGui::TreeNodeEx(node->Name, tree_node_flags)) + { + for (ExampleTreeNode* child : node->Childs) + DrawNode(child, selection); + ImGui::TreePop(); + } + else if (ImGui::IsItemToggledOpen()) + { + TreeCloseAndUnselectChildNodes(node, selection); + } + } + + static bool TreeNodeGetOpen(ExampleTreeNode* node) + { + return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID); + } + + static void TreeNodeSetOpen(ExampleTreeNode* node, bool open) + { + ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open); + } + + // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected. + // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node + // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc. + static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0) + { + // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!) + int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0; + if (depth == 0 || TreeNodeGetOpen(node)) + { + for (ExampleTreeNode* child : node->Childs) + unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1); + TreeNodeSetOpen(node, false); + } + + // Select root node if any of its child was selected, otherwise unselect + selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0)); + return unselected_count; + } + + // Apply multi-selection requests + static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection) + { + for (ImGuiSelectionRequest& req : ms_io->Requests) + { + if (req.Type == ImGuiSelectionRequestType_SetAll) + { + if (req.Selected) + TreeSetAllInOpenNodes(tree, selection, req.Selected); + else + selection->Clear(); + } + else if (req.Type == ImGuiSelectionRequestType_SetRange) + { + ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem; + ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem; + for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node)) + selection->SetItemSelected((ImGuiID)node->UID, req.Selected); + } + } + } + + static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected) + { + if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme + selection->SetItemSelected((ImGuiID)node->UID, selected); + if (node->Parent == NULL || TreeNodeGetOpen(node)) + for (ExampleTreeNode* child : node->Childs) + TreeSetAllInOpenNodes(child, selection, selected); + } + + // Interpolate in *user-visible order* AND only *over opened nodes*. + // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler. + // Here the tricks are that: + // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion. + // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)' + // which would only be called when crossing from child to a parent, aka not too much. + // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack, + // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location. + static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node) + { + // Reached last node + if (curr_node == last_node) + return NULL; + + // Recurse into childs. Query storage to tell if the node is open. + if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node)) + return curr_node->Childs[0]; + + // Next sibling, then into our own parent + while (curr_node->Parent != NULL) + { + if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size) + return curr_node->Parent->Childs[curr_node->IndexInParent + 1]; + curr_node = curr_node->Parent; + } + return NULL; + } + + }; // ExampleTreeFuncs + + static ImGuiSelectionBasicStorage selection; + static ExampleTreeNode* tree = ExampleTree_CreateDemoTree(); // Create tree once + ImGui::Text("Selection size: %d", selection.Size); + + if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) + { + ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d; + ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1); + ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); + for (ExampleTreeNode* node : tree->Childs) + ExampleTreeFuncs::DrawNode(node, &selection); + ms_io = ImGui::EndMultiSelect(); + ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); + } + ImGui::EndChild(); + + ImGui::TreePop(); + } + // Advanced demonstration of BeginMultiSelect() // - Showcase clipping. // - Showcase deletion. From 1f634f1d94e16feb3d0b15ad79e8bc44cccc184d Mon Sep 17 00:00:00 2001 From: SPeak Date: Tue, 30 Jul 2024 05:55:02 +0800 Subject: [PATCH 039/136] Eaxmples: Android: Fix build failed issue. (#7832) set android:exported to true (IntentFilter) Signed-off-by: Sunrisepeak --- .../android/app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml b/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml index a87b95b4f..5a1e2d9e5 100644 --- a/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml +++ b/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:name="imgui.example.android.MainActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:configChanges="orientation|keyboardHidden|screenSize" - android:exported="false"> + android:exported="true"> From 1b44e4044491b96c7bc30989f8d8c356bc57bada Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Jul 2024 11:44:13 +0200 Subject: [PATCH 040/136] Demo: re-use tree data. Fix property editor vertical alignment. Tweak recent memory allocation monitor. --- imgui.cpp | 7 +++- imgui_demo.cpp | 93 +++++++++++++++++++++++++++----------------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6bd0c052a..97ee6fe1a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15070,7 +15070,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int n = buf_size - 1; n >= 0; n--) { ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[(info->LastEntriesIdx - n + buf_size) % buf_size]; - BulletText("Frame %06d: %+3d ( %2d malloc, %2d free )%s", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount, (n == 0) ? " (most recent)" : ""); + BulletText("Frame %06d: %+3d ( %2d alloc, %2d free )", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount); + if (n == 0) + { + SameLine(); + Text("<- %d frames ago", g.FrameCount - entry->FrameCount); + } } TreePop(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 08798e181..a5f7408c2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -199,6 +199,7 @@ Index of this file: #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Forward Declarations +struct ImGuiDemoWindowData; static void ShowExampleAppMainMenuBar(); static void ShowExampleAppAssetsBrowser(bool* p_open); static void ShowExampleAppConsole(bool* p_open); @@ -206,7 +207,7 @@ static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleAppDocuments(bool* p_open); static void ShowExampleAppLog(bool* p_open); static void ShowExampleAppLayout(bool* p_open); -static void ShowExampleAppPropertyEditor(bool* p_open); +static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); static void ShowExampleAppSimpleOverlay(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open); @@ -217,10 +218,9 @@ static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) -struct DemoWindowData; -static void ShowDemoWindowMenuBar(DemoWindowData* demo_data); -static void ShowDemoWindowWidgets(DemoWindowData* demo_data); -static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data); +static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data); +static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data); +static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data); static void ShowDemoWindowLayout(); static void ShowDemoWindowPopups(); static void ShowDemoWindowTables(); @@ -309,13 +309,14 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl // (this allocates _many_ more times than most other code in either Dear ImGui or others demo) static ExampleTreeNode* ExampleTree_CreateDemoTree() { - static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; char name_buf[32]; int uid = 0; ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); - for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * 2; idx_L0++) + const int root_items_multiplier = 2; + for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) { - snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / 2], idx_L0 % 2); + snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); const int number_of_childs = (int)strlen(node_L1->Name); for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) @@ -338,7 +339,8 @@ static ExampleTreeNode* ExampleTree_CreateDemoTree() // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- -struct DemoWindowData +// Data to be shared accross different functions of the demo. +struct ImGuiDemoWindowData { // Examples Apps (accessible from the "Examples" menu) bool ShowMainMenuBar = false; @@ -362,6 +364,9 @@ struct DemoWindowData bool ShowIDStackTool = false; bool ShowStyleEditor = false; bool ShowAbout = false; + + // Other data + ExampleTreeNode* DemoTree = NULL; }; // Demonstrate most Dear ImGui features (this is big function!) @@ -377,32 +382,32 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_CHECKVERSION(); // Stored data - static DemoWindowData demo; + static ImGuiDemoWindowData demo_data; // Examples Apps (accessible from the "Examples" menu) - if (demo.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } - if (demo.ShowAppDocuments) { ShowExampleAppDocuments(&demo.ShowAppDocuments); } - if (demo.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo.ShowAppAssetsBrowser); } - if (demo.ShowAppConsole) { ShowExampleAppConsole(&demo.ShowAppConsole); } - if (demo.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo.ShowAppCustomRendering); } - if (demo.ShowAppLog) { ShowExampleAppLog(&demo.ShowAppLog); } - if (demo.ShowAppLayout) { ShowExampleAppLayout(&demo.ShowAppLayout); } - if (demo.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo.ShowAppPropertyEditor); } - if (demo.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo.ShowAppSimpleOverlay); } - if (demo.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo.ShowAppAutoResize); } - if (demo.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo.ShowAppConstrainedResize); } - if (demo.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo.ShowAppFullscreen); } - if (demo.ShowAppLongText) { ShowExampleAppLongText(&demo.ShowAppLongText); } - if (demo.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo.ShowAppWindowTitles); } + if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } + if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } + if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); } + if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); } + if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); } + if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); } + if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); } + if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); } + if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); } + if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); } + if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); } + if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); } + if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); } + if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); } // Dear ImGui Tools (accessible from the "Tools" menu) - if (demo.ShowMetrics) { ImGui::ShowMetricsWindow(&demo.ShowMetrics); } - if (demo.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo.ShowDebugLog); } - if (demo.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo.ShowIDStackTool); } - if (demo.ShowAbout) { ImGui::ShowAboutWindow(&demo.ShowAbout); } - if (demo.ShowStyleEditor) + if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); } + if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); } + if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); } + if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); } + if (demo_data.ShowStyleEditor) { - ImGui::Begin("Dear ImGui Style Editor", &demo.ShowStyleEditor); + ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor); ImGui::ShowStyleEditor(); ImGui::End(); } @@ -452,7 +457,7 @@ void ImGui::ShowDemoWindow(bool* p_open) //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) // Menu Bar - ShowDemoWindowMenuBar(&demo); + ShowDemoWindowMenuBar(&demo_data); ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); @@ -573,7 +578,7 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Configuration/Style"); if (ImGui::TreeNode("Style")) { - ImGui::Checkbox("Style Editor", &demo.ShowStyleEditor); + ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor); ImGui::SameLine(); HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::TreePop(); @@ -621,7 +626,7 @@ void ImGui::ShowDemoWindow(bool* p_open) } // All demo contents - ShowDemoWindowWidgets(&demo); + ShowDemoWindowWidgets(&demo_data); ShowDemoWindowLayout(); ShowDemoWindowPopups(); ShowDemoWindowTables(); @@ -636,7 +641,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // [SECTION] ShowDemoWindowMenuBar() //----------------------------------------------------------------------------- -static void ShowDemoWindowMenuBar(DemoWindowData* demo_data) +static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Menu"); if (ImGui::BeginMenuBar()) @@ -701,7 +706,7 @@ static void ShowDemoWindowMenuBar(DemoWindowData* demo_data) // [SECTION] ShowDemoWindowWidgets() //----------------------------------------------------------------------------- -static void ShowDemoWindowWidgets(DemoWindowData* demo_data) +static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets"); //ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -3098,7 +3103,7 @@ struct ExampleDualListBox // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- -static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) +static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) @@ -3580,11 +3585,13 @@ static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) }; // ExampleTreeFuncs static ImGuiSelectionBasicStorage selection; - static ExampleTreeNode* tree = ExampleTree_CreateDemoTree(); // Create tree once + if (demo_data->DemoTree == NULL) + demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once ImGui::Text("Selection size: %d", selection.Size); if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { + ExampleTreeNode* tree = demo_data->DemoTree; ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d; ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1); ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); @@ -4597,8 +4604,8 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Layout/Clipping"); - if (ImGui::TreeNode("Clipping")) + IMGUI_DEMO_MARKER("Layout/Text Clipping"); + if (ImGui::TreeNode("Text Clipping")) { static ImVec2 size(100.0f, 100.0f); static ImVec2 offset(30.0f, 30.0f); @@ -8868,6 +8875,7 @@ struct ExampleAppPropertyEditor ImGui::TableNextRow(); ImGui::PushID(field_desc.Name); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted(field_desc.Name); ImGui::TableNextColumn(); void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); @@ -8933,7 +8941,7 @@ struct ExampleAppPropertyEditor }; // Demonstrate creating a simple property editor. -static void ShowExampleAppPropertyEditor(bool* p_open) +static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data) { ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Property editor", p_open)) @@ -8944,8 +8952,9 @@ static void ShowExampleAppPropertyEditor(bool* p_open) IMGUI_DEMO_MARKER("Examples/Property Editor"); static ExampleAppPropertyEditor property_editor; - static ExampleTreeNode* tree_data = ExampleTree_CreateDemoTree(); - property_editor.Draw(tree_data); + if (demo_data->DemoTree == NULL) + demo_data->DemoTree = ExampleTree_CreateDemoTree(); + property_editor.Draw(demo_data->DemoTree); ImGui::End(); } From ec9a4ef487acde06cf1840b1b13310a6c0ba7d62 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Jul 2024 12:22:29 +0200 Subject: [PATCH 041/136] Clipper: accept that no item have been submitted if in indeterminate Begin(INT_MAX) mode. (#1311, #3823) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 97ee6fe1a..728fc0832 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3062,7 +3062,8 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); if (affected_by_floating_point_precision) clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. - + if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode. + return false; IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. } From 8199457a7d9e453f8d3d9cadc14683fb54a858b5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Jul 2024 14:49:07 +0200 Subject: [PATCH 042/136] Version 1.91.0 --- docs/CHANGELOG.txt | 110 ++++++++++++++++++++++++--------------------- imgui.cpp | 4 +- imgui.h | 22 ++++----- imgui_demo.cpp | 4 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 78 insertions(+), 70 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1c4bd71a1..8c83dadff 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,9 +36,11 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.0 WIP (In Progress) + VERSION 1.91.0 (Released 2024-07-30) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.0 + Breaking changes: - IO, IME: renamed platform IME hook and added explicit context for consistency and future-proofness. @@ -46,7 +48,7 @@ Breaking changes: - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); It is expected that for a vast majority of users this is automatically set by core library and/or platform backend so it won't have any effect. -- Obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). +- Obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (#7838) You should never need those functions! You can do everything in less a confusing manner by only using GetCursorScreenPos() and GetContentRegionAvail(). Also always consider that if you are using GetWindowPos() and GetCursorPos() you may also be making things unnecessarily complicated. @@ -69,32 +71,24 @@ Breaking changes: - Commented out obsolete ImGuiModFlags_XXX values (renamed to ImGuiMod_XXX in 1.89). (#4921, #456) - ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl, ImGuiModFlags_Shift -> ImGuiMod_Shift etc. - Backends: GLFW+Emscripten: Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to - ImGui_ImplGlfw_InstallEmscriptenCallbacks(), with additional GLFWWindow* parameter. (#7647) [@ypujante] + ImGui_ImplGlfw_InstallEmscriptenCallbacks(), with an additional GLFWWindow* parameter. (#7647) [@ypujante] Other changes: - Added TextLink(), TextLinkOpenURL() hyperlink widgets. (#7660) - IO: added io.PlatformOpenInShellFn handler to open a link/folder/file in OS shell. (#7660) - Default to use ShellExecute() under Windows, and system("") under Mac/Linux/etc. - Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default implementation. -- IO: added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match tye + Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default Windows/Linux/Mac implementations. +- IO: added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match the typical "Nintendo/Japanese consoles" button layout when using Gamepad navigation. (#787, #5723) - Added PushItemFlag()/PopItemFlags(), ImGuiItemFlags to modify shared item flags: - - Added ImGuiItemFlags_NoTabStop to disable tabbing through items. - - Added ImGuiItemFlags_NoNav to disable any navigation and focus of items. (#787) - - Added ImGuiItemFlags_NoNavDefaultFocus to disable item being default focus. (#787) - - Added ImGuiItemFlags_ButtonRepeat to enable repeat on any button-like behavior. - - Added ImGuiItemFlags_AutoClosePopups to disable menu items/selection auto closing parent popups. - Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). - (#1379, #1468, #2200, #4936, #5216, #7302, #7573) - - This was mostly all previously in imgui_internal.h. -- Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. This is a simplified version of a more - complete set of function available in imgui_internal.h. One common use-case for this is to allow - your items to disable standard inputs behaviors such as Tab or Alt handling, Mouse Wheel scrolling, - etc. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) - // Hovering or activating the button will disable mouse wheel default behavior to scroll - InvisibleButton(...); - SetItemKeyOwner(ImGuiKey_MouseWheelY); + - Added ImGuiItemFlags_NoTabStop to disable tabbing through items. + - Added ImGuiItemFlags_NoNav to disable any navigation and focus of items. (#787) + - Added ImGuiItemFlags_NoNavDefaultFocus to disable item being default focus. (#787) + - Added ImGuiItemFlags_ButtonRepeat to enable repeat on any button-like behavior. + - Added ImGuiItemFlags_AutoClosePopups to disable menu items/selection auto closing parent popups. + Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). + (#1379, #1468, #2200, #4936, #5216, #7302, #7573) + - This was mostly all previously in imgui_internal.h. - Multi-Select: added multi-select API and demos. (#1861, #6518) - This system implements standard multi-selection idioms (CTRL+mouse click, CTRL+keyboard moves, SHIFT+mouse click, SHIFT+keyboard moves, etc.) with support for clipper (not submitting non-visible @@ -103,15 +97,16 @@ Other changes: This is designed to allow all kinds of selection storage you may use in your application (e.g. set/map/hash, intrusive selection, interval trees, up to you). - The supported widgets are Selectable(), Checkbox(). TreeNode() is also technically supported but... - using this correctly is more complicated (you need some sort of linear/random access to your tree, + using this correctly is more complicated. You need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. - We will work toward simplifying and demoing this later. - - A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app. + We will work toward simplifying our existing demo for trees. + - A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app + (likely to suit a majority of users). - Documentation: - Wiki page https://github.com/ocornut/imgui/wiki/Multi-Select for API overview. - Demo code + headers are well commented. - Added BeginMultiSelect(), EndMultiSelect(), SetNextItemSelectionUserData(). - - Added IsItemToggledSelection() for use if you need latest selection update during currnet iteration. + - Added IsItemToggledSelection() for use if you need latest selection update during current iteration. - Added ImGuiMultiSelectIO and ImGuiSelectionRequest structures: - BeginMultiSelect() and EndMultiSelect() return a ImGuiMultiSelectIO structure, which is mostly an array of ImGuiSelectionRequest actions (clear, select all, set range, etc.) @@ -142,12 +137,23 @@ Other changes: - Multi-Select (with clipper) - Multi-Select (with deletion) - Multi-Select (dual list box) (#6648) + - Multi-Select (in a table) - Multi-Select (checkboxes) - Multi-Select (multiple scopes) + - Multi-Select (tiled assert browser) + - Multi-Select (trees) (#1861) - Multi-Select (advanced) +- Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. + This is a simplified version of a more complete set of function available in imgui_internal.h. + One common use-case for this is to allow your widgets to disable standard inputs behaviors such + as Tab or Alt handling, Mouse Wheel scrolling, etc. + (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) + // Hovering or activating the button will disable mouse wheel default behavior to scroll + InvisibleButton(...); + SetItemKeyOwner(ImGuiKey_MouseWheelY); - Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened. -- InputText: added '\' and '/' as word seperator. (#7824, #7704) [@reduf] +- InputText: added '\' and '/' as word separator. (#7824, #7704) [@reduf] - TreeNode: added SetNextItemStorageID() to specify/override the identifier used for persisting open/close storage. Useful if needing to often read/write from storage without manipulating the ID stack. (#7553, #6990, #3823, #1131) @@ -155,35 +161,37 @@ Other changes: the hovered state. (#7820) [@rerilier] - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can can use the clipper without knowing the amount of items beforehand. (#1311) - In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration + In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) at the end of your iteration loop to position the layout cursor correctly. This is done automatically if provided a count to Begin(). - Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (#7543) -- TabBar, Style: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate - thickness of the horizontal line over selectable tabs. [@DctrNoob] -- Misc: added GetID(int) variant for consistency. (#7111) +- Style, TabBar: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate + thickness of the horizontal line over selected tabs. [@DctrNoob] - Style: close button and collapse/window-menu button hover highlight made rectangular instead of round. -- Debug Tools: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) - Debug log entries add a imgui frame counter prefix + are redirected to ShowDebugLogWindow() and - other configurable locations. Always call IMGUI_DEBUG_LOG() for maximum stripping in caller code. -- Debug Tools: Debug Log: Added "Configure Outputs.." button. (#5855) -- Debug Tools: Debug Log: Fixed incorrect checkbox layout when partially clipped. -- Demo: Reworked "Property Editor" demo in a manner that more ressemble the tree data and +- Misc: added GetID(int) variant for consistency. (#7111) +- Debug Tools: + - Debug Log: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) + Printed entries include imgui frame counter prefix + are redirected to ShowDebugLogWindow() and + other configurable locations. Always call IMGUI_DEBUG_LOG() for maximum stripping in caller code. + - Debug Log: Added "Configure Outputs.." button. (#5855) + - Debug Log: Fixed incorrect checkbox layout when partially clipped. +- Demo: Reworked "Property Editor" demo in a manner that more resemble the tree data and struct description data that a real application would want to use. -- Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. - (#7768, #4858, #2622) [@Aemony] -- Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (#7807) -- Backends: SDL3: Update for API changes: SDL_GetClipboardText() memory ownership change. (#7801) -- Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762) -- Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) [@wermipls] -- Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. -- Backends: GLFW,SDL2: Added io.PlatformOpenInShellFn handler for web/Emscripten versions. (#7660) - [@ypujante, @ocornut] -- Backends; GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things - not supported by the embedded GLFW: gamepad support, mouse cursor shapes, copy to clipboard, - workaround for Super/Meta key, different ways of resizing, multi-window (glfw/canvas) support. - (#7647) [@ypujante] -- Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups - "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante] +- Backends: + - Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of (VK_LWIN || VK_RWIN). + (#7768, #4858, #2622) [@Aemony] + - Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (#7807) + - Backends: SDL3: Update for API changes: SDL_GetClipboardText() memory ownership change. (#7801) + - Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762) + - Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) [@wermipls] + - Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. + - Backends: GLFW,SDL2: Added io.PlatformOpenInShellFn handler for web/Emscripten versions. (#7660) + [@ypujante, @ocornut] + - Backends; GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things + not supported by the embedded GLFW: gamepad support, mouse cursor shapes, copy to clipboard, + workaround for Super/Meta key, different ways of resizing, multi-window (glfw/canvas) support. + (#7647) [@ypujante] + - Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups + "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante] ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 728fc0832..2c8611266 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (main code and documentation) // Help: @@ -430,7 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). + - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way. - instead of: GetWindowContentRegionMax().x - GetCursorPos().x - you can use: GetContentRegionAvail().x diff --git a/imgui.h b/imgui.h index 898308bb5..05e48a175 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (headers) // Help: @@ -27,8 +27,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.0 WIP" -#define IMGUI_VERSION_NUM 19099 +#define IMGUI_VERSION "1.91.0" +#define IMGUI_VERSION_NUM 19100 #define IMGUI_HAS_TABLE /* @@ -480,7 +480,7 @@ namespace ImGui IMGUI_API void SetCursorPos(const ImVec2& local_pos); // [window-local] " IMGUI_API void SetCursorPosX(float local_x); // [window-local] " IMGUI_API void SetCursorPosY(float local_y); // [window-local] " - IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates + IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates. Call GetCursorScreenPos() after Begin() to get the absolute coordinates version. // Other layout functions IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. @@ -669,12 +669,12 @@ namespace ImGui IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. - // Multi-selection system for Selectable(), Checkbox() functions* + // Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA] // - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used. // - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else). // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo. - // - (*) TreeNode() is technically supported but... using this correctly is more complicate: you need some sort of linear/random access to your tree, - // which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this. + // - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of linear/random access to your tree, + // which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the current demo. // - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them. IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, int items_count = -1); IMGUI_API ImGuiMultiSelectIO* EndMultiSelect(); @@ -2781,10 +2781,10 @@ enum ImGuiMultiSelectFlags_ ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all. ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests. - ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes) - ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes) - ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item - ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. only full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. + ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes). + ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes). + ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item. + ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. ImGuiMultiSelectFlags_BoxSelect2d = 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items. ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope. ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a5f7408c2..4d6c2bbf2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (demo code) // Help: @@ -3621,7 +3621,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) static bool use_deletion = true; static bool use_drag_drop = true; static bool show_in_table = false; - static bool show_color_button = false; + static bool show_color_button = true; static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; static WidgetType widget_type = WidgetType_Selectable; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 69e4f854c..57486a6e2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 7e9b22607..ab43922ba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 9c8262ff8..37dd70304 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8e35df662..2aa24efe8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 WIP +// dear imgui, v1.91.0 // (widgets code) /* From dcf54782d4be1070bab4821f06cdaf9181bfc528 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 31 Jul 2024 16:34:08 +0200 Subject: [PATCH 043/136] Version 1.91.WIP --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8c83dadff..877cd8584 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.1 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.91.0 (Released 2024-07-30) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 2c8611266..94c59e7ea 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 05e48a175..5b22dfe71 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (headers) // Help: @@ -27,8 +27,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.0" -#define IMGUI_VERSION_NUM 19100 +#define IMGUI_VERSION "1.91.1 WIP" +#define IMGUI_VERSION_NUM 19101 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4d6c2bbf2..2800e9518 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 57486a6e2..854ad4012 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index ab43922ba..0e39b0874 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 37dd70304..92c62949e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2aa24efe8..5ca9a9d3c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.0 +// dear imgui, v1.91.1 WIP // (widgets code) /* From 887478793b8f61c5385131d823dbb8ad8e8e900f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 31 Jul 2024 16:55:17 +0200 Subject: [PATCH 044/136] Examples: SDL2 (all), SDL3 (all), Win32+OpenGL3: Rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) --- docs/CHANGELOG.txt | 4 ++++ examples/example_sdl2_directx11/main.cpp | 5 +++++ examples/example_sdl2_opengl2/main.cpp | 5 +++++ examples/example_sdl2_opengl3/main.cpp | 5 +++++ examples/example_sdl2_sdlrenderer2/main.cpp | 5 +++++ examples/example_sdl2_vulkan/main.cpp | 5 +++++ examples/example_sdl3_opengl3/main.cpp | 5 +++++ examples/example_sdl3_sdlrenderer3/main.cpp | 5 +++++ examples/example_win32_opengl3/main.cpp | 5 +++++ 9 files changed, 44 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 877cd8584..7c0eb2050 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,10 @@ Breaking changes: Other changes: +- Examples: SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle + minimization without burning CPU or GPU by running unthrottled code. (#7844) + + ----------------------------------------------------------------------- VERSION 1.91.0 (Released 2024-07-30) diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index 3275bafde..47c852d27 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -126,6 +126,11 @@ int main(int, char**) CreateRenderTarget(); } } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplDX11_NewFrame(); diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index efb28edbc..a70edd225 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -105,6 +105,11 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL2_NewFrame(); diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index d748c1360..2a4d7b9e7 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -140,6 +140,11 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index 8bb309920..b186b6268 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -107,6 +107,11 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplSDLRenderer2_NewFrame(); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index afcebf1b9..cb116b76e 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -492,6 +492,11 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Resize swap chain? int fb_width, fb_height; diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index c4eee77d4..e6aba8809 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -136,6 +136,11 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 607d00b6b..951141548 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -111,6 +111,11 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplSDLRenderer3_NewFrame(); diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 594931dca..8ecd27a20 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -108,6 +108,11 @@ int main(int, char**) } if (done) break; + if (::IsIconic(hwnd)) + { + ::Sleep(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); From 71ee2ce3673c8182871cb0b8554f9caf089a5334 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 31 Jul 2024 17:33:24 +0200 Subject: [PATCH 045/136] Examples: GLFW: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper. --- backends/imgui_impl_glfw.cpp | 14 ++++++++++++++ backends/imgui_impl_glfw.h | 3 +++ docs/CHANGELOG.txt | 6 ++++-- examples/example_glfw_opengl2/main.cpp | 5 +++++ examples/example_glfw_opengl3/main.cpp | 5 +++++ examples/example_glfw_vulkan/main.cpp | 5 +++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 305891624..df581537b 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one. // 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter. // 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. @@ -99,6 +100,9 @@ #endif #include // for glfwGetCocoaWindow() #endif +#ifndef _WIN32 +#include // for usleep() +#endif #ifdef __EMSCRIPTEN__ #include @@ -825,6 +829,16 @@ void ImGui_ImplGlfw_NewFrame() ImGui_ImplGlfw_UpdateGamepads(); } +// GLFW doesn't provide a portable sleep function +void ImGui_ImplGlfw_Sleep(int milliseconds) +{ +#ifdef _WIN32 + ::Sleep(milliseconds); +#else + usleep(milliseconds * 1000); +#endif +} + #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data) { diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index c0eac1134..60b95bd99 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -57,4 +57,7 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event); +// GLFW helpers +IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds); + #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7c0eb2050..b265121e3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,8 +43,10 @@ Breaking changes: Other changes: -- Examples: SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle - minimization without burning CPU or GPU by running unthrottled code. (#7844) +- Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not + provide a way to do a portable sleep. (#7844) +- Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop + to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 5e47b0008..1fcec2b2a 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -91,6 +91,11 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); + if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) + { + ImGui_ImplGlfw_Sleep(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL2_NewFrame(); diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 22ef79eb7..3afe251e3 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -127,6 +127,11 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); + if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) + { + ImGui_ImplGlfw_Sleep(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index e1f099e3d..901b46c4c 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -494,6 +494,11 @@ int main(int, char**) g_MainWindowData.FrameIndex = 0; g_SwapChainRebuild = false; } + if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) + { + ImGui_ImplGlfw_Sleep(10); + continue; + } // Start the Dear ImGui frame ImGui_ImplVulkan_NewFrame(); From fd57b252ac1932760160947ca82b55b884f92600 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 31 Jul 2024 17:47:38 +0200 Subject: [PATCH 046/136] Examples: Fix for Emscripten. GLFW+WGPU: rework examples main loop to handle minimization. (#7844) Amend 8874787, 71ee2ce Amend ea39841f (emscripten_mainloop_stub.h) --- examples/example_glfw_wgpu/main.cpp | 5 +++++ examples/example_sdl3_sdlrenderer3/main.cpp | 3 +++ examples/libs/emscripten/emscripten_mainloop_stub.h | 7 ++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index c5872bd85..f510987ed 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -151,6 +151,11 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); + if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) + { + ImGui_ImplGlfw_Sleep(10); + continue; + } // React to changes in screen size int width, height; diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 951141548..6efd2754a 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -167,6 +167,9 @@ int main(int, char**) ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); SDL_RenderPresent(renderer); } +#ifdef __EMSCRIPTEN__ + EMSCRIPTEN_MAINLOOP_END; +#endif // Cleanup ImGui_ImplSDLRenderer3_Shutdown(); diff --git a/examples/libs/emscripten/emscripten_mainloop_stub.h b/examples/libs/emscripten/emscripten_mainloop_stub.h index 05cf60fed..8c4c48ecf 100644 --- a/examples/libs/emscripten/emscripten_mainloop_stub.h +++ b/examples/libs/emscripten/emscripten_mainloop_stub.h @@ -17,20 +17,21 @@ // - So the next logical step was to refactor all examples to follow that layout of using a "main loop" function. // This worked, but it made us lose all the nice things we had... -// Since only about 3 examples really need to run with Emscripten, here's our solution: +// Since only about 4 examples really need to run with Emscripten, here's our solution: // - Use some weird macros and capturing lambda to turn a loop in main() into a function. // - Hide all that crap in this file so it doesn't make our examples unusually ugly. // As a stance and principle of Dear ImGui development we don't use C++ headers and we don't // want to suggest to the newcomer that we would ever use C++ headers as this would affect // the initial judgment of many of our target audience. // - Technique is based on this idea: https://github.com/ocornut/imgui/pull/2492/ +// - The do { } while (0) is to allow our code calling continue in the main loop. #ifdef __EMSCRIPTEN__ #include #include static std::function MainLoopForEmscriptenP; static void MainLoopForEmscripten() { MainLoopForEmscriptenP(); } -#define EMSCRIPTEN_MAINLOOP_BEGIN MainLoopForEmscriptenP = [&]() -#define EMSCRIPTEN_MAINLOOP_END ; emscripten_set_main_loop(MainLoopForEmscripten, 0, true) +#define EMSCRIPTEN_MAINLOOP_BEGIN MainLoopForEmscriptenP = [&]() { do +#define EMSCRIPTEN_MAINLOOP_END while (0); }; emscripten_set_main_loop(MainLoopForEmscripten, 0, true) #else #define EMSCRIPTEN_MAINLOOP_BEGIN #define EMSCRIPTEN_MAINLOOP_END From 5e7dc72c926b489450e9ea82ea62fd3a6432d5aa Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Thu, 1 Aug 2024 00:04:34 +0200 Subject: [PATCH 047/136] Examples: SDL3: Update readme to use SDL3_DIR (#7846) --- examples/example_sdl3_opengl3/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example_sdl3_opengl3/README.md b/examples/example_sdl3_opengl3/README.md index 5828e4bfc..a032f8752 100644 --- a/examples/example_sdl3_opengl3/README.md +++ b/examples/example_sdl3_opengl3/README.md @@ -9,11 +9,11 @@ Use the provided project file (.vcxproj). Add to solution (imgui_examples.sln) i Use build_win32.bat or directly: ``` -set SDL2_DIR=path_to_your_sdl3_folder -cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL3.lib opengl32.lib /subsystem:console +set SDL3_DIR=path_to_your_sdl3_folder +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x86 SDL3.lib opengl32.lib /subsystem:console # ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries # or for 64-bit: -cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL3.lib SDL2mainopengl32.lib /subsystem:console +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x64 SDL3.lib SDL2mainopengl32.lib /subsystem:console ``` ## Linux and similar Unixes From 2981a10c537cbc329e5b4e58af1e1a1146d55ea4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 17:16:13 +0200 Subject: [PATCH 048/136] MultiSelect, TreeNode, Drag and Drop: fixed an issue where carrying a drag and drop payload over an already open tree node would select it. (#7850) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b265121e3..3f0d9c4ea 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- MultiSelect, TreeNode, Drag and Drop: fixed an issue where carrying a drag and drop + payload over an already open tree node would incorrectly select it. (#7850) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5ca9a9d3c..0f0134b9d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6531,6 +6531,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. toggled = true; + else + pressed = false; // Cancel press so it doesn't trigger selection. } if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) From 9f8f5e11455e87cce4ebdefa422661951701dfae Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 17:28:47 +0200 Subject: [PATCH 049/136] MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) --- docs/CHANGELOG.txt | 4 +++- imgui.h | 4 ++-- imgui_internal.h | 1 + imgui_widgets.cpp | 14 +++++++------- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3f0d9c4ea..a495cd5d3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,8 +43,10 @@ Breaking changes: Other changes: -- MultiSelect, TreeNode, Drag and Drop: fixed an issue where carrying a drag and drop +- MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload over an already open tree node would incorrectly select it. (#7850) +- MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow + when used in a multi-select context without any OpenOnXXX flags set. (#7850) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop diff --git a/imgui.h b/imgui.h index 5b22dfe71..6d4f51388 100644 --- a/imgui.h +++ b/imgui.h @@ -1177,8 +1177,8 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open - ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node - ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag! ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node. diff --git a/imgui_internal.h b/imgui_internal.h index 0e39b0874..5b6d4c195 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -970,6 +970,7 @@ enum ImGuiTreeNodeFlagsPrivate_ { ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader() ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, but reversed trees (#6517) + ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow, }; enum ImGuiSeparatorFlags_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0f0134b9d..11f1cdf60 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6475,6 +6475,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); + const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; + if (is_multi_select) // We absolutely need to distinguish open vs select so _OpenOnArrow comes by default + flags |= (flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick : ImGuiTreeNodeFlags_OpenOnArrow; + // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) @@ -6495,16 +6499,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool was_selected = selected; // Multi-selection support (header) - const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (is_multi_select) { // Handle multi-select + alter button flags for it MultiSelectItemHeader(id, &selected, &button_flags); if (is_mouse_x_over_arrow) button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease; - - // We absolutely need to distinguish open vs select so comes by default - flags |= ImGuiTreeNodeFlags_OpenOnArrow; } else { @@ -6519,12 +6519,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { if (pressed && g.DragDropHoldJustPressedId != id) { - if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id && !is_multi_select)) - toggled = true; + if ((flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 || (g.NavActivateId == id && !is_multi_select)) + toggled = true; // Single click if (flags & ImGuiTreeNodeFlags_OpenOnArrow) toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) - toggled = true; + toggled = true; // Double click } else if (pressed && g.DragDropHoldJustPressedId == id) { From 531364d72896f41c973730c2fbc0478da4ba64c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 22:26:12 +0200 Subject: [PATCH 050/136] Window refresh policy: fixed child window of skiprefresh windows not displaying. (#7797) Amend d4495446d. (#3515, #4763, #7556, #5116 , #4076, #2749, #2268) --- imgui.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 94c59e7ea..edbf15069 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6531,6 +6531,17 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) } } +static void SetWindowActiveForSkipRefresh(ImGuiWindow* window) +{ + window->Active = true; + for (ImGuiWindow* child : window->DC.ChildWindows) + if (!child->Hidden) + { + child->Active = child->SkipRefresh = true; + SetWindowActiveForSkipRefresh(child); + } +} + // When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) // should be positioned behind that modal window, unless the window was created inside the modal begin-stack. // In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. @@ -7233,7 +7244,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { // Skip refresh always mark active if (window->SkipRefresh) - window->Active = true; + SetWindowActiveForSkipRefresh(window); // Append SetCurrentWindow(window); From 6864a7f839ce78419d5db57a46c25c4216e9c712 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 22:40:09 +0200 Subject: [PATCH 051/136] Window refresh policy: extend tests to any window in the begin stack. (#7797) --- imgui.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index edbf15069..d1da2886e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6522,10 +6522,12 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) return; if (window->Hidden) // If was hidden (previous frame) return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow) - return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow) - return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow) + if (window->RootWindow == g.HoveredWindow->RootWindow || IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, window)) + return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow) + if (window->RootWindow == g.NavWindow->RootWindow || IsWindowWithinBeginStackOf(g.NavWindow->RootWindow, window)) + return; window->DrawList = NULL; window->SkipRefresh = true; } From 8cc6eee295871bc8852c12372860a50b950d3f56 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 3 Aug 2024 15:25:47 +0200 Subject: [PATCH 052/136] Fonts: amend assert when glyph range data seems incorrect. (#7856) --- imgui_draw.cpp | 5 +++-- misc/freetype/imgui_freetype.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 854ad4012..32cf64353 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2815,8 +2815,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. - IM_ASSERT(src_range[0] <= src_range[1]); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, + // or to forget to zero-terminate the glyph range array. + IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 68e38ed95..d97605b25 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -480,8 +480,9 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. - IM_ASSERT(src_range[0] <= src_range[1]); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, + // or to forget to zero-terminate the glyph range array. + IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; From 4b654db9040851228857528b44e195e358868e9a Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Tue, 6 Aug 2024 20:27:23 +0200 Subject: [PATCH 053/136] CI: Build example_sdl2_sdlrenderer2 with msbuild (#7864) --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48082d056..b223d2261 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -123,6 +123,11 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release' if: github.event_name == 'workflow_run' + - name: Build Win32 example_sdl2_sdlrenderer2 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build Win32 example_sdl2_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release' @@ -168,6 +173,11 @@ jobs: shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' + - name: Build x64 example_sdl2_sdlrenderer2 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build x64 example_sdl2_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' From 3232070d3abaec531d75e060fab14a26cb36ab55 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Aug 2024 12:47:03 +0200 Subject: [PATCH 054/136] Demo: Fixed truncation warning. (#7857) --- imgui_demo.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2800e9518..264df8af4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -310,23 +310,24 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl static ExampleTreeNode* ExampleTree_CreateDemoTree() { static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; - char name_buf[32]; + const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); + char name_buf[NAME_MAX_LEN]; int uid = 0; ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); const int root_items_multiplier = 2; for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) { - snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); const int number_of_childs = (int)strlen(node_L1->Name); for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) { - snprintf(name_buf, 32, "Child %d", idx_L1); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); node_L2->HasData = true; if (idx_L1 == 0) { - snprintf(name_buf, 32, "Sub-child %d", 0); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); node_L3->HasData = true; } From 45e7f7827a52462d83895d36c62d00e6eb33c266 Mon Sep 17 00:00:00 2001 From: lunarlattice <18731514+lunarlattice0@users.noreply.github.com> Date: Fri, 9 Aug 2024 03:27:38 -0700 Subject: [PATCH 055/136] Examples: SDL2+SDLRenderer: fixed return value. (#7876) --- examples/example_sdl2_sdlrenderer2/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index b186b6268..31fa3f9bf 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -47,7 +47,7 @@ int main(int, char**) if (renderer == nullptr) { SDL_Log("Error creating SDL_Renderer!"); - return 0; + return -1; } //SDL_RendererInfo info; //SDL_GetRendererInfo(renderer, &info); From 29fadad1939ab62adcc5cd9339db7a784de90120 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Aug 2024 14:30:16 +0200 Subject: [PATCH 056/136] TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a495cd5d3..386d330c8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,7 @@ Other changes: payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) +- TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 11f1cdf60..d5c9fa077 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1425,6 +1425,9 @@ bool ImGui::TextLink(const char* label) bool pressed = ButtonBehavior(bb, id, &hovered, &held); RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_None); + if (hovered) + SetMouseCursor(ImGuiMouseCursor_Hand); + ImVec4 text_colf = g.Style.Colors[ImGuiCol_TextLink]; ImVec4 line_colf = text_colf; { From 591a18a9c4bf421de05a0eee7e85dea25f64209d Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 2 Aug 2024 00:05:51 +0200 Subject: [PATCH 057/136] Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) --- backends/imgui_impl_sdl2.cpp | 12 ++++++++++++ backends/imgui_impl_sdl3.cpp | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 15db0a843..2b115f360 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -321,6 +321,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { + if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); @@ -328,6 +330,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { + if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! float wheel_x = -event->wheel.preciseX; @@ -346,6 +350,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { + if (event->button.windowID != SDL_GetWindowID(bd->Window)) + return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -361,12 +367,16 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { + if (event->text.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_KEYDOWN: case SDL_KEYUP: { + if (event->key.windowID != SDL_GetWindowID(bd->Window)) + return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); @@ -375,6 +385,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_WINDOWEVENT: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 05718d21c..a74a316d2 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -307,6 +307,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { + if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); @@ -314,6 +316,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { + if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; float wheel_y = event->wheel.y; @@ -327,6 +331,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { + if (event->button.windowID != SDL_GetWindowID(bd->Window)) + return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -342,12 +348,16 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { + if (event->text.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { + if (event->key.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); @@ -357,6 +367,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; return true; @@ -367,13 +379,19 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddFocusEvent(true); return true; case SDL_EVENT_WINDOW_FOCUS_LOST: + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddFocusEvent(false); return true; case SDL_EVENT_GAMEPAD_ADDED: From 1b61d55079a66692207562c4d8d711527954f514 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 13:57:08 +0200 Subject: [PATCH 058/136] Backends: SDL2, SDL3: ignore events of other SDL windows, amends + wrapping into a function as it'll be convenient for multi-viewport check. (#7853) + Misc typo fix. --- backends/imgui_impl_sdl2.cpp | 21 +++++++++++++++------ backends/imgui_impl_sdl3.cpp | 34 +++++++++++++++++++++------------- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 2b115f360..9fff2ab56 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). @@ -110,6 +111,7 @@ struct ImGui_ImplSDL2_Data { SDL_Window* Window; + Uint32 WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -306,6 +308,12 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0); } +static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; +} + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. @@ -321,7 +329,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { - if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == NULL) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -330,7 +338,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { - if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! @@ -350,7 +358,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - if (event->button.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == NULL) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -367,7 +375,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { - if (event->text.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == NULL) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -375,7 +383,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_KEYDOWN: case SDL_KEYUP: { - if (event->key.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == NULL) return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); @@ -385,7 +393,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_WINDOWEVENT: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == NULL) return false; // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. @@ -445,6 +453,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Window = window; + bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a74a316d2..5a58c9688 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) // 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) // 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) @@ -80,6 +81,7 @@ struct ImGui_ImplSDL3_Data { SDL_Window* Window; + SDL_WindowID WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -292,6 +294,13 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0); } + +static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id) +{ + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; +} + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. @@ -307,7 +316,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { - if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == NULL) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -316,7 +325,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { - if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; @@ -331,7 +340,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - if (event->button.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == NULL) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -348,7 +357,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { - if (event->text.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == NULL) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -356,7 +365,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { - if (event->key.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); @@ -367,7 +376,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; @@ -379,21 +388,19 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: - if (event->window.windowID != SDL_GetWindowID(bd->Window)) - return false; - io.AddFocusEvent(true); - return true; case SDL_EVENT_WINDOW_FOCUS_LOST: - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + { + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; - io.AddFocusEvent(false); + io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED); return true; + } case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_REMOVED: { @@ -441,6 +448,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Window = window; + bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 386d330c8..e272b19ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,7 @@ Other changes: - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) +- Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) diff --git a/imgui.h b/imgui.h index 6d4f51388..9080bb1b5 100644 --- a/imgui.h +++ b/imgui.h @@ -3385,7 +3385,7 @@ struct ImFontAtlas struct ImFont { // Members: Hot ~20/24 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) From 2d99052d1d43bd17a72bce0531c605b30aa6bc0b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 14:07:25 +0200 Subject: [PATCH 059/136] Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. (#7853) This will be used to support filtering of events with multi-viewports. --- backends/imgui_impl_sdl2.cpp | 3 ++- backends/imgui_impl_sdl3.cpp | 6 ++++-- docs/CHANGELOG.txt | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 9fff2ab56..c4724969d 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. @@ -483,7 +484,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void // Set platform dependent data in viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - main_viewport->PlatformHandle = (void*)window; + main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID; main_viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; SDL_VERSION(&info.version); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 5a58c9688..24627347b 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) // 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) @@ -133,7 +134,8 @@ static void ImGui_ImplSDL3_SetClipboardText(void*, const char* text) static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); - SDL_Window* window = (SDL_Window*)viewport->PlatformHandle; + SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; + SDL_Window* window = SDL_GetWindowFromID(window_id); if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != NULL) { SDL_StopTextInput(bd->ImeWindow); @@ -413,7 +415,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Window* window) { - viewport->PlatformHandle = window; + viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(window); viewport->PlatformHandleRaw = nullptr; #if defined(_WIN32) && !defined(__WINRT__) viewport->PlatformHandleRaw = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e272b19ec..24f6c640c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,7 @@ Other changes: - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] +- Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) From 61313a75891c6cdb9ad313bd0f6e11eb6fde2c67 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 16:31:49 +0200 Subject: [PATCH 060/136] Docs: better promote IMGUI_DEFINE_MATH_OPERATORS. (#6164, #6137, #5966, #2832) --- imgui.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 9080bb1b5..b531bebc6 100644 --- a/imgui.h +++ b/imgui.h @@ -5,6 +5,7 @@ // - See links below. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // - Read top of imgui.cpp for more details, links and comments. +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. // Resources: // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) @@ -280,8 +281,8 @@ typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] -// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. -// Add '#define IMGUI_DEFINE_MATH_OPERATORS' in your imconfig.h file to benefit from courtesy maths operators for those types. +// - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { @@ -2664,7 +2665,7 @@ struct ImGuiListClipper // Helpers: ImVec2/ImVec4 operators // - It is important that we are keeping those disabled by default so they don't leak in user space. // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) -// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. +// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF From fabceaf03695ec0d8044d58b15460edd171cf7ea Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 18:28:56 +0200 Subject: [PATCH 061/136] Internals: renamed IsModKey() -> IsLRModKey() and GetModForModKey() -> GetModForLRModKey() to be more explicit. --- imgui.cpp | 12 ++++++------ imgui_internal.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d1da2886e..74236c1a4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8407,7 +8407,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] INPUTS //----------------------------------------------------------------------------- -// - GetModForModKey() [Internal] +// - GetModForLRModKey() [Internal] // - FixupKeyChord() [Internal] // - GetKeyData() [Internal] // - GetKeyIndex() [Internal] @@ -8470,7 +8470,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - Shortcut() [Internal] //----------------------------------------------------------------------------- -static ImGuiKeyChord GetModForModKey(ImGuiKey key) +static ImGuiKeyChord GetModForLRModKey(ImGuiKey key) { if (key == ImGuiKey_LeftCtrl || key == ImGuiKey_RightCtrl) return ImGuiMod_Ctrl; @@ -8487,8 +8487,8 @@ ImGuiKeyChord ImGui::FixupKeyChord(ImGuiKeyChord key_chord) { // Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified. ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); - if (IsModKey(key)) - key_chord |= GetModForModKey(key); + if (IsLRModKey(key)) + key_chord |= GetModForLRModKey(key); return key_chord; } @@ -8579,8 +8579,8 @@ const char* ImGui::GetKeyChordName(ImGuiKeyChord key_chord) ImGuiContext& g = *GImGui; const ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); - if (IsModKey(key)) - key_chord &= ~GetModForModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift" + if (IsLRModKey(key)) + key_chord &= ~GetModForLRModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift" ImFormatString(g.TempKeychordName, IM_ARRAYSIZE(g.TempKeychordName), "%s%s%s%s%s", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "", diff --git a/imgui_internal.h b/imgui_internal.h index 5b6d4c195..339a4e3a6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3298,7 +3298,7 @@ namespace ImGui inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } - inline bool IsModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; } + inline bool IsLRModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; } ImGuiKeyChord FixupKeyChord(ImGuiKeyChord key_chord); inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) { From 092c88dc7bdd6e736f0313fc366f7d20c18da519 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 19:02:27 +0200 Subject: [PATCH 062/136] IO: rework interleaved keys<>char trickling: only trickle for keys known to be likely to input characters. (#7889, #4921, #4858) Amend fa2b318d. Refer to regression test "inputs_io_inputqueue" amended for IMGUI_VERSION_NUM >= 19102 --- imgui.cpp | 26 +++++++++++++++++++------- imgui.h | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 74236c1a4..ed7983542 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8780,8 +8780,9 @@ static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInput return 0; } -// We need this to filter some Shortcut() routes when an item e.g. an InputText() is active -// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be. +// - We need this to filter some Shortcut() routes when an item e.g. an InputText() is active +// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be. +// - This is also used by UpdateInputEvents() to avoid trickling in the most common case of e.g. pressing ImGuiKey_G also emitting a G character. static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord) { // Mimic 'ignore_char_inputs' logic in InputText() @@ -8795,6 +8796,8 @@ static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord) // Return true for A-Z, 0-9 and other keys associated to char inputs. Other keys such as F1-F12 won't be filtered. ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + if (key == ImGuiKey_None) + return false; return g.KeysMayBeCharInput.TestBit(key); } @@ -9599,9 +9602,9 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) // Only trickle chars<>key when working with InputText() // FIXME: InputText() could parse event trail? // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters) - const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); + const bool trickle_interleaved_nonchar_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); - bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false; + bool mouse_moved = false, mouse_wheeled = false, key_changed = false, key_changed_nonchar = false, text_inputted = false; int mouse_button_changed = 0x00; ImBitArray key_changed_mask; @@ -9653,12 +9656,19 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) IM_ASSERT(key != ImGuiKey_None); ImGuiKeyData* key_data = GetKeyData(key); const int key_data_index = (int)(key_data - g.IO.KeysData); - if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0)) + if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || mouse_button_changed != 0)) break; + + const bool key_is_potentially_for_char_input = IsKeyChordPotentiallyCharInput(GetMergedModsFromKeys() | key); + if (trickle_interleaved_nonchar_keys_and_text && (text_inputted && !key_is_potentially_for_char_input)) + break; + key_data->Down = e->Key.Down; key_data->AnalogValue = e->Key.AnalogValue; key_changed = true; key_changed_mask.SetBit(key_data_index); + if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input) + key_changed_nonchar = true; // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -9672,11 +9682,13 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) continue; // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with - if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) + if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) + break; + if (trickle_interleaved_nonchar_keys_and_text && key_changed_nonchar) break; unsigned int c = e->Text.Char; io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); - if (trickle_interleaved_keys_and_text) + if (trickle_interleaved_nonchar_keys_and_text) text_inputted = true; } else if (e->Type == ImGuiInputEventType_Focus) diff --git a/imgui.h b/imgui.h index b531bebc6..1d7759199 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.1 WIP" -#define IMGUI_VERSION_NUM 19101 +#define IMGUI_VERSION_NUM 19102 #define IMGUI_HAS_TABLE /* From ecb1962013d280499c047e4523ceabd4a223d629 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 19:10:03 +0200 Subject: [PATCH 063/136] IO, InputText: missing changelog entry (amend 092c88d) + readme note on missing features. --- docs/CHANGELOG.txt | 3 +++ docs/README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 24f6c640c..40b651f42 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- IO, InputText: fixed an issue where typing text in a InputText() would defer character + processing by one frame, because of the trickling input queue. Reworked interleaved + keys<>char trickling to take account for keys known to input characters. (#7889, #4921, #4858) - MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow diff --git a/docs/README.md b/docs/README.md index 2c976341c..a1807abac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,7 +22,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin Dear ImGui is a **bloat-free graphical user interface library for C++**. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline-enabled application. It is fast, portable, renderer agnostic, and self-contained (no external dependencies). -Dear ImGui is designed to **enable fast iterations** and to **empower programmers** to create **content creation tools and visualization / debug tools** (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal and lacks certain features commonly found in more high-level libraries. +Dear ImGui is designed to **enable fast iterations** and to **empower programmers** to create **content creation tools and visualization / debug tools** (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal and lacks certain features commonly found in more high-level libraries. Among other things, full internationalization (right-to-left text, bidirectional text, text shaping etc.) and accessibility features are not supported. Dear ImGui is particularly suited to integration in game engines (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on console platforms where operating system features are non-standard. From eb7201b9026a8812d02b3421b43b61c050b81151 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 Aug 2024 15:34:14 +0200 Subject: [PATCH 064/136] Fonts: Made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 21 ++++++++++++++++----- imgui.h | 1 + imgui_draw.cpp | 11 +++++++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 40b651f42..dc30091c0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,7 @@ Other changes: - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) +- Fonts: Made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] diff --git a/imgui.cpp b/imgui.cpp index ed7983542..ed7522b27 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5068,6 +5068,8 @@ static void InitViewportDrawData(ImGuiViewportP* viewport) // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): // some frequently called functions which to modify both channels and clipping simultaneously tend to use the // more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. +// - This is analoguous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack, +// which in the case of ClipRect is not so problematic but tends to be more restrictive for fonts. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); @@ -7574,22 +7576,31 @@ void ImGui::SetCurrentFont(ImFont* font) g.DrawListSharedData.FontScale = g.FontScale; } +// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authorative against window-local ImDrawList. +// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. +// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... +// - Some code paths never really fully worked with multiple atlas textures. +// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() +// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem +// because we have a concrete need and a test bed for multiple atlas textures. void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; - if (!font) + if (font == NULL) font = GetDefaultFont(); - SetCurrentFont(font); g.FontStack.push_back(font); - g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); + SetCurrentFont(font); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PopFont() { ImGuiContext& g = *GImGui; - g.CurrentWindow->DrawList->PopTextureID(); + IM_ASSERT(g.FontStack.Size > 0); g.FontStack.pop_back(); - SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); + ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); + SetCurrentFont(font); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) diff --git a/imgui.h b/imgui.h index 1d7759199..b8aa34072 100644 --- a/imgui.h +++ b/imgui.h @@ -3152,6 +3152,7 @@ struct ImDrawList IMGUI_API void _OnChangedClipRect(); IMGUI_API void _OnChangedTextureID(); IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API void _SetTextureID(ImTextureID texture_id); IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 32cf64353..65d68708d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -526,7 +526,6 @@ void ImDrawList::_OnChangedClipRect() CmdBuffer.pop_back(); return; } - curr_cmd->ClipRect = _CmdHeader.ClipRect; } @@ -549,7 +548,6 @@ void ImDrawList::_OnChangedTextureID() CmdBuffer.pop_back(); return; } - curr_cmd->TextureId = _CmdHeader.TextureId; } @@ -625,6 +623,15 @@ void ImDrawList::PopTextureID() _OnChangedTextureID(); } +// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID(). +void ImDrawList::_SetTextureID(ImTextureID texture_id) +{ + if (_CmdHeader.TextureId == texture_id) + return; + _CmdHeader.TextureId = texture_id; + _OnChangedTextureID(); +} + // Reserve space for a number of vertices and indices. // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or // submit the intermediate results. PrimUnreserve() can be used to release unused allocations. From e471206b0889948c436f144669beb9b8875110c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 Aug 2024 17:54:42 +0200 Subject: [PATCH 065/136] Windows: adjust default ClipRect to better match rendering of thick borders. (#7887, #7888 + #3312, #7540, #3756, #6170, #6365) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dc30091c0..d12bb58d1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,9 @@ Other changes: - IO, InputText: fixed an issue where typing text in a InputText() would defer character processing by one frame, because of the trickling input queue. Reworked interleaved keys<>char trickling to take account for keys known to input characters. (#7889, #4921, #4858) +- Windows: adjust default ClipRect to better match rendering of thick borders (which are in + theory not supported). Compensate for the fact that borders are centered around the windows + edge rather than inner. (#7887, #7888 + #3312, #7540, #3756, #6170, #6365) - MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow diff --git a/imgui.cpp b/imgui.cpp index ed7522b27..ede9f4b84 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7066,10 +7066,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Affected by window/frame border size. Used by: // - Begin() initial clip rect float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); - window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize); - window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); - window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - window->WindowBorderSize); - window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); + + // Try to match the fact that our border is drawn centered over the window rectangle, rather than inner. + // This is why we do a *0.5f here. We don't currently even technically support large values for WindowBorderSize, + // see e.g #7887 #7888, but may do after we move the window border to become an inner border (and then we can remove the 0.5f here). + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize * 0.5f); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size * 0.5f); + window->InnerClipRect.Max.x = ImFloor(window->InnerRect.Max.x - window->WindowBorderSize * 0.5f); + window->InnerClipRect.Max.y = ImFloor(window->InnerRect.Max.y - window->WindowBorderSize * 0.5f); window->InnerClipRect.ClipWithFull(host_rect); // Default item width. Make it proportional to window size if window manually resizes From 59e69dc6df758e59f318e38a8db5bc4c8a8164c1 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 21 Aug 2024 09:14:52 +0200 Subject: [PATCH 066/136] ImGuiSelectionBasicStorage constructor needs visibility (#7906) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index b8aa34072..c55f5dda6 100644 --- a/imgui.h +++ b/imgui.h @@ -2860,7 +2860,7 @@ struct ImGuiSelectionBasicStorage ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). // Methods - ImGuiSelectionBasicStorage(); + IMGUI_API ImGuiSelectionBasicStorage(); IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions. It uses 'items_count' passed to BeginMultiSelect() IMGUI_API bool Contains(ImGuiID id) const; // Query if an item id is in selection. IMGUI_API void Clear(); // Clear selection From 8a946b69e98d819e9123963122d3b8b10df52e78 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Aug 2024 13:25:45 +0200 Subject: [PATCH 067/136] InputText: allow callback to update buffer while in read-only mode (fix for imgui_memory_editor 0.54 in read-only mode). See https://github.com/ocornut/imgui_club/pull/46 --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d12bb58d1..228e84dd1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,7 @@ Other changes: payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) +- InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Fonts: Made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d5c9fa077..5aa70bdc2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4912,7 +4912,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } if (buf_dirty) { - IM_ASSERT(!is_readonly); + // Callback may update buffer and thus set buf_dirty even in read-only mode. IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? if (callback_data.BufTextLen > backup_current_text_length && is_resizable) From 521f84a3a9f21aa93d12a49823d589b560f899a5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Aug 2024 14:26:53 +0200 Subject: [PATCH 068/136] InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) Amend 66f0fb986, c5db276521 --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 228e84dd1..7b20e0033 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,7 @@ Other changes: - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) +- InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Fonts: Made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5aa70bdc2..e8d5f9683 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5194,7 +5194,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { - // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); @@ -5203,7 +5203,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... // FIXME: This quite messy/tricky, should attempt to get rid of the child window. EndGroup(); - if (g.LastItemData.ID == 0) + if (g.LastItemData.ID == 0 || g.LastItemData.ID != GetWindowScrollbarID(draw_window, ImGuiAxis_Y)) { g.LastItemData.ID = id; g.LastItemData.InFlags = item_data_backup.InFlags; From bf75504d7a42ca9fc6f71fce558eca1f4a6f0201 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 13:46:54 +0200 Subject: [PATCH 069/136] Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. + tweak existing function to early out on error. --- docs/CHANGELOG.txt | 3 ++- docs/TODO.txt | 1 - imgui.cpp | 48 ++++++++++++++++++++++++++++++++++++---------- imgui.h | 6 ++++-- imgui_demo.cpp | 10 +++++----- imgui_widgets.cpp | 6 +++--- 6 files changed, 52 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7b20e0033..6ba4c4dad 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,7 +56,8 @@ Other changes: - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) -- Fonts: Made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) +- Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. +- Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] diff --git a/docs/TODO.txt b/docs/TODO.txt index eecce6b42..cd992784d 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -194,7 +194,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - settings/persistence: helpers to make TreeNodeBehavior persist (even during dev!) - may need to store some semantic and/or data type in ImGuiStoragePair - style: better default styles. (#707) - - style: PushStyleVar: allow direct access to individual float X/Y elements. - style: add a highlighted text color (for headers, etc.) - style: border types: out-screen, in-screen, etc. (#447) - style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier) diff --git a/imgui.cpp b/imgui.cpp index ede9f4b84..bb7e55c82 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3309,28 +3309,56 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + if (var_info->Type != ImGuiDataType_Float || var_info->Count != 1) { - float* pvar = (float*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; } - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; +} + +void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) +{ + ImGuiContext& g = *GImGui; + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + { + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + return; + } + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + pvar->x = val_x; +} + +void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) +{ + ImGuiContext& g = *GImGui; + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + { + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + return; + } + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + pvar->y = val_y; } void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) { - ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; } - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; } void ImGui::PopStyleVar(int count) diff --git a/imgui.h b/imgui.h index c55f5dda6..0289e798b 100644 --- a/imgui.h +++ b/imgui.h @@ -438,8 +438,10 @@ namespace ImGui IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame()! + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. " + IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x); // modify X component of a style ImVec2 variable. " + IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y); // modify Y component of a style ImVec2 variable. " IMGUI_API void PopStyleVar(int count = 1); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); // modify specified shared item flag, e.g. PushItemFlag(ImGuiItemFlags_NoTabStop, true) IMGUI_API void PopItemFlag(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 264df8af4..ddc8f9b2a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3677,7 +3677,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) { ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize()); if (widget_type == WidgetType_TreeNode) - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f)); + ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f); ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); selection.ApplyRequests(ms_io); @@ -3693,7 +3693,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f); - //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f)); + //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f); } ImGuiListClipper clipper; @@ -5082,8 +5082,8 @@ const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; static void PushStyleCompact() { ImGuiStyle& style = ImGui::GetStyle(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); + ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f)); + ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f)); } static void PopStyleCompact() @@ -6117,7 +6117,7 @@ static void ShowDemoWindowTables() for (int row = 0; row < 8; row++) { if ((row % 3) == 2) - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(style.CellPadding.x, 20.0f)); + ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f); ImGui::TableNextRow(ImGuiTableRowFlags_None); ImGui::TableNextColumn(); ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e8d5f9683..36cc2d6d2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1944,7 +1944,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; - PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text + PushStyleVarX(ImGuiStyleVar_WindowPadding, g.Style.FramePadding.x); // Horizontally align ourselves with the framed text bool ret = Begin(name, NULL, window_flags); PopStyleVar(); if (!ret) @@ -8688,7 +8688,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); - PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); float w = label_size.x; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); @@ -8895,7 +8895,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut float w = label_size.x; window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); PopStyleVar(); if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) From 8e401047952fa7e1ea80f7c3d390f7203697583b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 18:13:34 +0200 Subject: [PATCH 070/136] Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString(). --- backends/imgui_impl_glfw.cpp | 9 ++++----- docs/CHANGELOG.txt | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index df581537b..73aae768d 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -176,14 +176,14 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() } // Functions -static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) +static const char* ImGui_ImplGlfw_GetClipboardText(void*) { - return glfwGetClipboardString((GLFWwindow*)user_data); + return glfwGetClipboardString(NULL); } -static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +static void ImGui_ImplGlfw_SetClipboardText(void*, const char* text) { - glfwSetClipboardString((GLFWwindow*)user_data, text); + glfwSetClipboardString(NULL, text); } static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) @@ -588,7 +588,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; - io.ClipboardUserData = bd->Window; #ifdef __EMSCRIPTEN__ io.PlatformOpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6ba4c4dad..1cfe8ef8e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,8 @@ Other changes: provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. +- Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() + since GLFW own tests are doing that and it seems unnecessary. - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) From e6460722ea14f61b2eff6cbfdd6770d9e4874454 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 16:31:10 +0200 Subject: [PATCH 071/136] IO: Added GetPlatformIO(), ImGuiPlatformIO, currently empty. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 16 ++++++++++++++-- imgui.h | 18 ++++++++++++++---- imgui_internal.h | 1 + 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1cfe8ef8e..4b02e8f36 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- IO: Added GetPlatformIO() and ImGuiPlatformIO, pulled from 'docking' branch, which + is a centralized spot to connect os/platform/renderer related functions. + Clipboard, IME and OpenInShell hooks are moved here. (#7660) - IO, InputText: fixed an issue where typing text in a InputText() would defer character processing by one frame, because of the trickling input queue. Reworked interleaved keys<>char trickling to take account for keys known to input characters. (#7889, #4921, #4858) diff --git a/imgui.cpp b/imgui.cpp index bb7e55c82..9f4d38df7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -63,7 +63,7 @@ CODE // [SECTION] INCLUDES // [SECTION] FORWARD DECLARATIONS // [SECTION] CONTEXT AND MEMORY ALLOCATORS -// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO) // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) // [SECTION] MISC HELPERS/UTILITIES (File functions) @@ -1244,7 +1244,7 @@ static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; static void* GImAllocatorUserData = NULL; //----------------------------------------------------------------------------- -// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO) //----------------------------------------------------------------------------- ImGuiStyle::ImGuiStyle() @@ -1762,6 +1762,12 @@ void ImGuiIO::AddFocusEvent(bool focused) g.InputEventsQueue.push_back(e); } +ImGuiPlatformIO::ImGuiPlatformIO() +{ + // Most fields are initialized with zero + memset(this, 0, sizeof(*this)); +} + //----------------------------------------------------------------------------- // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) //----------------------------------------------------------------------------- @@ -4461,6 +4467,12 @@ ImGuiIO& ImGui::GetIO() return GImGui->IO; } +ImGuiPlatformIO& ImGui::GetPlatformIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?"); + return GImGui->PlatformIO; +} + // Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() ImDrawData* ImGui::GetDrawData() { diff --git a/imgui.h b/imgui.h index 0289e798b..eaffc7417 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.1 WIP" -#define IMGUI_VERSION_NUM 19102 +#define IMGUI_VERSION_NUM 19103 #define IMGUI_HAS_TABLE /* @@ -49,7 +49,7 @@ Index of this file: // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) -// [SECTION] Platform Dependent Interfaces (ImGuiPlatformImeData) +// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) // [SECTION] Obsolete functions and types */ @@ -172,13 +172,14 @@ struct ImFontGlyph; // A single font glyph (code point + coordin struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) -struct ImGuiIO; // Main configuration and I/O between your application and ImGui +struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO) struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME hooks). Extends ImGuiIO. In docking branch, this gets extended to support multi-viewports. struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests. struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage. @@ -325,7 +326,8 @@ namespace ImGui IMGUI_API void SetCurrentContext(ImGuiContext* ctx); // Main - IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiIO& GetIO(); // access the ImGuiIO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // access the ImGuiPlatformIO structure (mostly hooks/functions to connect to platform/renderer and OS Clipboard, IME etc.) IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleColor(), PushStyleVar() to modify style mid-frame! IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! @@ -2196,6 +2198,8 @@ struct ImGuiStyle // - initialization: backends and user code writes to ImGuiIO. // - main loop: backends writes to ImGuiIO, user code and imgui code reads from ImGuiIO. //----------------------------------------------------------------------------- +// Also see ImGui::GetPlatformIO() and ImGuiPlatformIO struct for OS/platform related functions: clipboard, IME etc. +//----------------------------------------------------------------------------- // [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. // If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. @@ -3483,6 +3487,12 @@ struct ImGuiViewport // [SECTION] Platform Dependent Interfaces //----------------------------------------------------------------------------- +// Access via ImGui::GetPlatformIO() +struct ImGuiPlatformIO +{ + IMGUI_API ImGuiPlatformIO(); +}; + // (Optional) Support for IME (Input Method Editor) via the io.PlatformSetImeDataFn() function. struct ImGuiPlatformImeData { diff --git a/imgui_internal.h b/imgui_internal.h index 339a4e3a6..29099cd04 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1994,6 +1994,7 @@ struct ImGuiContext bool Initialized; bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; + ImGuiPlatformIO PlatformIO; ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. From ba2f4a2cd56e33d99798b084dc4229efb2fa1140 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 16:42:57 +0200 Subject: [PATCH 072/136] IO: (BREAKING) moved GetIO().PlatformOpenInShellFn to GetPlatformIO(.Platform_OpenInShellFn. (#7660) --- backends/imgui_impl_glfw.cpp | 5 ++++- backends/imgui_impl_sdl2.cpp | 5 ++++- docs/CHANGELOG.txt | 5 +++++ imconfig.h | 2 +- imgui.cpp | 15 +++++++++------ imgui.h | 14 +++++++++----- imgui_widgets.cpp | 4 ++-- 7 files changed, 34 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 73aae768d..776396786 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -20,6 +20,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn // 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one. // 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter. // 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw) @@ -586,10 +588,11 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Window = window; bd->Time = 0.0; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; #ifdef __EMSCRIPTEN__ - io.PlatformOpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; + platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif // Create mouse cursors diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index c4724969d..d9ba69d16 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn // 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. @@ -458,12 +460,13 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; io.ClipboardUserData = nullptr; io.PlatformSetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ - io.PlatformOpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; + platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; #endif // Gamepad handling diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4b02e8f36..4cbeb025c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,10 @@ HOW TO UPDATE? Breaking changes: +- IO: moved some functions from ImGuiIO to ImGuiPlatformIO: + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) + - access those via GetPlatformIO() instead of GetIO(). + Other changes: - IO: Added GetPlatformIO() and ImGuiPlatformIO, pulled from 'docking' branch, which @@ -114,6 +118,7 @@ Other changes: - Added TextLink(), TextLinkOpenURL() hyperlink widgets. (#7660) - IO: added io.PlatformOpenInShellFn handler to open a link/folder/file in OS shell. (#7660) + (*EDIT* From next version 1.91.1 we moved this to platform_io.Platform_OpenInShellFn *EDIT**) Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default Windows/Linux/Mac implementations. - IO: added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match the typical "Nintendo/Japanese consoles" button layout when using Gamepad navigation. (#787, #5723) diff --git a/imconfig.h b/imconfig.h index 6e4c743d4..b8d55842b 100644 --- a/imconfig.h +++ b/imconfig.h @@ -43,7 +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_DEFAULT_SHELL_FUNCTIONS // Don't implement default io.PlatformOpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")). +//#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. //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) diff --git a/imgui.cpp b/imgui.cpp index 9f4d38df7..d4eb59b9b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,10 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) + - access those via GetPlatformIO() instead of GetIO(). + some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol. - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way. - instead of: GetWindowContentRegionMax().x - GetCursorPos().x @@ -1144,7 +1148,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSetti static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); -static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); +static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); namespace ImGui { @@ -1393,7 +1397,6 @@ ImGuiIO::ImGuiIO() // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; - PlatformOpenInShellUserData = NULL; PlatformLocaleDecimalPoint = '.'; // Input (NB: we already have memset zero the entire structure!) @@ -3805,7 +3808,7 @@ void ImGui::Initialize() g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) - g.IO.PlatformOpenInShellFn = PlatformOpenInShellFn_DefaultImpl; + g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; g.IO.PlatformSetImeDataFn = PlatformSetImeDataFn_DefaultImpl; // Create default viewport @@ -14477,14 +14480,14 @@ static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text #ifdef _MSC_VER #pragma comment(lib, "shell32") #endif -static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) +static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { return (INT_PTR)::ShellExecuteA(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT) > 32; } #else #include #include -static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) +static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { #if defined(__APPLE__) const char* args[] { "open", "--", path, NULL }; @@ -14508,7 +14511,7 @@ static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) } #endif #else -static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; } +static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; } #endif // Default shell handlers //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index eaffc7417..9a745dd90 100644 --- a/imgui.h +++ b/imgui.h @@ -2295,11 +2295,6 @@ struct ImGuiIO void (*SetClipboardTextFn)(void* user_data, const char* text); void* ClipboardUserData; - // Optional: Open link/folder/file in OS Shell - // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) - bool (*PlatformOpenInShellFn)(ImGuiContext* ctx, const char* path); - void* PlatformOpenInShellUserData; - // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) void (*PlatformSetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); @@ -3491,6 +3486,15 @@ struct ImGuiViewport struct ImGuiPlatformIO { IMGUI_API ImGuiPlatformIO(); + + //------------------------------------------------------------------ + // Inputs - Interface with OS/backends + //------------------------------------------------------------------ + + // Optional: Open link/folder/file in OS Shell + // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) + bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); + void* Platform_OpenInShellUserData; }; // (Optional) Support for IME (Input Method Editor) via the io.PlatformSetImeDataFn() function. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 36cc2d6d2..f064a5dd8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1462,8 +1462,8 @@ void ImGui::TextLinkOpenURL(const char* label, const char* url) if (url == NULL) url = label; if (TextLink(label)) - if (g.IO.PlatformOpenInShellFn != NULL) - g.IO.PlatformOpenInShellFn(&g, url); + if (g.PlatformIO.Platform_OpenInShellFn != NULL) + g.PlatformIO.Platform_OpenInShellFn(&g, url); SetItemTooltip("%s", url); // It is more reassuring for user to _always_ display URL when we same as label if (BeginPopupContextItem()) { From 9ff60ae31d5d2328c0081ae17024d4057ad8a22a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 16:55:14 +0200 Subject: [PATCH 073/136] IO: (BREAKING) moved GetIO().PlatformSetImeDataFn to GetPlatformIO(.Platform_SetImeDataFn. (#7660) --- backends/imgui_impl_osx.mm | 5 ++++- backends/imgui_impl_sdl2.cpp | 3 ++- backends/imgui_impl_sdl3.cpp | 5 ++++- docs/CHANGELOG.txt | 4 ++++ docs/FAQ.md | 2 +- imgui.cpp | 17 +++++++++-------- imgui.h | 13 +++++++------ imgui_internal.h | 2 +- 8 files changed, 32 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index ab0e0ecc6..30f4ab24a 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -29,6 +29,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. // 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen. @@ -465,7 +467,8 @@ bool ImGui_ImplOSX_Init(NSView* view) [view addSubview:bd->KeyEventResponder]; ImGui_ImplOSX_AddTrackingArea(view); - io.PlatformSetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Platform_SetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); if (data->WantVisible) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index d9ba69d16..c30fe6d81 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -23,6 +23,7 @@ // (minor and older changes stripped away, please see git history for details) // 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: // - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn +// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. @@ -464,7 +465,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; io.ClipboardUserData = nullptr; - io.PlatformSetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; + platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; #endif diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 24627347b..37ab21c24 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) @@ -454,10 +456,11 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; io.ClipboardUserData = nullptr; - io.PlatformSetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; + platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; // Gamepad handling bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4cbeb025c..85e3cb04d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,7 +43,11 @@ Breaking changes: - IO: moved some functions from ImGuiIO to ImGuiPlatformIO: - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) + - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn. - access those via GetPlatformIO() instead of GetIO(). + (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and + often automatically set by core library and backends, we are exceptionally not maintaining + a legacy redirection symbol for those two.) Other changes: diff --git a/docs/FAQ.md b/docs/FAQ.md index e120e8cd6..d104c30bc 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -639,7 +639,7 @@ The applications in examples/ are doing that. Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode). You may also use `MultiByteToWideChar()` or `ToUnicode()` to retrieve Unicode codepoints from MultiByte characters or keyboard state. Windows: if your language is relying on an Input Method Editor (IME), you can write your HWND to ImGui::GetMainViewport()->PlatformHandleRaw -for the default implementation of io.PlatformSetImeDataFn() to set your Microsoft IME position correctly. +for the default implementation of GetPlatformIO().Platform_SetImeDataFn() to set your Microsoft IME position correctly. ##### [Return to Index](#index) diff --git a/imgui.cpp b/imgui.cpp index d4eb59b9b..e7615b1c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,7 +431,8 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) + - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn - access those via GetPlatformIO() instead of GetIO(). some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol. - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) @@ -1147,7 +1148,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSetti // Platform Dependents default implementation for IO functions static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); -static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); +static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); namespace ImGui @@ -3809,7 +3810,7 @@ void ImGui::Initialize() g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; - g.IO.PlatformSetImeDataFn = PlatformSetImeDataFn_DefaultImpl; + g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl; // Create default viewport ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); @@ -5226,11 +5227,11 @@ void ImGui::EndFrame() // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) ImGuiPlatformImeData* ime_data = &g.PlatformImeData; - if (g.IO.PlatformSetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) { - IMGUI_DEBUG_LOG_IO("[io] Calling io.PlatformSetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); ImGuiViewport* viewport = GetMainViewport(); - g.IO.PlatformSetImeDataFn(&g, viewport, ime_data); + g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data); } // Hide implicit/fallback "Debug" window if it hasn't been used @@ -14524,7 +14525,7 @@ static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { ret #pragma comment(lib, "imm32") #endif -static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) +static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) { // Notify OS Input Method Editor of text input position HWND hwnd = (HWND)viewport->PlatformHandleRaw; @@ -14550,7 +14551,7 @@ static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewp #else -static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData*) {} +static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData*) {} #endif // Default IME handlers diff --git a/imgui.h b/imgui.h index 9a745dd90..0400abdcd 100644 --- a/imgui.h +++ b/imgui.h @@ -2295,11 +2295,6 @@ struct ImGuiIO void (*SetClipboardTextFn)(void* user_data, const char* text); void* ClipboardUserData; - // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) - // (default to use native imm32 api on Windows) - void (*PlatformSetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); - //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to io.PlatformSetImeDataFn in 1.91.0] - // Optional: Platform locale ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point @@ -3495,9 +3490,15 @@ struct ImGuiPlatformIO // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); void* Platform_OpenInShellUserData; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + void (*Platform_SetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); + void* Platform_ImeUserData; + //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to platform_io.PlatformSetImeDataFn in 1.91.1] }; -// (Optional) Support for IME (Input Method Editor) via the io.PlatformSetImeDataFn() function. +// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. struct ImGuiPlatformImeData { bool WantVisible; // A widget wants the IME to be visible diff --git a/imgui_internal.h b/imgui_internal.h index 29099cd04..6bd2aa457 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2275,7 +2275,7 @@ struct ImGuiContext // Platform support ImGuiPlatformImeData PlatformImeData; // Data updated by current frame - ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the io.PlatformSetImeDataFn() handler. + ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the platform_io.Platform_SetImeDataFn() handler. // Settings bool SettingsLoaded; From e54f240ea0aad351ee7971e2cb7afe8881120dde Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 17:18:16 +0200 Subject: [PATCH 074/136] IO: (BREAKING) moved io.PlatformLocaleDecimalPoint to platform_io.Platform_LocaleDecimalPoint. (#7389, #6719, #2278) --- docs/CHANGELOG.txt | 5 +++-- imgui.cpp | 7 ++++--- imgui.h | 7 ++++--- imgui_widgets.cpp | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 85e3cb04d..a061e71c8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,8 +42,9 @@ HOW TO UPDATE? Breaking changes: - IO: moved some functions from ImGuiIO to ImGuiPlatformIO: - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) - - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn. + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) + - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn. + - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint. (#7389, #6719, #2278) - access those via GetPlatformIO() instead of GetIO(). (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and often automatically set by core library and backends, we are exceptionally not maintaining diff --git a/imgui.cpp b/imgui.cpp index e7615b1c5..deed85399 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,8 +431,9 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) - - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) + - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn + - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) - access those via GetPlatformIO() instead of GetIO(). some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol. - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) @@ -1398,7 +1399,6 @@ ImGuiIO::ImGuiIO() // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; - PlatformLocaleDecimalPoint = '.'; // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); @@ -1770,6 +1770,7 @@ ImGuiPlatformIO::ImGuiPlatformIO() { // Most fields are initialized with zero memset(this, 0, sizeof(*this)); + Platform_LocaleDecimalPoint = '.'; } //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 0400abdcd..a1ccfd73d 100644 --- a/imgui.h +++ b/imgui.h @@ -2295,9 +2295,6 @@ struct ImGuiIO void (*SetClipboardTextFn)(void* user_data, const char* text); void* ClipboardUserData; - // Optional: Platform locale - ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point - //------------------------------------------------------------------ // Input - Call before calling NewFrame() //------------------------------------------------------------------ @@ -3496,6 +3493,10 @@ struct ImGuiPlatformIO void (*Platform_SetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); void* Platform_ImeUserData; //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to platform_io.PlatformSetImeDataFn in 1.91.1] + + // Optional: Platform locale + // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point + ImWchar Platform_LocaleDecimalPoint; // '.' }; // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f064a5dd8..f4625f2a7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4132,10 +4132,10 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. // Change the default decimal_point with: - // ImGui::GetIO()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; + // ImGui::GetPlatformIO()->Platform_LocaleDecimalPoint = *localeconv()->decimal_point; // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. ImGuiContext& g = *ctx; - const unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint; + const unsigned c_decimal_point = (unsigned int)g.PlatformIO.Platform_LocaleDecimalPoint; if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint)) if (c == '.' || c == ',') c = c_decimal_point; From 214977e5fd1ba25d8c77824b2993450b63cdc075 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 17:50:10 +0200 Subject: [PATCH 075/136] IO: (BREAKING) moved io.GetClipboardTextFn, io.SetClipboardTextFn to platform_io.Platform_GetClipboardTextFn, platform_io.Platform_SetClipboardTextFn. --- backends/imgui_impl_allegro5.cpp | 13 +++++---- backends/imgui_impl_glfw.cpp | 4 ++- backends/imgui_impl_osx.mm | 10 ++++--- backends/imgui_impl_sdl2.cpp | 14 +++++---- backends/imgui_impl_sdl3.cpp | 13 +++++---- docs/CHANGELOG.txt | 18 +++++++++--- imgui.cpp | 49 +++++++++++++++++++------------- imgui.h | 20 +++++++++---- imgui_widgets.cpp | 2 +- 9 files changed, 90 insertions(+), 53 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index db366fa74..e41f02140 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -20,6 +20,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn +// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). @@ -291,7 +294,7 @@ void ImGui_ImplAllegro5_InvalidateDeviceObjects() } #if ALLEGRO_HAS_CLIPBOARD -static const char* ImGui_ImplAllegro5_GetClipboardText(void*) +static const char* ImGui_ImplAllegro5_GetClipboardText(ImGuiContext*) { ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); if (bd->ClipboardTextData) @@ -300,7 +303,7 @@ static const char* ImGui_ImplAllegro5_GetClipboardText(void*) return bd->ClipboardTextData; } -static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text) +static void ImGui_ImplAllegro5_SetClipboardText(ImGuiContext*, const char* text) { ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); al_set_clipboard_text(bd->Display, text); @@ -447,9 +450,9 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro)); #if ALLEGRO_HAS_CLIPBOARD - io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; - io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; - io.ClipboardUserData = nullptr; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; + platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; #endif return true; diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 776396786..66b71c5e7 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -20,7 +20,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn +// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn // 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one. // 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 30f4ab24a..870038d85 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -29,7 +29,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn +// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. @@ -395,6 +397,7 @@ IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view) { bool ImGui_ImplOSX_Init(NSView* view) { ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); @@ -425,14 +428,14 @@ bool ImGui_ImplOSX_Init(NSView* view) // Note that imgui.cpp also include default OSX clipboard handlers which can be enabled // by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line. // Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api. - io.SetClipboardTextFn = [](void*, const char* str) -> void + platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* str) -> void { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString]; }; - io.GetClipboardTextFn = [](void*) -> const char* + platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) -> const char* { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]]; @@ -467,7 +470,6 @@ bool ImGui_ImplOSX_Init(NSView* view) [view addSubview:bd->KeyEventResponder]; ImGui_ImplOSX_AddTrackingArea(view); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index c30fe6d81..b1cc8c9e6 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,7 +21,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn +// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn // - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. @@ -146,7 +148,7 @@ static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData() } // Functions -static const char* ImGui_ImplSDL2_GetClipboardText(void*) +static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); if (bd->ClipboardTextData) @@ -155,7 +157,7 @@ static const char* ImGui_ImplSDL2_GetClipboardText(void*) return bd->ClipboardTextData; } -static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text) +static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text) { SDL_SetClipboardText(text); } @@ -462,9 +464,9 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCanUseGlobalState = mouse_can_use_global_state; ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; - io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; - io.ClipboardUserData = nullptr; + platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; + platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; + platform_io.Platform_ClipboardUserData = nullptr; platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 37ab21c24..deb8c7925 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,7 +21,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-08-22: Follow up on function pointers moved from ImGuiIO to ImGuiPlatformIO: +// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn +// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn // 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) @@ -118,7 +120,7 @@ static ImGui_ImplSDL3_Data* ImGui_ImplSDL3_GetBackendData() } // Functions -static const char* ImGui_ImplSDL3_GetClipboardText(void*) +static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); if (bd->ClipboardTextData) @@ -128,7 +130,7 @@ static const char* ImGui_ImplSDL3_GetClipboardText(void*) return bd->ClipboardTextData; } -static void ImGui_ImplSDL3_SetClipboardText(void*, const char* text) +static void ImGui_ImplSDL3_SetClipboardText(ImGuiContext*, const char* text) { SDL_SetClipboardText(text); } @@ -457,9 +459,8 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCanUseGlobalState = mouse_can_use_global_state; ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; - io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; - io.ClipboardUserData = nullptr; + platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; + platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; // Gamepad handling diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a061e71c8..25cd2b8c7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,10 +41,18 @@ HOW TO UPDATE? Breaking changes: -- IO: moved some functions from ImGuiIO to ImGuiPlatformIO: - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn. (#7660) - - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn. - - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint. (#7389, #6719, #2278) +- IO: moved clipboard functions from ImGuiIO to ImGuiPlatformIO: + - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + - in function signatures, changed 'void* user_data' to 'ImGuiContext* ctx' for consistency + with other functions. Pull your user data from platform_io.ClipboardUserData if used. + - as this is will affect all users of custom engines/backends, we are providing proper + legacy redirection (will obsolete). +- IO: moved other functions from ImGuiIO to ImGuiPlatformIO: + - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) + - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn + - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) + - clipboard function signature changed: - access those via GetPlatformIO() instead of GetIO(). (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and often automatically set by core library and backends, we are exceptionally not maintaining @@ -76,6 +84,8 @@ Other changes: - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. - Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() since GLFW own tests are doing that and it seems unnecessary. +- Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO + instead of ImGuiIO. - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) diff --git a/imgui.cpp b/imgui.cpp index deed85399..381ffb259 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,6 +431,8 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: + - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + changed 'void* user_data' to 'ImGuiContext* ctx'. Pull your user data from platform_io.ClipboardUserData. + - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + same as above line. - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) @@ -1146,9 +1148,9 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSetti static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); -// Platform Dependents default implementation for IO functions -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); -static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); +// Platform Dependents default implementation for ImGuiPlatformIO functions +static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx); +static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text); static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); @@ -3806,10 +3808,9 @@ void ImGui::Initialize() // Setup default localization table LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); - // Setup default platform clipboard/IME handlers. - g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations - g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; - g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) + // Setup default ImGuiPlatformIO clipboard/IME handlers. + g.PlatformIO.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + g.PlatformIO.Platform_SetClipboardTextFn = Platform_SetClipboardTextFn_DefaultImpl; g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl; @@ -4451,14 +4452,14 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr const char* ImGui::GetClipboardText() { ImGuiContext& g = *GImGui; - return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; + return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : ""; } void ImGui::SetClipboardText(const char* text) { ImGuiContext& g = *GImGui; - if (g.IO.SetClipboardTextFn) - g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); + if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) + g.PlatformIO.Platform_SetClipboardTextFn(&g, text); } const char* ImGui::GetVersion() @@ -10096,6 +10097,14 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); #endif + + // Remap legacy clipboard handlers (OBSOLETED in 1.91.1, August 2024) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (g.IO.GetClipboardTextFn != NULL && (g.PlatformIO.Platform_GetClipboardTextFn == NULL || g.PlatformIO.Platform_GetClipboardTextFn == Platform_GetClipboardTextFn_DefaultImpl)) + g.PlatformIO.Platform_GetClipboardTextFn = [](ImGuiContext* ctx) { return ctx->IO.GetClipboardTextFn(ctx->IO.ClipboardUserData); }; + if (g.IO.SetClipboardTextFn != NULL && (g.PlatformIO.Platform_SetClipboardTextFn == NULL || g.PlatformIO.Platform_SetClipboardTextFn == Platform_SetClipboardTextFn_DefaultImpl)) + g.PlatformIO.Platform_SetClipboardTextFn = [](ImGuiContext* ctx, const char* text) { return ctx->IO.SetClipboardTextFn(ctx->IO.ClipboardUserData, text); }; +#endif } static void ImGui::ErrorCheckEndFrameSanityChecks() @@ -14347,9 +14356,9 @@ static void ImGui::UpdateViewportsNewFrame() // Win32 clipboard implementation // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *ctx; g.ClipboardHandlerData.clear(); if (!::OpenClipboard(NULL)) return NULL; @@ -14370,7 +14379,7 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) return g.ClipboardHandlerData.Data; } -static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text) { if (!::OpenClipboard(NULL)) return; @@ -14397,7 +14406,7 @@ static PasteboardRef main_clipboard = 0; // OSX clipboard implementation // If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! -static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text) { if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); @@ -14410,9 +14419,9 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text) } } -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *ctx; if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); PasteboardSynchronize(main_clipboard); @@ -14446,15 +14455,15 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) #else // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. -static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *ctx; return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); } -static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text) +static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text) { - ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + ImGuiContext& g = *ctx; g.ClipboardHandlerData.clear(); const char* text_end = text + strlen(text); g.ClipboardHandlerData.resize((int)(text_end - text) + 1); diff --git a/imgui.h b/imgui.h index a1ccfd73d..2825cc60c 100644 --- a/imgui.h +++ b/imgui.h @@ -2289,12 +2289,6 @@ struct ImGuiIO void* BackendRendererUserData; // = NULL // User data for renderer backend void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend - // Optional: Access OS clipboard - // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*GetClipboardTextFn)(void* user_data); - void (*SetClipboardTextFn)(void* user_data, const char* text); - void* ClipboardUserData; - //------------------------------------------------------------------ // Input - Call before calling NewFrame() //------------------------------------------------------------------ @@ -2396,6 +2390,14 @@ struct ImGuiIO //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. #endif + // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. + // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; +#endif + IMGUI_API ImGuiIO(); }; @@ -3483,6 +3485,12 @@ struct ImGuiPlatformIO // Inputs - Interface with OS/backends //------------------------------------------------------------------ + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); + void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text); + void* Platform_ClipboardUserData; + // Optional: Open link/folder/file in OS Shell // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f4625f2a7..2d96ed909 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4740,7 +4740,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (is_cut || is_copy) { // Cut, Copy - if (io.SetClipboardTextFn) + if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) { const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; From 5de7f69cbb9d52dc2cebb27261dfadcf0da3840d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 19:53:49 +0200 Subject: [PATCH 076/136] (BREAKING) Commented out obsolete ImageButton(). (#5533, #4471, #2464, #1390) --- docs/CHANGELOG.txt | 5 +++++ docs/TODO.txt | 1 + imgui.cpp | 5 +++++ imgui.h | 4 ++-- imgui_widgets.cpp | 20 ++++++++------------ 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 25cd2b8c7..181cccfc1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,11 @@ Breaking changes: (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and often automatically set by core library and backends, we are exceptionally not maintaining a legacy redirection symbol for those two.) +- Commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). (#5533, #4471, #2464, #1390) + - old ImageButton() used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID) + - new ImageButton() requires an explicit 'const char* str_id' + - old ImageButton() had frame_padding' override argument. + - new ImageButton() always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar(). Other changes: diff --git a/docs/TODO.txt b/docs/TODO.txt index cd992784d..84a00bc6e 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -190,6 +190,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - tree node/opt: could avoid formatting when clipped (flag assuming we don't care about width/height, assume single line height? format only %s/%c to be able to count height?) - settings: write more decent code to allow saving/loading new fields: columns, selected tree nodes? + - settings: facilitate extension lazily calling AddSettingsHandler() while running and still getting their data call the ReadXXX handlers immediately. - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437) - settings/persistence: helpers to make TreeNodeBehavior persist (even during dev!) - may need to store some semantic and/or data type in ImGuiStoragePair diff --git a/imgui.cpp b/imgui.cpp index 381ffb259..457fc2031 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -438,6 +438,11 @@ CODE - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) - access those via GetPlatformIO() instead of GetIO(). some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol. + - commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). As a reminder: + - old ImageButton() before 1.89 used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID) + - new ImageButton() since 1.89 requires an explicit 'const char* str_id' + - old ImageButton() before 1.89 had frame_padding' override argument. + - new ImageButton() since 1.89 always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar(). - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way. - instead of: GetWindowContentRegionMax().x - GetCursorPos().x diff --git a/imgui.h b/imgui.h index 2825cc60c..1aea4c811 100644 --- a/imgui.h +++ b/imgui.h @@ -3547,13 +3547,13 @@ namespace ImGui // OBSOLETED in 1.89.4 (from March 2023) static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopAllowKeyboardFocus() { PopItemFlag(); } - // OBSOLETED in 1.89 (from August 2022) - IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding) // OBSOLETED in 1.87 (from February 2022 but more formally obsoleted April 2024) IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + //-- OBSOLETED in 1.89 (from August 2022) + //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version. //-- OBSOLETED in 1.88 (from May 2022) //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d96ed909..5b7898edd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1108,28 +1108,24 @@ bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const I #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy API obsoleted in 1.89. Two differences with new ImageButton() -// - new ImageButton() requires an explicit 'const char* str_id' Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID) -// - new ImageButton() always use style.FramePadding Old ImageButton() had an override argument. -// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions. +// - old ImageButton() used ImTextureId as item id (created issue with multiple buttons with same image, transient texture id values, opaque computation of ID) +// - new ImageButton() requires an explicit 'const char* str_id' +// - old ImageButton() had frame_padding' override argument. +// - new ImageButton() always use style.FramePadding. +/* bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->SkipItems) - return false; - // Default to using texture ID as ID. User can still push string/integer prefixes. PushID((void*)(intptr_t)user_texture_id); - const ImGuiID id = window->GetID("#image"); - PopID(); - if (frame_padding >= 0) PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding)); - bool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col); + bool ret = ImageButton("", user_texture_id, size, uv0, uv1, bg_col, tint_col); if (frame_padding >= 0) PopStyleVar(); + PopID(); return ret; } +*/ #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS bool ImGui::Checkbox(const char* label, bool* v) From d15da2c47d98a8bf5a09219ea6d310710972f8bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Aug 2024 20:27:50 +0200 Subject: [PATCH 077/136] Backends: GLFW: undo accidentally not committing use of Platform_SetClipboardTextFn as I was testing the legacy path (amend 214977e). --- backends/imgui_impl_glfw.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 66b71c5e7..ee230ee1b 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -180,16 +180,6 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() } // Functions -static const char* ImGui_ImplGlfw_GetClipboardText(void*) -{ - return glfwGetClipboardString(NULL); -} - -static void ImGui_ImplGlfw_SetClipboardText(void*, const char* text) -{ - glfwSetClipboardString(NULL, text); -} - static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) { switch (key) @@ -591,8 +581,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Time = 0.0; ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; - io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(NULL, text); }; + platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(NULL); }; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif From d474ed7f78c505308a54c70dd51c24c6965f605f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 12:47:40 +0200 Subject: [PATCH 078/136] InputText: Internals: store Scroll.y as it seems sane to (internally) expose it in a way that's agnostic of our use of a child window (#7913, #383) --- imgui.h | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 20 ++++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/imgui.h b/imgui.h index 1aea4c811..028adafb8 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.1 WIP" -#define IMGUI_VERSION_NUM 19103 +#define IMGUI_VERSION_NUM 19104 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 6bd2aa457..537f51329 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1121,7 +1121,7 @@ struct IMGUI_API ImGuiInputTextState ImVector InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) int BufCapacityA; // end-user buffer capacity - float ScrollX; // horizontal scrolling/offset + ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) ImStb::STB_TexteditState Stb; // state for stb_textedit.h float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5b7898edd..63c4b21cd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4407,7 +4407,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - state->ScrollX = 0.0f; + state->Scroll = ImVec2(0.0f, 0.0f); stb_textedit_initialize_state(&state->Stb, !is_multiline); } @@ -4459,6 +4459,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // FIXME: May be a problem to always steal Alt on OSX, would ideally still allow an uninterrupted Alt down-up to toggle menu if (is_osx) SetKeyOwner(ImGuiMod_Alt, id); + + // Expose scroll in a manner that is agnostic to us using a child window + if (is_multiline) + state->Scroll.y = draw_window->Scroll.y; } // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) @@ -4522,7 +4526,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ g.ActiveIdAllowOverlap = !io.MouseDown[0]; // Edit in progress - const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->Scroll.x; const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); if (select_all) @@ -5078,14 +5082,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { const float scroll_increment_x = inner_size.x * 0.25f; const float visible_width = inner_size.x - style.FramePadding.x; - if (cursor_offset.x < state->ScrollX) - state->ScrollX = IM_TRUNC(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); - else if (cursor_offset.x - visible_width >= state->ScrollX) - state->ScrollX = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x); + if (cursor_offset.x < state->Scroll.x) + state->Scroll.x = IM_TRUNC(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); + else if (cursor_offset.x - visible_width >= state->Scroll.x) + state->Scroll.x = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x); } else { - state->ScrollX = 0.0f; + state->Scroll.y = 0.0f; } // Vertical scroll @@ -5106,7 +5110,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Draw selection - const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); + const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f); if (render_selection) { const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); From ce484301c0f9c1aeedb5427b186ab7dd2dc4b9a3 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Fri, 23 Aug 2024 14:12:18 +0200 Subject: [PATCH 079/136] CI: Add manual trigger for 'workflow_run' builds (#7865) --- .github/workflows/build.yml | 1 + .github/workflows/manual.yml | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 .github/workflows/manual.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b223d2261..4320a2025 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: # "scheduled" workflow, while maintaining ability to perform local CI builds. workflows: - scheduled + - manual branches: - master - docking diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml new file mode 100644 index 000000000..3c472f1bf --- /dev/null +++ b/.github/workflows/manual.yml @@ -0,0 +1,12 @@ +# +# This is a dummy workflow used to trigger full builds manually. +# +name: manual + +on: workflow_dispatch + +jobs: + manual: + runs-on: ubuntu-latest + steps: + - run: exit 0 From 438f9e1a3e7f7d63d0d20b50cc199e5f714895f2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 14:14:07 +0200 Subject: [PATCH 080/136] InputText: amend d474ed7 for static analysis. (#7913) --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 63c4b21cd..c55e95500 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4461,7 +4461,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ SetKeyOwner(ImGuiMod_Alt, id); // Expose scroll in a manner that is agnostic to us using a child window - if (is_multiline) + if (is_multiline && state != NULL) state->Scroll.y = draw_window->Scroll.y; } From 088e6fc04715dde2969cd584073c5150521b148a Mon Sep 17 00:00:00 2001 From: BillKek <51540758+BillKek@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:44:00 +0300 Subject: [PATCH 081/136] Examples: Win32+OpenGL3: added batch. file for msys2/mingw build. (#6544) --- examples/example_win32_opengl3/build_mingw.bat | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 examples/example_win32_opengl3/build_mingw.bat diff --git a/examples/example_win32_opengl3/build_mingw.bat b/examples/example_win32_opengl3/build_mingw.bat new file mode 100644 index 000000000..767218585 --- /dev/null +++ b/examples/example_win32_opengl3/build_mingw.bat @@ -0,0 +1,8 @@ +@REM Build for MINGW64 or 32 from MSYS2. +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_opengl3 +@set INCLUDES=-I../.. -I../../backends +@set SOURCES=main.cpp ../../backends/imgui_impl_opengl3.cpp ../../backends/imgui_impl_win32.cpp ../../imgui*.cpp +@set LIBS=-lopengl32 -lgdi32 -ldwmapi +mkdir %OUT_DIR% +g++ -DUNICODE %INCLUDES% %SOURCES% -o %OUT_DIR%/%OUT_EXE%.exe --static -mwindows %LIBS% %LIBS% From 1e939fcc32af81c755c31edb9db3357f9fb50d19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 14:55:27 +0200 Subject: [PATCH 082/136] Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside a drag and drop source or target. (#6973) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 181cccfc1..692c48f1a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,8 @@ Other changes: - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) +- Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside + a drag and drop source or target: a SetNextWindowPos() call won't be overriden. (#6973) - Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. - Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not diff --git a/imgui.cpp b/imgui.cpp index 457fc2031..17f19bc22 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11096,7 +11096,8 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale; - SetNextWindowPos(tooltip_pos); + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + SetNextWindowPos(tooltip_pos); SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( tooltip_flags |= ImGuiTooltipFlags_OverridePrevious; @@ -15937,7 +15938,7 @@ static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags) void ImGui::ShowDebugLogWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) { @@ -16254,7 +16255,7 @@ static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_f void ImGui::ShowIDStackToolWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { From 0b9adc2c799f5ed6b33fefd7cdb3c68d10751a29 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 15:24:22 +0200 Subject: [PATCH 083/136] BeginChild: (BREAKING) renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders. Amend 7713c2925 + renamed similar argument in other functions. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 18 ++++++++++-------- imgui.h | 19 ++++++++++++------- imgui_demo.cpp | 36 ++++++++++++++++++------------------ imgui_internal.h | 2 +- imgui_tables.cpp | 4 ++-- imgui_widgets.cpp | 4 ++-- 7 files changed, 49 insertions(+), 38 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 692c48f1a..a05f91b88 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ HOW TO UPDATE? Breaking changes: +- BeginChild(): renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. [@cfillion] + Kept inline redirection flag (will obsolete). - IO: moved clipboard functions from ImGuiIO to ImGuiPlatformIO: - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn @@ -845,6 +847,7 @@ Breaking changes: Before: BeginChild("Name", size, false) After: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) Existing code will still work as 'ImGuiChildFlags_Border == true', but you are encouraged to update call sites. + **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - BeginChild(): Added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for use with BeginChild() anyhow, passing it to Begin() had no effect. Now that we accept @@ -894,6 +897,7 @@ Other changes: child windows from the bottom/right border (toward layout direction). Resized child windows settings are saved and persistent in .ini file. (#1710) - BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter. + **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - BeginChild(): Added ImGuiChildFlags_AutoResizeX and ImGuiChildFlags_AutoResizeY to auto-resize on one axis, while generally providing a size on the other axis. (#1666, #1395, #1496, #1710) e.g. BeginChild("name", {-FLT_MIN, 0.0f}, ImGuiChildFlags_AutoResizeY); diff --git a/imgui.cpp b/imgui.cpp index 17f19bc22..fbf067879 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/08/23 (1.91.1) - renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. kept inline redirection flag. - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + changed 'void* user_data' to 'ImGuiContext* ctx'. Pull your user data from platform_io.ClipboardUserData. - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + same as above line. @@ -514,6 +515,7 @@ CODE - new: BeginChild("Name", size, ImGuiChildFlags_Border) - old: BeginChild("Name", size, false) - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) + **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow. - old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding); - new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0); @@ -3637,13 +3639,13 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con } // Render a rectangle shaped with optional rounding and borders -void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders, float rounding) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); const float border_size = g.Style.FrameBorderSize; - if (border && border_size > 0.0f) + if (borders && border_size > 0.0f) { window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); @@ -5623,7 +5625,7 @@ ImVec2 ImGui::GetItemRectSize() } // Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'. -// ImGuiChildFlags_Border is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details! +// ImGuiChildFlags_Borders is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details! bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGuiID id = GetCurrentWindow()->GetID(str_id); @@ -5642,7 +5644,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I IM_ASSERT(id != 0); // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument. - const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened; + const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened; IM_UNUSED(ImGuiChildFlags_SupportedMask_); IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?"); IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!"); @@ -5677,7 +5679,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I PushStyleVar(ImGuiStyleVar_ChildRounding, g.Style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, g.Style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.FramePadding); - child_flags |= ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding; + child_flags |= ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding; window_flags |= ImGuiWindowFlags_NoMove; } @@ -5707,7 +5709,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I // Set style const float backup_border_size = g.Style.ChildBorderSize; - if ((child_flags & ImGuiChildFlags_Border) == 0) + if ((child_flags & ImGuiChildFlags_Borders) == 0) g.Style.ChildBorderSize = 0.0f; // Begin into window @@ -15804,7 +15806,7 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); if (flags & ImGuiWindowFlags_ChildWindow) BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags, - (window->ChildFlags & ImGuiChildFlags_Border) ? "Border " : "", + (window->ChildFlags & ImGuiChildFlags_Borders) ? "Borders " : "", (window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "", (window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "", (window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : ""); @@ -15983,7 +15985,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) EndPopup(); } - BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); const ImGuiDebugLogFlags backup_log_flags = g.DebugLogFlags; g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper; diff --git a/imgui.h b/imgui.h index 028adafb8..cc89955d0 100644 --- a/imgui.h +++ b/imgui.h @@ -369,10 +369,10 @@ namespace ImGui // Child Windows // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false". - // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Border == true. + // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true. // Consider updating your old code: // BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None); - // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Border); + // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders); // - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): // == 0.0f: use remaining parent window size for this axis. // > 0.0f: use specified size for this axis. @@ -843,7 +843,7 @@ namespace ImGui // Legacy Columns API (prefer using Tables!) // - You can also use SameLine(pos_x) to mimic simplified columns. - IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool borders = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column @@ -1098,7 +1098,7 @@ enum ImGuiWindowFlags_ }; // Flags for ImGui::BeginChild() -// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Border to be backward compatible with old API using 'bool border = false'. +// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool border = false'. // About using AutoResizeX/AutoResizeY flags: // - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints"). // - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing. @@ -1109,7 +1109,7 @@ enum ImGuiWindowFlags_ enum ImGuiChildFlags_ { ImGuiChildFlags_None = 0, - ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason) + ImGuiChildFlags_Borders = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason) ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense) ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags) ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " @@ -1118,6 +1118,11 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. + + // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiChildFlags_Border = ImGuiChildFlags_Borders, // Renamed in 1.91.1 (August 2024) for consistency. +#endif }; // Flags for ImGui::PushItemFlag() @@ -3537,8 +3542,8 @@ namespace ImGui // OBSOLETED in 1.90.0 (from September 2023) static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } static inline void EndChildFrame() { EndChild(); } - //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border - //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border + //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders + //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ddc8f9b2a..a729e45b2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2762,7 +2762,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) static bool embed_all_inside_a_child_window = false; ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Border); + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); // Testing IsWindowFocused() function with its various flags. ImGui::BulletText( @@ -2810,7 +2810,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); - ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Border); + ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders); ImGui::Text("This is another child window for testing the _ChildWindows flag."); ImGui::EndChild(); if (embed_all_inside_a_child_window) @@ -3375,7 +3375,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width. - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items)); ImGuiSelectionExternalStorage storage_wrapper; @@ -3881,7 +3881,7 @@ static void ShowDemoWindowLayout() if (!disable_menu) window_flags |= ImGuiWindowFlags_MenuBar; ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Border, window_flags); + ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags); if (!disable_menu && ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) @@ -3911,7 +3911,7 @@ static void ShowDemoWindowLayout() { HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents."); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg)); - if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) for (int n = 0; n < 10; n++) ImGui::Text("Line %04d", n); ImGui::PopStyleColor(); @@ -3929,7 +3929,7 @@ static void ShowDemoWindowLayout() ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); - if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) + if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY)) for (int n = 0; n < draw_lines; n++) ImGui::Text("Line %04d", n); ImGui::EndChild(); @@ -3947,11 +3947,11 @@ static void ShowDemoWindowLayout() { static int offset_x = 0; static bool override_bg_color = true; - static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; + static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); ImGui::Checkbox("Override ChildBg color", &override_bg_color); - ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border); + ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders); ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY); @@ -4361,7 +4361,7 @@ static void ShowDemoWindowLayout() const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Border, child_flags); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -4408,7 +4408,7 @@ static void ShowDemoWindowLayout() float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Border, child_flags); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) @@ -4450,7 +4450,7 @@ static void ShowDemoWindowLayout() ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); - ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() @@ -4596,7 +4596,7 @@ static void ShowDemoWindowLayout() } if (show_child) { - ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Border); + ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders); ImGui::EndChild(); } ImGui::End(); @@ -7942,7 +7942,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "Right-click to open edit options menu."); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); - ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); ImGui::PushItemWidth(ImGui::GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++) { @@ -8176,7 +8176,7 @@ static void ShowExampleMenuFile() { static bool enabled = true; ImGui::MenuItem("Enabled", "", &enabled); - ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Border); + ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders); for (int i = 0; i < 10; i++) ImGui::Text("Scrolling Text %d", i); ImGui::EndChild(); @@ -8773,7 +8773,7 @@ static void ShowExampleAppLayout(bool* p_open) // Left static int selected = 0; { - ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX); + ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX); for (int i = 0; i < 100; i++) { // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav @@ -8834,7 +8834,7 @@ struct ExampleAppPropertyEditor { // Left side: draw tree // - Currently using a table to benefit from RowBg feature - if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Border | ImGuiChildFlags_NavFlattened)) + if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened)) { ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); @@ -9448,7 +9448,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) // To use a child window instead we could use, e.g: // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color - // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove); + // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); // ImGui::PopStyleColor(); // ImGui::PopStyleVar(); // [...] @@ -10100,7 +10100,7 @@ struct ExampleAssetsBrowser ImGuiIO& io = ImGui::GetIO(); ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing))); - if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove)) + if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); diff --git a/imgui_internal.h b/imgui_internal.h index 537f51329..884c85a19 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3508,7 +3508,7 @@ namespace ImGui IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); - IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_None); // Navigation highlight diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 92c62949e..3d757fd98 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -4428,12 +4428,12 @@ void ImGui::EndColumns() NavUpdateCurrentWindowIsScrollPushableX(); } -void ImGui::Columns(int columns_count, const char* id, bool border) +void ImGui::Columns(int columns_count, const char* id, bool borders) { ImGuiWindow* window = GetCurrentWindow(); IM_ASSERT(columns_count >= 1); - ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); + ImGuiOldColumnFlags flags = (borders ? 0 : ImGuiOldColumnFlags_NoBorder); //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior ImGuiOldColumns* columns = window->DC.CurrentColumns; if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c55e95500..ce80cfd87 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4312,7 +4312,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); g.NavActivateId = backup_activate_id; PopStyleVar(3); PopStyleColor(); @@ -5242,7 +5242,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); - if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) // Visualize undo state + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state { PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); for (int n = 0; n < IMSTB_TEXTEDIT_UNDOSTATECOUNT; n++) From a131c3e6111952d0e8fd898763fe7cd3b2172ee3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 18:24:44 +0200 Subject: [PATCH 084/136] Tables: revert a34071876 extending outer bottom/right border by 1, this is not the right solution. (#6765, #3752) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a05f91b88..e4584d686 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,6 +80,8 @@ Other changes: payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) +- Tables: revert 1.90 extension of bottom-most and right-most outer border offset by one. + This is not the right solution. (#6765, #3752) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3d757fd98..92ab79a7f 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2743,7 +2743,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) const ImU32 outer_col = table->BorderColorStrong; if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) { - inner_drawlist->AddRect(outer_border.Min, outer_border.Max + ImVec2(1, 1), outer_col, 0.0f, 0, border_size); + inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); } else if (table->Flags & ImGuiTableFlags_BordersOuterV) { From 864a2bf6b824f9c1329d8493386208d4b0fd311c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 19:12:54 +0200 Subject: [PATCH 085/136] Tables: another attempt at making contents not overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) --- docs/CHANGELOG.txt | 5 +++-- imgui_tables.cpp | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e4584d686..d19e8f39e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,8 +80,9 @@ Other changes: payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) -- Tables: revert 1.90 extension of bottom-most and right-most outer border offset by one. - This is not the right solution. (#6765, #3752) +- Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right + by an extra pixel + rework the change so that contents doesn't overlap the bottom and + right border in a scrolling table. (#6765, #3752, #7428) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 92ab79a7f..fd7e6da57 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -460,16 +460,27 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); - // Make left and top borders not overlap our contents by offsetting HostClipRect (#6765) + // Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752) // (we normally shouldn't alter HostClipRect as we rely on TableMergeDrawChannels() expanding non-clipped column toward the // limits of that rectangle, in order for ImDrawListSplitter::Merge() to merge the draw commands. However since the overlap // problem only affect scrolling tables in this case we can get away with doing it without extra cost). if (inner_window != outer_window) { + // FIXME: Because inner_window's Scrollbar doesn't know about border size, since it's not encoded in window->WindowBorderSize, + // it already overlaps it and doesn't need an extra offset. Ideally we should be able to pass custom border size with + // different x/y values to BeginChild(). if (flags & ImGuiTableFlags_BordersOuterV) + { table->HostClipRect.Min.x = ImMin(table->HostClipRect.Min.x + TABLE_BORDER_SIZE, table->HostClipRect.Max.x); + if (inner_window->DecoOuterSizeX2 == 0.0f) + table->HostClipRect.Max.x = ImMax(table->HostClipRect.Max.x - TABLE_BORDER_SIZE, table->HostClipRect.Min.x); + } if (flags & ImGuiTableFlags_BordersOuterH) + { table->HostClipRect.Min.y = ImMin(table->HostClipRect.Min.y + TABLE_BORDER_SIZE, table->HostClipRect.Max.y); + if (inner_window->DecoOuterSizeY2 == 0.0f) + table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y); + } } // Padding and Spacing @@ -497,7 +508,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect; table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width table->InnerClipRect.ClipWithFull(table->HostClipRect); - table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; + table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y; table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() @@ -1249,7 +1260,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (table->Flags & ImGuiTableFlags_NoClip) table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); else - inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); + inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); } // Process hit-testing on resizing borders. Actual size change will be applied in EndTable() From 1d88609043fd7a25df7f5f4acd7aa3cc4aaf8033 Mon Sep 17 00:00:00 2001 From: tanoxyz <36295026+tanoxyz@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:40:48 +0200 Subject: [PATCH 086/136] Changed call from cosf to ImCos (#7939) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fbf067879..2b4099966 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14757,7 +14757,7 @@ void ImGui::UpdateDebugToolFlashStyleColor() ImGuiContext& g = *GImGui; if (g.DebugFlashStyleColorTime <= 0.0f) return; - ColorConvertHSVtoRGB(cosf(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z); + ColorConvertHSVtoRGB(ImCos(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z); g.Style.Colors[g.DebugFlashStyleColorIdx].w = 1.0f; if ((g.DebugFlashStyleColorTime -= g.IO.DeltaTime) <= 0.0f) DebugFlashStyleColorStop(); From 28caa223567cef70c295d58ec23fefc6125e4bbe Mon Sep 17 00:00:00 2001 From: James Wrigley Date: Tue, 3 Sep 2024 00:50:20 +0200 Subject: [PATCH 087/136] Fix minor typo (#7943) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index cc89955d0..f6b7a7d0b 100644 --- a/imgui.h +++ b/imgui.h @@ -460,7 +460,7 @@ namespace ImGui // - Use the ShowStyleEditor() function to interactively see/edit the colors. IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied - IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList From 4a06fe59b4d2dcd14ab9f79b7644ebad9a6d007a Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 3 Sep 2024 15:32:40 +0200 Subject: [PATCH 088/136] Update FONTS.md (#7944) --- docs/FONTS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index df8b610e5..c451af61c 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -50,7 +50,9 @@ All loaded fonts glyphs are rendered into a single texture atlas ahead of time. ### (4) Font atlas texture fails to upload to GPU. -This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. +This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty white rectangles.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. + +![empty squares](https://github.com/user-attachments/assets/68b50fb5-8b9d-4c38-baec-6ac384f06d26) Some solutions: - You may reduce oversampling, e.g. `font_config.OversampleH = 1`, this will half your texture size for a quality loss. @@ -60,6 +62,8 @@ Some solutions: - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. - Set `io.Fonts.TexDesiredWidth` to specify a texture width to reduce maximum texture height (see comment in `ImFontAtlas::Build()` function). +Future versions of Dear ImGui should solve this problem. + ##### [Return to Index](#index) --------------------------------------- From ee9e3a2ed66bd618ca17ebcba18088e4c9c64bd2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Aug 2024 19:40:47 +0200 Subject: [PATCH 089/136] Tabs: avoid queuing a refocus when tab is already focused, which would have the side-effect of e.g. closing popup on a mouse release. (#7914) + Debug Log: add details about closed popups. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 3 +++ imgui_widgets.cpp | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d19e8f39e..028f12d4c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other changes: - Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right by an extra pixel + rework the change so that contents doesn't overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) +- Tabs: avoid queuing a refocus when tab is already focused, which would have the + side-effect of e.g. closing popup on a mouse release. (#7914) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) diff --git a/imgui.cpp b/imgui.cpp index 2b4099966..dfa74d994 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11370,6 +11370,9 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ ImGuiContext& g = *GImGui; IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d\n", remaining, restore_focus_to_window_under_popup); IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); + if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) + for (int n = remaining; n < g.OpenPopupStack.Size; n++) + IMGUI_DEBUG_LOG_POPUP("[popup] - Closing PopupID 0x%08X Window \"%s\"\n", g.OpenPopupStack[n].PopupId, g.OpenPopupStack[n].Window ? g.OpenPopupStack[n].Window->Name : NULL); // Trim open popup stack ImGuiPopupData prev_popup = g.OpenPopupStack[remaining]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ce80cfd87..436d81b0a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -9986,7 +9986,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) TabBarQueueFocus(tab_bar, tab); if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) From 6a7319543c4b0bfdf3b6b06ce8a14d762aba985e Mon Sep 17 00:00:00 2001 From: Matt Guerrette Date: Sun, 25 Aug 2024 13:07:10 -0400 Subject: [PATCH 090/136] Backends: SDL3: following SDL3 reverting their change, result of SDL_GetGamepads must be freed. (#7918, #7898, #7807) --- backends/imgui_impl_sdl3.cpp | 4 +++- docs/CHANGELOG.txt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index deb8c7925..0387b155c 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn @@ -672,7 +673,7 @@ static void ImGui_ImplSDL3_UpdateGamepads() { ImGui_ImplSDL3_CloseGamepads(); int sdl_gamepads_count = 0; - const SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count); + SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count); for (int n = 0; n < sdl_gamepads_count; n++) if (SDL_Gamepad* gamepad = SDL_OpenGamepad(sdl_gamepads[n])) { @@ -681,6 +682,7 @@ static void ImGui_ImplSDL3_UpdateGamepads() break; } bd->WantUpdateGamepadsList = false; + SDL_free(sdl_gamepads); } // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 028f12d4c..dbb0917ff 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -96,6 +96,8 @@ Other changes: provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. +- Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership logic was reverted back + by SDL3 on July 27. (#7918, #7898, #7807) [@cheyao, @MattGuerrette] - Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() since GLFW own tests are doing that and it seems unnecessary. - Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO @@ -103,7 +105,7 @@ Other changes: - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) - +Backends: SDL3: following SDL3 reverting their change, result of SDL_GetGamepads must be freed. (#7918, #7898) ----------------------------------------------------------------------- VERSION 1.91.0 (Released 2024-07-30) From 4832027eb6a313dedb4c4d0a04c6352a0e68e83f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Sep 2024 19:05:32 +0200 Subject: [PATCH 091/136] Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure. --- backends/imgui_impl_sdl3.cpp | 2 +- backends/imgui_impl_sdl3.h | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 ++ backends/imgui_impl_sdlrenderer3.h | 2 ++ docs/CHANGELOG.txt | 27 ++++++++++++--------- examples/example_sdl3_opengl3/main.cpp | 2 +- examples/example_sdl3_sdlrenderer3/main.cpp | 2 +- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 0387b155c..540b6931a 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -2,7 +2,7 @@ // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN**) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) // Implemented features: // [X] Platform: Clipboard support. diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 39b7839d8..880ba9615 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -2,7 +2,7 @@ // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN**) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) // Implemented features: // [X] Platform: Clipboard support. diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 8ba262548..d3926c2fb 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -1,6 +1,8 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 // (Requires: SDL 3.0.0+) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) + // Note how SDL_Renderer is an _optional_ component of SDL3. // For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. // If your application will want to render any non trivial amount of graphics other than UI, diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 1a730208a..6c23deca9 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -1,6 +1,8 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 // (Requires: SDL 3.0.0+) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) + // Note how SDL_Renderer is an _optional_ component of SDL3. // For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. // If your application will want to render any non trivial amount of graphics other than UI, diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dbb0917ff..9065b46ee 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -92,18 +92,21 @@ Other changes: a drag and drop source or target: a SetNextWindowPos() call won't be overriden. (#6973) - Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. - Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) -- Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not - provide a way to do a portable sleep. (#7844) -- Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] -- Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. -- Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership logic was reverted back - by SDL3 on July 27. (#7918, #7898, #7807) [@cheyao, @MattGuerrette] -- Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() - since GLFW own tests are doing that and it seems unnecessary. -- Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO - instead of ImGuiIO. -- Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop - to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) +- Backends: + - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not + provide a way to do a portable sleep. (#7844) + - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] + - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. + - Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership logic was reverted back + by SDL3 on July 27. (#7918, #7898, #7807) [@cheyao, @MattGuerrette] + - Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() + since GLFW own tests are doing that and it seems unnecessary. + - Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO + instead of ImGuiIO. +- Examples: + - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop + to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) + - Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure. Backends: SDL3: following SDL3 reverting their change, result of SDL_GetGamepads must be freed. (#7918, #7898) diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index e6aba8809..0ba09dc93 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -27,7 +27,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0) + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 6efd2754a..ef98d752d 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -25,7 +25,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0) + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; From 07be01767afd005372035e471f8ac6e85e200001 Mon Sep 17 00:00:00 2001 From: Yan Pujante Date: Fri, 23 Aug 2024 10:05:38 -0700 Subject: [PATCH 092/136] Demo: added emscripten version. (#7915) --- imgui_demo.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a729e45b2..fe38ebf2e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -116,6 +116,9 @@ Index of this file: #if !defined(_MSC_VER) || _MSC_VER >= 1800 #include // PRId64/PRIu64, not avail in some MinGW headers. #endif +#ifdef __EMSCRIPTEN__ +#include // __EMSCRIPTEN_major__ etc. +#endif // Visual Studio warnings #ifdef _MSC_VER @@ -7688,6 +7691,7 @@ void ImGui::ShowAboutWindow(bool* p_open) #endif #ifdef __EMSCRIPTEN__ ImGui::Text("define: __EMSCRIPTEN__"); + ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__); #endif ImGui::Separator(); ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); From 30dcdcbe736f551c0d7bc87ce5ed43edc835d7a2 Mon Sep 17 00:00:00 2001 From: Yan Pujante Date: Fri, 23 Aug 2024 09:56:02 -0700 Subject: [PATCH 093/136] Backends: GLFW: Emscripten: use OpenURL() when available and using EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3. Fixes popup blocked in some browsers. (#7915, #7660) --- backends/imgui_impl_glfw.cpp | 6 +++++- docs/CHANGELOG.txt | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index ee230ee1b..06b5142a1 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -560,7 +560,11 @@ void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows) } #ifdef __EMSCRIPTEN__ -EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (char const* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); +#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 3'4'0'20240817 +void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); } +#else +EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); +#endif #endif static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9065b46ee..6bedd7173 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -95,6 +95,8 @@ Other changes: - Backends: - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) + - Backends: GLFW+Emscripten: Use OpenURL() from GLFW3 contrib port when available and using + the contrib port instead of Emscripten own GLFW3 implementation. (#7647, #7915, #7660) [@ypujante] - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. - Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership logic was reverted back @@ -103,6 +105,7 @@ Other changes: since GLFW own tests are doing that and it seems unnecessary. - Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO instead of ImGuiIO. + - Examples: - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) @@ -262,7 +265,7 @@ Other changes: - Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. - Backends: GLFW,SDL2: Added io.PlatformOpenInShellFn handler for web/Emscripten versions. (#7660) [@ypujante, @ocornut] - - Backends; GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things + - Backends: GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things not supported by the embedded GLFW: gamepad support, mouse cursor shapes, copy to clipboard, workaround for Super/Meta key, different ways of resizing, multi-window (glfw/canvas) support. (#7647) [@ypujante] From a93f7db875cbda4abe50f3e347879508c8490be4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Sep 2024 20:55:00 +0200 Subject: [PATCH 094/136] Misc merge/small stuff from docking to reduce drift. Among other things: - merged cfd23957 (#7940, #7823), also see ac64b6563 (#6716): moved above on 2023/08/14 in both branches. - moving the RenderDimmedBackgrounds() call, from f422e782, see 676497fe intently undoing ac64b65 -> confusing. (#6716) --- docs/CHANGELOG.txt | 3 --- imgui.cpp | 49 +++++++++++++++++++++++++--------------------- imgui.h | 4 ++-- imgui_internal.h | 24 ++++++++++++++--------- imgui_widgets.cpp | 4 ++-- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6bedd7173..22df64e0f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -105,14 +105,11 @@ Other changes: since GLFW own tests are doing that and it seems unnecessary. - Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO instead of ImGuiIO. - - Examples: - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) - Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure. -Backends: SDL3: following SDL3 reverting their change, result of SDL_GetGamepads must be freed. (#7918, #7898) - ----------------------------------------------------------------------- VERSION 1.91.0 (Released 2024-07-30) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index dfa74d994..deb006e09 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1380,12 +1380,6 @@ ImGuiIO::ImGuiIO() FontAllowUserScaling = false; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); - MouseDoubleClickTime = 0.30f; - MouseDoubleClickMaxDist = 6.0f; - MouseDragThreshold = 6.0f; - KeyRepeatDelay = 0.275f; - KeyRepeatRate = 0.050f; - // Miscellaneous options MouseDrawCursor = false; #ifdef __APPLE__ @@ -1404,6 +1398,13 @@ ImGuiIO::ImGuiIO() ConfigDebugBeginReturnValueOnce = false; ConfigDebugBeginReturnValueLoop = false; + // Inputs Behaviors + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + MouseDragThreshold = 6.0f; + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + // Platform Functions // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; @@ -4229,8 +4230,9 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // Test if another item is active (e.g. being dragged) const ImGuiID id = g.LastItemData.ID; if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) - if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) - return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + if (g.ActiveId != window->MoveId) + return false; // Test if interactions on this window are blocked by an active popup or modal. // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. @@ -4242,7 +4244,8 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return false; // Special handling for calling after Begin() which represent the title bar or tab. - // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + // When the window is skipped/collapsed (SkipItems==true) that last item (always ->MoveId submitted by Begin) + // will never be overwritten so we need to detect the case. if (id == window->MoveId && window->WriteAccessed) return false; @@ -4640,9 +4643,10 @@ void ImGui::UpdateMouseMovingWindowEndFrame() StartMouseMovingWindow(g.HoveredWindow); //-V595 // Cancel moving if clicked outside of title bar - if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) - if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) - g.MovingWindow = NULL; + if (g.IO.ConfigWindowsMoveFromTitleBarOnly) + if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) if (g.HoveredIdIsDisabled) @@ -5200,7 +5204,7 @@ static void ImGui::RenderDimmedBackgrounds() } else if (dim_bg_for_window_list) { - // Draw dimming behind CTRL+Tab target window + // Draw dimming behind CTRL+Tab target window and behind CTRL+Tab UI window RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio)); // Draw border around CTRL+Tab target window @@ -5325,9 +5329,6 @@ void ImGui::Render() g.IO.MetricsRenderWindows = 0; CallContextHooks(&g, ImGuiContextHookType_RenderPre); - // Draw modal/window whitening backgrounds - RenderDimmedBackgrounds(); - // Add background ImDrawList (for each active viewport) for (ImGuiViewportP* viewport : g.Viewports) { @@ -5336,6 +5337,9 @@ void ImGui::Render() AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); } + // Draw modal/window whitening backgrounds + RenderDimmedBackgrounds(); + // Add ImDrawList to render ImGuiWindow* windows_to_render_top_most[2]; windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; @@ -14335,10 +14339,11 @@ static void ImGui::UpdateViewportsNewFrame() for (ImGuiViewportP* viewport : g.Viewports) { - // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. - viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; - viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; - viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); + // Lock down space taken by menu bars and status bars + // Setup initial value for functions like BeginMainMenuBar(), DockSpaceOverViewport() etc. + viewport->WorkInsetMin = viewport->BuildWorkInsetMin; + viewport->WorkInsetMax = viewport->BuildWorkInsetMax; + viewport->BuildWorkInsetMin = viewport->BuildWorkInsetMax = ImVec2(0.0f, 0.0f); viewport->UpdateWorkRect(); } } @@ -15762,9 +15767,9 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) if (open) { ImGuiWindowFlags flags = viewport->Flags; - BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Inset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, - viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); + viewport->WorkInsetMin.x, viewport->WorkInsetMin.y, viewport->WorkInsetMax.x, viewport->WorkInsetMax.y); BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", diff --git a/imgui.h b/imgui.h index f6b7a7d0b..3ded051f1 100644 --- a/imgui.h +++ b/imgui.h @@ -3447,7 +3447,7 @@ enum ImGuiViewportFlags_ ImGuiViewportFlags_None = 0, ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) - ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: is created/managed by the application (rather than a dear imgui backend) + ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the application (rather than a dear imgui backend) }; // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. @@ -3487,7 +3487,7 @@ struct ImGuiPlatformIO IMGUI_API ImGuiPlatformIO(); //------------------------------------------------------------------ - // Inputs - Interface with OS/backends + // Input - Interface with OS/backends //------------------------------------------------------------------ // Optional: Access OS clipboard diff --git a/imgui_internal.h b/imgui_internal.h index 884c85a19..70f7e4dca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -94,6 +94,7 @@ Index of this file: #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif // In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h @@ -1806,23 +1807,28 @@ struct ImGuiViewportP : public ImGuiViewport ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData - ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) - ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). - ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. - ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. + + // Per-viewport work area + // - Insets are >= 0.0f values, distance from viewport corners to work area. + // - BeginMainMenuBar() and DockspaceOverViewport() tend to use work area to avoid stepping over existing contents. + // - Generally 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land. + ImVec2 WorkInsetMin; // Work Area inset locked for the frame. GetWorkRect() always fits within GetMainRect(). + ImVec2 WorkInsetMax; // " + ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset + ImVec2 BuildWorkInsetMax; // " ImGuiViewportP() { BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; } ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) - ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } - ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } - void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields + ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& inset_min, const ImVec2& inset_max) const { return ImVec2(ImMax(0.0f, Size.x - inset_min.x - inset_max.x), ImMax(0.0f, Size.y - inset_min.y - inset_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkInsetMin); WorkSize = CalcWorkRectSize(WorkInsetMin, WorkInsetMax); } // Update public fields // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } - ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkInsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkInsetMin, BuildWorkInsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } }; //----------------------------------------------------------------------------- @@ -2612,7 +2618,7 @@ struct IMGUI_API ImGuiWindow ImVec2 WindowPadding; // Window padding at the time of Begin(). float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. float WindowBorderSize; // Window border size at the time of Begin(). - float TitleBarHeight, MenuBarHeight; + float TitleBarHeight, MenuBarHeight; // Note that those used to be function before 2024/05/28. If you have old code calling TitleBarHeight() you can change it to TitleBarHeight. float DecoOuterSizeX1, DecoOuterSizeY1; // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin(). float DecoOuterSizeX2, DecoOuterSizeY2; // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y). float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes). diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 436d81b0a..b550e8d84 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8557,9 +8557,9 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im // Report our size into work area (for next frame) using actual window size if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) - viewport->BuildWorkOffsetMin[axis] += axis_size; + viewport->BuildWorkInsetMin[axis] += axis_size; else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) - viewport->BuildWorkOffsetMax[axis] -= axis_size; + viewport->BuildWorkInsetMax[axis] += axis_size; } window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; From f99febfd6fa16d44ca73832d20a9367d433783d7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Sep 2024 21:19:25 +0200 Subject: [PATCH 095/136] Made BeginItemTooltip() and IsItemHovered() with delay flag infer an implicit ID using Pos only. (#7945, #1485, #143) Perhaps a better approach would be to: store last non-zero ID + count successive zero ID and combine then. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 +++++++++++- imgui.h | 2 +- imgui_internal.h | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 22df64e0f..066a61f02 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - Windows: adjust default ClipRect to better match rendering of thick borders (which are in theory not supported). Compensate for the fact that borders are centered around the windows edge rather than inner. (#7887, #7888 + #3312, #7540, #3756, #6170, #6365) +- Made BeginItemTooltip() and IsItemHovered() with delay flag infer an implicit ID (for + ID-less items such as Text element) in a way that works when item resizes. (#7945, #1485) - MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow diff --git a/imgui.cpp b/imgui.cpp index deb006e09..767dbf70d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4261,7 +4261,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) const float delay = CalcDelayFromHoveredFlags(flags); if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary)) { - ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect); + ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromPos(g.LastItemData.Rect.Min); if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id)) g.HoverItemDelayTimer = 0.0f; g.HoverItemDelayId = hover_delay_id; @@ -8367,6 +8367,16 @@ ImGuiID ImGuiWindow::GetID(int n) } // This is only used in rare/specific situations to manufacture an ID out of nowhere. +// FIXME: Consider instead storing last non-zero ID + count of successive zero-ID, and combine those? +ImGuiID ImGuiWindow::GetIDFromPos(const ImVec2& p_abs) +{ + ImGuiID seed = IDStack.back(); + ImVec2 p_rel = ImGui::WindowPosAbsToRel(this, p_abs); + ImGuiID id = ImHashData(&p_rel, sizeof(p_rel), seed); + return id; +} + +// " ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { ImGuiID seed = IDStack.back(); diff --git a/imgui.h b/imgui.h index 3ded051f1..f7b1f3a29 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.1 WIP" -#define IMGUI_VERSION_NUM 19104 +#define IMGUI_VERSION_NUM 19105 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 70f7e4dca..59d8af7eb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2715,6 +2715,7 @@ public: ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); ImGuiID GetID(int n); + ImGuiID GetIDFromPos(const ImVec2& p_abs); ImGuiID GetIDFromRectangle(const ImRect& r_abs); // We don't use g.FontSize because the window may be != g.CurrentWindow. @@ -3124,8 +3125,8 @@ namespace ImGui inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; } inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } - inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); } + inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } // Windows: Display Order and Focus Order IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); From afb15e9795888a704ca2c8d0eba6ae4dbd7ded11 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Sep 2024 21:49:35 +0200 Subject: [PATCH 096/136] PlotHistogram, PlotLines: register item ID in a more idiomatic manner. (#7935, #3072) --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 5 +++++ imgui_widgets.cpp | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 066a61f02..54b3e8cca 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -92,6 +92,8 @@ Other changes: - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside a drag and drop source or target: a SetNextWindowPos() call won't be overriden. (#6973) +- PlotHistogram, PlotLines: register item ID in a more idiomatic manner, fixes preventing + e.g. GetItemID() and other ID-based helper to work. (#7935, #3072) - Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. - Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fe38ebf2e..b83cf2987 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2004,6 +2004,10 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::Separator(); + ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); + ImGui::TextLinkOpenURL("https://github.com/epezent/implot"); + ImGui::Separator(); + ImGui::TreePop(); } @@ -6448,6 +6452,7 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX); ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable); + ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable); ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody); ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b550e8d84..99992a717 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8224,7 +8224,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, 0, &frame_bb)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_NoNav)) return -1; const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); From 776813416b5af283280250c08cc45af53fed066c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Sep 2024 21:55:26 +0200 Subject: [PATCH 097/136] PlotHistogram, PlotLines: use ButtonBehavior() to be idiomatic. (#7935, #3072) --- docs/CHANGELOG.txt | 4 ++-- imgui_widgets.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 54b3e8cca..d76a04042 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -92,8 +92,8 @@ Other changes: - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside a drag and drop source or target: a SetNextWindowPos() call won't be overriden. (#6973) -- PlotHistogram, PlotLines: register item ID in a more idiomatic manner, fixes preventing - e.g. GetItemID() and other ID-based helper to work. (#7935, #3072) +- PlotHistogram, PlotLines: register item ID and use button behavior in a more idiomatic manner, + fixes preventing e.g. GetItemID() and other ID-based helper to work. (#7935, #3072) - Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. - Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) - Backends: diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 99992a717..fd52c93cd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8226,7 +8226,8 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_NoNav)) return -1; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + bool hovered; + ButtonBehavior(frame_bb, id, &hovered, NULL); // Determine scale from values if not specified if (scale_min == FLT_MAX || scale_max == FLT_MAX) From 722a2a12fb2dc32d01fe28f226ec2d2e4e908498 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Sep 2024 14:41:22 +0200 Subject: [PATCH 098/136] Tables: comments. (#7937) --- imgui.h | 2 +- imgui_demo.cpp | 7 ++++++- imgui_tables.cpp | 9 +++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/imgui.h b/imgui.h index f7b1f3a29..cfee0fcc7 100644 --- a/imgui.h +++ b/imgui.h @@ -1948,7 +1948,7 @@ enum ImGuiTableColumnFlags_ ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. - ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit horizontal label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will submit an empty label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. You may append into this cell by calling TableSetColumnIndex() right after the TableHeadersRow() call. ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b83cf2987..5c9bcd3b4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6403,7 +6403,11 @@ static void ShowDemoWindowTables() // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. static bool column_selected[3] = {}; - // Instead of calling TableHeadersRow() we'll submit custom headers ourselves + // Instead of calling TableHeadersRow() we'll submit custom headers ourselves. + // (A different approach is also possible: + // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. + // - Call TableHeadersRow() normally. This will submit TableHeader() with no name. + // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) ImGui::TableNextRow(ImGuiTableRowFlags_Headers); for (int column = 0; column < COLUMNS_COUNT; column++) { @@ -6418,6 +6422,7 @@ static void ShowDemoWindowTables() ImGui::PopID(); } + // Submit table contents for (int row = 0; row < 5; row++) { ImGui::TableNextRow(); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index fd7e6da57..69d1322bd 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3018,7 +3018,8 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth() // The intent is that advanced users willing to create customized headers would not need to use this helper // and can create their own! For example: TableHeader() may be preceded by Checkbox() or other custom widgets. // See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this. -// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy. +// This code is intentionally written to not make much use of internal functions, to give you better direction +// if you need to write your own. // FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public. void ImGui::TableHeadersRow() { @@ -3026,7 +3027,8 @@ void ImGui::TableHeadersRow() ImGuiTable* table = g.CurrentTable; IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); - // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout) + // Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make + // it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this. if (!table->IsLayoutLocked) TableUpdateLayout(table); @@ -3043,8 +3045,7 @@ void ImGui::TableHeadersRow() if (!TableSetColumnIndex(column_n)) continue; - // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) - // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide. + // Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation) const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); PushID(column_n); TableHeader(name); From 8dd33839f026ddd154c550b72f21a70746e6cab5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Sep 2024 15:15:48 +0200 Subject: [PATCH 099/136] Tables: fixed an issue detecting hovering column/row when using multiple synched instances layed out at different X positions. (#7933) Was reading ClipRect from last frame. --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d76a04042..95745581a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -85,6 +85,8 @@ Other changes: - Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right by an extra pixel + rework the change so that contents doesn't overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) +- Tables: fixed an issue detecting hovering column/row when using multiple synched instances, + layed out at different X positions. (#7932) - Tabs: avoid queuing a refocus when tab is already focused, which would have the side-effect of e.g. closing popup on a mouse release. (#7914) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 69d1322bd..9ee70fc50 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1070,10 +1070,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) continue; } - // Detect hovered column - if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x) - table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; - // Lock start position column->MinX = offset_x; @@ -1128,8 +1124,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->Flags |= ImGuiTableColumnFlags_IsVisible; if (column->SortOrder != -1) column->Flags |= ImGuiTableColumnFlags_IsSorted; - if (table->HoveredColumnBody == column_n) + + // Detect hovered column + if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x) + { column->Flags |= ImGuiTableColumnFlags_IsHovered; + table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; + } // Alignment // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in From f75cf62d2f36a66fcdc7be7161a3798bea926509 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Sep 2024 15:31:39 +0200 Subject: [PATCH 100/136] Tables: fixed resizing columns when using multiple synched instances that are layed out at different X positions. (#7933) TableGetMaxColumnWidth() was using MinX from previous column. Storing info in column. Still incorrect interleaved data for multi-instances but it covers majority of use cases. --- docs/CHANGELOG.txt | 4 ++-- imgui_internal.h | 3 ++- imgui_tables.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 95745581a..4c2537a8c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -85,8 +85,8 @@ Other changes: - Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right by an extra pixel + rework the change so that contents doesn't overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) -- Tables: fixed an issue detecting hovering column/row when using multiple synched instances, - layed out at different X positions. (#7932) +- Tables: fixed an issue resizing columns or querying hovered column/row when using multiple + synched instances that are layed out at different X positions. (#7933) - Tabs: avoid queuing a refocus when tab is already focused, which would have the side-effect of e.g. closing popup on a mouse release. (#7914) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) diff --git a/imgui_internal.h b/imgui_internal.h index 59d8af7eb..cb7923c64 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2827,6 +2827,7 @@ struct ImGuiTableColumn float MaxX; float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() float WidthAuto; // Automatic width + float WidthMax; // Maximum width (FIXME: overwritten by each instance) float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). ImRect ClipRect; // Clipping rectangle for the column @@ -3470,7 +3471,7 @@ namespace ImGui IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); - IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableRemove(ImGuiTable* table); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 9ee70fc50..aaa40de81 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1074,8 +1074,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->MinX = offset_x; // Lock width based on start position and minimum/maximum width for this position - float max_width = TableGetMaxColumnWidth(table, column_n); - column->WidthGiven = ImMin(column->WidthGiven, max_width); + column->WidthMax = TableCalcMaxColumnWidth(table, column_n); + column->WidthGiven = ImMin(column->WidthGiven, column->WidthMax); column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth)); column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; @@ -2207,8 +2207,8 @@ void ImGui::TableEndCell(ImGuiTable* table) // Note that actual columns widths are computed in TableUpdateLayout(). //------------------------------------------------------------------------- -// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. -float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) +// Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis. +float ImGui::TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n) { const ImGuiTableColumn* column = &table->Columns[column_n]; float max_width = FLT_MAX; @@ -2270,7 +2270,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) IM_ASSERT(table->MinColumnWidth > 0.0f); const float min_width = table->MinColumnWidth; - const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); + const float max_width = ImMax(min_width, column_0->WidthMax); // Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933) column_0_width = ImClamp(column_0_width, min_width, max_width); if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) return; From 1dfbb100d6ca6e7d813102e979c07f66a56546bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Sep 2024 16:17:30 +0200 Subject: [PATCH 101/136] Version 1.91.1 --- docs/CHANGELOG.txt | 24 +++++++++++++----------- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 22 insertions(+), 20 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4c2537a8c..d7fec4cff 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,9 +36,11 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.1 WIP (In Progress) + VERSION 1.91.1 (Released 2024-09-04) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.1 + Breaking changes: - BeginChild(): renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. [@cfillion] @@ -54,7 +56,6 @@ Breaking changes: - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) - - clipboard function signature changed: - access those via GetPlatformIO() instead of GetIO(). (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and often automatically set by core library and backends, we are exceptionally not maintaining @@ -63,14 +64,14 @@ Breaking changes: - old ImageButton() used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID) - new ImageButton() requires an explicit 'const char* str_id' - old ImageButton() had frame_padding' override argument. - - new ImageButton() always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar(). + - new ImageButton() always use style.FramePadding, which you can modify using PushStyleVar()/PopStyleVar(). Other changes: - IO: Added GetPlatformIO() and ImGuiPlatformIO, pulled from 'docking' branch, which is a centralized spot to connect os/platform/renderer related functions. Clipboard, IME and OpenInShell hooks are moved here. (#7660) -- IO, InputText: fixed an issue where typing text in a InputText() would defer character +- IO, InputText: fixed an issue where typing text in an InputText() would defer character processing by one frame, because of the trickling input queue. Reworked interleaved keys<>char trickling to take account for keys known to input characters. (#7889, #4921, #4858) - Windows: adjust default ClipRect to better match rendering of thick borders (which are in @@ -78,10 +79,10 @@ Other changes: edge rather than inner. (#7887, #7888 + #3312, #7540, #3756, #6170, #6365) - Made BeginItemTooltip() and IsItemHovered() with delay flag infer an implicit ID (for ID-less items such as Text element) in a way that works when item resizes. (#7945, #1485) -- MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop - payload over an already open tree node would incorrectly select it. (#7850) -- MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow - when used in a multi-select context without any OpenOnXXX flags set. (#7850) +- MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload + over an already open tree node using multi-select would incorrectly select it. (#7850) +- MultiSelect+TreeNode: default open behavior is _OpenOnDoubleClick + _OpenOnArrow when + used in a multi-select context without any ImGuiTreeNode_OpenOnXXX flags set. (#7850) - Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right by an extra pixel + rework the change so that contents doesn't overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) @@ -93,11 +94,12 @@ Other changes: - InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside - a drag and drop source or target: a SetNextWindowPos() call won't be overriden. (#6973) + a drag and drop source or target: a SetNextWindowPos() call won't be overridden. (#6973) - PlotHistogram, PlotLines: register item ID and use button behavior in a more idiomatic manner, fixes preventing e.g. GetItemID() and other ID-based helper to work. (#7935, #3072) -- Style: added PushStyleVarX(), PushStyleVarY() helpers to modify only one component of a ImVec2 var. -- Fonts: made it possible to use PushFont()/PopFont() calls accross Begin() calls. (#3224, #3875, #6398, #7903) +- Style: added PushStyleVarX(), PushStyleVarY() helpers to conveniently modify only + one component of a ImVec2 var. +- Fonts: made it possible to use PushFont()/PopFont() calls across Begin() calls. (#3224, #3875, #6398, #7903) - Backends: - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) diff --git a/imgui.cpp b/imgui.cpp index 767dbf70d..ac76ddd19 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index cfee0fcc7..a6766e2d6 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.1 WIP" -#define IMGUI_VERSION_NUM 19105 +#define IMGUI_VERSION "1.91.1" +#define IMGUI_VERSION_NUM 19110 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5c9bcd3b4..9ca73806d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 65d68708d..e033c357c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index cb7923c64..a99cb2652 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index aaa40de81..5685c2ace 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fd52c93cd..7f2b12711 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 WIP +// dear imgui, v1.91.1 // (widgets code) /* From 41eebc87a06d15979ed0088a4f5ec5673ccc2f6c Mon Sep 17 00:00:00 2001 From: CrackedMatter <81803926+CrackedMatter@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:04:28 +0200 Subject: [PATCH 102/136] Fixed C++26 invalid enum operation (#7954) --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7f2b12711..b9e2ca2ce 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5196,7 +5196,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); - g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + g.NextItemData.ItemFlags |= (ImGuiItemFlags)ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); From e3cb016328468e5902127777fc08b0c249039aaa Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 15:15:49 +0200 Subject: [PATCH 103/136] CI: upgrade Ubuntu version to get newer Clang. Add C++26 build test. (#7954) --- .github/workflows/build.yml | 17 ++++++++++++++--- examples/example_null/Makefile | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4320a2025..4539ecbf6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -218,7 +218,7 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release' Linux: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -433,6 +433,17 @@ jobs: EOF clang++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp + - name: Build example_null (single file build, c++26) + run: | + cat > example_single_file.cpp <<'EOF' + + #define IMGUI_IMPLEMENTATION + #include "misc/single_file/imgui_single_file.h" + #include "examples/example_null/main.cpp" + + EOF + clang++ -I. -std=c++26 -Wall -Wformat -o example_single_file example_single_file.cpp + - name: Build example_null (without c++ runtime) run: | cat > example_single_file.cpp <<'EOF' @@ -481,7 +492,7 @@ jobs: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO Emscripten: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -508,7 +519,7 @@ jobs: make -C examples/example_glfw_wgpu -f Makefile.emscripten Android: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/examples/example_null/Makefile b/examples/example_null/Makefile index 9ceb35349..4a67cecd8 100644 --- a/examples/example_null/Makefile +++ b/examples/example_null/Makefile @@ -1,6 +1,6 @@ # # Cross Platform Makefile -# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1+ and Mac OS X # # Important: This is a "null backend" application, with no visible output or interaction! # This is used for testing purpose and continuous integration, and has little use for end-user. From 943fd216ecadedd4ca59bb3ec56730c73bb9295c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 15:19:04 +0200 Subject: [PATCH 104/136] CI: Amend e3cb016. --- .github/workflows/build.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4539ecbf6..7c7f7471f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -324,6 +324,18 @@ jobs: EOF g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp + - name: Build example_null (with C++26) + run: | + cat > example_single_file.cpp <<'EOF' + + #define IMGUI_DISABLE_OBSOLETE_KEYIO + #define IMGUI_IMPLEMENTATION + #include "misc/single_file/imgui_single_file.h" + #include "examples/example_null/main.cpp" + + EOF + g++ -I. -std=c++26 -Wall -Wformat -o example_single_file example_single_file.cpp + - name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_DEBUG_TOOLS) run: | cat > example_single_file.cpp <<'EOF' @@ -433,7 +445,7 @@ jobs: EOF clang++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp - - name: Build example_null (single file build, c++26) + - name: Build example_null (single file build, c++20) run: | cat > example_single_file.cpp <<'EOF' @@ -442,7 +454,7 @@ jobs: #include "examples/example_null/main.cpp" EOF - clang++ -I. -std=c++26 -Wall -Wformat -o example_single_file example_single_file.cpp + clang++ -I. -std=c++20 -Wall -Wformat -o example_single_file example_single_file.cpp - name: Build example_null (without c++ runtime) run: | From 4a1a38f7ed0ab89aa506dcba346e90d698d1a8d2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 15:28:41 +0200 Subject: [PATCH 105/136] CI: Amend 943fd21. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c7f7471f..702e281bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -324,7 +324,7 @@ jobs: EOF g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp - - name: Build example_null (with C++26) + - name: Build example_null (with C++20) run: | cat > example_single_file.cpp <<'EOF' @@ -334,7 +334,7 @@ jobs: #include "examples/example_null/main.cpp" EOF - g++ -I. -std=c++26 -Wall -Wformat -o example_single_file example_single_file.cpp + g++ -I. -std=c++20 -Wall -Wformat -o example_single_file example_single_file.cpp - name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_DEBUG_TOOLS) run: | From d0b742efdee1d09ff0e87a8a1419e08f7f84174c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 15:30:29 +0200 Subject: [PATCH 106/136] CI: build with Clang C++26 on Linux. (#7954) --- .github/workflows/build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 702e281bf..1d43da032 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -393,6 +393,18 @@ jobs: EOF g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp + - name: Build example_null (C++26, Clang) + run: | + cat > example_single_file.cpp <<'EOF' + + #define IMGUI_IMPLEMENTATION + #define IMGUI_DISABLE_DEMO_WINDOWS + #include "misc/single_file/imgui_single_file.h" + #include "examples/example_null/main.cpp" + + EOF + clang++ -I. -std=c++26 -Wall -Wformat -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp + - name: Build example_null (without c++ runtime, Clang) run: | cat > example_single_file.cpp <<'EOF' From 193c1e2366857dbfdbc3dd98c5b95f47b881f122 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 20:03:23 +0200 Subject: [PATCH 107/136] Version 1.91.2 WIP --- docs/CHANGELOG.txt | 8 ++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d7fec4cff..0136b45a7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,14 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.2 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + ----------------------------------------------------------------------- VERSION 1.91.1 (Released 2024-09-04) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index ac76ddd19..6706135e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index a6766e2d6..0eeba4af0 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.1" -#define IMGUI_VERSION_NUM 19110 +#define IMGUI_VERSION "1.91.2 WIP" +#define IMGUI_VERSION_NUM 19111 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9ca73806d..aabb220d6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e033c357c..a681059bb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index a99cb2652..a0b110904 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5685c2ace..f247ed6d3 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b9e2ca2ce..3b0fcc52f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.1 +// dear imgui, v1.91.2 WIP // (widgets code) /* From d16cb171c6667c6b7e8d0bd89389a968492c14ce Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 20:16:37 +0200 Subject: [PATCH 108/136] Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439, extend #370, #369) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0136b45a7..f425dc60e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) + ----------------------------------------------------------------------- VERSION 1.91.1 (Released 2024-09-04) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 6706135e3..fd018802a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13182,9 +13182,11 @@ static void ImGui::NavUpdateWindowing() // Keyboard: Press and Release ALT to toggle menu layer const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt }; + bool windowing_toggle_layer_start = false; for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) { + windowing_toggle_layer_start = true; g.NavWindowingToggleLayer = true; g.NavWindowingToggleKey = windowing_toggle_key; g.NavInputSource = ImGuiInputSource_Keyboard; @@ -13198,7 +13200,9 @@ static void ImGui::NavUpdateWindowing() // We cancel toggling nav layer if an owner has claimed the key. if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper) g.NavWindowingToggleLayer = false; - if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false) + else if (windowing_toggle_layer_start == false && g.LastKeyboardKeyPressTime == g.Time) + g.NavWindowingToggleLayer = false; + else if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false) g.NavWindowingToggleLayer = false; // Apply layer toggle on Alt release From a5cf4fe374d491c882974d492a05117ef4bcc102 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Sep 2024 20:45:07 +0200 Subject: [PATCH 109/136] InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f425dc60e..82c7a60b6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,7 @@ Breaking changes: Other changes: - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) +- InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. ----------------------------------------------------------------------- VERSION 1.91.1 (Released 2024-09-04) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3b0fcc52f..2f998a649 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3894,9 +3894,18 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -static bool is_separator(unsigned int c) +static bool ImCharIsSeparatorW(unsigned int c) { - return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!' || c=='\\' || c=='/'; + static const unsigned int separator_list[] = + { + ',', 0x3001, '.', 0x3002, ';', 0xFF1B, '(', 0xFF08, ')', 0xFF09, '{', 0xFF5B, '}', 0xFF5D, + '[', 0x300C, ']', 0x300D, '|', 0xFF5C, '!', 0xFF01, '\\', 0xFFE5, '/', 0x30FB, 0xFF0F, + '\n', '\r', + }; + for (unsigned int separator : separator_list) + if (c == separator) + return true; + return false; } static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) @@ -3906,9 +3915,9 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) return 0; bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]); - bool prev_separ = is_separator(obj->TextW[idx - 1]); + bool prev_separ = ImCharIsSeparatorW(obj->TextW[idx - 1]); bool curr_white = ImCharIsBlankW(obj->TextW[idx]); - bool curr_separ = is_separator(obj->TextW[idx]); + bool curr_separ = ImCharIsSeparatorW(obj->TextW[idx]); return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) @@ -3917,9 +3926,9 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) return 0; bool prev_white = ImCharIsBlankW(obj->TextW[idx]); - bool prev_separ = is_separator(obj->TextW[idx]); + bool prev_separ = ImCharIsSeparatorW(obj->TextW[idx]); bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]); - bool curr_separ = is_separator(obj->TextW[idx - 1]); + bool curr_separ = ImCharIsSeparatorW(obj->TextW[idx - 1]); return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } From a2366f902249107f1533a85d3d1f93ec193f52f0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Sep 2024 11:38:48 +0200 Subject: [PATCH 110/136] TextLinkOpenURL: display a verb in front the link. Update Gallery & other links. (#7885, #7660) --- docs/BACKENDS.md | 2 +- docs/CHANGELOG.txt | 1 + docs/FAQ.md | 10 +++++----- docs/README.md | 6 +++--- imgui.cpp | 7 ++++--- imgui.h | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 2 +- 8 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 55a0983dd..de5cd6697 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -135,7 +135,7 @@ Generally: It is unlikely you will add value to your project by creating your own backend. Also: -The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows +The [multi-viewports feature](https://github.com/ocornut/imgui/wiki/Multi-Viewports) of the 'docking' branch allows Dear ImGui windows to be seamlessly detached from the main application window. This is achieved using an extra layer to the Platform and Renderer backends, which allows Dear ImGui to communicate platform-specific requests such as: "create an additional OS window", "create a render context", "get the OS position of this diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 82c7a60b6..70b7424e9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,7 @@ Other changes: - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. +- TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660) ----------------------------------------------------------------------- VERSION 1.91.1 (Released 2024-09-04) diff --git a/docs/FAQ.md b/docs/FAQ.md index d104c30bc..d53a5a099 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -77,9 +77,9 @@ or view this file with any Markdown viewer. ### Q: Which version should I get? I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported. -You may use the [docking](https://github.com/ocornut/imgui/tree/docking) branch which includes: -- [Docking features](https://github.com/ocornut/imgui/issues/2109) -- [Multi-viewport features](https://github.com/ocornut/imgui/issues/1542) +You may use the ['docking'](https://github.com/ocornut/imgui/tree/docking) branch which includes: +- [Docking features](https://github.com/ocornut/imgui/wiki/Docking) +- [Multi-viewport features](https://github.com/ocornut/imgui/wiki/Multi-Viewports) Many projects are using this branch and it is kept in sync with master regularly. @@ -654,7 +654,7 @@ You may take a look at: - [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding) -- [Gallery](https://github.com/ocornut/imgui/issues/7503) +- [Gallery](https://github.com/ocornut/imgui/issues?q=label%3Agallery) ##### [Return to Index](#index) @@ -700,7 +700,7 @@ There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/ci - Individuals: you can support continued maintenance and development via PayPal donations. See [README](https://github.com/ocornut/imgui/blob/master/docs/README.md). - If you are experienced with Dear ImGui and C++, look at [GitHub Issues](https://github.com/ocornut/imgui/issues), [GitHub Discussions](https://github.com/ocornut/imgui/discussions), the [Wiki](https://github.com/ocornut/imgui/wiki), read [docs/TODO.txt](https://github.com/ocornut/imgui/blob/master/docs/TODO.txt), and see how you want to help and can help! - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere, etc. -You may post screenshots or links in the [gallery threads](https://github.com/ocornut/imgui/issues/7503). Visuals are ideal as they inspire other programmers. Disclosing your use of Dear ImGui helps the library grow credibility, and helps other teams and programmers with taking decisions. +You may post screenshots or links in the [gallery threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery). Visuals are ideal as they inspire other programmers. Disclosing your use of Dear ImGui helps the library grow credibility, and helps other teams and programmers with taking decisions. - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues or sometimes incomplete PR. ##### [Return to Index](#index) diff --git a/docs/README.md b/docs/README.md index a1807abac..0968727f1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -141,7 +141,7 @@ Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. Examples projects using Dear ImGui: [Tracy](https://github.com/wolfpld/tracy) (profiler), [ImHex](https://github.com/WerWolv/ImHex) (hex editor/data analysis), [RemedyBG](https://remedybg.itch.io/remedybg) (debugger) and [hundreds of others](https://github.com/ocornut/imgui/wiki/Software-using-Dear-ImGui). -For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues/7503)! +For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery)! For a list of third-party widgets and extensions, check out the [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page. @@ -170,11 +170,11 @@ Private support is available for paying business customers (E-mail: _contact @ d **Which version should I get?** -We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with nice releases notes) but it is generally safe and recommended to sync to latest `master` or `docking` branch. The library is fairly stable and regressions tend to be fixed fast when reported. Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features. This branch is kept in sync with master regularly. +We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with nice releases notes) but it is generally safe and recommended to sync to latest `master` or `docking` branch. The library is fairly stable and regressions tend to be fixed fast when reported. Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/wiki/Multi-Viewports) and [Docking](https://github.com/ocornut/imgui/wiki/Docking) features. This branch is kept in sync with master regularly. **Who uses Dear ImGui?** -See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues/7503)! +See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery)! How to help ----------- diff --git a/imgui.cpp b/imgui.cpp index fd018802a..1d9d8b899 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10,7 +10,7 @@ // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - Homepage ................... https://github.com/ocornut/imgui // - Releases & changelog ....... https://github.com/ocornut/imgui/releases -// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) +// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) @@ -3780,7 +3780,7 @@ void ImGui::DestroyContext(ImGuiContext* ctx) IM_DELETE(ctx); } -// IMPORTANT: ###xxx suffixes must be same in ALL languages to allow for automation. +// IMPORTANT: interactive elements requires a fixed ###xxx suffix, it must be same in ALL languages to allow for automation. static const ImGuiLocEntry GLocalizationEntriesEnUS[] = { { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" }, @@ -3791,7 +3791,8 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] = { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, - { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" }, + { ImGuiLocKey_OpenLink_s, "Open '%s'" }, + { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" }, }; void ImGui::Initialize() diff --git a/imgui.h b/imgui.h index 0eeba4af0..0394967ee 100644 --- a/imgui.h +++ b/imgui.h @@ -11,7 +11,7 @@ // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - Homepage ................... https://github.com/ocornut/imgui // - Releases & changelog ....... https://github.com/ocornut/imgui/releases -// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) +// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) diff --git a/imgui_internal.h b/imgui_internal.h index a0b110904..5d23ebfef 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1882,6 +1882,7 @@ enum ImGuiLocKey : int ImGuiLocKey_WindowingMainMenuBar, ImGuiLocKey_WindowingPopup, ImGuiLocKey_WindowingUntitled, + ImGuiLocKey_OpenLink_s, ImGuiLocKey_CopyLink, ImGuiLocKey_COUNT }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2f998a649..7b86fb8be 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1460,7 +1460,7 @@ void ImGui::TextLinkOpenURL(const char* label, const char* url) if (TextLink(label)) if (g.PlatformIO.Platform_OpenInShellFn != NULL) g.PlatformIO.Platform_OpenInShellFn(&g, url); - SetItemTooltip("%s", url); // It is more reassuring for user to _always_ display URL when we same as label + SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label if (BeginPopupContextItem()) { if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink))) From 21d03edcb0cdad9e870f94f55ebb1d6deb54bc30 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Sep 2024 16:22:55 +0200 Subject: [PATCH 111/136] InputText: renamed namespace from stb_texture structure and added an indirection. --- imgui_internal.h | 27 +++++++------- imgui_widgets.cpp | 90 +++++++++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 5d23ebfef..ab7cbc1f3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -216,6 +216,8 @@ namespace ImStb } // namespace ImStb +typedef ImStb::STB_TexteditState ImStbTexteditState; + //----------------------------------------------------------------------------- // [SECTION] Macros //----------------------------------------------------------------------------- @@ -1110,11 +1112,13 @@ struct IMGUI_API ImGuiInputTextDeactivatedState ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } void ClearFreeMemory() { ID = 0; TextA.clear(); } }; + // Internal state of the currently focused/edited text input box // For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState { ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). + ImStbTexteditState* Stb; // State for stb_textedit.h ImGuiID ID; // widget id owning the text state int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. @@ -1123,7 +1127,7 @@ struct IMGUI_API ImGuiInputTextState bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) int BufCapacityA; // end-user buffer capacity ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) - ImStb::STB_TexteditState Stb; // state for stb_textedit.h + float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection @@ -1133,22 +1137,21 @@ struct IMGUI_API ImGuiInputTextState int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet. int ReloadSelectionEnd; - ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + ImGuiInputTextState(); + ~ImGuiInputTextState(); void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } - int GetUndoAvailCount() const { return Stb.undostate.undo_point; } - int GetRedoAvailCount() const { return IMSTB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation // Cursor & Selection void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking - void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } - bool HasSelection() const { return Stb.select_start != Stb.select_end; } - void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } - int GetCursorPos() const { return Stb.cursor; } - int GetSelectionStart() const { return Stb.select_start; } - int GetSelectionEnd() const { return Stb.select_end; } - void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } + void CursorClamp() { Stb->cursor = ImMin(Stb->cursor, CurLenW); Stb->select_start = ImMin(Stb->select_start, CurLenW); Stb->select_end = ImMin(Stb->select_end, CurLenW); } + bool HasSelection() const { return Stb->select_start != Stb->select_end; } + void ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } + int GetCursorPos() const { return Stb->cursor; } + int GetSelectionStart() const { return Stb->select_start; } + int GetSelectionEnd() const { return Stb->select_end; } + void SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenW; Stb->has_preferred_x = 0; } // Reload user buf (WIP #2890) // If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this) @@ -1156,7 +1159,7 @@ struct IMGUI_API ImGuiInputTextState // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // state->ReloadUserBufAndSelectAll(); void ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } - void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb.select_start; ReloadSelectionEnd = Stb.select_end; } + void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } void ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7b86fb8be..f35927727 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4029,9 +4029,21 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st } // namespace ImStb +// We added an extra indirection where 'Stb' is heap-allocated, in order facilitate the work of bindings generators. +ImGuiInputTextState::ImGuiInputTextState() +{ + memset(this, 0, sizeof(*this)); + Stb = IM_NEW(ImStbTexteditState); +} + +ImGuiInputTextState::~ImGuiInputTextState() +{ + IM_DELETE(Stb); +} + void ImGuiInputTextState::OnKeyPressed(int key) { - stb_textedit_key(this, &Stb, key); + stb_textedit_key(this, Stb, key); CursorFollow = true; CursorAnimReset(); } @@ -4229,7 +4241,7 @@ static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* st const int insert_len = new_last_diff - first_diff + 1; const int delete_len = old_last_diff - first_diff + 1; if (insert_len > 0 || delete_len > 0) - if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len)) + if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb->undostate, first_diff, delete_len, insert_len)) for (int i = 0; i < delete_len; i++) p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i); } @@ -4371,7 +4383,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; const bool init_reload_from_user_buf = (state != NULL && state->ReloadUserBuf); - const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state. + const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); if ((init_state && g.ActiveId != id) || init_changed_specs || init_reload_from_user_buf) @@ -4417,13 +4429,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else { state->Scroll = ImVec2(0.0f, 0.0f); - stb_textedit_initialize_state(&state->Stb, !is_multiline); + stb_textedit_initialize_state(state->Stb, !is_multiline); } if (init_reload_from_user_buf) { - state->Stb.select_start = state->ReloadSelectionStart; - state->Stb.cursor = state->Stb.select_end = state->ReloadSelectionEnd; + state->Stb->select_start = state->ReloadSelectionStart; + state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; state->CursorClamp(); } else if (!is_multiline) @@ -4437,7 +4449,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } if (flags & ImGuiInputTextFlags_AlwaysOverwrite) - state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) + state->Stb->insert_mode = 1; // stb field name is indeed incorrect (see #2863) } const bool is_osx = io.ConfigMacOSXBehaviors; @@ -4545,34 +4557,34 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift) { - stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + stb_textedit_click(state, state->Stb, mouse_x, mouse_y); const int multiclick_count = (io.MouseClickedCount[0] - 2); if ((multiclick_count % 2) == 0) { // Double-click: Select word // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) - const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\n'; - if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol) + const bool is_bol = (state->Stb->cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor - 1) == '\n'; + if (STB_TEXT_HAS_SELECTION(state->Stb) || !is_bol) state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); - if (!STB_TEXT_HAS_SELECTION(&state->Stb)) - ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb); - state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor); - state->Stb.select_end = state->Stb.cursor; - ImStb::stb_textedit_clamp(state, &state->Stb); + if (!STB_TEXT_HAS_SELECTION(state->Stb)) + ImStb::stb_textedit_prep_selection_at_cursor(state->Stb); + state->Stb->cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb->cursor); + state->Stb->select_end = state->Stb->cursor; + ImStb::stb_textedit_clamp(state, state->Stb); } else { // Triple-click: Select line - const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\n'; + const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor) == '\n'; state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART); state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT); state->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT); if (!is_eol && is_multiline) { - ImSwap(state->Stb.select_start, state->Stb.select_end); - state->Stb.cursor = state->Stb.select_end; + ImSwap(state->Stb->select_start, state->Stb->select_end); + state->Stb->cursor = state->Stb->select_end; } state->CursorFollow = false; } @@ -4583,15 +4595,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (hovered) { if (io.KeyShift) - stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + stb_textedit_drag(state, state->Stb, mouse_x, mouse_y); else - stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + stb_textedit_click(state, state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); } } else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) { - stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + stb_textedit_drag(state, state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); state->CursorFollow = true; } @@ -4644,7 +4656,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(state != NULL); const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); - state->Stb.row_count_per_page = row_count_per_page; + state->Stb->row_count_per_page = row_count_per_page; const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl @@ -4751,8 +4763,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Cut, Copy if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) { - const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; - const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->CurLenW; const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); @@ -4764,7 +4776,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!state->HasSelection()) state->SelectAll(); state->CursorFollow = true; - stb_textedit_cut(state, &state->Stb); + stb_textedit_cut(state, state->Stb); } } else if (is_paste) @@ -4786,7 +4798,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ clipboard_filtered[clipboard_filtered_len] = 0; if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation { - stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + stb_textedit_paste(state, state->Stb, clipboard_filtered, clipboard_filtered_len); state->CursorFollow = true; } MemFree(clipboard_filtered); @@ -4813,7 +4825,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ apply_new_text_length = 0; value_changed = true; IMSTB_TEXTEDIT_CHARTYPE empty_string; - stb_textedit_replace(state, &state->Stb, &empty_string, 0); + stb_textedit_replace(state, state->Stb, &empty_string, 0); } else if (strcmp(buf, state->InitialTextA.Data) != 0) { @@ -4828,7 +4840,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); } - stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); + stb_textedit_replace(state, state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); } } @@ -4903,9 +4915,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) ImWchar* text = state->TextW.Data; - const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); - const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); - const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb->cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb->select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb->select_end); // Call user code callback(&callback_data); @@ -4916,9 +4928,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(callback_data.BufSize == state->BufCapacityA); IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; - if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } - if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb->cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb->cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb->select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } if (buf_dirty) { // Callback may update buffer and thus set buf_dirty even in read-only mode. @@ -5040,13 +5052,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ int searches_remaining = 0; if (render_cursor) { - searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_input_ptr[0] = text_begin + state->Stb->cursor; searches_result_line_no[0] = -1; searches_remaining++; } if (render_selection) { - searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_input_ptr[1] = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end); searches_result_line_no[1] = -1; searches_remaining++; } @@ -5122,8 +5134,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f); if (render_selection) { - const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); - const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end); ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. @@ -5244,7 +5256,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *GImGui; - ImStb::STB_TexteditState* stb_state = &state->Stb; + ImStb::STB_TexteditState* stb_state = state->Stb; ImStb::StbUndoState* undo_state = &stb_state->undostate; Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); From ca5701d45807ff7bdc71ccb85d9f1030cc8e917d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Sep 2024 16:29:47 +0200 Subject: [PATCH 112/136] InputText: moved all ImGuiInputTextState functions to not be inline. --- imgui.h | 2 +- imgui_internal.h | 24 +++++++++++------------- imgui_widgets.cpp | 13 +++++++++++++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/imgui.h b/imgui.h index 0394967ee..18efaff42 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.2 WIP" -#define IMGUI_VERSION_NUM 19111 +#define IMGUI_VERSION_NUM 19112 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index ab7cbc1f3..7748f0703 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1127,7 +1127,6 @@ struct IMGUI_API ImGuiInputTextState bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) int BufCapacityA; // end-user buffer capacity ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) - float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection @@ -1144,24 +1143,23 @@ struct IMGUI_API ImGuiInputTextState void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation // Cursor & Selection - void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking - void CursorClamp() { Stb->cursor = ImMin(Stb->cursor, CurLenW); Stb->select_start = ImMin(Stb->select_start, CurLenW); Stb->select_end = ImMin(Stb->select_end, CurLenW); } - bool HasSelection() const { return Stb->select_start != Stb->select_end; } - void ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } - int GetCursorPos() const { return Stb->cursor; } - int GetSelectionStart() const { return Stb->select_start; } - int GetSelectionEnd() const { return Stb->select_end; } - void SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenW; Stb->has_preferred_x = 0; } + void CursorAnimReset(); + void CursorClamp(); + bool HasSelection() const; + void ClearSelection(); + int GetCursorPos() const; + int GetSelectionStart() const; + int GetSelectionEnd() const; + void SelectAll(); // Reload user buf (WIP #2890) // If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this) // strcpy(my_buf, "hello"); // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // state->ReloadUserBufAndSelectAll(); - void ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } - void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } - void ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } - + void ReloadUserBufAndSelectAll(); + void ReloadUserBufAndKeepSelection(); + void ReloadUserBufAndMoveToEnd(); }; enum ImGuiWindowRefreshFlags_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f35927727..877dbd108 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4048,6 +4048,19 @@ void ImGuiInputTextState::OnKeyPressed(int key) CursorAnimReset(); } +// Those functions are not inlined in imgui_internal.h, allowing us to hide ImStbTexteditState from that header. +void ImGuiInputTextState::CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking +void ImGuiInputTextState::CursorClamp() { Stb->cursor = ImMin(Stb->cursor, CurLenW); Stb->select_start = ImMin(Stb->select_start, CurLenW); Stb->select_end = ImMin(Stb->select_end, CurLenW); } +bool ImGuiInputTextState::HasSelection() const { return Stb->select_start != Stb->select_end; } +void ImGuiInputTextState::ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } +int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor; } +int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } +int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } +void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenW; Stb->has_preferred_x = 0; } +void ImGuiInputTextState::ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } +void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } +void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } + ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() { memset(this, 0, sizeof(*this)); From 15cb7d61f98de0bcde9fb3ddfdcb25fdccc8b7c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Sep 2024 16:52:16 +0200 Subject: [PATCH 113/136] InputText: moved imstb_textedit.h include to imgui_widgets.cpp --- imgui_internal.h | 31 +++++++++++-------------------- imgui_widgets.cpp | 6 ++++++ imstb_textedit.h | 3 ++- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 7748f0703..1aa94ff3b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -198,26 +198,6 @@ typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif -//------------------------------------------------------------------------- -// [SECTION] STB libraries includes -//------------------------------------------------------------------------- - -namespace ImStb -{ - -#undef IMSTB_TEXTEDIT_STRING -#undef IMSTB_TEXTEDIT_CHARTYPE -#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState -#define IMSTB_TEXTEDIT_CHARTYPE ImWchar -#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) -#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 -#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 -#include "imstb_textedit.h" - -} // namespace ImStb - -typedef ImStb::STB_TexteditState ImStbTexteditState; - //----------------------------------------------------------------------------- // [SECTION] Macros //----------------------------------------------------------------------------- @@ -1113,6 +1093,17 @@ struct IMGUI_API ImGuiInputTextDeactivatedState void ClearFreeMemory() { ID = 0; TextA.clear(); } }; +// Forward declare imstb_textedit.h structure + make its main configuration define accessible +#undef IMSTB_TEXTEDIT_STRING +#undef IMSTB_TEXTEDIT_CHARTYPE +#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState +#define IMSTB_TEXTEDIT_CHARTYPE ImWchar +#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) +#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 +#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 +namespace ImStb { struct STB_TexteditState; } +typedef ImStb::STB_TexteditState ImStbTexteditState; + // Internal state of the currently focused/edited text input box // For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 877dbd108..10cdf3428 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3786,6 +3786,7 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f //------------------------------------------------------------------------- // [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint //------------------------------------------------------------------------- +// - imstb_textedit.h include // - InputText() // - InputTextWithHint() // - InputTextMultiline() @@ -3796,6 +3797,11 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f // - DebugNodeInputTextState() [Internal] //------------------------------------------------------------------------- +namespace ImStb +{ +#include "imstb_textedit.h" +} + bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() diff --git a/imstb_textedit.h b/imstb_textedit.h index 783054ab9..faaf518f4 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -3,6 +3,7 @@ // Those changes would need to be pushed into nothings/stb: // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783) +// - Added name to struct or it may be forward declared in our code. // Grep for [DEAR IMGUI] to find the changes. // - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_* @@ -318,7 +319,7 @@ typedef struct int undo_char_point, redo_char_point; } StbUndoState; -typedef struct +typedef struct STB_TexteditState { ///////////////////// // From 4236bc088fd360a02064652069ed9bf04f013507 Mon Sep 17 00:00:00 2001 From: scribam Date: Sun, 8 Sep 2024 12:19:51 +0200 Subject: [PATCH 114/136] Backends: SDL2: use SDL_Vulkan_GetDrawableSize with Vulkan instead of SDL_GL_GetDrawableSize. (#7967, #3190) --- backends/imgui_impl_sdl2.cpp | 8 ++++++++ docs/CHANGELOG.txt | 1 + 2 files changed, 9 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index b1cc8c9e6..027dff9f2 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn @@ -112,6 +113,9 @@ #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 #endif #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#if SDL_HAS_VULKAN +extern "C" { extern DECLSPEC void SDLCALL SDL_Vulkan_GetDrawableSize(SDL_Window* window, int* w, int* h); } +#endif // SDL Data struct ImGui_ImplSDL2_Data @@ -760,6 +764,10 @@ void ImGui_ImplSDL2_NewFrame() w = h = 0; if (bd->Renderer != nullptr) SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h); +#if SDL_HAS_VULKAN + else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN) + SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h); +#endif else SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 70b7424e9..d915d9510 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,7 @@ Other changes: - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660) +- Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam] ----------------------------------------------------------------------- VERSION 1.91.1 (Released 2024-09-04) From a8eec244056b8880f459d2073333fca4da5a917a Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Mon, 9 Sep 2024 21:07:10 +0200 Subject: [PATCH 115/136] Demo: fix some id conflicts. (#7961) --- imgui_demo.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index aabb220d6..652049513 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -547,7 +547,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent); ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application."); ImGui::BeginDisabled(); - ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . + ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); ImGui::EndDisabled(); ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover."); ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); @@ -2000,8 +2000,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; - ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::Separator(); ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); @@ -2596,6 +2596,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); if (ImGui::TreeNode("Drag to reorder items (simple)")) { + // FIXME: temporary ID Conflict during reordering as a same item may be submitting twice. + // Simple reordering HelpMarker( "We don't use the drag and drop api at all here! " @@ -4225,7 +4227,7 @@ static void ShowDemoWindowLayout() // down by FramePadding.y ahead of time) ImGui::AlignTextToFramePadding(); ImGui::Text("OK Blahblah"); ImGui::SameLine(); - ImGui::Button("Some framed item"); ImGui::SameLine(); + ImGui::Button("Some framed item##2"); ImGui::SameLine(); HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); // SmallButton() uses the same vertical padding as Text @@ -7148,12 +7150,14 @@ static void ShowDemoWindowColumns() { if (h_borders && ImGui::GetColumnIndex() == 0) ImGui::Separator(); + ImGui::PushID(i); ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); ImGui::Text("Long text that is likely to clip"); ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); + ImGui::PopID(); ImGui::NextColumn(); } ImGui::Columns(1); From 67cd4ead6505b3386d4ef9c713c98546e86e26ca Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Sep 2024 15:28:40 +0200 Subject: [PATCH 116/136] Added io.ConfigDebugHighlightIdConflicts debug feature! (#7961, #7669) Also #74, #96, #480, #501, #647, #654, #719, #843, #894, #1057, #1173, #1390, #1414, #1556, #1768, #2041, #2116, #2330, #2475, #2562, #2667, #2807, #2885, #3102, #3375, #3526, #3964, #4008, #4070, #4158, #4172, #4199, #4375, #4395, #4471, #4548, #4612, #4631, #4657, #4796, #5210, #5303, #5360, #5393, #5533, #5692, #5707, #5729, #5773, #5787, #5884, #6046, #6093, #6186, #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434, #7472, #7581, #7724, #7926, #7937 and probably more.. Tagging to increase visibility! --- docs/CHANGELOG.txt | 19 +++++++++++++++++++ docs/FAQ.md | 5 +++-- imgui.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ imgui.h | 11 ++++++++++- imgui_demo.cpp | 18 ++++++++++++++---- imgui_internal.h | 4 ++++ imgui_widgets.cpp | 3 +++ 7 files changed, 95 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d915d9510..35c4c6743 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,25 @@ Breaking changes: Other changes: +- Added io.ConfigDebugHighlightIdConflicts debug feature! (#7961, #7669) + THIS DETECTS THE MOST COMMON USER ERROR BY FIRST-TIME DEAR IMGUI PROGRAMMERS! + - The tool detects when multiple items are sharing the same identifier, due to not + using PushID/PopID in loops, or not using ID stack facilities such as "##" suffixes. + Very frequently it happens when using empty "" labels. + - When hovering an item with a conflicting ID, all visible items with the same ID will + be highlighted and an explanatory tooltip is made visible. + - The feature may be disabled and is exposed in Demo->Tools menu. + - I've been wanting to add this tool for a long time, but was stalled by finding a way to + not make it spammy + make it practically zero cost. After @pthom made various proposals to + solve the same problem (thanks for pushing me!), I decided it was time to finish it. + - Added ImGuiItemFlags_AllowDuplicateId to use with PushItemFlag/PopItemFlag() if for some + reason you intend to have duplicate identifiers. + - (#74, #96, #480, #501, #647, #654, #719, #843, #894, #1057, #1173, #1390, #1414, #1556, #1768, + #2041, #2116, #2330, #2475, #2562, #2667, #2807, #2885, #3102, #3375, #3526, #3964, #4008, + #4070, #4158, #4172, #4199, #4375, #4395, #4471, #4548, #4612, #4631, #4657, #4796, #5210, + #5303, #5360, #5393, #5533, #5692, #5707, #5729, #5773, #5787, #5884, #6046, #6093, #6186, + #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434, + #7472, #7581, #7724, #7926, #7937 and probably more..) - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660) diff --git a/docs/FAQ.md b/docs/FAQ.md index d53a5a099..4e2a42576 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -204,10 +204,11 @@ ctx->RSSetScissorRects(1, &r); ### Q: How can I have multiple widgets with the same label? ### Q: How can I have multiple windows with the same label? -**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE:** +**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE!** +
**USING AN EMPTY LABEL IS THE SAME AS USING THE SAME LABEL AS YOUR PARENT WIDGET!** - +
 ImGui::Begin("Incorrect!");
diff --git a/imgui.cpp b/imgui.cpp
index 1d9d8b899..e6cf5ca45 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1395,6 +1395,8 @@ ImGuiIO::ImGuiIO()
     ConfigWindowsResizeFromEdges = true;
     ConfigWindowsMoveFromTitleBarOnly = false;
     ConfigMemoryCompactTimer = 60.0f;
+    ConfigDebugIsDebuggerPresent = false;
+    ConfigDebugHighlightIdConflicts = true;
     ConfigDebugBeginReturnValueOnce = false;
     ConfigDebugBeginReturnValueLoop = false;
 
@@ -4290,6 +4292,17 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
 {
     ImGuiContext& g = *GImGui;
     ImGuiWindow* window = g.CurrentWindow;
+
+    // Detect ID conflicts
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+    if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0)
+    {
+        g.HoveredIdPreviousFrameItemCount++;
+        if (g.DebugDrawIdConflicts == id)
+            window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
+    }
+#endif
+
     if (g.HoveredWindow != window)
         return false;
     if (!IsMouseHoveringRect(bb.Min, bb.Max))
@@ -4833,6 +4846,11 @@ void ImGui::NewFrame()
     if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
         KeepAliveID(g.DragDropPayload.SourceId);
 
+    // [DEBUG]
+    g.DebugDrawIdConflicts = 0;
+    if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1)
+        g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame;
+
     // Update HoveredId data
     if (!g.HoveredIdPreviousFrame)
         g.HoveredIdTimer = 0.0f;
@@ -4843,6 +4861,7 @@ void ImGui::NewFrame()
     if (g.HoveredId && g.ActiveId != g.HoveredId)
         g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
     g.HoveredIdPreviousFrame = g.HoveredId;
+    g.HoveredIdPreviousFrameItemCount = 0;
     g.HoveredId = 0;
     g.HoveredIdAllowOverlap = false;
     g.HoveredIdIsDisabled = false;
@@ -5235,6 +5254,29 @@ void ImGui::EndFrame()
         return;
     IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
 
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+    if (g.DebugDrawIdConflicts != 0)
+    {
+        PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.10f));
+        if (g.DebugItemPickerActive == false && BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
+        {
+            SeparatorText("MESSAGE FROM DEAR IMGUI");
+            Text("Programmer error: %d visible items with conflicting ID!", g.HoveredIdPreviousFrameItemCount);
+            BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!");
+            BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!");
+            BulletText("Press F1 to open \"FAQ -> About the ID Stack System\" and read details.");
+            BulletText("Press CTRL+P to activate Item Picker and debug-break in item call-stack.");
+            BulletText("Set io.ConfigDebugDetectIdConflicts=false to disable this warning in non-programmers builds.");
+            EndTooltip();
+        }
+        PopStyleColor();
+        if (Shortcut(ImGuiMod_Ctrl | ImGuiKey_P, ImGuiInputFlags_RouteGlobal))
+            DebugStartItemPicker();
+        if (Shortcut(ImGuiKey_F1, ImGuiInputFlags_RouteGlobal) && g.PlatformIO.Platform_OpenInShellFn != NULL)
+            g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage");
+    }
+#endif
+
     CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
 
     ErrorCheckEndFrameSanityChecks();
diff --git a/imgui.h b/imgui.h
index 18efaff42..ebb156d4b 100644
--- a/imgui.h
+++ b/imgui.h
@@ -29,7 +29,7 @@
 // Library Version
 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
 #define IMGUI_VERSION       "1.91.2 WIP"
-#define IMGUI_VERSION_NUM   19112
+#define IMGUI_VERSION_NUM   19113
 #define IMGUI_HAS_TABLE
 
 /*
@@ -1135,6 +1135,7 @@ enum ImGuiItemFlags_
     ImGuiItemFlags_NoNavDefaultFocus        = 1 << 2,   // false    // Disable item being a candidate for default focus (e.g. used by title bar items).
     ImGuiItemFlags_ButtonRepeat             = 1 << 3,   // false    // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held.
     ImGuiItemFlags_AutoClosePopups          = 1 << 4,   // true     // MenuItem()/Selectable() automatically close their parent popup window.
+    ImGuiItemFlags_AllowDuplicateId         = 1 << 5,   // false    // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
 };
 
 // Flags for ImGui::InputText()
@@ -2231,6 +2232,7 @@ struct ImGuiIO
     const char* LogFilename;                    // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
     void*       UserData;                       // = NULL           // Store your own data.
 
+    // Font system
     ImFontAtlas*Fonts;                          //            // Font atlas: load, rasterize and pack one or more fonts into a single texture.
     float       FontGlobalScale;                // = 1.0f           // Global scale all fonts
     bool        FontAllowUserScaling;           // = false          // Allow user scaling text of individual window with CTRL+Wheel.
@@ -2238,6 +2240,7 @@ struct ImGuiIO
     ImVec2      DisplayFramebufferScale;        // = (1, 1)         // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale.
 
     // 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.
     bool        ConfigMacOSXBehaviors;          // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.
     bool        ConfigNavSwapGamepadButtons;    // = false          // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout.
@@ -2267,6 +2270,12 @@ struct ImGuiIO
     //   e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version).
     bool        ConfigDebugIsDebuggerPresent;   // = false          // Enable various tools calling IM_DEBUG_BREAK().
 
+    // Tools to detect code submitting items with conflicting/duplicate IDs
+    // - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers.
+    // - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead!
+    // - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
+    bool        ConfigDebugHighlightIdConflicts;// = true           // Highlight and show an error message when multiple items have conflicting identifiers.
+
     // Tools to test correct Begin/End and BeginChild/EndChild behaviors.
     // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()
     // - This is inconsistent with other BeginXXX functions and create confusion for many users.
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 652049513..8c9745dfb 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -546,6 +546,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
             ImGui::SeparatorText("Debug");
             ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
             ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
+            ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
+            ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
             ImGui::BeginDisabled();
             ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
             ImGui::EndDisabled();
@@ -684,6 +686,7 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
         if (ImGui::BeginMenu("Tools"))
         {
             IMGUI_DEMO_MARKER("Menu/Tools");
+            ImGuiIO& io = ImGui::GetIO();
 #ifndef IMGUI_DISABLE_DEBUG_TOOLS
             const bool has_debug_tools = true;
 #else
@@ -692,14 +695,16 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
             ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
             ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
             ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
-            ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
-            bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
+            bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
             if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
                 ImGui::DebugStartItemPicker();
             if (!is_debugger_present)
                 ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
-            ImGui::Separator();
+            ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
             ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
+
+            ImGui::SeparatorText("Debug Options");
+            ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
             ImGui::EndMenu();
         }
         ImGui::EndMenuBar();
@@ -2596,7 +2601,10 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
         IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
         if (ImGui::TreeNode("Drag to reorder items (simple)"))
         {
-            // FIXME: temporary ID Conflict during reordering as a same item may be submitting twice.
+            // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
+            // This code was always slightly faulty but in a way which was not easily noticeable.
+            // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
+            ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
 
             // Simple reordering
             HelpMarker(
@@ -2619,6 +2627,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
                     }
                 }
             }
+
+            ImGui::PopItemFlag();
             ImGui::TreePop();
         }
 
diff --git a/imgui_internal.h b/imgui_internal.h
index 1aa94ff3b..04dfba3b3 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -2042,9 +2042,11 @@ struct ImGuiContext
     ImVec2                  WheelingAxisAvg;
 
     // Item/widgets state and tracking information
+    ImGuiID                 DebugDrawIdConflicts;               // Set when we detect multiple items with the same identifier
     ImGuiID                 DebugHookIdInfo;                    // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
     ImGuiID                 HoveredId;                          // Hovered widget, filled during the frame
     ImGuiID                 HoveredIdPreviousFrame;
+    int                     HoveredIdPreviousFrameItemCount;    // Count numbers of items using the same ID as last frame's hovered id
     float                   HoveredIdTimer;                     // Measure contiguous hovering time
     float                   HoveredIdNotActiveTimer;            // Measure contiguous hovering time where the item has not been active
     bool                    HoveredIdAllowOverlap;
@@ -2365,8 +2367,10 @@ struct ImGuiContext
         WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
         WheelingWindowReleaseTimer = 0.0f;
 
+        DebugDrawIdConflicts = 0;
         DebugHookIdInfo = 0;
         HoveredId = HoveredIdPreviousFrame = 0;
+        HoveredIdPreviousFrameItemCount = 0;
         HoveredIdAllowOverlap = false;
         HoveredIdIsDisabled = false;
         HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 10cdf3428..33af0686e 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3551,6 +3551,8 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
 
 // Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets)
 // FIXME: Facilitate using this in variety of other situations.
+// FIXME: Among other things, setting ImGuiItemFlags_AllowDuplicateId in LastItemData is currently correct but
+// the expected relationship between TempInputXXX functions and LastItemData is a little fishy.
 bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags)
 {
     // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id.
@@ -3561,6 +3563,7 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char*
         ClearActiveID();
 
     g.CurrentWindow->DC.CursorPos = bb.Min;
+    g.LastItemData.InFlags |= ImGuiItemFlags_AllowDuplicateId;
     bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem);
     if (init)
     {

From abd07f6d30736c00fba899d41043a78a5de0f765 Mon Sep 17 00:00:00 2001
From: alektron 
Date: Tue, 27 Aug 2024 01:37:50 +0200
Subject: [PATCH 117/136] InputText: added native support for UTF-8 text
 editing and god rid of the wchar buffer. (#7925)

WIP (requires subsequent commits for fixes)
---
 imgui.cpp         |   2 +-
 imgui_internal.h  |  11 +-
 imgui_widgets.cpp | 278 +++++++++++++++++++++++++---------------------
 imstb_textedit.h  |  54 +++++----
 4 files changed, 189 insertions(+), 156 deletions(-)

diff --git a/imgui.cpp b/imgui.cpp
index e6cf5ca45..71b1b1011 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1975,7 +1975,7 @@ const char* ImStreolRange(const char* str, const char* str_end)
     return p ? p : str_end;
 }
 
-const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
+const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line
 {
     while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
         buf_mid_line--;
diff --git a/imgui_internal.h b/imgui_internal.h
index 04dfba3b3..ec4c069eb 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -366,7 +366,7 @@ IMGUI_API const char*   ImStristr(const char* haystack, const char* haystack_end
 IMGUI_API void          ImStrTrimBlanks(char* str);                                         // Remove leading and trailing blanks from a buffer.
 IMGUI_API const char*   ImStrSkipBlank(const char* str);                                    // Find first non-blank character.
 IMGUI_API int           ImStrlenW(const ImWchar* str);                                      // Computer string length (ImWchar string)
-IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin);   // Find beginning-of-line (ImWchar string)
+IMGUI_API const char*   ImStrbol(const char* buf_mid_line, const char* buf_begin);          // Find beginning-of-line
 IM_MSVC_RUNTIME_CHECKS_OFF
 static inline char      ImToUpper(char c)               { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
 static inline bool      ImCharIsBlankA(char c)          { return c == ' ' || c == '\t'; }
@@ -1097,7 +1097,7 @@ struct IMGUI_API ImGuiInputTextDeactivatedState
 #undef IMSTB_TEXTEDIT_STRING
 #undef IMSTB_TEXTEDIT_CHARTYPE
 #define IMSTB_TEXTEDIT_STRING             ImGuiInputTextState
-#define IMSTB_TEXTEDIT_CHARTYPE           ImWchar
+#define IMSTB_TEXTEDIT_CHARTYPE           char
 #define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE   (-1.0f)
 #define IMSTB_TEXTEDIT_UNDOSTATECOUNT     99
 #define IMSTB_TEXTEDIT_UNDOCHARCOUNT      999
@@ -1111,8 +1111,7 @@ struct IMGUI_API ImGuiInputTextState
     ImGuiContext*           Ctx;                    // parent UI context (needs to be set explicitly by parent).
     ImStbTexteditState*     Stb;                    // State for stb_textedit.h
     ImGuiID                 ID;                     // widget id owning the text state
-    int                     CurLenW, CurLenA;       // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.
-    ImVector       TextW;                  // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
+    int                     CurLenA;                // UTF-8 length of the string in TextA (in bytes)
     ImVector          TextA;                  // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
     ImVector          InitialTextA;           // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
     bool                    TextAIsValid;           // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)
@@ -1129,8 +1128,8 @@ struct IMGUI_API ImGuiInputTextState
 
     ImGuiInputTextState();
     ~ImGuiInputTextState();
-    void        ClearText()                 { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
-    void        ClearFreeMemory()           { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
+    void        ClearText()                 { CurLenA = 0; TextA[0] = 0; CursorClamp(); }
+    void        ClearFreeMemory()           { TextA.clear(); InitialTextA.clear(); }
     void        OnKeyPressed(int key);      // Cannot be inline because we call in code in stb_textedit.h implementation
 
     // Cursor & Selection
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 33af0686e..5a8721c78 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -128,7 +128,7 @@ static const ImU64          IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
 // For InputTextEx()
 static bool     InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false);
 static int      InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
-static ImVec2   InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
+static ImVec2   InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
 
 //-------------------------------------------------------------------------
 // [SECTION] Widgets: Text, etc.
@@ -3836,7 +3836,7 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
     return line_count;
 }
 
-static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
+static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line)
 {
     ImGuiContext& g = *ctx;
     ImFont* font = g.Font;
@@ -3846,10 +3846,11 @@ static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begi
     ImVec2 text_size = ImVec2(0, 0);
     float line_width = 0.0f;
 
-    const ImWchar* s = text_begin;
+    const char* s = text_begin;
     while (s < text_end)
     {
-        unsigned int c = (unsigned int)(*s++);
+        unsigned int c;
+        s += ImTextCharFromUtf8(&c, s, text_end);
         if (c == '\n')
         {
             text_size.x = ImMax(text_size.x, line_width);
@@ -3885,22 +3886,21 @@ static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begi
 namespace ImStb
 {
 
-static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->CurLenW; }
-static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->CurLenW); return obj->TextW[idx]; }
-static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * g.FontScale; }
+static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->CurLenA; }
+static char    STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->CurLenA); return obj->TextA[idx]; }
+static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextA.Size); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; }
 static int     STB_TEXTEDIT_KEYTOTEXT(int key)                                                    { return key >= 0x200000 ? 0 : key; }
-static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
+static char    STB_TEXTEDIT_NEWLINE = '\n';
 static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
 {
-    const ImWchar* text = obj->TextW.Data;
-    const ImWchar* text_remaining = NULL;
-    const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
+    const char* text_remaining = NULL;
+    const ImVec2 size = InputTextCalcTextSize(obj->Ctx, obj->TextA.Data + line_start_idx, obj->TextA.Data + obj->CurLenA, &text_remaining, NULL, true);
     r->x0 = 0.0f;
     r->x1 = size.x;
     r->baseline_y_delta = size.y;
     r->ymin = 0.0f;
     r->ymax = size.y;
-    r->num_chars = (int)(text_remaining - (text + line_start_idx));
+    r->num_chars = (int)(text_remaining - (obj->TextA.Data + line_start_idx));
 }
 
 static bool ImCharIsSeparatorW(unsigned int c)
@@ -3923,10 +3923,14 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)
     if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
         return 0;
 
-    bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]);
-    bool prev_separ = ImCharIsSeparatorW(obj->TextW[idx - 1]);
-    bool curr_white = ImCharIsBlankW(obj->TextW[idx]);
-    bool curr_separ = ImCharIsSeparatorW(obj->TextW[idx]);
+    const char* prevPtr = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx);
+    unsigned int curr; ImTextCharFromUtf8(&curr, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
+    unsigned int prev; ImTextCharFromUtf8(&prev, prevPtr, obj->TextA.Data + obj->TextA.Size);
+
+    bool prev_white = ImCharIsBlankW(prev);
+    bool prev_separ = ImCharIsSeparatorW(prev);
+    bool curr_white = ImCharIsBlankW(curr);
+    bool curr_separ = ImCharIsSeparatorW(curr);
     return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
 }
 static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
@@ -3934,63 +3938,108 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
     if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
         return 0;
 
-    bool prev_white = ImCharIsBlankW(obj->TextW[idx]);
-    bool prev_separ = ImCharIsSeparatorW(obj->TextW[idx]);
-    bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]);
-    bool curr_separ = ImCharIsSeparatorW(obj->TextW[idx - 1]);
+    const char* prevPtr = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx);
+    unsigned int prev; ImTextCharFromUtf8(&prev, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
+    unsigned int curr; ImTextCharFromUtf8(&curr, prevPtr, obj->TextA.Data + obj->TextA.Size);
+
+    bool prev_white = ImCharIsBlankW(prev);
+    bool prev_separ = ImCharIsSeparatorW(prev);
+    bool curr_white = ImCharIsBlankW(curr);
+    bool curr_separ = ImCharIsSeparatorW(curr);
     return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
 }
 static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)   { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
-static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
-static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
+static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
+static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
 static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)  { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
 #define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL  // They need to be #define for stb_textedit.h
 #define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
+#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX  IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL
+#define IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX  IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX_IMPL
+
+static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
+{
+    unsigned int c;
+    return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
+}
+
+static int CountLeadingHighBits(unsigned char b)
+{
+    for (int i = 0; i < (int)sizeof(b) * 8; i++)
+    {
+        bool set = (b >> (7 - i)) & 1;
+        if (!set)
+            return i;
+    }
+
+    return sizeof(b) * 8;
+}
+
+static int IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
+{
+    //Backwards check/count for UTF-8 multi byte sequence
+    int num_seq_bytes = 0;
+    for (int i = idx - 1; i >= 0; i -= 1)
+    {
+        bool is_seq_byte = (obj->TextA.Data[i] & 0x80) == 0x80 && (obj->TextA.Data[i] & 0x40) == 0;
+        num_seq_bytes += is_seq_byte;
+        if (!is_seq_byte)
+        {
+            if (num_seq_bytes > 0)
+            {
+                char initial_byte = obj->TextA.Data[i];
+                char num_leading_bits = (char)CountLeadingHighBits(initial_byte);
+                bool is_multi_byte_seq = num_leading_bits == num_seq_bytes + 1;
+                if (is_multi_byte_seq)
+                {
+                    return idx - (num_seq_bytes + 1);
+                }
+            }
+            break;
+        }
+    }
+    return idx - 1;
+}
 
 static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
 {
-    ImWchar* dst = obj->TextW.Data + pos;
+    char* dst = obj->TextA.Data + pos;
 
-    // We maintain our buffer length in both UTF-8 and wchar formats
     obj->Edited = true;
-    obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
-    obj->CurLenW -= n;
+    obj->CurLenA -= n;
 
     // Offset remaining text (FIXME-OPT: Use memmove)
-    const ImWchar* src = obj->TextW.Data + pos + n;
-    while (ImWchar c = *src++)
+    const char* src = obj->TextA.Data + pos + n;
+    while (char c = *src++)
         *dst++ = c;
     *dst = '\0';
 }
 
-static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len)
+static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len)
 {
     const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0;
-    const int text_len = obj->CurLenW;
+    const int text_len = obj->CurLenA;
     IM_ASSERT(pos <= text_len);
 
-    const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
-    if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA))
+    if (!is_resizable && (new_text_len + obj->CurLenA + 1 > obj->BufCapacityA))
         return false;
 
     // Grow internal buffer if needed
-    if (new_text_len + text_len + 1 > obj->TextW.Size)
+    if (new_text_len + text_len + 1 > obj->TextA.Size)
     {
         if (!is_resizable)
             return false;
-        IM_ASSERT(text_len < obj->TextW.Size);
-        obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1);
+        obj->TextA.resize(text_len + ImClamp(new_text_len, 32, ImMax(256, new_text_len)) + 1);
     }
 
-    ImWchar* text = obj->TextW.Data;
+    char* text = obj->TextA.Data;
     if (pos != text_len)
-        memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
-    memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
+        memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos));
+    memcpy(text + pos, new_text, (size_t)new_text_len);
 
     obj->Edited = true;
-    obj->CurLenW += new_text_len;
-    obj->CurLenA += new_text_len_utf8;
-    obj->TextW[obj->CurLenW] = '\0';
+    obj->CurLenA += new_text_len;
+    obj->TextA[obj->CurLenA] = '\0';
 
     return true;
 }
@@ -4022,8 +4071,8 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im
 // the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?)
 static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
 {
-    stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len);
-    ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW);
+    stb_text_makeundo_replace(str, state, 0, str->CurLenA, text_len);
+    ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenA);
     state->cursor = state->select_start = state->select_end = 0;
     if (text_len <= 0)
         return;
@@ -4052,20 +4101,25 @@ ImGuiInputTextState::~ImGuiInputTextState()
 
 void ImGuiInputTextState::OnKeyPressed(int key)
 {
-    stb_textedit_key(this, Stb, key);
+    //We prematurely convert the key to a UTF8 byte sequence, even for keys where that doesn't even make sense (e.g. arrow keys).
+    //Not optimal but stb_textedit_key will only use the UTF8 values for valid character keys anyways.
+    //The changes we had to make to stb_textedit_key make it very much UTF8 specific which is not too great.
+    char utf8[5];
+    ImTextCharToUtf8(utf8, key);
+    stb_textedit_key(this, Stb, key, utf8, (int)strlen(utf8));
     CursorFollow = true;
     CursorAnimReset();
 }
 
 // Those functions are not inlined in imgui_internal.h, allowing us to hide ImStbTexteditState from that header.
 void ImGuiInputTextState::CursorAnimReset()                 { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
-void ImGuiInputTextState::CursorClamp()                     { Stb->cursor = ImMin(Stb->cursor, CurLenW); Stb->select_start = ImMin(Stb->select_start, CurLenW); Stb->select_end = ImMin(Stb->select_end, CurLenW); }
+void ImGuiInputTextState::CursorClamp()                     { Stb->cursor = ImMin(Stb->cursor, CurLenA); Stb->select_start = ImMin(Stb->select_start, CurLenA); Stb->select_end = ImMin(Stb->select_end, CurLenA); }
 bool ImGuiInputTextState::HasSelection() const              { return Stb->select_start != Stb->select_end; }
 void ImGuiInputTextState::ClearSelection()                  { Stb->select_start = Stb->select_end = Stb->cursor; }
 int  ImGuiInputTextState::GetCursorPos() const              { return Stb->cursor; }
 int  ImGuiInputTextState::GetSelectionStart() const         { return Stb->select_start; }
 int  ImGuiInputTextState::GetSelectionEnd() const           { return Stb->select_end; }
-void ImGuiInputTextState::SelectAll()                       { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenW; Stb->has_preferred_x = 0; }
+void ImGuiInputTextState::SelectAll()                       { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenA; Stb->has_preferred_x = 0; }
 void ImGuiInputTextState::ReloadUserBufAndSelectAll()       { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; }
 void ImGuiInputTextState::ReloadUserBufAndKeepSelection()   { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; }
 void ImGuiInputTextState::ReloadUserBufAndMoveToEnd()       { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; }
@@ -4238,26 +4292,21 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
 // FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly.
 static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a)
 {
-    ImGuiContext& g = *GImGui;
-    const ImWchar* old_buf = state->TextW.Data;
-    const int old_length = state->CurLenW;
-    const int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a);
-    g.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar));
-    ImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data;
-    ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a);
+    const char* old_buf = state->TextA.Data;
+    const int old_length = state->CurLenA;
 
-    const int shorter_length = ImMin(old_length, new_length);
+    const int shorter_length = ImMin(old_length, new_length_a);
     int first_diff;
     for (first_diff = 0; first_diff < shorter_length; first_diff++)
-        if (old_buf[first_diff] != new_buf[first_diff])
+        if (old_buf[first_diff] != new_buf_a[first_diff])
             break;
-    if (first_diff == old_length && first_diff == new_length)
+    if (first_diff == old_length && first_diff == new_length_a)
         return;
 
-    int old_last_diff = old_length - 1;
-    int new_last_diff = new_length - 1;
+    int old_last_diff = old_length   - 1;
+    int new_last_diff = new_length_a - 1;
     for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--)
-        if (old_buf[old_last_diff] != new_buf[new_last_diff])
+        if (old_buf[old_last_diff] != new_buf_a[new_last_diff])
             break;
 
     const int insert_len = new_last_diff - first_diff + 1;
@@ -4434,13 +4483,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             recycle_state = false;
 
         // Start edition
-        const char* buf_end = NULL;
         state->ID = id;
-        state->TextW.resize(buf_size + 1);          // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.
-        state->TextA.resize(0);
-        state->TextAIsValid = false;                // TextA is not valid yet (we will display buf until then)
-        state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
-        state->CurLenA = (int)(buf_end - buf);      // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
+        state->TextA.resize(buf_size + 1);          // we use +1 to make sure that .Data is always pointing to at least an empty string.
+        state->TextAIsValid = true;
+        state->CurLenA = (int)strlen(buf);
+        memcpy(state->TextA.Data, buf, state->CurLenA + 1);
 
         if (recycle_state)
         {
@@ -4522,18 +4569,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     bool value_changed = false;
     bool validated = false;
 
-    // When read-only we always use the live data passed to the function
-    // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :(
-    if (is_readonly && state != NULL && (render_cursor || render_selection))
-    {
-        const char* buf_end = NULL;
-        state->TextW.resize(buf_size + 1);
-        state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end);
-        state->CurLenA = (int)(buf_end - buf);
-        state->CursorClamp();
-        render_selection &= state->HasSelection();
-    }
-
     // Select the buffer to render.
     const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid;
     const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
@@ -4786,12 +4821,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             if (g.PlatformIO.Platform_SetClipboardTextFn != NULL)
             {
                 const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0;
-                const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->CurLenW;
-                const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
-                char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char));
-                ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
-                SetClipboardText(clipboard_data);
-                MemFree(clipboard_data);
+                const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->CurLenA;
+
+                char backup = state->TextA.Data[ie];
+                state->TextA.Data[ie] = 0; // A bit of a hack since SetClipboardText only takes null terminated strings
+                SetClipboardText(state->TextA.Data + ib);
+                state->TextA.Data[ie] = backup;
             }
             if (is_cut)
             {
@@ -4807,15 +4842,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             {
                 // Filter pasted buffer
                 const int clipboard_len = (int)strlen(clipboard);
-                ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar));
+                char* clipboard_filtered = (char*)IM_ALLOC((clipboard_len + 1));
                 int clipboard_filtered_len = 0;
                 for (const char* s = clipboard; *s != 0; )
                 {
                     unsigned int c;
-                    s += ImTextCharFromUtf8(&c, s, NULL);
+                    int len = ImTextCharFromUtf8(&c, s, NULL);
                     if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true))
                         continue;
-                    clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
+                    memcpy(clipboard_filtered + clipboard_filtered_len, s, len);
+                    clipboard_filtered_len += len;
+                    s += len;
                 }
                 clipboard_filtered[clipboard_filtered_len] = 0;
                 if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
@@ -4851,27 +4888,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             }
             else if (strcmp(buf, state->InitialTextA.Data) != 0)
             {
-                // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
-                // Push records into the undo stack so we can CTRL+Z the revert operation itself
                 apply_new_text = state->InitialTextA.Data;
                 apply_new_text_length = state->InitialTextA.Size - 1;
-                value_changed = true;
-                ImVector w_text;
-                if (apply_new_text_length > 0)
-                {
-                    w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1);
-                    ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length);
-                }
-                stb_textedit_replace(state, state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0);
-            }
-        }
 
-        // Apply ASCII value
-        if (!is_readonly)
-        {
-            state->TextAIsValid = true;
-            state->TextA.resize(state->TextW.Size * 4 + 1);
-            ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL);
+                // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
+                // Push records into the undo stack so we can CTRL+Z the revert operation itself
+                value_changed = true;
+                stb_textedit_replace(state, state->Stb, state->InitialTextA.Data, state->InitialTextA.Size - 1);
+            }
         }
 
         // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer
@@ -4935,11 +4959,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     callback_data.BufSize = state->BufCapacityA;
                     callback_data.BufDirty = false;
 
-                    // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
-                    ImWchar* text = state->TextW.Data;
-                    const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb->cursor);
-                    const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb->select_start);
-                    const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb->select_end);
+                    const int utf8_cursor_pos = callback_data.CursorPos = state->Stb->cursor;
+                    const int utf8_selection_start = callback_data.SelectionStart = state->Stb->select_start;
+                    const int utf8_selection_end = state->Stb->select_end;
 
                     // Call user code
                     callback(&callback_data);
@@ -4950,17 +4972,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
                     IM_ASSERT(callback_data.Flags == flags);
                     const bool buf_dirty = callback_data.BufDirty;
-                    if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty)            { state->Stb->cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; }
-                    if (callback_data.SelectionStart != utf8_selection_start || buf_dirty)  { state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb->cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
-                    if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty)      { state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb->select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
+                    if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty)            { state->Stb->cursor = callback_data.CursorPos; state->CursorFollow = true; }
+                    if (callback_data.SelectionStart != utf8_selection_start || buf_dirty)  { state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb->cursor : callback_data.SelectionStart; }
+                    if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty)      { state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb->select_start : callback_data.SelectionEnd; }
                     if (buf_dirty)
                     {
                         // Callback may update buffer and thus set buf_dirty even in read-only mode.
                         IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
                         InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?
                         if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
-                            state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize
-                        state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
+                            state->TextA.resize(state->TextA.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize
+
+                        memcpy(state->TextA.Data, callback_data.Buf, callback_data.BufTextLen);
                         state->CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
                         state->CursorAnimReset();
                     }
@@ -5064,12 +5087,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         // - Measure text height (for scrollbar)
         // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
         // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
-        const ImWchar* text_begin = state->TextW.Data;
+        const char* text_begin = state->TextA.Data;
         ImVec2 cursor_offset, select_start_offset;
 
         {
             // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
-            const ImWchar* searches_input_ptr[2] = { NULL, NULL };
+            const char* searches_input_ptr[2] = { NULL, NULL };
             int searches_result_line_no[2] = { -1000, -1000 };
             int searches_remaining = 0;
             if (render_cursor)
@@ -5090,7 +5113,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             searches_remaining += is_multiline ? 1 : 0;
             int line_count = 0;
             //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++)  // FIXME-OPT: Could use this when wchar_t are 16-bit
-            for (const ImWchar* s = text_begin; *s != 0; s++)
+            for (const char* s = text_begin; *s != 0; s++)
                 if (*s == '\n')
                 {
                     line_count++;
@@ -5104,11 +5127,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                 searches_result_line_no[1] = line_count;
 
             // Calculate 2d position by finding the beginning of the line and measuring distance
-            cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
+            cursor_offset.x = InputTextCalcTextSize(&g, ImStrbol(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
             cursor_offset.y = searches_result_line_no[0] * g.FontSize;
             if (searches_result_line_no[1] >= 0)
             {
-                select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
+                select_start_offset.x = InputTextCalcTextSize(&g, ImStrbol(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
                 select_start_offset.y = searches_result_line_no[1] * g.FontSize;
             }
 
@@ -5156,14 +5179,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f);
         if (render_selection)
         {
-            const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end);
-            const ImWchar* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end);
+            const char* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end);
+            const char* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end);
 
             ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
             float bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
             float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
             ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
-            for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
+            for (const char* p = text_selected_begin; p < text_selected_end; )
             {
                 if (rect_pos.y > clip_rect.w + g.FontSize)
                     break;
@@ -5177,7 +5200,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                 }
                 else
                 {
-                    ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true);
+                    ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true);
                     if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
                     ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
                     rect.ClipWith(clip_rect);
@@ -5282,7 +5305,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
     ImStb::StbUndoState* undo_state = &stb_state->undostate;
     Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId);
     DebugLocateItemOnHover(state->ID);
-    Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end);
+    Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end);
     Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x);
     Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point);
     if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state
@@ -5294,11 +5317,8 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
             const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' ';
             if (undo_rec_type == ' ')
                 BeginDisabled();
-            char buf[64] = "";
-            if (undo_rec_type != ' ' && undo_rec->char_storage != -1)
-                ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length);
-            Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"",
-                undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf);
+            Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%.*s\"",
+                undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, undo_rec->insert_length, undo_state->undo_char + undo_rec->char_storage);
             if (undo_rec_type == ' ')
                 EndDisabled();
         }
diff --git a/imstb_textedit.h b/imstb_textedit.h
index faaf518f4..28508607b 100644
--- a/imstb_textedit.h
+++ b/imstb_textedit.h
@@ -4,6 +4,7 @@
 // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
 // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
 // - Added name to struct or it may be forward declared in our code.
+// - Added UTF8 support https://github.com/nothings/stb/issues/188
 // Grep for [DEAR IMGUI] to find the changes.
 // - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
 
@@ -439,13 +440,13 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
    if (x < r.x1) {
       // search characters in row for one that straddles 'x'
       prev_x = r.x0;
-      for (k=0; k < r.num_chars; ++k) {
+      for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
          float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
          if (x < prev_x+w) {
             if (x < prev_x+w/2)
                return k+i;
             else
-               return k+i+1;
+               return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
          }
          prev_x += w;
       }
@@ -564,7 +565,7 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
 
    // now scan to find xpos
    find->x = r.x0;
-   for (i=0; first+i < n; ++i)
+   for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
       find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
 }
 
@@ -641,6 +642,17 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
    }
 }
 
+//[DEAR IMGUI]
+//Functions must be implemented for UTF8 support
+//Code in this file that uses them, is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
+//There is not necessarily a '[DEAR IMGUI]' at the usage sites
+#ifndef IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX
+#define IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(obj, idx) idx - 1
+#endif
+#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
+#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) idx + 1
+#endif
+
 #ifdef STB_TEXTEDIT_IS_SPACE
 static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
 {
@@ -722,15 +734,16 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
 #endif
 
 // API key: process a keyboard input
-static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
+//[DEAR IMGUI] In addition to the key we also pass in the decoded UTF8 byte sequence, if it is a character key.
+//This is a bit ugly and only makes sense for UTF8. One could think of other solutions that wouldn't make this function so UTF8 specific.
+//If the idea is to push the changes upstream to stb_textedit it might be worth thinking about but since this is just for [DEAR IMGUI], it might not be worth the complication
+static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key, const IMSTB_TEXTEDIT_CHARTYPE* decoded, int decoded_size)
 {
 retry:
    switch (key) {
       default: {
          int c = STB_TEXTEDIT_KEYTOTEXT(key);
          if (c > 0) {
-            IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c;
-
             // can't add newline in single-line mode
             if (c == '\n' && state->single_line)
                break;
@@ -738,15 +751,15 @@ retry:
             if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
                stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
                STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
-               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
-                  ++state->cursor;
+               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, decoded, decoded_size)) {
+                  state->cursor += decoded_size;
                   state->has_preferred_x = 0;
                }
             } else {
                stb_textedit_delete_selection(str,state); // implicitly clamps
-               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
-                  stb_text_makeundo_insert(state, state->cursor, 1);
-                  ++state->cursor;
+               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, decoded, decoded_size)) {
+                  stb_text_makeundo_insert(state, state->cursor, decoded_size);
+                  state->cursor += decoded_size;
                   state->has_preferred_x = 0;
                }
             }
@@ -776,7 +789,7 @@ retry:
             stb_textedit_move_to_first(state);
          else
             if (state->cursor > 0)
-               --state->cursor;
+               state->cursor = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->cursor);
          state->has_preferred_x = 0;
          break;
 
@@ -785,7 +798,7 @@ retry:
          if (STB_TEXT_HAS_SELECTION(state))
             stb_textedit_move_to_last(str, state);
          else
-            ++state->cursor;
+            state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
          stb_textedit_clamp(str, state);
          state->has_preferred_x = 0;
          break;
@@ -795,7 +808,7 @@ retry:
          stb_textedit_prep_selection_at_cursor(state);
          // move selection left
          if (state->select_end > 0)
-            --state->select_end;
+            state->select_end = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->select_end);
          state->cursor = state->select_end;
          state->has_preferred_x = 0;
          break;
@@ -845,7 +858,7 @@ retry:
       case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
          stb_textedit_prep_selection_at_cursor(state);
          // move selection right
-         ++state->select_end;
+         state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
          stb_textedit_clamp(str, state);
          state->cursor = state->select_end;
          state->has_preferred_x = 0;
@@ -901,7 +914,7 @@ retry:
                x += dx;
                if (x > goal_x)
                   break;
-               ++state->cursor;
+               state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
             }
             stb_textedit_clamp(str, state);
 
@@ -963,7 +976,7 @@ retry:
                x += dx;
                if (x > goal_x)
                   break;
-               ++state->cursor;
+               state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
             }
             stb_textedit_clamp(str, state);
 
@@ -991,7 +1004,7 @@ retry:
          else {
             int n = STB_TEXTEDIT_STRINGLEN(str);
             if (state->cursor < n)
-               stb_textedit_delete(str, state, state->cursor, 1);
+               stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
          }
          state->has_preferred_x = 0;
          break;
@@ -1003,8 +1016,9 @@ retry:
          else {
             stb_textedit_clamp(str, state);
             if (state->cursor > 0) {
-               stb_textedit_delete(str, state, state->cursor-1, 1);
-               --state->cursor;
+               int prev = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->cursor);
+               stb_textedit_delete(str, state, prev, state->cursor - prev);
+               state->cursor = prev;
             }
          }
          state->has_preferred_x = 0;

From d1b7817959245230e0ef24f8c9886c0e6d0d1396 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 5 Sep 2024 15:25:30 +0200
Subject: [PATCH 118/136] InputText: amends: renames, coding style. (#7925)

---
 imgui.h           |  2 +-
 imgui_internal.h  |  1 -
 imgui_widgets.cpp | 17 ++++++++---------
 imstb_textedit.h  | 22 +++++++++++-----------
 4 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/imgui.h b/imgui.h
index ebb156d4b..095c25002 100644
--- a/imgui.h
+++ b/imgui.h
@@ -29,7 +29,7 @@
 // Library Version
 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
 #define IMGUI_VERSION       "1.91.2 WIP"
-#define IMGUI_VERSION_NUM   19113
+#define IMGUI_VERSION_NUM   19114
 #define IMGUI_HAS_TABLE
 
 /*
diff --git a/imgui_internal.h b/imgui_internal.h
index ec4c069eb..4dfcfce9a 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -1114,7 +1114,6 @@ struct IMGUI_API ImGuiInputTextState
     int                     CurLenA;                // UTF-8 length of the string in TextA (in bytes)
     ImVector          TextA;                  // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
     ImVector          InitialTextA;           // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
-    bool                    TextAIsValid;           // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)
     int                     BufCapacityA;           // end-user buffer capacity
     ImVec2                  Scroll;                 // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y)
     float                   CursorAnim;             // timer for cursor blink, reset on every user action so the cursor reappears immediately
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 5a8721c78..64e701407 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3952,10 +3952,10 @@ static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)
 static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
 static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
 static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)  { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
-#define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL  // They need to be #define for stb_textedit.h
-#define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
+#define STB_TEXTEDIT_MOVEWORDLEFT       STB_TEXTEDIT_MOVEWORDLEFT_IMPL  // They need to be #define for stb_textedit.h
+#define STB_TEXTEDIT_MOVEWORDRIGHT      STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
 #define IMSTB_TEXTEDIT_GETNEXTCHARINDEX  IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL
-#define IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX  IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX_IMPL
+#define IMSTB_TEXTEDIT_GETPREVCHARINDEX  IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL
 
 static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
 {
@@ -3975,9 +3975,9 @@ static int CountLeadingHighBits(unsigned char b)
     return sizeof(b) * 8;
 }
 
-static int IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
+static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
 {
-    //Backwards check/count for UTF-8 multi byte sequence
+    // Backwards check/count for UTF-8 multi byte sequence
     int num_seq_bytes = 0;
     for (int i = idx - 1; i >= 0; i -= 1)
     {
@@ -4479,13 +4479,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         // Preserve cursor position and undo/redo stack if we come back to same widget
         // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate?
         bool recycle_state = (state->ID == id && !init_changed_specs && !init_reload_from_user_buf);
-        if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0)))
+        if (recycle_state && (state->CurLenA != buf_len || (strncmp(state->TextA.Data, buf, buf_len) != 0)))
             recycle_state = false;
 
         // Start edition
         state->ID = id;
         state->TextA.resize(buf_size + 1);          // we use +1 to make sure that .Data is always pointing to at least an empty string.
-        state->TextAIsValid = true;
         state->CurLenA = (int)strlen(buf);
         memcpy(state->TextA.Data, buf, state->CurLenA + 1);
 
@@ -4570,7 +4569,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     bool validated = false;
 
     // Select the buffer to render.
-    const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid;
+    const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state;
     const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
 
     // Password pushes a temporary font with only a fallback glyph
@@ -4842,7 +4841,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             {
                 // Filter pasted buffer
                 const int clipboard_len = (int)strlen(clipboard);
-                char* clipboard_filtered = (char*)IM_ALLOC((clipboard_len + 1));
+                char* clipboard_filtered = (char*)IM_ALLOC(clipboard_len + 1);
                 int clipboard_filtered_len = 0;
                 for (const char* s = clipboard; *s != 0; )
                 {
diff --git a/imstb_textedit.h b/imstb_textedit.h
index 28508607b..22122c08b 100644
--- a/imstb_textedit.h
+++ b/imstb_textedit.h
@@ -4,7 +4,7 @@
 // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
 // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
 // - Added name to struct or it may be forward declared in our code.
-// - Added UTF8 support https://github.com/nothings/stb/issues/188
+// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
 // Grep for [DEAR IMGUI] to find the changes.
 // - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
 
@@ -642,15 +642,15 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
    }
 }
 
-//[DEAR IMGUI]
-//Functions must be implemented for UTF8 support
-//Code in this file that uses them, is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
-//There is not necessarily a '[DEAR IMGUI]' at the usage sites
-#ifndef IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX
-#define IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(obj, idx) idx - 1
+// [DEAR IMGUI]
+// Functions must be implemented for UTF8 support
+// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
+// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
+#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
+#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
 #endif
 #ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
-#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) idx + 1
+#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
 #endif
 
 #ifdef STB_TEXTEDIT_IS_SPACE
@@ -789,7 +789,7 @@ retry:
             stb_textedit_move_to_first(state);
          else
             if (state->cursor > 0)
-               state->cursor = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->cursor);
+               state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
          state->has_preferred_x = 0;
          break;
 
@@ -808,7 +808,7 @@ retry:
          stb_textedit_prep_selection_at_cursor(state);
          // move selection left
          if (state->select_end > 0)
-            state->select_end = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->select_end);
+            state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
          state->cursor = state->select_end;
          state->has_preferred_x = 0;
          break;
@@ -1016,7 +1016,7 @@ retry:
          else {
             stb_textedit_clamp(str, state);
             if (state->cursor > 0) {
-               int prev = IMSTB_TEXTEDIT_GETPREVIOUSCHARINDEX(str, state->cursor);
+               int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
                stb_textedit_delete(str, state, prev, state->cursor - prev);
                state->cursor = prev;
             }

From 1674fe96ff57e4540b6c1860e61aa7fcc06642fe Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 5 Sep 2024 16:31:41 +0200
Subject: [PATCH 119/136] InputText: amends: add stb_textedit_text() api.
 (#7925)

It seems sensible to push this change in stb_textedit repo eventually.
---
 imgui_internal.h  |  1 +
 imgui_widgets.cpp | 23 +++++++++++-------
 imstb_textedit.h  | 61 ++++++++++++++++++++++++++++-------------------
 3 files changed, 52 insertions(+), 33 deletions(-)

diff --git a/imgui_internal.h b/imgui_internal.h
index 4dfcfce9a..e6f3f8ec5 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -1130,6 +1130,7 @@ struct IMGUI_API ImGuiInputTextState
     void        ClearText()                 { CurLenA = 0; TextA[0] = 0; CursorClamp(); }
     void        ClearFreeMemory()           { TextA.clear(); InitialTextA.clear(); }
     void        OnKeyPressed(int key);      // Cannot be inline because we call in code in stb_textedit.h implementation
+    void        OnCharPressed(unsigned int c);
 
     // Cursor & Selection
     void        CursorAnimReset();
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 64e701407..f35563119 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3889,7 +3889,6 @@ namespace ImStb
 static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->CurLenA; }
 static char    STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->CurLenA); return obj->TextA[idx]; }
 static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextA.Size); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; }
-static int     STB_TEXTEDIT_KEYTOTEXT(int key)                                                    { return key >= 0x200000 ? 0 : key; }
 static char    STB_TEXTEDIT_NEWLINE = '\n';
 static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
 {
@@ -4101,12 +4100,18 @@ ImGuiInputTextState::~ImGuiInputTextState()
 
 void ImGuiInputTextState::OnKeyPressed(int key)
 {
-    //We prematurely convert the key to a UTF8 byte sequence, even for keys where that doesn't even make sense (e.g. arrow keys).
-    //Not optimal but stb_textedit_key will only use the UTF8 values for valid character keys anyways.
-    //The changes we had to make to stb_textedit_key make it very much UTF8 specific which is not too great.
+    stb_textedit_key(this, Stb, key);
+    CursorFollow = true;
+    CursorAnimReset();
+}
+
+void ImGuiInputTextState::OnCharPressed(unsigned int c)
+{
+    // Convert the key to a UTF8 byte sequence.
+    // The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great.
     char utf8[5];
-    ImTextCharToUtf8(utf8, key);
-    stb_textedit_key(this, Stb, key, utf8, (int)strlen(utf8));
+    ImTextCharToUtf8(utf8, c);
+    stb_textedit_text(this, Stb, utf8, (int)strlen(utf8));
     CursorFollow = true;
     CursorAnimReset();
 }
@@ -4674,7 +4679,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             {
                 unsigned int c = '\t'; // Insert TAB
                 if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
-                    state->OnKeyPressed((int)c);
+                    state->OnCharPressed(c);
             }
             // FIXME: Implement Shift+Tab
             /*
@@ -4697,7 +4702,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     if (c == '\t') // Skip Tab, see above.
                         continue;
                     if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
-                        state->OnKeyPressed((int)c);
+                        state->OnCharPressed(c);
                 }
 
             // Consume characters
@@ -4781,7 +4786,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             {
                 unsigned int c = '\n'; // Insert new line
                 if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data))
-                    state->OnKeyPressed((int)c);
+                    state->OnCharPressed(c);
             }
         }
         else if (is_cancel)
diff --git a/imstb_textedit.h b/imstb_textedit.h
index 22122c08b..b7a761c85 100644
--- a/imstb_textedit.h
+++ b/imstb_textedit.h
@@ -211,6 +211,7 @@
 //    int  stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
 //    int  stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
 //    void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
+//    void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
 //
 //    Each of these functions potentially updates the string and updates the
 //    state.
@@ -245,7 +246,12 @@
 //          various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
 //          set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
 //          clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
-//          anything other type you wante before including.
+//          anything other type you want before including.
+//          if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
+//          transformed into text and stb_textedit_text() is automatically called.
+//
+//      text: [DEAR IMGUI] added 2024-09
+//          call this to text inputs sent to the textfield.
 //
 //
 //   When rendering, you can read the cursor position and selection state from
@@ -733,37 +739,44 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
 #define STB_TEXTEDIT_KEYTYPE int
 #endif
 
+// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
+static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
+{
+   // can't add newline in single-line mode
+   if (text[0] == '\n' && state->single_line)
+      return;
+
+   if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
+      stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
+      STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
+      if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
+         state->cursor += text_len;
+         state->has_preferred_x = 0;
+      }
+   }
+   else {
+      stb_textedit_delete_selection(str, state); // implicitly clamps
+      if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
+         stb_text_makeundo_insert(state, state->cursor, text_len);
+         state->cursor += text_len;
+         state->has_preferred_x = 0;
+      }
+   }
+}
+
 // API key: process a keyboard input
-//[DEAR IMGUI] In addition to the key we also pass in the decoded UTF8 byte sequence, if it is a character key.
-//This is a bit ugly and only makes sense for UTF8. One could think of other solutions that wouldn't make this function so UTF8 specific.
-//If the idea is to push the changes upstream to stb_textedit it might be worth thinking about but since this is just for [DEAR IMGUI], it might not be worth the complication
-static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key, const IMSTB_TEXTEDIT_CHARTYPE* decoded, int decoded_size)
+static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
 {
 retry:
    switch (key) {
       default: {
+#ifdef STB_TEXTEDIT_KEYTOTEXT
          int c = STB_TEXTEDIT_KEYTOTEXT(key);
          if (c > 0) {
-            // can't add newline in single-line mode
-            if (c == '\n' && state->single_line)
-               break;
-
-            if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
-               stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
-               STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
-               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, decoded, decoded_size)) {
-                  state->cursor += decoded_size;
-                  state->has_preferred_x = 0;
-               }
-            } else {
-               stb_textedit_delete_selection(str,state); // implicitly clamps
-               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, decoded, decoded_size)) {
-                  stb_text_makeundo_insert(state, state->cursor, decoded_size);
-                  state->cursor += decoded_size;
-                  state->has_preferred_x = 0;
-               }
-            }
+            IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
+            stb_textedit_text(str, state, &ch, 1);
          }
+#endif
          break;
       }
 

From e240bc151a3650be8af0ea9d426d4fb44914c7e0 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 5 Sep 2024 16:29:30 +0200
Subject: [PATCH 120/136] InputText: amends: add note about
 STB_TEXTEDIT_GETCHAR. tweak InputTextCalcTextSize() to use similar
 debug-friendly logic as ImFont:CalcTextSizeA(). misc small tidying up.
 (#7925)

---
 imgui_widgets.cpp | 51 ++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 20 deletions(-)

diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index f35563119..6d701d03b 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3836,6 +3836,7 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
     return line_count;
 }
 
+// FIXME: Ideally we'd share code with ImFont::CalcTextSizeA()
 static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line)
 {
     ImGuiContext& g = *ctx;
@@ -3849,8 +3850,12 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c
     const char* s = text_begin;
     while (s < text_end)
     {
-        unsigned int c;
-        s += ImTextCharFromUtf8(&c, s, text_end);
+        unsigned int c = (unsigned int)*s;
+        if (c < 0x80)
+            s += 1;
+        else
+            s += ImTextCharFromUtf8(&c, s, text_end);
+
         if (c == '\n')
         {
             text_size.x = ImMax(text_size.x, line_width);
@@ -3863,7 +3868,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c
         if (c == '\r')
             continue;
 
-        const float char_width = font->GetCharAdvance((ImWchar)c) * scale;
+        const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX) * scale;
         line_width += char_width;
     }
 
@@ -3883,23 +3888,27 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c
 }
 
 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
+// With our UTF-8 use of stb_textedit:
+// - STB_TEXTEDIT_GETCHAR is nothing more than a a "GETBYTE". It's only used to compare to ascii or to copy blocks of text so we are fine.
+// - One exception is the STB_TEXTEDIT_IS_SPACE feature which would expect a full char in order to handle full-width space such as 0x3000 (see ImCharIsBlankW).
+// - ...but we don't use that feature.
 namespace ImStb
 {
-
 static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->CurLenA; }
 static char    STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->CurLenA); return obj->TextA[idx]; }
 static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextA.Size); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; }
 static char    STB_TEXTEDIT_NEWLINE = '\n';
 static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
 {
+    const char* text = obj->TextA.Data;
     const char* text_remaining = NULL;
-    const ImVec2 size = InputTextCalcTextSize(obj->Ctx, obj->TextA.Data + line_start_idx, obj->TextA.Data + obj->CurLenA, &text_remaining, NULL, true);
+    const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->CurLenA, &text_remaining, NULL, true);
     r->x0 = 0.0f;
     r->x1 = size.x;
     r->baseline_y_delta = size.y;
     r->ymin = 0.0f;
     r->ymax = size.y;
-    r->num_chars = (int)(text_remaining - (obj->TextA.Data + line_start_idx));
+    r->num_chars = (int)(text_remaining - (text + line_start_idx));
 }
 
 static bool ImCharIsSeparatorW(unsigned int c)
@@ -3922,14 +3931,15 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)
     if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
         return 0;
 
-    const char* prevPtr = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx);
-    unsigned int curr; ImTextCharFromUtf8(&curr, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
-    unsigned int prev; ImTextCharFromUtf8(&prev, prevPtr, obj->TextA.Data + obj->TextA.Size);
+    const char* curr_p = obj->TextA.Data + idx;
+    const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p);
+    unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->TextA.Size);
+    unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->TextA.Size);
 
-    bool prev_white = ImCharIsBlankW(prev);
-    bool prev_separ = ImCharIsSeparatorW(prev);
-    bool curr_white = ImCharIsBlankW(curr);
-    bool curr_separ = ImCharIsSeparatorW(curr);
+    bool prev_white = ImCharIsBlankW(prev_c);
+    bool prev_separ = ImCharIsSeparatorW(prev_c);
+    bool curr_white = ImCharIsBlankW(curr_c);
+    bool curr_separ = ImCharIsSeparatorW(curr_c);
     return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
 }
 static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
@@ -3937,14 +3947,15 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
     if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
         return 0;
 
-    const char* prevPtr = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx);
-    unsigned int prev; ImTextCharFromUtf8(&prev, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
-    unsigned int curr; ImTextCharFromUtf8(&curr, prevPtr, obj->TextA.Data + obj->TextA.Size);
+    const char* curr_p = obj->TextA.Data + idx;
+    const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p);
+    unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->TextA.Size);
+    unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->TextA.Size);
 
-    bool prev_white = ImCharIsBlankW(prev);
-    bool prev_separ = ImCharIsSeparatorW(prev);
-    bool curr_white = ImCharIsBlankW(curr);
-    bool curr_separ = ImCharIsSeparatorW(curr);
+    bool prev_white = ImCharIsBlankW(prev_c);
+    bool prev_separ = ImCharIsSeparatorW(prev_c);
+    bool curr_white = ImCharIsBlankW(curr_c);
+    bool curr_separ = ImCharIsSeparatorW(curr_c);
     return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
 }
 static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)   { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }

From 3d1e593b5b1c6842001a5cf9db1845c93df07689 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 5 Sep 2024 19:56:12 +0200
Subject: [PATCH 121/136] InputText: amends: fixed next/prev word
 implementation. (#7925)

+ replace IMSTB_TEXTEDIT_GETPREVCHARINDEX code with ImTextFindPreviousUtf8Codepoint().
---
 imgui_widgets.cpp | 91 ++++++++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 49 deletions(-)

diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 6d701d03b..24d1fda7e 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3911,6 +3911,25 @@ static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob
     r->num_chars = (int)(text_remaining - (text + line_start_idx));
 }
 
+#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX  IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL
+#define IMSTB_TEXTEDIT_GETPREVCHARINDEX  IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL
+
+static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
+{
+    if (idx >= obj->CurLenA)
+        return obj->CurLenA + 1;
+    unsigned int c;
+    return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
+}
+
+static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
+{
+    if (idx <= 0)
+        return -1;
+    const char* p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx);
+    return (int)(p - obj->TextA.Data);
+}
+
 static bool ImCharIsSeparatorW(unsigned int c)
 {
     static const unsigned int separator_list[] =
@@ -3958,58 +3977,32 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
     bool curr_separ = ImCharIsSeparatorW(curr_c);
     return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
 }
-static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)   { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
-static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
-static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenA; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
+static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)
+{
+    idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx);
+    while (idx >= 0 && !is_word_boundary_from_right(obj, idx))
+        idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx);
+    return idx < 0 ? 0 : idx;
+}
+static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)
+{
+    int len = obj->CurLenA;
+    idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx);
+    while (idx < len && !is_word_boundary_from_left(obj, idx))
+        idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx);
+    return idx > len ? len : idx;
+}
+static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)
+{
+    idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx);
+    int len = obj->CurLenA;
+    while (idx < len && !is_word_boundary_from_right(obj, idx))
+        idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx);
+    return idx > len ? len : idx;
+}
 static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx)  { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
 #define STB_TEXTEDIT_MOVEWORDLEFT       STB_TEXTEDIT_MOVEWORDLEFT_IMPL  // They need to be #define for stb_textedit.h
 #define STB_TEXTEDIT_MOVEWORDRIGHT      STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
-#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX  IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL
-#define IMSTB_TEXTEDIT_GETPREVCHARINDEX  IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL
-
-static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
-{
-    unsigned int c;
-    return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size);
-}
-
-static int CountLeadingHighBits(unsigned char b)
-{
-    for (int i = 0; i < (int)sizeof(b) * 8; i++)
-    {
-        bool set = (b >> (7 - i)) & 1;
-        if (!set)
-            return i;
-    }
-
-    return sizeof(b) * 8;
-}
-
-static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx)
-{
-    // Backwards check/count for UTF-8 multi byte sequence
-    int num_seq_bytes = 0;
-    for (int i = idx - 1; i >= 0; i -= 1)
-    {
-        bool is_seq_byte = (obj->TextA.Data[i] & 0x80) == 0x80 && (obj->TextA.Data[i] & 0x40) == 0;
-        num_seq_bytes += is_seq_byte;
-        if (!is_seq_byte)
-        {
-            if (num_seq_bytes > 0)
-            {
-                char initial_byte = obj->TextA.Data[i];
-                char num_leading_bits = (char)CountLeadingHighBits(initial_byte);
-                bool is_multi_byte_seq = num_leading_bits == num_seq_bytes + 1;
-                if (is_multi_byte_seq)
-                {
-                    return idx - (num_seq_bytes + 1);
-                }
-            }
-            break;
-        }
-    }
-    return idx - 1;
-}
 
 static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
 {

From 19accb14a9e52f515624485ef8ea6eba8dbab7c3 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Wed, 11 Sep 2024 12:57:54 +0200
Subject: [PATCH 122/136] InputText: amends: fixed undo-stack reconcile. fixed
 metrics crash. fixes character filtering. (#7925)

Refer to imgui_test_suite for tests.
---
 imgui_internal.h  |  3 ++-
 imgui_widgets.cpp | 31 ++++++++++++++++---------------
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/imgui_internal.h b/imgui_internal.h
index e6f3f8ec5..b54848635 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -1112,8 +1112,9 @@ struct IMGUI_API ImGuiInputTextState
     ImStbTexteditState*     Stb;                    // State for stb_textedit.h
     ImGuiID                 ID;                     // widget id owning the text state
     int                     CurLenA;                // UTF-8 length of the string in TextA (in bytes)
-    ImVector          TextA;                  // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
+    ImVector          TextA;                  // main UTF8 buffer.
     ImVector          InitialTextA;           // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
+    ImVector          CallbackTextBackup;     // temporary storage for callback to support automatic reconcile of undo-stack
     int                     BufCapacityA;           // end-user buffer capacity
     ImVec2                  Scroll;                 // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y)
     float                   CursorAnim;             // timer for cursor blink, reset on every user action so the cursor reappears immediately
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 24d1fda7e..b5c69e73e 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -4301,8 +4301,8 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im
 // FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly.
 static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a)
 {
-    const char* old_buf = state->TextA.Data;
-    const int old_length = state->CurLenA;
+    const char* old_buf = state->CallbackTextBackup.Data;
+    const int old_length = state->CallbackTextBackup.Size - 1;
 
     const int shorter_length = ImMin(old_length, new_length_a);
     int first_diff;
@@ -4323,7 +4323,7 @@ static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* st
     if (insert_len > 0 || delete_len > 0)
         if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb->undostate, first_diff, delete_len, insert_len))
             for (int i = 0; i < delete_len; i++)
-                p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i);
+                p[i] = old_buf[first_diff + i];
 }
 
 // As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables)
@@ -4598,11 +4598,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     }
 
     // Process mouse inputs and character inputs
-    int backup_current_text_length = 0;
     if (g.ActiveId == id)
     {
         IM_ASSERT(state != NULL);
-        backup_current_text_length = state->CurLenA;
         state->Edited = false;
         state->BufCapacityA = buf_size;
         state->Flags = flags;
@@ -4856,11 +4854,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                 {
                     unsigned int c;
                     int len = ImTextCharFromUtf8(&c, s, NULL);
+                    s += len;
                     if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true))
                         continue;
-                    memcpy(clipboard_filtered + clipboard_filtered_len, s, len);
+                    memcpy(clipboard_filtered + clipboard_filtered_len, s - len, len);
                     clipboard_filtered_len += len;
-                    s += len;
                 }
                 clipboard_filtered[clipboard_filtered_len] = 0;
                 if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
@@ -4960,6 +4958,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     callback_data.Flags = flags;
                     callback_data.UserData = callback_user_data;
 
+                    // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925
+                    state->CallbackTextBackup.resize(state->CurLenA + 1);
+                    memcpy(state->CallbackTextBackup.Data, state->TextA.Data, state->CurLenA + 1);
+
                     char* callback_buf = is_readonly ? buf : state->TextA.Data;
                     callback_data.EventKey = event_key;
                     callback_data.Buf = callback_buf;
@@ -4988,11 +4990,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                         // Callback may update buffer and thus set buf_dirty even in read-only mode.
                         IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
                         InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?
-                        if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
-                            state->TextA.resize(state->TextA.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize
-
-                        memcpy(state->TextA.Data, callback_data.Buf, callback_data.BufTextLen);
                         state->CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
+                        state->TextA.Size = state->CurLenA + 1;
                         state->CursorAnimReset();
                     }
                 }
@@ -5024,9 +5023,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     // Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
     if (apply_new_text != NULL)
     {
-        // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
-        // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
-        // without any storage on user's side.
+        //// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
+        //// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
+        //// without any storage on user's side.
         IM_ASSERT(apply_new_text_length >= 0);
         if (is_resizable)
         {
@@ -5325,8 +5324,10 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
             const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' ';
             if (undo_rec_type == ' ')
                 BeginDisabled();
+            const int buf_preview_len = (undo_rec_type != ' ' && undo_rec->char_storage != -1) ? undo_rec->insert_length : 0;
+            const char* buf_preview_str = undo_state->undo_char + undo_rec->char_storage;
             Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%.*s\"",
-                undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, undo_rec->insert_length, undo_state->undo_char + undo_rec->char_storage);
+                undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf_preview_len, buf_preview_str);
             if (undo_rec_type == ' ')
                 EndDisabled();
         }

From 8807b01b28883dfbf7b971a4aa6c1199e4dea827 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Wed, 11 Sep 2024 14:15:23 +0200
Subject: [PATCH 123/136] InputText: amends: now can use memchr()/strchr() for
 line counting. Much faster! (#7925)

---
 docs/CHANGELOG.txt |  4 ++++
 docs/TODO.txt      |  1 -
 imgui_widgets.cpp  | 24 ++++++++++--------------
 3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 35c4c6743..1611bf59b 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -63,6 +63,10 @@ Other changes:
      #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434,
      #7472, #7581, #7724, #7926, #7937 and probably more..)
 - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439)
+- InputText: internal refactoring to simplify and optimize the code. The ImWchar buffer has been
+  removed. Simplifications allowed to implement new optimizations for handling very large text buffers
+  (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build).
+  This is the first step toward more refactorig. (#7925) [@alektron, @ocornut]
 - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow.
 - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660)
 - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam]
diff --git a/docs/TODO.txt b/docs/TODO.txt
index 84a00bc6e..ddceb3b3d 100644
--- a/docs/TODO.txt
+++ b/docs/TODO.txt
@@ -65,7 +65,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
  - selectable: generic BeginSelectable()/EndSelectable() mechanism. (work out alongside range-select branch)
  - selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection)
 
- - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. (WIP branch)
  - input text: preserve scrolling when unfocused?
  - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541)
  - input text: expose CursorPos in char filter event (#816)
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index b5c69e73e..94e1abff6 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -5119,14 +5119,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
             searches_remaining += is_multiline ? 1 : 0;
             int line_count = 0;
-            //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++)  // FIXME-OPT: Could use this when wchar_t are 16-bit
-            for (const char* s = text_begin; *s != 0; s++)
-                if (*s == '\n')
-                {
-                    line_count++;
-                    if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
-                    if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
-                }
+            for (const char* s = text_begin; (s = strchr(s, '\n')) != NULL; s++) // FIXME-OPT: memchr() would be faster?
+            {
+                line_count++;
+                if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
+                if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
+            }
             line_count++;
             if (searches_result_line_no[0] == -1)
                 searches_result_line_no[0] = line_count;
@@ -5199,11 +5197,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     break;
                 if (rect_pos.y < clip_rect.y)
                 {
-                    //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p);  // FIXME-OPT: Could use this when wchar_t are 16-bit
-                    //p = p ? p + 1 : text_selected_end;
-                    while (p < text_selected_end)
-                        if (*p++ == '\n')
-                            break;
+                    p = (const char*)memchr((void*)p, '\n', text_selected_end - p);
+                    p = p ? p + 1 : text_selected_end;
                 }
                 else
                 {
@@ -5213,13 +5208,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                     rect.ClipWith(clip_rect);
                     if (rect.Overlaps(clip_rect))
                         draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
+                    rect_pos.x = draw_pos.x - draw_scroll.x;
                 }
-                rect_pos.x = draw_pos.x - draw_scroll.x;
                 rect_pos.y += g.FontSize;
             }
         }
 
         // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
+        // FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through it.
         if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
         {
             ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);

From dc6346b763e4c92fe57887ee1cb4fe557517d4fa Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 12 Sep 2024 19:22:09 +0200
Subject: [PATCH 124/136] Fonts: fixed ellipsis "..." rendering width
 miscalculation bug introduced in 1.91.0. (#7976)

Amend 0f63d3e9
---
 docs/CHANGELOG.txt | 1 +
 imgui.cpp          | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 1611bf59b..28b3cae26 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -68,6 +68,7 @@ Other changes:
   (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build).
   This is the first step toward more refactorig. (#7925) [@alektron, @ocornut]
 - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow.
+- Fonts: fixed ellipsis "..." rendering width miscalculation bug introduced in 1.91.0. (#7976) [@DDeimos]
 - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660)
 - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam]
 
diff --git a/imgui.cpp b/imgui.cpp
index 71b1b1011..3c2fd6658 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -4007,7 +4007,7 @@ static void SetCurrentWindow(ImGuiWindow* window)
     if (window)
     {
         g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
-        g.FontScale = g.FontSize / g.Font->FontSize;
+        g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
         ImGui::NavUpdateCurrentWindowIsScrollPushableX();
     }
 }

From 52a6ab44b1f0387922ec802ad909cf32a5283f24 Mon Sep 17 00:00:00 2001
From: David Briscoe <43559+idbrii@users.noreply.github.com>
Date: Thu, 12 Sep 2024 10:24:37 -0700
Subject: [PATCH 125/136] Doc: Fix typo. (#7974)

---
 imgui.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/imgui.cpp b/imgui.cpp
index 3c2fd6658..59a918e86 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -9046,7 +9046,7 @@ bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
     return IsKeyPressed(key, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any);
 }
 
-// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
+// Important: unlike legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
 bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id)
 {
     const ImGuiKeyData* key_data = GetKeyData(key);

From ac2ad79812e8f17ed4d76b8645c3f10e385018c8 Mon Sep 17 00:00:00 2001
From: Yan Pujante 
Date: Sat, 7 Sep 2024 10:22:45 -0700
Subject: [PATCH 126/136] Backends: GLFW+Emscripten: use OSX behaviors
 automatically when using contrib glfw port. (#7965, #7915)

---
 backends/imgui_impl_glfw.cpp              | 22 +++++++++++++++++++++-
 docs/CHANGELOG.txt                        |  2 ++
 examples/example_glfw_wgpu/CMakeLists.txt |  1 -
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp
index 06b5142a1..9c6722f78 100644
--- a/backends/imgui_impl_glfw.cpp
+++ b/backends/imgui_impl_glfw.cpp
@@ -18,6 +18,11 @@
 // - Documentation        https://dearimgui.com/docs (same as your local docs/ folder).
 // - Introduction, links and more at the top of imgui.cpp
 
+// About Emscripten support:
+// - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.)
+// - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser.
+// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details.
+
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
 //  2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
@@ -560,7 +565,7 @@ void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
 }
 
 #ifdef __EMSCRIPTEN__
-#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 3'4'0'20240817
+#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
 void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); }
 #else
 EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
@@ -639,6 +644,21 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
     ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
 #endif
 
+    // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
+    // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
+#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
+    if (emscripten::glfw3::IsRuntimePlatformApple())
+    {
+        ImGui::GetIO().ConfigMacOSXBehaviors = true;
+
+        // Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used.
+        // This means that Meta + V only registers a single key-press, even if the keys are held.
+        // This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself.
+        // See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key
+        emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10);
+    }
+#endif
+
     bd->ClientApi = client_api;
     return true;
 }
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 28b3cae26..2189f2584 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -71,6 +71,8 @@ Other changes:
 - Fonts: fixed ellipsis "..." rendering width miscalculation bug introduced in 1.91.0. (#7976) [@DDeimos]
 - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660)
 - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam]
+- Backends: GLFW+Emscripten: use OSX behaviors automatically when using contrib glfw port. (#7965, #7915)
+  [@ypujante]
 
 -----------------------------------------------------------------------
  VERSION 1.91.1 (Released 2024-09-04)
diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt
index 77b492fdc..6be95af44 100644
--- a/examples/example_glfw_wgpu/CMakeLists.txt
+++ b/examples/example_glfw_wgpu/CMakeLists.txt
@@ -91,7 +91,6 @@ if(EMSCRIPTEN)
   if("${IMGUI_EMSCRIPTEN_GLFW3}" STREQUAL "--use-port=contrib.glfw3")
     target_compile_options(example_glfw_wgpu PUBLIC
         "${IMGUI_EMSCRIPTEN_GLFW3}"
-        "-DEMSCRIPTEN_USE_PORT_CONTRIB_GLFW3" # unnecessary beyond emscripten 3.1.59
     )
   endif()
   message(STATUS "Using ${IMGUI_EMSCRIPTEN_GLFW3} GLFW implementation")

From 6dcb7be35f8e9b54d4a3e3c75a97ab09589e4f38 Mon Sep 17 00:00:00 2001
From: Yan Pujante 
Date: Sat, 7 Sep 2024 10:23:20 -0700
Subject: [PATCH 127/136] CI: amend build tests for emscripten (#7965)

+ Backends: GLFW: minor preemptive fix.
---
 .github/workflows/build.yml  | 16 +++++++++++++++-
 backends/imgui_impl_glfw.cpp |  2 ++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1d43da032..f95ff43c8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -527,6 +527,7 @@ jobs:
         emsdk-master/emsdk update
         emsdk-master/emsdk install latest
         emsdk-master/emsdk activate latest
+        sudo apt-get install build-essential
 
     - name: Build example_sdl2_opengl3 with Emscripten
       run: |
@@ -535,13 +536,26 @@ jobs:
         popd
         make -C examples/example_sdl2_opengl3 -f Makefile.emscripten
 
-    - name: Build example_glfw_wgpu
+    # This build compiles example_glfw_wgpu using Makefile.emscripten and Emscripten GLFW built-in implementation (-sUSE_GLFW=3)
+    # This ensures 2 things: the make build works, and the GLFW built-in implementation is tested
+    - name: Build example_glfw_wgpu with Emscripten/Makefile
       run: |
         pushd emsdk-master
         source ./emsdk_env.sh
         popd
         make -C examples/example_glfw_wgpu -f Makefile.emscripten
 
+    # This build compiles example_glfw_wgpu using CMakeLists.txt and Emscripten GLFW contrib port (--use-port=contrib.glfw3)
+    # This ensures 2 things: the CMake build works, and the GLFW contrib port is tested
+    - name: Build example_glfw_wgpu with Emscripten/CMake
+      run: |
+        pushd emsdk-master
+        source ./emsdk_env.sh
+        popd
+        emcc -v
+        emcmake cmake -B build -DCMAKE_BUILD_TYPE=Release examples/example_glfw_wgpu
+        cmake --build build
+
   Android:
     runs-on: ubuntu-24.04
     steps:
diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp
index 9c6722f78..30afaf4f0 100644
--- a/backends/imgui_impl_glfw.cpp
+++ b/backends/imgui_impl_glfw.cpp
@@ -646,6 +646,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
 
     // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
     // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
+#ifdef __EMSCRIPTEN__
 #if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
     if (emscripten::glfw3::IsRuntimePlatformApple())
     {
@@ -657,6 +658,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
         // See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key
         emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10);
     }
+#endif
 #endif
 
     bd->ClientApi = client_api;

From 4d00bf8add44155a4f6b489538bd77d6214a4432 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Thu, 12 Sep 2024 23:13:32 +0200
Subject: [PATCH 128/136] MultiSelect+Tables: fixed an issue where box-select
 would skip items while drag-scrolling in a table with outer borders. (#7970,
 #7821).

See "widgets_multiselect_boxselect_2" test.
---
 docs/CHANGELOG.txt | 2 ++
 imgui_widgets.cpp  | 7 ++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 2189f2584..903af40c3 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -63,6 +63,8 @@ Other changes:
      #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434,
      #7472, #7581, #7724, #7926, #7937 and probably more..)
 - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439)
+- MultiSelect+Tables: fixed an issue where box-select would skip items while drag-scrolling
+  in a table with outer borders. (#7970, #7821).
 - InputText: internal refactoring to simplify and optimize the code. The ImWchar buffer has been
   removed. Simplifications allowed to implement new optimizations for handling very large text buffers
   (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build).
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 94e1abff6..14c5af3e4 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -7403,6 +7403,7 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe
 
 static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window)
 {
+    ImGuiContext& g = *GImGui;
     if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect)
     {
         // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only
@@ -7410,8 +7411,12 @@ static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window)
     }
     else
     {
-        // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect?
+        // When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970)
         ImRect scope_rect = window->InnerClipRect;
+        if (g.CurrentTable != NULL)
+            scope_rect = g.CurrentTable->HostClipRect;
+
+        // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect?
         scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max);
         return scope_rect;
     }

From dab63231d888f4a39c4d5729e14296c30cef2bc7 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 11:19:05 +0200
Subject: [PATCH 129/136] Misc: Made it accepted to call SetMouseCursor() with
 any out-of-bound value, as a way to allow hacking in custom cursors if
 desirable.

---
 docs/CHANGELOG.txt |  2 ++
 imgui.cpp          | 10 +++++++---
 imgui_demo.cpp     |  3 ++-
 imgui_tables.cpp   |  2 +-
 imgui_widgets.cpp  |  2 +-
 5 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 903af40c3..b91d55530 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -70,6 +70,8 @@ Other changes:
   (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build).
   This is the first step toward more refactorig. (#7925) [@alektron, @ocornut]
 - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow.
+- Misc: Made it accepted to call SetMouseCursor() with any out-of-bound value, as a way to allow
+  hacking in custom cursors if desirable.
 - Fonts: fixed ellipsis "..." rendering width miscalculation bug introduced in 1.91.0. (#7976) [@DDeimos]
 - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660)
 - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam]
diff --git a/imgui.cpp b/imgui.cpp
index 59a918e86..bdeda3fe7 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -3702,7 +3702,8 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl
 void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
 {
     ImGuiContext& g = *GImGui;
-    IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
+    if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values.
+        mouse_cursor = ImGuiMouseCursor_Arrow;
     ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
     for (ImGuiViewportP* viewport : g.Viewports)
     {
@@ -6198,7 +6199,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
         ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
         //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
         if (hovered || held)
-            g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
+            SetMouseCursor((resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE);
 
         if (held && g.IO.MouseDoubleClicked[0])
         {
@@ -6244,7 +6245,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
         if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER)
             hovered = false;
         if (hovered || held)
-            g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
+            SetMouseCursor((axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS);
         if (held && g.IO.MouseDoubleClicked[0])
         {
             // Double-clicking bottom or right border auto-fit on this axis
@@ -9296,6 +9297,9 @@ ImGuiMouseCursor ImGui::GetMouseCursor()
     return g.MouseCursor;
 }
 
+// We intentionally accept values of ImGuiMouseCursor that are outside our bounds, in case users needs to hack-in a custom cursor value.
+// Custom cursors may be handled by custom backends. If you are using a standard backend and want to hack in a custom cursor, you may
+// handle it before the backend _NewFrame() call and temporarily set ImGuiConfigFlags_NoMouseCursorChange during the backend _NewFrame() call.
 void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
 {
     ImGuiContext& g = *GImGui;
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 8c9745dfb..cc21099a8 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -7490,7 +7490,8 @@ static void ShowDemoWindowInputs()
             IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
 
             ImGuiMouseCursor current = ImGui::GetMouseCursor();
-            ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
+            const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
+            ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
             ImGui::BeginDisabled(true);
             ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
             ImGui::EndDisabled();
diff --git a/imgui_tables.cpp b/imgui_tables.cpp
index f247ed6d3..9a6e06a2d 100644
--- a/imgui_tables.cpp
+++ b/imgui_tables.cpp
@@ -4409,7 +4409,7 @@ void ImGui::EndColumns()
             {
                 ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
                 if (hovered || held)
-                    g.MouseCursor = ImGuiMouseCursor_ResizeEW;
+                    SetMouseCursor(ImGuiMouseCursor_ResizeEW);
                 if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize))
                     dragging_column = n;
             }
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 14c5af3e4..3576d31fa 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -4438,7 +4438,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     }
     const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
     if (hovered)
-        g.MouseCursor = ImGuiMouseCursor_TextInput;
+        SetMouseCursor(ImGuiMouseCursor_TextInput);
 
     // We are only allowed to access the state if we are already the active widget.
     ImGuiInputTextState* state = GetInputTextState(id);

From 510b6adc9bb0cfea012f513e358f3df962fe91b7 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 12:09:02 +0200
Subject: [PATCH 130/136] CI: disable month-long PVS Studio warning about
 expiring licence.

---
 .github/workflows/static-analysis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 69df5cdf8..99b058c91 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -42,5 +42,5 @@ jobs:
           fi
           cd examples/example_null
           pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
-          pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
+          pvs-studio-analyzer analyze --disableLicenseExpirationCheck -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
           plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log

From b53d91a4c40b69ec1d7e95e44863c8c921ed2f11 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 14:15:43 +0200
Subject: [PATCH 131/136] InputText: optimization for large text: using
 memchr() instead of strchr() shaves 0.2 ms on 865k multi-line text case.
 Approximately 20%. (#7925)

---
 docs/CHANGELOG.txt | 2 +-
 imgui_widgets.cpp  | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index b91d55530..069b60388 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -68,7 +68,7 @@ Other changes:
 - InputText: internal refactoring to simplify and optimize the code. The ImWchar buffer has been
   removed. Simplifications allowed to implement new optimizations for handling very large text buffers
   (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build).
-  This is the first step toward more refactorig. (#7925) [@alektron, @ocornut]
+  This is the first step toward more refactoring. (#7925) [@alektron, @ocornut]
 - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow.
 - Misc: Made it accepted to call SetMouseCursor() with any out-of-bound value, as a way to allow
   hacking in custom cursors if desirable.
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 3576d31fa..64156b40d 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -5095,6 +5095,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
         // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
         const char* text_begin = state->TextA.Data;
+        const char* text_end = text_begin + state->CurLenA;
         ImVec2 cursor_offset, select_start_offset;
 
         {
@@ -5119,7 +5120,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
             searches_remaining += is_multiline ? 1 : 0;
             int line_count = 0;
-            for (const char* s = text_begin; (s = strchr(s, '\n')) != NULL; s++) // FIXME-OPT: memchr() would be faster?
+            for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
             {
                 line_count++;
                 if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }

From aef07aea27472b9a678967404d06ea7ab6d71fb9 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 14:36:25 +0200
Subject: [PATCH 132/136] InputText: minor tidying up of selection search loop
 (no need to imply it runs in single line mode)

---
 imgui_widgets.cpp | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 64156b40d..26f617806 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -5100,33 +5100,30 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
 
         {
             // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
-            const char* searches_input_ptr[2] = { NULL, NULL };
             int searches_result_line_no[2] = { -1000, -1000 };
-            int searches_remaining = 0;
+            const char* searches_input_ptr[2] = { NULL, NULL };
             if (render_cursor)
             {
                 searches_input_ptr[0] = text_begin + state->Stb->cursor;
                 searches_result_line_no[0] = -1;
-                searches_remaining++;
             }
             if (render_selection)
             {
                 searches_input_ptr[1] = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end);
                 searches_result_line_no[1] = -1;
-                searches_remaining++;
             }
 
-            // Iterate all lines to find our line numbers
-            // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
-            searches_remaining += is_multiline ? 1 : 0;
-            int line_count = 0;
-            for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
+            // Count lines and find line number for cursor and selection ends
+            int line_count = 1;
+            if (is_multiline)
             {
-                line_count++;
-                if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
-                if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
+                for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
+                {
+                    if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; }
+                    if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; }
+                    line_count++;
+                }
             }
-            line_count++;
             if (searches_result_line_no[0] == -1)
                 searches_result_line_no[0] = line_count;
             if (searches_result_line_no[1] == -1)

From 7ac50bf77d08aaf569acc00feacd7eb44785f241 Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 14:42:58 +0200
Subject: [PATCH 133/136] InputText: more tidying up of selection search loop.

---
 imgui_widgets.cpp | 40 ++++++++++++++++------------------------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 26f617806..c5ee2734a 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -5099,19 +5099,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         ImVec2 cursor_offset, select_start_offset;
 
         {
-            // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
-            int searches_result_line_no[2] = { -1000, -1000 };
-            const char* searches_input_ptr[2] = { NULL, NULL };
-            if (render_cursor)
-            {
-                searches_input_ptr[0] = text_begin + state->Stb->cursor;
-                searches_result_line_no[0] = -1;
-            }
-            if (render_selection)
-            {
-                searches_input_ptr[1] = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end);
-                searches_result_line_no[1] = -1;
-            }
+            // Find lines numbers straddling cursor and selection min position
+            int cursor_line_no = render_cursor ? -1 : -1000;
+            int selmin_line_no = render_selection ? -1 : -1000;
+            const char* cursor_ptr = render_cursor ? text_begin + state->Stb->cursor : NULL;
+            const char* selmin_ptr = render_selection ? text_begin + ImMin(state->Stb->select_start, state->Stb->select_end) : NULL;
 
             // Count lines and find line number for cursor and selection ends
             int line_count = 1;
@@ -5119,23 +5111,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             {
                 for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
                 {
-                    if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; }
-                    if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; }
+                    if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; }
+                    if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; }
                     line_count++;
                 }
             }
-            if (searches_result_line_no[0] == -1)
-                searches_result_line_no[0] = line_count;
-            if (searches_result_line_no[1] == -1)
-                searches_result_line_no[1] = line_count;
+            if (cursor_line_no == -1)
+                cursor_line_no = line_count;
+            if (selmin_line_no == -1)
+                selmin_line_no = line_count;
 
             // Calculate 2d position by finding the beginning of the line and measuring distance
-            cursor_offset.x = InputTextCalcTextSize(&g, ImStrbol(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
-            cursor_offset.y = searches_result_line_no[0] * g.FontSize;
-            if (searches_result_line_no[1] >= 0)
+            cursor_offset.x = InputTextCalcTextSize(&g, ImStrbol(cursor_ptr, text_begin), cursor_ptr).x;
+            cursor_offset.y = cursor_line_no * g.FontSize;
+            if (selmin_line_no >= 0)
             {
-                select_start_offset.x = InputTextCalcTextSize(&g, ImStrbol(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
-                select_start_offset.y = searches_result_line_no[1] * g.FontSize;
+                select_start_offset.x = InputTextCalcTextSize(&g, ImStrbol(selmin_ptr, text_begin), selmin_ptr).x;
+                select_start_offset.y = selmin_line_no * g.FontSize;
             }
 
             // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)

From 4925695ae882f628d149ebcc8bd17471dd2c3efb Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 14:52:42 +0200
Subject: [PATCH 134/136] InputText: optimize
 InputTextCalcTextLenAndLineCount() for inactive multiline path. (#7925)

---
 imgui_widgets.cpp | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index c5ee2734a..4156ce8af 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -3822,16 +3822,22 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, si
     return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);
 }
 
+// This is only used in the path where the multiline widget is inactivate.
 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
 {
     int line_count = 0;
     const char* s = text_begin;
-    while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
-        if (c == '\n')
-            line_count++;
-    s--;
-    if (s[0] != '\n' && s[0] != '\r')
+    while (true)
+    {
+        const char* s_eol = strchr(s, '\n');
         line_count++;
+        if (s_eol == NULL)
+        {
+            s = s + strlen(s);
+            break;
+        }
+        s = s_eol + 1;
+    }
     *out_text_end = s;
     return line_count;
 }

From 1ac162f2b083819663fe12b7217c40abdaf501cb Mon Sep 17 00:00:00 2001
From: Aaron C Gaudette 
Date: Mon, 16 Sep 2024 16:07:02 +0200
Subject: [PATCH 135/136] Backends: WGPU: add
 IMGUI_IMPL_WEBGPU_BACKEND_DAWN/IMGUI_IMPL_WEBGPU_BACKEND_WGPU to support more
 targets. (#7977, #7969, #6602, #6188, #7523)

---
 backends/imgui_impl_wgpu.cpp              | 29 +++++++++++++++++++++++
 backends/imgui_impl_wgpu.h                |  7 ++++++
 docs/CHANGELOG.txt                        |  2 ++
 examples/example_glfw_wgpu/CMakeLists.txt |  5 ++++
 4 files changed, 43 insertions(+)

diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp
index bf741e1a4..503ac8efd 100644
--- a/backends/imgui_impl_wgpu.cpp
+++ b/backends/imgui_impl_wgpu.cpp
@@ -16,6 +16,7 @@
 
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
+//  2024-09-16: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU define to handle ever-changing native implementations. (#7977)
 //  2024-01-22: Added configurable PipelineMultisampleState struct. (#7240)
 //  2024-01-22: (Breaking) ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes.
 //  2024-01-22: Fixed pipeline layout leak. (#7245)
@@ -35,6 +36,18 @@
 //  2021-02-18: Change blending equation to preserve alpha in output buffer.
 //  2021-01-28: Initial version.
 
+// When targeting native platforms (i.e. NOT emscripten), one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN
+// or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details.
+#ifndef __EMSCRIPTEN__
+    #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
+    #error exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined!
+    #endif
+#else
+    #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
+    #error neither IMGUI_IMPL_WEBGPU_BACKEND_DAWN nor IMGUI_IMPL_WEBGPU_BACKEND_WGPU may be defined if targeting emscripten!
+    #endif
+#endif
+
 #include "imgui.h"
 #ifndef IMGUI_DISABLE
 #include "imgui_impl_wgpu.h"
@@ -245,7 +258,11 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c
     ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
 
     WGPUShaderModuleWGSLDescriptor wgsl_desc = {};
+#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN
+    wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
+#else
     wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
+#endif
     wgsl_desc.code = wgsl_source;
 
     WGPUShaderModuleDescriptor desc = {};
@@ -660,7 +677,11 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
     // Create depth-stencil State
     WGPUDepthStencilState depth_stencil_state = {};
     depth_stencil_state.format = bd->depthStencilFormat;
+#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN
+    depth_stencil_state.depthWriteEnabled = WGPUOptionalBool_False;
+#else
     depth_stencil_state.depthWriteEnabled = false;
+#endif
     depth_stencil_state.depthCompare = WGPUCompareFunction_Always;
     depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always;
     depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep;
@@ -730,7 +751,15 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
     // Setup backend capabilities flags
     ImGui_ImplWGPU_Data* bd = IM_NEW(ImGui_ImplWGPU_Data)();
     io.BackendRendererUserData = (void*)bd;
+#if defined(__EMSCRIPTEN__)
+    io.BackendRendererName = "imgui_impl_webgpu_emscripten";
+#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
+    io.BackendRendererName = "imgui_impl_webgpu_dawn";
+#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
+    io.BackendRendererName = "imgui_impl_webgpu_wgpu";
+#else
     io.BackendRendererName = "imgui_impl_webgpu";
+#endif
     io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
 
     bd->initInfo = *init_info;
diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h
index 87d9580bf..e6835dee9 100644
--- a/backends/imgui_impl_wgpu.h
+++ b/backends/imgui_impl_wgpu.h
@@ -2,6 +2,13 @@
 // This needs to be used along with a Platform Binding (e.g. GLFW)
 // (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
 
+// Important note to dawn and/or wgpu users: when targeting native platforms (i.e. NOT emscripten),
+// one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided.
+// Add #define to your imconfig.h file, or as a compilation flag in your build system.
+// This requirement will be removed once WebGPU stabilizes and backends converge on a unified interface.
+//#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
+//#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU
+
 // Implemented features:
 //  [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
 //  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 069b60388..95df895c4 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -77,6 +77,8 @@ Other changes:
 - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam]
 - Backends: GLFW+Emscripten: use OSX behaviors automatically when using contrib glfw port. (#7965, #7915)
   [@ypujante]
+- Backends: WebGPU: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU
+  defines to handle ever-changing native implementations. (#7977, #7969, #6602, #6188, #7523) [@acgaudette]
 
 -----------------------------------------------------------------------
  VERSION 1.91.1 (Released 2024-09-04)
diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt
index 6be95af44..8e164e488 100644
--- a/examples/example_glfw_wgpu/CMakeLists.txt
+++ b/examples/example_glfw_wgpu/CMakeLists.txt
@@ -79,6 +79,11 @@ add_executable(example_glfw_wgpu
   ${IMGUI_DIR}/imgui_tables.cpp
   ${IMGUI_DIR}/imgui_widgets.cpp
 )
+IF(NOT EMSCRIPTEN)
+  target_compile_definitions(example_glfw_wgpu PUBLIC
+    "IMGUI_IMPL_WEBGPU_BACKEND_DAWN"
+  )
+endif()
 target_include_directories(example_glfw_wgpu PUBLIC
   ${IMGUI_DIR}
   ${IMGUI_DIR}/backends

From 08b1496b7e566eecf1b870bce1eed57522c6593c Mon Sep 17 00:00:00 2001
From: ocornut 
Date: Mon, 16 Sep 2024 17:22:31 +0200
Subject: [PATCH 136/136] Backends: Win32: fixed an issue where a viewport
 destroyed while clicking would hog mouse tracking and temporary lead to
 incorrect update of HoveredWindow. (#7971)

# Conflicts:
#	backends/imgui_impl_win32.cpp
#	docs/CHANGELOG.txt
---
 backends/imgui_impl_win32.cpp | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp
index 0e48d8636..758e70d01 100644
--- a/backends/imgui_impl_win32.cpp
+++ b/backends/imgui_impl_win32.cpp
@@ -107,7 +107,7 @@ struct ImGui_ImplWin32_Data
 {
     HWND                        hWnd;
     HWND                        MouseHwnd;
-    int                         MouseTrackedArea;   // 0: not tracked, 1: client are, 2: non-client area
+    int                         MouseTrackedArea;   // 0: not tracked, 1: client area, 2: non-client area
     int                         MouseButtonsDown;
     INT64                       Time;
     INT64                       TicksPerSecond;
@@ -629,6 +629,16 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
         }
         return 0;
     }
+    case WM_DESTROY:
+        if (bd->MouseHwnd == hwnd && bd->MouseTrackedArea != 0)
+        {
+            TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 };
+            ::TrackMouseEvent(&tme_cancel);
+            bd->MouseHwnd = nullptr;
+            bd->MouseTrackedArea = 0;
+            io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+        }
+        return 0;
     case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
     case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
     case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: