From 40f9e4e8e2ff3204021182726a8c0f18db68e213 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Oct 2025 18:32:35 +0100 Subject: [PATCH] Windows: store BgClickFlags which allows the equivalent of io.ConfigWindowsMoveFromTitleBarOnly to be overridden on a per window basis. (#899, #3071, #5044, + #3379) io.ConfigWindowsMoveFromTitleBarOnly now sets initial value for BgClickFlags. Using e.g. ImGui::GetCurrentWindow()->BgClickFlags &= ~ImGuiWindowBgClickFlags_Move; allow per-window override. This will be extended for supporting scrolling options for #3379. As a minor side effect: the effect of enabling io.ConfigWindowsMoveFromTitleBarOnly now happens one frame later ('window_modal_bounds_exceeding_work_area" test accidentally broke in some situations because of that) --- imgui.cpp | 12 ++++++++---- imgui_internal.h | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 63ceb9311..14e90ada1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5217,7 +5217,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symetrical, at the later doesn't clear ActiveId. // Cancel moving if clicked outside of title bar - if (g.IO.ConfigWindowsMoveFromTitleBarOnly) + if ((hovered_window->BgClickFlags & ImGuiWindowBgClickFlags_Move) == 0) // set by io.ConfigWindowsMoveFromTitleBarOnly if (!(hovered_root->Flags & ImGuiWindowFlags_NoTitleBar)) if (!hovered_root->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; @@ -6768,7 +6768,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si const float grip_hover_outer_size = g.WindowsBorderHoverPadding; ImRect clamp_rect = visibility_rect; - const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar); + const bool window_move_from_title_bar = !(window->BgClickFlags & ImGuiWindowBgClickFlags_Move) && !(window->Flags & ImGuiWindowFlags_NoTitleBar); if (window_move_from_title_bar) clamp_rect.Min.y -= window->TitleBarHeight; @@ -6957,9 +6957,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect) { - ImGuiContext& g = *GImGui; ImVec2 size_for_clamping = window->Size; - if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!(window->BgClickFlags & ImGuiWindowBgClickFlags_Move) && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) size_for_clamping.y = window->TitleBarHeight; window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); } @@ -7928,6 +7927,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (flags & ImGuiWindowFlags_Tooltip) g.TooltipPreviousWindow = window; + // Set default BgClickFlags + // This is set at the end of this function, so UpdateManualResize()/ClampWindowPos() may use last-frame value if overriden by user code. + // FIXME: The general intent is that we will later expose config options to default to enable scrolling + select scrolling mouse button. + window->BgClickFlags = g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move; + // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. window->DC.WindowItemStatusFlags = ImGuiItemStatusFlags_None; diff --git a/imgui_internal.h b/imgui_internal.h index 3cfd42cb4..c3c783efa 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -209,6 +209,7 @@ typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // F typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() typedef int ImGuiTypingSelectFlags; // -> enum ImGuiTypingSelectFlags_ // Flags: for GetTypingSelectRequest() +typedef int ImGuiWindowBgClickFlags; // -> enum ImGuiWindowBgClickFlags_ // Flags: for overriding behavior of clicking on window background/void. typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy() // Table column indexing @@ -1283,6 +1284,12 @@ enum ImGuiWindowRefreshFlags_ // Refresh policy/frequency, Load Balancing etc. }; +enum ImGuiWindowBgClickFlags_ +{ + ImGuiWindowBgClickFlags_None = 0, + ImGuiWindowBgClickFlags_Move = 1 << 0, // Click on bg/void + drag to move window. Cleared by default when using io.ConfigWindowsMoveFromTitleBarOnly. +}; + enum ImGuiNextWindowDataFlags_ { ImGuiNextWindowDataFlags_None = 0, @@ -2662,6 +2669,7 @@ struct IMGUI_API ImGuiWindow ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only ImS8 DisableInputsFrames; // Disable window interactions for N frames + ImGuiWindowBgClickFlags BgClickFlags : 8; // Configure behavior of click+dragging on window bg/void or over items. Default sets by io.ConfigWindowsMoveFromTitleBarOnly. If you use this please report in #3379. ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use.