|
|
@@ -11,16 +11,16 @@
|
|
|
// - FAQ http://dearimgui.org/faq
|
|
|
// - Homepage & latest https://github.com/ocornut/imgui
|
|
|
// - Releases & changelog https://github.com/ocornut/imgui/releases
|
|
|
-// - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!)
|
|
|
+// - Gallery https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!)
|
|
|
+// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
|
|
|
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
|
|
|
-// - Wiki https://github.com/ocornut/imgui/wiki
|
|
|
// - Issues & support https://github.com/ocornut/imgui/issues
|
|
|
// - Discussions https://github.com/ocornut/imgui/discussions
|
|
|
|
|
|
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
|
|
|
// See LICENSE.txt for copyright and licensing details (standard MIT License).
|
|
|
// This library is free but needs your support to sustain development and maintenance.
|
|
|
-// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org".
|
|
|
+// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com".
|
|
|
// Individuals: you can support continued development via donations. See docs/README or web page.
|
|
|
|
|
|
// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
|
|
|
@@ -134,13 +134,13 @@ CODE
|
|
|
|
|
|
READ FIRST
|
|
|
----------
|
|
|
- - Remember to read the FAQ (https://www.dearimgui.org/faq)
|
|
|
+ - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
|
|
|
- Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or
|
|
|
destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs.
|
|
|
- Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
|
|
|
- The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
|
|
|
- Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
|
|
|
- You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ.
|
|
|
+ You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
|
|
|
- Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
|
|
|
For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
|
|
|
where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
|
|
|
@@ -576,7 +576,7 @@ CODE
|
|
|
- 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
|
|
|
- 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
|
|
|
- 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
|
|
|
- - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild().
|
|
|
+ - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().
|
|
|
- 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
|
|
|
- 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
|
|
|
- 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal.
|
|
|
@@ -744,14 +744,14 @@ CODE
|
|
|
==============
|
|
|
|
|
|
Q: How can I help?
|
|
|
- A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui!
|
|
|
+ A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui!
|
|
|
We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
|
|
|
This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project.
|
|
|
- Individuals: you can support continued development via PayPal donations. See README.
|
|
|
- If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt
|
|
|
and see how you want to help and can help!
|
|
|
- Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
|
|
|
- You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3488). Visuals are ideal as they inspire other programmers.
|
|
|
+ You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
|
|
|
But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.
|
|
|
- If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately).
|
|
|
|
|
|
@@ -860,7 +860,7 @@ static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time
|
|
|
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
|
|
|
|
|
|
// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
|
|
|
-static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
|
|
|
+static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
|
|
|
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
|
|
|
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
|
|
|
|
|
|
@@ -899,8 +899,8 @@ static void NavUpdateInitResult();
|
|
|
static float NavUpdatePageUpPageDown();
|
|
|
static inline void NavUpdateAnyRequestFlag();
|
|
|
static void NavEndFrame();
|
|
|
-static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
|
|
|
-static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
|
|
|
+static bool NavScoreItem(ImGuiNavItemData* result, ImRect cand);
|
|
|
+static void NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
|
|
|
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
|
|
|
static ImVec2 NavCalcPreferredRefPos();
|
|
|
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
|
|
|
@@ -3740,10 +3740,17 @@ void ImGui::UpdateMouseWheel()
|
|
|
|
|
|
// Mouse wheel scrolling
|
|
|
// If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
|
|
|
+ if (g.IO.KeyCtrl)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
|
|
|
+ // (we avoid doing it on OSX as it the OS input layer handles this already)
|
|
|
+ const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
|
|
|
+ const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel;
|
|
|
+ const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH;
|
|
|
|
|
|
// Vertical Mouse Wheel scrolling
|
|
|
- const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
|
|
|
- if (wheel_y != 0.0f && !g.IO.KeyCtrl)
|
|
|
+ if (wheel_y != 0.0f)
|
|
|
{
|
|
|
StartLockWheelingWindow(window);
|
|
|
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
|
|
|
@@ -3757,8 +3764,7 @@ void ImGui::UpdateMouseWheel()
|
|
|
}
|
|
|
|
|
|
// Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
|
|
|
- const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
|
|
|
- if (wheel_x != 0.0f && !g.IO.KeyCtrl)
|
|
|
+ if (wheel_x != 0.0f)
|
|
|
{
|
|
|
StartLockWheelingWindow(window);
|
|
|
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
|
|
|
@@ -3812,6 +3818,7 @@ void ImGui::UpdateTabFocus()
|
|
|
void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
+ g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
|
|
|
|
|
|
// Find the window hovered by mouse:
|
|
|
// - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
|
|
|
@@ -4029,7 +4036,7 @@ void ImGui::NewFrame()
|
|
|
UpdateTabFocus();
|
|
|
|
|
|
// Mark all windows as not visible and compact unused memory.
|
|
|
- IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
|
|
|
+ IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
|
|
|
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
|
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
|
{
|
|
|
@@ -4541,7 +4548,7 @@ static void FindHoveredWindow()
|
|
|
hovered_window = g.MovingWindow;
|
|
|
|
|
|
ImVec2 padding_regular = g.Style.TouchExtraPadding;
|
|
|
- ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
|
|
|
+ ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;
|
|
|
for (int i = g.Windows.Size - 1; i >= 0; i--)
|
|
|
{
|
|
|
ImGuiWindow* window = g.Windows[i];
|
|
|
@@ -4555,7 +4562,7 @@ static void FindHoveredWindow()
|
|
|
if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
|
|
|
bb.Expand(padding_regular);
|
|
|
else
|
|
|
- bb.Expand(padding_for_resize_from_edges);
|
|
|
+ bb.Expand(padding_for_resize);
|
|
|
if (!bb.Contains(g.IO.MousePos))
|
|
|
continue;
|
|
|
|
|
|
@@ -4984,7 +4991,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
|
|
|
parent_window->DC.CursorPos = child_window->Pos;
|
|
|
|
|
|
// Process navigation-in immediately so NavInit can run on first frame
|
|
|
- if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
|
|
|
+ if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll))
|
|
|
{
|
|
|
FocusWindow(child_window);
|
|
|
NavInitWindow(child_window, false);
|
|
|
@@ -5031,13 +5038,13 @@ void ImGui::EndChild()
|
|
|
ImGuiWindow* parent_window = g.CurrentWindow;
|
|
|
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
|
|
|
ItemSize(sz);
|
|
|
- if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
|
|
|
+ if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
|
|
|
{
|
|
|
ItemAdd(bb, window->ChildId);
|
|
|
RenderNavHighlight(bb, window->ChildId);
|
|
|
|
|
|
// When browsing a window that has no activable items (scroll only) we keep a highlight on the child
|
|
|
- if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
|
|
|
+ if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)
|
|
|
RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
|
|
|
}
|
|
|
else
|
|
|
@@ -5138,7 +5145,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
|
|
|
window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
|
|
|
}
|
|
|
|
|
|
- g.WindowsFocusOrder.push_back(window);
|
|
|
+ if (!(flags & ImGuiWindowFlags_ChildWindow))
|
|
|
+ {
|
|
|
+ g.WindowsFocusOrder.push_back(window);
|
|
|
+ window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
|
|
|
+ }
|
|
|
+
|
|
|
if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
|
|
|
g.Windows.push_front(window); // Quite slow but rare and only once
|
|
|
else
|
|
|
@@ -5272,53 +5284,64 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co
|
|
|
*out_size = size_constrained;
|
|
|
}
|
|
|
|
|
|
+// Data for resizing from corner
|
|
|
struct ImGuiResizeGripDef
|
|
|
{
|
|
|
ImVec2 CornerPosN;
|
|
|
ImVec2 InnerDir;
|
|
|
int AngleMin12, AngleMax12;
|
|
|
};
|
|
|
-
|
|
|
static const ImGuiResizeGripDef resize_grip_def[4] =
|
|
|
{
|
|
|
- { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
|
|
|
- { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
|
|
|
- { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
|
|
|
- { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused)
|
|
|
+ { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
|
|
|
+ { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
|
|
|
+ { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
|
|
|
+ { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused)
|
|
|
};
|
|
|
|
|
|
+// Data for resizing from borders
|
|
|
struct ImGuiResizeBorderDef
|
|
|
{
|
|
|
ImVec2 InnerDir;
|
|
|
- ImVec2 CornerPosN1, CornerPosN2;
|
|
|
+ ImVec2 SegmentN1, SegmentN2;
|
|
|
float OuterAngle;
|
|
|
};
|
|
|
-
|
|
|
static const ImGuiResizeBorderDef resize_border_def[4] =
|
|
|
{
|
|
|
- { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top
|
|
|
+ { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left
|
|
|
{ ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
|
|
|
- { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom
|
|
|
- { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left
|
|
|
+ { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up
|
|
|
+ { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down
|
|
|
};
|
|
|
|
|
|
static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
|
|
|
{
|
|
|
ImRect rect = window->Rect();
|
|
|
- if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
|
|
|
- if (border_n == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } // Top
|
|
|
- if (border_n == 1) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } // Right
|
|
|
- if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } // Bottom
|
|
|
- if (border_n == 3) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } // Left
|
|
|
+ if (thickness == 0.0f)
|
|
|
+ rect.Max -= ImVec2(1, 1);
|
|
|
+ if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }
|
|
|
+ if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }
|
|
|
+ if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }
|
|
|
+ if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }
|
|
|
IM_ASSERT(0);
|
|
|
return ImRect();
|
|
|
}
|
|
|
|
|
|
// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
|
|
|
-// 4..7: borders (Top, Right, Bottom, Left)
|
|
|
-ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
|
|
|
+ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n)
|
|
|
{
|
|
|
- IM_ASSERT(n >= 0 && n <= 7);
|
|
|
+ IM_ASSERT(n >= 0 && n < 4);
|
|
|
+ ImGuiID id = window->ID;
|
|
|
+ id = ImHashStr("#RESIZE", 0, id);
|
|
|
+ id = ImHashData(&n, sizeof(int), id);
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+// Borders (Left, Right, Up, Down)
|
|
|
+ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir)
|
|
|
+{
|
|
|
+ IM_ASSERT(dir >= 0 && dir < 4);
|
|
|
+ int n = (int)dir + 4;
|
|
|
ImGuiID id = window->ID;
|
|
|
id = ImHashStr("#RESIZE", 0, id);
|
|
|
id = ImHashData(&n, sizeof(int), id);
|
|
|
@@ -5341,7 +5364,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
|
|
|
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
|
|
|
const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
|
|
|
const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
|
|
|
- const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
|
|
|
+ const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;
|
|
|
|
|
|
ImVec2 pos_target(FLT_MAX, FLT_MAX);
|
|
|
ImVec2 size_target(FLT_MAX, FLT_MAX);
|
|
|
@@ -5353,15 +5376,16 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
|
|
|
PushID("#RESIZE");
|
|
|
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
|
|
|
{
|
|
|
- const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
|
|
|
- const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
|
|
|
+ const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];
|
|
|
+ const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);
|
|
|
|
|
|
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
|
|
|
- ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
|
|
|
+ bool hovered, held;
|
|
|
+ ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);
|
|
|
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
|
|
|
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
|
|
|
- bool hovered, held;
|
|
|
- ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
|
|
|
+ ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
|
|
|
+ ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
|
|
|
//GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
|
|
|
if (hovered || held)
|
|
|
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
|
|
|
@@ -5377,39 +5401,41 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
|
|
|
{
|
|
|
// Resize from any of the four corners
|
|
|
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
|
|
|
- ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip
|
|
|
- ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
|
|
|
- ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
|
|
|
+ ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
|
|
|
+ ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
|
|
|
+ ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
|
|
|
corner_target = ImClamp(corner_target, clamp_min, clamp_max);
|
|
|
- CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
|
|
|
+ CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
|
|
|
}
|
|
|
+
|
|
|
+ // Only lower-left grip is visible before hovering/activating
|
|
|
if (resize_grip_n == 0 || held || hovered)
|
|
|
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
|
|
|
}
|
|
|
for (int border_n = 0; border_n < resize_border_count; border_n++)
|
|
|
{
|
|
|
+ const ImGuiResizeBorderDef& def = resize_border_def[border_n];
|
|
|
+ const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
|
|
|
+
|
|
|
bool hovered, held;
|
|
|
- ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
|
|
|
- ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
|
|
|
+ ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
|
|
|
+ ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
|
|
|
+ ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren);
|
|
|
//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
|
|
|
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
|
|
|
{
|
|
|
- g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
|
|
|
+ g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
|
|
|
if (held)
|
|
|
*border_held = border_n;
|
|
|
}
|
|
|
if (held)
|
|
|
{
|
|
|
+ ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX);
|
|
|
+ ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX);
|
|
|
ImVec2 border_target = window->Pos;
|
|
|
- ImVec2 border_posn;
|
|
|
- if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top
|
|
|
- if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right
|
|
|
- if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom
|
|
|
- if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left
|
|
|
- ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX);
|
|
|
- ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX);
|
|
|
+ border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;
|
|
|
border_target = ImClamp(border_target, clamp_min, clamp_max);
|
|
|
- CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
|
|
|
+ CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
|
|
|
}
|
|
|
}
|
|
|
PopID();
|
|
|
@@ -5476,8 +5502,8 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
|
|
|
{
|
|
|
const ImGuiResizeBorderDef& def = resize_border_def[border_held];
|
|
|
ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
|
|
|
- window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
|
|
|
- window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
|
|
|
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
|
|
|
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
|
|
|
window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual
|
|
|
}
|
|
|
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
|
|
|
@@ -5705,14 +5731,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
|
|
|
// Update the Appearing flag
|
|
|
bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
|
|
|
- const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
|
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
|
{
|
|
|
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
|
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
|
|
|
window_just_activated_by_user |= (window != popup_ref.Window);
|
|
|
}
|
|
|
- window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
|
|
|
+ window->Appearing = window_just_activated_by_user;
|
|
|
if (window->Appearing)
|
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
|
|
|
|
|
|
@@ -5839,6 +5864,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
|
|
|
|
|
|
// Update contents size from last frame for auto-fitting (or use explicit size)
|
|
|
+ const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
|
|
|
CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
|
|
|
if (window->HiddenFramesCanSkipItems > 0)
|
|
|
window->HiddenFramesCanSkipItems--;
|
|
|
@@ -6201,8 +6227,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
|
|
|
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
|
|
|
- window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
|
|
|
- window->DC.NavLayerActiveMaskNext = 0x00;
|
|
|
+ window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;
|
|
|
+ window->DC.NavLayersActiveMaskNext = 0x00;
|
|
|
window->DC.NavHideHighlightOneFrame = false;
|
|
|
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
|
|
|
|
|
|
@@ -6359,15 +6385,22 @@ void ImGui::End()
|
|
|
void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(window == window->RootWindow);
|
|
|
+
|
|
|
+ const int cur_order = window->FocusOrder;
|
|
|
+ IM_ASSERT(g.WindowsFocusOrder[cur_order] == window);
|
|
|
if (g.WindowsFocusOrder.back() == window)
|
|
|
return;
|
|
|
- for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
|
|
|
- if (g.WindowsFocusOrder[i] == window)
|
|
|
- {
|
|
|
- memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
|
|
|
- g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
|
|
|
- break;
|
|
|
- }
|
|
|
+
|
|
|
+ const int new_order = g.WindowsFocusOrder.Size - 1;
|
|
|
+ for (int n = cur_order; n < new_order; n++)
|
|
|
+ {
|
|
|
+ g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];
|
|
|
+ g.WindowsFocusOrder[n]->FocusOrder--;
|
|
|
+ IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);
|
|
|
+ }
|
|
|
+ g.WindowsFocusOrder[new_order] = window;
|
|
|
+ window->FocusOrder = (short)new_order;
|
|
|
}
|
|
|
|
|
|
void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
|
|
|
@@ -6447,18 +6480,13 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
|
|
- int start_idx = g.WindowsFocusOrder.Size - 1;
|
|
|
- if (under_this_window != NULL)
|
|
|
- {
|
|
|
- int under_this_window_idx = FindWindowFocusIndex(under_this_window);
|
|
|
- if (under_this_window_idx != -1)
|
|
|
- start_idx = under_this_window_idx - 1;
|
|
|
- }
|
|
|
+ const int start_idx = ((under_this_window != NULL) ? FindWindowFocusIndex(under_this_window) : g.WindowsFocusOrder.Size) - 1;
|
|
|
for (int i = start_idx; i >= 0; i--)
|
|
|
{
|
|
|
// We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.
|
|
|
ImGuiWindow* window = g.WindowsFocusOrder[i];
|
|
|
- if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
|
|
|
+ IM_ASSERT(window == window->RootWindow);
|
|
|
+ if (window != ignore_window && window->WasActive)
|
|
|
if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
|
|
|
{
|
|
|
ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
|
|
|
@@ -6951,11 +6979,11 @@ void ImGui::SetItemDefaultFocus()
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
if (!window->Appearing)
|
|
|
return;
|
|
|
- if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
|
|
|
+ if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
|
|
|
{
|
|
|
g.NavInitRequest = false;
|
|
|
- g.NavInitResultId = g.NavWindow->DC.LastItemId;
|
|
|
- g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
|
|
|
+ g.NavInitResultId = window->DC.LastItemId;
|
|
|
+ g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
|
|
|
NavUpdateAnyRequestFlag();
|
|
|
if (!IsItemVisible())
|
|
|
SetScrollHereY();
|
|
|
@@ -7364,7 +7392,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
|
|
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
|
|
|
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
|
|
|
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
|
|
|
- window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
|
|
|
+ window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
|
|
|
if (g.NavId == id || g.NavAnyRequest)
|
|
|
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
|
|
|
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
|
|
|
@@ -8080,6 +8108,11 @@ void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
|
OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
|
|
|
}
|
|
|
|
|
|
+void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags)
|
|
|
+{
|
|
|
+ OpenPopupEx(id, popup_flags);
|
|
|
+}
|
|
|
+
|
|
|
// Mark popup as open (toggle toward open state).
|
|
|
// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
|
|
|
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
|
|
|
@@ -8339,10 +8372,21 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags
|
|
|
}
|
|
|
|
|
|
// This is a helper to handle the simplest case of associating one named popup to one given widget.
|
|
|
-// - You can pass a NULL str_id to use the identifier of the last item.
|
|
|
-// - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
|
|
|
-// - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid
|
|
|
-// computing the ID twice because BeginPopupContextXXX functions may be called very frequently.
|
|
|
+// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
|
|
|
+// - To create a popup with a specific identifier, pass it in str_id.
|
|
|
+// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
|
|
|
+// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
|
|
|
+// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
|
|
|
+// This is essentially the same as:
|
|
|
+// id = str_id ? GetID(str_id) : GetItemID();
|
|
|
+// OpenPopupOnItemClick(str_id);
|
|
|
+// return BeginPopup(id);
|
|
|
+// Which is essentially the same as:
|
|
|
+// id = str_id ? GetID(str_id) : GetItemID();
|
|
|
+// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
|
|
|
+// OpenPopup(id);
|
|
|
+// return BeginPopup(id);
|
|
|
+// The main difference being that this is tweaked to avoid computing the ID twice.
|
|
|
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
|
|
|
{
|
|
|
ImGuiWindow* window = GImGui->CurrentWindow;
|
|
|
@@ -8517,13 +8561,13 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
|
|
|
-void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
|
|
|
+void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
IM_ASSERT(g.NavWindow != NULL);
|
|
|
IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
|
|
|
g.NavId = id;
|
|
|
- g.NavLayer = (ImGuiNavLayer)nav_layer;
|
|
|
+ g.NavLayer = nav_layer;
|
|
|
g.NavFocusScopeId = focus_scope_id;
|
|
|
g.NavWindow->NavLastIds[nav_layer] = id;
|
|
|
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
|
|
|
@@ -8586,7 +8630,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
|
|
|
}
|
|
|
|
|
|
// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
|
|
|
-static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
|
|
|
+static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
@@ -8717,7 +8761,7 @@ static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
|
|
|
return new_best;
|
|
|
}
|
|
|
|
|
|
-static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
|
|
|
+static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
|
|
|
{
|
|
|
result->Window = window;
|
|
|
result->ID = id;
|
|
|
@@ -8755,7 +8799,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
|
|
|
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
|
|
|
if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
|
|
{
|
|
|
- ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
+ ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
#if IMGUI_DEBUG_NAV_SCORING
|
|
|
// [DEBUG] Score all items in NavWindow at all times
|
|
|
if (!g.NavMoveRequest)
|
|
|
@@ -8874,10 +8918,16 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
IM_ASSERT(window == g.NavWindow);
|
|
|
+
|
|
|
+ if (window->Flags & ImGuiWindowFlags_NoNavInputs)
|
|
|
+ {
|
|
|
+ g.NavId = g.NavFocusScopeId = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
bool init_for_nav = false;
|
|
|
- if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
- if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
|
|
|
- init_for_nav = true;
|
|
|
+ if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
|
|
|
+ init_for_nav = true;
|
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
|
|
|
if (init_for_nav)
|
|
|
{
|
|
|
@@ -8991,8 +9041,16 @@ static void ImGui::NavUpdate()
|
|
|
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
|
|
|
if (io.KeyShift)
|
|
|
io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
|
|
|
- if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
|
|
|
+
|
|
|
+ // AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl)
|
|
|
+ // But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
|
|
|
+ if (io.KeyAlt && !io.KeyCtrl)
|
|
|
io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
|
|
|
+
|
|
|
+ // We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370)
|
|
|
+ if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0)
|
|
|
+ g.NavWindowingToggleLayer = false;
|
|
|
+
|
|
|
#undef NAV_MAP_KEY
|
|
|
}
|
|
|
memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
|
|
|
@@ -9058,6 +9116,11 @@ static void ImGui::NavUpdate()
|
|
|
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
|
|
|
ClearActiveID();
|
|
|
}
|
|
|
+ else if (g.NavLayer != ImGuiNavLayer_Main)
|
|
|
+ {
|
|
|
+ // Leave the "menu" layer
|
|
|
+ NavRestoreLayer(ImGuiNavLayer_Main);
|
|
|
+ }
|
|
|
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
|
{
|
|
|
// Exit child window
|
|
|
@@ -9074,11 +9137,6 @@ static void ImGui::NavUpdate()
|
|
|
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
|
|
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
|
|
}
|
|
|
- else if (g.NavLayer != ImGuiNavLayer_Main)
|
|
|
- {
|
|
|
- // Leave the "menu" layer
|
|
|
- NavRestoreLayer(ImGuiNavLayer_Main);
|
|
|
- }
|
|
|
else
|
|
|
{
|
|
|
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
|
|
|
@@ -9168,7 +9226,7 @@ static void ImGui::NavUpdate()
|
|
|
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
|
|
|
ImGuiWindow* window = g.NavWindow;
|
|
|
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
|
|
- if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
|
|
+ if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
|
|
{
|
|
|
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
|
|
|
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
|
|
@@ -9234,6 +9292,7 @@ static void ImGui::NavUpdateInitResult()
|
|
|
return;
|
|
|
|
|
|
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
|
|
|
+ // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
|
|
|
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
|
|
|
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
|
|
|
if (g.NavInitRequestFromMove)
|
|
|
@@ -9259,7 +9318,7 @@ static void ImGui::NavUpdateMoveResult()
|
|
|
}
|
|
|
|
|
|
// Select which result to use
|
|
|
- ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
+ ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
|
|
|
// PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
|
|
|
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
|
|
|
@@ -9326,7 +9385,7 @@ static float ImGui::NavUpdatePageUpPageDown()
|
|
|
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
|
|
|
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
|
|
|
{
|
|
|
- if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
|
|
|
+ if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
|
|
|
{
|
|
|
// Fallback manual-scroll when window has no navigable item
|
|
|
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
|
|
|
@@ -9444,13 +9503,12 @@ static void ImGui::NavEndFrame()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
|
|
|
+static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
|
|
|
- if (g.WindowsFocusOrder[i] == window)
|
|
|
- return i;
|
|
|
- return -1;
|
|
|
+ int order = window->FocusOrder;
|
|
|
+ IM_ASSERT(g.WindowsFocusOrder[order] == window);
|
|
|
+ return order;
|
|
|
}
|
|
|
|
|
|
static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
|
|
|
@@ -9589,8 +9647,9 @@ static void ImGui::NavUpdateWindowing()
|
|
|
if (apply_focus_window->NavLastIds[0] == 0)
|
|
|
NavInitWindow(apply_focus_window, false);
|
|
|
|
|
|
- // If the window only has a menu layer, select it directly
|
|
|
- if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
|
|
|
+ // If the window has ONLY a menu layer (no main layer), select it directly
|
|
|
+ // FIXME-NAV: This should be done in NavInit.. or in FocusWindow..
|
|
|
+ if (apply_focus_window->DC.NavLayersActiveMask == (1 << ImGuiNavLayer_Menu))
|
|
|
g.NavLayer = ImGuiNavLayer_Menu;
|
|
|
}
|
|
|
if (apply_focus_window)
|
|
|
@@ -9599,10 +9658,12 @@ static void ImGui::NavUpdateWindowing()
|
|
|
// Apply menu/layer toggle
|
|
|
if (apply_toggle_layer && g.NavWindow)
|
|
|
{
|
|
|
+ ClearActiveID();
|
|
|
+
|
|
|
// Move to parent menu if necessary
|
|
|
ImGuiWindow* new_nav_window = g.NavWindow;
|
|
|
while (new_nav_window->ParentWindow
|
|
|
- && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
|
|
|
+ && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
|
|
|
&& (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
|
|
|
&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
|
|
|
new_nav_window = new_nav_window->ParentWindow;
|
|
|
@@ -9616,7 +9677,7 @@ static void ImGui::NavUpdateWindowing()
|
|
|
g.NavDisableMouseHover = true;
|
|
|
|
|
|
// Reinitialize navigation when entering menu bar with the Alt key.
|
|
|
- const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
|
|
|
+ const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
|
|
|
if (new_nav_layer == ImGuiNavLayer_Menu)
|
|
|
g.NavWindow->NavLastIds[new_nav_layer] = 0;
|
|
|
NavRestoreLayer(new_nav_layer);
|
|
|
@@ -11092,7 +11153,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|
|
// Misc Details
|
|
|
if (TreeNode("Internal state"))
|
|
|
{
|
|
|
- const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
|
|
|
+ const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
|
|
|
|
|
|
Text("WINDOWING");
|
|
|
Indent();
|
|
|
@@ -11424,12 +11485,19 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
|
|
|
BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
|
|
|
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
|
|
|
BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
|
|
|
- BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
|
|
|
- BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
|
|
|
- if (!window->NavRectRel[0].IsInverted())
|
|
|
- BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
|
|
|
- else
|
|
|
- BulletText("NavRectRel[0]: <None>");
|
|
|
+ for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
|
|
|
+ {
|
|
|
+ ImRect r = window->NavRectRel[layer];
|
|
|
+ if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)
|
|
|
+ {
|
|
|
+ BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
|
|
|
+ if (IsItemHovered())
|
|
|
+ GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255));
|
|
|
+ }
|
|
|
+ BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
|
|
|
if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
|
|
|
if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
|
|
|
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
|