From e384078d7aad79607f32a5db87ebc004cc6b5c56 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 19 Oct 2017 22:49:36 +0200 Subject: [PATCH 01/11] IO: reordering some supposedly private fields. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 17c39f5e..a6b1116c 100644 --- a/imgui.h +++ b/imgui.h @@ -871,9 +871,9 @@ struct ImGuiIO //------------------------------------------------------------------ ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame()) - bool MouseClicked[5]; // Mouse button went from !Down to Down ImVec2 MouseClickedPos[5]; // Position at time of clicking float MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? bool MouseReleased[5]; // Mouse button went from Down to !Down bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. From 2a32a2e66297a2a3c0bd73f87c0aa991d4c15707 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 12:38:48 +0200 Subject: [PATCH 02/11] Demos: Tweaks of popups/context/menus section. --- imgui_demo.cpp | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2a3ce928..7fafd9ef 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1383,22 +1383,6 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::EndPopup(); } - ImGui::Spacing(); - ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); - ImGui::Separator(); - // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. - // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here - // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. - ImGui::PushID("foo"); - ImGui::MenuItem("Menu item", "CTRL+M"); - if (ImGui::BeginMenu("Menu inside a regular window")) - { - ShowExampleMenuFile(); - ImGui::EndMenu(); - } - ImGui::PopID(); - ImGui::Separator(); - ImGui::TreePop(); } @@ -1415,7 +1399,9 @@ void ImGui::ShowTestWindow(bool* p_open) { if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::DragFloat("Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::PushItemWidth(-1); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::PopItemWidth(); ImGui::EndPopup(); } @@ -1485,6 +1471,25 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::TreePop(); } + + if (ImGui::TreeNode("Menus inside a regular window")) + { + ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::Separator(); + // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. + // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here + // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. + ImGui::PushID("foo"); + ImGui::MenuItem("Menu item", "CTRL+M"); + if (ImGui::BeginMenu("Menu inside a regular window")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::PopID(); + ImGui::Separator(); + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("Columns")) From 5f7299e15a28fbadc693bdc90184e23c367b488e Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 13:07:57 +0200 Subject: [PATCH 03/11] Refactor EndFrame() code that process focusing window with left mouse button. This commit should be no-op. --- imgui.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4f14032c..a7de91f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2771,25 +2771,28 @@ void ImGui::EndFrame() g.CurrentWindow->Active = false; ImGui::End(); - // Click to focus window and start moving (after we're done with all our widgets) - if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) + if (g.ActiveId == 0 && g.HoveredId == 0) { - if (!(g.NavWindow && !g.NavWindow->WasActive && g.NavWindow->Active)) // Unless we just made a popup appear + if (!g.NavWindow || g.NavWindow->WasActive || !g.NavWindow->Active) // Unless we just made a popup appear { - if (g.HoveredRootWindow != NULL) + // Click to focus window and start moving (after we're done with all our widgets) + if (g.IO.MouseClicked[0]) { - FocusWindow(g.HoveredWindow); - if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) + if (g.HoveredRootWindow != NULL) { - g.MovedWindow = g.HoveredWindow; - g.MovedWindowMoveId = g.HoveredWindow->MoveId; - SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow); + FocusWindow(g.HoveredWindow); + if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) + { + g.MovedWindow = g.HoveredWindow; + g.MovedWindowMoveId = g.HoveredWindow->MoveId; + SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow); + } + } + else if (g.NavWindow != NULL && GetFrontMostModalRootWindow() == NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); } - } - else if (g.NavWindow != NULL && GetFrontMostModalRootWindow() == NULL) - { - // Clicking on void disable focus - FocusWindow(NULL); } } } From 853018dd4dff37ffeb32f89980a52c300e84dc35 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 13:21:42 +0200 Subject: [PATCH 04/11] Popups: Fixed a bug introduced in 1a35766356032a77bed1e9f16bdfcd60b93784cf which made the BeginPopupContextXXX functions create popups without border. (nb: all that border mess is going away in styling clean up) --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a7de91f3..b05ad6c7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3750,7 +3750,7 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) if (IsItemHovered() && IsMouseClicked(mouse_button)) OpenPopupEx(id, false); - return BeginPopupEx(id, 0); + return BeginPopupEx(id, ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_AlwaysAutoResize); } bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) @@ -3761,7 +3761,7 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool a if (IsWindowRectHovered() && IsMouseClicked(mouse_button)) if (also_over_items || !IsAnyItemHovered()) OpenPopupEx(id, true); - return BeginPopupEx(id, 0); + return BeginPopupEx(id, ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_AlwaysAutoResize); } bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) @@ -3771,7 +3771,7 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) ImGuiID id = GImGui->CurrentWindow->GetID(str_id); if (!IsAnyWindowHovered() && IsMouseClicked(mouse_button)) OpenPopupEx(id, true); - return BeginPopupEx(id, 0); + return BeginPopupEx(id, ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_AlwaysAutoResize); } static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) From 87ae40843c0b5c526edd9cdb62b072cd0bcc49ff Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 13:26:39 +0200 Subject: [PATCH 05/11] Popups: popups can be closed with a right-click anywhere, without altering focus under the popup.(~#439) --- imgui.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b05ad6c7..93385989 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -643,7 +643,7 @@ static void MarkIniSettingsDirty(ImGuiWindow* window); static ImRect GetVisibleRect(); -static void CloseInactivePopups(); +static void CloseInactivePopups(ImGuiWindow* ref_window); static void ClosePopupToLevel(int remaining); static ImGuiWindow* GetFrontMostModalRootWindow(); static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid); @@ -2441,7 +2441,7 @@ void ImGui::NewFrame() // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. g.CurrentWindowStack.resize(0); g.CurrentPopupStack.resize(0); - CloseInactivePopups(); + CloseInactivePopups(g.NavWindow); // Create implicit window - we will only render it if the user has added something to it. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. @@ -2773,7 +2773,7 @@ void ImGui::EndFrame() if (g.ActiveId == 0 && g.HoveredId == 0) { - if (!g.NavWindow || g.NavWindow->WasActive || !g.NavWindow->Active) // Unless we just made a popup appear + if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear { // Click to focus window and start moving (after we're done with all our widgets) if (g.IO.MouseClicked[0]) @@ -2794,6 +2794,13 @@ void ImGui::EndFrame() FocusWindow(NULL); } } + + // With right mouse button we close popups without changing focus + // (The left mouse button path calls FocusWindow which will lead NewFrame->CloseInactivePopups to trigger) + if (g.IO.MouseClicked[1]) + { + CloseInactivePopups(g.HoveredWindow); + } } } @@ -3567,7 +3574,7 @@ void ImGui::OpenPopup(const char* str_id) OpenPopupEx(g.CurrentWindow->GetID(str_id), false); } -static void CloseInactivePopups() +static void CloseInactivePopups(ImGuiWindow* ref_window) { ImGuiContext& g = *GImGui; if (g.OpenPopupStack.empty()) @@ -3576,7 +3583,7 @@ static void CloseInactivePopups() // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. // Don't close our own child popup windows int n = 0; - if (g.NavWindow) + if (ref_window) { for (n = 0; n < g.OpenPopupStack.Size; n++) { @@ -3589,7 +3596,7 @@ static void CloseInactivePopups() bool has_focus = false; for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) - has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == g.NavWindow->RootWindow); + has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); if (!has_focus) break; } From 3b485cda51807b9a29cb0ba3a3e22c2b500f7cdc Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 16:09:24 +0200 Subject: [PATCH 06/11] Fixed a bug allowing to move a _NoMove window from a child that doesn't have the flag. (#1381) broken by e56eba44fe0724a64f88f041fddad2eac3661cc3 (#1337) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 93385989..e9619bac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2781,7 +2781,7 @@ void ImGui::EndFrame() if (g.HoveredRootWindow != NULL) { FocusWindow(g.HoveredWindow); - if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) + if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove) && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoMove)) { g.MovedWindow = g.HoveredWindow; g.MovedWindowMoveId = g.HoveredWindow->MoveId; From e6f06627e9cc7b47b4b428f15dc6d4c1910e7a18 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 16:13:13 +0200 Subject: [PATCH 07/11] Made the ImGuiWindowFlags_NoMove flag inherited from parent to child, so in a setup with RootWindow (no flag) -> Child (NoMove flag) -> SubChild (no flag) user won't be able to move the root window by clicking on SubChild. (#1381) --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index e9619bac..a65cf90c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3785,6 +3785,7 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b { ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; + flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag const ImVec2 content_avail = ImGui::GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); From d29a6a5a5a22cd114557854c918b3d3c1a8262b6 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 16:40:10 +0200 Subject: [PATCH 08/11] Moved IMGUI_DISABLE_OBSOLETE_FUNCTIONS block lower in the imgui.h file so obsolete functions can use flags. Also sane to quarantine them outside of the respectable area. --- imgui.cpp | 7 ------- imgui.h | 36 +++++++++++++++++++++--------------- imgui_internal.h | 1 - 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a65cf90c..46306503 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5284,13 +5284,6 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi g.SetNextWindowPosCond = cond ? cond : ImGuiCond_Always; } -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImGui::SetNextWindowPosCenter(ImGuiCond cond) -{ - SetNextWindowPos(GetIO().DisplaySize * 0.5f, cond, ImVec2(0.5f, 0.5f)); -} -#endif - void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index a6b1116c..4771175e 100644 --- a/imgui.h +++ b/imgui.h @@ -485,21 +485,6 @@ namespace ImGui IMGUI_API ImGuiContext* GetCurrentContext(); IMGUI_API void SetCurrentContext(ImGuiContext* ctx); - // Obsolete functions (Will be removed! Also see 'API BREAKING CHANGES' section in imgui.cpp) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE 1.52+. use SetNextWindowSize() instead if you want to set a window size. - static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETE 1.52+ - void SetNextWindowPosCenter(ImGuiCond cond = 0); // OBSOLETE 1.52+ - static inline bool IsItemHoveredRect() { return IsItemRectHovered(); } // OBSOLETE 1.51+ - static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETE 1.51+. This was partly broken. You probably wanted to use ImGui::GetIO().WantCaptureMouse instead. - static inline bool IsMouseHoveringAnyWindow() { return IsAnyWindowHovered(); } // OBSOLETE 1.51+ - static inline bool IsMouseHoveringWindow() { return IsWindowRectHovered(); } // OBSOLETE 1.51+ - static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ - static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ - static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ - static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETE 1.42+ -#endif - } // namespace ImGui // Flags for ImGui::Begin() @@ -886,6 +871,27 @@ struct ImGuiIO IMGUI_API ImGuiIO(); }; +//----------------------------------------------------------------------------- +// Obsolete functions (Will be removed! Also see 'API BREAKING CHANGES' section in imgui.cpp) +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE 1.52+. use SetNextWindowSize() instead if you want to set a window size. + static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETE 1.52+ + static inline void SetNextWindowPosCenter(ImGuiCond cond = 0) { SetNextWindowPos(ImVec2(GetIO().DisplaySize.x * 0.5f, GetIO().DisplaySize.y * 0.5f), cond, ImVec2(0.5f, 0.5f)); } // OBSOLETE 1.52+ + static inline bool IsItemHoveredRect() { return IsItemRectHovered(); } // OBSOLETE 1.51+ + static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETE 1.51+. This was partly broken. You probably wanted to use ImGui::GetIO().WantCaptureMouse instead. + static inline bool IsMouseHoveringAnyWindow() { return IsAnyWindowHovered(); } // OBSOLETE 1.51+ + static inline bool IsMouseHoveringWindow() { return IsWindowRectHovered(); } // OBSOLETE 1.51+ + static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1 << 5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ + static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ + static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ + static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETE 1.42+ +} +#endif + //----------------------------------------------------------------------------- // Helpers //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index ec6d4e51..8f8dcc6c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -433,7 +433,6 @@ struct ImGuiContext bool ActiveIdIsAlive; // Active widget has been seen this frame bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) - ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. From 564ff2dfd379d40568879a5bc89e8cfea7e51d2f Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 17:52:22 +0200 Subject: [PATCH 09/11] IsItemHovered(), IsWindowHovered(): added flags to enable various and more specific behavior. Will enable improvements for popups/context menus and drag'n drop. (relate ~#439, #1013, #143, #925) The legacy confusing IsItemRectHovered(), IsWindowRectHovered() can be completely removed now. Changed IsWindowHovered() behavior with default parameter: it now return false is the window is blocked by a popup. Demo: Added tests for those two functions. --- imgui.cpp | 51 +++++++++++++++++++++++++------------------------- imgui.h | 23 ++++++++++++++++------- imgui_demo.cpp | 28 +++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 46306503..efb234f0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -216,11 +216,12 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2017/10/20 (1.52) - removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51, the new flags available for IsItemHovered() and IsWindowHovered() are providing much more details/options, and those legacy entry points were confusing/misleading. - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". - - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. @@ -1944,15 +1945,22 @@ void ImGui::KeepAliveID(ImGuiID id) g.ActiveIdIsAlive = true; } -static inline bool IsWindowContentHoverable(ImGuiWindow* window) +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) { // An active popup disable hovering on other windows (apart from its own children) // FIXME-OPT: This could be cached/stored within the window. ImGuiContext& g = *GImGui; if (g.NavWindow) if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) - if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow) - return false; + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + // For the purpose of those flags we differentiate "standard popup" from "modal popup" + // NB: The order of those two tests is important because Modal windows are also Popups. + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + return false; + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return false; + } return true; } @@ -2012,7 +2020,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id) // This is roughly matching the behavior of internal-facing ItemHoverable() // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()) // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId -bool ImGui::IsItemHovered() +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { ImGuiContext& g = *GImGui; @@ -2023,21 +2031,16 @@ bool ImGui::IsItemHovered() // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. //if (g.HoveredWindow != window) // return false; - if (g.HoveredRootWindow != window->RootWindow) - return false; - if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) return false; - if (!IsWindowContentHoverable(window)) + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + if (!IsWindowContentHoverable(window, flags)) return false; return true; } -bool ImGui::IsItemRectHovered() -{ - ImGuiWindow* window = GetCurrentWindowRead(); - return window->DC.LastItemRectHoveredRect; -} - // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) { @@ -2052,7 +2055,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) return false; - if (!IsWindowContentHoverable(window)) + if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_Default)) return false; SetHoveredID(id); @@ -5086,16 +5089,11 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) return "Unknown"; } -bool ImGui::IsWindowHovered() -{ - ImGuiContext& g = *GImGui; - return g.HoveredWindow == g.CurrentWindow && IsWindowContentHoverable(g.HoveredRootWindow); -} - -bool ImGui::IsWindowRectHovered() +bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { + IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; - return g.HoveredWindow == g.CurrentWindow; + return g.HoveredWindow == g.CurrentWindow && IsWindowContentHoverable(g.HoveredRootWindow, flags); } bool ImGui::IsWindowFocused() @@ -5116,10 +5114,11 @@ bool ImGui::IsRootWindowOrAnyChildFocused() return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow; } -bool ImGui::IsRootWindowOrAnyChildHovered() +bool ImGui::IsRootWindowOrAnyChildHovered(ImGuiHoveredFlags flags) { + IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; - return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow); + return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow, flags); } float ImGui::GetWindowWidth() diff --git a/imgui.h b/imgui.h index 4771175e..3b72401d 100644 --- a/imgui.h +++ b/imgui.h @@ -80,6 +80,7 @@ typedef int ImGuiColumnsFlags; // flags: for *Columns*() typedef int ImGuiInputTextFlags; // flags: for InputText*() // enum ImGuiInputTextFlags_ typedef int ImGuiSelectableFlags; // flags: for Selectable() // enum ImGuiSelectableFlags_ typedef int ImGuiTreeNodeFlags; // flags: for TreeNode*(), Collapsing*() // enum ImGuiTreeNodeFlags_ +typedef int ImGuiHoveredFlags; // flags: for IsItemHovered() // enum ImGuiHoveredFlags_ typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); typedef void (*ImGuiSizeConstraintCallback)(ImGuiSizeConstraintCallbackData* data); #ifdef _MSC_VER @@ -414,8 +415,7 @@ namespace ImGui IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // Utilities - IMGUI_API bool IsItemHovered(); // is the last item hovered by mouse (and usable)? - IMGUI_API bool IsItemRectHovered(); // is the last item hovered by mouse? even if another item is active or window is blocked by popup while we are hovering this + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered by mouse (and usable)? IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) IMGUI_API bool IsItemVisible(); // is the last item visible? (aka not out of sight due to clipping/scrolling.) @@ -426,11 +426,10 @@ namespace ImGui IMGUI_API ImVec2 GetItemRectSize(); // " IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. IMGUI_API bool IsWindowFocused(); // is current window focused - IMGUI_API bool IsWindowHovered(); // is current window hovered and hoverable (not blocked by a popup) (differentiate child windows from each others) - IMGUI_API bool IsWindowRectHovered(); // is current window rectangle hovered, disregarding of any consideration of being blocked by a popup. (unlike IsWindowHovered() this will return true even if the window is blocked because of a popup) + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags = 0); // is current window hovered (and typically: not blocked by a popup/modal) IMGUI_API bool IsRootWindowFocused(); // is current root window focused (root = top-most parent of a child, otherwise self) IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused - IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) + IMGUI_API bool IsRootWindowOrAnyChildHovered(ImGuiHoveredFlags flags = 0); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) IMGUI_API bool IsAnyWindowHovered(); // is mouse hovering any visible window IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. @@ -569,6 +568,16 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_AllowDoubleClick = 1 << 2 // Generate press events on double clicks too }; +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_Default = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 0, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 1, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 2, // Return true even if an active item is blocking access to this item/window + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 3, // Return true even if the position is overlapped by another window + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped +}; + // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array enum ImGuiKey_ { @@ -881,10 +890,10 @@ namespace ImGui bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE 1.52+. use SetNextWindowSize() instead if you want to set a window size. static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETE 1.52+ static inline void SetNextWindowPosCenter(ImGuiCond cond = 0) { SetNextWindowPos(ImVec2(GetIO().DisplaySize.x * 0.5f, GetIO().DisplaySize.y * 0.5f), cond, ImVec2(0.5f, 0.5f)); } // OBSOLETE 1.52+ - static inline bool IsItemHoveredRect() { return IsItemRectHovered(); } // OBSOLETE 1.51+ + static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETE 1.51+ static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETE 1.51+. This was partly broken. You probably wanted to use ImGui::GetIO().WantCaptureMouse instead. static inline bool IsMouseHoveringAnyWindow() { return IsAnyWindowHovered(); } // OBSOLETE 1.51+ - static inline bool IsMouseHoveringWindow() { return IsWindowRectHovered(); } // OBSOLETE 1.51+ + static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // OBSOLETE 1.51+ static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1 << 5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7fafd9ef..d923dffe 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1763,6 +1763,34 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::TreePop(); } + if (ImGui::TreeNode("Hovering")) + { + // Testing IsWindowHovered() function + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n", + //"IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)); + //ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)); + + // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) + ImGui::Button("ITEM"); + ImGui::BulletText( + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemhovered(_RectOnly) = %d\n", + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)); + + ImGui::TreePop(); + } + if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); From 695ea45fca41debe15c0ed2fe86ff0bc8961d67e Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 17:59:48 +0200 Subject: [PATCH 10/11] IsWindowHovered(): Changed default behavior to now return false is a widget from another window is active + Added support for ImGuiHoveredFlags_AllowWhenBlockedByActiveItem. (relate to drag'n drop idoms: #143) --- imgui.cpp | 22 ++++++++++++++++++---- imgui_demo.cpp | 8 ++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index efb234f0..69b0dcd0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5091,9 +5091,16 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { - IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) == 0); // Flags not supported by this function + IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; - return g.HoveredWindow == g.CurrentWindow && IsWindowContentHoverable(g.HoveredRootWindow, flags); + if (g.HoveredWindow != g.CurrentWindow) + return false; + if (!IsWindowContentHoverable(g.HoveredRootWindow, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveIdWindow != g.CurrentWindow) + return false; + return true; } bool ImGui::IsWindowFocused() @@ -5116,9 +5123,16 @@ bool ImGui::IsRootWindowOrAnyChildFocused() bool ImGui::IsRootWindowOrAnyChildHovered(ImGuiHoveredFlags flags) { - IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) == 0); // Flags not supported by this function + IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function ImGuiContext& g = *GImGui; - return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow, flags); + if (!g.HoveredRootWindow || (g.HoveredRootWindow != g.CurrentWindow->RootWindow)) + return false; + if (!IsWindowContentHoverable(g.HoveredRootWindow, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveIdWindow != g.CurrentWindow) + return false; + return true; } float ImGui::GetWindowWidth() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d923dffe..242decae 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1768,11 +1768,11 @@ void ImGui::ShowTestWindow(bool* p_open) // Testing IsWindowHovered() function ImGui::BulletText( "IsWindowHovered() = %d\n" - "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n", - //"IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n", + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n", ImGui::IsWindowHovered(), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)); - //ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)); + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)); // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) ImGui::Button("ITEM"); From 3cc10d25a97a4eeba0dda8d02f3e0ed9c6e13c72 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Oct 2017 17:59:59 +0200 Subject: [PATCH 11/11] BeginPopupContextItem(), BeginPopupContextWindow(): Using newly introduced IsItemHovered() flags to allow reopening another context menu (over same or not same item) with right-click. (#439) (+1 squashed commits) --- imgui.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 69b0dcd0..385b7d22 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -216,6 +216,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if a popup window is blocking access to the window or an item is active in another window. You can use the newly introduced IsWindowHovered() flags to requests those specific behavior if you need them. - 2017/10/20 (1.52) - removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51, the new flags available for IsItemHovered() and IsWindowHovered() are providing much more details/options, and those legacy entry points were confusing/misleading. - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). @@ -3758,8 +3759,9 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) ImGuiWindow* window = GImGui->CurrentWindow; ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! IM_ASSERT(id != 0); // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) - if (IsItemHovered() && IsMouseClicked(mouse_button)) - OpenPopupEx(id, false); + if (IsMouseClicked(mouse_button)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id, true); return BeginPopupEx(id, ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_AlwaysAutoResize); } @@ -3768,9 +3770,10 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool a if (!str_id) str_id = "window_context"; ImGuiID id = GImGui->CurrentWindow->GetID(str_id); - if (IsWindowRectHovered() && IsMouseClicked(mouse_button)) - if (also_over_items || !IsAnyItemHovered()) - OpenPopupEx(id, true); + if (IsMouseClicked(mouse_button)) + if (IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (also_over_items || !IsAnyItemHovered()) + OpenPopupEx(id, true); return BeginPopupEx(id, ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_AlwaysAutoResize); }