1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

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.
This commit is contained in:
reuk 2024-11-28 16:19:12 +00:00
parent 2fcf9ebf38
commit fc76e936d3
No known key found for this signature in database

View file

@ -324,12 +324,35 @@ private:
void setNewScreenPos (Point<int> 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