@eclipse-glsp/client 0.10.0-next.e5fcffe.169 → 1.0.0
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 +6 -5
- package/lib/features/layout/di.config.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/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 +12 -6
- 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/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
|
@@ -13,12 +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 {
|
|
17
|
+
Action,
|
|
18
|
+
ChangeBoundsOperation,
|
|
19
|
+
ElementAndBounds,
|
|
20
|
+
hasArrayProp,
|
|
21
|
+
hasNumberProp,
|
|
22
|
+
hasStringProp,
|
|
23
|
+
SetBoundsAction,
|
|
24
|
+
Writable
|
|
25
|
+
} from '@eclipse-glsp/protocol';
|
|
17
26
|
import { inject, injectable, optional } from 'inversify';
|
|
18
|
-
import {
|
|
27
|
+
import { ElementMove, IActionDispatcher, IActionHandler, ICommand, MoveAction, SModelElement } from 'sprotty';
|
|
19
28
|
import { TYPES } from '../../base/types';
|
|
20
|
-
import { toValidElementAndBounds, toValidElementMove
|
|
21
|
-
import { BoundsAwareModelElement } from '../../utils/smodel-util';
|
|
29
|
+
import { toValidElementAndBounds, toValidElementMove } from '../../utils/layout-utils';
|
|
30
|
+
import { BoundsAwareModelElement, getElements } from '../../utils/smodel-util';
|
|
22
31
|
import { isBoundsAwareMoveable, isResizable } from '../change-bounds/model';
|
|
23
32
|
import { IMovementRestrictor } from '../change-bounds/movement-restrictor';
|
|
24
33
|
import { SelectionService } from '../select/selection-service';
|
|
@@ -33,7 +42,14 @@ export enum ResizeDimension {
|
|
|
33
42
|
Width_And_Height
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
/**
|
|
46
|
+
* A function that computes a single number from a set of given numbers
|
|
47
|
+
* i.e. it reduces the given numbers to one single number.
|
|
48
|
+
* Mainly used by the {@link ResizeElementsCommand} to reduce the given dimensions to a target dimension value.
|
|
49
|
+
*/
|
|
50
|
+
export type ReduceFunction = (...values: number[]) => number;
|
|
51
|
+
|
|
52
|
+
export namespace ReduceFunction {
|
|
37
53
|
/**
|
|
38
54
|
* Returns the minimal value of the given numbers.
|
|
39
55
|
* @param values Numbers to be evaluated.
|
|
@@ -79,13 +95,18 @@ export namespace Reduce {
|
|
|
79
95
|
}
|
|
80
96
|
|
|
81
97
|
/**
|
|
82
|
-
* Returns the reduce function that corresponds to the given {@link
|
|
98
|
+
* Returns the reduce function that corresponds to the given {@link ReduceFunctionType}.
|
|
83
99
|
* @param type The reduce function kind.
|
|
84
100
|
* @returns The corresponding reduce function.
|
|
85
101
|
*/
|
|
102
|
+
export function get(type: ReduceFunctionType): ReduceFunction {
|
|
103
|
+
return ReduceFunction[type];
|
|
104
|
+
}
|
|
86
105
|
}
|
|
87
106
|
|
|
88
|
-
type
|
|
107
|
+
/** Union type of all {@link ReduceFunction} keys. */
|
|
108
|
+
export type ReduceFunctionType = Exclude<keyof typeof ReduceFunction, 'get'>;
|
|
109
|
+
|
|
89
110
|
export interface ResizeElementsAction extends Action {
|
|
90
111
|
kind: typeof ResizeElementsAction.KIND;
|
|
91
112
|
|
|
@@ -93,14 +114,16 @@ export interface ResizeElementsAction extends Action {
|
|
|
93
114
|
* IDs of the elements that should be resized. If no IDs are given, the selected elements will be resized.
|
|
94
115
|
*/
|
|
95
116
|
elementIds: string[];
|
|
117
|
+
|
|
96
118
|
/**
|
|
97
119
|
* Resize dimension. The default is {@link ResizeDimension.Width}.
|
|
98
120
|
*/
|
|
99
121
|
dimension: ResizeDimension;
|
|
122
|
+
|
|
100
123
|
/**
|
|
101
|
-
*
|
|
124
|
+
* Type of the {@link ReduceFunction} that should be used to reduce the dimension to a target dimension value
|
|
102
125
|
*/
|
|
103
|
-
|
|
126
|
+
reduceFunction: ReduceFunctionType;
|
|
104
127
|
}
|
|
105
128
|
|
|
106
129
|
export namespace ResizeElementsAction {
|
|
@@ -111,14 +134,14 @@ export namespace ResizeElementsAction {
|
|
|
111
134
|
Action.hasKind(object, KIND) &&
|
|
112
135
|
hasArrayProp(object, 'elementIds') &&
|
|
113
136
|
hasNumberProp(object, 'dimension') &&
|
|
114
|
-
'
|
|
137
|
+
hasStringProp(object, 'reduceFunction')
|
|
115
138
|
);
|
|
116
139
|
}
|
|
117
140
|
|
|
118
141
|
export function create(options: {
|
|
119
142
|
elementIds?: string[];
|
|
120
143
|
dimension?: ResizeDimension;
|
|
121
|
-
|
|
144
|
+
reduceFunction: ReduceFunctionType;
|
|
122
145
|
}): ResizeElementsAction {
|
|
123
146
|
return {
|
|
124
147
|
kind: KIND,
|
|
@@ -129,99 +152,24 @@ export namespace ResizeElementsAction {
|
|
|
129
152
|
}
|
|
130
153
|
}
|
|
131
154
|
|
|
132
|
-
|
|
133
|
-
export
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Right,
|
|
137
|
-
Top,
|
|
138
|
-
Middle,
|
|
139
|
-
Bottom
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export namespace Select {
|
|
143
|
-
export function all(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
144
|
-
return elements;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function first(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
148
|
-
return [elements[0]];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function last(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
152
|
-
return [elements[elements.length - 1]];
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
type SelectFn = (elements: BoundsAwareModelElement[]) => BoundsAwareModelElement[];
|
|
157
|
-
export interface AlignElementsAction extends Action {
|
|
158
|
-
kind: typeof AlignElementsAction.KIND;
|
|
155
|
+
@injectable()
|
|
156
|
+
export abstract class LayoutElementsActionHandler implements IActionHandler {
|
|
157
|
+
@inject(TYPES.IActionDispatcher)
|
|
158
|
+
protected actionDispatcher: IActionDispatcher;
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
*/
|
|
163
|
-
elementIds: string[];
|
|
164
|
-
/**
|
|
165
|
-
* Alignment direction. The default is {@link Alignment.Left}
|
|
166
|
-
*/
|
|
167
|
-
alignment: Alignment;
|
|
168
|
-
/**
|
|
169
|
-
* Function to selected elements that are considered during alignment calculation, see Select.* for potential functions.
|
|
170
|
-
* The default value is {@link Select.all}.
|
|
171
|
-
*/
|
|
172
|
-
selectionFunction: SelectFn;
|
|
173
|
-
}
|
|
160
|
+
@inject(TYPES.SelectionService)
|
|
161
|
+
protected selectionService: SelectionService;
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
|
|
163
|
+
@inject(TYPES.IMovementRestrictor)
|
|
164
|
+
@optional()
|
|
165
|
+
protected movementRestrictor?: IMovementRestrictor;
|
|
177
166
|
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
Action.hasKind(object, KIND) &&
|
|
181
|
-
hasArrayProp(object, 'elementIds') &&
|
|
182
|
-
hasNumberProp(object, 'alignment') &&
|
|
183
|
-
'selectionFunction' in object
|
|
184
|
-
);
|
|
185
|
-
}
|
|
167
|
+
abstract handle(action: Action): void | Action | ICommand;
|
|
186
168
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return
|
|
191
|
-
kind: KIND,
|
|
192
|
-
elementIds: [],
|
|
193
|
-
alignment: Alignment.Left,
|
|
194
|
-
selectionFunction: Select.all,
|
|
195
|
-
...options
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
@injectable()
|
|
200
|
-
abstract class LayoutElementsCommand extends Command {
|
|
201
|
-
constructor(
|
|
202
|
-
@inject(TYPES.Action) protected action: ResizeElementsAction | AlignElementsAction,
|
|
203
|
-
@inject(TYPES.IActionDispatcher) protected actionDispatcher: IActionDispatcher,
|
|
204
|
-
@inject(TYPES.SelectionService) protected selectionService: SelectionService,
|
|
205
|
-
@inject(TYPES.IMovementRestrictor) @optional() readonly movementRestrictor?: IMovementRestrictor
|
|
206
|
-
) {
|
|
207
|
-
super();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
getActionElements(context: CommandExecutionContext): BoundsAwareModelElement[] {
|
|
211
|
-
const model = context.root;
|
|
212
|
-
const elementIDs = this.action.elementIds;
|
|
213
|
-
if (elementIDs.length === 0) {
|
|
214
|
-
// collect the selected elements from the selection service (selection order is kept by service)
|
|
215
|
-
this.selectionService.getSelectedElementIDs().forEach(elementID => elementIDs.push(elementID));
|
|
216
|
-
}
|
|
217
|
-
const boundsAwareElements: BoundsAwareModelElement[] = [];
|
|
218
|
-
elementIDs.forEach(id => {
|
|
219
|
-
const element = model.index.getById(id);
|
|
220
|
-
if (element && this.isActionElement(element)) {
|
|
221
|
-
boundsAwareElements.push(element);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
return boundsAwareElements;
|
|
169
|
+
getSelectedElements(selection: { elementIds: string[] }): BoundsAwareModelElement[] {
|
|
170
|
+
const index = this.selectionService.getModelRoot().index;
|
|
171
|
+
const selectedElements = selection.elementIds.length > 0 ? selection.elementIds : this.selectionService.getSelectedElementIDs();
|
|
172
|
+
return getElements(index, selectedElements, this.isActionElement);
|
|
225
173
|
}
|
|
226
174
|
|
|
227
175
|
protected abstract isActionElement(element: SModelElement): element is BoundsAwareModelElement;
|
|
@@ -236,79 +184,60 @@ abstract class LayoutElementsCommand extends Command {
|
|
|
236
184
|
}
|
|
237
185
|
|
|
238
186
|
@injectable()
|
|
239
|
-
export class
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
constructor(
|
|
243
|
-
@inject(TYPES.Action) protected override action: ResizeElementsAction,
|
|
244
|
-
@inject(TYPES.IActionDispatcher) protected override actionDispatcher: IActionDispatcher,
|
|
245
|
-
@inject(TYPES.SelectionService) protected override selectionService: SelectionService,
|
|
246
|
-
@inject(TYPES.IMovementRestrictor) @optional() override readonly movementRestrictor?: IMovementRestrictor
|
|
247
|
-
) {
|
|
248
|
-
super(action, actionDispatcher, selectionService, movementRestrictor);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
protected isActionElement(element: SModelElement): element is BoundsAwareModelElement {
|
|
252
|
-
return isResizable(element);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
execute(context: CommandExecutionContext): CommandReturn {
|
|
256
|
-
const elements = this.getActionElements(context);
|
|
187
|
+
export class ResizeElementsActionHandler extends LayoutElementsActionHandler {
|
|
188
|
+
handle(action: ResizeElementsAction): void {
|
|
189
|
+
const elements = this.getSelectedElements(action);
|
|
257
190
|
if (elements.length > 1) {
|
|
258
|
-
|
|
191
|
+
const reduceFn = ReduceFunction.get(action.reduceFunction);
|
|
192
|
+
switch (action.dimension) {
|
|
259
193
|
case ResizeDimension.Width:
|
|
260
|
-
this.resizeWidth(elements);
|
|
261
|
-
break;
|
|
194
|
+
return this.resizeWidth(elements, reduceFn);
|
|
262
195
|
case ResizeDimension.Height:
|
|
263
|
-
this.resizeHeight(elements);
|
|
264
|
-
break;
|
|
196
|
+
return this.resizeHeight(elements, reduceFn);
|
|
265
197
|
case ResizeDimension.Width_And_Height:
|
|
266
|
-
this.resizeWidthAndHeight(elements);
|
|
267
|
-
break;
|
|
198
|
+
return this.resizeWidthAndHeight(elements, reduceFn);
|
|
268
199
|
}
|
|
269
200
|
}
|
|
270
|
-
return context.root;
|
|
271
201
|
}
|
|
272
202
|
|
|
273
|
-
resizeWidth(elements: BoundsAwareModelElement[]): void {
|
|
274
|
-
const targetWidth =
|
|
203
|
+
resizeWidth(elements: BoundsAwareModelElement[], reduceFn: ReduceFunction): void {
|
|
204
|
+
const targetWidth = reduceFn(...elements.map(element => element.bounds.width));
|
|
275
205
|
this.dispatchResizeActions(elements, (element, bounds) => {
|
|
276
|
-
// resize around center
|
|
206
|
+
// resize around center (horizontal)
|
|
277
207
|
const halfDiffWidth = 0.5 * (targetWidth - element.bounds.width);
|
|
278
|
-
bounds.newPosition
|
|
208
|
+
bounds.newPosition!.x = element.bounds.x - halfDiffWidth;
|
|
279
209
|
bounds.newSize.width = targetWidth;
|
|
280
210
|
});
|
|
281
211
|
}
|
|
282
212
|
|
|
283
|
-
resizeHeight(elements: BoundsAwareModelElement[]): void {
|
|
284
|
-
const targetHeight =
|
|
213
|
+
resizeHeight(elements: BoundsAwareModelElement[], reduceFn: ReduceFunction): void {
|
|
214
|
+
const targetHeight = reduceFn(...elements.map(element => element.bounds.height));
|
|
285
215
|
this.dispatchResizeActions(elements, (element, bounds) => {
|
|
286
|
-
// resize around middle
|
|
216
|
+
// resize around middle (vertical)
|
|
287
217
|
const halfDiffHeight = 0.5 * (targetHeight - element.bounds.height);
|
|
288
|
-
bounds.newPosition
|
|
218
|
+
bounds.newPosition!.y = element.bounds.y - halfDiffHeight;
|
|
289
219
|
bounds.newSize.height = targetHeight;
|
|
290
220
|
});
|
|
291
221
|
}
|
|
292
222
|
|
|
293
|
-
resizeWidthAndHeight(elements: BoundsAwareModelElement[]): void {
|
|
294
|
-
const targetWidth =
|
|
295
|
-
const targetHeight =
|
|
223
|
+
resizeWidthAndHeight(elements: BoundsAwareModelElement[], reduceFn: ReduceFunction): void {
|
|
224
|
+
const targetWidth = reduceFn(...elements.map(element => element.bounds.width));
|
|
225
|
+
const targetHeight = reduceFn(...elements.map(element => element.bounds.height));
|
|
296
226
|
this.dispatchResizeActions(elements, (element, bounds) => {
|
|
297
|
-
// resize around center and middle
|
|
227
|
+
// resize around center and middle (horizontal & vertical)
|
|
298
228
|
const halfDiffWidth = 0.5 * (targetWidth - element.bounds.width);
|
|
299
229
|
const halfDiffHeight = 0.5 * (targetHeight - element.bounds.height);
|
|
300
|
-
bounds.newPosition
|
|
301
|
-
bounds.
|
|
302
|
-
bounds.newSize.width = targetWidth;
|
|
303
|
-
bounds.newSize.height = targetHeight;
|
|
230
|
+
bounds.newPosition = { x: element.bounds.x - halfDiffWidth, y: element.bounds.y - halfDiffHeight };
|
|
231
|
+
bounds.newSize = { width: targetWidth, height: targetHeight };
|
|
304
232
|
});
|
|
305
233
|
}
|
|
306
234
|
|
|
307
235
|
dispatchResizeActions(
|
|
308
236
|
elements: BoundsAwareModelElement[],
|
|
309
|
-
change: (element: BoundsAwareModelElement, bounds:
|
|
237
|
+
change: (element: BoundsAwareModelElement, bounds: Writable<ElementAndBounds>) => void
|
|
310
238
|
): void {
|
|
311
239
|
const elementAndBounds: ElementAndBounds[] = []; // client- and server-side resize
|
|
240
|
+
|
|
312
241
|
elements.forEach(element => {
|
|
313
242
|
const elementChange = this.createElementAndBounds(element, change);
|
|
314
243
|
if (elementChange) {
|
|
@@ -321,9 +250,9 @@ export class ResizeElementsCommand extends LayoutElementsCommand {
|
|
|
321
250
|
|
|
322
251
|
createElementAndBounds(
|
|
323
252
|
element: BoundsAwareModelElement,
|
|
324
|
-
change: (_element: BoundsAwareModelElement, _bounds:
|
|
325
|
-
):
|
|
326
|
-
const bounds:
|
|
253
|
+
change: (_element: BoundsAwareModelElement, _bounds: Writable<ElementAndBounds>) => void
|
|
254
|
+
): Writable<ElementAndBounds> | undefined {
|
|
255
|
+
const bounds: ElementAndBounds = {
|
|
327
256
|
elementId: element.id,
|
|
328
257
|
newPosition: {
|
|
329
258
|
x: element.bounds.x,
|
|
@@ -337,107 +266,173 @@ export class ResizeElementsCommand extends LayoutElementsCommand {
|
|
|
337
266
|
change(element, bounds);
|
|
338
267
|
return toValidElementAndBounds(element, bounds, this.movementRestrictor);
|
|
339
268
|
}
|
|
269
|
+
protected isActionElement(element: SModelElement): element is BoundsAwareModelElement {
|
|
270
|
+
return isResizable(element);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// eslint-disable-next-line no-shadow
|
|
275
|
+
export enum Alignment {
|
|
276
|
+
Left,
|
|
277
|
+
Center,
|
|
278
|
+
Right,
|
|
279
|
+
Top,
|
|
280
|
+
Middle,
|
|
281
|
+
Bottom
|
|
282
|
+
}
|
|
340
283
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
284
|
+
/**
|
|
285
|
+
* A function that retrieves a specific (sub)-selection of elements from a given set of elements.
|
|
286
|
+
* Mainly used by the {@link AlignElementsActionHandler}.
|
|
287
|
+
*/
|
|
288
|
+
export type SelectFunction = (elements: BoundsAwareModelElement[]) => BoundsAwareModelElement[];
|
|
289
|
+
export namespace SelectFunction {
|
|
290
|
+
/**
|
|
291
|
+
* Select all elements from the given set of elements.
|
|
292
|
+
* @param elements The set of elements.
|
|
293
|
+
* @returns All elements.
|
|
294
|
+
*/
|
|
295
|
+
export function all(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
296
|
+
return elements;
|
|
344
297
|
}
|
|
345
298
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Select the first element from a given set of elements.
|
|
301
|
+
* @param elements The elements.
|
|
302
|
+
* @returns An array containing the first element of the given elements.
|
|
303
|
+
*/
|
|
304
|
+
export function first(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
305
|
+
return [elements[0]];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Select the last element from a given set of elements.
|
|
310
|
+
* @param elements The elements.
|
|
311
|
+
* @returns An array containing the last element of the given elements.
|
|
312
|
+
*/
|
|
313
|
+
export function last(elements: BoundsAwareModelElement[]): BoundsAwareModelElement[] {
|
|
314
|
+
return [elements[elements.length - 1]];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Returns the select function that corresponds to the given {@link SelectFunctionType}.
|
|
319
|
+
* @param type The select function type.
|
|
320
|
+
* @returns The corresponding select function.
|
|
321
|
+
*/
|
|
322
|
+
export function get(kind: SelectFunctionType): SelectFunction {
|
|
323
|
+
return SelectFunction[kind];
|
|
349
324
|
}
|
|
350
325
|
}
|
|
351
326
|
|
|
352
|
-
@
|
|
353
|
-
export
|
|
354
|
-
static readonly KIND = AlignElementsAction.KIND;
|
|
327
|
+
/** Union type of all {@link SelectFunction} keys. */
|
|
328
|
+
export type SelectFunctionType = Exclude<keyof typeof SelectFunction, 'get'>;
|
|
355
329
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
330
|
+
export interface AlignElementsAction extends Action {
|
|
331
|
+
kind: typeof AlignElementsAction.KIND;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* IDs of the elements that should be aligned. If no IDs are given, the selected elements will be aligned.
|
|
335
|
+
*/
|
|
336
|
+
elementIds: string[];
|
|
337
|
+
/**
|
|
338
|
+
* Alignment direction. The default is {@link Alignment.Left}
|
|
339
|
+
*/
|
|
340
|
+
alignment: Alignment;
|
|
341
|
+
/**
|
|
342
|
+
* Function to selected elements that are considered during alignment calculation.
|
|
343
|
+
* The default value is {@link Select.all}.
|
|
344
|
+
*/
|
|
345
|
+
selectFunction: SelectFunctionType;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export namespace AlignElementsAction {
|
|
349
|
+
export const KIND = 'alignElements';
|
|
350
|
+
|
|
351
|
+
export function is(object: any): object is AlignElementsAction {
|
|
352
|
+
return (
|
|
353
|
+
Action.hasKind(object, KIND) &&
|
|
354
|
+
hasArrayProp(object, 'elementIds') &&
|
|
355
|
+
hasNumberProp(object, 'alignment') &&
|
|
356
|
+
hasStringProp(object, 'selectFunction')
|
|
357
|
+
);
|
|
363
358
|
}
|
|
364
359
|
|
|
365
|
-
|
|
366
|
-
|
|
360
|
+
export function create(
|
|
361
|
+
options: { elementIds?: string[]; alignment?: Alignment; selectionFunction?: SelectFunctionType } = {}
|
|
362
|
+
): AlignElementsAction {
|
|
363
|
+
return {
|
|
364
|
+
kind: KIND,
|
|
365
|
+
elementIds: [],
|
|
366
|
+
alignment: Alignment.Left,
|
|
367
|
+
selectFunction: 'all',
|
|
368
|
+
...options
|
|
369
|
+
};
|
|
367
370
|
}
|
|
371
|
+
}
|
|
368
372
|
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
@injectable()
|
|
374
|
+
export class AlignElementsActionHandler extends LayoutElementsActionHandler {
|
|
375
|
+
handle(action: AlignElementsAction): void {
|
|
376
|
+
const elements = this.getSelectedElements(action);
|
|
377
|
+
const selectFn = SelectFunction.get(action.selectFunction);
|
|
378
|
+
const calculatedElements = selectFn(elements);
|
|
371
379
|
if (elements.length > 1) {
|
|
372
|
-
switch (
|
|
380
|
+
switch (action.alignment) {
|
|
373
381
|
case Alignment.Left:
|
|
374
|
-
this.alignLeft(
|
|
375
|
-
break;
|
|
382
|
+
return this.alignLeft(calculatedElements);
|
|
376
383
|
case Alignment.Center:
|
|
377
|
-
this.alignCenter(
|
|
378
|
-
break;
|
|
384
|
+
return this.alignCenter(calculatedElements);
|
|
379
385
|
case Alignment.Right:
|
|
380
|
-
this.alignRight(
|
|
381
|
-
break;
|
|
386
|
+
return this.alignRight(calculatedElements);
|
|
382
387
|
case Alignment.Top:
|
|
383
|
-
this.alignTop(
|
|
384
|
-
break;
|
|
388
|
+
return this.alignTop(calculatedElements);
|
|
385
389
|
case Alignment.Middle:
|
|
386
|
-
this.alignMiddle(
|
|
387
|
-
break;
|
|
390
|
+
return this.alignMiddle(calculatedElements);
|
|
388
391
|
case Alignment.Bottom:
|
|
389
|
-
this.alignBottom(
|
|
390
|
-
break;
|
|
392
|
+
return this.alignBottom(calculatedElements);
|
|
391
393
|
}
|
|
392
394
|
}
|
|
393
|
-
return context.root;
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
alignLeft(elements: BoundsAwareModelElement[]): void {
|
|
397
|
-
const
|
|
398
|
-
const minX = calculationElements.map(element => element.bounds.x).reduce((a, b) => Math.min(a, b));
|
|
398
|
+
const minX = elements.map(element => element.bounds.x).reduce((a, b) => Math.min(a, b));
|
|
399
399
|
this.dispatchAlignActions(elements, (_, move) => (move.toPosition.x = minX));
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
alignCenter(elements: BoundsAwareModelElement[]): void {
|
|
403
|
-
const
|
|
404
|
-
const
|
|
405
|
-
const maxX = calculationElements.map(element => element.bounds.x + element.bounds.width).reduce((a, b) => Math.max(a, b));
|
|
403
|
+
const minX = elements.map(element => element.bounds.x).reduce((a, b) => Math.min(a, b));
|
|
404
|
+
const maxX = elements.map(element => element.bounds.x + element.bounds.width).reduce((a, b) => Math.max(a, b));
|
|
406
405
|
const diffX = maxX - minX;
|
|
407
406
|
const centerX = minX + 0.5 * diffX;
|
|
408
407
|
this.dispatchAlignActions(elements, (element, move) => (move.toPosition.x = centerX - 0.5 * element.bounds.width));
|
|
409
408
|
}
|
|
410
409
|
|
|
411
410
|
alignRight(elements: BoundsAwareModelElement[]): void {
|
|
412
|
-
const
|
|
413
|
-
const maxX = calculationElements.map(element => element.bounds.x + element.bounds.width).reduce((a, b) => Math.max(a, b));
|
|
411
|
+
const maxX = elements.map(element => element.bounds.x + element.bounds.width).reduce((a, b) => Math.max(a, b));
|
|
414
412
|
this.dispatchAlignActions(elements, (element, move) => (move.toPosition.x = maxX - element.bounds.width));
|
|
415
413
|
}
|
|
416
414
|
|
|
417
415
|
alignTop(elements: BoundsAwareModelElement[]): void {
|
|
418
|
-
const
|
|
419
|
-
const minY = calculationElements.map(element => element.bounds.y).reduce((a, b) => Math.min(a, b));
|
|
416
|
+
const minY = elements.map(element => element.bounds.y).reduce((a, b) => Math.min(a, b));
|
|
420
417
|
this.dispatchAlignActions(elements, (_, move) => (move.toPosition.y = minY));
|
|
421
418
|
}
|
|
422
419
|
|
|
423
420
|
alignMiddle(elements: BoundsAwareModelElement[]): void {
|
|
424
|
-
const
|
|
425
|
-
const
|
|
426
|
-
const maxY = calculationElements.map(element => element.bounds.y + element.bounds.height).reduce((a, b) => Math.max(a, b));
|
|
421
|
+
const minY = elements.map(element => element.bounds.y).reduce((a, b) => Math.min(a, b));
|
|
422
|
+
const maxY = elements.map(element => element.bounds.y + element.bounds.height).reduce((a, b) => Math.max(a, b));
|
|
427
423
|
const diffY = maxY - minY;
|
|
428
424
|
const middleY = minY + 0.5 * diffY;
|
|
429
425
|
this.dispatchAlignActions(elements, (element, move) => (move.toPosition.y = middleY - 0.5 * element.bounds.height));
|
|
430
426
|
}
|
|
431
427
|
|
|
432
428
|
alignBottom(elements: BoundsAwareModelElement[]): void {
|
|
433
|
-
const
|
|
434
|
-
const maxY = calculationElements.map(element => element.bounds.y + element.bounds.height).reduce((a, b) => Math.max(a, b));
|
|
429
|
+
const maxY = elements.map(element => element.bounds.y + element.bounds.height).reduce((a, b) => Math.max(a, b));
|
|
435
430
|
this.dispatchAlignActions(elements, (element, move) => (move.toPosition.y = maxY - element.bounds.height));
|
|
436
431
|
}
|
|
437
432
|
|
|
438
433
|
dispatchAlignActions(
|
|
439
434
|
elements: BoundsAwareModelElement[],
|
|
440
|
-
change: (element: BoundsAwareModelElement, move:
|
|
435
|
+
change: (element: BoundsAwareModelElement, move: Writable<ElementMove>) => void
|
|
441
436
|
): void {
|
|
442
437
|
const moves: ElementMove[] = []; // client-side move
|
|
443
438
|
const elementAndBounds: ElementAndBounds[] = []; // server-side move
|
|
@@ -455,9 +450,9 @@ export class AlignElementsCommand extends LayoutElementsCommand {
|
|
|
455
450
|
|
|
456
451
|
createElementMove(
|
|
457
452
|
element: BoundsAwareModelElement,
|
|
458
|
-
change: (_element: BoundsAwareModelElement, _move:
|
|
459
|
-
):
|
|
460
|
-
const move:
|
|
453
|
+
change: (_element: BoundsAwareModelElement, _move: Writable<ElementMove>) => void
|
|
454
|
+
): Writable<ElementMove> | undefined {
|
|
455
|
+
const move: ElementMove = {
|
|
461
456
|
elementId: element.id,
|
|
462
457
|
fromPosition: {
|
|
463
458
|
x: element.bounds.x,
|
|
@@ -485,14 +480,7 @@ export class AlignElementsCommand extends LayoutElementsCommand {
|
|
|
485
480
|
}
|
|
486
481
|
};
|
|
487
482
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
// we dispatch another action which can be undone, so no explicit implementation necessary
|
|
491
|
-
return context.root;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
redo(context: CommandExecutionContext): CommandReturn {
|
|
495
|
-
// we dispatch another action which can be redone, so no explicit implementation necessary
|
|
496
|
-
return context.root;
|
|
483
|
+
protected isActionElement(element: SModelElement): element is BoundsAwareModelElement {
|
|
484
|
+
return isBoundsAwareMoveable(element);
|
|
497
485
|
}
|
|
498
486
|
}
|
|
@@ -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
|
}
|