@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
150 lines (134 loc) • 5.94 kB
text/typescript
/********************************************************************************
* Copyright (c) 2023 Business Informatics Group (TU Wien) 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 {
Action,
CenterAction,
GModelElement,
GModelRoot,
KeyListener,
Point,
SetViewportAction,
TYPES,
Viewport,
isViewport,
matchesKeystroke
} from '@eclipse-glsp/sprotty';
import { inject, injectable } from 'inversify';
import { messages, repeatOnMessagesUpdated } from '../../../base/messages';
import { SelectionService } from '../../../base/selection-service';
import type { IShortcutManager } from '../../../base/shortcuts/shortcuts-manager';
import { getAbsolutePositionByPoint } from '../../../utils/viewpoint-util';
import { BaseTool } from '../../tools/base-tools';
import type { ZoomFactors } from '../../viewport/zoom-viewport-action';
import { ElementNavigatorKeyListener } from '../element-navigation/diagram-navigation-tool';
import { EnableKeyboardGridAction, KeyboardGridCellSelectedAction, KeyboardGridKeyboardEventAction } from '../keyboard-grid/action';
import { HideToastAction, ShowToastMessageAction } from '../toast/toast-handler';
/**
* Zoom viewport and elements when its focused and arrow keys are hit.
*/
export class GridCellZoomTool extends BaseTool {
static ID = 'glsp.accessibility-grid-cell-zoom-tool';
static TOKEN = Symbol.for(GridCellZoomTool.name);
protected readonly zoomKeyListener = new GridZoomKeyListener(this);
protected readonly shortcutManager: IShortcutManager;
protected readonly zoomFactors: ZoomFactors;
selectionService: SelectionService;
get id(): string {
return GridCellZoomTool.ID;
}
enable(): void {
this.toDisposeOnDisable.push(
this.keyTool.registerListener(this.zoomKeyListener),
repeatOnMessagesUpdated(() =>
this.shortcutManager.register(GridCellZoomTool.TOKEN, [
{
shortcuts: ['CTRL', '+'],
description: messages.grid.shortcut_zoom_in,
group: messages.shortcut.group_zoom,
position: 0
}
])
)
);
}
handle(action: Action): Action | void {
if (isViewport(this.editorContext.modelRoot)) {
let viewportAction: Action | undefined = undefined;
if (KeyboardGridCellSelectedAction.is(action) && action.options.originId === GridCellZoomTool.ID) {
viewportAction = this.zoomKeyListener.setNewZoomFactor(
this.editorContext.modelRoot,
this.zoomFactors.in,
getAbsolutePositionByPoint(this.editorContext.modelRoot, action.options.centerCellPosition)
);
} else if (KeyboardGridKeyboardEventAction.is(action) && action.options.originId === GridCellZoomTool.ID) {
if (matchesKeystroke(action.options.event, 'Minus')) {
viewportAction = this.zoomKeyListener.setNewZoomFactor(this.editorContext.modelRoot, this.zoomFactors.out);
} else if (matchesKeystroke(action.options.event, 'Digit0', 'ctrl')) {
viewportAction = CenterAction.create([]);
}
}
if (viewportAction) {
this.actionDispatcher.dispatchAll([
viewportAction,
HideToastAction.create({ id: Symbol.for(ElementNavigatorKeyListener.name) })
]);
}
}
}
}
export class GridZoomKeyListener extends KeyListener {
constructor(protected tool: GridCellZoomTool) {
super();
}
setNewZoomFactor(viewport: GModelElement & GModelRoot & Viewport, zoomFactor: number, point?: Point): SetViewportAction {
let newViewport: Viewport;
const newZoom = viewport.zoom * zoomFactor;
if (point) {
newViewport = {
scroll: {
x: point.x - (0.5 * viewport.canvasBounds.width) / newZoom,
y: point.y - (0.5 * viewport.canvasBounds.height) / newZoom
},
zoom: newZoom
};
} else {
newViewport = {
scroll: viewport.scroll,
zoom: newZoom
};
}
return SetViewportAction.create(viewport.id, newViewport, { animate: false });
}
override keyDown(element: GModelElement, event: KeyboardEvent): Action[] {
if (this.matchesZoomViaGrid(event)) {
return [
EnableKeyboardGridAction.create({
originId: GridCellZoomTool.ID,
triggerActions: []
}),
ShowToastMessageAction.createWithTimeout({
id: Symbol.for(ElementNavigatorKeyListener.name),
message: messages.grid.zoom_in_grid
})
];
}
return [];
}
protected matchesZoomViaGrid(event: KeyboardEvent): boolean {
return event.key === '+' && event.ctrlKey;
}
}