Skip to content

Commit 1badac9

Browse files
committedJan 14, 2025
1 parent dd8adbc commit 1badac9

File tree

2 files changed

+121
-2
lines changed

2 files changed

+121
-2
lines changed
 

‎packages/eez-studio-ui/draggable.tsx

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { closestBySelector } from "eez-studio-shared/dom";
2+
import { IPointerEvent } from "project-editor/flow/editor/mouse-handler";
23

34
export const DRAGGABLE_OVERLAY_ELEMENT_ID = "eez-draggable-overlay-element";
45

@@ -22,6 +23,7 @@ export class Draggable {
2223
params: any;
2324
savedBodyUserSelect: string | null = null;
2425
capturedPointerId: number = 0;
26+
lastDragMoveEvent: PointerEvent | undefined;
2527

2628
constructor(private config: DraggableConfig) {}
2729

@@ -108,6 +110,7 @@ export class Draggable {
108110
this.element.setPointerCapture(e.pointerId);
109111

110112
this.dragging = true;
113+
this.lastDragMoveEvent = undefined;
111114

112115
this.xDragStart = e.clientX;
113116
this.yDragStart = e.clientY;
@@ -126,6 +129,7 @@ export class Draggable {
126129
onPointerMove = (e: PointerEvent) => {
127130
if (this.dragging) {
128131
if (this.config.onDragMove) {
132+
this.lastDragMoveEvent = e;
129133
this.config.onDragMove(
130134
e,
131135
e.clientX - this.xDragStart,
@@ -155,11 +159,30 @@ export class Draggable {
155159
};
156160

157161
onKeyDown = (e: KeyboardEvent) => {
158-
if (e.keyCode == 27 /* ESC */) {
162+
if (e.key == "Escape") {
159163
e.preventDefault();
160164
e.stopPropagation();
161165

162166
this.finishDragging(undefined, true);
167+
} else if (this.dragging) {
168+
if (this.config.onDragMove && this.lastDragMoveEvent) {
169+
let moveEvent: IPointerEvent = {
170+
clientX: this.lastDragMoveEvent.clientX,
171+
clientY: this.lastDragMoveEvent.clientY,
172+
movementX: this.lastDragMoveEvent.movementX,
173+
movementY: this.lastDragMoveEvent.movementY,
174+
ctrlKey: e.ctrlKey,
175+
shiftKey: e.shiftKey,
176+
timeStamp: e.timeStamp
177+
};
178+
179+
this.config.onDragMove(
180+
moveEvent as PointerEvent,
181+
moveEvent.clientX - this.xDragStart,
182+
moveEvent.clientY - this.yDragStart,
183+
this.params
184+
);
185+
}
163186
}
164187
};
165188

‎packages/project-editor/flow/editor/mouse-handler.tsx

+97-1
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,94 @@ export class DragMouseHandler extends MouseHandlerWithSnapLines {
371371
});
372372
}
373373

374+
getConnectionLineAlignedY(context: IFlowContext, event: IPointerEvent) {
375+
if (!event.ctrlKey) {
376+
return undefined;
377+
}
378+
379+
let foundConnectionLine;
380+
let foundDx = 0;
381+
382+
for (const connectionLine of (context.document.flow.object as Flow)
383+
.connectionLines) {
384+
if (
385+
this.selectedObjects.find(
386+
selectedObject =>
387+
selectedObject.object == connectionLine.sourceComponent
388+
)
389+
) {
390+
// skip connection lines where source is among selected objects
391+
continue;
392+
}
393+
394+
const selectedObject = this.selectedObjects.find(
395+
selectedObject =>
396+
selectedObject.object == connectionLine.targetComponent
397+
);
398+
if (selectedObject) {
399+
const sourceOutputX =
400+
connectionLine.sourceComponent.geometry.left +
401+
connectionLine.sourceComponent.geometry.outputs[
402+
connectionLine.output
403+
].position.x;
404+
405+
const targetInputX =
406+
this.rects[
407+
this.selectedObjects.findIndex(
408+
selectedObject =>
409+
selectedObject.object ==
410+
connectionLine.targetComponent
411+
)
412+
].left +
413+
connectionLine.targetComponent.geometry.inputs[
414+
connectionLine.input
415+
].position.x;
416+
417+
const dx = targetInputX - sourceOutputX;
418+
419+
if (
420+
dx > 0 &&
421+
(!foundConnectionLine || Math.abs(dx) < Math.abs(foundDx))
422+
) {
423+
foundConnectionLine = connectionLine;
424+
foundDx = dx;
425+
}
426+
}
427+
}
428+
429+
if (!foundConnectionLine) {
430+
return undefined;
431+
}
432+
433+
const topSource = foundConnectionLine.sourceComponent.top;
434+
435+
const topBounding = this.selectionBoundingRectAtDown.top;
436+
const topTarget =
437+
this.objectPositionsAtDown[
438+
this.selectedObjects.findIndex(
439+
selectedObject =>
440+
selectedObject.object ==
441+
foundConnectionLine.targetComponent
442+
)
443+
].y;
444+
445+
const sourceOutputY =
446+
foundConnectionLine.sourceComponent.geometry.outputs[
447+
foundConnectionLine.output
448+
].position.y;
449+
450+
const targetInputY =
451+
foundConnectionLine.targetComponent.geometry.inputs[
452+
foundConnectionLine.input
453+
].position.y;
454+
455+
return (
456+
topSource +
457+
(topBounding - topTarget) -
458+
(targetInputY - sourceOutputY)
459+
);
460+
}
461+
374462
down(context: IFlowContext, event: IPointerEvent) {
375463
super.down(context, event);
376464

@@ -403,13 +491,21 @@ export class DragMouseHandler extends MouseHandlerWithSnapLines {
403491
return;
404492
}
405493

406-
const { left, top } = this.snapLines.dragSnap(
494+
let { left, top } = this.snapLines.dragSnap(
407495
this.left,
408496
this.top,
409497
this.selectionBoundingRectAtDown.width,
410498
this.selectionBoundingRectAtDown.height
411499
);
412500

501+
const connectionLineAlignedY = this.getConnectionLineAlignedY(
502+
context,
503+
event
504+
);
505+
if (connectionLineAlignedY) {
506+
top = connectionLineAlignedY;
507+
}
508+
413509
const viewState = context.viewState;
414510

415511
viewState.dxMouseDrag = left - this.selectionBoundingRectAtDown.left;

0 commit comments

Comments
 (0)