From 20c7aab60c5beec1d1a5f353ab4385988d6e9abd Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 7 Dec 2017 12:49:52 +0100 Subject: [PATCH 1/5] Exposed GetOverlayDrawList(). (~#545, ~#530) --- imgui.cpp | 5 +++++ imgui.h | 1 + 2 files changed, 6 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b6c70764..20a1b7a1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2233,6 +2233,11 @@ int ImGui::GetFrameCount() return GImGui->FrameCount; } +ImDrawList* ImGui::GetOverlayDrawList() +{ + return &GImGui->OverlayDrawList; +} + void ImGui::NewFrame() { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 71fe24c2..8929dea7 100644 --- a/imgui.h +++ b/imgui.h @@ -441,6 +441,7 @@ namespace ImGui 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. IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); + IMGUI_API ImDrawList* GetOverlayDrawList(); // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text IMGUI_API const char* GetStyleColorName(ImGuiCol idx); IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); From 94bf12f14b69393fa8f471fc90dcdd370fb91566 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 6 Dec 2017 22:20:08 +0100 Subject: [PATCH 2/5] Demo: Display better mouse cursor info for debugging backends. --- imgui.h | 2 +- imgui_demo.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 8929dea7..f8153c85 100644 --- a/imgui.h +++ b/imgui.h @@ -738,7 +738,7 @@ enum ImGuiMouseCursor_ ImGuiMouseCursor_Move, // Unused ImGuiMouseCursor_ResizeNS, // Unused ImGuiMouseCursor_ResizeEW, // When hovering over a column - ImGuiMouseCursor_ResizeNESW, // Unused + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window ImGuiMouseCursor_Count_ }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6b0fed76..db3a163d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1828,12 +1828,16 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Mouse cursors")) { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_Count_); + + ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); ImGui::Text("Hover to see mouse cursors:"); ImGui::SameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); for (int i = 0; i < ImGuiMouseCursor_Count_; i++) { char label[32]; - sprintf(label, "Mouse cursor %d", i); + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); ImGui::Bullet(); ImGui::Selectable(label, false); if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(i); From abe5ad3c7a9fc2546642af7218285a95f59c4629 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 6 Dec 2017 23:38:33 +0100 Subject: [PATCH 3/5] Demo: Added display for IsMouseDragging() function. --- imgui_demo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index db3a163d..95608aff 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1810,6 +1810,8 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); + for (int button = 0; button < 3; button++) + ImGui::Text("IsMouseDragging(%d) = %d", button, ImGui::IsMouseDragging(button)); ImGui::Button("Drag Me"); if (ImGui::IsItemActive()) { From 8959c64b335a73528fa939a16e197a40c2eeca82 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 7 Dec 2017 13:26:56 +0100 Subject: [PATCH 4/5] Internals: Cleanup FindBestPopupWindowPos() to be more digestible, since we are bounds to rework the logic there. No functional changes intended --- imgui.cpp | 37 ++++++++++++++++++++++++------------- imgui_internal.h | 5 +++-- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 20a1b7a1..4d986dce 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -656,7 +656,7 @@ static ImRect GetVisibleRect(); 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); +static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& rect_to_avoid); static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); @@ -1845,7 +1845,7 @@ ImGuiWindow::ImGuiWindow(const char* name) AutoFitFramesX = AutoFitFramesY = -1; AutoFitOnlyGrows = false; AutoFitChildAxises = 0x00; - AutoPosLastDirection = -1; + AutoPosLastDirection = ImGuiDir_None; HiddenFrames = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); @@ -4017,28 +4017,39 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); } -static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& r_inner) +static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_avoid) { const ImGuiStyle& style = GImGui->Style; - // Clamp into visible area while not overlapping the cursor. Safety padding is optional if our popup size won't fit without it. + // r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) + // r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. ImVec2 safe_padding = style.DisplaySafeAreaPadding; ImRect r_outer(GetVisibleRect()); r_outer.Expand(ImVec2((size.x - r_outer.GetWidth() > safe_padding.x*2) ? -safe_padding.x : 0.0f, (size.y - r_outer.GetHeight() > safe_padding.y*2) ? -safe_padding.y : 0.0f)); ImVec2 base_pos_clamped = ImClamp(base_pos, r_outer.Min, r_outer.Max - size); + //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); - for (int n = (*last_dir != -1) ? -1 : 0; n < 4; n++) // Last, Right, down, up, left. (Favor last used direction). + const ImGuiDir dir_prefered_order[ImGuiDir_Count_] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_Count_; n++) { - const int dir = (n == -1) ? *last_dir : n; - ImRect rect(dir == 0 ? r_inner.Max.x : r_outer.Min.x, dir == 1 ? r_inner.Max.y : r_outer.Min.y, dir == 3 ? r_inner.Min.x : r_outer.Max.x, dir == 2 ? r_inner.Min.y : r_outer.Max.y); - if (rect.GetWidth() < size.x || rect.GetHeight() < size.y) + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + if (avail_w < size.x) continue; + float avail_h = (dir == ImGuiDir_Down ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + if (avail_h < size.y) + continue; + + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; *last_dir = dir; - return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : base_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : base_pos_clamped.y); + return pos; } // Fallback, try to keep within display - *last_dir = -1; + *last_dir = ImGuiDir_None; ImVec2 pos = base_pos; pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); @@ -4382,7 +4393,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (window_just_activated_by_user) { // Popup first latch mouse position, will position itself when it appears next frame - window->AutoPosLastDirection = -1; + window->AutoPosLastDirection = ImGuiDir_None; if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) window->PosFloat = g.IO.MousePos; } @@ -4523,9 +4534,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api) { ImVec2 ref_pos = g.IO.MousePos; - ImRect rect_to_avoid(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24, ref_pos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? + ImRect rect_to_avoid(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24, ref_pos.y + 24); // FIXME: Completely hard-coded. Store boxes in mouse cursor data? Scale? Center on cursor hit-point? window->PosFloat = FindBestPopupWindowPos(ref_pos, window->Size, &window->AutoPosLastDirection, rect_to_avoid); - if (window->AutoPosLastDirection == -1) + if (window->AutoPosLastDirection == ImGuiDir_None) window->PosFloat = ref_pos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. } diff --git a/imgui_internal.h b/imgui_internal.h index 1483a5e7..3a2c6270 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -248,7 +248,8 @@ enum ImGuiDir ImGuiDir_Left = 0, ImGuiDir_Right = 1, ImGuiDir_Up = 2, - ImGuiDir_Down = 3 + ImGuiDir_Down = 3, + ImGuiDir_Count_ }; // 2D axis aligned bounding-box @@ -726,7 +727,7 @@ struct IMGUI_API ImGuiWindow int AutoFitFramesX, AutoFitFramesY; bool AutoFitOnlyGrows; int AutoFitChildAxises; - int AutoPosLastDirection; + ImGuiDir AutoPosLastDirection; int HiddenFrames; ImGuiCond SetWindowPosAllowFlags; // store condition flags for next SetWindowPos() call. ImGuiCond SetWindowSizeAllowFlags; // store condition flags for next SetWindowSize() call. From 3c9f9a455e7d3e81cd42421dab837597d8e52911 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 7 Dec 2017 16:36:07 +0100 Subject: [PATCH 5/5] Internals: Cleanup FindBestPopupWindowPos() to be more digestible, since we are bounds to rework the logic there. No functional changes intended. FIXED TYPO. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4d986dce..360f0f51 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4037,7 +4037,7 @@ static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); if (avail_w < size.x) continue; - float avail_h = (dir == ImGuiDir_Down ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); if (avail_h < size.y) continue;