Internals: HoveredWindowUnderMovingWindow special handling for drag and drop of window without altering the _NoInputs window flag, which worked but messed up the IsWindowHovered() user-facing flags.

This commit is contained in:
omar 2018-06-26 19:05:02 +02:00
parent 7abf72ec78
commit 140ece0aeb
2 changed files with 22 additions and 13 deletions

View File

@ -2333,6 +2333,7 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla
// Filter by viewport // Filter by viewport
if (window->Viewport != g.MouseRefViewport) if (window->Viewport != g.MouseRefViewport)
if (g.MovingWindow == NULL || window->RootWindow != g.MovingWindow->RootWindow)
return false; return false;
return true; return true;
@ -4140,11 +4141,11 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
ImGuiWindow* modal_window = GetFrontMostPopupModal(); ImGuiWindow* modal_window = GetFrontMostPopupModal();
if (modal_window) if (modal_window)
if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
g.HoveredRootWindow = g.HoveredWindow = NULL; g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
// Disabled mouse? // Disabled mouse?
if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
g.HoveredWindow = g.HoveredRootWindow = NULL; g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
// We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward.
int mouse_earliest_button_down = -1; int mouse_earliest_button_down = -1;
@ -4164,7 +4165,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
// FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
g.HoveredWindow = g.HoveredRootWindow = NULL; g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
// Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app) // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
if (g.WantCaptureMouseNextFrame != -1) if (g.WantCaptureMouseNextFrame != -1)
@ -4336,9 +4337,12 @@ void ImGui::NewFrame()
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
// Find hovered window
// (needs to be before UpdateMovingWindow so we fill HoveredWindowUnderMovingWindow on the mouse release frame)
UpdateHoveredWindowAndCaptureFlags();
// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
UpdateMovingWindow(); UpdateMovingWindow();
UpdateHoveredWindowAndCaptureFlags();
// Background darkening/whitening // Background darkening/whitening
if (GetFrontMostPopupModal() != NULL || g.NavWindowingTarget != NULL) if (GetFrontMostPopupModal() != NULL || g.NavWindowingTarget != NULL)
@ -4567,8 +4571,7 @@ void ImGui::Shutdown(ImGuiContext* context)
g.CurrentWindowStack.clear(); g.CurrentWindowStack.clear();
g.WindowsById.Clear(); g.WindowsById.Clear();
g.NavWindow = NULL; g.NavWindow = NULL;
g.HoveredWindow = NULL; g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
g.HoveredRootWindow = NULL;
g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
g.MovingWindow = NULL; g.MovingWindow = NULL;
g.ColorModifiers.clear(); g.ColorModifiers.clear();
@ -5527,16 +5530,18 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
} }
// Find window given position, search front-to-back // Find window given position, search front-to-back
// FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected. // FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically with SetWindowPos() and not SetNextWindowPos()
// will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window isn't affected.
static void FindHoveredWindow() static void FindHoveredWindow()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* hovered_window = NULL; ImGuiWindow* hovered_window = NULL;
ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs))
hovered_window = g.MovingWindow; hovered_window = g.MovingWindow;
for (int i = g.Windows.Size - 1; i >= 0 && hovered_window == NULL; i--) for (int i = g.Windows.Size - 1; i >= 0; i--)
{ {
ImGuiWindow* window = g.Windows[i]; ImGuiWindow* window = g.Windows[i];
if (!window->Active) if (!window->Active)
@ -5553,14 +5558,16 @@ static void FindHoveredWindow()
{ {
if (hovered_window == NULL) if (hovered_window == NULL)
hovered_window = window; hovered_window = window;
if (hovered_window) if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
hovered_window_ignoring_moving_window = window;
if (hovered_window && hovered_window_ignoring_moving_window)
break; break;
} }
} }
g.HoveredWindow = hovered_window; g.HoveredWindow = hovered_window;
g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
} }
// Test if mouse cursor is hovering given rectangle // Test if mouse cursor is hovering given rectangle
@ -14685,7 +14692,7 @@ bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
return false; return false;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) if (g.HoveredWindowUnderMovingWindow == NULL || window->RootWindow != g.HoveredWindowUnderMovingWindow->RootWindow)
return false; return false;
IM_ASSERT(id != 0); IM_ASSERT(id != 0);
if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
@ -14711,7 +14718,7 @@ bool ImGui::BeginDragDropTarget()
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
return false; return false;
if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow) if (g.HoveredWindowUnderMovingWindow == NULL || window->RootWindow != g.HoveredWindowUnderMovingWindow->RootWindow)
return false; return false;
const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
@ -15128,6 +15135,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
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", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
ImGui::Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]);
ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");

View File

@ -660,6 +660,7 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Being drawn into ImGuiWindow* CurrentWindow; // Being drawn into
ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
ImGuiWindow* HoveredWindowUnderMovingWindow;
ImGuiID HoveredId; // Hovered widget ImGuiID HoveredId; // Hovered widget
bool HoveredIdAllowOverlap; bool HoveredIdAllowOverlap;
ImGuiID HoveredIdPreviousFrame; ImGuiID HoveredIdPreviousFrame;