From a89590b4259b91de57f8417109f8ebc299bdb5ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Apr 2023 10:38:45 +0200 Subject: [PATCH 1/8] Backends: Win32: revert accidental deletion of ImGui_ImplWin32_EnableAlphaCompositing() in a566ecc (#3218) --- backends/imgui_impl_win32.cpp | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 363e016d8..c347a871c 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -817,3 +817,45 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST); return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); } + +//--------------------------------------------------------------------------------------------------------- +// Transparency related helpers (optional) +//-------------------------------------------------------------------------------------------------------- + +#if defined(_MSC_VER) +#pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi' +#endif + +// [experimental] +// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c +// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW) +void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd) +{ + if (!_IsWindowsVistaOrGreater()) + return; + + BOOL composition; + if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition) + return; + + BOOL opaque; + DWORD color; + if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) + { + HRGN region = ::CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + ::DeleteObject(region); + } + else + { + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + } +} + +//--------------------------------------------------------------------------------------------------------- From 662ce46971955586f4c6fb13c8c8e53d76e3232d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Apr 2023 14:52:59 +0200 Subject: [PATCH 2/8] Debug Log: Fixed not parsing 0xXXXXXXXX values when the identifier is at the end of the line. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a887cb5a0..9f5d1860b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,8 @@ Other changes: showing when a sorting column has no visible name. (#6342) [@lukaasm] - InputText: Avoid setting io.WantTextInputNextFrame during the deactivation frame. (#6341) [@lukaasm] +- Debug Tools: Debug Log: Fixed not parsing 0xXXXXXXXX values for geo-locating on mouse + hover hover when the identifier is at the end of the line. (#5855) - Backends: Clear bits sets io.BackendFlags on backend Shutdown(). (#6334, #6335] [@GereonV] Potentially this would facilitate switching runtime backend mid-session. - Backends: Win32: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw diff --git a/imgui.cpp b/imgui.cpp index cdd4219a1..80e82a16f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14390,7 +14390,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) TextUnformatted(line_begin, line_end); ImRect text_rect = g.LastItemData.Rect; if (IsItemHovered()) - for (const char* p = line_begin; p < line_end - 10; p++) + for (const char* p = line_begin; p <= line_end - 10; p++) { ImGuiID id = 0; if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) From 8d9e50c807ba3cfbcd741bf30cc28feeed46f7f2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Apr 2023 14:53:55 +0200 Subject: [PATCH 3/8] Nav: fixed IMGUI_DEBUG_NAV_SCORING not setting NavMoveClipDir, leading to debug result not matching real results. --- imgui.cpp | 29 +++++++++++++++++------------ imgui_internal.h | 4 ++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 80e82a16f..62ff79135 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5312,7 +5312,8 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b parent_window->DC.CursorPos = child_window->Pos; // Process navigation-in immediately so NavInit can run on first frame - if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll)) + // Can enter a child if (A) it has navigatable items or (B) it can be scrolled. + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY)) { FocusWindow(child_window); NavInitWindow(child_window, false); @@ -5359,7 +5360,7 @@ void ImGui::EndChild() ImGuiWindow* parent_window = g.CurrentWindow; ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); ItemSize(sz); - if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavWindowHasScrollY) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) { ItemAdd(bb, window->ChildId); RenderNavHighlight(bb, window->ChildId); @@ -6670,7 +6671,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; window->DC.NavLayersActiveMaskNext = 0x00; window->DC.NavHideHighlightOneFrame = false; - window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); + window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f); window->DC.MenuBarAppending = false; window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); @@ -9368,6 +9369,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu DebugLocateItemResolveWithLastItem(); #endif //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) + // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) if (is_rect_visible) @@ -10651,12 +10654,12 @@ ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; } -static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) +static float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max) { - if (a1 < b0) - return a1 - b0; - if (b1 < a0) - return a0 - b1; + if (cand_max < curr_min) + return cand_max - curr_min; + if (curr_max < cand_min) + return cand_min - curr_max; return 0.0f; } @@ -10738,11 +10741,12 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result) quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; } + const ImGuiDir move_dir = g.NavMoveDir; #if IMGUI_DEBUG_NAV_SCORING char buf[200]; if (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate. { - if (quadrant == g.NavMoveDir) + if (quadrant == move_dir) { ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); ImDrawList* draw_list = GetForegroundDrawList(window); @@ -10766,7 +10770,6 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result) // Is it in the quadrant we're interested in moving to? bool new_best = false; - const ImGuiDir move_dir = g.NavMoveDir; if (quadrant == move_dir) { // Does it beat the current best candidate? @@ -11271,7 +11274,7 @@ static void ImGui::NavUpdate() ImGuiWindow* window = g.NavWindow; const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. const ImGuiDir move_dir = g.NavMoveDir; - if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None) + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) { if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); @@ -11389,6 +11392,7 @@ void ImGui::NavUpdateCreateMoveRequest() { if (g.NavMoveDir == ImGuiDir_None) g.NavMoveDir = g.NavMoveDirForDebug; + g.NavMoveClipDir = g.NavMoveDir; g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; } #endif @@ -11502,6 +11506,7 @@ void ImGui::NavMoveRequestApplyResult() g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) NavRestoreHighlightAfterMove(); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); return; } @@ -11638,7 +11643,7 @@ static float ImGui::NavUpdatePageUpPageDown() if (g.NavLayer != ImGuiNavLayer_Main) NavRestoreLayer(ImGuiNavLayer_Main); - if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY) { // Fallback manual-scroll when window has no navigable item if (IsKeyPressed(ImGuiKey_PageUp, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) diff --git a/imgui_internal.h b/imgui_internal.h index e17aaa401..e9f315fb3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2226,14 +2226,14 @@ struct IMGUI_API ImGuiWindowTempData ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. ImVec1 GroupOffset; - ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensentate and fix the most common use case of large scroll area. + ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensate and fix the most common use case of large scroll area. // Keyboard/Gamepad navigation ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) short NavLayersActiveMask; // Which layers have been written to (result from previous frame) short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) bool NavHideHighlightOneFrame; - bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) + bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) // Miscellaneous bool MenuBarAppending; // FIXME: Remove this From 00d3f9295e5caf417886572266bebb490ad3577b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Apr 2023 16:24:14 +0200 Subject: [PATCH 4/8] Nav: Fixed navigation within tables/columns where item boundaries goes beyond columns limits. (#2221) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 26 +++++++++++++++++++++++--- imgui.h | 2 +- imgui_internal.h | 2 ++ imgui_tables.cpp | 4 ++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9f5d1860b..0e91bb116 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,8 @@ Other changes: showing when a sorting column has no visible name. (#6342) [@lukaasm] - InputText: Avoid setting io.WantTextInputNextFrame during the deactivation frame. (#6341) [@lukaasm] +- Nav: Fixed navigation within tables/columns where item boundaries goes beyond columns limits, + unclipped bounding boxes would interfere with other columns. (#2221) [@zzzyap, @ocornut] - Debug Tools: Debug Log: Fixed not parsing 0xXXXXXXXX values for geo-locating on mouse hover hover when the identifier is at the end of the line. (#5855) - Backends: Clear bits sets io.BackendFlags on backend Shutdown(). (#6334, #6335] [@GereonV] diff --git a/imgui.cpp b/imgui.cpp index 62ff79135..4687f95cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3743,7 +3743,10 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentWindow = window; g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; if (window) + { g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); + ImGui::NavUpdateCurrentWindowIsScrollPushableX(); + } } void ImGui::GcCompactTransientMiscBuffers() @@ -6670,6 +6673,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; window->DC.NavLayersActiveMaskNext = 0x00; + window->DC.NavIsScrollPushableX = true; window->DC.NavHideHighlightOneFrame = false; window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f); @@ -10825,6 +10829,15 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); } +// True when current work location may be scrolled horizontally when moving left / right. +// This is generally always true UNLESS within a column. We don't have a vertical equivalent. +void ImGui::NavUpdateCurrentWindowIsScrollPushableX() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL); +} + // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) // This is called after LastItemData is set. static void ImGui::NavProcessItem() @@ -10832,9 +10845,16 @@ static void ImGui::NavProcessItem() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = g.LastItemData.ID; - const ImRect nav_bb = g.LastItemData.NavRect; const ImGuiItemFlags item_flags = g.LastItemData.InFlags; + // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) + if (window->DC.NavIsScrollPushableX == false) + { + g.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + g.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + } + const ImRect nav_bb = g.LastItemData.NavRect; + // Process Init Request if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0) { @@ -10876,7 +10896,7 @@ static void ImGui::NavProcessItem() } } - // Update window-relative bounding box of navigated item + // Update information for currently focused/navigated item if (g.NavId == id) { if (g.NavWindow != window) @@ -10884,7 +10904,7 @@ static void ImGui::NavProcessItem() g.NavLayer = window->DC.NavLayerCurrent; g.NavFocusScopeId = g.CurrentFocusScopeId; g.NavIdIsAlive = true; - window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) + window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) } } diff --git a/imgui.h b/imgui.h index 0e1c3951f..3b8fb2eda 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.6 WIP" -#define IMGUI_VERSION_NUM 18951 +#define IMGUI_VERSION_NUM 18952 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index e9f315fb3..02dc3edf4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2232,6 +2232,7 @@ struct IMGUI_API ImGuiWindowTempData ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) short NavLayersActiveMask; // Which layers have been written to (result from previous frame) short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) + bool NavIsScrollPushableX; // Set when current work location may be scrolled horizontally when moving left / right. This is generally always true UNLESS within a column. bool NavHideHighlightOneFrame; bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) @@ -2894,6 +2895,7 @@ namespace ImGui IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. 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_tables.cpp b/imgui_tables.cpp index 012235a3b..ea0367416 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -483,6 +483,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Make table current g.CurrentTable = table; + outer_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); outer_window->DC.CurrentTableIdx = table_idx; if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. inner_window->DC.CurrentTableIdx = table_idx; @@ -1436,6 +1437,7 @@ void ImGui::EndTable() g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; } outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; + NavUpdateCurrentWindowIsScrollPushableX(); } // See "COLUMN SIZING POLICIES" comments at the top of this file @@ -3902,6 +3904,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFl columns->Count = columns_count; columns->Flags = flags; window->DC.CurrentColumns = columns; + window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); columns->HostCursorPosY = window->DC.CursorPos.y; columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; @@ -4092,6 +4095,7 @@ void ImGui::EndColumns() window->DC.CurrentColumns = NULL; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + NavUpdateCurrentWindowIsScrollPushableX(); } void ImGui::Columns(int columns_count, const char* id, bool border) From f0fe1957a8ac43e4882c8b276c1b87a631e84592 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Apr 2023 19:05:58 +0200 Subject: [PATCH 5/8] Focus: merge extra param for FocusTopMostWindowUnderOne() from docking branch to facilitate merge. --- imgui.cpp | 22 ++++++++++++---------- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4687f95cd..c892a00c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4624,7 +4624,7 @@ void ImGui::NewFrame() // Closing the focused window restore focus to the first active root window in descending z-order if (g.NavWindow && !g.NavWindow->WasActive) - FocusTopMostWindowUnderOne(NULL, NULL); + FocusTopMostWindowUnderOne(NULL, NULL, NULL); // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. @@ -6968,9 +6968,10 @@ void ImGui::FocusWindow(ImGuiWindow* window) BringWindowToDisplayFront(display_front_window); } -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport) { ImGuiContext& g = *GImGui; + IM_UNUSED(filter_viewport); // Unused in master branch. int start_idx = g.WindowsFocusOrder.Size - 1; if (under_this_window != NULL) { @@ -6988,13 +6989,14 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. ImGuiWindow* window = g.WindowsFocusOrder[i]; IM_ASSERT(window == window->RootWindow); - if (window != ignore_window && window->WasActive) - if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) - { - ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); - FocusWindow(focus_window); - return; - } + if (window == ignore_window || !window->WasActive) + continue; + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } } FocusWindow(NULL); } @@ -10261,7 +10263,7 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ if (focus_window && !focus_window->WasActive && popup_window) { // Fallback - FocusTopMostWindowUnderOne(popup_window, NULL); + FocusTopMostWindowUnderOne(popup_window, NULL, NULL); } else { diff --git a/imgui_internal.h b/imgui_internal.h index 02dc3edf4..a74572be7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2752,7 +2752,7 @@ namespace ImGui // Windows: Display Order and Focus Order IMGUI_API void FocusWindow(ImGuiWindow* window); - IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport); IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ed38787de..337e01580 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7084,7 +7084,7 @@ void ImGui::EndMainMenuBar() // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL); + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL); End(); } From 30eceaf95fe227a466bc5cd78afde1ac8e1b07ca Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Apr 2023 17:30:05 +0200 Subject: [PATCH 6/8] Focus: start moving modal check into FocusWindow(), add ImGuiFocusRequestFlags_UnlessBelowModal (currently opt-in, should try to make opt-out). (#6357, #4317) --- imgui.cpp | 33 ++++++++++++++++++++++----------- imgui_internal.h | 15 +++++++++++++-- imgui_widgets.cpp | 2 +- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c892a00c5..844932913 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1056,7 +1056,6 @@ static void RenderWindowDecorations(ImGuiWindow* window, const ImRec static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); -static ImGuiWindow* FindBlockingModal(ImGuiWindow* window); // Viewports static void UpdateViewportsNewFrame(); @@ -3911,7 +3910,7 @@ bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flag // Inhibit hover unless the window is within the stack of our modal/popup if (want_inhibit) - if (!ImGui::IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) + if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) return false; } return true; @@ -4296,10 +4295,10 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (g.HoveredIdDisabled) g.MovingWindow = NULL; } - else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL) + else if (root_window == NULL && g.NavWindow != NULL) { // Clicking on void disable focus - FocusWindow(NULL); + FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal); } } @@ -4624,7 +4623,7 @@ void ImGui::NewFrame() // Closing the focused window restore focus to the first active root window in descending z-order if (g.NavWindow && !g.NavWindow->WasActive) - FocusTopMostWindowUnderOne(NULL, NULL, NULL); + FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_None); // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. @@ -6077,7 +6076,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags // - Window // .. returns Modal2 // - Window // .. returns Modal2 // - Modal2 // .. returns Modal2 -static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) { ImGuiContext& g = *GImGui; if (g.OpenPopupStack.Size <= 0) @@ -6091,6 +6090,8 @@ static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) continue; if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. continue; + if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. + return popup_window; if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. break; for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow) @@ -6928,10 +6929,19 @@ int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) } // Moving window to front of display and set focus (which happens to be back of our sorted list) -void ImGui::FocusWindow(ImGuiWindow* window) +void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) { ImGuiContext& g = *GImGui; + // Modal check? + if (flags & ImGuiFocusRequestFlags_UnlessBelowModal) + if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + return; + } + + // Apply focus if (g.NavWindow != window) { SetNavWindow(window); @@ -6968,7 +6978,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) BringWindowToDisplayFront(display_front_window); } -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport) +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) { ImGuiContext& g = *GImGui; IM_UNUSED(filter_viewport); // Unused in master branch. @@ -6994,11 +7004,11 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) { ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); - FocusWindow(focus_window); + FocusWindow(focus_window, flags); return; } } - FocusWindow(NULL); + FocusWindow(NULL, flags); } // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. @@ -10101,6 +10111,7 @@ bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) return IsPopupOpen(id, popup_flags); } +// FIXME: In principle we should converge toward replacing calls to GetTopMostPopupModal() + IsWindowWithinBeginStackOf() with calls to FindBlockingModal() ImGuiWindow* ImGui::GetTopMostPopupModal() { ImGuiContext& g = *GImGui; @@ -10263,7 +10274,7 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ if (focus_window && !focus_window->WasActive && popup_window) { // Fallback - FocusTopMostWindowUnderOne(popup_window, NULL, NULL); + FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_None); } else { diff --git a/imgui_internal.h b/imgui_internal.h index a74572be7..5e71419b1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -164,6 +164,7 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E // Flags typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags +typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow(); typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for IsKeyPressed(), IsMouseClicked(), SetKeyOwner(), SetItemKeyOwner() etc. typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags @@ -906,6 +907,15 @@ enum ImGuiSeparatorFlags_ ImGuiSeparatorFlags_SpanAllColumns = 1 << 2, }; +// Flags for FocusWindow(). This is not called ImGuiFocusFlags to avoid confusion with public-facing ImGuiFocusedFlags. +// FIXME: Once we finishing replacing more uses of GetTopMostPopupModal()+IsWindowWithinBeginStackOf() +// and FindBlockingModal() with this, we may want to change the flag to be opt-out instead of opt-in. +enum ImGuiFocusRequestFlags_ +{ + ImGuiFocusRequestFlags_None = 0, + ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 0, // Do not set focus if the window is below a modal. +}; + enum ImGuiTextFlags_ { ImGuiTextFlags_None = 0, @@ -2751,8 +2761,8 @@ namespace ImGui inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } // Windows: Display Order and Focus Order - IMGUI_API void FocusWindow(ImGuiWindow* window); - IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport); + IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags); IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); @@ -2872,6 +2882,7 @@ namespace ImGui IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImGuiWindow* GetTopMostPopupModal(); IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); + IMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 337e01580..fb445b99b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7084,7 +7084,7 @@ void ImGui::EndMainMenuBar() // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL); + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal); End(); } From 01ca196530490756e3f722ddc33046054dc8f9ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Apr 2023 17:46:41 +0200 Subject: [PATCH 7/8] Focus: move focused child restore code in FocusWindow() with ImGuiFocusRequestFlags_RestoreFocusedChild flag. (#6357) # Conflicts: # imgui.cpp --- imgui.cpp | 26 +++++++++++--------------- imgui_internal.h | 3 ++- imgui_widgets.cpp | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 844932913..9de7c9b36 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4623,7 +4623,7 @@ void ImGui::NewFrame() // Closing the focused window restore focus to the first active root window in descending z-order if (g.NavWindow && !g.NavWindow->WasActive) - FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_None); + FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. @@ -6941,6 +6941,10 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) return; } + // Find last focused child (if any) and focus it instead. + if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) + window = NavRestoreLastChildNavWindow(window); + // Apply focus if (g.NavWindow != window) { @@ -7003,8 +7007,7 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind continue; if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) { - ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); - FocusWindow(focus_window, flags); + FocusWindow(window, flags); return; } } @@ -10272,16 +10275,9 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ { ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window; if (focus_window && !focus_window->WasActive && popup_window) - { - // Fallback - FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_None); - } + FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback else - { - if (g.NavLayer == ImGuiNavLayer_Main && focus_window) - focus_window = NavRestoreLastChildNavWindow(focus_window); - FocusWindow(focus_window); - } + FocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None); } } @@ -11854,7 +11850,7 @@ static void ImGui::NavUpdateWindowing() bool apply_toggle_layer = false; ImGuiWindow* modal_window = GetTopMostPopupModal(); - bool allow_windowing = (modal_window == NULL); + bool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows over a popup if (!allow_windowing) g.NavWindowingTarget = NULL; @@ -11983,9 +11979,9 @@ static void ImGui::NavUpdateWindowing() { ClearActiveID(); NavRestoreHighlightAfterMove(); - apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); ClosePopupsOverWindow(apply_focus_window, false); - FocusWindow(apply_focus_window); + FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); + apply_focus_window = g.NavWindow; if (apply_focus_window->NavLastIds[0] == 0) NavInitWindow(apply_focus_window, false); diff --git a/imgui_internal.h b/imgui_internal.h index 5e71419b1..900d5cf68 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -913,7 +913,8 @@ enum ImGuiSeparatorFlags_ enum ImGuiFocusRequestFlags_ { ImGuiFocusRequestFlags_None = 0, - ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 0, // Do not set focus if the window is below a modal. + ImGuiFocusRequestFlags_RestoreFocusedChild = 1 << 0, // Find last focused child (if any) and focus it instead. + ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 1, // Do not set focus if the window is below a modal. }; enum ImGuiTextFlags_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fb445b99b..3a2e6c269 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7084,7 +7084,7 @@ void ImGui::EndMainMenuBar() // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) - FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal); + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); End(); } From 4d42450a73918bbf25214218a74a281ae19429a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Apr 2023 18:09:48 +0200 Subject: [PATCH 8/8] Focus: amend ImGuiFocusRequestFlags_UnlessBelowModal to bring to front-most below the modal, simplify code in Begin(). (#6357, #4317) --- imgui.cpp | 34 +++++++++++++--------------------- imgui.h | 2 +- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9de7c9b36..9f25ed049 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6076,6 +6076,9 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags // - Window // .. returns Modal2 // - Window // .. returns Modal2 // - Modal2 // .. returns Modal2 +// Notes: +// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. +// Only difference is here we check for ->Active/WasActive but it may be unecessary. ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) { ImGuiContext& g = *GImGui; @@ -6466,22 +6469,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) want_focus = true; else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) want_focus = true; - - ImGuiWindow* modal = GetTopMostPopupModal(); - if (modal != NULL && !IsWindowWithinBeginStackOf(window, modal)) - { - // Avoid focusing a window that is created outside of active modal. This will prevent active modal from being closed. - // Since window is not focused it would reappear at the same display position like the last time it was visible. - // In case of completely new windows it would go to the top (over current modal), but input to such window would still be blocked by modal. - // Position window behind a modal that is not a begin-parent of this window. - want_focus = false; - if (window == window->RootWindow) - { - ImGuiWindow* blocking_modal = FindBlockingModal(window); - IM_ASSERT(blocking_modal != NULL); - BringWindowToDisplayBehind(window, blocking_modal); - } - } } // [Test Engine] Register whole window in the item system (before submitting further decorations) @@ -6699,11 +6686,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->AutoFitFramesY--; // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + // We ImGuiFocusRequestFlags_UnlessBelowModal to: + // - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed. + // - Position window behind the modal that is not a begin-parent of this window. if (want_focus) - { - FocusWindow(window); + FocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal); + if (want_focus && window == g.NavWindow) NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls - } // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) @@ -6938,6 +6927,8 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) { IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal. return; } @@ -10114,7 +10105,7 @@ bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) return IsPopupOpen(id, popup_flags); } -// FIXME: In principle we should converge toward replacing calls to GetTopMostPopupModal() + IsWindowWithinBeginStackOf() with calls to FindBlockingModal() +// Also see FindBlockingModal(NULL) ImGuiWindow* ImGui::GetTopMostPopupModal() { ImGuiContext& g = *GImGui; @@ -10125,6 +10116,7 @@ ImGuiWindow* ImGui::GetTopMostPopupModal() return NULL; } +// See Demo->Stacked Modal to confirm what this is for. ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() { ImGuiContext& g = *GImGui; @@ -10253,7 +10245,7 @@ void ImGui::ClosePopupsExceptModals() for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--) { ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window; - if (!window || window->Flags & ImGuiWindowFlags_Modal) + if (!window || (window->Flags & ImGuiWindowFlags_Modal)) break; } if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below diff --git a/imgui.h b/imgui.h index 3b8fb2eda..f787bf0b4 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.6 WIP" -#define IMGUI_VERSION_NUM 18952 +#define IMGUI_VERSION_NUM 18953 #define IMGUI_HAS_TABLE /*