@eclipse-glsp/client 0.10.0-next.e5fcffe.169 → 1.1.0-next.282a632.186
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/decoration.css +5 -1
- package/css/glsp-sprotty.css +39 -0
- package/css/tool-palette.css +2 -2
- package/lib/base/container-modules.d.ts.map +1 -1
- package/lib/base/container-modules.js +10 -9
- package/lib/base/container-modules.js.map +1 -1
- package/lib/base/editor-context-service.d.ts +2 -3
- package/lib/base/editor-context-service.d.ts.map +1 -1
- package/lib/base/editor-context-service.js +11 -12
- package/lib/base/editor-context-service.js.map +1 -1
- package/lib/base/model/update-model-command.d.ts +14 -7
- package/lib/base/model/update-model-command.d.ts.map +1 -1
- package/lib/base/model/update-model-command.js +31 -41
- package/lib/base/model/update-model-command.js.map +1 -1
- package/lib/base/source-uri-aware.d.ts +2 -17
- package/lib/base/source-uri-aware.d.ts.map +1 -1
- package/lib/base/source-uri-aware.js +4 -6
- package/lib/base/source-uri-aware.js.map +1 -1
- package/lib/features/change-bounds/movement-restrictor.d.ts +36 -6
- package/lib/features/change-bounds/movement-restrictor.d.ts.map +1 -1
- package/lib/features/change-bounds/movement-restrictor.js +54 -39
- package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
- package/lib/features/change-bounds/snap.d.ts +20 -5
- package/lib/features/change-bounds/snap.d.ts.map +1 -1
- package/lib/features/change-bounds/snap.js +19 -8
- package/lib/features/change-bounds/snap.js.map +1 -1
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts +5 -7
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts.map +1 -1
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js +7 -14
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js.map +1 -1
- package/lib/features/hover/hover.d.ts +1 -2
- package/lib/features/hover/hover.d.ts.map +1 -1
- package/lib/features/hover/hover.js +2 -15
- package/lib/features/hover/hover.js.map +1 -1
- package/lib/features/layout/di.config.d.ts +2 -2
- package/lib/features/layout/di.config.d.ts.map +1 -1
- package/lib/features/layout/di.config.js +8 -5
- package/lib/features/layout/di.config.js.map +1 -1
- package/lib/features/layout/hbox-layout.d.ts +1 -1
- package/lib/features/layout/hbox-layout.d.ts.map +1 -1
- package/lib/features/layout/hbox-layout.js +19 -7
- package/lib/features/layout/hbox-layout.js.map +1 -1
- package/lib/features/layout/{layout-commands.d.ts → layout-elements-action.d.ts} +75 -57
- package/lib/features/layout/layout-elements-action.d.ts.map +1 -0
- package/lib/features/layout/{layout-commands.js → layout-elements-action.js} +153 -197
- package/lib/features/layout/layout-elements-action.js.map +1 -0
- package/lib/features/layout/layout-elements-action.spec.d.ts +3 -0
- package/lib/features/layout/layout-elements-action.spec.d.ts.map +1 -0
- package/lib/features/layout/{layout-commands.spec.js → layout-elements-action.spec.js} +63 -56
- package/lib/features/layout/layout-elements-action.spec.js.map +1 -0
- package/lib/features/layout/layouter.d.ts +37 -0
- package/lib/features/layout/layouter.d.ts.map +1 -0
- package/lib/features/layout/layouter.js +131 -0
- package/lib/features/layout/layouter.js.map +1 -0
- package/lib/features/layout/vbox-layout.d.ts +1 -1
- package/lib/features/layout/vbox-layout.d.ts.map +1 -1
- package/lib/features/layout/vbox-layout.js +17 -5
- package/lib/features/layout/vbox-layout.js.map +1 -1
- package/lib/features/mouse-tool/mouse-tool.d.ts +0 -1
- package/lib/features/mouse-tool/mouse-tool.d.ts.map +1 -1
- package/lib/features/mouse-tool/mouse-tool.js +9 -5
- package/lib/features/mouse-tool/mouse-tool.js.map +1 -1
- package/lib/features/select/select-mouse-listener.d.ts +3 -1
- package/lib/features/select/select-mouse-listener.d.ts.map +1 -1
- package/lib/features/select/select-mouse-listener.js +62 -0
- package/lib/features/select/select-mouse-listener.js.map +1 -1
- package/lib/features/select/selection-service.d.ts +12 -3
- package/lib/features/select/selection-service.d.ts.map +1 -1
- package/lib/features/select/selection-service.js +31 -45
- package/lib/features/select/selection-service.js.map +1 -1
- package/lib/features/select/selection-service.spec.js +1 -1
- package/lib/features/select/selection-service.spec.js.map +1 -1
- package/lib/features/source-model-watcher/di.config.d.ts +4 -0
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.d.ts.map +1 -1
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js +4 -4
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js.map +1 -1
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts → source-model-watcher/source-model-changed-action-handler.d.ts} +9 -9
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts.map → source-model-watcher/source-model-changed-action-handler.d.ts.map} +1 -1
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.js → source-model-watcher/source-model-changed-action-handler.js} +19 -19
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.js.map → source-model-watcher/source-model-changed-action-handler.js.map} +1 -1
- package/lib/features/tool-feedback/change-bounds-tool-feedback.js +1 -1
- package/lib/features/tool-feedback/change-bounds-tool-feedback.js.map +1 -1
- package/lib/features/tool-feedback/edge-edit-tool-feedback.d.ts +3 -2
- package/lib/features/tool-feedback/edge-edit-tool-feedback.d.ts.map +1 -1
- package/lib/features/tool-feedback/edge-edit-tool-feedback.js +13 -6
- package/lib/features/tool-feedback/edge-edit-tool-feedback.js.map +1 -1
- package/lib/features/tools/di.config.d.ts +9 -2
- package/lib/features/tools/di.config.d.ts.map +1 -1
- package/lib/features/tools/di.config.js +14 -3
- package/lib/features/tools/di.config.js.map +1 -1
- package/lib/features/tools/enable-default-tools-on-focus-loss.d.ts +26 -0
- package/lib/features/tools/enable-default-tools-on-focus-loss.d.ts.map +1 -0
- package/lib/features/tools/enable-default-tools-on-focus-loss.js +29 -0
- package/lib/features/tools/enable-default-tools-on-focus-loss.js.map +1 -0
- package/lib/features/validation/di.config.d.ts +0 -15
- package/lib/features/validation/di.config.d.ts.map +1 -1
- package/lib/features/validation/di.config.js +6 -4
- package/lib/features/validation/di.config.js.map +1 -1
- package/lib/features/validation/issue-marker.d.ts +11 -5
- package/lib/features/validation/issue-marker.d.ts.map +1 -1
- package/lib/features/validation/issue-marker.js +25 -5
- package/lib/features/validation/issue-marker.js.map +1 -1
- package/lib/features/validation/marker-navigator.d.ts +11 -17
- package/lib/features/validation/marker-navigator.d.ts.map +1 -1
- package/lib/features/validation/marker-navigator.js +32 -61
- package/lib/features/validation/marker-navigator.js.map +1 -1
- package/lib/features/validation/validate.d.ts +8 -19
- package/lib/features/validation/validate.d.ts.map +1 -1
- package/lib/features/validation/validate.js +29 -55
- package/lib/features/validation/validate.js.map +1 -1
- package/lib/index.d.ts +6 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +16 -15
- package/lib/index.js.map +1 -1
- package/lib/lib/model.d.ts +1 -1
- package/lib/lib/model.d.ts.map +1 -1
- package/lib/lib/model.js +3 -3
- package/lib/lib/model.js.map +1 -1
- package/lib/model-source/glsp-diagram-server.d.ts +1 -1
- package/lib/model-source/glsp-diagram-server.d.ts.map +1 -1
- package/lib/model-source/glsp-diagram-server.js +1 -1
- package/lib/model-source/glsp-diagram-server.js.map +1 -1
- package/lib/utils/layout-utils.d.ts +4 -20
- package/lib/utils/layout-utils.d.ts.map +1 -1
- package/lib/utils/layout-utils.js +1 -1
- package/lib/utils/layout-utils.js.map +1 -1
- package/lib/views/base-view-module.d.ts.map +1 -1
- package/lib/views/base-view-module.js +3 -1
- package/lib/views/base-view-module.js.map +1 -1
- package/lib/views/glsp-projection-view.d.ts +30 -0
- package/lib/views/glsp-projection-view.d.ts.map +1 -0
- package/lib/views/glsp-projection-view.js +142 -0
- package/lib/views/glsp-projection-view.js.map +1 -0
- package/lib/views/index.d.ts +1 -0
- package/lib/views/index.d.ts.map +1 -1
- package/lib/views/index.js +1 -0
- package/lib/views/index.js.map +1 -1
- package/package.json +4 -4
- package/src/base/container-modules.ts +6 -5
- package/src/base/editor-context-service.ts +15 -7
- package/src/base/model/update-model-command.ts +48 -34
- package/src/base/source-uri-aware.ts +5 -4
- package/src/features/change-bounds/movement-restrictor.ts +73 -43
- package/src/features/change-bounds/snap.ts +15 -12
- package/src/features/context-menu/selection-service-aware-context-menu-mouse-listener.ts +19 -25
- package/src/features/hover/hover.ts +2 -24
- package/src/features/layout/di.config.ts +14 -6
- package/src/features/layout/hbox-layout.ts +24 -7
- package/src/features/layout/{layout-commands.spec.ts → layout-elements-action.spec.ts} +56 -48
- package/src/features/layout/{layout-commands.ts → layout-elements-action.ts} +195 -207
- package/src/features/layout/layouter.ts +137 -0
- package/src/features/layout/vbox-layout.ts +22 -5
- package/src/features/mouse-tool/mouse-tool.ts +8 -6
- package/src/features/select/select-mouse-listener.ts +81 -1
- package/src/features/select/selection-service.spec.ts +1 -1
- package/src/features/select/selection-service.ts +37 -50
- package/src/features/{model-source-watcher → source-model-watcher}/di.config.ts +5 -5
- package/src/features/{model-source-watcher/model-source-changed-action-handler.ts → source-model-watcher/source-model-changed-action-handler.ts} +12 -12
- package/src/features/tool-feedback/change-bounds-tool-feedback.ts +1 -1
- package/src/features/tool-feedback/edge-edit-tool-feedback.ts +14 -6
- package/src/features/tools/di.config.ts +13 -2
- package/src/features/tools/enable-default-tools-on-focus-loss.ts +33 -0
- package/src/features/validation/di.config.ts +10 -7
- package/src/features/validation/issue-marker.ts +34 -12
- package/src/features/validation/marker-navigator.ts +29 -66
- package/src/features/validation/validate.ts +36 -71
- package/src/index.ts +8 -7
- package/src/lib/model.ts +1 -1
- package/src/model-source/glsp-diagram-server.ts +1 -1
- package/src/utils/layout-utils.ts +7 -27
- package/src/views/base-view-module.ts +5 -1
- package/src/views/glsp-projection-view.tsx +166 -0
- package/src/views/index.ts +2 -0
- package/lib/features/layout/layout-commands.d.ts.map +0 -1
- package/lib/features/layout/layout-commands.js.map +0 -1
- package/lib/features/layout/layout-commands.spec.d.ts +0 -3
- package/lib/features/layout/layout-commands.spec.d.ts.map +0 -1
- package/lib/features/layout/layout-commands.spec.js.map +0 -1
- package/lib/features/model-source-watcher/di.config.d.ts +0 -4
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2022 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
import {
|
|
17
|
+
BoundsData,
|
|
18
|
+
ILogger,
|
|
19
|
+
LayoutRegistry,
|
|
20
|
+
StatefulLayouter,
|
|
21
|
+
SModelElement,
|
|
22
|
+
Layouter,
|
|
23
|
+
SParentElement,
|
|
24
|
+
LayoutContainer,
|
|
25
|
+
isLayoutContainer
|
|
26
|
+
} from 'sprotty';
|
|
27
|
+
import { injectable } from 'inversify';
|
|
28
|
+
import { Bounds } from 'sprotty-protocol/lib/utils/geometry';
|
|
29
|
+
|
|
30
|
+
@injectable()
|
|
31
|
+
export class LayouterExt extends Layouter {
|
|
32
|
+
override layout(element2boundsData: Map<SModelElement, BoundsData>): void {
|
|
33
|
+
new StatefulLayouterExt(element2boundsData, this.layoutRegistry, this.logger).layout();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2-pass layout:
|
|
38
|
+
// Step 1: Find "rendered size" of each element (may take resizeContainer into account)
|
|
39
|
+
// Child-to-parent layout
|
|
40
|
+
// Step 2: Extend parents as necessary, then use the adjusted parent size to properly
|
|
41
|
+
// align children (center/end alignments, hGrab/vGrab)
|
|
42
|
+
// Parent-to-children layout
|
|
43
|
+
|
|
44
|
+
export class StatefulLayouterExt extends StatefulLayouter {
|
|
45
|
+
protected toBeLayouted2: (SParentElement & LayoutContainer)[];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param elementToBoundsData The map of element to bounds data. Bounds Data are computed from the hidden
|
|
50
|
+
* SVG rendering pass.
|
|
51
|
+
* @param layoutRegistry2 The registry of available layouts.
|
|
52
|
+
* @param log The log.
|
|
53
|
+
*/
|
|
54
|
+
constructor(
|
|
55
|
+
protected readonly elementToBoundsData: Map<SModelElement, BoundsData>,
|
|
56
|
+
protected readonly layoutRegistry2: LayoutRegistry,
|
|
57
|
+
log: ILogger
|
|
58
|
+
) {
|
|
59
|
+
super(elementToBoundsData, layoutRegistry2, log);
|
|
60
|
+
this.toBeLayouted2 = [];
|
|
61
|
+
elementToBoundsData.forEach((data, element) => {
|
|
62
|
+
if (isLayoutContainer(element)) {
|
|
63
|
+
this.toBeLayouted2.push(element);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
for (const element of this.toBeLayouted2) {
|
|
67
|
+
// Clear previous layout information for dynamic-layout objects
|
|
68
|
+
elementToBoundsData.delete(element);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override getBoundsData(element: SModelElement): BoundsData {
|
|
73
|
+
let boundsData = this.elementToBoundsData.get(element);
|
|
74
|
+
let bounds = (element as any).bounds;
|
|
75
|
+
if (isLayoutContainer(element) && this.toBeLayouted2.indexOf(element) >= 0) {
|
|
76
|
+
bounds = this.doLayout(element);
|
|
77
|
+
} else if (isLayoutContainer(element)) {
|
|
78
|
+
bounds = {
|
|
79
|
+
x: 0,
|
|
80
|
+
y: 0,
|
|
81
|
+
width: -1,
|
|
82
|
+
height: -1
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (!boundsData) {
|
|
86
|
+
boundsData = {
|
|
87
|
+
bounds: bounds,
|
|
88
|
+
boundsChanged: false,
|
|
89
|
+
alignmentChanged: false
|
|
90
|
+
};
|
|
91
|
+
this.elementToBoundsData.set(element, boundsData);
|
|
92
|
+
}
|
|
93
|
+
return boundsData;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override layout(): void {
|
|
97
|
+
// First pass: apply layout with cleared container data. Will get
|
|
98
|
+
// preferred size for all elements (Children first, then parents)
|
|
99
|
+
while (this.toBeLayouted2.length > 0) {
|
|
100
|
+
const element = this.toBeLayouted2[0];
|
|
101
|
+
this.doLayout(element);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.toBeLayouted2 = [];
|
|
105
|
+
this.elementToBoundsData.forEach((data, element) => {
|
|
106
|
+
if (isLayoutContainer(element)) {
|
|
107
|
+
this.toBeLayouted2.push(element);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Second pass: apply layout with initial size data for all
|
|
112
|
+
// nodes. Update the position/size of all elements, taking
|
|
113
|
+
// vGrab/hGrab into account (parent -> children).
|
|
114
|
+
while (this.toBeLayouted2.length > 0) {
|
|
115
|
+
const element = this.toBeLayouted2[0];
|
|
116
|
+
this.doLayout(element);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
protected override doLayout(element: SParentElement & LayoutContainer): Bounds {
|
|
121
|
+
const index = this.toBeLayouted2.indexOf(element);
|
|
122
|
+
if (index >= 0) {
|
|
123
|
+
this.toBeLayouted2.splice(index, 1);
|
|
124
|
+
}
|
|
125
|
+
const layout = this.layoutRegistry2.get(element.layout);
|
|
126
|
+
if (layout) {
|
|
127
|
+
layout.layout(element, this);
|
|
128
|
+
}
|
|
129
|
+
const boundsData = this.elementToBoundsData.get(element);
|
|
130
|
+
if (boundsData !== undefined && boundsData.bounds !== undefined) {
|
|
131
|
+
return boundsData.bounds;
|
|
132
|
+
} else {
|
|
133
|
+
this.log.error(element, 'Layout failed');
|
|
134
|
+
return Bounds.EMPTY;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -49,6 +49,9 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
49
49
|
|
|
50
50
|
const fixedSize = this.getFixedContainerBounds(container, options, layouter);
|
|
51
51
|
|
|
52
|
+
const currentWidth = (boundsData.bounds?.width || 0) - options.paddingLeft - options.paddingRight;
|
|
53
|
+
const currentHeight = (boundsData.bounds?.height || 0) - options.paddingTop - options.paddingBottom;
|
|
54
|
+
|
|
52
55
|
const maxWidth =
|
|
53
56
|
options.paddingFactor *
|
|
54
57
|
(options.resizeContainer
|
|
@@ -60,8 +63,11 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
60
63
|
? Math.max(fixedSize.height - options.paddingTop - options.paddingBottom, childrenSize.height)
|
|
61
64
|
: Math.max(0, fixedSize.height - options.paddingTop - options.paddingBottom));
|
|
62
65
|
|
|
66
|
+
const width = Math.max(currentWidth, maxWidth);
|
|
67
|
+
const height = Math.max(currentHeight, maxHeight);
|
|
68
|
+
|
|
63
69
|
// Remaining size that can be grabbed by children with the vGrab option
|
|
64
|
-
const grabHeight: number =
|
|
70
|
+
const grabHeight: number = height - childrenSize.height;
|
|
65
71
|
// Number of children that request vGrab
|
|
66
72
|
// FIXME: This approach works fine when only 1 child uses VGrab, but may cause rounding issues
|
|
67
73
|
// when the grabHeight can't be equally shared by all children.
|
|
@@ -70,7 +76,7 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
70
76
|
.filter(opt => opt.vGrab).length;
|
|
71
77
|
|
|
72
78
|
if (maxWidth > 0 && maxHeight > 0) {
|
|
73
|
-
const offset = this.layoutChildren(container, layouter, options,
|
|
79
|
+
const offset = this.layoutChildren(container, layouter, options, width, height, grabHeight, grabbingChildren);
|
|
74
80
|
boundsData.bounds = this.getFinalContainerBounds(container, offset, options, childrenSize.width, childrenSize.height);
|
|
75
81
|
boundsData.boundsChanged = true;
|
|
76
82
|
}
|
|
@@ -155,7 +161,14 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
155
161
|
grabHeight?: number,
|
|
156
162
|
grabbingChildren?: number
|
|
157
163
|
): Point {
|
|
164
|
+
const hAlign = childOptions.hGrab ? 'left' : childOptions.hAlign;
|
|
165
|
+
const dx = this.getDx(hAlign, bounds, maxWidth);
|
|
158
166
|
let offset = super.layoutChild(child, boundsData, bounds, childOptions, containerOptions, currentOffset, maxWidth, maxHeight);
|
|
167
|
+
boundsData.bounds = {
|
|
168
|
+
...boundsData.bounds!,
|
|
169
|
+
x: currentOffset.x + dx,
|
|
170
|
+
y: currentOffset.y
|
|
171
|
+
};
|
|
159
172
|
if (childOptions.hGrab) {
|
|
160
173
|
boundsData.bounds = {
|
|
161
174
|
x: boundsData.bounds!.x,
|
|
@@ -197,7 +210,7 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
197
210
|
}
|
|
198
211
|
|
|
199
212
|
protected override getChildLayoutOptions(child: SChildElement, containerOptions: VBoxLayoutOptionsExt): VBoxLayoutOptionsExt {
|
|
200
|
-
return super.getChildLayoutOptions(child, containerOptions) as VBoxLayoutOptionsExt;
|
|
213
|
+
return super.getChildLayoutOptions(child, this.filterContainerOptions(containerOptions)) as VBoxLayoutOptionsExt;
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
protected override getLayoutOptions(element: SModelElement): VBoxLayoutOptionsExt {
|
|
@@ -250,7 +263,11 @@ export class VBoxLayouterExt extends VBoxLayouter {
|
|
|
250
263
|
};
|
|
251
264
|
}
|
|
252
265
|
|
|
253
|
-
protected
|
|
254
|
-
|
|
266
|
+
protected filterContainerOptions(containerOptions: VBoxLayoutOptionsExt): VBoxLayoutOptionsExt {
|
|
267
|
+
// Reset object-specific layout options to default before merging,
|
|
268
|
+
// to make sure they won't be inherited (grab, prefSize)
|
|
269
|
+
// eslint-disable-next-line no-null/no-null
|
|
270
|
+
const localOptions = { vGrab: false, hGrab: false, prefHeight: null, prefWidth: null };
|
|
271
|
+
return { ...containerOptions, ...localOptions };
|
|
255
272
|
}
|
|
256
273
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
+
import { Action } from '@eclipse-glsp/protocol';
|
|
16
17
|
import { injectable, multiInject, optional } from 'inversify';
|
|
17
18
|
import { MouseListener, MouseTool, SModelElement, SModelRoot } from 'sprotty';
|
|
18
19
|
import { TYPES } from '../../base/types';
|
|
@@ -48,10 +49,6 @@ export class RankingMouseTool extends MouseTool implements IMouseTool {
|
|
|
48
49
|
this.rankedMouseListeners = groupBy(this.mouseListeners, listener => getRank(listener));
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
contextMenu(model: SModelRoot, event: MouseEvent): void {
|
|
52
|
-
event.preventDefault();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
52
|
protected override handleEvent<K extends MouseListenerMethods>(methodName: K, model: SModelRoot, event: MouseEvent): void {
|
|
56
53
|
this.focusOnMouseEvent(methodName, model);
|
|
57
54
|
const element = this.getTargetElement(model, event);
|
|
@@ -82,8 +79,13 @@ export class RankingMouseTool extends MouseTool implements IMouseTool {
|
|
|
82
79
|
if (actions.length > 0) {
|
|
83
80
|
event.preventDefault();
|
|
84
81
|
for (const actionOrPromise of actions) {
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
if (Action.is(actionOrPromise)) {
|
|
83
|
+
await this.actionDispatcher.dispatch(actionOrPromise);
|
|
84
|
+
} else {
|
|
85
|
+
actionOrPromise.then((action: Action) => {
|
|
86
|
+
this.actionDispatcher.dispatch(action);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
}
|
|
@@ -13,7 +13,21 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import {
|
|
16
|
+
import { Action, SelectAction } from '@eclipse-glsp/protocol';
|
|
17
|
+
import {
|
|
18
|
+
BringToFrontAction,
|
|
19
|
+
findParentByFeature,
|
|
20
|
+
isCtrlOrCmd,
|
|
21
|
+
isSelectable,
|
|
22
|
+
SButton,
|
|
23
|
+
SelectMouseListener,
|
|
24
|
+
SModelElement,
|
|
25
|
+
SModelRoot,
|
|
26
|
+
SRoutableElement,
|
|
27
|
+
SRoutingHandle,
|
|
28
|
+
SwitchEditModeAction
|
|
29
|
+
} from 'sprotty';
|
|
30
|
+
import { toArray } from 'sprotty/lib/utils/iterable';
|
|
17
31
|
import { DEFAULT_RANK, Ranked } from '../rank/model';
|
|
18
32
|
|
|
19
33
|
/**
|
|
@@ -22,4 +36,70 @@ import { DEFAULT_RANK, Ranked } from '../rank/model';
|
|
|
22
36
|
*/
|
|
23
37
|
export class RankedSelectMouseListener extends SelectMouseListener implements Ranked {
|
|
24
38
|
rank: number = DEFAULT_RANK - 1; /* we want to be executed before all default mouse listeners */
|
|
39
|
+
|
|
40
|
+
override mouseDown(target: SModelElement, event: MouseEvent): Action[] {
|
|
41
|
+
const result: Action[] = [];
|
|
42
|
+
if (this.buttonHandlerRegistry !== undefined && target instanceof SButton && target.enabled) {
|
|
43
|
+
const buttonHandler = this.buttonHandlerRegistry.get(target.type);
|
|
44
|
+
if (buttonHandler !== undefined) {
|
|
45
|
+
return buttonHandler.buttonPressed(target);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const selectableTarget = findParentByFeature(target, isSelectable);
|
|
49
|
+
if (selectableTarget !== undefined || target instanceof SModelRoot) {
|
|
50
|
+
this.hasDragged = false;
|
|
51
|
+
let deselect: SModelElement[] = [];
|
|
52
|
+
// multi-selection?
|
|
53
|
+
if (!isCtrlOrCmd(event)) {
|
|
54
|
+
deselect = toArray(
|
|
55
|
+
target.root.index
|
|
56
|
+
.all()
|
|
57
|
+
.filter(
|
|
58
|
+
element =>
|
|
59
|
+
isSelectable(element) &&
|
|
60
|
+
element.selected &&
|
|
61
|
+
!(selectableTarget instanceof SRoutingHandle && element === (selectableTarget.parent as SModelElement))
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (selectableTarget !== undefined) {
|
|
66
|
+
if (!selectableTarget.selected) {
|
|
67
|
+
this.wasSelected = false;
|
|
68
|
+
result.push(
|
|
69
|
+
SelectAction.create({
|
|
70
|
+
selectedElementsIDs: [selectableTarget.id],
|
|
71
|
+
deselectedElementsIDs: deselect.map(e => e.id)
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
result.push(BringToFrontAction.create([selectableTarget.id]));
|
|
75
|
+
const routableDeselect = deselect.filter(e => e instanceof SRoutableElement).map(e => e.id);
|
|
76
|
+
if (selectableTarget instanceof SRoutableElement) {
|
|
77
|
+
result.push(
|
|
78
|
+
SwitchEditModeAction.create({
|
|
79
|
+
elementsToActivate: [selectableTarget.id],
|
|
80
|
+
elementsToDeactivate: routableDeselect
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
} else if (routableDeselect.length > 0) {
|
|
84
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: routableDeselect }));
|
|
85
|
+
}
|
|
86
|
+
} else if (isCtrlOrCmd(event)) {
|
|
87
|
+
this.wasSelected = false;
|
|
88
|
+
result.push(SelectAction.create({ deselectedElementsIDs: [selectableTarget.id] }));
|
|
89
|
+
if (selectableTarget instanceof SRoutableElement) {
|
|
90
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: [selectableTarget.id] }));
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
this.wasSelected = true;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
result.push(SelectAction.create({ deselectedElementsIDs: deselect.map(e => e.id) }));
|
|
97
|
+
const routableDeselect = deselect.filter(e => e instanceof SRoutableElement).map(e => e.id);
|
|
98
|
+
if (routableDeselect.length > 0) {
|
|
99
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: routableDeselect }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
25
105
|
}
|
|
@@ -347,7 +347,7 @@ describe('SelectionService', () => {
|
|
|
347
347
|
expect(selectionService.hasSelectedElements()).to.equal(expectedSelection.length > 0);
|
|
348
348
|
expect(selectionService.getSelectedElementIDs()).to.have.lengthOf(expectedSelection.length);
|
|
349
349
|
if (expectedSelection.length > 0) {
|
|
350
|
-
expect(selectionService.getSelectedElementIDs()).to.have.
|
|
350
|
+
expect(selectionService.getSelectedElementIDs()).to.have.ordered.members(expectedSelection);
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Action, distinctAdd, remove, SelectAction, SelectAllAction } from '@eclipse-glsp/protocol';
|
|
16
|
+
import { Action, distinctAdd, pluck, remove, SelectAction, SelectAllAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, multiInject, optional } from 'inversify';
|
|
18
18
|
import {
|
|
19
19
|
Command,
|
|
@@ -25,12 +25,11 @@ import {
|
|
|
25
25
|
SelectAllCommand as SprottySelectAllCommand,
|
|
26
26
|
SelectCommand as SprottySelectCommand,
|
|
27
27
|
SModelElement,
|
|
28
|
-
SModelRoot
|
|
29
|
-
SParentElement
|
|
28
|
+
SModelRoot
|
|
30
29
|
} from 'sprotty';
|
|
31
30
|
import { SModelRootListener } from '../../base/model/update-model-command';
|
|
32
31
|
import { TYPES } from '../../base/types';
|
|
33
|
-
import { getElements } from '../../utils/smodel-util';
|
|
32
|
+
import { getElements, getMatchingElements } from '../../utils/smodel-util';
|
|
34
33
|
import { IFeedbackActionDispatcher } from '../tool-feedback/feedback-action-dispatcher';
|
|
35
34
|
import { SelectFeedbackAction } from './select-feedback-action';
|
|
36
35
|
|
|
@@ -135,8 +134,8 @@ export class SelectionService implements SModelRootListener {
|
|
|
135
134
|
* QUERY METHODS
|
|
136
135
|
*/
|
|
137
136
|
|
|
138
|
-
getSelectedElementIDs():
|
|
139
|
-
return this.selectedElementIDs;
|
|
137
|
+
getSelectedElementIDs(): string[] {
|
|
138
|
+
return [...this.selectedElementIDs];
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
hasSelectedElements(): boolean {
|
|
@@ -152,6 +151,11 @@ export class SelectionService implements SModelRootListener {
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Handles a {@link SelectAction} and propagates the new selection to the {@link SelectionService}.
|
|
156
|
+
* Other tools might be selection-sensitive which means {@link SelectAction}s must be processed as fast as possible.
|
|
157
|
+
* Handling the action with a command ensures that the action is processed before the next render tick.
|
|
158
|
+
*/
|
|
155
159
|
@injectable()
|
|
156
160
|
export class SelectCommand extends Command {
|
|
157
161
|
static readonly KIND = SprottySelectCommand.KIND;
|
|
@@ -168,36 +172,30 @@ export class SelectCommand extends Command {
|
|
|
168
172
|
|
|
169
173
|
execute(context: CommandExecutionContext): SModelRoot {
|
|
170
174
|
const model = context.root;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.action.deselectedElementsIDs.forEach(id => {
|
|
178
|
-
const element = model.index.getById(id);
|
|
179
|
-
if (element instanceof SChildElement && isSelectable(element)) {
|
|
180
|
-
this.deselected.push(element);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
return this.redo(context);
|
|
175
|
+
const selectionGuard = (element: any): element is SModelElement => element instanceof SChildElement && isSelectable(element);
|
|
176
|
+
const selectedElements = getElements(model.index, this.action.selectedElementsIDs, selectionGuard);
|
|
177
|
+
const deselectedElements = getElements(model.index, this.action.deselectedElementsIDs, selectionGuard);
|
|
178
|
+
|
|
179
|
+
this.selectionService.updateSelection(model, pluck(selectedElements, 'id'), pluck(deselectedElements, 'id'));
|
|
180
|
+
return model;
|
|
184
181
|
}
|
|
185
182
|
|
|
183
|
+
// Basically no-op since client-side undo is not supported in GLSP.
|
|
186
184
|
undo(context: CommandExecutionContext): SModelRoot {
|
|
187
|
-
const select = this.deselected.map(element => element.id);
|
|
188
|
-
const deselect = this.selected.map(element => element.id);
|
|
189
|
-
this.selectionService.updateSelection(context.root, select, deselect);
|
|
190
185
|
return context.root;
|
|
191
186
|
}
|
|
192
187
|
|
|
188
|
+
// Basically no-op since client-side redo is not supported in GLSP.
|
|
193
189
|
redo(context: CommandExecutionContext): SModelRoot {
|
|
194
|
-
const select = this.selected.map(element => element.id);
|
|
195
|
-
const deselect = this.deselected.map(element => element.id);
|
|
196
|
-
this.selectionService.updateSelection(context.root, select, deselect);
|
|
197
190
|
return context.root;
|
|
198
191
|
}
|
|
199
192
|
}
|
|
200
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Handles a {@link SelectAllAction} and propagates the new selection to the {@link SelectionService}.
|
|
196
|
+
* Other tools might be selection-sensitive which means {@link SelectionAllAction}s must be processed as fast as possible.
|
|
197
|
+
* Handling the action with a command ensures that the action is processed before the next render tick.
|
|
198
|
+
*/
|
|
201
199
|
@injectable()
|
|
202
200
|
export class SelectAllCommand extends Command {
|
|
203
201
|
static readonly KIND = SprottySelectAllCommand.KIND;
|
|
@@ -211,38 +209,27 @@ export class SelectAllCommand extends Command {
|
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
execute(context: CommandExecutionContext): SModelRoot {
|
|
214
|
-
|
|
212
|
+
const model = context.root;
|
|
213
|
+
const selectionGuard = (element: any): element is SModelElement => element instanceof SChildElement && isSelectable(element);
|
|
214
|
+
|
|
215
|
+
const selectables = getMatchingElements(model.index, selectionGuard);
|
|
216
|
+
const selectableIds = pluck(selectables, 'id');
|
|
217
|
+
if (this.action.select) {
|
|
218
|
+
this.selectionService.updateSelection(model, selectableIds, []);
|
|
219
|
+
} else {
|
|
220
|
+
this.selectionService.updateSelection(model, [], selectableIds);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return model;
|
|
215
224
|
}
|
|
216
225
|
|
|
226
|
+
// Basically no-op since client-side undo is not supported in GLSP.
|
|
217
227
|
undo(context: CommandExecutionContext): SModelRoot {
|
|
218
|
-
const index = context.root.index;
|
|
219
|
-
for (const previousState of this.previousSelection) {
|
|
220
|
-
const element = index.getById(previousState[0]);
|
|
221
|
-
if (element !== undefined && isSelectable(element)) {
|
|
222
|
-
element.selected = previousState[1];
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
228
|
return context.root;
|
|
226
229
|
}
|
|
227
230
|
|
|
231
|
+
// Basically no-op since client-side redo is not supported in GLSP.
|
|
228
232
|
redo(context: CommandExecutionContext): SModelRoot {
|
|
229
|
-
const selectables: string[] = [];
|
|
230
|
-
this.selectAll(context.root, this.action.select, selectables);
|
|
231
|
-
if (this.action.select) {
|
|
232
|
-
this.selectionService.updateSelection(context.root, selectables, []);
|
|
233
|
-
} else {
|
|
234
|
-
this.selectionService.updateSelection(context.root, [], selectables);
|
|
235
|
-
}
|
|
236
233
|
return context.root;
|
|
237
234
|
}
|
|
238
|
-
|
|
239
|
-
protected selectAll(element: SParentElement, newState: boolean, selected: string[]): void {
|
|
240
|
-
if (isSelectable(element)) {
|
|
241
|
-
this.previousSelection.set(element.id, element.selected);
|
|
242
|
-
selected.push(element.id);
|
|
243
|
-
}
|
|
244
|
-
for (const child of element.children) {
|
|
245
|
-
this.selectAll(child, newState, selected);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
235
|
}
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import {
|
|
16
|
+
import { SourceModelChangedAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { ContainerModule } from 'inversify';
|
|
18
18
|
import { configureActionHandler } from 'sprotty';
|
|
19
|
-
import {
|
|
19
|
+
import { SourceModelChangedActionHandler } from './source-model-changed-action-handler';
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
configureActionHandler({ bind, isBound },
|
|
21
|
+
const sourceModelWatcherModule = new ContainerModule((bind, _unbind, isBound) => {
|
|
22
|
+
configureActionHandler({ bind, isBound }, SourceModelChangedAction.KIND, SourceModelChangedActionHandler);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
export default
|
|
25
|
+
export default sourceModelWatcherModule;
|
|
@@ -13,43 +13,43 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Action,
|
|
16
|
+
import { Action, ServerMessageAction, ServerStatusAction, SourceModelChangedAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, optional } from 'inversify';
|
|
18
18
|
import { IActionDispatcher, IActionHandler, ViewerOptions } from 'sprotty';
|
|
19
19
|
import { TYPES } from '../../base/types';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* An external handler of the model
|
|
22
|
+
* An external handler of the source model change event.
|
|
23
23
|
*
|
|
24
24
|
* This allows external applications to react specifically to this event, e.g. by bringing up the diagram,
|
|
25
25
|
* check their dirty state, show a dialog, etc.
|
|
26
26
|
*/
|
|
27
27
|
@injectable()
|
|
28
|
-
export abstract class
|
|
28
|
+
export abstract class ExternalSourceModelChangedHandler {
|
|
29
29
|
/**
|
|
30
|
-
* Notifies about a change of the model
|
|
30
|
+
* Notifies about a change of the source model.
|
|
31
31
|
* @returns actions to be dispatched after the notification.
|
|
32
32
|
*/
|
|
33
|
-
abstract
|
|
33
|
+
abstract notifySourceModelChange(sourceModelName: string, options: ViewerOptions): Promise<Action[]>;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
@injectable()
|
|
37
|
-
export class
|
|
37
|
+
export class SourceModelChangedActionHandler implements IActionHandler {
|
|
38
38
|
@inject(TYPES.IActionDispatcher)
|
|
39
39
|
protected dispatcher: IActionDispatcher;
|
|
40
40
|
|
|
41
41
|
@inject(TYPES.ViewerOptions)
|
|
42
42
|
protected options: ViewerOptions;
|
|
43
43
|
|
|
44
|
-
@inject(
|
|
44
|
+
@inject(ExternalSourceModelChangedHandler)
|
|
45
45
|
@optional()
|
|
46
|
-
protected externalModelSourceChangedHandler?:
|
|
46
|
+
protected externalModelSourceChangedHandler?: ExternalSourceModelChangedHandler;
|
|
47
47
|
|
|
48
48
|
handle(action: Action): void {
|
|
49
|
-
if (
|
|
49
|
+
if (SourceModelChangedAction.is(action)) {
|
|
50
50
|
if (this.externalModelSourceChangedHandler) {
|
|
51
51
|
this.externalModelSourceChangedHandler
|
|
52
|
-
.
|
|
52
|
+
.notifySourceModelChange(action.sourceModelName, this.options)
|
|
53
53
|
.then(actions => this.dispatcher.dispatchAll(actions));
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
@@ -57,8 +57,8 @@ export class ModelSourceChangedActionHandler implements IActionHandler {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
protected showSimpleNotification(action:
|
|
61
|
-
const message = `The model
|
|
60
|
+
protected showSimpleNotification(action: SourceModelChangedAction): void {
|
|
61
|
+
const message = `The source model ${action.sourceModelName} has changed. You might want to consider reloading.`;
|
|
62
62
|
const timeout = 0;
|
|
63
63
|
const severity = 'WARNING';
|
|
64
64
|
this.dispatcher.dispatchAll([
|
|
@@ -224,7 +224,7 @@ export class FeedbackMoveMouseListener extends MouseListener {
|
|
|
224
224
|
protected validateMove(startPostion: Point, toPosition: Point, element: SModelElement, isFinished: boolean): Point {
|
|
225
225
|
let newPosition = toPosition;
|
|
226
226
|
if (this.tool.movementRestrictor) {
|
|
227
|
-
const valid = this.tool.movementRestrictor.validate(
|
|
227
|
+
const valid = this.tool.movementRestrictor.validate(element, toPosition);
|
|
228
228
|
let action;
|
|
229
229
|
if (!valid) {
|
|
230
230
|
action = createMovementRestrictionFeedback(element, this.tool.movementRestrictor);
|
|
@@ -265,20 +265,20 @@ export class FeedbackEdgeRouteMovingMouseListener extends MouseListener {
|
|
|
265
265
|
}
|
|
266
266
|
const positionUpdate = this.pointPositionUpdater.updatePosition(target, { x: event.pageX, y: event.pageY }, !event.altKey);
|
|
267
267
|
if (positionUpdate) {
|
|
268
|
-
const moveActions = this.handleMoveOnClient(target, positionUpdate);
|
|
268
|
+
const moveActions = this.handleMoveOnClient(target, positionUpdate, !event.altKey);
|
|
269
269
|
result.push(...moveActions);
|
|
270
270
|
}
|
|
271
271
|
return result;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
protected handleMoveOnClient(target: SModelElement, positionUpdate: Point): Action[] {
|
|
274
|
+
protected handleMoveOnClient(target: SModelElement, positionUpdate: Point, isSnap: boolean): Action[] {
|
|
275
275
|
const handleMoves: ElementMove[] = [];
|
|
276
276
|
target.root.index
|
|
277
277
|
.all()
|
|
278
278
|
.filter(element => isSelected(element))
|
|
279
279
|
.forEach(element => {
|
|
280
280
|
if (isRoutingHandle(element)) {
|
|
281
|
-
const elementMove = this.toElementMove(element, positionUpdate);
|
|
281
|
+
const elementMove = this.toElementMove(element, positionUpdate, isSnap);
|
|
282
282
|
if (elementMove) {
|
|
283
283
|
handleMoves.push(elementMove);
|
|
284
284
|
}
|
|
@@ -290,21 +290,29 @@ export class FeedbackEdgeRouteMovingMouseListener extends MouseListener {
|
|
|
290
290
|
return [];
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
protected toElementMove(element: SRoutingHandle, positionDelta: Point): ElementMove | undefined {
|
|
293
|
+
protected toElementMove(element: SRoutingHandle, positionDelta: Point, isSnap: boolean): ElementMove | undefined {
|
|
294
294
|
const point = this.getHandlePosition(element);
|
|
295
295
|
if (point !== undefined) {
|
|
296
|
+
const snappedPoint = this.getSnappedHandlePosition(element, point, isSnap);
|
|
296
297
|
return {
|
|
297
298
|
elementId: element.id,
|
|
298
299
|
fromPosition: point,
|
|
299
300
|
toPosition: {
|
|
300
|
-
x:
|
|
301
|
-
y:
|
|
301
|
+
x: snappedPoint.x + positionDelta.x,
|
|
302
|
+
y: snappedPoint.y + positionDelta.y
|
|
302
303
|
}
|
|
303
304
|
};
|
|
304
305
|
}
|
|
305
306
|
return undefined;
|
|
306
307
|
}
|
|
307
308
|
|
|
309
|
+
protected getSnappedHandlePosition(element: SRoutingHandle, point: Point, isSnap: boolean): Point {
|
|
310
|
+
if (this.snapper && isSnap) {
|
|
311
|
+
return this.snapper.snap(point, element);
|
|
312
|
+
}
|
|
313
|
+
return point;
|
|
314
|
+
}
|
|
315
|
+
|
|
308
316
|
protected getHandlePosition(handle: SRoutingHandle): Point | undefined {
|
|
309
317
|
if (this.edgeRouterRegistry) {
|
|
310
318
|
const parent = handle.parent;
|