From bce495c5813898a4eae503ac02fe8a2d353bdc19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Jun 2015 10:02:56 -0600 Subject: [PATCH] Added BeginPopupModal() with actual modal behaviour (WIP api) (#249) --- imgui.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- imgui.h | 10 ++++++---- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d0568bcd8..93f996ab1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -548,6 +548,7 @@ static bool CloseWindowButton(bool* p_opened = NULL); static void FocusWindow(ImGuiWindow* window); static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs); static void CloseInactivePopups(); +static ImGuiWindow* GetFrontMostModalRootWindow(); static void SetWindowScrollY(ImGuiWindow* window, float scroll_y); // Helpers: String @@ -2149,6 +2150,9 @@ void ImGui::NewFrame() g.HoveredRootWindow = g.HoveredWindow->RootWindow; else g.HoveredRootWindow = FindHoveredWindow(g.IO.MousePos, true); + if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow()) + if (g.HoveredRootWindow != modal_window) + g.HoveredRootWindow = g.HoveredWindow = NULL; // Are we using inputs? Tell user so they can capture/discard the inputs away from the rest of their application. // When clicking outside of a window we assume the click is owned by the application and won't request capture. @@ -2372,7 +2376,7 @@ void ImGui::Render() g.MovedWindow = g.HoveredWindow; SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); } - else if (g.FocusedWindow != NULL) + else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL) { // Clicking on void disable focus FocusWindow(NULL); @@ -3149,6 +3153,16 @@ static void CloseInactivePopups() g.OpenedPopupStack.resize(n); } +static ImGuiWindow* GetFrontMostModalRootWindow() +{ + ImGuiState& g = *GImGui; + if (!g.OpenedPopupStack.empty()) + if (ImGuiWindow* front_most_popup = g.OpenedPopupStack.back().Window) + if (front_most_popup->Flags & ImGuiWindowFlags_Modal) + return front_most_popup; + return NULL; +} + static void ClosePopupToLevel(int remaining) { ImGuiState& g = *GImGui; @@ -3220,12 +3234,33 @@ bool ImGui::BeginPopup(const char* str_id) return BeginPopupEx(str_id, ImGuiWindowFlags_ShowBorders); } +bool ImGui::BeginPopupModal(const char* name, ImGuiWindowFlags extra_flags) +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id)) + { + ClearSetNextWindowData(); // We behave like Begin() and need to consume those values + return false; + } + + ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoSavedSettings; + bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), -1.0f, flags); + if (!opened) // Opened can be 'false' when the popup is completely clipped (e.g. zero size display) + ImGui::EndPopup(); + + return opened; +} + void ImGui::EndPopup() { - IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup); + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); IM_ASSERT(GImGui->CurrentPopupStack.size() > 0); ImGui::End(); - ImGui::PopStyleVar(); + if (!(window->Flags & ImGuiWindowFlags_Modal)) + ImGui::PopStyleVar(); } bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) @@ -3611,7 +3646,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->SizeContents.y += window->ScrollY; // Hide popup/tooltip window when first appearing while we measure size (because we recycle them) - if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_visible) + if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && (flags & ImGuiWindowFlags_AlwaysAutoResize) && !window_was_visible) { window->HiddenFrames = 1; if (!window_size_set_by_api) diff --git a/imgui.h b/imgui.h index 314d0009d..01d7ddb40 100644 --- a/imgui.h +++ b/imgui.h @@ -171,9 +171,10 @@ namespace ImGui // Popup 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 mouse_button = 1); // open and begin popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // open and begin popup when clicked on current window - IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // open and begin popup when clicked in void (no window) + IMGUI_API bool BeginPopupModal(const char* name, ImGuiWindowFlags extra_flags = 0); + IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item + IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on current window + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin 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. @@ -428,7 +429,8 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ComboBox = 1 << 23, // Don't use! For internal use by ComboBox() ImGuiWindowFlags_Tooltip = 1 << 24, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 25, // Don't use! For internal use by BeginPopup() - ImGuiWindowFlags_ChildMenu = 1 << 26 // Don't use! For internal use by BeginMenu() + ImGuiWindowFlags_Modal = 1 << 26, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 27 // Don't use! For internal use by BeginMenu() }; // Flags for ImGui::InputText()