From 1a35766356032a77bed1e9f16bdfcd60b93784cf Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 16 Oct 2017 23:36:34 +0200 Subject: [PATCH] BeginPopupContextItem() now supports a NULL string identifier and uses the last item ID if available. For interactive items (that have an ID) this works! For non interactive items we assert. --- imgui.cpp | 25 +++++++++++++++---------- imgui.h | 2 +- imgui_demo.cpp | 9 +++++++-- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c2d6aa013..9e969385e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3697,38 +3697,43 @@ void ImGui::EndPopup() PopStyleVar(); } -// This is a helper to handle the most simple case of associating one named popup to one given widget. +// This is a helper to handle the simplest case of associating one named popup to one given widget. // 1. If you have many possible popups (for different "instances" of a same widget, or for wholly different widgets), you may be better off handling // this yourself so you can store data relative to the widget that opened the popup instead of choosing different popup identifiers. // 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemRectHovered() // and passing true to the OpenPopupEx(). -// Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that -// the item can be interacted with (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu -// driven by click position. +// This is because hovering an item in a window below the popup won't work. IsItemRectHovered() skips this test. +// The pattern of ignoring the fact that the item can be interacted with (because it is blocked by the active popup) may useful in some situation +// when e.g. large canvas where the content of menu driven by click position. 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(GImGui->CurrentWindow->GetID(str_id), false); - return BeginPopup(str_id); + OpenPopupEx(id, false); + return BeginPopupEx(id, 0); } bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items) { 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(GImGui->CurrentWindow->GetID(str_id), true); - return BeginPopup(str_id); + OpenPopupEx(id, true); + return BeginPopupEx(id, 0); } bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) { if (!str_id) str_id = "void_context"; + ImGuiID id = GImGui->CurrentWindow->GetID(str_id); if (!IsAnyWindowHovered() && IsMouseClicked(mouse_button)) - OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), true); - return BeginPopup(str_id); + OpenPopupEx(id, true); + return BeginPopupEx(id, 0); } static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) diff --git a/imgui.h b/imgui.h index a5a5972e1..8984f9910 100644 --- a/imgui.h +++ b/imgui.h @@ -392,7 +392,7 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (block interactions behind the modal window, can't close the modal window by clicking outside) - IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp! + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // 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(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3f7d5feea..107c4b86d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1402,6 +1402,11 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Context menus")) { + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + // if (IsItemHovered() && IsMouseClicked(0)) + // OpenPopup(id); + // return BeginPopup(id); + // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. static float value = 0.5f; ImGui::Text("Value = %.3f (<-- right-click here)", value); if (ImGui::BeginPopupContextItem("item context menu")) @@ -1413,9 +1418,9 @@ void ImGui::ShowTestWindow(bool* p_open) } static char name[32] = "Label1"; - char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceeding label + char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label ImGui::Button(buf); - if (ImGui::BeginPopupContextItem("rename context menu")) + if (ImGui::BeginPopupContextItem()) // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). { ImGui::Text("Edit name:"); ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));