Skip to content

Commit f948d03

Browse files
committed
Make it so that dragging on the canvas doesn't clear the selection
Change-Id: I8dcafd2406e65850d775e90d09f2b9ae1211c50c
1 parent e1ca234 commit f948d03

File tree

1 file changed

+33
-9
lines changed

1 file changed

+33
-9
lines changed

ui/src/widgets/nodegraph.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ interface CanvasState {
100100
type: 'input' | 'output';
101101
} | null;
102102
selectionRect: SelectionRect | null; // Box selection state
103+
canvasMouseDownPos: Position;
103104
}
104105

105106
export interface NodeGraphApi {
@@ -303,6 +304,7 @@ export function NodeGraph(): m.Component<NodeGraphAttrs> {
303304
undockCandidate: null,
304305
hoveredPort: null,
305306
selectionRect: null,
307+
canvasMouseDownPos: {x: 0, y: 0},
306308
};
307309

308310
let latestVnode: m.Vnode<NodeGraphAttrs> | null = null;
@@ -1386,24 +1388,46 @@ export function NodeGraph(): m.Component<NodeGraphAttrs> {
13861388
return;
13871389
}
13881390

1389-
// Clear selection if not holding Shift or Cmd/Ctrl (or if multiselect is disabled)
1390-
if (!multiselect || (!e.shiftKey && !e.metaKey && !e.ctrlKey)) {
1391-
canvasState.selectedNodes.clear();
1391+
// Start panning and store position to detect click vs drag
1392+
canvasState.isPanning = true;
1393+
canvasState.panStart = {x: e.clientX, y: e.clientY};
1394+
canvasState.canvasMouseDownPos = {x: e.clientX, y: e.clientY};
1395+
e.preventDefault();
1396+
}
1397+
},
1398+
onclick: (e: MouseEvent) => {
1399+
const target = e.target as HTMLElement;
1400+
// Clear selection on canvas click (only if mouse didn't move significantly)
1401+
if (
1402+
target.classList.contains('pf-canvas') ||
1403+
target.tagName === 'svg'
1404+
) {
1405+
const dx = Math.abs(e.clientX - canvasState.canvasMouseDownPos.x);
1406+
const dy = Math.abs(e.clientY - canvasState.canvasMouseDownPos.y);
1407+
const threshold = 3; // Pixels of movement tolerance
13921408

1393-
// Call onSelectionClear callback
1409+
// Only clear if it was a click (not a drag)
1410+
if (dx <= threshold && dy <= threshold) {
1411+
canvasState.selectedNodes.clear();
13941412
const {onSelectionClear} = vnode.attrs;
13951413
if (onSelectionClear !== undefined) {
13961414
onSelectionClear();
13971415
}
13981416
}
1399-
1400-
canvasState.isPanning = true;
1401-
canvasState.panStart = {x: e.clientX, y: e.clientY};
1402-
e.preventDefault();
14031417
}
14041418
},
14051419
onkeydown: (e: KeyboardEvent) => {
1406-
if (e.key === 'Delete' || e.key === 'Backspace') {
1420+
if (e.key === 'Escape') {
1421+
// Deselect all nodes with Escape key
1422+
if (canvasState.selectedNodes.size > 0) {
1423+
canvasState.selectedNodes.clear();
1424+
const {onSelectionClear} = vnode.attrs;
1425+
if (onSelectionClear !== undefined) {
1426+
onSelectionClear();
1427+
}
1428+
e.preventDefault();
1429+
}
1430+
} else if (e.key === 'Delete' || e.key === 'Backspace') {
14071431
const {onNodeRemove} = vnode.attrs;
14081432
if (canvasState.selectedNodes.size > 0 && onNodeRemove) {
14091433
// Delete all selected nodes

0 commit comments

Comments
 (0)