@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
|
@@ -13,25 +13,31 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Action, SetModelAction, UpdateModelAction } from '@eclipse-glsp/protocol';
|
|
17
|
-
import { inject, injectable, multiInject, optional
|
|
16
|
+
import { Action, SetModelAction, toTypeGuard, UpdateModelAction } from '@eclipse-glsp/protocol';
|
|
17
|
+
import { inject, injectable, multiInject, optional } from 'inversify';
|
|
18
18
|
import {
|
|
19
19
|
ActionHandlerRegistry,
|
|
20
|
+
Animation,
|
|
20
21
|
Command,
|
|
21
22
|
CommandActionHandler,
|
|
22
23
|
CommandExecutionContext,
|
|
23
24
|
CommandReturn,
|
|
24
25
|
IActionHandler,
|
|
25
26
|
ILogger,
|
|
27
|
+
MorphEdgesAnimation,
|
|
26
28
|
SModelRoot,
|
|
29
|
+
UpdateAnimationData,
|
|
27
30
|
UpdateModelCommand
|
|
28
31
|
} from 'sprotty';
|
|
29
32
|
import { IFeedbackActionDispatcher } from '../../features/tool-feedback/feedback-action-dispatcher';
|
|
30
33
|
import { FeedbackCommand } from '../../features/tool-feedback/model';
|
|
31
34
|
import { TYPES } from '../types';
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
*
|
|
36
|
+
/**
|
|
37
|
+
* ActionHandler that transforms a {@link SetModelAction} into an {@link UpdateModelAction} that can be handled
|
|
38
|
+
* by the {@link FeedbackAwareUpdateModelCommand}. This can be done because in sprotty an {@link UpdateModelCommand} and
|
|
39
|
+
* a {@link SetModelCommand} have the same behavior of no model is present yet.
|
|
40
|
+
*/
|
|
35
41
|
@injectable()
|
|
36
42
|
export class SetModelActionHandler implements IActionHandler {
|
|
37
43
|
handle(action: Action): Action | void {
|
|
@@ -46,38 +52,41 @@ export interface SModelRootListener {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
49
|
-
* A special
|
|
50
|
-
* feedback to the `newRoot` before performing the update
|
|
55
|
+
* A special {@link UpdateModelCommand} that retrieves all registered {@link Action}s from the {@link IFeedbackActionDispatcher}
|
|
56
|
+
* (if present) and applies their feedback to the `newRoot` before performing the update. This enables persistent client-side feedback
|
|
57
|
+
* across model updates initiated by the GLSP server.
|
|
51
58
|
*/
|
|
52
59
|
@injectable()
|
|
53
60
|
export class FeedbackAwareUpdateModelCommand extends UpdateModelCommand {
|
|
54
|
-
@inject(TYPES.ILogger)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@
|
|
61
|
+
@inject(TYPES.ILogger)
|
|
62
|
+
protected logger: ILogger;
|
|
63
|
+
|
|
64
|
+
@inject(TYPES.IFeedbackActionDispatcher)
|
|
65
|
+
@optional()
|
|
66
|
+
protected feedbackActionDispatcher: IFeedbackActionDispatcher;
|
|
67
|
+
|
|
68
|
+
@multiInject(TYPES.SModelRootListener)
|
|
69
|
+
@optional()
|
|
70
|
+
protected modelRootListeners: SModelRootListener[] = [];
|
|
58
71
|
|
|
59
72
|
protected actionHandlerRegistry?: ActionHandlerRegistry;
|
|
60
73
|
|
|
61
|
-
constructor(
|
|
74
|
+
constructor(
|
|
75
|
+
@inject(TYPES.Action) action: UpdateModelAction,
|
|
76
|
+
@inject(TYPES.ActionHandlerRegistryProvider)
|
|
77
|
+
actionHandlerRegistryProvider: () => Promise<ActionHandlerRegistry>
|
|
78
|
+
) {
|
|
62
79
|
super({ animate: true, ...action });
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@postConstruct()
|
|
66
|
-
protected initialize(): void {
|
|
67
|
-
this.actionHandlerRegistryProvider().then(registry => (this.actionHandlerRegistry = registry));
|
|
80
|
+
actionHandlerRegistryProvider().then(registry => (this.actionHandlerRegistry = registry));
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
protected override performUpdate(oldRoot: SModelRoot, newRoot: SModelRoot, context: CommandExecutionContext): CommandReturn {
|
|
71
84
|
if (this.feedbackActionDispatcher && this.actionHandlerRegistry) {
|
|
72
|
-
// Create a temporary context
|
|
85
|
+
// Create a temporary context which defines the `newRoot` as `root`
|
|
73
86
|
// This way we do not corrupt the redo/undo behavior of the super class
|
|
74
87
|
const tempContext: CommandExecutionContext = {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
logger: context.logger,
|
|
78
|
-
modelChanged: context.modelChanged,
|
|
79
|
-
modelFactory: context.modelFactory,
|
|
80
|
-
syncer: context.syncer
|
|
88
|
+
...context,
|
|
89
|
+
root: newRoot
|
|
81
90
|
};
|
|
82
91
|
|
|
83
92
|
const feedbackCommands = this.getFeedbackCommands(this.actionHandlerRegistry);
|
|
@@ -91,19 +100,24 @@ export class FeedbackAwareUpdateModelCommand extends UpdateModelCommand {
|
|
|
91
100
|
protected getFeedbackCommands(registry: ActionHandlerRegistry): Command[] {
|
|
92
101
|
const result: Command[] = [];
|
|
93
102
|
this.feedbackActionDispatcher.getRegisteredFeedback().forEach(action => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
const commands = registry
|
|
104
|
+
.get(action.kind)
|
|
105
|
+
.filter<CommandActionHandler>(toTypeGuard(CommandActionHandler))
|
|
106
|
+
.map(handler => handler.handle(action));
|
|
107
|
+
result.push(...commands);
|
|
98
108
|
});
|
|
99
|
-
// sort commands
|
|
100
|
-
return result.sort((a, b) => getPriority(b) - getPriority(a));
|
|
109
|
+
// sort commands descanting by priority
|
|
110
|
+
return result.sort((a, b) => this.getPriority(b) - this.getPriority(a));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected getPriority(command: Partial<FeedbackCommand>): number {
|
|
114
|
+
return command.priority ?? 0;
|
|
101
115
|
}
|
|
102
|
-
}
|
|
103
116
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
// Override the `createAnimations` implementation and remove the animation for edge morphing. Otherwise routing & reconnect
|
|
118
|
+
// handles flicker after each server update.
|
|
119
|
+
protected override createAnimations(data: UpdateAnimationData, root: SModelRoot, context: CommandExecutionContext): Animation[] {
|
|
120
|
+
const animations = super.createAnimations(data, root, context);
|
|
121
|
+
return animations.filter(animation => !(animation instanceof MorphEdgesAnimation));
|
|
107
122
|
}
|
|
108
|
-
return 0;
|
|
109
123
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/********************************************************************************
|
|
2
|
-
* Copyright (c) 2020 EclipseSource and others.
|
|
2
|
+
* Copyright (c) 2020-2022 EclipseSource and others.
|
|
3
3
|
*
|
|
4
4
|
* This program and the accompanying materials are made available under the
|
|
5
5
|
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
import { AnyObject, hasStringProp } from '@eclipse-glsp/protocol';
|
|
17
|
+
export interface SourceUriAware {
|
|
18
|
+
sourceURI: string;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export function isSourceUriAware(obj: any): obj is SourceUriAware {
|
|
21
|
-
return obj
|
|
22
|
+
return AnyObject.is(obj) && hasStringProp(obj, 'sourceURI');
|
|
22
23
|
}
|
|
@@ -20,40 +20,35 @@ import { toAbsoluteBounds } from '../../utils/viewpoint-util';
|
|
|
20
20
|
import { ModifyCSSFeedbackAction } from '../tool-feedback/css-feedback';
|
|
21
21
|
import { isBoundsAwareMoveable, SResizeHandle } from './model';
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A `MovementRestrictor` is an optional service that can be used by tools to validate
|
|
25
|
+
* whether a certain move operation (e.g. `ChangeBoundsOperation`) in the diagram is valid.
|
|
26
|
+
*/
|
|
23
27
|
export interface IMovementRestrictor {
|
|
24
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Validate whether moving the given element to a new given location is allowed.
|
|
30
|
+
* @param element The element that should be moved.
|
|
31
|
+
* @param newLocation The new location of the element.
|
|
32
|
+
* @returns `true` if the the element is movable and moving to the given location is allowed, `false` otherwise.
|
|
33
|
+
* Should also return `false` if the newLocation is `undefined`:
|
|
34
|
+
*/
|
|
35
|
+
validate(element: SModelElement, newLocation?: Point): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Feedback css-classes. Can be applied to elements that did fail the validation.
|
|
38
|
+
*/
|
|
25
39
|
cssClasses?: string[];
|
|
26
40
|
}
|
|
27
41
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const elements: SModelElement[] = [element];
|
|
33
|
-
if (element instanceof SParentElement) {
|
|
34
|
-
element.children.filter(child => child instanceof SResizeHandle).forEach(e => elements.push(e));
|
|
35
|
-
}
|
|
36
|
-
return ModifyCSSFeedbackAction.create({ elements, add: movementRestrictor.cssClasses });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function removeMovementRestrictionFeedback(
|
|
40
|
-
element: SModelElement,
|
|
41
|
-
movementRestrictor: IMovementRestrictor
|
|
42
|
-
): ModifyCSSFeedbackAction {
|
|
43
|
-
const elements: SModelElement[] = [element];
|
|
44
|
-
if (element instanceof SParentElement) {
|
|
45
|
-
element.children.filter(child => child instanceof SResizeHandle).forEach(e => elements.push(e));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return ModifyCSSFeedbackAction.create({ elements, remove: movementRestrictor.cssClasses });
|
|
49
|
-
}
|
|
50
|
-
|
|
42
|
+
/**
|
|
43
|
+
* A `IMovementRestrictor` that checks for overlapping elements. Move operations
|
|
44
|
+
* are only valid if the element does not collide with another element after moving.
|
|
45
|
+
*/
|
|
51
46
|
@injectable()
|
|
52
|
-
export class
|
|
47
|
+
export class NoOverlapMovementRestrictor implements IMovementRestrictor {
|
|
53
48
|
cssClasses = ['movement-not-allowed'];
|
|
54
49
|
|
|
55
|
-
validate(
|
|
56
|
-
if (!isBoundsAwareMoveable(element)) {
|
|
50
|
+
validate(element: SModelElement, newLocation?: Point): boolean {
|
|
51
|
+
if (!isBoundsAwareMoveable(element) || !newLocation) {
|
|
57
52
|
return false;
|
|
58
53
|
}
|
|
59
54
|
// Create ghost element at the newLocation
|
|
@@ -71,27 +66,62 @@ export class NoOverlapMovmentRestrictor implements IMovementRestrictor {
|
|
|
71
66
|
.all()
|
|
72
67
|
.filter(e => e.id !== ghostElement.id && e !== ghostElement.root && e instanceof SNode)
|
|
73
68
|
.map(e => e as SModelElement & BoundsAware)
|
|
74
|
-
).some(e => areOverlapping(e, ghostElement));
|
|
69
|
+
).some(e => this.areOverlapping(e, ghostElement));
|
|
75
70
|
}
|
|
76
|
-
}
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
protected areOverlapping(element1: SModelElement & BoundsAware, element2: SModelElement & BoundsAware): boolean {
|
|
73
|
+
const b1 = toAbsoluteBounds(element1);
|
|
74
|
+
const b2 = toAbsoluteBounds(element2);
|
|
75
|
+
const r1TopLeft: Point = b1;
|
|
76
|
+
const r1BottomRight = { x: b1.x + b1.width, y: b1.y + b1.height };
|
|
77
|
+
const r2TopLeft: Point = b2;
|
|
78
|
+
const r2BottomRight = { x: b2.x + b2.width, y: b2.y + b2.height };
|
|
79
|
+
|
|
80
|
+
// If one rectangle is on left side of other
|
|
81
|
+
if (r1TopLeft.x > r2BottomRight.x || r2TopLeft.x > r1BottomRight.x) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
// If one rectangle is above other
|
|
86
|
+
if (r1BottomRight.y < r2TopLeft.y || r2BottomRight.y < r1TopLeft.y) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return true;
|
|
89
91
|
}
|
|
92
|
+
}
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Utility function to create an action that applies the given {@link IMovementRestrictor.cssClasses} to the given element.
|
|
96
|
+
* @param element The element on which the css classes should be applied.
|
|
97
|
+
* @param movementRestrictor The movement restrictor whose cssClasses should be applied.
|
|
98
|
+
* @returns The corresponding {@link ModifyCSSFeedbackAction}
|
|
99
|
+
*/
|
|
100
|
+
export function createMovementRestrictionFeedback(
|
|
101
|
+
element: SModelElement,
|
|
102
|
+
movementRestrictor: IMovementRestrictor
|
|
103
|
+
): ModifyCSSFeedbackAction {
|
|
104
|
+
const elements: SModelElement[] = [element];
|
|
105
|
+
if (element instanceof SParentElement) {
|
|
106
|
+
element.children.filter(child => child instanceof SResizeHandle).forEach(e => elements.push(e));
|
|
107
|
+
}
|
|
108
|
+
return ModifyCSSFeedbackAction.create({ elements, add: movementRestrictor.cssClasses });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Utility function to create an action that removes the given {@link IMovementRestrictor.cssClasses} from the given element.
|
|
113
|
+
* @param element The element from which the css classes should be removed.
|
|
114
|
+
* @param movementRestrictor The movement restrictor whose cssClasses should be removed.
|
|
115
|
+
* @returns The corresponding {@link ModifyCSSFeedbackAction}
|
|
116
|
+
*/
|
|
117
|
+
export function removeMovementRestrictionFeedback(
|
|
118
|
+
element: SModelElement,
|
|
119
|
+
movementRestrictor: IMovementRestrictor
|
|
120
|
+
): ModifyCSSFeedbackAction {
|
|
121
|
+
const elements: SModelElement[] = [element];
|
|
122
|
+
if (element instanceof SParentElement) {
|
|
123
|
+
element.children.filter(child => child instanceof SResizeHandle).forEach(e => elements.push(e));
|
|
94
124
|
}
|
|
95
125
|
|
|
96
|
-
return
|
|
126
|
+
return ModifyCSSFeedbackAction.create({ elements, remove: movementRestrictor.cssClasses });
|
|
97
127
|
}
|
|
@@ -13,25 +13,28 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Point } from '@eclipse-glsp/protocol';
|
|
16
|
+
import { Point, Writable } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { injectable } from 'inversify';
|
|
18
18
|
import { findParentByFeature, ISnapper, isViewport, SModelElement } from 'sprotty';
|
|
19
|
-
import { WriteablePoint } from '../../utils/layout-utils';
|
|
20
19
|
|
|
20
|
+
/**
|
|
21
|
+
* A {@link ISnapper} implementation that snaps all elements onto a fixed gride size.
|
|
22
|
+
* The default grid size is 10x10 pixel.
|
|
23
|
+
* To configure a custom grid size bind the `TYPES.ISnapper` service identifier
|
|
24
|
+
* to constant value, e.g:
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* bind(TYPES.ISnapper).toConstantValue(new GridSnapper({x:25 ,y:25 }));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
21
30
|
@injectable()
|
|
22
31
|
export class GridSnapper implements ISnapper {
|
|
23
|
-
|
|
24
|
-
return 10;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
get gridY(): number {
|
|
28
|
-
return 10;
|
|
29
|
-
}
|
|
32
|
+
constructor(public grid: { x: number; y: number } = { x: 10, y: 10 }) {}
|
|
30
33
|
|
|
31
34
|
snap(position: Point, element: SModelElement): Point {
|
|
32
35
|
return {
|
|
33
|
-
x: Math.round(position.x / this.
|
|
34
|
-
y: Math.round(position.y / this.
|
|
36
|
+
x: Math.round(position.x / this.grid.x) * this.grid.x,
|
|
37
|
+
y: Math.round(position.y / this.grid.y) * this.grid.y
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -46,7 +49,7 @@ export class GridSnapper implements ISnapper {
|
|
|
46
49
|
*/
|
|
47
50
|
export class PointPositionUpdater {
|
|
48
51
|
protected lastDragPosition?: Point;
|
|
49
|
-
protected positionDelta:
|
|
52
|
+
protected positionDelta: Writable<Point> = { x: 0, y: 0 };
|
|
50
53
|
|
|
51
54
|
constructor(protected snapper?: ISnapper) {}
|
|
52
55
|
|
|
@@ -15,53 +15,47 @@
|
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import { Action } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, optional } from 'inversify';
|
|
18
|
-
import {
|
|
19
|
-
ContextMenuProviderRegistry,
|
|
20
|
-
findParentByFeature,
|
|
21
|
-
IContextMenuServiceProvider,
|
|
22
|
-
isSelectable,
|
|
23
|
-
MouseListener,
|
|
24
|
-
SModelElement
|
|
25
|
-
} from 'sprotty';
|
|
18
|
+
import { ContextMenuProviderRegistry, IContextMenuServiceProvider, MouseListener, SModelElement } from 'sprotty';
|
|
26
19
|
import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
|
|
27
20
|
import { TYPES } from '../../base/types';
|
|
28
21
|
import { SelectionService } from '../select/selection-service';
|
|
29
22
|
|
|
30
23
|
@injectable()
|
|
31
24
|
export class SelectionServiceAwareContextMenuMouseListener extends MouseListener {
|
|
32
|
-
@inject(TYPES.IContextMenuServiceProvider)
|
|
33
|
-
@
|
|
34
|
-
|
|
25
|
+
@inject(TYPES.IContextMenuServiceProvider)
|
|
26
|
+
@optional()
|
|
27
|
+
protected readonly contextMenuService?: IContextMenuServiceProvider;
|
|
28
|
+
|
|
29
|
+
@inject(TYPES.IContextMenuProviderRegistry)
|
|
30
|
+
@optional()
|
|
31
|
+
protected readonly menuProvider?: ContextMenuProviderRegistry;
|
|
32
|
+
|
|
33
|
+
@inject(TYPES.SelectionService)
|
|
34
|
+
protected selectionService: SelectionService;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Opens the context menu
|
|
37
|
+
* Opens the context menu.
|
|
38
38
|
*/
|
|
39
|
-
override
|
|
40
|
-
|
|
41
|
-
return this.openContextMenu(event, target);
|
|
42
|
-
}
|
|
43
|
-
return [];
|
|
39
|
+
override contextMenu(target: SModelElement, event: MouseEvent): (Action | Promise<Action>)[] {
|
|
40
|
+
return this.openContextMenu(target, event);
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
/**
|
|
47
44
|
* Opens the context menu.
|
|
48
45
|
*
|
|
49
|
-
* - query the element on the click-target
|
|
50
|
-
* - select the element
|
|
51
46
|
* - query the context menu service and the context menu elements
|
|
52
47
|
* - show the context menu
|
|
53
48
|
* - send a focus state change to indicate that the diagram becomes inactive, once the context menu is shown
|
|
54
49
|
*
|
|
55
50
|
* When the context menu is closed, we focus the diagram element again.
|
|
56
51
|
*/
|
|
57
|
-
protected openContextMenu(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (selectableTarget) {
|
|
61
|
-
selectableTarget.selected = true;
|
|
62
|
-
this.selectionService.updateSelection(target.root, [selectableTarget.id], []);
|
|
52
|
+
protected openContextMenu(target: SModelElement, event: MouseEvent): Promise<Action>[] {
|
|
53
|
+
if (!this.contextMenuService || !this.menuProvider) {
|
|
54
|
+
return [];
|
|
63
55
|
}
|
|
64
56
|
|
|
57
|
+
const mousePosition = { x: event.x, y: event.y };
|
|
58
|
+
|
|
65
59
|
const result = Promise.all([this.contextMenuService(), this.menuProvider.getItems(target.root, mousePosition)])
|
|
66
60
|
.then(([menuService, menuItems]) => menuService.show(menuItems, mousePosition, () => this.focusEventTarget(event)))
|
|
67
61
|
.then((): Action => FocusStateChangedAction.create(false));
|
|
@@ -23,20 +23,11 @@ import {
|
|
|
23
23
|
SModelRootSchema
|
|
24
24
|
} from '@eclipse-glsp/protocol';
|
|
25
25
|
import { injectable } from 'inversify';
|
|
26
|
-
import {
|
|
27
|
-
EMPTY_ROOT,
|
|
28
|
-
HoverFeedbackAction,
|
|
29
|
-
HoverMouseListener,
|
|
30
|
-
IActionHandler,
|
|
31
|
-
ICommand,
|
|
32
|
-
SIssueMarker,
|
|
33
|
-
SIssueSeverity,
|
|
34
|
-
SModelElement
|
|
35
|
-
} from 'sprotty';
|
|
26
|
+
import { EMPTY_ROOT, HoverFeedbackAction, HoverMouseListener, IActionHandler, ICommand, SModelElement } from 'sprotty';
|
|
36
27
|
import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
|
|
37
28
|
import { EnableDefaultToolsAction, EnableToolsAction } from '../../base/tool-manager/tool-actions';
|
|
38
29
|
import { EdgeCreationTool } from '../tools/edge-creation-tool';
|
|
39
|
-
import { GIssueMarker } from '../validation/issue-marker';
|
|
30
|
+
import { getSeverity, GIssueMarker } from '../validation/issue-marker';
|
|
40
31
|
@injectable()
|
|
41
32
|
export class GlspHoverMouseListener extends HoverMouseListener implements IActionHandler {
|
|
42
33
|
protected enableHover = true;
|
|
@@ -117,16 +108,3 @@ export class GlspHoverMouseListener extends HoverMouseListener implements IActio
|
|
|
117
108
|
return bounds;
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
|
-
|
|
121
|
-
export function getSeverity(marker: SIssueMarker): SIssueSeverity {
|
|
122
|
-
let currentSeverity: SIssueSeverity = 'info';
|
|
123
|
-
for (const severity of marker.issues.map(s => s.severity)) {
|
|
124
|
-
if (severity === 'error') {
|
|
125
|
-
return severity;
|
|
126
|
-
}
|
|
127
|
-
if (severity === 'warning' && currentSeverity === 'info') {
|
|
128
|
-
currentSeverity = severity;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return currentSeverity;
|
|
132
|
-
}
|
|
@@ -14,19 +14,27 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import { ContainerModule } from 'inversify';
|
|
17
|
-
import {
|
|
17
|
+
import { configureActionHandler, configureLayout, HBoxLayouter, TYPES, VBoxLayouter } from 'sprotty';
|
|
18
18
|
import { FreeFormLayouter } from './freeform-layout';
|
|
19
19
|
import { HBoxLayouterExt } from './hbox-layout';
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
AlignElementsAction,
|
|
22
|
+
AlignElementsActionHandler,
|
|
23
|
+
ResizeElementsAction,
|
|
24
|
+
ResizeElementsActionHandler
|
|
25
|
+
} from './layout-elements-action';
|
|
26
|
+
import { LayouterExt } from './layouter';
|
|
21
27
|
import { VBoxLayouterExt } from './vbox-layout';
|
|
22
28
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const layoutModule = new ContainerModule((bind, _unbind, isBound, rebind) => {
|
|
30
|
+
const context = { bind, isBound };
|
|
31
|
+
configureActionHandler(context, ResizeElementsAction.KIND, ResizeElementsActionHandler);
|
|
32
|
+
configureActionHandler(context, AlignElementsAction.KIND, AlignElementsActionHandler);
|
|
26
33
|
|
|
27
34
|
rebind(VBoxLayouter).to(VBoxLayouterExt);
|
|
28
35
|
rebind(HBoxLayouter).to(HBoxLayouterExt);
|
|
36
|
+
rebind(TYPES.Layouter).to(LayouterExt);
|
|
29
37
|
configureLayout({ bind, isBound }, FreeFormLayouter.KIND, FreeFormLayouter);
|
|
30
38
|
});
|
|
31
39
|
|
|
32
|
-
export default
|
|
40
|
+
export default layoutModule;
|
|
@@ -49,6 +49,9 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
49
49
|
|
|
50
50
|
const fixedSize = this.getFixedContainerBounds(container, options, layouter);
|
|
51
51
|
|
|
52
|
+
const currentWidth = boundsData.bounds ? boundsData.bounds?.width - options.paddingLeft - options.paddingRight : 0;
|
|
53
|
+
const currentHeight = boundsData.bounds ? boundsData.bounds?.height - options.paddingTop - options.paddingBottom : 0;
|
|
54
|
+
|
|
52
55
|
const maxWidth =
|
|
53
56
|
options.paddingFactor *
|
|
54
57
|
(options.resizeContainer
|
|
@@ -60,8 +63,11 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
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 hGrab option
|
|
64
|
-
const grabWidth
|
|
70
|
+
const grabWidth = width - childrenSize.width;
|
|
65
71
|
// Number of children that request hGrab
|
|
66
72
|
// FIXME: This approach works fine when only 1 child uses HGrab, but may cause rounding issues
|
|
67
73
|
// when the grabHeight can't be equally shared by all children.
|
|
@@ -69,8 +75,8 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
69
75
|
.map(child => this.getChildLayoutOptions(child, options))
|
|
70
76
|
.filter(opt => opt.hGrab).length;
|
|
71
77
|
|
|
72
|
-
if (
|
|
73
|
-
const offset = this.layoutChildren(container, layouter, options,
|
|
78
|
+
if (width > 0 && height > 0) {
|
|
79
|
+
const offset = this.layoutChildren(container, layouter, options, width, height, grabWidth, grabbingChildren);
|
|
74
80
|
boundsData.bounds = this.getFinalContainerBounds(container, offset, options, childrenSize.width, childrenSize.height);
|
|
75
81
|
boundsData.boundsChanged = true;
|
|
76
82
|
}
|
|
@@ -155,8 +161,15 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
155
161
|
grabWidth?: number,
|
|
156
162
|
grabbingChildren?: number
|
|
157
163
|
): Point {
|
|
164
|
+
const vAlign = childOptions.vGrab ? 'top' : childOptions.vAlign;
|
|
165
|
+
const dy = this.getDy(vAlign, bounds, maxHeight);
|
|
158
166
|
let offset = super.layoutChild(child, boundsData, bounds, childOptions, containerOptions, currentOffset, maxWidth, maxHeight);
|
|
159
|
-
|
|
167
|
+
boundsData.bounds = {
|
|
168
|
+
...boundsData.bounds!,
|
|
169
|
+
x: currentOffset.x,
|
|
170
|
+
y: currentOffset.y + dy
|
|
171
|
+
};
|
|
172
|
+
if (childOptions.vGrab) {
|
|
160
173
|
boundsData.bounds = {
|
|
161
174
|
x: boundsData.bounds!.x,
|
|
162
175
|
y: boundsData.bounds!.y,
|
|
@@ -197,7 +210,7 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
197
210
|
}
|
|
198
211
|
|
|
199
212
|
protected override getChildLayoutOptions(child: SChildElement, containerOptions: HBoxLayoutOptionsExt): HBoxLayoutOptionsExt {
|
|
200
|
-
return super.getChildLayoutOptions(child, containerOptions) as HBoxLayoutOptionsExt;
|
|
213
|
+
return super.getChildLayoutOptions(child, this.filterContainerOptions(containerOptions)) as HBoxLayoutOptionsExt;
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
protected override getLayoutOptions(element: SModelElement): HBoxLayoutOptionsExt {
|
|
@@ -250,7 +263,11 @@ export class HBoxLayouterExt extends HBoxLayouter {
|
|
|
250
263
|
};
|
|
251
264
|
}
|
|
252
265
|
|
|
253
|
-
protected
|
|
254
|
-
|
|
266
|
+
protected filterContainerOptions(containerOptions: HBoxLayoutOptionsExt): HBoxLayoutOptionsExt {
|
|
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
|
}
|