From f8b7d5c76d114dc86366200199d6b48bbfe98316 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:53:43 +0100 Subject: [PATCH 1/5] Tracking ActiveIdWindow along with ActiveId --- imgui.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ea70d592..fe182ea2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1250,8 +1250,9 @@ struct ImGuiState ImGuiID ActiveId; // Active widget ImGuiID ActiveIdPreviousFrame; bool ActiveIdIsAlive; - bool ActiveIdIsJustActivated; // Set when - bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction. + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction + ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window. float SettingsDirtyTimer; ImVector Settings; @@ -1466,12 +1467,13 @@ static inline ImGuiWindow* GetParentWindow() return g.CurrentWindowStack[g.CurrentWindowStack.size() - 2]; } -static void SetActiveId(ImGuiID id) +static void SetActiveId(ImGuiID id, ImGuiWindow* window = NULL) { ImGuiState& g = *GImGui; g.ActiveId = id; g.ActiveIdIsFocusedOnly = false; g.ActiveIdIsJustActivated = true; + g.ActiveIdWindow = window; } static void RegisterAliveId(ImGuiID id) @@ -2379,7 +2381,7 @@ void ImGui::Render() { IM_ASSERT(g.MovedWindow == NULL); g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->MoveID); + SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); } else if (g.FocusedWindow != NULL) { @@ -4887,7 +4889,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } else { - SetActiveId(id); + SetActiveId(id, window); } FocusWindow(window); } @@ -5537,7 +5539,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int char text_buf[64]; ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); - SetActiveId(g.ScalarAsInputTextId); + SetActiveId(g.ScalarAsInputTextId, window); g.HoveredId = 0; // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) @@ -5767,7 +5769,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); const bool is_ctrl_down = g.IO.KeyCtrl; @@ -5825,7 +5827,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float if (hovered && g.IO.MouseClicked[0]) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); } @@ -6071,7 +6073,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, f const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] | g.IO.MouseDoubleClicked[0]))) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0]) @@ -6855,16 +6857,14 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (focus_requested_by_tab || (user_clicked && is_ctrl_down)) select_all = true; } - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); } else if (io.MouseClicked[0]) { // Release focus when we click outside if (g.ActiveId == id) - { SetActiveId(0); - } } // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. From b0a9bbf6f6aaa6ee47d9db0d5290812c3d9efd07 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:58:49 +0100 Subject: [PATCH 2/5] Popup taking focus deactivate focused widget of other window (#126) e.g. focus InputText(), open contextual popup, input text used to stay focused --- imgui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fe182ea2..56242512 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4015,6 +4015,11 @@ static void FocusWindow(ImGuiWindow* window) if (window->RootWindow) window = window->RootWindow; + // Steal focus on active widgets + if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) + SetActiveId(0); + if (g.Windows.back() == window) return; @@ -6786,11 +6791,11 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Edit a string of text bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; + ImGuiState& g = *GImGui; const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; From 1cb6a294b0cda721121a4cf3e3242241427d015c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:07:24 +0100 Subject: [PATCH 3/5] BeginPopupContextWindow() rearranged and clarified parameters (#126) --- imgui.cpp | 5 +++-- imgui.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 56242512..96920a33 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3180,10 +3180,11 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int button) return ImGui::BeginPopup(str_id); } -bool ImGui::BeginPopupContextWindow(const char* str_id, bool void_only, int button) +bool ImGui::BeginPopupContextWindow(bool in_empty_space_only, const char* str_id, int button) { + if (str_id == NULL) str_id = "window_context_menu"; if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) - if (!void_only || !ImGui::IsAnyItemHovered()) + if (!in_empty_space_only || !ImGui::IsAnyItemHovered()) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } diff --git a/imgui.h b/imgui.h index 0cb0ad5a..a36f6167 100644 --- a/imgui.h +++ b/imgui.h @@ -170,7 +170,7 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(const char* str_id = "window_context_menu", bool void_only = false, int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextWindow(bool in_void_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. From 235cca4f971cda95d2b14c2d599e98aac6a0ca5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:24:39 +0100 Subject: [PATCH 4/5] Fix to allow opening popup from a left-click on void or another window (because left-click would normally override focus immediately) (#126) Neither appears to be really useful frankly. --- imgui.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 96920a33..735b5d33 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2377,16 +2377,19 @@ void ImGui::Render() // 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.HoveredRootWindow != NULL) + if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear { - IM_ASSERT(g.MovedWindow == NULL); - g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); - } - else if (g.FocusedWindow != NULL) - { - // Clicking on void disable focus - FocusWindow(NULL); + if (g.HoveredRootWindow != NULL) + { + IM_ASSERT(g.MovedWindow == NULL); + g.MovedWindow = g.HoveredWindow; + SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); + } + else if (g.FocusedWindow != NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } } } From dcc7df2b216091a2ed238cac1c071dcd48ca0463 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:28:53 +0100 Subject: [PATCH 5/5] Added BeginPopupContextVoid() helper for completeness (#126) --- imgui.cpp | 10 +++++++++- imgui.h | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 735b5d33..26d91908 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3185,13 +3185,21 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int button) bool ImGui::BeginPopupContextWindow(bool in_empty_space_only, const char* str_id, int button) { - if (str_id == NULL) str_id = "window_context_menu"; + if (!str_id) str_id = "window_context_menu"; if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) if (!in_empty_space_only || !ImGui::IsAnyItemHovered()) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } +bool ImGui::BeginPopupContextVoid(const char* str_id, int button) +{ + if (!str_id) str_id = "void_context_menu"; + if (!ImGui::IsMouseHoveringAnyWindow() && ImGui::IsMouseClicked(button)) + ImGui::OpenPopup(str_id); + return ImGui::BeginPopup(str_id); +} + bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index a36f6167..3be321d1 100644 --- a/imgui.h +++ b/imgui.h @@ -170,7 +170,8 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(bool in_void_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextWindow(bool in_empty_space_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextVoid(const char* str_id = "void_context_menu", int button = 1); // open popup when clicked in void (no window) IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup.