Improved behavior of mouse cursor during drag operations; this should also fix behavior on some linux machines that show a "forbidden" cursor while dragging

This commit is contained in:
Bane Stojkovic
2025-12-29 15:44:59 +01:00
parent a9a98bf3a4
commit 49d805a60c
6 changed files with 84 additions and 11 deletions
@@ -251,8 +251,10 @@ public class Presenter implements IPlugInPort {
@Override
public Cursor getCursorAt(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
// Only change the cursor if we're not making a new component.
if (operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS || altDown)
if (operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS || altDown) {
return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
}
if (instantiationManager.getComponentTypeSlot() == null) {
// Scale point to remove zoom factor.
Point2D scaledPoint = scalePoint(point);
@@ -269,6 +271,7 @@ public class Presenter implements IPlugInPort {
}
}
}
return Cursor.getDefaultCursor();
}
@@ -1581,6 +1584,7 @@ public class Presenter implements IPlugInPort {
drawingManager.clearContinuityArea();
projectFileManager.notifyFileChange();
}
messageDispatcher.dispatchMessage(EventType.REPAINT);
dragInProgress = false;
}
@@ -445,9 +445,13 @@
<changeType>NEW_FEATURE</changeType>
<description>Added Chinese simplified (thank you chenjingyuanku) and Hindi UI translation and updated all other languages with new translations</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added configuration for text scale factor in rare cases when system scale factor is not applied correctly; requires adding a configuration property to config.xml with key 'fontScaleFactor' and a desired float value</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Added configuration for text scale factor in rare cases when system scale factor is not applied correctly; requires adding a configuration property to confix.xml with key 'fontScaleFactor' and a desired float value</description>
<description>Improved behavior of mouse cursor during drag operations; this should also fix behavior on some linux machines that show a "forbidden" cursor while dragging</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
@@ -21,6 +21,7 @@
*/
package org.diylc.swing.plugins.canvas;
import java.awt.Cursor;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.event.InputEvent;
@@ -54,7 +55,17 @@ class CanvasDragGestureListener implements DragGestureListener {
}
canvasPanel.setClickInProgress(false);
presenter.dragStarted(dge.getDragOrigin(), dge.getDragAction(), forceReSelection);
dge.startDrag(presenter.getCursorAt(dge.getDragOrigin(), false, false, false), new EmptyTransferable(), new CanvasSourceListener(
// Get the appropriate cursor from the presenter (e.g., HAND_CURSOR over components)
// Preserve the cursor context (HAND_CURSOR, CROSSHAIR_CURSOR, etc.) for drag operations
// On Linux, DEFAULT_CURSOR during drag can show "No" cursor, so use MOVE_CURSOR as fallback
Cursor requestedCursor = presenter.getCursorAt(dge.getDragOrigin(), false, false, false);
Cursor dragCursor = requestedCursor;
// Only replace DEFAULT_CURSOR with MOVE_CURSOR on Linux to prevent "No" cursor issue
// Preserve HAND_CURSOR, CROSSHAIR_CURSOR, etc. as they are appropriate for drag operations
if (requestedCursor.getType() == Cursor.DEFAULT_CURSOR) {
dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
}
dge.startDrag(dragCursor, new EmptyTransferable(), new CanvasSourceListener(
presenter));
}
}
@@ -271,6 +271,8 @@ public class CanvasPlugin implements IPlugIn{
public void mouseMoved(MouseEvent e) {
if (scrollPane.isMouseScrollMode())
return;
// if needed uncomment this code, it forces the cursor to refresh when it's stuck
// canvasPanel.setCursor(null);
canvasPanel.setCursor(plugInPort.getCursorAt(e.getPoint(), Utils.isMac() ? e.isMetaDown() : e.isControlDown(),
e.isShiftDown(), e.isAltDown()));
plugInPort.mouseMoved(e.getPoint(), Utils.isMac() ? e.isMetaDown() : e.isControlDown(),
@@ -21,11 +21,16 @@
*/
package org.diylc.swing.plugins.canvas;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.SwingUtilities;
import org.diylc.common.IPlugInPort;
@@ -50,13 +55,16 @@ class CanvasSourceListener implements DragSourceListener {
}
@Override
public void dragEnter(DragSourceDragEvent dsde) {}
public void dragEnter(DragSourceDragEvent dsde) {
updateCursor(dsde);
}
@Override
public void dragExit(DragSourceEvent dse) {}
@Override
public void dragOver(DragSourceDragEvent dsde) {
updateCursor(dsde);
Point p = dsde.getDragSourceContext().getComponent().getMousePosition();
if (p != null) {
dsde.getDragSourceContext().getComponent().firePropertyChange("dragPoint", p.x, p.y);
@@ -64,5 +72,26 @@ class CanvasSourceListener implements DragSourceListener {
}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {}
public void dropActionChanged(DragSourceDragEvent dsde) {
updateCursor(dsde);
}
/**
* Updates the cursor during drag operations using the presenter as the single source of truth.
* If the presenter returns DEFAULT_CURSOR, uses MOVE_CURSOR to prevent "No" cursor issues.
*/
private void updateCursor(DragSourceDragEvent dsde) {
Point mousePos = dsde.getDragSourceContext().getComponent().getMousePosition();
if (mousePos != null) {
// Use presenter as single source of truth for cursor
Cursor requestedCursor = presenter.getCursorAt(mousePos, false, false, false);
Cursor dragCursor = requestedCursor;
// If DEFAULT_CURSOR, use MOVE_CURSOR to prevent "No" cursor during drag operations
if (requestedCursor.getType() == Cursor.DEFAULT_CURSOR) {
dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
}
dsde.getDragSourceContext().setCursor(null);
dsde.getDragSourceContext().setCursor(dragCursor);
}
}
}
@@ -21,15 +21,13 @@
*/
package org.diylc.swing.plugins.canvas;
import java.awt.Point;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.*;
import java.awt.dnd.*;
import org.diylc.common.IPlugInPort;
import javax.swing.*;
/**
* {@link DropTargetListener} for {@link CanvasPanel}.
@@ -106,10 +104,35 @@ class CanvasTargetListener implements DropTargetListener {
@Override
public void drop(DropTargetDropEvent dtde) {
presenter.dragEnded(dtde.getLocation());
updateCursor(dtde);
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
presenter.dragActionChanged(dtde.getDropAction());
}
/**
* Updates the cursor during drag operations using the presenter as the single source of truth.
* If the presenter returns DEFAULT_CURSOR, uses MOVE_CURSOR to prevent "No" cursor issues.
*/
private void updateCursor(DropTargetDropEvent dsde) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Point mousePos = dsde.getDropTargetContext().getComponent().getMousePosition();
if (mousePos != null) {
// Use presenter as single source of truth for cursor
Cursor requestedCursor = presenter.getCursorAt(mousePos, false, false, false);
Cursor dragCursor = requestedCursor;
// If DEFAULT_CURSOR, use MOVE_CURSOR to prevent "No" cursor during drag operations
if (requestedCursor.getType() == Cursor.DEFAULT_CURSOR) {
dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
}
dsde.getDropTargetContext().getComponent().setCursor(null);
dsde.getDropTargetContext().getComponent().setCursor(dragCursor);
}
}
});
}
}