From 42f47590f983f489991f6ebfb72d2b32858cc270 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Oct 2024 19:13:04 +0200 Subject: [PATCH 01/21] Fixed ad37b79 breaking IsItemHovered()->IsItemFocused() passthrough for navigation. + Backends: comments. --- backends/imgui_impl_dx12.cpp | 1 + backends/imgui_impl_vulkan.cpp | 1 + imgui.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index e9345013c..be117b6c1 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -18,6 +18,7 @@ // (minor and older changes stripped away, please see git history for details) // 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. +// 2024-10-07: DirectX12: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index a68f862b1..4e4e332fc 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -28,6 +28,7 @@ // (minor and older changes stripped away, please see git history for details) // 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. +// 2024-10-07: Vulkan: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. // 2024-04-19: Vulkan: Added convenience support for Volk via IMGUI_IMPL_VULKAN_USE_VOLK define (you can also use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().) // 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. // 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. diff --git a/imgui.cpp b/imgui.cpp index 0ca2f4ab1..1cdf4383a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4445,7 +4445,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) { - if (g.LastItemData.ID == g.NavId && g.NavId != 0) // IsItemFocused() + if (!IsItemFocused()) return false; if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; From 50de550ecddf8569e4aaa5f45ab803da92fc5921 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Oct 2024 19:34:23 +0200 Subject: [PATCH 02/21] Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation (1.91.3 regression). (#8036) Regression in 1.91.3 commit 5109a77. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6a062c459..0ade98733 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,8 @@ Other changes: window. (#3200) - Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant when e.g activating the item with mouse, then ctrl+tabbing back and forth. +- Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation + (1.91.3 regression). (#8036) - DrawList: AddCallback() added an optional size parameter allowing to copy and store any amount of user data for usage by callbacks: (#6969, #4770, #7665) - If userdata_size == 0: we copy/store the 'userdata' argument as-is (existing behavior). diff --git a/imgui.cpp b/imgui.cpp index 1cdf4383a..3ce5e90db 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1199,6 +1199,7 @@ static bool NavScoreItem(ImGuiNavItemData* result); static void NavApplyItemToResult(ImGuiNavItemData* result); static void NavProcessItem(); static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); +static ImGuiInputSource NavCalcPreferredRefPosSource(); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); @@ -12177,14 +12178,14 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) const float scale = g.Style.MouseCursorScale; const ImVec2 ref_pos = NavCalcPreferredRefPos(); - if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen) + if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen && NavCalcPreferredRefPosSource() == ImGuiInputSource_Mouse) { - ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size); + ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size); if (r_outer.Contains(ImRect(tooltip_pos, tooltip_pos + window->Size))) return tooltip_pos; } - ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale; + ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale; ImRect r_avoid; if (!g.NavDisableHighlight && g.NavDisableMouseHover && !g.IO.ConfigNavMoveSetMousePos) r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); @@ -12779,7 +12780,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) } } -static ImVec2 ImGui::NavCalcPreferredRefPos() +static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; @@ -12787,6 +12788,21 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. if ((g.NavDisableHighlight || !g.NavDisableMouseHover || !window) && !activated_shortcut) + return ImGuiInputSource_Mouse; + else + return ImGuiInputSource_Keyboard; // or Nav in general +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + ImGuiInputSource source = NavCalcPreferredRefPosSource(); + + const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; + + // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. + if (source == ImGuiInputSource_Mouse) { // Mouse (we need a fallback in case the mouse becomes invalid after being used) // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard. From 49a9eee33f21bb4f67ffeaad7559a349d1687704 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Oct 2024 10:41:34 +0200 Subject: [PATCH 03/21] Commented out obsolete internals's SetItemUsingMouseWheel() (#2891), TreeNodeBehaviorIsOpen() (#4814, #5423, #282, #2958, #924) + Removed obsolete header checks for IMGUI_DISABLE_METRICS_WINDOW. --- imgui.h | 9 +++------ imgui_internal.h | 5 ++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 7d17aede6..2f9f18c2b 100644 --- a/imgui.h +++ b/imgui.h @@ -3616,8 +3616,8 @@ namespace ImGui //-- OBSOLETED in 1.89 (from August 2022) //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version. //-- OBSOLETED in 1.88 (from May 2022) - //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. - //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. + //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. + //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. //-- OBSOLETED in 1.86 (from November 2021) //IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for large list of evenly sized items. Prefer using ImGuiListClipper. //-- OBSOLETED in 1.85 (from August 2021) @@ -3700,10 +3700,7 @@ namespace ImGui #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) -#if defined(IMGUI_DISABLE_METRICS_WINDOW) && !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) -#define IMGUI_DISABLE_DEBUG_TOOLS -#endif -#if defined(IMGUI_DISABLE_METRICS_WINDOW) && defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) +#ifdef IMGUI_DISABLE_METRICS_WINDOW #error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. #endif diff --git a/imgui_internal.h b/imgui_internal.h index 5e378d669..f96e7091d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3478,9 +3478,8 @@ namespace ImGui // Obsolete functions #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 - inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 - + //inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 + //inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 //inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): From 971d243a872fbc50a654ed18d31a58f9152a294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DOTTEL=20Ga=C3=ABl?= Date: Tue, 15 Oct 2024 11:35:34 +0200 Subject: [PATCH 04/21] Fixed typo (#8063) --- docs/FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 38600fe47..8dde1967b 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -405,7 +405,7 @@ DirectX9: ``` ```cpp DirectX11: -- ImTextureID should contain a 'ID3D11ShaderResourceView*' (poiter) +- ImTextureID should contain a 'ID3D11ShaderResourceView*' (pointer) - See ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp ``` ```cpp From 67e5f3505d481519cf038aa9d054c5d0805a768d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Oct 2024 19:55:50 +0200 Subject: [PATCH 05/21] InvisibleButton: disable navigation properly + added ImGuiButtonFlags_EnableNav to enable navigation. (#8057) --- docs/CHANGELOG.txt | 5 ++++- imgui.h | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0ade98733..27b7dd780 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -73,7 +73,10 @@ Other changes: - Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most window. (#3200) - Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant - when e.g activating the item with mouse, then ctrl+tabbing back and forth. + when e.g activating the item with mouse, then Ctrl+Tabbing back and forth. +- InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but + not display navigation highlight. Properly navigation on it by default. (#8057) +- InvisibleButton: added ImGuiButtonFlags_EnableNav to enable navigation. (#8057) - Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation (1.91.3 regression). (#8036) - DrawList: AddCallback() added an optional size parameter allowing to copy and diff --git a/imgui.h b/imgui.h index 2f9f18c2b..ec5d572b9 100644 --- a/imgui.h +++ b/imgui.h @@ -1744,7 +1744,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, // [Internal] - //ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft, + ImGuiButtonFlags_EnableNav = 1 << 3, // InvisibleButton(): do not disable navigation/tabbing. Otherwise disabled by default. }; // Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() diff --git a/imgui_internal.h b/imgui_internal.h index f96e7091d..6e207d60e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -947,7 +947,7 @@ enum ImGuiSelectableFlagsPrivate_ enum ImGuiTreeNodeFlagsPrivate_ { ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader() - ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, but reversed trees (#6517) + ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, for reversed trees (#6517) ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow, }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2a7b1e9a8..1cd18c359 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -785,11 +785,12 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(size); - if (!ItemAdd(bb, id)) + if (!ItemAdd(bb, id, NULL, (flags & ImGuiButtonFlags_EnableNav) ? ImGuiItemFlags_None : ImGuiItemFlags_NoNav)) return false; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + RenderNavHighlight(bb, id); IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; From 83ecc846dc40645348d808c7119d1528e76c59a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Oct 2024 20:23:33 +0200 Subject: [PATCH 06/21] Disabled: clicking a disabled item focuses parent window. (#8064) --- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- imgui_widgets.cpp | 19 ++++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 27b7dd780..147e9f067 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,7 @@ Other changes: window. (#3200) - Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant when e.g activating the item with mouse, then Ctrl+Tabbing back and forth. +- Disabled: clicking a disabled item focuses parent window. (#8064) - InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but not display navigation highlight. Properly navigation on it by default. (#8057) - InvisibleButton: added ImGuiButtonFlags_EnableNav to enable navigation. (#8057) diff --git a/imgui.h b/imgui.h index ec5d572b9..ef0c59a9d 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.4 WIP" -#define IMGUI_VERSION_NUM 19134 +#define IMGUI_VERSION_NUM 19135 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1cd18c359..247fce39c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -542,7 +542,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Mouse handling const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; - if (hovered) + const bool hovered_disabled = (g.HoveredId == id && g.HoveredIdIsDisabled); + if (hovered || hovered_disabled) { IM_ASSERT(id != 0); // Lazily check inside rare path. @@ -559,7 +560,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } // Process initial action - if (!(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + const bool mods_ok = !(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt); + if (mods_ok && !hovered_disabled) { if (mouse_button_clicked != -1 && g.ActiveId != id) { @@ -606,7 +608,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) - SetFocusID(id, window); + SetFocusID(id, window); // FIXME: Lack of FocusWindow() call here is inconsistent with other paths. Research why. ClearActiveID(); } } @@ -617,6 +619,17 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, ImGuiInputFlags_Repeat, test_owner_id)) pressed = true; } + else if (mods_ok && hovered_disabled) + { + if (mouse_button_clicked != -1 && g.ActiveId != id) + { + // Disabled path still focus + // FIXME-NAV: Could somehow call SetNavID() with a null ID but mouse pos as NavRectRel so nav may be resumed? + // Will do it once we do it for regular click on window-void. + if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick)) + FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); + } + } if (pressed) g.NavDisableHighlight = true; From 04d9a0455702b376eec7074885bb722ad27171c0 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Thu, 8 Aug 2024 12:21:01 +0200 Subject: [PATCH 07/21] imgui_freetype: Added support for plutosvg to render OpenType SVG fonts. (#7927, #7187 + #6591, #6607) See #7927 for details. --- docs/CHANGELOG.txt | 4 ++++ imconfig.h | 9 ++++++--- misc/freetype/README.md | 26 ++++++++++++++++++++++---- misc/freetype/imgui_freetype.cpp | 24 +++++++++++++++++++----- misc/freetype/imgui_freetype.h | 7 +++++++ 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 147e9f067..5d61daa54 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,10 @@ Other changes: preventing use of external shortcuts not guarded by an ActiveId check. (#8048) [@geertbleyen] - InputText: ensure mouse cursor shape is set regardless of whether keyboard mode is enabled or not. (#6417) +- imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render + OpenType SVG fonts. Requires defining IMGUI_ENABLE_FREETYPE_PLUTOSVG along with IMGUI_ENABLE_FREETYPE. + Providing headers/librairies for plutosvg + plutovg is up to you (see #7927 for help). + (#7927, #7187, #6591, #6607) [@pthom] - Backends: DX11, DX12, SDLRenderer2/3. Vulkan, WGPU: expose selected state in ImGui_ImplXXXX_RenderState structures during render loop. (#6969, #5834, #7468, #3590) - Backends: DX9, DX10, DX11, DX12, OpenGL, Vulkan, WGPU: Changed default texture sampler diff --git a/imconfig.h b/imconfig.h index b8d55842b..63d6ba081 100644 --- a/imconfig.h +++ b/imconfig.h @@ -83,10 +83,13 @@ // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. //#define IMGUI_ENABLE_FREETYPE -//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) -// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). +//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT) // Only works in combination with IMGUI_ENABLE_FREETYPE. -// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) +// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg. +// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions. +// - Both require headers to be available in the include path + program to be linked with the library code (not provided). +// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) +//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG //#define IMGUI_ENABLE_FREETYPE_LUNASVG //---- Use stb_truetype to build and rasterize the font atlas (default) diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 275a53866..3955b080e 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -38,7 +38,25 @@ You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain color ### Using OpenType SVG fonts (SVGinOT) - *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. -- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT -- Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above - 1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. - 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. +- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT +- Two alternatives are possible to render SVG fonts: use "lunasvg" or "plutosvg". plutosvg will support some more fonts (e.g. NotoColorEmoji-Regular) and may load them faster. + +#### Using lunasvg +Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above +- Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. +- Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. + +#### Using plutosvg (and plutovg) +- Add `#define IMGUI_ENABLE_FREETYPE_PLUTOSVG` in your `imconfig.h`. +- Compile and link with plutosvg *and* plutovg (which is required by plutosvg) + +_Compilation hints for plutovg_ +- Compile all source files in `plutovg/source/*.c` +- Add include directory: `plutovg/include` + `plutovg/stb` + +_Compilation hints for plutosvg_ +- Compile `plutosvg/source/plutosvg.c` +- Add include directory: `plutosvg/source` +- Add define: `PLUTOSVG_HAS_FREETYPE` +- Link with: plutovg, freetype + diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index d97605b25..646a3b14e 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -6,8 +6,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. -// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' (#6591) +// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591) // 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly. // 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. @@ -45,12 +46,21 @@ #include FT_GLYPH_H // #include FT_SYNTHESIS_H // -#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +// Handle LunaSVG and PlutoSVG +#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) && defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) +#error "Cannot enable both IMGUI_ENABLE_FREETYPE_LUNASVG and IMGUI_ENABLE_FREETYPE_PLUTOSVG" +#endif +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG #include FT_OTSVG_H // #include FT_BBOX_H // #include +#endif +#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG +#include +#endif +#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined (IMGUI_ENABLE_FREETYPE_PLUTOSVG) #if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) -#error IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12 +#error IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12 #endif #endif @@ -269,11 +279,11 @@ namespace // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; -#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); #else #if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) - IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); + IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); #endif IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG @@ -810,6 +820,10 @@ static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas) SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot }; FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG +#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG + // With plutosvg, use provided hooks + FT_Property_Set(ft_library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks()); +#endif // IMGUI_ENABLE_FREETYPE_PLUTOSVG bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags); FT_Done_Library(ft_library); diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index b4e1d4893..6572b1547 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -5,6 +5,13 @@ #include "imgui.h" // IMGUI_API #ifndef IMGUI_DISABLE +// Usage: +// - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to enable support for imgui_freetype in imgui. + +// Optional support for OpenType SVG fonts: +// - Add '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG' to use plutosvg (not provided). See #7927. +// - Add '#define IMGUI_ENABLE_FREETYPE_LUNASVG' to use lunasvg (not provided). See #6591. + // Forward declarations struct ImFontAtlas; struct ImFontBuilderIO; From 706438a43c368c4a7d822b5ff997fa2befdbd5e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 11:37:16 +0200 Subject: [PATCH 08/21] Disabled: clicking a disabled item focuses parent window. Fix/amend 83ecc84. (#8064) 83ecc84 was too not supporting widgets using ItemHoverable() directly + too complex. Revert 83ecc84 in ButtonBehavior(), reimplement in UpdateMouseMovingWindowEndFrame()> --- imgui.cpp | 10 ++++++---- imgui_widgets.cpp | 16 ++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3ce5e90db..75e0ad40f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4875,12 +4875,13 @@ void ImGui::UpdateMouseMovingWindowNewFrame() } } -// Initiate moving window when clicking on empty space or title bar. +// Initiate focusing and moving window when clicking on empty space or title bar. +// Initiate focusing window when clicking on a disabled item. // Handle left-click and right-click focus. void ImGui::UpdateMouseMovingWindowEndFrame() { ImGuiContext& g = *GImGui; - if (g.ActiveId != 0 || g.HoveredId != 0) + if (g.ActiveId != 0 || (g.HoveredId != 0 && !g.HoveredIdIsDisabled)) return; // Unless we just made a window/popup appear @@ -4906,7 +4907,8 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; - // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) + // Cancel moving if clicked over an item which was disabled or inhibited by popups + // (when g.HoveredIdIsDisabled == true && g.HoveredId == 0 we are inhibited by popups, when g.HoveredIdIsDisabled == true && g.HoveredId != 0 we are over a disabled item)0 already) if (g.HoveredIdIsDisabled) g.MovingWindow = NULL; } @@ -4920,7 +4922,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // With right mouse button we close popups without changing focus based on where the mouse is aimed // Instead, focus will be restored to the window under the bottom-most closed popup. // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) - if (g.IO.MouseClicked[1]) + if (g.IO.MouseClicked[1] && g.HoveredId == 0) { // Find the top-most window between HoveredWindow and the top-most Modal Window. // This is where we can trim the popup stack. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 247fce39c..e240bdd90 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -542,8 +542,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Mouse handling const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; - const bool hovered_disabled = (g.HoveredId == id && g.HoveredIdIsDisabled); - if (hovered || hovered_disabled) + if (hovered) { IM_ASSERT(id != 0); // Lazily check inside rare path. @@ -561,7 +560,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Process initial action const bool mods_ok = !(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt); - if (mods_ok && !hovered_disabled) + if (mods_ok) { if (mouse_button_clicked != -1 && g.ActiveId != id) { @@ -619,17 +618,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, ImGuiInputFlags_Repeat, test_owner_id)) pressed = true; } - else if (mods_ok && hovered_disabled) - { - if (mouse_button_clicked != -1 && g.ActiveId != id) - { - // Disabled path still focus - // FIXME-NAV: Could somehow call SetNavID() with a null ID but mouse pos as NavRectRel so nav may be resumed? - // Will do it once we do it for regular click on window-void. - if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick)) - FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); - } - } if (pressed) g.NavDisableHighlight = true; From e6b5cafe65fd983eb87bf2fd4d7f68e544911fcd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 15:11:35 +0200 Subject: [PATCH 09/21] Internals: rename ImGuiLastItemData::InFlags -> ItemFlags. ImGuiNextItemData::Flags -> HasFlags to avoid mistakes. --- imgui.cpp | 42 +++++++++++++++++++------------------- imgui_internal.h | 8 ++++---- imgui_widgets.cpp | 52 +++++++++++++++++++++++------------------------ 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 75e0ad40f..36624f7f9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3702,7 +3702,7 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl return; if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) return; - if (id == g.LastItemData.ID && (g.LastItemData.InFlags & ImGuiItemFlags_NoNav)) + if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) return; ImGuiWindow* window = g.CurrentWindow; if (window->DC.NavHideHighlightOneFrame) @@ -4448,7 +4448,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { if (!IsItemFocused()) return false; - if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + if ((g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; if (flags & ImGuiHoveredFlags_ForTooltip) @@ -4483,11 +4483,11 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // Test if interactions on this window are blocked by an active popup or modal. // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. - if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck)) + if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.ItemFlags & ImGuiItemFlags_NoWindowHoverableCheck)) return false; // Test if the item is disabled - if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + if ((g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; // Special handling for calling after Begin() which represent the title bar or tab. @@ -4497,7 +4497,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.ItemFlags & ImGuiItemFlags_AllowOverlap) && id != 0) if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) if (g.HoveredIdPreviousFrame != g.LastItemData.ID) return false; @@ -4640,7 +4640,7 @@ void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemS { ImGuiContext& g = *GImGui; g.LastItemData.ID = item_id; - g.LastItemData.InFlags = in_flags; + g.LastItemData.ItemFlags = in_flags; g.LastItemData.StatusFlags = item_flags; g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; } @@ -10280,7 +10280,7 @@ bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord, ImGuiInputFlags flags, Im void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasShortcut; + g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasShortcut; g.NextItemData.Shortcut = key_chord; g.NextItemData.ShortcutFlags = flags; } @@ -10292,7 +10292,7 @@ void ImGui::ItemHandleShortcut(ImGuiID id) ImGuiInputFlags flags = g.NextItemData.ShortcutFlags; IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()! - if (g.LastItemData.InFlags & ImGuiItemFlags_Disabled) + if (g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) return; if (flags & ImGuiInputFlags_Tooltip) { @@ -10784,7 +10784,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu g.LastItemData.ID = id; g.LastItemData.Rect = bb; g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; - g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; + g.LastItemData.ItemFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; // Note: we don't copy 'g.NextItemData.SelectionUserData' to an hypothetical g.LastItemData.SelectionUserData: since the former is not cleared. @@ -10802,7 +10802,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. - if (!(g.LastItemData.InFlags & ImGuiItemFlags_NoNav)) + if (!(g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) { // FIMXE-NAV: investigate changing the window tests into a simple 'if (g.NavFocusScopeId == g.CurrentFocusScopeId)' test. window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); @@ -10812,12 +10812,12 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu NavProcessItem(); } - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasShortcut) + if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasShortcut) ItemHandleShortcut(id); } // Lightweight clear of SetNextItemXXX data. - g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + g.NextItemData.HasFlags = ImGuiNextItemDataFlags_None; g.NextItemData.ItemFlags = ImGuiItemFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE @@ -11046,7 +11046,7 @@ void ImGui::Unindent(float indent_w) void ImGui::SetNextItemWidth(float item_width) { ImGuiContext& g = *GImGui; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasWidth; g.NextItemData.Width = item_width; } @@ -11057,7 +11057,7 @@ void ImGui::PushItemWidth(float item_width) ImGuiWindow* window = g.CurrentWindow; window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); - g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PushMultiItemsWidths(int components, float w_full) @@ -11076,7 +11076,7 @@ void ImGui::PushMultiItemsWidths(int components, float w_full) prev_split = next_split; } window->DC.ItemWidth = ImMax(prev_split, 1.0f); - g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PopItemWidth() @@ -11099,7 +11099,7 @@ float ImGui::CalcItemWidth() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; float w; - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth) w = g.NextItemData.Width; else w = window->DC.ItemWidth; @@ -12444,7 +12444,7 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) result->Window = window; result->ID = g.LastItemData.ID; result->FocusScopeId = g.CurrentFocusScopeId; - result->InFlags = g.LastItemData.InFlags; + result->InFlags = g.LastItemData.ItemFlags; result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); if (result->InFlags & ImGuiItemFlags_HasSelectionUserData) { @@ -12469,7 +12469,7 @@ static void ImGui::NavProcessItem() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = g.LastItemData.ID; - const ImGuiItemFlags item_flags = g.LastItemData.InFlags; + const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags; // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) if (window->DC.NavIsScrollPushableX == false) @@ -12531,7 +12531,7 @@ static void ImGui::NavProcessItem() SetNavFocusScope(g.CurrentFocusScopeId); // Will set g.NavFocusScopeId AND store g.NavFocusScopePath g.NavFocusScopeId = g.CurrentFocusScopeId; g.NavIdIsAlive = true; - if (g.LastItemData.InFlags & ImGuiItemFlags_HasSelectionUserData) + if (g.LastItemData.ItemFlags & ImGuiItemFlags_HasSelectionUserData) { IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid); g.NavLastValidSelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData. @@ -12652,7 +12652,7 @@ void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGu ImGuiContext& g = *GImGui; g.NavMoveScoringItems = false; g.LastItemData.ID = tree_node_data->ID; - g.LastItemData.InFlags = tree_node_data->InFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). + g.LastItemData.ItemFlags = tree_node_data->InFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). g.LastItemData.NavRect = tree_node_data->NavRect; NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult() NavClearPreferredPosForAxis(ImGuiAxis_Y); @@ -13916,7 +13916,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); KeepAliveID(source_id); - bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.ItemFlags); if (is_hovered && g.IO.MouseClicked[mouse_button]) { SetActiveID(source_id, window); diff --git a/imgui_internal.h b/imgui_internal.h index 6e207d60e..f7e4f662e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1209,7 +1209,7 @@ enum ImGuiNextItemDataFlags_ struct ImGuiNextItemData { - ImGuiNextItemDataFlags Flags; + ImGuiNextItemDataFlags HasFlags; // Called HasFlags instead of Flags to avoid mistaking this ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData. // Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem() ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData() @@ -1223,14 +1223,14 @@ struct ImGuiNextItemData ImGuiID StorageId; // Set by SetNextItemStorageID() ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; } - inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! + inline void ClearFlags() { HasFlags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! }; // Status storage for the last submitted item struct ImGuiLastItemData { ImGuiID ID; - ImGuiItemFlags InFlags; // See ImGuiItemFlags_ + ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_ ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ ImRect Rect; // Full rectangle ImRect NavRect; // Navigation scoring rectangle (not displayed) @@ -3025,7 +3025,7 @@ namespace ImGui // Basic Accessors inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } - inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.ItemFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e240bdd90..3aba3a4da 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -505,7 +505,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Default behavior inherited from item flags // 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); + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); if (flags & ImGuiButtonFlags_AllowOverlap) item_flags |= ImGuiItemFlags_AllowOverlap; @@ -1150,7 +1150,7 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); ItemSize(total_bb, style.FramePadding.y); const bool is_visible = ItemAdd(total_bb, id); - const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; + const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(total_bb)) // Extra layer of "no logic clip" for box-select support { @@ -1180,7 +1180,7 @@ bool ImGui::Checkbox(const char* label, bool* v) } const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); - const bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + const bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; if (is_visible) { RenderNavHighlight(total_bb, id); @@ -2562,7 +2562,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v } if (g.ActiveId != id) return false; - if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) return false; switch (data_type) @@ -2609,7 +2609,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3104,7 +3104,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } if (set_new_value) - if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) set_new_value = false; if (set_new_value) @@ -3209,7 +3209,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3375,7 +3375,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id); if (clicked || g.NavActivateId == id) { @@ -3583,7 +3583,7 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* ClearActiveID(); g.CurrentWindow->DC.CursorPos = bb.Min; - g.LastItemData.InFlags |= ImGuiItemFlags_AllowDuplicateId; + g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId; bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); if (init) { @@ -3640,7 +3640,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG void ImGui::SetNextItemRefVal(ImGuiDataType data_type, void* p_data) { ImGuiContext& g = *GImGui; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasRefVal; + g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasRefVal; memcpy(&g.NextItemData.RefVal, p_data, DataTypeGetInfo(data_type)->Size); } @@ -3658,7 +3658,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - void* p_data_default = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; + void* p_data_default = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; char buf[64]; if ((flags & ImGuiInputTextFlags_DisplayEmptyRefVal) && DataTypeCompare(data_type, p_data, p_data_default) == 0) @@ -4465,7 +4465,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Ensure mouse cursor is set even after switching to keyboard/gamepad mode. May generalize further? (#6417) - bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags | ImGuiItemFlags_NoNavDisableMouseHover); + bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags | ImGuiItemFlags_NoNavDisableMouseHover); if (hovered) SetMouseCursor(ImGuiMouseCursor_TextInput); if (hovered && g.NavDisableMouseHover) @@ -4474,7 +4474,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We are only allowed to access the state if we are already the active widget. ImGuiInputTextState* state = GetInputTextState(id); - if (g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) + if (g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) flags |= ImGuiInputTextFlags_ReadOnly; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; @@ -5300,7 +5300,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.LastItemData.ID == 0 || g.LastItemData.ID != GetWindowScrollbarID(draw_window, ImGuiAxis_Y)) { g.LastItemData.ID = id; - g.LastItemData.InFlags = item_data_backup.InFlags; + g.LastItemData.ItemFlags = item_data_backup.ItemFlags; g.LastItemData.StatusFlags = item_data_backup.StatusFlags; } } @@ -5629,7 +5629,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Drag and Drop Target // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. - if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) { bool accepted_drag_drop = false; if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) @@ -6411,7 +6411,7 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) ImGuiStorage* storage = window->DC.StateStorage; bool is_open; - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) + if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasOpen) { if (g.NextItemData.OpenCond & ImGuiCond_Always) { @@ -6457,7 +6457,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags) ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back(); tree_node_data->ID = g.LastItemData.ID; tree_node_data->TreeFlags = flags; - tree_node_data->InFlags = g.LastItemData.InFlags; + tree_node_data->InFlags = g.LastItemData.ItemFlags; tree_node_data->NavRect = g.LastItemData.NavRect; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6506,7 +6506,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); // Compute open and multi-select states before ItemAdd() as it clear NextItem data. - ImGuiID storage_id = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; + ImGuiID storage_id = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); bool is_visible; @@ -6559,7 +6559,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.ItemFlags & ImGuiItemFlags_AllowOverlap)) button_flags |= ImGuiButtonFlags_AllowOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6571,7 +6571,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); - const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; + const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (is_multi_select) // We absolutely need to distinguish open vs select so _OpenOnArrow comes by default flags |= (flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick : ImGuiTreeNodeFlags_OpenOnArrow; @@ -6788,7 +6788,7 @@ void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) ImGuiContext& g = *GImGui; if (g.CurrentWindow->SkipItems) return; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasOpen; g.NextItemData.OpenVal = is_open; g.NextItemData.OpenCond = (ImU8)(cond ? cond : ImGuiCond_Always); } @@ -6799,7 +6799,7 @@ void ImGui::SetNextItemStorageID(ImGuiID storage_id) ImGuiContext& g = *GImGui; if (g.CurrentWindow->SkipItems) return; - g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasStorageID; + g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasStorageID; g.NextItemData.StorageId = storage_id; } @@ -6925,7 +6925,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl is_visible = ItemAdd(bb, id, NULL, extra_item_flags); } - const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; + const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(bb)) // Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd) return false; @@ -6953,7 +6953,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.ItemFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } // Multi-selection support (header) const bool was_selected = selected; @@ -7035,7 +7035,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.InFlags & ImGuiItemFlags_AutoClosePopups)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) CloseCurrentPopup(); if (disabled_item && !disabled_global) @@ -9960,7 +9960,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Calculate tab contents size ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument)); tab->RequestedWidth = -1.0f; - if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth) size.x = tab->RequestedWidth = g.NextItemData.Width; if (tab_is_new) tab->Width = ImMax(1.0f, size.x); From 0f6a463fae57cbec744f89b5d1afb7bb1a7eb34f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 15:16:05 +0200 Subject: [PATCH 10/21] Internals: rename ImGuiTreeNodeStackData::InFlags and ImGuiNavItemData::InFlags to ItemFlags too. --- imgui.cpp | 16 ++++++++-------- imgui_internal.h | 16 ++++++++-------- imgui_widgets.cpp | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 36624f7f9..772df22a5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4530,7 +4530,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) // FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28. // If you used this in your legacy/custom widgets code: -// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'. +// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.ItemFlags'. // - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable. bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) { @@ -10847,7 +10847,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); } //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] - //if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0) + //if ((g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav) == 0) // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] #endif @@ -12444,9 +12444,9 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) result->Window = window; result->ID = g.LastItemData.ID; result->FocusScopeId = g.CurrentFocusScopeId; - result->InFlags = g.LastItemData.ItemFlags; + result->ItemFlags = g.LastItemData.ItemFlags; result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); - if (result->InFlags & ImGuiItemFlags_HasSelectionUserData) + if (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) { IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid); result->SelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData. @@ -12652,7 +12652,7 @@ void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGu ImGuiContext& g = *GImGui; g.NavMoveScoringItems = false; g.LastItemData.ID = tree_node_data->ID; - g.LastItemData.ItemFlags = tree_node_data->InFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). + g.LastItemData.ItemFlags = tree_node_data->ItemFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). g.LastItemData.NavRect = tree_node_data->NavRect; NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult() NavClearPreferredPosForAxis(ImGuiAxis_Y); @@ -13039,7 +13039,7 @@ void ImGui::NavInitRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = 0; g.NavJustMovedToIsTabbing = false; - g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; + g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; } // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) @@ -13298,7 +13298,7 @@ void ImGui::NavMoveRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveKeyMods; g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; - g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; + g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId); } @@ -13318,7 +13318,7 @@ void ImGui::NavMoveRequestApplyResult() } // Tabbing: Activates Inputable, otherwise only Focus - if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->InFlags & ImGuiItemFlags_Inputable) == 0) + if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->ItemFlags & ImGuiItemFlags_Inputable) == 0) g.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate; // Activate diff --git a/imgui_internal.h b/imgui_internal.h index f7e4f662e..75b586c3b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -823,8 +823,8 @@ enum ImGuiDataTypePrivate_ //----------------------------------------------------------------------------- // Extend ImGuiItemFlags -// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags. -// - output: stored in g.LastItemData.InFlags +// - input: PushItemFlag() manipulates g.CurrentItemFlags, g.NextItemData.ItemFlags, ItemAdd() calls may add extra flags too. +// - output: stored in g.LastItemData.ItemFlags enum ImGuiItemFlagsPrivate_ { // Controlled by user @@ -908,7 +908,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine ImGuiButtonFlags_NoKeyModsAllowed = 1 << 16, // disable mouse interaction if a key modifier is held ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) - ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used every time an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.InFlags) + ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used every time an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.ItemFlags) ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) @@ -1250,7 +1250,7 @@ struct ImGuiTreeNodeStackData { ImGuiID ID; ImGuiTreeNodeFlags TreeFlags; - ImGuiItemFlags InFlags; // Used for nav landing + ImGuiItemFlags ItemFlags; // Used for nav landing ImRect NavRect; // Used for nav landing }; @@ -1590,14 +1590,14 @@ struct ImGuiNavItemData ImGuiID ID; // Init,Move // Best candidate item ID ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space - ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags + ImGuiItemFlags ItemFlags; // ????,Move // Best candidate item flags float DistBox; // Move // Best candidate box distance to current NavId float DistCenter; // Move // Best candidate center distance to current NavId float DistAxial; // Move // Best candidate axial distance to current NavId - ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData) + ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (ItemFlags & ImGuiItemFlags_HasSelectionUserData) ImGuiNavItemData() { Clear(); } - void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } + void Clear() { Window = NULL; ID = FocusScopeId = 0; ItemFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } }; // Storage for PushFocusScope() @@ -2177,7 +2177,7 @@ struct ImGuiContext ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). ImGuiKeyChord NavJustMovedToKeyMods; bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags. - bool NavJustMovedToHasSelectionData; // Copy of move result's InFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. + bool NavJustMovedToHasSelectionData; // Copy of move result's ItemFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3aba3a4da..60bb36631 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6457,7 +6457,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags) ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back(); tree_node_data->ID = g.LastItemData.ID; tree_node_data->TreeFlags = flags; - tree_node_data->InFlags = g.LastItemData.ItemFlags; + tree_node_data->ItemFlags = g.LastItemData.ItemFlags; tree_node_data->NavRect = g.LastItemData.NavRect; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } From 38617a5ad345126d912be491d09070fbaecb2be1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 15:38:00 +0200 Subject: [PATCH 11/21] Internals: remove ImGuiInputTextFlags_NoMarkEdited and g.LockMarkEdited n favor of ImGuiItemFlags_NoMarkEdited. --- imgui.cpp | 5 ++--- imgui.h | 2 +- imgui_internal.h | 7 +++---- imgui_widgets.cpp | 26 +++++++++++++++++--------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 772df22a5..182bd2162 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3986,7 +3986,6 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) DragSpeedDefaultRatio = 1.0f / 100.0f; DisabledAlphaBackup = 0.0f; DisabledStackSize = 0; - LockMarkEdited = 0; TooltipOverrideCount = 0; TooltipPreviousWindow = NULL; @@ -4373,10 +4372,10 @@ ImGuiID ImGui::GetHoveredID() void ImGui::MarkItemEdited(ImGuiID id) { - // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). + // This marking is to be able to provide info for IsItemDeactivatedAfterEdit(). // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. ImGuiContext& g = *GImGui; - if (g.LockMarkEdited > 0) + if (g.LastItemData.ItemFlags & ImGuiItemFlags_NoMarkEdited) return; if (g.ActiveId == id || g.ActiveId == 0) { diff --git a/imgui.h b/imgui.h index ef0c59a9d..4ea730626 100644 --- a/imgui.h +++ b/imgui.h @@ -1154,7 +1154,7 @@ enum ImGuiInputTextFlags_ // Inputs ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field - ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using IsItemDeactivatedAfterEdit() instead! ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter). diff --git a/imgui_internal.h b/imgui_internal.h index 75b586c3b..bf7759f7b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -834,6 +834,7 @@ enum ImGuiItemFlagsPrivate_ ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable() ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover. + ImGuiItemFlags_NoMarkEdited = 1 << 16, // false // Skip calling MarkItemEdited() // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 20, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -886,9 +887,8 @@ enum ImGuiInputTextFlagsPrivate_ { // [Internal] ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() - ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data - ImGuiInputTextFlags_MergedItem = 1 << 28, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. - ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 29, // For internal use by InputScalar() and TempInputScalar() + ImGuiInputTextFlags_MergedItem = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. + ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 28, // For internal use by InputScalar() and TempInputScalar() }; // Extend ImGuiButtonFlags_ @@ -2282,7 +2282,6 @@ struct ImGuiContext float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() short DisabledStackSize; - short LockMarkEdited; short TooltipOverrideCount; ImGuiWindow* TooltipPreviousWindow; // Window of last tooltip submitted during the frame ImVector ClipboardHandlerData; // If no custom clipboard handler is defined diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 60bb36631..9f171c97d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3601,6 +3601,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG { // FIXME: May need to clarify display behavior if format doesn't contain %. // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 + ImGuiContext& g = *GImGui; const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); char fmt_buf[32]; char data_buf[32]; @@ -3610,8 +3611,8 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); ImStrTrimBlanks(data_buf); - ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; - + 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_ARRAYSIZE(data_buf), flags)) { @@ -3630,6 +3631,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG } // 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); @@ -3666,8 +3668,10 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data else DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); - flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. - flags |= (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; + // Disable the MarkItemEdited() call in InputText but keep ImGuiItemStatusFlags_Edited. + // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. + g.NextItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; + flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; bool value_changed = false; if (p_step == NULL) @@ -3719,6 +3723,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PopID(); EndGroup(); } + + g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -5315,7 +5321,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) + if (value_changed) MarkItemEdited(id); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); @@ -6196,8 +6202,9 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) return; + ImGuiContext& g = *GImGui; - g.LockMarkEdited++; + PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); ImGuiColorEditFlags opts = g.ColorEditOptions; if (allow_opt_inputs) { @@ -6239,8 +6246,8 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) } g.ColorEditOptions = opts; + PopItemFlag(); EndPopup(); - g.LockMarkEdited--; } void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) @@ -6249,8 +6256,9 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) return; + ImGuiContext& g = *GImGui; - g.LockMarkEdited++; + PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); if (allow_opt_picker) { ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function @@ -6279,8 +6287,8 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_picker) Separator(); CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); } + PopItemFlag(); EndPopup(); - g.LockMarkEdited--; } //------------------------------------------------------------------------- From 604f2fa84aa2c71cab53e07235557b5b9207b76e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 15:42:11 +0200 Subject: [PATCH 12/21] InputScalar: added an assert to clarify that ImGuiInputTextFlags_EnterReturnsTrue is not supported by InputFloat, InputInt etc. (#8065) It was never correctly supported. Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit(). --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5d61daa54..373c12f70 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,8 @@ Other changes: preventing use of external shortcuts not guarded by an ActiveId check. (#8048) [@geertbleyen] - InputText: ensure mouse cursor shape is set regardless of whether keyboard mode is enabled or not. (#6417) +- InputScalar: added an assert to clarify that ImGuiInputTextFlags_EnterReturnsTrue is not + supported by InputFloat, InputInt, InputScalar etc. widgets. It actually never was. (#8065) - imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render OpenType SVG fonts. Requires defining IMGUI_ENABLE_FREETYPE_PLUTOSVG along with IMGUI_ENABLE_FREETYPE. Providing headers/librairies for plutosvg + plutovg is up to you (see #7927 for help). diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9f171c97d..8a504ef1d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3656,6 +3656,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; + IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()! if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; From db26fe7ca8de76d7802cb5c74f683e42870754ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 12:35:19 +0200 Subject: [PATCH 13/21] Debug Tools: Metrics: Fixed a crash when browsing "InputText" section before using one. (#8071) Caused by 21d03edcb --- imgui_widgets.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8a504ef1d..c8e0a5b5e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4129,6 +4129,7 @@ ImGuiInputTextState::ImGuiInputTextState() { memset(this, 0, sizeof(*this)); Stb = IM_NEW(ImStbTexteditState); + memset(Stb, 0, sizeof(*Stb)); } ImGuiInputTextState::~ImGuiInputTextState() From 7a56b411247a9bbe32b7642f4434561e4bc6c3eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Oct 2024 19:57:18 +0200 Subject: [PATCH 14/21] Nav: added io.ConfigNavEscapeClearFocusItem. (#8059, #2048, #1074, #3200) --- docs/CHANGELOG.txt | 11 ++++++++--- docs/TODO.txt | 4 ++-- imgui.cpp | 9 ++++++--- imgui.h | 5 +++-- imgui_demo.cpp | 2 ++ imgui_internal.h | 4 +++- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 373c12f70..129709152 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,8 +43,8 @@ Breaking changes: - The typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641) - This removes the requirement to redefine it for backends which are e.g. storing - descriptor sets or other 64-bits structures when building on 32-bits archs. - It therefore simplify various building scripts/helpers. + descriptor sets or other 64-bits structures when building on 32-bits archs + (namely our DX12 and Vulkan backends). It therefore simplify various building scripts/helpers. - You may have compile-time issues if you were casting to 'void*' instead of 'ImTextureID' when passing your types to functions taking ImTextureID values, e.g. ImGui::Image(). In doubt it is almost always better to do an intermediate intptr_t cast, since it @@ -67,7 +67,12 @@ Other changes: state to draw callbacks. (#6969, #5834, #7468, #3590) - IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921) - Error Handling: turned a few more functions into recoverable errors. (#1651) -- Nav: added io.ConfigNavEscapeClearFocusWindow to clear focused window on Escape. (#3200) +- Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change + how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) + - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. + - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect. + - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, + is for some reason your app relies on imgui focus to take other decisions. - Nav: pressing escape to hide nav highlight doesn't clear location from when ctrl+tabbing back into same window later. - Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most diff --git a/docs/TODO.txt b/docs/TODO.txt index e61501d78..dd98d18b1 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -275,13 +275,13 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) ! nav: never clear NavId on some setup (e.g. gamepad centric) - - nav: there's currently no way to completely clear focus with the keyboard. depending on patterns used by the application to dispatch inputs, it may be desirable. - nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view? - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window" - - nav: wrap around logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). + - nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). - nav: patterns to make it possible for arrows key to update selection (see JustMovedTo in range_select branch) - nav: restore/find nearest NavId when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name) - nav: SetItemDefaultFocus() level of priority, so widget like Selectable when inside a popup could claim a low-priority default focus on the first selected iem + - nav: holding space to repeat a button doesn't show button activated during hold. - nav: NavFlattened: init requests don't work properly on flattened siblings. - nav: NavFlattened: pageup/pagedown/home/end don't work properly on flattened siblings. - nav: NavFlattened: ESC on a flattened child should select something. diff --git a/imgui.cpp b/imgui.cpp index 182bd2162..773272e2c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1409,6 +1409,7 @@ ImGuiIO::ImGuiIO() ConfigNavSwapGamepadButtons = false; ConfigNavMoveSetMousePos = false; ConfigNavCaptureKeyboard = true; + ConfigNavEscapeClearFocusItem = true; ConfigNavEscapeClearFocusWindow = false; ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; @@ -13376,11 +13377,13 @@ static void ImGui::NavUpdateCancelRequest() { // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were // FIXME-NAV: This should happen on window appearing. - if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup)))// || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) - g.NavWindow->NavLastIds[0] = 0; + if (g.IO.ConfigNavEscapeClearFocusItem || g.IO.ConfigNavEscapeClearFocusWindow) + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup)))// || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; // Clear nav focus - g.NavId = 0; + if (g.IO.ConfigNavEscapeClearFocusItem || g.IO.ConfigNavEscapeClearFocusWindow) + g.NavId = 0; if (g.IO.ConfigNavEscapeClearFocusWindow) FocusWindow(NULL); } diff --git a/imgui.h b/imgui.h index 4ea730626..641f1d54d 100644 --- a/imgui.h +++ b/imgui.h @@ -2250,7 +2250,8 @@ struct ImGuiIO bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. - bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape (when no item is active, no popup open etc.) clears focused window + navigation id/highlight. + bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. + bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). 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). @@ -2367,7 +2368,7 @@ struct ImGuiIO bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when io.ConfigNavMoveSetMousePos is enabled. bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. - bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + bool NavVisible; // Keyboard/Gamepad navigation highlight is visible and allowed (will handle ImGuiKey_NavXXX events). float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. int MetricsRenderVertices; // Vertices output during last call to Render() int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index dca674054..63f6d15d1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -532,6 +532,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard); + ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem); + ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); diff --git a/imgui_internal.h b/imgui_internal.h index bf7759f7b..bc00d0c28 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1600,7 +1600,7 @@ struct ImGuiNavItemData void Clear() { Window = NULL; ID = FocusScopeId = 0; ItemFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } }; -// Storage for PushFocusScope() +// Storage for PushFocusScope(), g.FocusScopeStack[], g.NavFocusRoute[] struct ImGuiFocusScopeData { ImGuiID ID; @@ -3223,6 +3223,8 @@ namespace ImGui IMGUI_API void RenderDragDropTargetRect(const ImRect& bb, const ImRect& item_clip_rect); // Typing-Select API + // (provide Windows Explorer style "select items by typing partial name" + "cycle through items by typing same letter" feature) + // (this is currently not documented nor used by main library, but should work. See "widgets_typingselect" in imgui_test_suite for usage code. Please let us know if you use this!) IMGUI_API ImGuiTypingSelectRequest* GetTypingSelectRequest(ImGuiTypingSelectFlags flags = ImGuiTypingSelectFlags_None); IMGUI_API int TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx); IMGUI_API int TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx); From 23b655f8e3a37305a89174e32ceaab057dc67318 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 16:42:22 +0200 Subject: [PATCH 15/21] Internals: (Breaking) changed g.NavDisableHighlight to g.NavCursorVisible : same logic but inverted value. (#1074, #2048, #7237, #8059, #1712, #7370, #787) --- imgui.cpp | 36 ++++++++++++++++++------------------ imgui.h | 2 +- imgui_internal.h | 3 ++- imgui_widgets.cpp | 10 +++++----- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 773272e2c..4dd02ee0a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3701,7 +3701,7 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl ImGuiContext& g = *GImGui; if (id != g.NavId) return; - if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + if (!g.NavCursorVisible && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) return; if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) return; @@ -3910,7 +3910,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; NavIdIsAlive = false; NavMousePosDirty = false; - NavDisableHighlight = true; + NavCursorVisible = false; NavDisableMouseHover = false; NavAnyRequest = false; @@ -4444,7 +4444,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) ImGuiWindow* window = g.CurrentWindow; IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0, "Invalid flags for IsItemHovered()!"); - if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) + if (g.NavDisableMouseHover && g.NavCursorVisible && !(flags & ImGuiHoveredFlags_NoNavOverride)) { if (!IsItemFocused()) return false; @@ -4824,7 +4824,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) ImGuiContext& g = *GImGui; FocusWindow(window); SetActiveID(window->MoveId, window); - g.NavDisableHighlight = true; + g.NavCursorVisible = false; g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; g.ActiveIdNoClearOnFocusLoss = true; SetActiveIdUsingAllKeyboardKeys(); @@ -5835,7 +5835,7 @@ bool ImGui::IsAnyItemActive() bool ImGui::IsAnyItemFocused() { ImGuiContext& g = *GImGui; - return g.NavId != 0 && !g.NavDisableHighlight; + return g.NavId != 0 && g.NavCursorVisible; } bool ImGui::IsItemVisible() @@ -6689,7 +6689,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Title bar only const float backup_border_size = style.FrameBorderSize; g.Style.FrameBorderSize = window->WindowBorderSize; - ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && g.NavCursorVisible) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); g.Style.FrameBorderSize = backup_border_size; } @@ -12189,7 +12189,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale; ImRect r_avoid; - if (!g.NavDisableHighlight && g.NavDisableMouseHover && !g.IO.ConfigNavMoveSetMousePos) + if (g.NavCursorVisible && g.NavDisableMouseHover && !g.IO.ConfigNavMoveSetMousePos) r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); else r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. @@ -12272,7 +12272,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) g.NavDisableMouseHover = true; else - g.NavDisableHighlight = true; + g.NavCursorVisible = false; // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) NavClearPreferredPosForAxis(ImGuiAxis_X); @@ -12738,7 +12738,7 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer) void ImGui::NavRestoreHighlightAfterMove() { ImGuiContext& g = *GImGui; - g.NavDisableHighlight = false; + g.NavCursorVisible = true; g.NavDisableMouseHover = g.NavMousePosDirty = true; } @@ -12789,7 +12789,7 @@ static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. - if ((g.NavDisableHighlight || !g.NavDisableMouseHover || !window) && !activated_shortcut) + if ((!g.NavCursorVisible || !g.NavDisableMouseHover || !window) && !activated_shortcut) return ImGuiInputSource_Mouse; else return ImGuiInputSource_Keyboard; // or Nav in general @@ -12897,7 +12897,7 @@ static void ImGui::NavUpdate() // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) bool set_mouse_pos = false; if (g.NavMousePosDirty && g.NavIdIsAlive) - if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + if (g.NavCursorVisible && g.NavDisableMouseHover && g.NavWindow) set_mouse_pos = true; g.NavMousePosDirty = false; IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); @@ -12913,7 +12913,7 @@ static void ImGui::NavUpdate() // Set output flags for user application io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); - io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + io.NavVisible = (io.NavActive && g.NavId != 0 && g.NavCursorVisible) || (g.NavWindowingTarget != NULL); // Process NavCancel input (to close a popup, get back to parent, clear focus) NavUpdateCancelRequest(); @@ -12921,7 +12921,7 @@ static void ImGui::NavUpdate() // Process manual activation request g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0; g.NavActivateFlags = ImGuiActivateFlags_None; - if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + if (g.NavId != 0 && g.NavCursorVisible && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_NoOwner)); const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, 0, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, 0, ImGuiKeyOwner_NoOwner))); @@ -12946,7 +12946,7 @@ static void ImGui::NavUpdate() } } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) - g.NavDisableHighlight = true; + g.NavCursorVisible = false; if (g.NavActivateId != 0) IM_ASSERT(g.NavActivateDownId == g.NavActivateId); @@ -13003,7 +13003,7 @@ static void ImGui::NavUpdate() // Always prioritize mouse highlight if navigation is disabled if (!nav_keyboard_active && !nav_gamepad_active) { - g.NavDisableHighlight = true; + g.NavCursorVisible = false; g.NavDisableMouseHover = set_mouse_pos = false; } @@ -13147,7 +13147,7 @@ void ImGui::NavUpdateCreateMoveRequest() IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitResult.ID = 0; - g.NavDisableHighlight = false; + g.NavCursorVisible = true; } // When using gamepad, we project the reference nav bounding box into window visible area. @@ -13211,7 +13211,7 @@ void ImGui::NavUpdateCreateTabbingRequest() // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; if (nav_keyboard_active) - g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1; + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavCursorVisible == false && g.ActiveId == 0) ? 0 : +1; else g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate; @@ -15823,7 +15823,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); Text("NavActivateFlags: %04X", g.NavActivateFlags); - Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + Text("NavCursorVisible: %d, NavDisableMouseHover: %d", g.NavCursorVisible, g.NavDisableMouseHover); Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); Text("NavFocusRoute[] = "); for (int path_n = g.NavFocusRoute.Size - 1; path_n >= 0; path_n--) diff --git a/imgui.h b/imgui.h index 641f1d54d..d89661bf2 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.4 WIP" -#define IMGUI_VERSION_NUM 19135 +#define IMGUI_VERSION_NUM 19136 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index bc00d0c28..a0f1c1c09 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2144,7 +2144,8 @@ struct ImGuiContext ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if io.ConfigNavMoveSetMousePos is set (not enabled by default) - bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavCursorVisible; // Nav focus rectangle is visible? We hide it after a mouse click. We show it after a nav move. + //bool NavDisableHighlight; // Before 1.91.4 (2024/10/18) we used g.NavDisableHighlight. g.NavCursorVisible is the new variable name, with opposite value (g.NavDisableHighlight = !g.NavCursorVisible) bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. // Navigation: Init & Move Requests diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c8e0a5b5e..7e67cea4e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -620,12 +620,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } if (pressed) - g.NavDisableHighlight = true; + g.NavCursorVisible = false; } // Gamepad/Keyboard handling // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse. - if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover) + if (g.NavId == id && g.NavCursorVisible && g.NavDisableMouseHover) if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) hovered = true; if (g.NavActivateDownId == id) @@ -689,7 +689,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ClearActiveID(); } if (!(flags & ImGuiButtonFlags_NoNavFocus)) - g.NavDisableHighlight = true; + g.NavCursorVisible = false; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { @@ -7001,7 +7001,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) - g.NavDisableHighlight = true; + g.NavCursorVisible = false; } } if (pressed) @@ -8624,7 +8624,7 @@ void ImGui::EndMenuBar() IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) FocusWindow(window); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); - g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. g.NavDisableMouseHover = g.NavMousePosDirty = true; NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat } From 0536ace2b6c24bd1fb14550ac83e035e879834c1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 16:46:14 +0200 Subject: [PATCH 16/21] Internals: (Breaking) renamed RenderNavHighlight() to RenderNavCursor(), ImGuiNavHighlightFlags to ImGuiNavRenderCursorFlags. (#1074, #2048, #7237, #8059, #1712, #7370, #787) + referenced in #8057, #3882, #3411, #2155, #3351, #4722, #1658, #4050. --- imgui.cpp | 14 +++++++------- imgui_internal.h | 23 ++++++++++++++++------- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 46 +++++++++++++++++++++++----------------------- 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4dd02ee0a..6679291c2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3696,12 +3696,12 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) } } -void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags) { ImGuiContext& g = *GImGui; if (id != g.NavId) return; - if (!g.NavCursorVisible && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + if (!g.NavCursorVisible && !(flags & ImGuiNavRenderCursorFlags_AlwaysDraw)) return; if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) return; @@ -3709,11 +3709,11 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl if (window->DC.NavHideHighlightOneFrame) return; - float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + float rounding = (flags & ImGuiNavRenderCursorFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; ImRect display_rect = bb; display_rect.ClipWith(window->ClipRect); const float thickness = 2.0f; - if (flags & ImGuiNavHighlightFlags_Compact) + if (flags & ImGuiNavRenderCursorFlags_Compact) { window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness); } @@ -6067,11 +6067,11 @@ void ImGui::EndChild() if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !nav_flattened) { ItemAdd(bb, child_window->ChildId); - RenderNavHighlight(bb, child_window->ChildId); + RenderNavCursor(bb, child_window->ChildId); // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) if (child_window->DC.NavLayersActiveMask == 0 && child_window == g.NavWindow) - RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_Compact); + RenderNavCursor(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavRenderCursorFlags_Compact); } else { @@ -15950,7 +15950,7 @@ bool ImGui::DebugBreakButton(const char* label, const char* description_of_locat ColorConvertRGBtoHSV(col4f.x, col4f.y, col4f.z, hsv.x, hsv.y, hsv.z); ColorConvertHSVtoRGB(hsv.x + 0.20f, hsv.y, hsv.z, col4f.x, col4f.y, col4f.z); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, GetColorU32(col4f), true, g.Style.FrameRounding); RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, g.Style.ButtonTextAlign, &bb); diff --git a/imgui_internal.h b/imgui_internal.h index a0f1c1c09..94e0cb0e0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -177,7 +177,7 @@ typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // F typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow() typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() -typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavRenderCursorFlags; // -> enum ImGuiNavRenderCursorFlags_//Flags: for RenderNavCursor() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions @@ -1546,12 +1546,18 @@ enum ImGuiScrollFlags_ ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY, }; -enum ImGuiNavHighlightFlags_ +enum ImGuiNavRenderCursorFlags_ { - ImGuiNavHighlightFlags_None = 0, - ImGuiNavHighlightFlags_Compact = 1 << 1, // Compact highlight, no padding - ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. - ImGuiNavHighlightFlags_NoRounding = 1 << 3, + ImGuiNavRenderCursorFlags_None = 0, + ImGuiNavRenderCursorFlags_Compact = 1 << 1, // Compact highlight, no padding/distance from focused item + ImGuiNavRenderCursorFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse. + ImGuiNavRenderCursorFlags_NoRounding = 1 << 3, +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiNavHighlightFlags_None = ImGuiNavRenderCursorFlags_None, // Renamed in 1.91.4 + ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4 + ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4 + ImGuiNavHighlightFlags_NoRounding = ImGuiNavRenderCursorFlags_NoRounding, // Renamed in 1.91.4 +#endif }; enum ImGuiNavMoveFlags_ @@ -3343,7 +3349,10 @@ namespace ImGui IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); - IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_None); // Navigation highlight + IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4 +#endif IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3ba15fef5..1f8035cde 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3139,7 +3139,7 @@ void ImGui::TableHeader(const char* label) if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); } - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding); + RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding); if (held) table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7e67cea4e..e5f2acc8d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -739,7 +739,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); if (g.LogEnabled) @@ -791,7 +791,7 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; @@ -817,7 +817,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu // Render const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); @@ -858,7 +858,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) ImU32 bg_col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); if (hovered) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact); + RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); ImU32 cross_col = GetColorU32(ImGuiCol_Text); ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; @@ -885,7 +885,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact); + RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); // Switch to moving the window after mouse is moved beyond the initial drag threshold @@ -1092,7 +1092,7 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& imag // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); @@ -1183,7 +1183,7 @@ bool ImGui::Checkbox(const char* label, bool* v) const bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; if (is_visible) { - RenderNavHighlight(total_bb, id); + RenderNavCursor(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); if (mixed_value) @@ -1285,7 +1285,7 @@ bool ImGui::RadioButton(const char* label, bool active) if (pressed) MarkItemEdited(id); - RenderNavHighlight(total_bb, id); + RenderNavCursor(total_bb, id); const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); if (active) @@ -1425,7 +1425,7 @@ bool ImGui::TextLink(const char* label) bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held); - RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_None); + RenderNavCursor(bb, id); if (hovered) SetMouseCursor(ImGuiMouseCursor_Hand); @@ -1856,7 +1856,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF // Render shape const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); if (!(flags & ImGuiComboFlags_NoArrowButton)) @@ -2658,7 +2658,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavHighlight(frame_bb, id); + RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Drag behavior @@ -3240,7 +3240,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavHighlight(frame_bb, id); + RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior @@ -3389,7 +3389,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavHighlight(frame_bb, id); + RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior @@ -5102,7 +5102,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Render frame if (!is_multiline) { - RenderNavHighlight(frame_bb, id); + RenderNavCursor(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); } @@ -6113,7 +6113,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl else window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); } - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); if ((flags & ImGuiColorEditFlags_NoBorder) == 0) { if (g.Style.FrameBorderSize > 0.0f) @@ -6677,15 +6677,15 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // Render { const ImU32 text_col = GetColorU32(ImGuiCol_Text); - ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact; + ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact; if (is_multi_select) - nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle + nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle if (display_frame) { // Framed type const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); - RenderNavHighlight(frame_bb, id, nav_highlight_flags); + RenderNavCursor(frame_bb, id, nav_render_cursor_flags); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) @@ -6705,7 +6705,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); } - RenderNavHighlight(frame_bb, id, nav_highlight_flags); + RenderNavCursor(frame_bb, id, nav_render_cursor_flags); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) @@ -7026,10 +7026,10 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } if (g.NavId == id) { - ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding; + ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding; if (is_multi_select) - nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle - RenderNavHighlight(bb, id, nav_highlight_flags); + nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle + RenderNavCursor(bb, id, nav_render_cursor_flags); } } @@ -10109,7 +10109,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, float y_offset = 1.0f * g.CurrentDpiScale; display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), style.TabBarOverlineSize); } - RenderNavHighlight(bb, id); + RenderNavCursor(bb, id); // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); From 0bae2db77fdfe16f0f3c0f76b3af60de9f624b5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 18:07:58 +0200 Subject: [PATCH 17/21] Internals: (Breaking) renamed NavDisableMouseHover to NavHighlightItemUnderNav. Considering adding NavHighlightItemUnderMouse as well, but would require to resolve quite a few ambiguities and for a feature we don't have yet. --- imgui.cpp | 30 +++++++++++++++--------------- imgui_internal.h | 9 +++++---- imgui_widgets.cpp | 14 +++++++------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6679291c2..09acf5cd6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3911,7 +3911,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) NavIdIsAlive = false; NavMousePosDirty = false; NavCursorVisible = false; - NavDisableMouseHover = false; + NavHighlightItemUnderNav = false; NavAnyRequest = false; NavInitRequest = false; @@ -4444,7 +4444,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) ImGuiWindow* window = g.CurrentWindow; IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0, "Invalid flags for IsItemHovered()!"); - if (g.NavDisableMouseHover && g.NavCursorVisible && !(flags & ImGuiHoveredFlags_NoNavOverride)) + if (g.NavHighlightItemUnderNav && g.NavCursorVisible && !(flags & ImGuiHoveredFlags_NoNavOverride)) { if (!IsItemFocused()) return false; @@ -4615,7 +4615,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag } #endif - if (g.NavDisableMouseHover && (item_flags & ImGuiItemFlags_NoNavDisableMouseHover) == 0) + if (g.NavHighlightItemUnderNav && (item_flags & ImGuiItemFlags_NoNavDisableMouseHover) == 0) return false; return true; @@ -6589,7 +6589,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size g.NavWindowingToggleLayer = false; - g.NavDisableMouseHover = true; + g.NavHighlightItemUnderNav = true; resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaSize); if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) @@ -7859,7 +7859,7 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) if (g.NavWindow != window) { SetNavWindow(window); - if (window && g.NavDisableMouseHover) + if (window && g.NavHighlightItemUnderNav) g.NavMousePosDirty = true; g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavLayer = ImGuiNavLayer_Main; @@ -9778,7 +9778,7 @@ static void ImGui::UpdateMouseInputs() // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) - g.NavDisableMouseHover = false; + g.NavHighlightItemUnderNav = false; for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) { @@ -9817,7 +9817,7 @@ static void ImGui::UpdateMouseInputs() // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation if (io.MouseClicked[i]) - g.NavDisableMouseHover = false; + g.NavHighlightItemUnderNav = false; } } @@ -12189,7 +12189,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale; ImRect r_avoid; - if (g.NavCursorVisible && g.NavDisableMouseHover && !g.IO.ConfigNavMoveSetMousePos) + if (g.NavCursorVisible && g.NavHighlightItemUnderNav && !g.IO.ConfigNavMoveSetMousePos) r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); else r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. @@ -12270,7 +12270,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) - g.NavDisableMouseHover = true; + g.NavHighlightItemUnderNav = true; else g.NavCursorVisible = false; @@ -12739,7 +12739,7 @@ void ImGui::NavRestoreHighlightAfterMove() { ImGuiContext& g = *GImGui; g.NavCursorVisible = true; - g.NavDisableMouseHover = g.NavMousePosDirty = true; + g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; } static inline void ImGui::NavUpdateAnyRequestFlag() @@ -12789,7 +12789,7 @@ static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. - if ((!g.NavCursorVisible || !g.NavDisableMouseHover || !window) && !activated_shortcut) + if ((!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) && !activated_shortcut) return ImGuiInputSource_Mouse; else return ImGuiInputSource_Keyboard; // or Nav in general @@ -12897,7 +12897,7 @@ static void ImGui::NavUpdate() // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) bool set_mouse_pos = false; if (g.NavMousePosDirty && g.NavIdIsAlive) - if (g.NavCursorVisible && g.NavDisableMouseHover && g.NavWindow) + if (g.NavCursorVisible && g.NavHighlightItemUnderNav && g.NavWindow) set_mouse_pos = true; g.NavMousePosDirty = false; IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); @@ -13004,7 +13004,7 @@ static void ImGui::NavUpdate() if (!nav_keyboard_active && !nav_gamepad_active) { g.NavCursorVisible = false; - g.NavDisableMouseHover = set_mouse_pos = false; + g.NavHighlightItemUnderNav = set_mouse_pos = false; } // Update mouse position if requested @@ -13717,7 +13717,7 @@ static void ImGui::NavUpdateWindowing() const float NAV_MOVE_SPEED = 800.0f; const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); g.NavWindowingAccumDeltaPos += nav_move_dir * move_step; - g.NavDisableMouseHover = true; + g.NavHighlightItemUnderNav = true; ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos); if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) { @@ -15823,7 +15823,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); Text("NavActivateFlags: %04X", g.NavActivateFlags); - Text("NavCursorVisible: %d, NavDisableMouseHover: %d", g.NavCursorVisible, g.NavDisableMouseHover); + Text("NavCursorVisible: %d, NavHighlightItemUnderNav: %d", g.NavCursorVisible, g.NavHighlightItemUnderNav); Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); Text("NavFocusRoute[] = "); for (int path_n = g.NavFocusRoute.Size - 1; path_n >= 0; path_n--) diff --git a/imgui_internal.h b/imgui_internal.h index 94e0cb0e0..85ca13910 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -833,7 +833,7 @@ enum ImGuiItemFlagsPrivate_ ImGuiItemFlags_MixedValue = 1 << 12, // 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_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable() ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. - ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover. + ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover highlight (behave as if NavHighlightItemUnderNav==false). ImGuiItemFlags_NoMarkEdited = 1 << 16, // false // Skip calling MarkItemEdited() // Controlled by widget code @@ -2133,6 +2133,10 @@ struct ImGuiContext ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. // Gamepad/keyboard Navigation + bool NavCursorVisible; // Nav focus cursor/rectangle is visible? We hide it after a mouse click. We show it after a nav move. + bool NavHighlightItemUnderNav; // Disable mouse hovering highlight. Highlight navigation focused item instead of mouse hovered item. + //bool NavDisableHighlight; // Old name for !g.NavCursorVisible before 1.91.4 (2024/10/18). OPPOSITE VALUE (g.NavDisableHighlight == !g.NavCursorVisible) + //bool NavDisableMouseHover; // Old name for g.NavHighlightItemUnderNav before 1.91.1 (2024/10/18) this was called When user starts using keyboard/gamepad, we hide mouse hovering highlight until mouse is touched again. ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavId; // Focused item for navigation ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) @@ -2150,9 +2154,6 @@ struct ImGuiContext ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if io.ConfigNavMoveSetMousePos is set (not enabled by default) - bool NavCursorVisible; // Nav focus rectangle is visible? We hide it after a mouse click. We show it after a nav move. - //bool NavDisableHighlight; // Before 1.91.4 (2024/10/18) we used g.NavDisableHighlight. g.NavCursorVisible is the new variable name, with opposite value (g.NavDisableHighlight = !g.NavCursorVisible) - bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. // Navigation: Init & Move Requests bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e5f2acc8d..3b28daa4d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -625,7 +625,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Gamepad/Keyboard handling // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse. - if (g.NavId == id && g.NavCursorVisible && g.NavDisableMouseHover) + if (g.NavId == id && g.NavCursorVisible && g.NavHighlightItemUnderNav) if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) hovered = true; if (g.NavActivateDownId == id) @@ -4476,7 +4476,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags | ImGuiItemFlags_NoNavDisableMouseHover); if (hovered) SetMouseCursor(ImGuiMouseCursor_TextInput); - if (hovered && g.NavDisableMouseHover) + if (hovered && g.NavHighlightItemUnderNav) hovered = false; // We are only allowed to access the state if we are already the active widget. @@ -6628,7 +6628,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if ((flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 || (g.NavActivateId == id && !is_multi_select)) toggled = true; // Single click if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + toggled |= is_mouse_x_over_arrow && !g.NavHighlightItemUnderNav; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) toggled = true; // Double click } @@ -6998,7 +6998,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { - if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) g.NavCursorVisible = false; @@ -8625,7 +8625,7 @@ void ImGui::EndMenuBar() FocusWindow(window); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. - g.NavDisableMouseHover = g.NavMousePosDirty = true; + g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat } } @@ -8833,7 +8833,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) if (!enabled) EndDisabled(); - const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover; + const bool hovered = (g.HoveredId == id) && enabled && !g.NavHighlightItemUnderNav; if (menuset_is_open) PopItemFlag(); @@ -8868,7 +8868,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) - if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover && g.ActiveId == 0) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavHighlightItemUnderNav && g.ActiveId == 0) want_close = true; // Open From 634a7ed988682e0dbb415810ded2f8d86e4996e4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 17:06:30 +0200 Subject: [PATCH 18/21] Nav: added SetNavCursorVisible(). (#1074, #2048, #7237, #8059) + Further internal renaming for consistency. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 47 ++++++++++++++++++++++++++-------------------- imgui.h | 10 ++++++---- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 4 ++-- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 129709152..319530e0a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,8 @@ Other changes: state to draw callbacks. (#6969, #5834, #7468, #3590) - IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921) - Error Handling: turned a few more functions into recoverable errors. (#1651) +- Nav: added NavSetCursorVisible(bool visible) to manipulate visibility of keyboard/gamepad + navigation cursor. (#1074, #2048, #7237, #8059) - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. diff --git a/imgui.cpp b/imgui.cpp index 09acf5cd6..ba4a34121 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8558,7 +8558,7 @@ void ImGui::FocusItem() return; } - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavHighlight | ImGuiNavMoveFlags_NoSelect; + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavCursorVisible | ImGuiNavMoveFlags_NoSelect; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; SetNavWindow(window); NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags); @@ -8593,7 +8593,7 @@ void ImGui::SetKeyboardFocusHere(int offset) SetNavWindow(window); - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavHighlight; + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavCursorVisible; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. if (offset == -1) @@ -12209,6 +12209,20 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) // In our terminology those should be interchangeable, yet right now this is super confusing. // Those two functions are merely a legacy artifact, so at minimum naming should be clarified. +void ImGui::SetNavCursorVisible(bool visible) +{ + ImGuiContext& g = *GImGui; + g.NavCursorVisible = visible; +} + +// (was called NavRestoreHighlightAfterMove() before 1.91.4) +void ImGui::SetNavCursorVisibleAfterMove() +{ + ImGuiContext& g = *GImGui; + g.NavCursorVisible = true; + g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; +} + void ImGui::SetNavWindow(ImGuiWindow* window) { ImGuiContext& g = *GImGui; @@ -12735,13 +12749,6 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer) } } -void ImGui::NavRestoreHighlightAfterMove() -{ - ImGuiContext& g = *GImGui; - g.NavCursorVisible = true; - g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; -} - static inline void ImGui::NavUpdateAnyRequestFlag() { ImGuiContext& g = *GImGui; @@ -13050,7 +13057,7 @@ void ImGui::NavInitRequestApplyResult() if (result->SelectionUserData != ImGuiSelectionUserData_Invalid) g.NavLastValidSelectionUserData = result->SelectionUserData; if (g.NavInitRequestFromMove) - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); } // Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position @@ -13243,9 +13250,9 @@ void ImGui::NavMoveRequestApplyResult() if (result == NULL) { if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) - g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; - if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) - NavRestoreHighlightAfterMove(); + g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavCursorVisible; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavCursorVisible) == 0) + SetNavCursorVisibleAfterMove(); NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis. IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); return; @@ -13330,9 +13337,9 @@ void ImGui::NavMoveRequestApplyResult() g.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState | ImGuiActivateFlags_FromTabbing; } - // Enable nav highlight - if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) - NavRestoreHighlightAfterMove(); + // Make nav cursor visible + if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavCursorVisible) == 0) + SetNavCursorVisibleAfterMove(); } // Process Escape/NavCancel input (to close a popup, get back to parent, clear focus) @@ -13356,7 +13363,7 @@ static void ImGui::NavUpdateCancelRequest() { // Leave the "menu" layer NavRestoreLayer(ImGuiNavLayer_Main); - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); } else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow) { @@ -13366,7 +13373,7 @@ static void ImGui::NavUpdateCancelRequest() IM_ASSERT(child_window->ChildId != 0); FocusWindow(parent_window); SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_window->Rect())); - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); } else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) { @@ -13732,7 +13739,7 @@ static void ImGui::NavUpdateWindowing() if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) { ClearActiveID(); - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); ClosePopupsOverWindow(apply_focus_window, false); FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); apply_focus_window = g.NavWindow; @@ -13779,7 +13786,7 @@ static void ImGui::NavUpdateWindowing() if (new_nav_layer == ImGuiNavLayer_Menu) g.NavWindow->NavLastIds[new_nav_layer] = 0; NavRestoreLayer(new_nav_layer); - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); } } } diff --git a/imgui.h b/imgui.h index d89661bf2..c5ef6e935 100644 --- a/imgui.h +++ b/imgui.h @@ -900,10 +900,12 @@ namespace ImGui IMGUI_API void PopClipRect(); // Focus, Activation - // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" - IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of of a newly appearing window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + // Keyboard/Gamepad Navigation + IMGUI_API void SetNavCursorVisible(bool visible); // alter visibility of keyboard/gamepad cursor. by default: show when using an arrow key, hide when clicking with mouse. + // Overlapping mode IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. @@ -996,7 +998,7 @@ namespace ImGui // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. - // Inputs Utilities: Mouse specific + // Inputs Utilities: Mouse // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') @@ -1676,7 +1678,7 @@ enum ImGuiCol_ ImGuiCol_TextLink, // Hyperlink color ImGuiCol_TextSelectedBg, ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target - ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item + ImGuiCol_NavHighlight, // Color of gamepad/keyboard navigation cursor/rectangle, when visible ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active diff --git a/imgui_internal.h b/imgui_internal.h index 85ca13910..921263456 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1578,7 +1578,7 @@ enum ImGuiNavMoveFlags_ ImGuiNavMoveFlags_IsPageMove = 1 << 11, // Identify a PageDown/PageUp request. ImGuiNavMoveFlags_Activate = 1 << 12, // Activate/select target item. ImGuiNavMoveFlags_NoSelect = 1 << 13, // Don't trigger selection by not setting g.NavJustMovedTo - ImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14, // Do not alter the visible state of keyboard vs mouse nav highlight + ImGuiNavMoveFlags_NoSetNavCursorVisible = 1 << 14, // Do not alter the nav cursor visible state ImGuiNavMoveFlags_NoClearActiveId = 1 << 15, // (Experimental) Do not clear active id when applying move result }; @@ -3114,7 +3114,7 @@ namespace ImGui IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); IMGUI_API void NavHighlightActivated(ImGuiID id); IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis); - IMGUI_API void NavRestoreHighlightAfterMove(); + IMGUI_API void SetNavCursorVisibleAfterMove(); IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); IMGUI_API void SetNavWindow(ImGuiWindow* window); IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3b28daa4d..c3a61070b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7200,7 +7200,7 @@ int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, else idx = TypingSelectFindBestLeadingMatch(req, items_count, get_item_name_func, user_data); if (idx != -1) - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); return idx; } @@ -8883,7 +8883,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) { want_open = want_open_nav_init = true; NavMoveRequestCancel(); - NavRestoreHighlightAfterMove(); + SetNavCursorVisibleAfterMove(); } } else From 1ff9768aa30e2e4152144a68e0edcf7aefa4d0f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 17:12:00 +0200 Subject: [PATCH 19/21] Nav: (Breaking) renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor. (#1074, #2048, #7237, #8059, #1712, #7370, #787) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 7 ++++--- imgui.h | 3 ++- imgui_draw.cpp | 6 +++--- imgui_widgets.cpp | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 319530e0a..ca0c2a374 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ HOW TO UPDATE? Breaking changes: +- Style: renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor, for consistency with newly + exposed and reworked features. Kept inline redirection enum (will obsolete). - The typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641) - This removes the requirement to redefine it for backends which are e.g. storing descriptor sets or other 64-bits structures when building on 32-bits archs diff --git a/imgui.cpp b/imgui.cpp index ba4a34121..4a965898d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete). - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). kept legacy names (will obsolete) + code that copies settings once the first time. Dynamically changing the old value won't work. Switch to using the new value! @@ -3491,7 +3492,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_TextLink: return "TextLink"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; case ImGuiCol_DragDropTarget: return "DragDropTarget"; - case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavCursor: return "NavCursor"; case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; @@ -3715,7 +3716,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl const float thickness = 2.0f; if (flags & ImGuiNavRenderCursorFlags_Compact) { - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness); + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness); } else { @@ -3724,7 +3725,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl bool fully_visible = window->ClipRect.Contains(display_rect); if (!fully_visible) window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness); + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness); if (!fully_visible) window->DrawList->PopClipRect(); } diff --git a/imgui.h b/imgui.h index c5ef6e935..5cc9922ff 100644 --- a/imgui.h +++ b/imgui.h @@ -1678,7 +1678,7 @@ enum ImGuiCol_ ImGuiCol_TextLink, // Hyperlink color ImGuiCol_TextSelectedBg, ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target - ImGuiCol_NavHighlight, // Color of gamepad/keyboard navigation cursor/rectangle, when visible + ImGuiCol_NavCursor, // Color of gamepad/keyboard navigation cursor/rectangle, when visible ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active @@ -1688,6 +1688,7 @@ enum ImGuiCol_ ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9] ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9] ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9] + ImGuiCol_NavHighlight = ImGuiCol_NavCursor, // [renamed in 1.91.4] #endif }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index efee2ec9c..57b7d3ba2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -230,7 +230,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); @@ -293,7 +293,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); @@ -357,7 +357,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); - colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c3a61070b..ddfc263ef 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7399,7 +7399,7 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling - window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavHighlight)); // FIXME-MULTISELECT: Styling + window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT: Styling // Scroll const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; From 3982cb35dcf987ac278db35548d714c938bd4ab7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 17:26:20 +0200 Subject: [PATCH 20/21] Nav, Docs: consistently use "keyboard/gamepad" instead of sometimes "gamepad/keyboard". --- imgui.cpp | 31 +++++++++++++++++-------------- imgui.h | 24 +++++++++++++----------- imgui_demo.cpp | 2 +- imgui_internal.h | 12 ++++++------ imgui_widgets.cpp | 8 ++++---- 5 files changed, 41 insertions(+), 36 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4a965898d..c4388cedd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1400,6 +1400,13 @@ ImGuiIO::ImGuiIO() FontAllowUserScaling = false; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + // Keyboard/Gamepad Navigation options + ConfigNavSwapGamepadButtons = false; + ConfigNavMoveSetMousePos = false; + ConfigNavCaptureKeyboard = true; + ConfigNavEscapeClearFocusItem = true; + ConfigNavEscapeClearFocusWindow = false; + // Miscellaneous options MouseDrawCursor = false; #ifdef __APPLE__ @@ -1407,11 +1414,6 @@ ImGuiIO::ImGuiIO() #else ConfigMacOSXBehaviors = false; #endif - ConfigNavSwapGamepadButtons = false; - ConfigNavMoveSetMousePos = false; - ConfigNavCaptureKeyboard = true; - ConfigNavEscapeClearFocusItem = true; - ConfigNavEscapeClearFocusWindow = false; ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; ConfigInputTextEnterKeepActive = false; @@ -3900,8 +3902,13 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) CurrentItemFlags = ImGuiItemFlags_None; DebugShowGroupRects = false; + NavCursorVisible = false; + NavHighlightItemUnderNav = false; + NavMousePosDirty = false; + NavIdIsAlive = false; + NavId = 0; NavWindow = NULL; - NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; + NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; NavLayer = ImGuiNavLayer_Main; NavNextActivateId = 0; NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; @@ -3909,10 +3916,6 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) NavHighlightActivatedTimer = 0.0f; NavInputSource = ImGuiInputSource_Keyboard; NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; - NavIdIsAlive = false; - NavMousePosDirty = false; - NavCursorVisible = false; - NavHighlightItemUnderNav = false; NavAnyRequest = false; NavInitRequest = false; @@ -5197,7 +5200,7 @@ void ImGui::NewFrame() //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt)); //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper)); - // Update gamepad/keyboard navigation + // Update keyboard/gamepad navigation NavUpdate(); // Update mouse input state @@ -9777,7 +9780,7 @@ static void ImGui::UpdateMouseInputs() g.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f; //IMGUI_DEBUG_LOG("%.4f\n", g.MouseStationaryTimer); - // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + // If mouse moved we re-enable mouse hovering in case it was disabled by keyboard/gamepad. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) g.NavHighlightItemUnderNav = false; @@ -9816,7 +9819,7 @@ static void ImGui::UpdateMouseInputs() // We provide io.MouseDoubleClicked[] as a legacy service io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); - // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by keyboard/gamepad navigation if (io.MouseClicked[i]) g.NavHighlightItemUnderNav = false; } @@ -12310,7 +12313,7 @@ static float inline NavScoreItemDistInterval(float cand_min, float cand_max, flo return 0.0f; } -// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 +// Scoring function for keyboard/gamepad directional navigation. Based on https://gist.github.com/rygorous/6981057 static bool ImGui::NavScoreItem(ImGuiNavItemData* result) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 5cc9922ff..60bcbee6c 100644 --- a/imgui.h +++ b/imgui.h @@ -581,7 +581,7 @@ namespace ImGui // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. // - Format string may also be set to NULL or use the default format ("%f" or "%d"). - // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For keyboard/gamepad navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. @@ -1080,8 +1080,8 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) - ImGuiWindowFlags_NoNavInputs = 1 << 16, // No gamepad/keyboard navigation within the window - ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by CTRL+TAB) ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, @@ -1121,7 +1121,7 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. - ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. + ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow keyboard/gamepad navigation to cross over parent border to this child or between sibling child windows. // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -1328,7 +1328,7 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled - ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse + ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using keyboard/gamepad navigation state when active, always query mouse ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, @@ -1678,7 +1678,7 @@ enum ImGuiCol_ ImGuiCol_TextLink, // Hyperlink color ImGuiCol_TextSelectedBg, ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target - ImGuiCol_NavCursor, // Color of gamepad/keyboard navigation cursor/rectangle, when visible + ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active @@ -2230,7 +2230,7 @@ struct ImGuiIO // Configuration // Default value //------------------------------------------------------------------ - ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc. ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame. float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. @@ -2246,15 +2246,17 @@ struct ImGuiIO ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. - // Miscellaneous options - // (you can visualize and interact with all options in 'Demo->Configuration') - bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + // Keyboard/Gamepad Navigation options bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). + + // Miscellaneous options + // (you can visualize and interact with all options in 'Demo->Configuration') + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 63f6d15d1..c484dd48c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1012,7 +1012,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // The following examples are passed for documentation purpose but may not be useful to most users. // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used. + // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. ImGui::Button("Manual", sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) diff --git a/imgui_internal.h b/imgui_internal.h index 921263456..bca327cdf 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -141,7 +141,7 @@ struct ImGuiLocEntry; // A localization entry. struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiMultiSelectState; // Multi-selection persistent state (for focused selection). struct ImGuiMultiSelectTempData; // Multi-selection temporary state (while traversing). -struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiNavItemData; // Result of a keyboard/gamepad directional navigation move query result struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions @@ -2132,13 +2132,15 @@ struct ImGuiContext // Viewports ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. - // Gamepad/keyboard Navigation + // Keyboard/Gamepad Navigation bool NavCursorVisible; // Nav focus cursor/rectangle is visible? We hide it after a mouse click. We show it after a nav move. bool NavHighlightItemUnderNav; // Disable mouse hovering highlight. Highlight navigation focused item instead of mouse hovered item. //bool NavDisableHighlight; // Old name for !g.NavCursorVisible before 1.91.4 (2024/10/18). OPPOSITE VALUE (g.NavDisableHighlight == !g.NavCursorVisible) //bool NavDisableMouseHover; // Old name for g.NavHighlightItemUnderNav before 1.91.1 (2024/10/18) this was called When user starts using keyboard/gamepad, we hide mouse hovering highlight until mouse is touched again. - ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' + bool NavMousePosDirty; // When set we will update mouse position if io.ConfigNavMoveSetMousePos is set (not enabled by default) + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid ImGuiID NavId; // Focused item for navigation + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer) ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() @@ -2152,8 +2154,6 @@ struct ImGuiContext ImGuiActivateFlags NavNextActivateFlags; ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. - bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid - bool NavMousePosDirty; // When set we will update mouse position if io.ConfigNavMoveSetMousePos is set (not enabled by default) // Navigation: Init & Move Requests bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() @@ -3101,7 +3101,7 @@ namespace ImGui IMGUI_API bool BeginComboPreview(); IMGUI_API void EndComboPreview(); - // Gamepad/Keyboard Navigation + // Keyboard/Gamepad Navigation IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); IMGUI_API void NavInitRequestApplyResult(); IMGUI_API bool NavMoveRequestButNoResultYet(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ddfc263ef..e0bc7f747 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -623,7 +623,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.NavCursorVisible = false; } - // Gamepad/Keyboard handling + // Keyboard/Gamepad navigation handling // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse. if (g.NavId == id && g.NavCursorVisible && g.NavHighlightItemUnderNav) if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) @@ -3049,14 +3049,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; if (decimal_precision > 0) { - input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + input_delta /= 100.0f; // Keyboard/Gamepad tweak speeds in % of slider bounds if (tweak_slow) input_delta /= 10.0f; } else { 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 + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Keyboard/Gamepad tweak speeds in integer steps else input_delta /= 100.0f; } @@ -6995,7 +6995,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl selected = pressed = true; } - // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with keyboard/gamepad if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) From ab9ce2a927ab0688c97f7fefadb49d84e41df346 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Oct 2024 18:28:27 +0200 Subject: [PATCH 21/21] Nav: added io.ConfigNavCursorVisibleAuto, io.ConfigNavCursorVisibleAlways. (#1074, #2048, #7237, #8059, #3200, #787) Note: the NavCursorHideFrames addition is to support 88a354585 even though ConfigNavCursorVisibleAlways is set. --- docs/CHANGELOG.txt | 34 ++++++++++++++++++++-------------- docs/TODO.txt | 1 - imgui.cpp | 21 +++++++++++++++++---- imgui.h | 2 ++ imgui_demo.cpp | 6 +++++- imgui_internal.h | 1 + imgui_widgets.cpp | 14 ++++++++++---- 7 files changed, 55 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ca0c2a374..3279969a2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,20 +69,26 @@ Other changes: state to draw callbacks. (#6969, #5834, #7468, #3590) - IO: WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921) - Error Handling: turned a few more functions into recoverable errors. (#1651) -- Nav: added NavSetCursorVisible(bool visible) to manipulate visibility of keyboard/gamepad - navigation cursor. (#1074, #2048, #7237, #8059) -- Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change - how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) - - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. - - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect. - - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, - is for some reason your app relies on imgui focus to take other decisions. -- Nav: pressing escape to hide nav highlight doesn't clear location from when ctrl+tabbing - back into same window later. -- Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most - window. (#3200) -- Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant - when e.g activating the item with mouse, then Ctrl+Tabbing back and forth. +- Nav (Keyboard/Gamepad navigation): + - Nav: added io.ConfigNavCursorVisibleAuto and io.ConfigNavCursorVisibleAlways to configure + visibility of navigation cursor. (#1074, #2048, #7237, #8059, #3200, #787) + - Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling + of cursor visibility (mouse click hide the cursor, arrow keys makes it visible). + - Set io.ConfigNavCursorVisibleAlways to keep cursor always visible. + - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of + navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059) + - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change + how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) + - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. + - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have a specific effect. + - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, + is for some reason your app relies on imgui focus to take other decisions. + - Nav: pressing escape to hide nav highlight doesn't clear location from when Ctrl+Tabbing + back into same window later. + - Nav: fixed Ctrl+Tab so when starting with no focused window it starts from the top-most + window. (#3200) + - Nav: rectangle highlight not rendered for items with ImGuiItemFlags_NoNav. Can be relevant + when e.g activating the item with mouse, then Ctrl+Tabbing back and forth. - Disabled: clicking a disabled item focuses parent window. (#8064) - InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but not display navigation highlight. Properly navigation on it by default. (#8057) diff --git a/docs/TODO.txt b/docs/TODO.txt index dd98d18b1..2a42874cd 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -274,7 +274,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) - ! nav: never clear NavId on some setup (e.g. gamepad centric) - nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view? - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window" - nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). diff --git a/imgui.cpp b/imgui.cpp index c4388cedd..0ebd61dc5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1406,6 +1406,8 @@ ImGuiIO::ImGuiIO() ConfigNavCaptureKeyboard = true; ConfigNavEscapeClearFocusItem = true; ConfigNavEscapeClearFocusWindow = false; + ConfigNavCursorVisibleAuto = true; + ConfigNavCursorVisibleAlways = false; // Miscellaneous options MouseDrawCursor = false; @@ -3916,6 +3918,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) NavHighlightActivatedTimer = 0.0f; NavInputSource = ImGuiInputSource_Keyboard; NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; + NavCursorHideFrames = 0; NavAnyRequest = false; NavInitRequest = false; @@ -4828,7 +4831,8 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) ImGuiContext& g = *GImGui; FocusWindow(window); SetActiveID(window->MoveId, window); - g.NavCursorVisible = false; + if (g.IO.ConfigNavCursorVisibleAuto) + g.NavCursorVisible = false; g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; g.ActiveIdNoClearOnFocusLoss = true; SetActiveIdUsingAllKeyboardKeys(); @@ -12216,6 +12220,8 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) void ImGui::SetNavCursorVisible(bool visible) { ImGuiContext& g = *GImGui; + if (g.IO.ConfigNavCursorVisibleAlways) + visible = true; g.NavCursorVisible = visible; } @@ -12223,7 +12229,8 @@ void ImGui::SetNavCursorVisible(bool visible) void ImGui::SetNavCursorVisibleAfterMove() { ImGuiContext& g = *GImGui; - g.NavCursorVisible = true; + if (g.IO.ConfigNavCursorVisibleAuto) + g.NavCursorVisible = true; g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; } @@ -12289,7 +12296,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) g.NavHighlightItemUnderNav = true; - else + else if (g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = false; // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) @@ -12904,6 +12911,9 @@ static void ImGui::NavUpdate() NavMoveRequestApplyResult(); g.NavTabbingCounter = 0; g.NavMoveSubmitted = g.NavMoveScoringItems = false; + if (g.NavCursorHideFrames > 0) + if (--g.NavCursorHideFrames == 0) + g.NavCursorVisible = true; // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) bool set_mouse_pos = false; @@ -12958,6 +12968,8 @@ static void ImGui::NavUpdate() } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) g.NavCursorVisible = false; + else if (g.IO.ConfigNavCursorVisibleAlways && g.NavCursorHideFrames == 0) + g.NavCursorVisible = true; if (g.NavActivateId != 0) IM_ASSERT(g.NavActivateDownId == g.NavActivateId); @@ -13158,7 +13170,8 @@ void ImGui::NavUpdateCreateMoveRequest() IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitResult.ID = 0; - g.NavCursorVisible = true; + if (g.IO.ConfigNavCursorVisibleAuto) + g.NavCursorVisible = true; } // When using gamepad, we project the reference nav bounding box into window visible area. diff --git a/imgui.h b/imgui.h index 60bcbee6c..73705cd36 100644 --- a/imgui.h +++ b/imgui.h @@ -2252,6 +2252,8 @@ struct ImGuiIO bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). + bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. + bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. // Miscellaneous options // (you can visualize and interact with all options in 'Demo->Configuration') diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c484dd48c..668c5c0ee 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -527,7 +527,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); - ImGui::SeparatorText("Navigation"); + ImGui::SeparatorText("Keyboard/Gamepad Navigation"); ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons); ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); @@ -536,6 +536,10 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); + ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto); + ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor."); + ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); + ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); diff --git a/imgui_internal.h b/imgui_internal.h index bca327cdf..97a51a355 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2154,6 +2154,7 @@ struct ImGuiContext ImGuiActivateFlags NavNextActivateFlags; ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. + ImS8 NavCursorHideFrames; // Navigation: Init & Move Requests bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e0bc7f747..307e11d5b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -619,7 +619,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool pressed = true; } - if (pressed) + if (pressed && g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = false; } @@ -688,7 +688,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } ClearActiveID(); } - if (!(flags & ImGuiButtonFlags_NoNavFocus)) + if (!(flags & ImGuiButtonFlags_NoNavFocus) && g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = false; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) @@ -7001,7 +7001,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) - g.NavCursorVisible = false; + if (g.IO.ConfigNavCursorVisibleAuto) + g.NavCursorVisible = false; } } if (pressed) @@ -8624,7 +8625,12 @@ void ImGui::EndMenuBar() IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) FocusWindow(window); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); - g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. + // FIXME-NAV: How to deal with this when not using g.IO.ConfigNavCursorVisibleAuto? + if (g.NavCursorVisible) + { + g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. Will be set again + g.NavCursorHideFrames = 2; + } g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat }