From 650eca386e985c06d55ffac43291d76ca5af7fa6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Feb 2026 20:14:25 +0100 Subject: [PATCH 01/19] Doc: update link to imgui_manual, add a new one near top of the demo + update binaries. --- docs/FAQ.md | 1 + docs/README.md | 5 ++--- imgui.cpp | 6 ++++-- imgui.h | 2 +- imgui_demo.cpp | 5 ++++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 6c9526aa7..12e47c72c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -55,6 +55,7 @@ or view this file with any Markdown viewer. - Handy [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide to integrate Dear ImGui in an existing application. - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder to explain how to integrate Dear ImGui with your own engine/application. You can run those applications and explore them. - See demo code in [imgui_demo.cpp](https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp) and particularly the `ImGui::ShowDemoWindow()` function. The demo covers most features of Dear ImGui, so you can read the code and see its output. +- See pthom's online [imgui_manual](https://pthom.github.io/imgui_manual) which is a web version of the demo with a source code browser. - See documentation: [Backends](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md), [Examples](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md), [Fonts](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). - See documentation and comments at the top of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) + general API comments in [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h). - The [Glossary](https://github.com/ocornut/imgui/wiki/Glossary) page may be useful. diff --git a/docs/README.md b/docs/README.md index 4f090545a..fe8f3e975 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,11 +110,10 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG ### Demo Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. -- [Web version of the demo](https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html) courtesy of [@pthom](https://github.com/pthom). -- [Screenshot of the demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). +- [Web version of the demo](https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html) w/ source code browser, courtesy of [@pthom](https://github.com/pthom). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20250625.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20250625.zip) (Windows, 1.92.0, built 2025/06/25, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20260225.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20260225.zip) (Windows, 1.92.6, built 2026/02/25, master) or [older binaries](https://www.dearimgui.com/binaries). ### Gallery diff --git a/imgui.cpp b/imgui.cpp index fddbff78e..baefdddce 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -20,7 +20,7 @@ // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser) +// - Web version of the Demo .... https://pthom.github.io/imgui_manual (w/ source code browser) // For FIRST-TIME users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. @@ -207,7 +207,7 @@ CODE The UI can be highly dynamic, there are no construction or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version. + Or browse https://pthom.github.io/imgui_manual for a web version w/ source code browser. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. @@ -1101,6 +1101,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - Run the examples/ applications and explore them. - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. + - See pthom's online imgui_manual (https://pthom.github.io/imgui_manual) which is a web + version of the demo with a source code browser. - The demo covers most features of Dear ImGui, so you can read the code and see its output. - See documentation and comments at the top of imgui.cpp + effectively imgui.h. - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the diff --git a/imgui.h b/imgui.h index f038f68f6..1bc641c48 100644 --- a/imgui.h +++ b/imgui.h @@ -20,7 +20,7 @@ // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser) +// - Web version of the Demo .... https://pthom.github.io/imgui_manual (w/ source code browser) // For FIRST-TIME users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5112f4ac9..346e9dfd7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -12,7 +12,7 @@ // How to easily locate code? // - 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 +// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual // - Find a visible string and search for it in the code! //--------------------------------------------------- @@ -443,6 +443,9 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); + ImGui::BulletText("Web demo (w/ source code browser): "); + ImGui::SameLine(0, 0); + ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_manual"); ImGui::SeparatorText("PROGRAMMER GUIDE:"); ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); From c40226e9de0d96b04578c4720d00f240785d3846 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Feb 2026 22:10:41 +0100 Subject: [PATCH 02/19] CloseButton, InputText: scale thickness to integer amount when using style.ScaleAllSizes(). (#7031) --- docs/CHANGELOG.txt | 9 ++++++++- imgui_widgets.cpp | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8af53f4df..f018f33e3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,7 +60,14 @@ Other Changes: - InputText: - Shift+Enter in multi-line editor always adds a new line, regardless of ImGuiInputTextFlags_CtrlEnterForNewLine being set or not. (#9239) -- Style: border sizes are now scaled (and rounded) by ScaleAllSizes(). +- Style: + - Border sizes are now scaled (and rounded) by ScaleAllSizes(). + - When using large values with ScallAllSizes(), the following items thickness + are scaled to integer amounts: + - InputText Caret/cursor thickness. (#7031) + - CloseButton() thickness. + - TextLink() underline thickness. + - ColorButton() border. - Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Clipper: - Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 775375ecf..6998929df 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -919,7 +919,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) const ImU32 cross_col = GetColorU32(ImGuiCol_Text); const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; - const float cross_thickness = 1.0f; // FIXME-DPI + const float cross_thickness = 1.0f * (float)(int)g.Style._MainScale; // FIXME-DPI window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness); @@ -1529,7 +1529,7 @@ bool ImGui::TextLink(const char* label) } float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f); - window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI + window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); RenderText(bb.Min, label, label_end); @@ -5566,7 +5566,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031) // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) // This is required for some backends (SDL3) to start emitting character/text inputs. @@ -6424,7 +6424,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border // FIXME-DPI + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding, 0, 1.0f * (float)(int)g.Style._MainScale); // Color buttons are often in need of some sort of border // FIXME-DPI } // Drag and Drop Source From ef022c5e0a6f68aa12196d5ea4b102c63f4a0c8e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Feb 2026 17:21:57 +0100 Subject: [PATCH 03/19] Separator: added and following style.SeparatorSize. (#2657, #9263) Reapply c5d83d8a from 1.70 which was reverted in 9534ef9b2. --- docs/CHANGELOG.txt | 15 ++++++++++++++- imgui.cpp | 19 ++++++++++++++++--- imgui.h | 4 +++- imgui_demo.cpp | 4 +++- imgui_widgets.cpp | 11 +++++++---- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f018f33e3..59f268ff0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,18 @@ HOW TO UPDATE? Breaking Changes: + - Separator(): fixed a legacy quirk where Separator() was submitting a zero-height + item for layout purpose, even though it draws a 1-pixel separator. + The fix could affect code e.g. computing height from multiple widgets in order to + allocate vertical space for a footer or multi-line status bar. (#2657, #9263) + The "Console" example had such a bug: + float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + Should be: + float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + When such idiom was used and assuming zero-height Separator, it is likely that + in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range. - Combo(), ListBox(): commented out legacy signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed from: getter type: bool (*getter)(void* user_data, int idx, const char** out_text) @@ -67,7 +79,8 @@ Other Changes: - InputText Caret/cursor thickness. (#7031) - CloseButton() thickness. - TextLink() underline thickness. - - ColorButton() border. + - ColorButton() border thickness. + - Separator() thickness, via scaling newly added style.SeparatorSize. (#2657, #9263) - Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Clipper: - Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false. diff --git a/imgui.cpp b/imgui.cpp index baefdddce..0c793234a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -394,7 +394,17 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: 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. - - 2026/02/27 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed. + - 2026/02/26 (1.92.7) - Separator: fixed a legacy quirk where Separator() was submitting a zero-height item for layout purpose, even though it draws a 1-pixel separator. + The fix could affect code e.g. computing height from multiple widgets in order to allocate vertical space for a footer or multi-line status bar. (#2657, #9263) + The "Console" example had such a bug: + float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + Should be: + float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + When such idiom was used and assuming zero-height Separator, it is likely that + in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range. + - 2026/02/23 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed. - Old getter type: bool (*getter)(void* user_data, int idx, const char** out_text) // Set label + return bool. False replaced label with placeholder. - New getter type: const char* (*getter)(void* user_data, int idx) // Return label or NULL/empty label if missing - 2026/01/08 (1.92.6) - Commented out legacy names obsoleted in 1.90 (Sept 2023): 'BeginChildFrame()' --> 'BeginChild()' with 'ImGuiChildFlags_FrameStyle'. 'EndChildFrame()' --> 'EndChild()'. 'ShowStackToolWindow()' --> 'ShowIDStackToolWindow()'. 'IM_OFFSETOF()' --> 'offsetof()'. @@ -1499,7 +1509,8 @@ ImGuiStyle::ImGuiStyle() 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; // Thickness of border in SeparatorText() + SeparatorSize = 1.0f; // Thickness of border in Separator(). + 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. @@ -1572,8 +1583,9 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) DragDropTargetBorderSize = ImTrunc(DragDropTargetBorderSize * scale_factor); DragDropTargetPadding = ImTrunc(DragDropTargetPadding * scale_factor); ColorMarkerSize = ImTrunc(ColorMarkerSize * scale_factor); - SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); + SeparatorSize = ImTrunc(SeparatorSize * scale_factor); SeparatorTextBorderSize = ImTrunc(SeparatorTextBorderSize * scale_factor); + SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImTrunc(MouseCursorScale * scale_factor); @@ -3636,6 +3648,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorSize)}, // ImGuiStyleVar_SeparatorSize { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding diff --git a/imgui.h b/imgui.h index 1bc641c48..594dc8204 100644 --- a/imgui.h +++ b/imgui.h @@ -30,7 +30,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.7 WIP" -#define IMGUI_VERSION_NUM 19263 +#define IMGUI_VERSION_NUM 19264 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -1852,6 +1852,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorSize, // float SeparatorSize ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding @@ -2331,6 +2332,7 @@ struct ImGuiStyle 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 SeparatorSize; // Thickness of border in Separator() 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. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 346e9dfd7..813feee23 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8507,6 +8507,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + SliderFloat("SeparatorSize", &style.SeparatorSize, 0.0f, 10.0f, "%.0f"); SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); @@ -8975,7 +8976,8 @@ struct ExampleAppConsole ImGui::Separator(); // Reserve enough left-over height for 1 separator + 1 input text - const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + ImGuiStyle& style = ImGui::GetStyle(); + const float footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar)) { if (ImGui::BeginPopupContextWindow()) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6998929df..07639a08f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1664,9 +1664,13 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) // We don't provide our width to the layout so that it doesn't get feed back into AutoFit // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) - const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + + // Between 1.71 and 1.92.7, we maintained a hack where a 1.0f thin Separator() would not impact layout. + // This was mostly chosen to allow backward compatibility with user's code assuming zero-height when calculating height for layout (e.g. bottom alignment of a status bar). + // In order to handle scaling we need to scale separator thickness and it would not makes sense to have a disparity depending on height. + ////float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); - ItemSize(ImVec2(0.0f, thickness_for_layout)); + ItemSize(ImVec2(0.0f, thickness)); if (ItemAdd(bb, 0)) { @@ -1692,14 +1696,13 @@ void ImGui::Separator() return; // Those flags should eventually be configurable by the user - // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; // Only applies to legacy Columns() api as they relied on Separator() a lot. if (window->DC.CurrentColumns) flags |= ImGuiSeparatorFlags_SpanAllColumns; - SeparatorEx(flags, 1.0f); + SeparatorEx(flags, g.Style.SeparatorSize); } void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) From 14e0c70f8825d4ca15031eb78c9fb4b47f5fbbb9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Feb 2026 18:34:23 +0100 Subject: [PATCH 04/19] Sliders: removed unnecessary is_logarithmic parameters as they can be inferred. (#3786, #1823, #1316, #642) --- imgui_demo.cpp | 2 +- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 813feee23..7499aa8d6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10003,7 +10003,7 @@ static void ShowExampleAppWindowTitles(bool*) ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##2"); - IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2");; + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2"); ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); ImGui::End(); diff --git a/imgui_internal.h b/imgui_internal.h index 78457fbb8..9fe84ddb4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3661,8 +3661,8 @@ namespace ImGui // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " - template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); - template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size); template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 07639a08f..44f6f4f60 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2564,9 +2564,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); // Convert to parametric space, apply delta, convert back - float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); float v_new_parametric = v_old_parametric + g.DragCurrentAccum; - v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); v_old_ref_for_accum_remainder = v_old_parametric; } else @@ -2583,7 +2583,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (is_logarithmic) { // Convert to parametric space, apply delta, convert back - float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); } else @@ -2933,14 +2933,14 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ // Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) template -float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) return 0.0f; IM_UNUSED(data_type); const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); - if (is_logarithmic) + if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller { bool flipped = v_max < v_min; @@ -2990,7 +2990,7 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T // Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) template -TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. @@ -3000,7 +3000,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T return v_max; TYPE result = (TYPE)0; - if (is_logarithmic) + if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller { // Fudge min/max to avoid getting silly results close to zero FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; @@ -3105,7 +3105,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const float mouse_abs_pos = g.IO.MousePos[axis]; if (g.ActiveIdIsJustActivated) { - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -3160,7 +3160,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } else if (g.SliderCurrentAccumDirty) { - clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits { @@ -3174,10 +3174,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ clicked_t = ImSaturate(clicked_t + delta); // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) v_new = RoundScalarWithFormatT(format, data_type, v_new); - float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (delta > 0) g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); @@ -3195,7 +3195,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ if (set_new_value) { - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); // Round to user desired precision based on format string if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) @@ -3217,7 +3217,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { // Output grab position so it can be displayed by the caller - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); From 238651ffa34f03ce23b429a9ddf371af99cdaa05 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Feb 2026 23:50:40 +0100 Subject: [PATCH 05/19] Sliders: shallow rework of TempInputScalar(). Toward #9164, #76 --- imgui_widgets.cpp | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 44f6f4f60..c7aea144b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3710,29 +3710,28 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; g.LastItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a new item, so we poke LastItemData. - bool value_changed = false; - if (TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags)) + if (!TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags)) + return false; + + // Backup old value + size_t data_type_size = type_info->Size; + ImGuiDataTypeStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL); + if (p_clamp_min || p_clamp_max) { - // Backup old value - size_t data_type_size = type_info->Size; - ImGuiDataTypeStorage data_backup; - memcpy(&data_backup, p_data, data_type_size); - - // Apply new value (or operations) then clamp - DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL); - if (p_clamp_min || p_clamp_max) - { - if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) - ImSwap(p_clamp_min, p_clamp_max); - DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); - } - - // Only mark as edited if new value is different - g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; - value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; - if (value_changed) - MarkItemEdited(id); + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + ImSwap(p_clamp_min, p_clamp_max); + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); } + + // Only mark as edited if new value is different + g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; + bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); return value_changed; } From 11acd9f5cb469890c3915e36f8b8ea702add3c95 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Feb 2026 23:38:16 +0100 Subject: [PATCH 06/19] Sliders: extracted code into TempInputIsClampEnabled() helper for reuse. Toward #9164, #76 --- imgui_widgets.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c7aea144b..f1837920c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2659,6 +2659,20 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v return false; } +// Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) +static bool TempInputIsClampEnabled(ImGuiSliderFlags flags, ImGuiDataType data_type, const void* p_min, const void* p_max) +{ + if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) + { + const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? ImGui::DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max + if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) + return true; + if (clamp_range_dir == 0) + return ImGui::DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; + } + return false; +}; + // Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. // Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) @@ -2724,16 +2738,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (temp_input_is_active) { - // Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - bool clamp_enabled = false; - if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) - { - const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max - if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) - clamp_enabled = true; - else if (clamp_range_dir == 0) - clamp_enabled = DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; - } + const bool clamp_enabled = TempInputIsClampEnabled(flags, data_type, p_min, p_max); return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); } @@ -3325,7 +3330,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (temp_input_is_active) { // Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; + const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; // Don't use TempInputIsClampEnabled() return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); } From ba84d2d37253c89b17b2cb7b357e130093b79ef5 Mon Sep 17 00:00:00 2001 From: Simon <42865234+SimonMaracine@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:48:30 +0200 Subject: [PATCH 07/19] Fixed -Wconversion warnings in GCC. (#9265) --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 9fe84ddb4..0d229e6c2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -534,7 +534,7 @@ inline float ImLinearSweep(float current, float target, float speed) { if (cu inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; } inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } -inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / n; avg += sample / n; return avg; } +inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / (float)n; avg += sample / (float)n; return avg; } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry From 41765fbda723d23e04e98afec40447d149d02ec8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Mar 2026 18:03:27 +0100 Subject: [PATCH 08/19] Scrollbar: extend hit-testing bounding box when window is sitting at the edge of a viewport. (#9276) --- docs/CHANGELOG.txt | 6 +++++- imgui_internal.h | 1 + imgui_widgets.cpp | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 59f268ff0..062b1bc90 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,11 +81,15 @@ Other Changes: - TextLink() underline thickness. - ColorButton() border thickness. - Separator() thickness, via scaling newly added style.SeparatorSize. (#2657, #9263) -- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Clipper: - Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false. - Added `UserIndex` helper storage. This is solely a convenience for cases where you may want to carry an index around. +- Scrollbar: + - Implemented a custom tweak to extend hit-testing bounding box when window is sitting + at the edge of a viewport (e.g. fullscreen or docked window), so that e.g. mouse the + mouse at the extreme of the screen will reach the scrollbar. (#9276) +- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Backends: - SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) [@jaenis] diff --git a/imgui_internal.h b/imgui_internal.h index 0d229e6c2..ee9847393 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3643,6 +3643,7 @@ namespace ImGui IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); + IMGUI_API void ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis); // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f1837920c..97e297caa 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -974,6 +974,16 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); } +void ImGui::ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis) +{ + ImRect window_rect = window->RootWindow->Rect(); + ImRect viewport_rect = window->Viewport->GetMainRect(); + if (window_rect.Min[axis] == viewport_rect.Min[axis] && bb->Min[axis] > window_rect.Min[axis] && bb->Min[axis] - threshold <= window_rect.Min[axis]) + bb->Min[axis] = window_rect.Min[axis]; + if (window_rect.Max[axis] == viewport_rect.Max[axis] && bb->Max[axis] < window_rect.Max[axis] && bb->Max[axis] + threshold >= window_rect.Max[axis]) + bb->Max[axis] = window_rect.Max[axis]; +} + void ImGui::Scrollbar(ImGuiAxis axis) { ImGuiContext& g = *GImGui; @@ -1035,11 +1045,15 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + // As a special thing, we allow scrollbar near the edge of a screen/viewport to be reachable with mouse at the extreme edge (#9276) + ImRect bb_hit = bb_frame; + ExtendHitBoxWhenNearViewportEdge(window, &bb_hit, g.Style.WindowBorderSize, (ImGuiAxis)(axis ^ 1)); + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). bool held = false; bool hovered = false; ItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav); - ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + ButtonBehavior(bb_hit, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_visible_v); float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); From ca166c0e5fe955dab06116411654cfc52596d185 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2026 14:24:03 +0100 Subject: [PATCH 09/19] Docs: imgui_manual -> imgui_explorer. Amend 650eca3. --- docs/FAQ.md | 2 +- docs/README.md | 2 +- imgui.cpp | 6 +++--- imgui_demo.cpp | 6 +++--- imgui_internal.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 12e47c72c..05dd777b3 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -55,7 +55,7 @@ or view this file with any Markdown viewer. - Handy [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide to integrate Dear ImGui in an existing application. - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder to explain how to integrate Dear ImGui with your own engine/application. You can run those applications and explore them. - See demo code in [imgui_demo.cpp](https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp) and particularly the `ImGui::ShowDemoWindow()` function. The demo covers most features of Dear ImGui, so you can read the code and see its output. -- See pthom's online [imgui_manual](https://pthom.github.io/imgui_manual) which is a web version of the demo with a source code browser. +- See pthom's online [imgui_explorer](https://pthom.github.io/imgui_explorer) which is a web version of the demo with a source code browser. - See documentation: [Backends](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md), [Examples](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md), [Fonts](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). - See documentation and comments at the top of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) + general API comments in [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h). - The [Glossary](https://github.com/ocornut/imgui/wiki/Glossary) page may be useful. diff --git a/docs/README.md b/docs/README.md index fe8f3e975..a409b9301 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,7 +110,7 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG ### Demo Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. -- [Web version of the demo](https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html) w/ source code browser, courtesy of [@pthom](https://github.com/pthom). +- [imgui_explorer](https://pthom.github.io/imgui_explorer): Web version of the demo w/ source code browser, courtesy of [@pthom](https://github.com/pthom). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: - [imgui-demo-binaries-20260225.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20260225.zip) (Windows, 1.92.6, built 2026/02/25, master) or [older binaries](https://www.dearimgui.com/binaries). diff --git a/imgui.cpp b/imgui.cpp index 0c793234a..354db305d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -20,7 +20,7 @@ // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// - Web version of the Demo .... https://pthom.github.io/imgui_manual (w/ source code browser) +// - Web version of the Demo .... https://pthom.github.io/imgui_explorer (w/ source code browser) // For FIRST-TIME users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. @@ -207,7 +207,7 @@ CODE The UI can be highly dynamic, there are no construction or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - Or browse https://pthom.github.io/imgui_manual for a web version w/ source code browser. + Or browse pthom's online imgui_explorer: https://pthom.github.io/imgui_explorer for a web version w/ source code browser. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. @@ -1111,7 +1111,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - Run the examples/ applications and explore them. - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. - - See pthom's online imgui_manual (https://pthom.github.io/imgui_manual) which is a web + - See pthom's online imgui_explorer (https://pthom.github.io/imgui_explorer) which is a web version of the demo with a source code browser. - The demo covers most features of Dear ImGui, so you can read the code and see its output. - See documentation and comments at the top of imgui.cpp + effectively imgui.h. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7499aa8d6..5f1e69d60 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -12,7 +12,7 @@ // How to easily locate code? // - 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 +// - Browse pthom's online imgui_explorer: web version the demo w/ source code browser: https://pthom.github.io/imgui_explorer // - Find a visible string and search for it in the code! //--------------------------------------------------- @@ -282,7 +282,7 @@ static void HelpMarker(const char* desc) } } -// Helper to wire demo markers located in code to an interactive browser (e.g. imgui_manual) +// Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) #if IMGUI_VERSION_NUM >= 19263 namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); }; #define IMGUI_DEMO_MARKER(section) do { ImGui::DemoMarker("imgui_demo.cpp", __LINE__, section); } while (0) @@ -445,7 +445,7 @@ void ImGui::ShowDemoWindow(bool* p_open) "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); ImGui::BulletText("Web demo (w/ source code browser): "); ImGui::SameLine(0, 0); - ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_manual"); + ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_explorer"); ImGui::SeparatorText("PROGRAMMER GUIDE:"); ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); diff --git a/imgui_internal.h b/imgui_internal.h index ee9847393..1aa4b416e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3717,7 +3717,7 @@ namespace ImGui IMGUI_API bool BeginErrorTooltip(); IMGUI_API void EndErrorTooltip(); - // Demo Doc Marker for e.g. imgui_manual + // Demo Doc Marker for e.g. imgui_explorer IMGUI_API void DemoMarker(const char* file, int line, const char* section); // Debug Tools From 6f8bdb7bf71055efdfed8b88d45899df3e834ef4 Mon Sep 17 00:00:00 2001 From: Brenton Bostick Date: Mon, 9 Mar 2026 09:51:06 -0400 Subject: [PATCH 10/19] Docs: fixed misc typos (#9267) --- imgui.cpp | 18 +++++++++--------- imgui.h | 2 +- imgui_draw.cpp | 4 ++-- imgui_internal.h | 2 +- imstb_rectpack.h | 4 ++-- imstb_truetype.h | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 354db305d..f3b0c7b5f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3519,7 +3519,7 @@ bool ImGuiListClipper::Step() return ret; } -// Generic helper, equivalent to old ImGui::CalcListClipping() but statelesss +// Generic helper, equivalent to old ImGui::CalcListClipping() but stateless void ImGui::CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end) { *out_visible_start = ImMax((int)((clip_rect.Min.y - pos.y) / items_height), 0); @@ -5886,7 +5886,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 ImDrawList* draw_list = window->RootWindow->DrawList; if (draw_list->CmdBuffer.Size == 0) draw_list->AddDrawCmd(); - draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to strictly ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); ImDrawCmd cmd = draw_list->CmdBuffer.back(); IM_ASSERT(cmd.ElemCount == 6); @@ -12277,15 +12277,15 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to // - Each popups may contain child windows, which is why we compare ->RootWindow! // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child // We step through every popup from bottom to top to validate their position relative to reference window. - bool ref_window_is_descendent_of_popup = false; + bool ref_window_is_descendant_of_popup = false; for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) if (IsWindowWithinBeginStackOf(ref_window, popup_window)) { - ref_window_is_descendent_of_popup = true; + ref_window_is_descendant_of_popup = true; break; } - if (!ref_window_is_descendent_of_popup) + if (!ref_window_is_descendant_of_popup) break; } } @@ -14751,7 +14751,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() // We build a throwaway ID based on current ID stack + relative AABB of items in window. - // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); @@ -17367,7 +17367,7 @@ void ImGui::DebugNodeFont(ImFont* font) src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); } - DebugNodeFontGlyphesForSrcMask(font, baked, ~0); + DebugNodeFontGlyphsForSrcMask(font, baked, ~0); TreePop(); } PopID(); @@ -17376,7 +17376,7 @@ void ImGui::DebugNodeFont(ImFont* font) Unindent(); } -void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask) +void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask) { ImDrawList* draw_list = GetWindowDrawList(); const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); @@ -18147,7 +18147,7 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeFont(ImFont*) {} -void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont*, ImFontBaked*, int) {} +void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont*, ImFontBaked*, int) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} diff --git a/imgui.h b/imgui.h index 594dc8204..eca23ac18 100644 --- a/imgui.h +++ b/imgui.h @@ -3644,7 +3644,7 @@ enum ImFontAtlasFlags_ // - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. // Common pitfalls: -// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persists up until the // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 19209fed7..3a15fcd75 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3203,7 +3203,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); if (font_cfg.Name[0] == '\0') { - // Store a short copy of filename into into the font name for convenience + // Store a short copy of filename into the font name for convenience const char* p; for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "%s", p); @@ -3211,7 +3211,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); } -// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +// NB: Transfer ownership of 'font_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); diff --git a/imgui_internal.h b/imgui_internal.h index 1aa4b416e..0de97ac2b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3739,7 +3739,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); - IMGUI_API void DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); + IMGUI_API void DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture. IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); diff --git a/imstb_rectpack.h b/imstb_rectpack.h index f6917e7a6..ad0892130 100644 --- a/imstb_rectpack.h +++ b/imstb_rectpack.h @@ -315,7 +315,7 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0 if (node->y > min_y) { // raise min_y higher. // we've accounted for all waste up to min_y, - // but we'll now add more waste for everything we've visted + // but we'll now add more waste for everything we've visited waste_area += visited_width * (node->y - min_y); min_y = node->y; // the first time through, visited_width might be reduced @@ -470,7 +470,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i // insert the new node into the right starting point, and // let 'cur' point to the remaining nodes needing to be - // stiched back in + // stitched back in cur = *res.prev_link; if (cur->x < res.x) { diff --git a/imstb_truetype.h b/imstb_truetype.h index cf33289f6..ec4d42c7d 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -886,7 +886,7 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// the same as stbtt_GetCodepointBitmap, but you can specify a subpixel // shift for the character STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); From e92820db2ab0776337b9b22816994acf56c0c776 Mon Sep 17 00:00:00 2001 From: Yan Pujante Date: Thu, 5 Mar 2026 09:33:21 -0800 Subject: [PATCH 11/19] Backends, Examples: removed Emscripten < 4.0.10 support. Removed IMGUI_IMPL_WEBGPU_BACKEND_WGPU. (#9281, #8381) - This commit removes the option of using -sUSE_WEBGPU=1 from CMake and make - Compiling with a version of Emscripten >= 4.0.10 will work the same way as it was before - Compiling with a version of Emscripten < 4.0.10 will print an error message and abort the build (in the case of CMake) - Since there can only be 1 implementation for the backend in the case of Emscripten, this commit cleans the code accordingly --- backends/imgui_impl_wgpu.cpp | 48 ------------------- backends/imgui_impl_wgpu.h | 13 ----- examples/example_glfw_wgpu/CMakeLists.txt | 29 ++++------- .../example_glfw_wgpu/Makefile.emscripten | 6 +-- examples/example_glfw_wgpu/README.md | 7 +-- examples/example_glfw_wgpu/main.cpp | 3 -- examples/example_sdl2_wgpu/CMakeLists.txt | 24 +++------- .../example_sdl2_wgpu/Makefile.emscripten | 6 +-- examples/example_sdl2_wgpu/README.md | 7 +-- examples/example_sdl2_wgpu/main.cpp | 3 -- examples/example_sdl3_wgpu/CMakeLists.txt | 23 ++------- .../example_sdl3_wgpu/Makefile.emscripten | 6 +-- examples/example_sdl3_wgpu/README.md | 7 +-- examples/example_sdl3_wgpu/main.cpp | 3 -- 14 files changed, 24 insertions(+), 161 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index e98e9f3ca..a01bcf4f1 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -59,12 +59,6 @@ #error Exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined! #endif -// This condition is true when it's built with EMSCRIPTEN using -sUSE_WEBGPU=1 flag (deprecated from 4.0.10) -// This condition is false for all other 3 cases: WGPU-Native, DAWN-Native or DAWN-EMSCRIPTEN (using --use-port=emdawnwebgpu flag) -#if defined(__EMSCRIPTEN__) && defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN -#endif - #ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN // Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413) // Using type alias until WGPU adopts the same naming convention (#8369) @@ -261,15 +255,9 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; -#else - WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; - wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = wgsl_source; -#endif WGPUShaderModuleDescriptor desc = {}; desc.nextInChain = (WGPUChainedStruct*)&wgsl_desc; @@ -277,11 +265,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c WGPUProgrammableStageDescriptor stage_desc = {}; stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) stage_desc.entryPoint = { "main", WGPU_STRLEN }; -#else - stage_desc.entryPoint = "main"; -#endif return stage_desc; } @@ -400,11 +384,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder WGPUBufferDescriptor vb_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Vertex buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Vertex buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, MEMALIGN(fr->VertexBufferSize * sizeof(ImDrawVert), 4), false @@ -428,11 +408,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder WGPUBufferDescriptor ib_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Index buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Index buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, MEMALIGN(fr->IndexBufferSize * sizeof(ImDrawIdx), 4), false @@ -564,11 +540,7 @@ void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) // Create texture WGPUTextureDescriptor tex_desc = {}; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) tex_desc.label = { "Dear ImGui Texture", WGPU_STRLEN }; -#else - tex_desc.label = "Dear ImGui Texture"; -#endif tex_desc.dimension = WGPUTextureDimension_2D; tex_desc.size.width = tex->Width; tex_desc.size.height = tex->Height; @@ -609,20 +581,12 @@ void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUTexelCopyTextureInfo dst_view = {}; -#else - WGPUImageCopyTexture dst_view = {}; -#endif dst_view.texture = backend_tex->Texture; dst_view.mipLevel = 0; dst_view.origin = { (uint32_t)upload_x, (uint32_t)upload_y, 0 }; dst_view.aspect = WGPUTextureAspect_All; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUTexelCopyBufferLayout layout = {}; -#else - WGPUTextureDataLayout layout = {}; -#endif layout.offset = 0; layout.bytesPerRow = tex->Width * tex->BytesPerPixel; layout.rowsPerImage = upload_h; @@ -640,11 +604,7 @@ static void ImGui_ImplWGPU_CreateUniformBuffer() WGPUBufferDescriptor ub_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Uniform buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Uniform buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, MEMALIGN(sizeof(Uniforms), 16), false @@ -756,11 +716,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Create depth-stencil State WGPUDepthStencilState depth_stencil_state = {}; depth_stencil_state.format = bd->depthStencilFormat; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) 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; @@ -845,11 +801,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) io.BackendRendererName = "imgui_impl_wgpu (Dawn, Native)"; #endif #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#if defined(__EMSCRIPTEN__) - io.BackendRendererName = "imgui_impl_wgpu (WGPU, Emscripten)"; // linked using EMSCRIPTEN with "-sUSE_WEBGPU=1" flag, deprecated from EMSCRIPTEN 4.0.10 -#else io.BackendRendererName = "imgui_impl_wgpu (WGPU, Native)"; -#endif #endif io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 1e026be99..b0fc99310 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -33,20 +33,7 @@ // Setup Emscripten default if not specified. #if defined(__EMSCRIPTEN__) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #include - -#ifdef __EMSCRIPTEN_MAJOR__ -#if (__EMSCRIPTEN_MAJOR__ >= 5) || ((__EMSCRIPTEN_MAJOR__ >= 4) && (__EMSCRIPTEN_MINOR__ >= 0) && (__EMSCRIPTEN_TINY__ >= 10)) #define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -#else -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU -#endif -#else -#if (__EMSCRIPTEN_major__ >= 4) && (__EMSCRIPTEN_minor__ >= 0) && (__EMSCRIPTEN_tiny__ >= 10) -#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -#else -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU -#endif -#endif #endif #include diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt index 86291f9e2..f1951cb5d 100644 --- a/examples/example_glfw_wgpu/CMakeLists.txt +++ b/examples/example_glfw_wgpu/CMakeLists.txt @@ -52,23 +52,15 @@ set(IMGUI_EXAMPLE_SOURCE_FILES ) if(EMSCRIPTEN) - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() + if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") + else() + message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") endif() - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.57") + if(NOT IMGUI_EMSCRIPTEN_GLFW3) + # Defaults to contrib.glfw3 because Emscripten version is > 3.1.57 set(IMGUI_EMSCRIPTEN_GLFW3 "--use-port=contrib.glfw3" CACHE STRING "Choose between --use-port=contrib.glfw3 and -sUSE_GLFW=3 for GLFW implementation (default to --use-port=contrib.glfw3)") - else() # cannot use contrib.glfw3 prior to 3.1.57 - set(IMGUI_EMSCRIPTEN_GLFW3 "-sUSE_GLFW=3" CACHE STRING "Use -sUSE_GLFW=3 for GLFW implementation" FORCE) endif() set(LIBRARIES glfw) @@ -165,7 +157,6 @@ endif() # In this example IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN defined -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU defined # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN defined # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU defined @@ -191,12 +182,8 @@ else() # Emscripten settings endif() message(STATUS "Using ${IMGUI_EMSCRIPTEN_GLFW3} GLFW implementation") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_link_options(${IMGUI_EXECUTABLE} PRIVATE diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten index 8fee2fc7c..6af61e738 100644 --- a/examples/example_glfw_wgpu/Makefile.emscripten +++ b/examples/example_glfw_wgpu/Makefile.emscripten @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_glfw_wgpu/README.md b/examples/example_glfw_wgpu/README.md index 04320d22c..cee6b8c72 100644 --- a/examples/example_glfw_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -60,12 +60,7 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index f77314bd6..eda424372 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -19,9 +19,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt index ae0d626a1..c2c45094d 100644 --- a/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/examples/example_sdl2_wgpu/CMakeLists.txt @@ -52,17 +52,10 @@ set(IMGUI_EXAMPLE_SOURCE_FILES ) if(EMSCRIPTEN) - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() + if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") + else() + message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") endif() add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) @@ -160,7 +153,6 @@ endif() # IMGUI_IMPL_WEBGPU_BACKEND_DAWN/WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled (+EMSCRIPTEN) -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled (+EMSCRIPTEN) # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled @@ -180,12 +172,8 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings else() # Emscripten settings set(CMAKE_EXECUTABLE_SUFFIX ".html") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "-sUSE_SDL=2") diff --git a/examples/example_sdl2_wgpu/Makefile.emscripten b/examples/example_sdl2_wgpu/Makefile.emscripten index 69bcb00e7..9c5533c21 100644 --- a/examples/example_sdl2_wgpu/Makefile.emscripten +++ b/examples/example_sdl2_wgpu/Makefile.emscripten @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_sdl2_wgpu/README.md b/examples/example_sdl2_wgpu/README.md index afba7b857..7c88cc622 100644 --- a/examples/example_sdl2_wgpu/README.md +++ b/examples/example_sdl2_wgpu/README.md @@ -60,12 +60,7 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index 66bd77015..413097abd 100644 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -18,9 +18,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt index 2f3d48f62..6e418821c 100644 --- a/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/examples/example_sdl3_wgpu/CMakeLists.txt @@ -55,18 +55,8 @@ if(EMSCRIPTEN) if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.15") message(FATAL_ERROR "Using Emscripten with SDL3 needs Emscripten version >= 4.0.15") endif() - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() - endif() + # emdawnwebgpu was introduced in 4.0.10 so, due to the prior requirement, this will work + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) else() # Native/Desktop build @@ -162,7 +152,6 @@ endif() # IMGUI_IMPL_WEBGPU_BACKEND_DAWN/WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled (+EMSCRIPTEN) -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled (+EMSCRIPTEN) # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled @@ -182,12 +171,8 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings else() # Emscripten settings set(CMAKE_EXECUTABLE_SUFFIX ".html") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "-sUSE_SDL=3") diff --git a/examples/example_sdl3_wgpu/Makefile.emscripten b/examples/example_sdl3_wgpu/Makefile.emscripten index 58639a1fd..ee2ef8c34 100644 --- a/examples/example_sdl3_wgpu/Makefile.emscripten +++ b/examples/example_sdl3_wgpu/Makefile.emscripten @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_sdl3_wgpu/README.md b/examples/example_sdl3_wgpu/README.md index 35857be9e..5c44df364 100644 --- a/examples/example_sdl3_wgpu/README.md +++ b/examples/example_sdl3_wgpu/README.md @@ -60,12 +60,7 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index aa67d3098..42b19b7c5 100644 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -20,9 +20,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif From 83fa0ae2634fad2b8303f5929ba049650bf94bc0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2026 15:46:46 +0100 Subject: [PATCH 12/19] Backends, Examples: removed Emscripten < 4.0.10 support. Removed IMGUI_IMPL_WEBGPU_BACKEND_WGPU. Amends. (#9281, #8381) --- backends/imgui_impl_wgpu.cpp | 4 ++++ backends/imgui_impl_wgpu.h | 5 +++-- docs/CHANGELOG.txt | 4 +++- examples/example_glfw_wgpu/README.md | 3 ++- examples/example_glfw_wgpu/main.cpp | 30 ---------------------------- examples/example_sdl2_wgpu/README.md | 3 ++- examples/example_sdl2_wgpu/main.cpp | 30 ---------------------------- examples/example_sdl3_wgpu/README.md | 3 ++- examples/example_sdl3_wgpu/main.cpp | 30 ---------------------------- 9 files changed, 16 insertions(+), 96 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index a01bcf4f1..2b7edb0ba 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) // 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. (#8465) @@ -58,6 +59,9 @@ #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 +#if defined(__EMSCRIPTEN__) && defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore. +#endif #ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN // Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413) diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index b0fc99310..346538a4b 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -5,7 +5,8 @@ // When targeting native platforms: // - One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU *must* be provided. // When targeting Emscripten: -// - We now defaults to IMGUI_IMPL_WEBGPU_BACKEND_DAWN is Emscripten version is 4.0.10+, which correspond to using Emscripten '--use-port=emdawnwebgpu'. +// - We now defaults to IMGUI_IMPL_WEBGPU_BACKEND_DAWN and requires Emscripten 4.0.10+, which correspond to using Emscripten '--use-port=emdawnwebgpu'. +// - Emscripten < 4.0.10 is not supported anymore (old '-sUSE_WEBGPU=1' option). // - We can still define IMGUI_IMPL_WEBGPU_BACKEND_WGPU to use Emscripten '-s USE_WEBGPU=1' which is marked as obsolete by Emscripten. // Add #define to your imconfig.h file, or as a compilation flag in your build system. // This requirement may be removed once WebGPU stabilizes and backends converge on a unified interface. @@ -96,7 +97,7 @@ const char* ImGui_ImplWGPU_GetAdapterTypeName(WGPUAdapterType type); #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type); const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type); -#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) +#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level); #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 062b1bc90..fba7c64ef 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -94,12 +94,14 @@ Other Changes: - SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) [@jaenis] - WebGPU: fixed version check for Emscripten 5.0.0+. + - WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante] - Examples: - Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it, the canvas was not focusable in the DOM, which in turn make some backends (e.g. pongasoft/emscripten-glfw) not receive focus loss events. (#9259) [@pthom] - - WGPU: fixed undefined behaviors in example code for requesting adapter + - WebGPU: fixed undefined behaviors in example code for requesting adapter and device. (#9246, #9256) [@r-lyeh] + - GLFW/SDL2/SDL3+WebGPU: removed suport for Emscripten <4.0.10. (#9281) [@ypujante] ----------------------------------------------------------------------- diff --git a/examples/example_glfw_wgpu/README.md b/examples/example_glfw_wgpu/README.md index cee6b8c72..c1c40a59f 100644 --- a/examples/example_glfw_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -60,9 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index eda424372..54dfc6908 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -341,17 +341,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -408,7 +397,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU bool InitWGPU(GLFWwindow* window) @@ -458,23 +446,6 @@ bool InitWGPU(GLFWwindow* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - IM_ASSERT(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -494,7 +465,6 @@ bool InitWGPU(GLFWwindow* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/examples/example_sdl2_wgpu/README.md b/examples/example_sdl2_wgpu/README.md index 7c88cc622..3a0f2a630 100644 --- a/examples/example_sdl2_wgpu/README.md +++ b/examples/example_sdl2_wgpu/README.md @@ -60,9 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index 413097abd..b4c1be965 100644 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -325,17 +325,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -392,7 +381,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU static bool InitWGPU(SDL_Window* window) @@ -443,23 +431,6 @@ static bool InitWGPU(SDL_Window* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - assert(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -479,7 +450,6 @@ static bool InitWGPU(SDL_Window* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/examples/example_sdl3_wgpu/README.md b/examples/example_sdl3_wgpu/README.md index 5c44df364..c7d6aec7b 100644 --- a/examples/example_sdl3_wgpu/README.md +++ b/examples/example_sdl3_wgpu/README.md @@ -60,9 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported in ImGui) + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index 42b19b7c5..523d62156 100644 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -336,17 +336,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -403,7 +392,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU static bool InitWGPU(SDL_Window* window) @@ -454,23 +442,6 @@ static bool InitWGPU(SDL_Window* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - IM_ASSERT(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -490,7 +461,6 @@ static bool InitWGPU(SDL_Window* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; From 9e6b88862638e40d7915d6c45d0a1e40e7af1799 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2026 16:19:22 +0100 Subject: [PATCH 13/19] Examples: reorder builds items to favor main.cpp and backend failing earlier. --- examples/example_glfw_wgpu/Makefile.emscripten | 2 +- examples/example_sdl2_wgpu/Makefile.emscripten | 2 +- examples/example_sdl3_wgpu/Makefile.emscripten | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten index 6af61e738..ff386fec5 100644 --- a/examples/example_glfw_wgpu/Makefile.emscripten +++ b/examples/example_glfw_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = diff --git a/examples/example_sdl2_wgpu/Makefile.emscripten b/examples/example_sdl2_wgpu/Makefile.emscripten index 9c5533c21..ebc7f97c9 100644 --- a/examples/example_sdl2_wgpu/Makefile.emscripten +++ b/examples/example_sdl2_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = diff --git a/examples/example_sdl3_wgpu/Makefile.emscripten b/examples/example_sdl3_wgpu/Makefile.emscripten index ee2ef8c34..c84acc77f 100644 --- a/examples/example_sdl3_wgpu/Makefile.emscripten +++ b/examples/example_sdl3_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = From 512982d0d24c4240bbe8838fc8db879b684f3146 Mon Sep 17 00:00:00 2001 From: Yan Pujante Date: Thu, 5 Mar 2026 10:35:51 -0800 Subject: [PATCH 14/19] Examples: Emscripten: fixes minor rendering issues (#9281) - in Firefox, scrollbar would appear => adding overflow: hidden fixes this issue - when the canvas has the focus, Chrome draws a very small blue outline, setting it to none fixes this issue --- docs/CHANGELOG.txt | 3 +++ examples/libs/emscripten/shell_minimal.html | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fba7c64ef..7aac3883f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -99,6 +99,9 @@ Other Changes: - Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it, the canvas was not focusable in the DOM, which in turn make some backends (e.g. pongasoft/emscripten-glfw) not receive focus loss events. (#9259) [@pthom] + - Emscripten: fixed minor rendering issues with our HTML shell. (#9281) [@ypujante] + - hidden small blue outline when canvas is focused on Chrome. + - hidden scrollbar in Firefox. - WebGPU: fixed undefined behaviors in example code for requesting adapter and device. (#9246, #9256) [@r-lyeh] - GLFW/SDL2/SDL3+WebGPU: removed suport for Emscripten <4.0.10. (#9281) [@ypujante] diff --git a/examples/libs/emscripten/shell_minimal.html b/examples/libs/emscripten/shell_minimal.html index bcc5834a1..939dc1779 100644 --- a/examples/libs/emscripten/shell_minimal.html +++ b/examples/libs/emscripten/shell_minimal.html @@ -5,7 +5,7 @@ Dear ImGui Emscripten example From 5dd56d4bb5e0c0f0dbb317857157940188898853 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2026 17:59:49 +0100 Subject: [PATCH 15/19] Demo: add an option to enable ImGuiSliderFlags_ColorMarkers in Multi-Components section + fixed warnings. --- imgui_demo.cpp | 30 ++++++++++++++++-------------- imgui_widgets.cpp | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5f1e69d60..da8a78f81 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -284,7 +284,7 @@ static void HelpMarker(const char* desc) // Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) #if IMGUI_VERSION_NUM >= 19263 -namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); }; +namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); } #define IMGUI_DEMO_MARKER(section) do { ImGui::DemoMarker("imgui_demo.cpp", __LINE__, section); } while (0) #endif @@ -1726,7 +1726,6 @@ static void DemoWindowWidgetsDragsAndSliders() ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers); - //ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkersG", &flags, 1 << ImGuiSliderFlags_ColorMarkersIndexShift_); // Not explicitly documented but possible. // Drags static float drag_f = 0.5f; @@ -1942,29 +1941,32 @@ static void DemoWindowWidgetsMultiComponents() static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static int vec4i[4] = { 1, 5, 100, 255 }; + static ImGuiSliderFlags flags = 0; + ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers); // Only passing this to Drag/Sliders + ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); - ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::InputInt2("input int2", vec4i); - ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); - ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt2("slider int2", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("3-wide"); ImGui::InputFloat3("input float3", vec4f); - ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::InputInt3("input int3", vec4i); - ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); - ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt3("slider int3", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("4-wide"); ImGui::InputFloat4("input float4", vec4f); - ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); ImGui::InputInt4("input int4", vec4i); - ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); - ImGui::SliderInt4("slider int4", vec4i, 0, 255); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt4("slider int4", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("Ranges"); static float begin = 10, end = 90; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 97e297caa..cbb512634 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2685,7 +2685,7 @@ static bool TempInputIsClampEnabled(ImGuiSliderFlags flags, ImGuiDataType data_t return ImGui::DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; } return false; -}; +} // Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. // Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. From decb5cdf107031fe19129f42b3c09a899e243b88 Mon Sep 17 00:00:00 2001 From: MaciejDziuban Date: Sat, 31 Jan 2026 15:50:22 +0100 Subject: [PATCH 16/19] Backends: Vulkan: added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates. (#9211) This new setting allows an application to force the pipeline created by vulkan backend to specify more dynamic states than just default viewport and scissor. It is useful e.g. when using draw list callbacks, e.g. adding VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT to be able to use vkCmdSetColorBlendEquationEXT inside callbacks. --- backends/imgui_impl_vulkan.cpp | 9 ++++++--- backends/imgui_impl_vulkan.h | 1 + docs/CHANGELOG.txt | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index c3a304989..7bfd48a34 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-03-11: Vulkan: Added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying extra dynamic states to add when creating the VkPipeline. (#9211) // 2025-09-26: [Helpers] *BREAKING CHANGE*: Vulkan: Helper ImGui_ImplVulkanH_DestroyWindow() does not call vkDestroySurfaceKHR(): as surface is created by caller of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent that we don't destroy it. (#9163) // 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) // 2025-11-24: [Helpers] Vulkan: Helper for creating a swap-chain (used by examples and multi-viewports) selects VkSwapchainCreateInfoKHR's compositeAlpha based on cap.supportedCompositeAlpha. (#8784) @@ -1009,11 +1010,13 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; - VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + ImVector dynamic_states = info->ExtraDynamicStates; + dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); + dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state.dynamicStateCount = (uint32_t)IM_COUNTOF(dynamic_states); - dynamic_state.pDynamicStates = dynamic_states; + dynamic_state.dynamicStateCount = dynamic_states.Size; + dynamic_state.pDynamicStates = dynamic_states.Data; VkGraphicsPipelineCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 5b3baf00c..c3fef5105 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -86,6 +86,7 @@ struct ImGui_ImplVulkan_PipelineInfo VkRenderPass RenderPass; // Ignored if using dynamic rendering uint32_t Subpass; // VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT + ImVector ExtraDynamicStates; // Optional, allows to insert more dynamic states into our VkPipeline #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7aac3883f..ff03643cc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -102,6 +102,8 @@ Other Changes: - Emscripten: fixed minor rendering issues with our HTML shell. (#9281) [@ypujante] - hidden small blue outline when canvas is focused on Chrome. - hidden scrollbar in Firefox. + - Vulkan: added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying + extra dynamic states to add when creating the VkPipeline. (#9211) [@DziubanMaciej] - WebGPU: fixed undefined behaviors in example code for requesting adapter and device. (#9246, #9256) [@r-lyeh] - GLFW/SDL2/SDL3+WebGPU: removed suport for Emscripten <4.0.10. (#9281) [@ypujante] From 03a9946a1440b0061c8096d075d1df96ca77eb1c Mon Sep 17 00:00:00 2001 From: xttt Date: Wed, 11 Mar 2026 20:01:49 +0100 Subject: [PATCH 17/19] InputText: reworked so that io.ConfigInputTextEnterKeepActive reactivate in order for e.g. IsItemDeactivatedAfterEdit() to work. (#9001, #9115) --- imgui.cpp | 1 + imgui_internal.h | 1 + imgui_widgets.cpp | 12 +++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f3b0c7b5f..b88ff1d80 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4281,6 +4281,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseStationaryTimer = 0.0f; InputTextPasswordFontBackupFlags = ImFontFlags_None; + InputTextReactivateID = 0; TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; diff --git a/imgui_internal.h b/imgui_internal.h index 0de97ac2b..3cfac423f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2461,6 +2461,7 @@ struct ImGuiContext ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFontBaked InputTextPasswordFontBackupBaked; ImFontFlags InputTextPasswordFontBackupFlags; + ImGuiID InputTextReactivateID; // ID of InputText to reactivate on next frame (for ConfigInputTextEnterKeepActive behavior) ImGuiID TempInputId; // Temporary text input when using Ctrl+Click on a slider, etc. ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cbb512634..355b63a77 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4762,6 +4762,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); + // Check if this InputText should be reactivated (for ConfigInputTextEnterKeepActive) + const bool input_requested_by_reactivate = (g.InputTextReactivateID == id); + if (input_requested_by_reactivate) + g.InputTextReactivateID = 0; // Clear the flag + const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); @@ -4772,7 +4777,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); 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_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_reactivate); const bool init_state = (init_make_active || user_scroll_active); if (init_reload_from_user_buf) { @@ -5111,7 +5116,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { validated = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) + { + // Deactivate for one frame to trigger IsItemDeactivatedAfterEdit(), then reactivate state->SelectAll(); // No need to scroll + clear_active_id = true; + g.InputTextReactivateID = id; // Mark for reactivation on next frame + } else clear_active_id = true; } From 5aa7d61139b8857f413d72ada13618e0a9e9dc55 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Mar 2026 20:33:18 +0100 Subject: [PATCH 18/19] InputText: reworked so that io.ConfigInputTextEnterKeepActive reactivate in order for e.g. IsItemDeactivatedAfterEdit() to work. Amends. (#9001, #9115) Rework. Fixes dangling InputTextReactivateId in case of field being hidden on activation. --- imgui.cpp | 4 +++- imgui.h | 2 +- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 16 ++++------------ 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b88ff1d80..3638f6bfb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4281,7 +4281,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseStationaryTimer = 0.0f; InputTextPasswordFontBackupFlags = ImFontFlags_None; - InputTextReactivateID = 0; + InputTextReactivateId = 0; TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; @@ -5573,6 +5573,8 @@ void ImGui::NewFrame() g.ActiveIdIsJustActivated = false; if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) g.TempInputId = 0; + if (g.InputTextReactivateId != 0 && g.InputTextReactivateId != g.DeactivatedItemData.ID) + g.InputTextReactivateId = 0; if (g.ActiveId == 0) { g.ActiveIdUsingNavDirMask = 0x00; diff --git a/imgui.h b/imgui.h index eca23ac18..cc82c5f3d 100644 --- a/imgui.h +++ b/imgui.h @@ -2428,7 +2428,7 @@ struct ImGuiIO 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 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). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index da8a78f81..d7dc0b028 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -526,7 +526,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); diff --git a/imgui_internal.h b/imgui_internal.h index 3cfac423f..c54040747 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2461,7 +2461,7 @@ struct ImGuiContext ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFontBaked InputTextPasswordFontBackupBaked; ImFontFlags InputTextPasswordFontBackupFlags; - ImGuiID InputTextReactivateID; // ID of InputText to reactivate on next frame (for ConfigInputTextEnterKeepActive behavior) + ImGuiID InputTextReactivateId; // ID of InputText to reactivate on next frame (for io.ConfigInputTextEnterKeepActive behavior) ImGuiID TempInputId; // Temporary text input when using Ctrl+Click on a slider, etc. ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 355b63a77..78fae523b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4761,12 +4761,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); - - // Check if this InputText should be reactivated (for ConfigInputTextEnterKeepActive) - const bool input_requested_by_reactivate = (g.InputTextReactivateID == id); - if (input_requested_by_reactivate) - g.InputTextReactivateID = 0; // Clear the flag - + const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); @@ -5114,16 +5109,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool is_new_line = is_multiline && !is_gamepad_validate && (is_shift_enter || (is_enter && !ctrl_enter_for_new_line) || (is_ctrl_enter && ctrl_enter_for_new_line)); if (!is_new_line) { - validated = true; + validated = clear_active_id = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) { - // Deactivate for one frame to trigger IsItemDeactivatedAfterEdit(), then reactivate + // Queue reactivation, so that e.g. IsItemDeactivatedAfterEdit() will work. (#9001) state->SelectAll(); // No need to scroll - clear_active_id = true; - g.InputTextReactivateID = id; // Mark for reactivation on next frame + g.InputTextReactivateId = id; // Mark for reactivation on next frame } - else - clear_active_id = true; } else if (!is_readonly) { From 378cb85bf0810150b830b24b3f650fdfda5e7e1b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Mar 2026 21:02:46 +0100 Subject: [PATCH 19/19] Amend missing Changelog entry. (#9115) --- docs/CHANGELOG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff03643cc..176b7e6b6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,9 @@ Other Changes: - InputText: - Shift+Enter in multi-line editor always adds a new line, regardless of ImGuiInputTextFlags_CtrlEnterForNewLine being set or not. (#9239) + - Reworked io.ConfigInputTextEnterKeepActive mode so that pressing Enter will + deactivate/reactivate the item in order for e.g. IsItemDeactivatedAfterEdit() + signals to be emitted the same way regardless of that setting. (#9001, #9115) - Style: - Border sizes are now scaled (and rounded) by ScaleAllSizes(). - When using large values with ScallAllSizes(), the following items thickness