@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
114 lines (95 loc) • 4.67 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 { EdgeRouterRegistry, findParentByFeature, GModelElement, GModelRoot, Point, toArray } from '@eclipse-glsp/sprotty';
import { inject, injectable, optional } from 'inversify';
import { GEdge } from '../../../model';
import { calcElementAndRoute, isRoutable, isSelectableAndBoundsAware, SelectableBoundsAware } from '../../../utils/gmodel-util';
import { ElementNavigator } from './element-navigator';
()
export class LeftToRightTopToBottomElementNavigator implements ElementNavigator {
(EdgeRouterRegistry) () readonly edgeRouterRegistry?: EdgeRouterRegistry;
previous(
root: Readonly<GModelRoot>,
current?: SelectableBoundsAware,
previousCurrent?: SelectableBoundsAware,
predicate: (element: GModelElement) => boolean = () => true
): GModelElement | undefined {
const elements = this.getElements(root, predicate);
if (current === undefined) {
return elements.length > 0 ? elements[0] : undefined;
}
return elements[this.getPreviousIndex(current, elements) % elements.length];
}
next(
root: Readonly<GModelRoot>,
current?: SelectableBoundsAware,
previousCurrent?: SelectableBoundsAware,
predicate: (element: GModelElement) => boolean = () => true
): GModelElement | undefined {
const elements = this.getElements(root, predicate);
if (current === undefined) {
return elements.length > 0 ? elements[0] : undefined;
}
return elements[this.getNextIndex(current, elements) % elements.length];
}
protected getElements(root: Readonly<GModelRoot>, predicate: (element: GModelElement) => boolean): GModelElement[] {
const elements = toArray(root.index.all().filter(e => isSelectableAndBoundsAware(e))) as SelectableBoundsAware[];
return elements.sort((a, b) => this.compare(a, b)).filter(predicate);
}
protected getNextIndex(current: SelectableBoundsAware, elements: GModelElement[]): number {
for (let index = 0; index < elements.length; index++) {
if (this.compare(elements[index], current) > 0) {
return index;
}
}
return 0;
}
protected getPreviousIndex(current: SelectableBoundsAware, elements: GModelElement[]): number {
for (let index = elements.length - 1; index >= 0; index--) {
if (this.compare(elements[index], current) < 0) {
return index;
}
}
return elements.length - 1;
}
protected compare(one: GModelElement, other: GModelElement): number {
let positionOne: Point | undefined = undefined;
let positionOther: Point | undefined = undefined;
if (one instanceof GEdge && isRoutable(one)) {
positionOne = calcElementAndRoute(one, this.edgeRouterRegistry).newRoutingPoints?.[0];
}
if (other instanceof GEdge && isRoutable(other)) {
positionOther = calcElementAndRoute(other, this.edgeRouterRegistry).newRoutingPoints?.[0];
}
const boundsOne = findParentByFeature(one, isSelectableAndBoundsAware);
const boundsOther = findParentByFeature(other, isSelectableAndBoundsAware);
if (positionOne === undefined && boundsOne) {
positionOne = boundsOne.bounds;
}
if (positionOther === undefined && boundsOther) {
positionOther = boundsOther.bounds;
}
if (positionOne && positionOther) {
if (positionOne.y !== positionOther.y) {
return positionOne.y - positionOther.y;
}
if (positionOne.x !== positionOther.x) {
return positionOne.x - positionOther.x;
}
}
return 0;
}
}