From 4b82759598e34aed179177ecaa00e774c0d23484 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 25 Sep 2017 18:25:43 +0200 Subject: [PATCH] SetNextWindowPos: added a ImVec2 pivot parameter for positioning a given a center, bottom-right position, etc. As a generalization of SetNextWindowPosCenter() which is now obsolete. This will be useful for combo-like popups as well. Demo: Simple-overlay window uses the SetWindowPos pivot to select a corner to position itself at. --- imgui.cpp | 37 ++++++++++++++++++++++--------------- imgui.h | 4 ++-- imgui_demo.cpp | 28 +++++++++++++++++++--------- imgui_internal.h | 4 +++- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 310cfe2c..f7cda671 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -204,6 +204,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/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). - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). @@ -1804,7 +1805,7 @@ ImGuiWindow::ImGuiWindow(const char* name) AutoPosLastDirection = -1; HiddenFrames = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; - SetWindowPosCenterWanted = false; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); LastFrameActive = -1; ItemWidthDefault = 0.0f; @@ -3619,11 +3620,15 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags ext return false; } + // Center modal windows by default + if ((window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) == 0) + SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoSavedSettings; bool is_open = ImGui::Begin(name, p_open, flags); if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { - ImGui::EndPopup(); + EndPopup(); if (is_open) ClosePopup(id); return false; @@ -3994,9 +3999,12 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (window->Appearing) window->SetWindowPosAllowFlags |= ImGuiCond_Appearing; window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) != 0; - if (window_pos_set_by_api && ImLengthSqr(g.SetNextWindowPosVal - ImVec2(-FLT_MAX,-FLT_MAX)) < 0.001f) + if (window_pos_set_by_api && ImLengthSqr(g.SetNextWindowPosPivot) > 0.00001f) { - window->SetWindowPosCenterWanted = true; // May be processed on the next frame if this is our first frame and we are measuring size + // May be processed on the next frame if this is our first frame and we are measuring size + // FIXME: Look into removing the branch so everything can go through this same codepath for consistency. + window->SetWindowPosVal = g.SetNextWindowPosVal; + window->SetWindowPosPivot = g.SetNextWindowPosPivot; window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); } else @@ -4178,13 +4186,11 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->Size = window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user passed via BeginChild()->Begin(). } - bool window_pos_center = false; - window_pos_center |= (window->SetWindowPosCenterWanted && window->HiddenFrames == 0); - window_pos_center |= ((flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize); - if (window_pos_center) + const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0); + if (window_pos_with_pivot) { - // Center (any sort of window) - SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, fullscreen_rect.GetCenter() - window->SizeFull * 0.5f), 0); + // Position given a pivot (e.g. for centering) + SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); } else if (flags & ImGuiWindowFlags_ChildMenu) { @@ -5010,7 +5016,7 @@ static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) if (cond && (window->SetWindowPosAllowFlags & cond) == 0) return; window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); - window->SetWindowPosCenterWanted = false; + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); // Set const ImVec2 old_pos = window->Pos; @@ -5133,19 +5139,20 @@ void ImGui::SetWindowFocus(const char* name) } } -void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond) +void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) { ImGuiContext& g = *GImGui; g.SetNextWindowPosVal = pos; + g.SetNextWindowPosPivot = pivot; g.SetNextWindowPosCond = cond ? cond : ImGuiCond_Always; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS void ImGui::SetNextWindowPosCenter(ImGuiCond cond) { - ImGuiContext& g = *GImGui; - g.SetNextWindowPosVal = ImVec2(-FLT_MAX, -FLT_MAX); - g.SetNextWindowPosCond = cond ? cond : ImGuiCond_Always; + SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, cond, ImVec2(0.5f, 0.5f)); } +#endif void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) { diff --git a/imgui.h b/imgui.h index 238ff89d..4bfa9430 100644 --- a/imgui.h +++ b/imgui.h @@ -152,8 +152,7 @@ namespace ImGui IMGUI_API bool IsWindowAppearing(); IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows - IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // set next window position. call before Begin() - IMGUI_API void SetNextWindowPosCenter(ImGuiCond cond = 0); // set next window position to be centered on screen. call before Begin() + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (enforce the range of scrollbars). set axis to 0.0f to leave it automatic. call before Begin() @@ -489,6 +488,7 @@ namespace ImGui // Obsolete functions (Will be removed! Also see 'API BREAKING CHANGES' section in imgui.cpp) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + static 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+ diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 543172b2..9542b883 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1434,7 +1434,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::OpenPopup("Delete?"); if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); ImGui::Separator(); //static int dummy_i = 0; @@ -2114,20 +2114,30 @@ static void ShowExampleAppConstrainedResize(bool* p_open) ImGui::End(); } -// Demonstrate creating a simple static window with no decoration. +// Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. static void ShowExampleAppFixedOverlay(bool* p_open) { - ImGui::SetNextWindowPos(ImVec2(10,10)); + const float DISTANCE = 10.0f; + static int corner = 0; + ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE); + ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.3f)); - if (!ImGui::Begin("Example: Fixed Overlay", p_open, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) + if (ImGui::Begin("Example: Fixed Overlay", p_open, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) { + ImGui::Text("Simple overlay\nin the corner of the screen.\n(right-click to change position)"); + ImGui::Separator(); + ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + ImGui::EndPopup(); + } ImGui::End(); - return; } - ImGui::Text("Simple overlay\non the top-left side of the screen."); - ImGui::Separator(); - ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); - ImGui::End(); ImGui::PopStyleColor(); } diff --git a/imgui_internal.h b/imgui_internal.h index 056dccfa..8f6762bd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -437,6 +437,7 @@ struct ImGuiContext // Storage for SetNexWindow** and SetNextTreeNode*** functions ImVec2 SetNextWindowPosVal; + ImVec2 SetNextWindowPosPivot; ImVec2 SetNextWindowSizeVal; ImVec2 SetNextWindowContentSizeVal; bool SetNextWindowCollapsedVal; @@ -696,7 +697,8 @@ struct IMGUI_API ImGuiWindow ImGuiCond SetWindowPosAllowFlags; // store condition flags for next SetWindowPos() call. ImGuiCond SetWindowSizeAllowFlags; // store condition flags for next SetWindowSize() call. ImGuiCond SetWindowCollapsedAllowFlags; // store condition flags for next SetWindowCollapsed() call. - bool SetWindowPosCenterWanted; + ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack