Skip to content

Commit

Permalink
Introduce an optional grid module to deal with a grid layout (eclipse…
Browse files Browse the repository at this point in the history
…-glsp#343)

* Introduce an optional grid module to deal with a grid layout

- Optional grid module defines a grid based on x/y coordinates
-- Adds the grid as a background that properly zooms/resizes
-- By default uses the GridSnapper for positioning elements
-- Use grid for helper lines and movement tools

- Optional debug module that shows the bounds of elements
-- Useful for debugging but not meant for production

- Render optional debug and grid toggles in tool palette if present

- Add both optional modules to the workflow example
- Use half-grid snapping for routing handles for nicer UX
- Bonus: Add OriginViewportAction to reset to 0,0 on zoom-level 1

Contributed on behalf of Axon Ivy AG

Fixes eclipse-glsp/glsp#1336
  • Loading branch information
martin-fleck-at authored and holkerveen committed Dec 21, 2024
1 parent 504d924 commit ee46410
Show file tree
Hide file tree
Showing 41 changed files with 1,127 additions and 126 deletions.
2 changes: 2 additions & 0 deletions examples/workflow-glsp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@
export * from './direct-task-editing';
export * from './model';
export * from './workflow-diagram-module';
export * from './workflow-snapper';
export * from './workflow-startup';
export * from './workflow-views';
26 changes: 16 additions & 10 deletions examples/workflow-glsp/src/workflow-diagram-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@ import {
GLSPProjectionView,
GLabel,
GLabelView,
GridSnapper,
IHelperLineOptions,
ISnapper,
LogLevel,
Point,
RectangularNodeView,
RevealNamedElementActionProvider,
RoundedCornerNodeView,
Expand All @@ -41,7 +38,9 @@ import {
bindOrRebind,
configureDefaultModelElements,
configureModelElement,
debugModule,
editLabelFeature,
gridModule,
helperLineModule,
initializeDiagramContainer
} from '@eclipse-glsp/client';
Expand All @@ -51,14 +50,15 @@ import 'sprotty/css/edit-label.css';
import '../css/diagram.css';
import { directTaskEditor } from './direct-task-editing/di.config';
import { ActivityNode, CategoryNode, Icon, TaskNode, WeightedEdge } from './model';
import { WorkflowSnapper } from './workflow-snapper';
import { WorkflowStartup } from './workflow-startup';
import { IconView, WorkflowEdgeView } from './workflow-views';

export const workflowDiagramModule = new ContainerModule((bind, unbind, isBound, rebind) => {
const context = { bind, unbind, isBound, rebind };

bindOrRebind(context, TYPES.ILogger).to(ConsoleLogger).inSingletonScope();
bindOrRebind(context, TYPES.LogLevel).toConstantValue(LogLevel.warn);
bind(TYPES.ISnapper).to(GridSnapper);
bindAsService(context, TYPES.ICommandPaletteActionProvider, RevealNamedElementActionProvider);
bindAsService(context, TYPES.IContextMenuItemProvider, DeleteElementContextMenuItemProvider);

Expand All @@ -82,22 +82,28 @@ export const workflowDiagramModule = new ContainerModule((bind, unbind, isBound,

bind<IHelperLineOptions>(TYPES.IHelperLineOptions).toDynamicValue(ctx => {
const options: IHelperLineOptions = {};
// the user needs to use twice the force (double the distance) to break through a helper line compared to moving on the grid
const snapper = ctx.container.get<ISnapper>(TYPES.ISnapper);
if (snapper instanceof GridSnapper) {
options.minimumMoveDelta = Point.multiplyScalar(snapper.grid, 2);
}
// skip icons for alignment as well as compartments which are only used for structure
options.alignmentElementFilter = element =>
DEFAULT_ALIGNABLE_ELEMENT_FILTER(element) && !(element instanceof Icon) && !(element instanceof GCompartment);
return options;
});

bindAsService(context, TYPES.IDiagramStartup, WorkflowStartup);
bindOrRebind(context, TYPES.ISnapper).to(WorkflowSnapper);
});

export function createWorkflowDiagramContainer(...containerConfiguration: ContainerConfiguration): Container {
return initializeWorkflowDiagramContainer(new Container(), ...containerConfiguration);
}

export function initializeWorkflowDiagramContainer(container: Container, ...containerConfiguration: ContainerConfiguration): Container {
return initializeDiagramContainer(container, workflowDiagramModule, directTaskEditor, helperLineModule, ...containerConfiguration);
return initializeDiagramContainer(
container,
directTaskEditor,
helperLineModule,
gridModule,
debugModule,
workflowDiagramModule,
...containerConfiguration
);
}
29 changes: 29 additions & 0 deletions examples/workflow-glsp/src/workflow-snapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/********************************************************************************
* Copyright (c) 2024 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { GModelElement, GRoutingHandle, GridSnapper, Point } from '@eclipse-glsp/client';
import { injectable } from 'inversify';

@injectable()
export class WorkflowSnapper extends GridSnapper {
override snap(position: Point, element: GModelElement): Point {
// we snap our edges to the center of the elements and our elements to the grid,
// so to allow for nicer angles and more fine-grained control, we allow routing points to be snapped half-grid
return element instanceof GRoutingHandle
? Point.snapToGrid(position, Point.divideScalar(this.grid, 2))
: super.snap(position, element);
}
}
30 changes: 30 additions & 0 deletions examples/workflow-glsp/src/workflow-startup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/********************************************************************************
* Copyright (c) 2024 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { GridManager, IDiagramStartup } from '@eclipse-glsp/client';
import { MaybePromise, TYPES } from '@eclipse-glsp/sprotty';
import { inject, injectable, optional } from 'inversify';

@injectable()
export class WorkflowStartup implements IDiagramStartup {
rank = -1;

@inject(TYPES.IGridManager) @optional() protected gridManager?: GridManager;

preRequestModel(): MaybePromise<void> {
this.gridManager?.setGridVisible(true);
}
}
3 changes: 2 additions & 1 deletion examples/workflow-standalone/css/diagram.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
--glsp-info-foreground: blue;
}

.sprotty-graph {
.sprotty-graph,
.grid-background {
background: rgb(179, 196, 202);
}

Expand Down
25 changes: 25 additions & 0 deletions packages/client/css/debug.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/********************************************************************************
* Copyright (c) 2024 Axon Ivy AG and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

.debug-bounds:has(> .debug-bounds-decoration) {
fill-opacity: 0.5;
}

.debug-bounds-decoration {
fill: none;
stroke: black;
stroke-width: 1px;
}
20 changes: 20 additions & 0 deletions packages/client/css/grid.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/********************************************************************************
* Copyright (c) 2024 Axon Ivy AG and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

/** Control visibility of background image through CSS class on parent */
.grid-background .sprotty-graph {
background-image: var(--grid-background-image);
}
6 changes: 0 additions & 6 deletions packages/client/css/keyboard-tool-palette.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,7 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

.accessibility-tool-palette.tool-palette {
top: 48px;
width: 240px;
}

.accessibility-tool-palette .header-tools i {
margin-right: 0.5em;
position: relative;
}

Expand Down
56 changes: 30 additions & 26 deletions packages/client/css/tool-palette.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
/* Css for main container */
.tool-palette {
position: absolute;
right: 40px;
top: 25px;
right: 45px;
top: 35px;
text-align: center;
width: 225px;
width: fit-content;
display: block;
z-index: 1000;
border-style: solid;
Expand All @@ -38,40 +38,41 @@
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */

box-shadow:
4px 0 4px 0 rgba(0, 0, 0, 0.2),
0 4px 4px 0 rgba(0, 0, 0, 0.19);
font-size: 14px;
}

/* Css for header compartment */

.palette-header {
padding: 0.4em;
text-align: left;
background: #cccccc;
background: rgb(151, 160, 165);
border: 1px solid rgba(60, 60, 60, 0.6);
box-shadow:
0 4px 8px 0 rgba(0, 0, 0, 0.2),
0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 6px;
}

.header-icon {
display: flex;
display: none;
align-items: center;
}

.header-icon i {
margin-right: 0.2em;
}

.header-tools {
display: flex;
align-items: center;
gap: 3px;
}

.header-tools i {
border: 1px solid #cccccc;
border: 1px solid transparent;
padding: 0.15em;
margin-right: 0.15em;
}
Expand All @@ -90,9 +91,6 @@
.palette-body {
background: rgba(100, 100, 100, 0.2);
border: 1px solid rgba(60, 60, 60, 0.6);
box-shadow:
0 4px 8px 0 rgba(0, 0, 0, 0.2),
0 6px 20px 0 rgba(0, 0, 0, 0.19);
}

.tool-group {
Expand All @@ -101,21 +99,21 @@
}

.group-header {
background: #cccccc;
background: rgb(187, 193, 196);
display: flex;
align-items: center;
}

.group-header:hover {
background: #aaaaaa;
background: rgb(187, 193, 196);
}

.group-header i {
padding: 0.4em;
}

.tool-button {
background: #ededee;
background: rgb(252, 253, 253);
padding: 0.4em;
display: flex;
align-items: center;
Expand All @@ -126,11 +124,11 @@
}

.tool-button:hover {
background: #dfdfdf;
background: rgb(220, 223, 224);
}

.tool-button.clicked {
background: #bddaef;
background: rgb(163, 201, 219);
}

.tool-button.collapsed {
Expand All @@ -147,13 +145,19 @@
right: 20px;
top: 35px;
z-index: 1000;
color: rgb(58, 63, 65);
}

.minimize-palette-button .codicon::before {
font-size: 20px;
}

.search-input {
background: #dfdfdf;
box-sizing: border-box;
background: rgb(252, 253, 253);
color: black;
border: #bddaef;
padding-left: 3px;
border: 1px solid rgb(187, 193, 196);
padding: 4px;
width: 100%;
margin: 3px;
margin: 3px 0;
}
Loading

0 comments on commit ee46410

Please sign in to comment.