@eclipse-glsp/client 2.2.0-next.340 → 2.2.0-next.342
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/change-bounds.css +0 -9
- package/lib/base/mouse-position-tracker.d.ts +4 -1
- package/lib/base/mouse-position-tracker.d.ts.map +1 -1
- package/lib/base/mouse-position-tracker.js +21 -0
- package/lib/base/mouse-position-tracker.js.map +1 -1
- package/lib/features/debug/debug-manager.d.ts +2 -2
- package/lib/features/debug/debug-manager.d.ts.map +1 -1
- package/lib/features/debug/debug-manager.js +8 -6
- package/lib/features/debug/debug-manager.js.map +1 -1
- package/lib/features/element-template/mouse-tracking-element-position-listener.d.ts.map +1 -1
- package/lib/features/element-template/mouse-tracking-element-position-listener.js +3 -2
- package/lib/features/element-template/mouse-tracking-element-position-listener.js.map +1 -1
- package/lib/features/export/glsp-svg-exporter.d.ts +24 -2
- package/lib/features/export/glsp-svg-exporter.d.ts.map +1 -1
- package/lib/features/export/glsp-svg-exporter.js +75 -17
- package/lib/features/export/glsp-svg-exporter.js.map +1 -1
- package/lib/features/grid/grid-manager.d.ts.map +1 -1
- package/lib/features/grid/grid-manager.js +5 -3
- package/lib/features/grid/grid-manager.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js +3 -6
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool.d.ts +3 -1
- package/lib/features/tools/change-bounds/change-bounds-tool.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool.js +10 -12
- package/lib/features/tools/change-bounds/change-bounds-tool.js.map +1 -1
- package/lib/features/tools/edge-creation/edge-creation-tool.d.ts +3 -0
- package/lib/features/tools/edge-creation/edge-creation-tool.d.ts.map +1 -1
- package/lib/features/tools/edge-creation/edge-creation-tool.js +14 -4
- package/lib/features/tools/edge-creation/edge-creation-tool.js.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts +6 -3
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js +20 -10
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool.d.ts +1 -0
- package/lib/features/tools/edge-edit/edge-edit-tool.d.ts.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool.js +5 -3
- package/lib/features/tools/edge-edit/edge-edit-tool.js.map +1 -1
- package/lib/features/tools/node-creation/container-manager.d.ts +7 -6
- package/lib/features/tools/node-creation/container-manager.d.ts.map +1 -1
- package/lib/features/tools/node-creation/container-manager.js +1 -1
- package/lib/features/tools/node-creation/container-manager.js.map +1 -1
- package/lib/features/tools/node-creation/insert-indicator.d.ts.map +1 -1
- package/lib/features/tools/node-creation/insert-indicator.js +1 -1
- package/lib/features/tools/node-creation/insert-indicator.js.map +1 -1
- package/lib/features/tools/node-creation/node-creation-tool.d.ts +3 -2
- package/lib/features/tools/node-creation/node-creation-tool.d.ts.map +1 -1
- package/lib/features/tools/node-creation/node-creation-tool.js +13 -4
- package/lib/features/tools/node-creation/node-creation-tool.js.map +1 -1
- package/package.json +3 -3
- package/src/base/mouse-position-tracker.ts +25 -2
- package/src/features/debug/debug-manager.ts +9 -7
- package/src/features/element-template/mouse-tracking-element-position-listener.ts +3 -2
- package/src/features/export/glsp-svg-exporter.ts +87 -18
- package/src/features/grid/grid-manager.ts +5 -3
- package/src/features/tools/change-bounds/change-bounds-tool-move-feedback.ts +3 -5
- package/src/features/tools/change-bounds/change-bounds-tool.ts +10 -12
- package/src/features/tools/edge-creation/edge-creation-tool.ts +17 -9
- package/src/features/tools/edge-edit/edge-edit-tool-feedback.ts +22 -9
- package/src/features/tools/edge-edit/edge-edit-tool.ts +6 -2
- package/src/features/tools/node-creation/container-manager.ts +9 -7
- package/src/features/tools/node-creation/insert-indicator.ts +1 -1
- package/src/features/tools/node-creation/node-creation-tool.ts +24 -4
|
@@ -14,12 +14,35 @@
|
|
|
14
14
|
*
|
|
15
15
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
16
16
|
********************************************************************************/
|
|
17
|
-
import {
|
|
18
|
-
|
|
17
|
+
import {
|
|
18
|
+
Action,
|
|
19
|
+
DOMHelper,
|
|
20
|
+
GModelElement,
|
|
21
|
+
MousePositionTracker,
|
|
22
|
+
Point,
|
|
23
|
+
TYPES,
|
|
24
|
+
ViewerOptions,
|
|
25
|
+
getAbsoluteClientBounds
|
|
26
|
+
} from '@eclipse-glsp/sprotty';
|
|
27
|
+
import { inject, injectable } from 'inversify';
|
|
19
28
|
import { Ranked } from './ranked';
|
|
20
29
|
|
|
21
30
|
@injectable()
|
|
22
31
|
export class GLSPMousePositionTracker extends MousePositionTracker implements Ranked {
|
|
23
32
|
/* we want to be executed before all default mouse listeners since we are just tracking the position and others may need it */
|
|
24
33
|
rank = Ranked.DEFAULT_RANK - 200;
|
|
34
|
+
|
|
35
|
+
@inject(TYPES.ViewerOptions) protected viewerOptions: ViewerOptions;
|
|
36
|
+
@inject(TYPES.DOMHelper) protected domHelper: DOMHelper;
|
|
37
|
+
|
|
38
|
+
override mouseMove(target: GModelElement, event: MouseEvent): (Action | Promise<Action>)[] {
|
|
39
|
+
// we cannot simply use the offsetX and offsetY properties of the event since they also consider nested HTML elements
|
|
40
|
+
// such as foreignObjects or the projection bars divs. Instead, we manually translate the client coordinates to the diagram
|
|
41
|
+
const clientToRoot = getAbsoluteClientBounds(target.root, this.domHelper, this.viewerOptions);
|
|
42
|
+
const clientToPosition = { x: event.clientX, y: event.clientY };
|
|
43
|
+
const rootToPosition = Point.subtract(clientToPosition, clientToRoot);
|
|
44
|
+
const positionOnDiagram = target.root.parentToLocal(rootToPosition);
|
|
45
|
+
this.lastPosition = positionOnDiagram;
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
25
48
|
}
|
|
@@ -32,19 +32,21 @@ export class DebugManager implements IActionHandler {
|
|
|
32
32
|
return this._debugEnabled;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
handle(action: EnableDebugModeAction): void {
|
|
36
|
-
this._debugEnabled = action.enable;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
35
|
@postConstruct()
|
|
40
36
|
protected init(): void {
|
|
41
37
|
this.debugFeedback = this.feedbackDispatcher.createEmitter();
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
handle(action: EnableDebugModeAction): void {
|
|
41
|
+
this.setDebugEnabled(action.enable);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setDebugEnabled(enabled: boolean): void {
|
|
45
|
+
if (this._debugEnabled && !enabled) {
|
|
46
|
+
this._debugEnabled = false;
|
|
46
47
|
this.debugFeedback.dispose();
|
|
47
|
-
} else {
|
|
48
|
+
} else if (!this._debugEnabled && enabled) {
|
|
49
|
+
this._debugEnabled = true;
|
|
48
50
|
this.debugFeedback
|
|
49
51
|
.add(EnableDebugModeAction.create({ enable: true }), EnableDebugModeAction.create({ enable: false }))
|
|
50
52
|
.submit();
|
|
@@ -54,10 +54,11 @@ export class MouseTrackingElementPositionListener extends DragAwareMouseListener
|
|
|
54
54
|
if (!element) {
|
|
55
55
|
return [];
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
const isInitializing = !this.tracker.isTracking();
|
|
58
|
+
if (isInitializing) {
|
|
58
59
|
this.initialize(element, ctx, event);
|
|
59
60
|
}
|
|
60
|
-
const move = this.tracker.moveElements([element], { snap: event, restrict: event });
|
|
61
|
+
const move = this.tracker.moveElements([element], { snap: event, restrict: event, skipStatic: !isInitializing });
|
|
61
62
|
const elementMove = move.elementMoves[0];
|
|
62
63
|
if (!elementMove) {
|
|
63
64
|
return [];
|
|
@@ -13,38 +13,107 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
+
import { ExportSvgAction, GModelRoot, RequestAction, SvgExporter } from '@eclipse-glsp/sprotty';
|
|
16
17
|
import { injectable } from 'inversify';
|
|
17
18
|
import { v4 as uuid } from 'uuid';
|
|
18
|
-
import { ExportSvgAction, RequestAction, GModelRoot, SvgExporter } from '@eclipse-glsp/sprotty';
|
|
19
19
|
|
|
20
20
|
@injectable()
|
|
21
21
|
export class GLSPSvgExporter extends SvgExporter {
|
|
22
|
-
override export(root: GModelRoot,
|
|
22
|
+
override export(root: GModelRoot, request?: RequestAction<ExportSvgAction>): void {
|
|
23
23
|
if (typeof document !== 'undefined') {
|
|
24
|
-
|
|
24
|
+
let svgElement = this.findSvgElement();
|
|
25
25
|
if (svgElement) {
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const bounds = this.getBounds(root);
|
|
32
|
-
const svg = this.createSvg(svgElement, root).replace(
|
|
33
|
-
'style="',
|
|
34
|
-
`style="width: ${bounds.width}px !important;height: ${bounds.height}px !important;border: none !important;`
|
|
35
|
-
);
|
|
36
|
-
// do not give request/response id here as otherwise the action is treated as an unrequested response
|
|
37
|
-
this.actionDispatcher.dispatch(ExportSvgAction.create(svg));
|
|
38
|
-
} finally {
|
|
39
|
-
svgElement.id = originalId;
|
|
40
|
-
}
|
|
26
|
+
svgElement = this.prepareSvgElement(svgElement, root, request);
|
|
27
|
+
const serializedSvg = this.createSvg(svgElement, root);
|
|
28
|
+
const svgExport = this.getSvgExport(serializedSvg, svgElement, root, request);
|
|
29
|
+
// do not give request/response id here as otherwise the action is treated as an unrequested response
|
|
30
|
+
this.actionDispatcher.dispatch(ExportSvgAction.create(svgExport));
|
|
41
31
|
}
|
|
42
32
|
}
|
|
43
33
|
}
|
|
44
34
|
|
|
35
|
+
protected override createSvg(svgElement: SVGSVGElement, root: GModelRoot): string {
|
|
36
|
+
// createSvg requires the svg to have a non-empty id, so we generate one if necessary
|
|
37
|
+
const originalId = svgElement.id;
|
|
38
|
+
try {
|
|
39
|
+
svgElement.id = originalId || uuid();
|
|
40
|
+
return super.createSvg(svgElement, root);
|
|
41
|
+
} finally {
|
|
42
|
+
svgElement.id = originalId;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
45
46
|
protected findSvgElement(): SVGSVGElement | null {
|
|
46
47
|
const div = document.getElementById(this.options.hiddenDiv);
|
|
47
48
|
// search for first svg element as hierarchy within Sprotty might change
|
|
48
49
|
return div && div.querySelector('svg');
|
|
49
50
|
}
|
|
51
|
+
|
|
52
|
+
protected prepareSvgElement(svgElement: SVGSVGElement, root: GModelRoot, request?: RequestAction<ExportSvgAction>): SVGSVGElement {
|
|
53
|
+
return svgElement;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected override copyStyles(source: Element, target: Element, skippedProperties: string[]): void {
|
|
57
|
+
this.copyStyle(source, target, skippedProperties);
|
|
58
|
+
|
|
59
|
+
// IE doesn't retrun anything on source.children
|
|
60
|
+
for (let i = 0; i < source.childNodes.length; ++i) {
|
|
61
|
+
const sourceChild = source.childNodes[i];
|
|
62
|
+
const targetChild = target.childNodes[i];
|
|
63
|
+
if (sourceChild instanceof Element) {
|
|
64
|
+
this.copyStyles(sourceChild, targetChild as Element, []);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
protected copyStyle(source: Element, target: Element, skippedProperties: string[]): void {
|
|
70
|
+
const sourceStyle = getComputedStyle(source);
|
|
71
|
+
const targetStyle = getComputedStyle(target);
|
|
72
|
+
|
|
73
|
+
let style = '';
|
|
74
|
+
for (let i = 0; i < sourceStyle.length; i++) {
|
|
75
|
+
const propertyName = sourceStyle[i];
|
|
76
|
+
if (!skippedProperties.includes(propertyName)) {
|
|
77
|
+
const propertyValue = sourceStyle.getPropertyValue(propertyName);
|
|
78
|
+
const propertyPriority = sourceStyle.getPropertyPriority(propertyName);
|
|
79
|
+
if (targetStyle.getPropertyValue(propertyName) !== propertyValue) {
|
|
80
|
+
if (isElementCSSInlineStyle(target)) {
|
|
81
|
+
// rather set the property directly on the element to keep other values intact
|
|
82
|
+
target.style.setProperty(propertyName, propertyValue);
|
|
83
|
+
} else {
|
|
84
|
+
// collect all properties to set them at once
|
|
85
|
+
style += `${propertyName}: ${propertyValue}${propertyPriority ? ' !' + propertyPriority : ''}; `;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (style !== '') {
|
|
91
|
+
target.setAttribute('style', style.trim());
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected getSvgExport(
|
|
96
|
+
serializedSvgElement: string,
|
|
97
|
+
svgElement: SVGElement,
|
|
98
|
+
root: GModelRoot,
|
|
99
|
+
request?: RequestAction<ExportSvgAction>
|
|
100
|
+
): string {
|
|
101
|
+
const svgExportStyle = this.getSvgExportStyle(svgElement, root, request);
|
|
102
|
+
return svgExportStyle ? serializedSvgElement.replace('style="', `style="${svgExportStyle}`) : serializedSvgElement;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected getSvgExportStyle(svgElement: SVGElement, root: GModelRoot, request?: RequestAction<ExportSvgAction>): string | undefined {
|
|
106
|
+
// provide generated svg code with respective sizing for proper viewing in browser and remove undesired border
|
|
107
|
+
const bounds = this.getBounds(root);
|
|
108
|
+
return (
|
|
109
|
+
`width: ${bounds.width}px !important;` +
|
|
110
|
+
`height: ${bounds.height}px !important;` +
|
|
111
|
+
'border: none !important;' +
|
|
112
|
+
'cursor: default !important;'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function isElementCSSInlineStyle(element: any): element is ElementCSSInlineStyle {
|
|
118
|
+
return 'style' in element && element.style instanceof CSSStyleDeclaration;
|
|
50
119
|
}
|
|
@@ -44,13 +44,15 @@ export class GridManager implements IActionHandler {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
handle(action: ShowGridAction): void {
|
|
47
|
-
this.
|
|
47
|
+
this.setGridVisible(action.show);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
setGridVisible(visible: boolean): void {
|
|
51
|
-
if (!visible) {
|
|
51
|
+
if (this._gridVisible && !visible) {
|
|
52
|
+
this._gridVisible = false;
|
|
52
53
|
this.gridFeedback.dispose();
|
|
53
|
-
} else {
|
|
54
|
+
} else if (!this._gridVisible && visible) {
|
|
55
|
+
this._gridVisible = true;
|
|
54
56
|
this.gridFeedback.add(ShowGridAction.create({ show: true }), ShowGridAction.create({ show: false })).submit();
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -112,11 +112,9 @@ export class FeedbackMoveMouseListener extends DragAwareMouseListener {
|
|
|
112
112
|
return [];
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
override
|
|
116
|
-
super.
|
|
117
|
-
if (
|
|
118
|
-
return this.mouseUp(target, event);
|
|
119
|
-
} else if (this.tracker.isTracking()) {
|
|
115
|
+
override draggingMouseMove(target: GModelElement, event: MouseEvent): Action[] {
|
|
116
|
+
super.draggingMouseMove(target, event);
|
|
117
|
+
if (this.tracker.isTracking()) {
|
|
120
118
|
return this.moveElements(target, event);
|
|
121
119
|
}
|
|
122
120
|
return [];
|
|
@@ -180,7 +180,7 @@ export class ChangeBoundsListener extends DragAwareMouseListener implements ISel
|
|
|
180
180
|
this.handleFeedback.submit();
|
|
181
181
|
return true;
|
|
182
182
|
} else {
|
|
183
|
-
this.
|
|
183
|
+
this.disposeResize();
|
|
184
184
|
return false;
|
|
185
185
|
}
|
|
186
186
|
}
|
|
@@ -233,21 +233,19 @@ export class ChangeBoundsListener extends DragAwareMouseListener implements ISel
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
override draggingMouseUp(target: GModelElement, event: MouseEvent): Action[] {
|
|
236
|
-
if (!this.tracker.isTracking()) {
|
|
237
|
-
return [];
|
|
238
|
-
}
|
|
239
236
|
const actions: Action[] = [];
|
|
240
237
|
if (this.activeResizeHandle) {
|
|
241
238
|
actions.push(...this.handleResizeOnServer(this.activeResizeHandle));
|
|
242
239
|
} else {
|
|
240
|
+
// since the move feedback is handled by another class we just see whether there is something to move
|
|
243
241
|
actions.push(...this.handleMoveOnServer(target));
|
|
244
242
|
}
|
|
245
|
-
this.
|
|
243
|
+
this.disposeResize({ keepHandles: true });
|
|
246
244
|
return actions;
|
|
247
245
|
}
|
|
248
246
|
|
|
249
247
|
override nonDraggingMouseUp(element: GModelElement, event: MouseEvent): Action[] {
|
|
250
|
-
this.
|
|
248
|
+
this.disposeResize({ keepHandles: true });
|
|
251
249
|
return super.nonDraggingMouseUp(element, event);
|
|
252
250
|
}
|
|
253
251
|
|
|
@@ -347,19 +345,19 @@ export class ChangeBoundsListener extends DragAwareMouseListener implements ISel
|
|
|
347
345
|
return element !== undefined && this.activeResizeElement !== undefined && element.id === this.activeResizeElement.id;
|
|
348
346
|
}
|
|
349
347
|
|
|
350
|
-
protected
|
|
351
|
-
|
|
352
|
-
|
|
348
|
+
protected disposeResize(opts: { keepHandles: boolean } = { keepHandles: false }): void {
|
|
349
|
+
if (!opts.keepHandles) {
|
|
350
|
+
this.handleFeedback.dispose();
|
|
351
|
+
}
|
|
353
352
|
this.resizeFeedback.dispose();
|
|
354
353
|
this.tracker.dispose();
|
|
355
354
|
this.activeResizeElement = undefined;
|
|
356
355
|
this.activeResizeHandle = undefined;
|
|
357
356
|
this.initialBounds = undefined;
|
|
358
|
-
super.dispose();
|
|
359
357
|
}
|
|
360
358
|
|
|
361
359
|
override dispose(): void {
|
|
362
|
-
this.
|
|
363
|
-
|
|
360
|
+
this.disposeResize();
|
|
361
|
+
super.dispose();
|
|
364
362
|
}
|
|
365
363
|
}
|
|
@@ -56,24 +56,32 @@ export class EdgeCreationTool extends BaseCreationTool<TriggerEdgeCreationAction
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
doEnable(): void {
|
|
59
|
-
|
|
59
|
+
this.toolFeedback();
|
|
60
|
+
this.creationListener();
|
|
61
|
+
this.trackFeedbackEdge();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected toolFeedback(): void {
|
|
60
65
|
const toolFeedback = this.createFeedbackEmitter()
|
|
61
66
|
.add(cursorFeedbackAction(CursorCSS.OPERATION_NOT_ALLOWED), cursorFeedbackAction())
|
|
62
67
|
.submit();
|
|
68
|
+
this.toDisposeOnDisable.push(toolFeedback);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected creationListener(): void {
|
|
63
72
|
const creationListener = new EdgeCreationToolMouseListener(
|
|
64
73
|
this.triggerAction,
|
|
65
74
|
this.actionDispatcher,
|
|
66
75
|
this.typeHintProvider,
|
|
67
76
|
this,
|
|
68
|
-
this.grid
|
|
69
|
-
);
|
|
70
|
-
this.toDisposeOnDisable.push(
|
|
71
|
-
mouseMovingFeedback,
|
|
72
|
-
this.mouseTool.registerListener(mouseMovingFeedback),
|
|
73
|
-
creationListener,
|
|
74
|
-
this.mouseTool.registerListener(creationListener),
|
|
75
|
-
toolFeedback
|
|
77
|
+
this.grid ? this.grid.x / 2 : undefined
|
|
76
78
|
);
|
|
79
|
+
this.toDisposeOnDisable.push(creationListener, this.mouseTool.registerListener(creationListener));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
protected trackFeedbackEdge(): void {
|
|
83
|
+
const mouseMovingFeedback = new FeedbackEdgeEndMovingMouseListener(this.anchorRegistry, this.feedbackDispatcher);
|
|
84
|
+
this.toDisposeOnDisable.push(mouseMovingFeedback, this.mouseTool.registerListener(mouseMovingFeedback));
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
typeGuard
|
|
42
42
|
} from '@eclipse-glsp/sprotty';
|
|
43
43
|
import { inject, injectable } from 'inversify';
|
|
44
|
+
import { DragAwareMouseListener } from '../../../base/drag-aware-mouse-listener';
|
|
44
45
|
import { IFeedbackActionDispatcher } from '../../../base/feedback/feedback-action-dispatcher';
|
|
45
46
|
import { FeedbackCommand } from '../../../base/feedback/feedback-command';
|
|
46
47
|
import { FeedbackEmitter } from '../../../base/feedback/feedback-emitter';
|
|
@@ -254,7 +255,7 @@ export class FeedbackEdgeSourceMovingMouseListener extends MouseListener impleme
|
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
export class FeedbackEdgeRouteMovingMouseListener extends
|
|
258
|
+
export class FeedbackEdgeRouteMovingMouseListener extends DragAwareMouseListener {
|
|
258
259
|
protected tracker: ChangeBoundsTracker;
|
|
259
260
|
|
|
260
261
|
constructor(
|
|
@@ -266,7 +267,7 @@ export class FeedbackEdgeRouteMovingMouseListener extends MouseListener {
|
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
override mouseDown(target: GModelElement, event: MouseEvent): Action[] {
|
|
269
|
-
const result
|
|
270
|
+
const result = super.mouseDown(target, event);
|
|
270
271
|
if (event.button === 0) {
|
|
271
272
|
const routingHandle = findParentByFeature(target, isRoutingHandle);
|
|
272
273
|
if (routingHandle !== undefined) {
|
|
@@ -279,11 +280,9 @@ export class FeedbackEdgeRouteMovingMouseListener extends MouseListener {
|
|
|
279
280
|
return result;
|
|
280
281
|
}
|
|
281
282
|
|
|
282
|
-
override
|
|
283
|
-
super.
|
|
284
|
-
if (
|
|
285
|
-
return this.mouseUp(target, event);
|
|
286
|
-
} else if (this.tracker.isTracking()) {
|
|
283
|
+
override draggingMouseMove(target: GModelElement, event: MouseEvent): Action[] {
|
|
284
|
+
super.draggingMouseMove(target, event);
|
|
285
|
+
if (this.tracker.isTracking()) {
|
|
287
286
|
return this.moveRoutingHandles(target, event);
|
|
288
287
|
}
|
|
289
288
|
return [];
|
|
@@ -327,10 +326,24 @@ export class FeedbackEdgeRouteMovingMouseListener extends MouseListener {
|
|
|
327
326
|
return undefined;
|
|
328
327
|
}
|
|
329
328
|
|
|
330
|
-
override
|
|
331
|
-
|
|
329
|
+
override nonDraggingMouseUp(element: GModelElement, event: MouseEvent): Action[] {
|
|
330
|
+
// should reset everything that may have happend on mouse down
|
|
331
|
+
this.tracker.stopTracking();
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
override draggingMouseUp(_target: GModelElement, _event: MouseEvent): Action[] {
|
|
336
|
+
if (!this.tracker.isTracking()) {
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
this.dispose();
|
|
332
340
|
return [];
|
|
333
341
|
}
|
|
342
|
+
|
|
343
|
+
override dispose(): void {
|
|
344
|
+
this.tracker.dispose();
|
|
345
|
+
super.dispose();
|
|
346
|
+
}
|
|
334
347
|
}
|
|
335
348
|
|
|
336
349
|
/**
|
|
@@ -80,6 +80,7 @@ export class EdgeEditTool extends BaseEditTool {
|
|
|
80
80
|
this.mouseTool.registerListener(this.edgeEditListener),
|
|
81
81
|
this.feedbackEdgeSourceMovingListener,
|
|
82
82
|
this.feedbackEdgeTargetMovingListener,
|
|
83
|
+
this.feedbackMovingListener,
|
|
83
84
|
this.selectionService.onSelectionChanged(change => this.edgeEditListener.selectionChanged(change.root, change.selectedElements))
|
|
84
85
|
);
|
|
85
86
|
}
|
|
@@ -110,10 +111,12 @@ export class EdgeEditListener extends DragAwareMouseListener implements ISelecti
|
|
|
110
111
|
// active reconnect handle data
|
|
111
112
|
protected reconnectMode?: 'NEW_SOURCE' | 'NEW_TARGET';
|
|
112
113
|
|
|
114
|
+
protected cursorFeedback: FeedbackEmitter;
|
|
113
115
|
protected editFeedback: FeedbackEmitter;
|
|
114
116
|
|
|
115
117
|
constructor(protected tool: EdgeEditTool) {
|
|
116
118
|
super();
|
|
119
|
+
this.cursorFeedback = this.tool.createFeedbackEmitter();
|
|
117
120
|
this.editFeedback = this.tool.createFeedbackEmitter();
|
|
118
121
|
}
|
|
119
122
|
|
|
@@ -264,11 +267,11 @@ export class EdgeEditListener extends DragAwareMouseListener implements ISelecti
|
|
|
264
267
|
(this.reconnectMode === 'NEW_SOURCE' && currentTarget.canConnect(this.edge, 'source')) ||
|
|
265
268
|
(this.reconnectMode === 'NEW_TARGET' && currentTarget.canConnect(this.edge, 'target'))
|
|
266
269
|
) {
|
|
267
|
-
this.
|
|
270
|
+
this.cursorFeedback.add(cursorFeedbackAction(CursorCSS.EDGE_RECONNECT), cursorFeedbackAction()).submit();
|
|
268
271
|
return [];
|
|
269
272
|
}
|
|
270
273
|
}
|
|
271
|
-
this.
|
|
274
|
+
this.cursorFeedback.add(cursorFeedbackAction(CursorCSS.OPERATION_NOT_ALLOWED), cursorFeedbackAction()).submit();
|
|
272
275
|
}
|
|
273
276
|
}
|
|
274
277
|
return [];
|
|
@@ -307,6 +310,7 @@ export class EdgeEditListener extends DragAwareMouseListener implements ISelecti
|
|
|
307
310
|
this.reconnectMode = undefined;
|
|
308
311
|
this.newConnectable = undefined;
|
|
309
312
|
this.routingHandle = undefined;
|
|
313
|
+
this.cursorFeedback.dispose();
|
|
310
314
|
this.editFeedback.dispose();
|
|
311
315
|
this.tool.deregisterFeedbackListeners();
|
|
312
316
|
super.dispose();
|
|
@@ -20,12 +20,6 @@ import { CSS_GHOST_ELEMENT, CursorCSS, cursorFeedbackAction } from '../../../bas
|
|
|
20
20
|
import { FeedbackEmitter } from '../../../base/feedback/feedback-emitter';
|
|
21
21
|
import { ContainerElement, isContainable } from '../../hints/model';
|
|
22
22
|
import { ChangeBoundsManager } from '../change-bounds/change-bounds-manager';
|
|
23
|
-
export interface TrackedInsert {
|
|
24
|
-
elementTypeId: string;
|
|
25
|
-
location: Point;
|
|
26
|
-
container?: GModelElement;
|
|
27
|
-
valid: boolean;
|
|
28
|
-
}
|
|
29
23
|
|
|
30
24
|
export interface InsertOptions extends Record<string, unknown> {
|
|
31
25
|
/** Flag to indicate whether the location within a container needs to be valid. Default: false */
|
|
@@ -42,6 +36,14 @@ export const DEFAULT_INSERT_OPTIONS: InsertOptions = {
|
|
|
42
36
|
validateLocationInContainer: false
|
|
43
37
|
};
|
|
44
38
|
|
|
39
|
+
export interface TrackedInsert {
|
|
40
|
+
elementTypeId: string;
|
|
41
|
+
location: Point;
|
|
42
|
+
container?: GModelElement;
|
|
43
|
+
valid: boolean;
|
|
44
|
+
options: InsertOptions;
|
|
45
|
+
}
|
|
46
|
+
|
|
45
47
|
@injectable()
|
|
46
48
|
export class ContainerManager {
|
|
47
49
|
@inject(ChangeBoundsManager) protected readonly changeBoundsManager: ChangeBoundsManager;
|
|
@@ -54,7 +56,7 @@ export class ContainerManager {
|
|
|
54
56
|
// we need to check whether the location is valid either because we do not have a container or the option is set
|
|
55
57
|
valid = opts?.validLocationOverwrite ?? this.changeBoundsManager.hasValidPosition(proxy, location);
|
|
56
58
|
}
|
|
57
|
-
return { elementTypeId, container, location, valid };
|
|
59
|
+
return { elementTypeId, container, location, valid, options };
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
findContainer(location: Point, ctx: GModelElement, evt?: MouseEvent): ContainerElement | undefined {
|
|
@@ -29,7 +29,7 @@ export class InsertIndicator extends GNode implements ArgsAware {
|
|
|
29
29
|
override type: string = InsertIndicator.TYPE;
|
|
30
30
|
override features?: FeatureSet = createFeatureSet(InsertIndicator.DEFAULT_FEATURES);
|
|
31
31
|
override cssClasses: string[] = ['insert-indicator', 'sprotty-node'];
|
|
32
|
-
override size: Dimension =
|
|
32
|
+
override size: Dimension = Dimension.ZERO;
|
|
33
33
|
args: Args = {};
|
|
34
34
|
|
|
35
35
|
constructor(length?: number) {
|
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import {
|
|
17
17
|
Action,
|
|
18
|
+
Args,
|
|
19
|
+
Bounds,
|
|
18
20
|
CreateNodeOperation,
|
|
21
|
+
Dimension,
|
|
19
22
|
Disposable,
|
|
20
23
|
DisposableCollection,
|
|
21
24
|
GModelElement,
|
|
@@ -24,6 +27,7 @@ import {
|
|
|
24
27
|
Point,
|
|
25
28
|
TYPES,
|
|
26
29
|
TriggerNodeCreationAction,
|
|
30
|
+
isBoundsAware,
|
|
27
31
|
isCtrlOrCmd,
|
|
28
32
|
isMoveable
|
|
29
33
|
} from '@eclipse-glsp/sprotty';
|
|
@@ -129,16 +133,16 @@ export class NodeCreationToolMouseListener extends DragAwareMouseListener {
|
|
|
129
133
|
return this.triggerAction.elementTypeId;
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
override nonDraggingMouseUp(
|
|
136
|
+
override nonDraggingMouseUp(ctx: GModelElement, event: MouseEvent): Action[] {
|
|
133
137
|
const result: Action[] = [];
|
|
134
138
|
|
|
135
|
-
const insert = this.getTrackedInsert(
|
|
139
|
+
const insert = this.getTrackedInsert(ctx, event);
|
|
136
140
|
if (insert.valid) {
|
|
137
141
|
result.push(
|
|
138
142
|
CreateNodeOperation.create(this.elementTypeId, {
|
|
139
143
|
location: insert.location,
|
|
140
144
|
containerId: insert.container?.id,
|
|
141
|
-
args: this.
|
|
145
|
+
args: this.getCreateNodeOperationArgs(insert, ctx, event)
|
|
142
146
|
})
|
|
143
147
|
);
|
|
144
148
|
}
|
|
@@ -158,6 +162,22 @@ export class NodeCreationToolMouseListener extends DragAwareMouseListener {
|
|
|
158
162
|
return result;
|
|
159
163
|
}
|
|
160
164
|
|
|
165
|
+
protected getCreateNodeOperationArgs(insert: TrackedInsert, ctx: GModelElement, event: MouseEvent): Args | undefined {
|
|
166
|
+
let args = { ...this.triggerAction.args };
|
|
167
|
+
const ghostElement = this.getGhostElement(ctx, event);
|
|
168
|
+
if (ghostElement) {
|
|
169
|
+
const ghostDimensions = isBoundsAware(ghostElement) ? Bounds.dimension(ghostElement.bounds) : Dimension.ZERO;
|
|
170
|
+
args = {
|
|
171
|
+
...args,
|
|
172
|
+
'ghost-x': ghostElement.position.x,
|
|
173
|
+
'ghost-y': ghostElement.position.y,
|
|
174
|
+
'ghost-width': ghostDimensions.width,
|
|
175
|
+
'ghost-height': ghostDimensions.height
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return args;
|
|
179
|
+
}
|
|
180
|
+
|
|
161
181
|
protected createGhostElement(ghostElement: GhostElement): string {
|
|
162
182
|
const templates = [ghostElement.template];
|
|
163
183
|
this.ghostElementFeedback.add(
|
|
@@ -176,7 +196,7 @@ export class NodeCreationToolMouseListener extends DragAwareMouseListener {
|
|
|
176
196
|
protected getTrackedInsert(ctx: GModelElement, event: MouseEvent): TrackedInsert {
|
|
177
197
|
const ghostElement = this.getGhostElement(ctx, event);
|
|
178
198
|
if (!ghostElement) {
|
|
179
|
-
return { elementTypeId: this.elementTypeId, location: Point.ORIGIN, valid: false };
|
|
199
|
+
return { elementTypeId: this.elementTypeId, location: Point.ORIGIN, valid: false, options: { evt: event } };
|
|
180
200
|
}
|
|
181
201
|
return this.tool.containerManager.insert(ghostElement, ghostElement.position, this.elementTypeId, { evt: event });
|
|
182
202
|
}
|