From fc76e936d3bcd79642b9244abd2b5f45698c1124 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 28 Nov 2024 16:19:12 +0000 Subject: [PATCH] DragImageComponent: Avoid case where image may detach from mouse when dragging between screens When two monitors are available, both with different scale factors, then the drag-image may 'detach' from the mouse while the image's top-left coordinate was on one display, and the mouse cursor was on the other display. This happened because, on Windows, the mouse cursor moves continuously in physical (not logical!) space. In other words, the mouse may not move continuously in logical space, and the discontinuity becomes visible when components are positioned relative to the mouse in logical space. In order to display consistently, the top-left position of the image must be set relative to the physical position of the mouse. --- .../mouse/juce_DragAndDropContainer.cpp | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp b/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp index 88fe008996..3ec2a0b18d 100644 --- a/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp +++ b/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp @@ -324,12 +324,35 @@ private: void setNewScreenPos (Point screenPos) { - auto newPos = screenPos - imageOffset; + setTopLeftPosition (std::invoke ([&] + { + if (auto* p = getParentComponent()) + return p->getLocalPoint (nullptr, screenPos - imageOffset); - if (auto* p = getParentComponent()) - newPos = p->getLocalPoint (nullptr, newPos); + #if JUCE_WINDOWS + // On Windows, the mouse position is continuous in physical pixels across screen boundaries. + // i.e. if two screens are set to different scale factors, when the mouse moves horizontally + // between those screens, the mouse's physical y coordinate will be preserved, and if + // the mouse moves vertically between screens its physical x coordinate will be preserved. - setTopLeftPosition (newPos); + // To avoid the dragged image detaching from the mouse, compute the new top left position + // in physical coords and then convert back to logical. + // If we were to stay in logical coordinates the whole time, the image may detach from the + // mouse because the mouse does not move continuously in logical coordinate space. + + const auto& displays = Desktop::getInstance().getDisplays(); + const auto physicalPos = displays.logicalToPhysical (screenPos); + + float scale = 1.0f; + + if (auto* p = getPeer()) + scale = (float) p->getPlatformScaleFactor(); + + return displays.physicalToLogical (physicalPos - (imageOffset * scale)); + #else + return screenPos - imageOffset; + #endif + })); } void sendDragMove (DragAndDropTarget::SourceDetails& details) const