From d6d94d90bf84437c25013fdcc79373e2e114a5d8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Aug 2023 19:16:39 +0200 Subject: [PATCH 01/11] Version 1.89.9 WIP + Minor typo fixes --- docs/BACKENDS.md | 2 +- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 8 ++++---- imgui.h | 10 +++++----- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 6 +++--- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 8 ++++---- 9 files changed, 29 insertions(+), 20 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 2b4a4fbe6..e5aa79be1 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -63,7 +63,7 @@ List of Platforms Backends: imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org - imgui_impl_sdl3.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org (*EXPERIMENTAL*) + imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org (*EXPERIMENTAL UNTIL SDL3 IS RELEASED*) imgui_impl_win32.cpp ; Win32 native API (Windows) imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 54b3d950b..1341157a0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,6 +36,15 @@ HOW TO UPDATE? - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.89.9 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.89.8 (Released 2023-08-01) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 6e851dc14..18f6e6abf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (main code and documentation) // Help: @@ -4048,7 +4048,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return false; // Test if using AllowOverlap and overlapped - if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0) + if ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0) if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) if (g.HoveredIdPreviousFrame != g.LastItemData.ID) return false; @@ -4116,7 +4116,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test. - if (item_flags & ImGuiItemflags_AllowOverlap) + if (item_flags & ImGuiItemFlags_AllowOverlap) { g.HoveredIdAllowOverlap = true; if (g.HoveredIdPreviousFrame != id) @@ -5320,7 +5320,7 @@ bool ImGui::IsItemEdited() void ImGui::SetNextItemAllowOverlap() { ImGuiContext& g = *GImGui; - g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap; + g.NextItemData.ItemFlags |= ImGuiItemFlags_AllowOverlap; } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui.h b/imgui.h index 37601a5ee..5d9a457c3 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (headers) // Help: @@ -25,8 +25,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.89.8" -#define IMGUI_VERSION_NUM 18980 +#define IMGUI_VERSION "1.89.9 WIP" +#define IMGUI_VERSION_NUM 18981 #define IMGUI_HAS_TABLE /* @@ -356,8 +356,8 @@ namespace ImGui IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives - IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) - IMGUI_API ImVec2 GetWindowSize(); // get current window size + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetScreenCursorPos()) + IMGUI_API ImVec2 GetWindowSize(); // get current window size (note: it is unlikely you need to use this. Consider using GetScreenCursorPos() and e.g. GetContentRegionAvail() instead) IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b22c002f4..aaedc7c97 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 44371f824..db1bc1e89 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 4e35a2042..14d95d195 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. @@ -800,7 +800,7 @@ enum ImGuiItemFlags_ ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() - ImGuiItemflags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. + ImGuiItemFlags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -1178,7 +1178,7 @@ enum ImGuiNextItemDataFlags_ struct ImGuiNextItemData { ImGuiNextItemDataFlags Flags; - ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemflags_AllowOverlap. + ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap. float Width; // Set by SetNextItemWidth() ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) ImGuiCond OpenCond; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 598521598..64693858b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 251e965db..30928bb56 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.8 +// dear imgui, v1.89.9 WIP // (widgets code) /* @@ -492,7 +492,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (flags & ImGuiButtonFlags_AllowOverlap) - item_flags |= ImGuiItemflags_AllowOverlap; + item_flags |= ImGuiItemFlags_AllowOverlap; if (flags & ImGuiButtonFlags_Repeat) item_flags |= ImGuiItemFlags_ButtonRepeat; @@ -6176,7 +6176,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; - if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) + if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) button_flags |= ImGuiButtonFlags_AllowOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6506,7 +6506,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } const bool was_selected = selected; bool hovered, held; From b7a7d673b96f08b1e8a7195aa59307730bbf3c54 Mon Sep 17 00:00:00 2001 From: Johannes Barthelmes <615914+jbarthelmes@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:35:15 +0200 Subject: [PATCH 02/11] Fixed an integer overflow and div-by-zero in SliderInt() when v_max is INT_MAX (#6675, #6679) --- docs/CHANGELOG.txt | 3 +++ imgui_widgets.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1341157a0..bbfe8ae79 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,9 @@ Breaking changes: Other changes: +- Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when + v_max=INT_MAX (#6675, #6679) [@jbarthelmes] + ----------------------------------------------------------------------- VERSION 1.89.8 (Released 2023-08-01) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 30928bb56..67f1d0dd2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2772,14 +2772,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); - const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + const float v_range_f = (float)(v_min < v_max ? v_max - v_min : v_min - v_max); // We don't need high precision for what we do with it. // Calculate bounds const float grab_padding = 2.0f; // FIXME: Should be part of style. const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; float grab_sz = style.GrabMinSize; - if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows - grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + if (!is_floating_point && v_range_f >= 0.0f) // v_range_f < 0 may happen on integer overflows + grab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMin(grab_sz, slider_sz); const float slider_usable_sz = slider_sz - grab_sz; const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; @@ -2848,8 +2848,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } else { - if ((v_range >= -100.0f && v_range <= 100.0f) || tweak_slow) - input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + if ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow) + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Gamepad/keyboard tweak speeds in integer steps else input_delta /= 100.0f; } From c00e68102ce9a962a146306d918c7346fca873d6 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 Aug 2023 11:44:51 +0200 Subject: [PATCH 03/11] Docs: update CONTRIBUTING.md --- docs/CONTRIBUTING.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 26e82f514..7d6738dc9 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -12,26 +12,29 @@ - Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). - Please browse the [Wiki](https://github.com/ocornut/imgui/wiki) to find code snippets, links and other resources (e.g. [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started), [Useful extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions)). +- Please read [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) if your question relates to setting up Dear ImGui. - Please read [docs/FAQ.md](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md). - Please read [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) if your question relates to fonts or text. -- Please read one of the [examples/](https://github.com/ocornut/imgui/tree/master/examples) application if your question relates to setting up Dear ImGui. - Please run `ImGui::ShowDemoWindow()` to explore the demo and its sources. -- Please use the search function of your IDE to search in for comments related to your situation. -- Please use the search function of GitHub to look for similar issues. You may [browse issues by Labels](https://github.com/ocornut/imgui/labels). +- Please use the search function of your IDE to search for symbols and comments related to your situation. +- Please use the search function of GitHub to look for similar topics (always include 'Closed' issues/pr in your search). +- You may [browse issues by Labels](https://github.com/ocornut/imgui/labels). - Please use a web search engine to look for similar issues. - If you get a crash or assert, use a debugger to locate the line triggering it and read the comments around. - Please don't be a [Help Vampire](https://slash7.com/2006/12/22/vampires/). -## Issues vs Discussions +## 'Issues' vs 'Discussions' -If you: +We are happy to use 'Issues' for many type of open-ended questions. We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents. + +Only if you: - Cannot BUILD or LINK examples. - Cannot BUILD, or LINK, or RUN Dear ImGui in your application or custom engine. - Cannot LOAD a font. Then please [use the Discussions forums](https://github.com/ocornut/imgui/discussions) instead of opening an issue. -If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an issue. Any form of discussions is welcome as a new issue. +If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue. ## How to open an issue @@ -46,16 +49,16 @@ Steps: - Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). - **PLEASE DO FILL THE REQUESTED NEW ISSUE TEMPLATE.** Including Dear ImGui version number, branch name, platform/renderer back-ends (imgui_impl_XXX files), operating system. - **Try to be explicit with your GOALS, your EXPECTATIONS and what you have tried**. Be mindful of [The XY Problem](http://xyproblem.info/). What you have in mind or in your code is not obvious to other people. People frequently discuss problems and suggest incorrect solutions without first clarifying their goals. When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.). If you tried something and it failed, show us what you tried. +- **Please INCLUDE CODE. Provide a Minimal, Complete, and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem**. An ideal submission includes a small piece of code that anyone can paste into one of the examples applications (examples/../main.cpp) or demo (imgui_demo.cpp) to understand and reproduce it. **Narrowing your problem to its shortest and purest form is the easiest way to understand it, explain it and fix it**. Please test your shortened code to ensure it exhibits the problem. **Often while creating the MCVE you will solve the problem!** Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time. - **Attach screenshots (or GIF/video) to clarify the context**. They often convey useful information that is omitted by the description. You can drag pictures/files in the message edit box. Avoid using 3rd party image hosting services, prefer the long-term longevity of GitHub attachments (you can drag pictures into your post). On Windows, you can use [ScreenToGif](https://www.screentogif.com/) to easily capture .gif files. - **If you are discussing an assert or a crash, please provide a debugger callstack**. Never state "it crashes" without additional information. If you don't know how to use a debugger and retrieve a callstack, learning about it will be useful. - **Please make sure that your project has asserts enabled.** Calls to IM_ASSERT() are scattered in the code to help catch common issues. When an assert is triggered read the comments around it. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application doesn't report an error, your asserts are disabled. -- **Please provide a Minimal, Complete, and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem**. An ideal submission includes a small piece of code that anyone can paste into one of the examples applications (examples/../main.cpp) or demo (imgui_demo.cpp) to understand and reproduce it. Narrowing your problem to its shortest and purest form is the easiest way to understand it. Please test your shortened code to ensure it exhibits the problem. **Often while creating the MCVE you will end up solving the problem!** Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time. - Please state if you have made substantial modifications to your copy of Dear ImGui or the back-end. - If you are not calling Dear ImGui directly from C++, please provide information about your Language and the wrapper/binding you are using. - Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proofread your messages before sending them. Edits are not seen by those users unless they browse the site. **Some unfortunate words of warning** -- If you are involved in cheating schemes (e.g. DLL injection) for competitive online multiplayer games, please don't try posting here. We won't answer and you will be blocked. It doesn't matter if your question relates to said project. We've had too many of you and need to project our time and sanity. +- If you are involved in cheating schemes (e.g. DLL injection) for competitive online multiplayer games, please don't post here. We won't answer and you will be blocked. It doesn't matter if your question relates to said project. We've had too many of you and need to project our time and sanity. - Due to frequent abuse of this service from the aforementioned users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and incomplete questions will be harshly dismissed. If you have been using Dear ImGui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fulfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information is useful in a given context. @@ -63,15 +66,13 @@ If you have been using Dear ImGui for a while or have been using C/C++ for sever ## How to open a Pull Request - **Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance.** PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. -- Many PRs are useful to demonstrate a need and a possible solution but aren't adequate for merging (causing other issues, not seeing other aspects of the big picture, etc.). In doubt, don't hesitate to push a PR because that is always the first step toward finding the mergeable solution! Even if a PR stays unmerged for a long time, its presence can be useful for other users and helps toward finding a general solution. +- Many PRs are useful to demonstrate a need and a possible solution but aren't adequate for merging (causing other issues, not seeing other aspects of the big picture, etc.). In doubt, don't hesitate to push a PR because that is always the first step toward pointing toward a problem, and finding the mergeable solution! Even if a PR stays unmerged for a long time, its presence can be useful for other users and helps toward finding a general solution. - **When adding a feature,** please describe the usage context (how you intend to use it, why you need it, etc.). Be mindful of [The XY Problem](http://xyproblem.info/). - **When fixing a warning or compilation problem,** please post the compiler log and specify the compiler version and platform you are using. - **Attach screenshots (or GIF/video) to clarify the context and demonstrate the feature at a glance.** You can drag pictures/files in the message edit box. Prefer the long-term longevity of GitHub attachments over 3rd party hosting (you can drag pictures into your post). - **Make sure your code follows the coding style already used in the codebase:** 4 spaces indentations (no tabs), `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment();`, C-style casts, etc.. We don't use modern C++ idioms and tend to use only a minimum of C++11 features. The applications under examples/ are generally less consistent because they sometimes try to mimic the coding style often adopted by a certain ecosystem (e.g. DirectX-related code tend to use the style of their sample). - **Make sure you create a branch dedicated to the pull request**. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR (we can still cherry-pick individual commits). -Thank you for reading! - ## Copyright / Contributor License Agreement Any code you submit will become part of the repository and be distributed under the [Dear ImGui license](https://github.com/ocornut/imgui/blob/master/LICENSE.txt). By submitting code to the project you agree that the code is your work and that you can give it to the project. From f8c768760b0746aa7c1652397e2d9234c8502cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Kucsma?= Date: Fri, 4 Aug 2023 18:18:57 +0200 Subject: [PATCH 04/11] Typo fix: _NoHostExtenY -> _NoHostExtendY (#6687) --- imgui_tables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 64693858b..33927b8ad 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -82,7 +82,7 @@ Index of this file: // Y with ScrollX/ScrollY disabled: we output table directly in current window // - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll. // - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) -// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) +// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtendY is set) // Y with ScrollX/ScrollY enabled: using a child window for scrolling // - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll. // - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. From 52587c28d60a5113c3e716df4f10ba7adb85f639 Mon Sep 17 00:00:00 2001 From: EggsyCRO <39103865+EggsyCRO@users.noreply.github.com> Date: Thu, 27 Jul 2023 21:56:18 +0200 Subject: [PATCH 05/11] ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bbfe8ae79..ad5868f3f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,8 @@ Other changes: - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when v_max=INT_MAX (#6675, #6679) [@jbarthelmes] +- ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively + large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] ----------------------------------------------------------------------- diff --git a/imgui_draw.cpp b/imgui_draw.cpp index db1bc1e89..ffdb44138 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -561,7 +561,7 @@ int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const { // Automatic segment count const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy - if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) return _Data->CircleSegmentCounts[radius_idx]; // Use cached value else return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); From cf3726bcbce8d488044b4e46c380c8a83967260a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Aug 2023 19:46:27 +0200 Subject: [PATCH 06/11] Internals: rename bg/fg drawlist holders in structs to reduce confusion. --- imgui.cpp | 20 ++++++++++---------- imgui_internal.h | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 18f6e6abf..ba469efd6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4258,33 +4258,33 @@ int ImGui::GetFrameCount() return GImGui->FrameCount; } -static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) +static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) { // Create the draw list on demand, because they are not frequently used for all viewports ImGuiContext& g = *GImGui; - IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); - ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists)); + ImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no]; if (draw_list == NULL) { draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); draw_list->_OwnerName = drawlist_name; - viewport->DrawLists[drawlist_no] = draw_list; + viewport->BgFgDrawLists[drawlist_no] = draw_list; } // Our ImDrawList system requires that there is always a command - if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) + if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount) { draw_list->_ResetForNewFrame(); draw_list->PushTextureID(g.IO.Fonts->TexID); draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); - viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; + viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount; } return draw_list; } ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) { - return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); + return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background"); } ImDrawList* ImGui::GetBackgroundDrawList() @@ -4295,7 +4295,7 @@ ImDrawList* ImGui::GetBackgroundDrawList() ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) { - return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); + return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); } ImDrawList* ImGui::GetForegroundDrawList() @@ -5090,7 +5090,7 @@ void ImGui::Render() { ImGuiViewportP* viewport = g.Viewports[n]; InitViewportDrawData(viewport); - if (viewport->DrawLists[0] != NULL) + if (viewport->BgFgDrawLists[0] != NULL) AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); } @@ -5125,7 +5125,7 @@ void ImGui::Render() FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder); // Add foreground ImDrawList (for each active viewport) - if (viewport->DrawLists[1] != NULL) + if (viewport->BgFgDrawLists[1] != NULL) AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch). diff --git a/imgui_internal.h b/imgui_internal.h index 14d95d195..f328a0720 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1600,8 +1600,8 @@ struct ImGuiOldColumns // Every instance of ImGuiViewport is in fact a ImGuiViewportP. struct ImGuiViewportP : public ImGuiViewport { - int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used - ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + int BgFgDrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used + ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) @@ -1609,8 +1609,8 @@ struct ImGuiViewportP : public ImGuiViewport ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. - ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } - ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + ImGuiViewportP() { BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; } + ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } From 2b1fc6f7659f33994fc1201fabedf8c469cefa3c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Aug 2023 20:13:05 +0200 Subject: [PATCH 07/11] Demo: Demonstrate out-of-order rendering using ImDrawListSplitter. --- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- imgui_demo.cpp | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ad5868f3f..5eb96b358 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,7 @@ Other changes: v_max=INT_MAX (#6675, #6679) [@jbarthelmes] - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] +- Demo: Demonstrate out-of-order rendering using ImDrawListSplitter. ----------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 5d9a457c3..931a5d17e 100644 --- a/imgui.h +++ b/imgui.h @@ -2706,7 +2706,7 @@ struct ImDrawList // Advanced: Channels // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) - // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! + // - This API shouldn't have been in ImDrawList in the first place! // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index aaedc7c97..674d3e49b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7866,6 +7866,43 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::EndTabItem(); } + // Demonstrate out-of-order rendering via channels splitting + // We use functions in ImDrawList as each draw list contains a convenience splitter, + // but you can also instantiate your own ImDrawListSplitter if you need to nest them. + if (ImGui::BeginTabItem("Draw Channels")) + { + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + { + ImGui::Text("Blue shape is drawn first: appears in back"); + ImGui::Text("Red shape is drawn after: appears in front"); + ImVec2 p0 = ImGui::GetCursorScreenPos(); + draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue + draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red + ImGui::Dummy(ImVec2(75, 75)); + } + ImGui::Separator(); + { + ImGui::Text("Blue shape is drawn first, into channel 1: appears in front"); + ImGui::Text("Red shape is drawn after, into channel 0: appears in back"); + ImVec2 p1 = ImGui::GetCursorScreenPos(); + + // Create 2 channels and draw a Blue shape THEN a Red shape. + // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. + draw_list->ChannelsSplit(2); + draw_list->ChannelsSetCurrent(1); + draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue + draw_list->ChannelsSetCurrent(0); + draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red + + // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. + // This works by copying draw indices only (vertices are not copied). + draw_list->ChannelsMerge(); + ImGui::Dummy(ImVec2(75, 75)); + ImGui::Text("After reordering, contents of channel 0 appears below channel 1."); + } + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } From 226923fa7e9d73e28958a04884943318797d9991 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Aug 2023 20:30:07 +0200 Subject: [PATCH 08/11] Metrics: Fixed "Drawlists" section and per-viewport equivalent appearing empty (regression from c649aca). (#6597, #6475, #6167, #5776, #5109, #4763, #3515, #1860) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5eb96b358..f7e6ec1ef 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other changes: v_max=INT_MAX (#6675, #6679) [@jbarthelmes] - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] +- Debug Tools: Metrics: Fixed "Drawlists" section and per-viewport equivalent + appearing empty (regression in 1.89.8). - Demo: Demonstrate out-of-order rendering using ImDrawListSplitter. diff --git a/imgui.cpp b/imgui.cpp index ba469efd6..ca2a6777c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4566,10 +4566,7 @@ void ImGui::NewFrame() // Mark rendering data as invalid to prevent user who may have a handle on it to use it. for (int n = 0; n < g.Viewports.Size; n++) - { - ImGuiViewportP* viewport = g.Viewports[n]; - viewport->DrawDataP.Clear(); - } + g.Viewports[n]->DrawDataP.Valid = false; // Drag and drop keep the source ID alive so even if the source disappear our state is consistent if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) From 4d6fbaff11afbbc939c3e219a9c27f073e50a9ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Aug 2023 15:23:59 +0200 Subject: [PATCH 09/11] Demo: define standard PRI names we use (if missing) instead of defininig IM_PRId64, IM_PRIu64. --- imgui_demo.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 674d3e49b..d6ea23e90 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -95,6 +95,15 @@ Index of this file: #include // NULL, malloc, free, atoi #include // intptr_t +// Format specifiers for 64-bit values (hasn't been decently standardized since VS2013) +#if !defined(_MSC_VER) || _MSC_VER >= 1800 +#include +#elif !defined(PRId64) +#define PRId64 "I64d" +#define PRIu64 "I64u" +#define PRIX64 "I64X" +#endif + // Visual Studio warnings #ifdef _MSC_VER #pragma warning (disable: 4127) // condition expression is constant @@ -142,16 +151,6 @@ Index of this file: #define vsnprintf _vsnprintf #endif -// Format specifiers, printing 64-bit hasn't been decently standardized... -// In a real application you should be using PRId64 and PRIu64 from (non-windows) and on Windows define them yourself. -#ifdef _MSC_VER -#define IM_PRId64 "I64d" -#define IM_PRIu64 "I64u" -#else -#define IM_PRId64 "lld" -#define IM_PRIu64 "llu" -#endif - // Helpers macros // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, // but making an exception here as those are largely simplifying code... @@ -2144,12 +2143,12 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); - ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); - ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); - ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); - ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); - ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); - ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms"); ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); @@ -2162,8 +2161,8 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); - ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); - ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); + ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms"); IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; From edebb90a9aed16edd4e13e5e1c17ad36e66b6fce Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Aug 2023 18:25:56 +0200 Subject: [PATCH 10/11] Demo: amend/fix for MinGW Amend 4d6fbaf. --- imgui_demo.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d6ea23e90..1cc5331b1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -94,14 +94,8 @@ Index of this file: #include // vsnprintf, sscanf, printf #include // NULL, malloc, free, atoi #include // intptr_t - -// Format specifiers for 64-bit values (hasn't been decently standardized since VS2013) #if !defined(_MSC_VER) || _MSC_VER >= 1800 -#include -#elif !defined(PRId64) -#define PRId64 "I64d" -#define PRIu64 "I64u" -#define PRIX64 "I64X" +#include // PRId64/PRIu64, not avail in some MinGW headers. #endif // Visual Studio warnings @@ -151,6 +145,15 @@ Index of this file: #define vsnprintf _vsnprintf #endif +// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013) +#if !defined(PRId64) && defined(_MSC_VER) +#define PRId64 "I64d" +#define PRIu64 "I64u" +#elif !defined(PRId64) +#define PRId64 "lld" +#define PRIu64 "llu" +#endif + // Helpers macros // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, // but making an exception here as those are largely simplifying code... From bc3c0ce7728f39530020a979a19bfc176e4e8596 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 8 Aug 2023 14:03:58 +0200 Subject: [PATCH 11/11] Nav, TreeNode: Pressing Left with ImGuiTreeNodeFlags_NavLeftJumpsBackHere now goes through proper navigation logic: honor scrolling and selection. (#1079, #1131) Added a stack for this purpose which other features might build on (e.g. #2920). However this is currently gated by many tests and not a performance concern, but making stack happen all the time may be undesirable. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 14 ++++++++++++++ imgui.h | 2 +- imgui_internal.h | 14 ++++++++++++++ imgui_widgets.cpp | 39 ++++++++++++++++++++++++++------------- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f7e6ec1ef..fcf936dcb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Breaking changes: Other changes: +- Nav, TreeNode: Pressing Left with ImGuiTreeNodeFlags_NavLeftJumpsBackHere now goes + through proper navigation logic: honor scrolling and selection. (#1079, #1131) - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when v_max=INT_MAX (#6675, #6679) [@jbarthelmes] - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively diff --git a/imgui.cpp b/imgui.cpp index ca2a6777c..e53ecf890 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3653,6 +3653,7 @@ void ImGui::Shutdown() g.FontStack.clear(); g.OpenPopupStack.clear(); g.BeginPopupStack.clear(); + g.NavTreeNodeStack.clear(); g.Viewports.clear_delete(); @@ -11191,6 +11192,19 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) NavUpdateAnyRequestFlag(); } +// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere +void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data) +{ + ImGuiContext& g = *GImGui; + g.NavMoveScoringItems = false; + g.LastItemData.ID = tree_node_data->ID; + g.LastItemData.InFlags = tree_node_data->InFlags; + g.LastItemData.NavRect = tree_node_data->NavRect; + NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult() + NavClearPreferredPosForAxis(ImGuiAxis_Y); + NavUpdateAnyRequestFlag(); +} + void ImGui::NavMoveRequestCancel() { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 931a5d17e..26c55736e 100644 --- a/imgui.h +++ b/imgui.h @@ -26,7 +26,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.89.9 WIP" -#define IMGUI_VERSION_NUM 18981 +#define IMGUI_VERSION_NUM 18982 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index f328a0720..f10843a5f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -135,6 +135,7 @@ struct ImGuiLastItemData; // Status storage for last submitted items struct ImGuiLocEntry; // A localization entry. struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiNavTreeNodeData; // Temporary storage for last TreeNode() being a Left arrow landing candidate. struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions @@ -1201,6 +1202,16 @@ struct ImGuiLastItemData ImGuiLastItemData() { memset(this, 0, sizeof(*this)); } }; +// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere. +// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop() +// Only stored when the node is a potential candidate for landing on a Left arrow jump. +struct ImGuiNavTreeNodeData +{ + ImGuiID ID; + ImGuiItemFlags InFlags; + ImRect NavRect; +}; + struct IMGUI_API ImGuiStackSizes { short SizeOfIDStack; @@ -1865,6 +1876,8 @@ struct ImGuiContext ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + ImVector NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted. + int BeginMenuCount; // Viewports @@ -2930,6 +2943,7 @@ namespace ImGui IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); + IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data); IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 67f1d0dd2..e5b9c0610 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6155,18 +6155,29 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; - // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. - // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). - // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. - const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + // Compute open and multi-select states before ItemAdd() as it clear NextItem data. bool is_open = TreeNodeUpdateNextOpen(id, flags); - if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) - window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); - bool item_add = ItemAdd(interact_bb, id); g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; g.LastItemData.DisplayRect = frame_bb; + // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled: + // Store data for the current depth to allow returning to this node from any child item. + // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). + // It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle. + // Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase. + if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + { + g.NavTreeNodeStack.resize(g.NavTreeNodeStack.Size + 1); + ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back(); + nav_tree_node_data->ID = id; + nav_tree_node_data->InFlags = g.LastItemData.InFlags; + nav_tree_node_data->NavRect = g.LastItemData.NavRect; + window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); + } + + const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; if (!item_add) { if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) @@ -6336,12 +6347,14 @@ void ImGui::TreePop() ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) - if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) - if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) - { - SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); - NavMoveRequestCancel(); - } + if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request + { + ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back(); + IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back()); + if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, nav_tree_node_data); + g.NavTreeNodeStack.pop_back(); + } window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.