/******************************************************************************** * Copyright (c) 2024-2026 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 ********************************************************************************/ /** @jsx svg */ import { Bounds, GModelElement, IVNodePostprocessor, Point, TYPES, isDecoration, isSizeable, setClass, svg } from '@eclipse-glsp/sprotty'; import { inject, injectable, optional } from 'inversify'; import { VNode } from 'snabbdom'; import { GGraph } from '../../model'; import { BoundsAwareModelElement } from '../../utils/gmodel-util'; import { IDebugManager } from './debug-manager'; export const CSS_DEBUG_BOUNDS = 'debug-bounds'; @injectable() export class DebugBoundsDecorator implements IVNodePostprocessor { @inject(TYPES.IDebugManager) @optional() protected debugManager?: IDebugManager; decorate(vnode: VNode, element: GModelElement): VNode { if (!this.debugManager?.isDebugEnabled) { return vnode; } if (isSizeable(element) && this.shouldDecorateSizeable(element)) { this.decorateSizeable(vnode, element); } if (element instanceof GGraph && this.shouldDecorateGraph(element)) { this.decorateGraph(vnode, element); } return vnode; } postUpdate(): void {} protected get decorationSize(): number { return 5; } protected shouldDecorateGraph(graph: GGraph): boolean { return true; } protected decorateGraph(vnode: VNode, graph: GGraph): void { setClass(vnode, CSS_DEBUG_BOUNDS, true); const svgChild = vnode.children?.find(child => typeof child !== 'string' && child.sel === 'svg') as VNode | undefined; const group = svgChild?.children?.find(child => typeof child !== 'string' && child.sel === 'g') as VNode | undefined; group?.children?.push(this.renderOrigin(graph)); } protected renderOrigin(graph: GGraph): VNode { return ( Origin = x: 0, y: 0 ); } protected shouldDecorateSizeable(element: BoundsAwareModelElement): boolean { return !isDecoration(element); } protected decorateSizeable(vnode: VNode, element: BoundsAwareModelElement): void { setClass(vnode, CSS_DEBUG_BOUNDS, true); vnode.children?.push(this.renderTopLeftCorner(element)); vnode.children?.push(this.renderTopRightCorner(element)); vnode.children?.push(this.renderBottomLeftCorner(element)); vnode.children?.push(this.renderBottomRightCorner(element)); vnode.children?.push(this.renderCenter(element)); } protected renderTopLeftCorner(element: BoundsAwareModelElement): VNode { const position = Bounds.position(element.bounds); const topLeft = Bounds.topLeft(element.bounds); const corner = Point.subtract(topLeft, position); return ( Top Left = x: {topLeft.x}, y: {topLeft.y} ); } protected renderTopRightCorner(element: BoundsAwareModelElement): VNode { const position = Bounds.position(element.bounds); const topRight = Bounds.topRight(element.bounds); const corner = Point.subtract(topRight, position); return ( Top Right = x: {topRight.x}, y: {topRight.y} ); } protected renderBottomLeftCorner(element: BoundsAwareModelElement): VNode { const position = Bounds.position(element.bounds); const bottomLeft = Bounds.bottomLeft(element.bounds); const corner = Point.subtract(bottomLeft, position); return ( Bottom Left = x: {bottomLeft.x}, y: {bottomLeft.y} ); } protected renderBottomRightCorner(element: BoundsAwareModelElement): VNode { const position = Bounds.position(element.bounds); const bottomRight = Bounds.bottomRight(element.bounds); const corner = Point.subtract(bottomRight, position); return ( Bottom Right = x: {bottomRight.x}, y: {bottomRight.y} ); } protected renderCenter(element: BoundsAwareModelElement): VNode { const bounds = element.bounds; const position = Bounds.position(bounds); const center = Bounds.center(bounds); const corner = Point.subtract(center, position); return ( Center = x: {center.x}, y: {center.y} Bounds = x: {bounds.x}, y: {bounds.y}, width: {bounds.width}, height: {bounds.height} ); } }