devexpress-diagram
Version:
DevExpress Diagram Control
168 lines (157 loc) • 7.7 kB
text/typescript
import { Point } from "@devexpress/utils/lib/geometry/point";
import { History } from "../../History/History";
import { Connector } from "../../Model/Connectors/Connector";
import { ConnectorRenderPointsContext } from "../../Model/Connectors/Routing/ConnectorRenderPointsContext";
import { ItemKey } from "../../Model/DiagramItem";
import { DiagramModel } from "../../Model/Model";
import { ModelUtils } from "../../Model/ModelUtils";
import { Shape } from "../../Model/Shapes/Shape";
import { DiagramModelOperation } from "../../ModelOperationSettings";
import { Selection } from "../../Selection/Selection";
import { DiagramMouseEvent, MouseButton, MouseEventElementType } from "../Event";
import { MouseHandler } from "../MouseHandler";
import { IVisualizerManager } from "../Visualizers/VisualizersManager";
import { MouseHandlerDraggingState } from "./MouseHandlerDraggingState";
import { SelectionDragHelper } from "../../Model/Helpers/DragHelper";
export class DraggingConnector {
readonly startPoints: Point[];
readonly startRenderContext: ConnectorRenderPointsContext | undefined;
constructor(readonly connector: Connector) {
this.startPoints = connector.points.map(x => x.clone());
this.startRenderContext = connector.tryCreateRenderPointsContext();
}
}
export abstract class MouseHandlerDragDiagramItemStateBase extends MouseHandlerDraggingState {
private fixedX: boolean;
private fixedY: boolean;
private lockInitDrag: boolean;
dragHelper: SelectionDragHelper;
startPoint: Point;
startScrollLeft = 0;
startScrollTop = 0;
shouldClone: boolean;
protected constructor(handler: MouseHandler, history: History,
protected model: DiagramModel,
protected selection: Selection,
protected visualizerManager: IVisualizerManager) {
super(handler, history);
}
protected abstract get areValidDraggingShapes(): boolean;
protected abstract get areValidDraggingConnectors(): boolean;
finish(): void {
this.dragHelper?.finish();
this.visualizerManager.resetExtensionLines();
this.visualizerManager.resetContainerTarget();
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
super.finish();
}
onMouseDown(evt: DiagramMouseEvent): void {
this.handler.addDiagramItemToSelection(evt);
this.shouldClone = this.handler.canCopySelectedItems(evt);
this.startPoint = evt.modelPoint;
this.initDrag();
this.lockInitDrag = false;
super.onMouseDown(evt);
}
onMouseMove(evt: DiagramMouseEvent): void {
this.mouseMoveEvent = evt;
if(evt.button !== MouseButton.Left) {
this.cancelChanges();
this.handler.switchToDefaultState();
return;
}
if(!this.canApplyChangesOnMouseMove(this.startPoint, evt.modelPoint))
return;
if(this.handler.canCopySelectedItems(evt))
if(!this.lockInitDrag) {
this.cancelChanges();
this.shouldClone = true;
this.copySelection();
this.initDrag();
this.lockInitDrag = true;
}
this.onApplyChanges(evt);
this.onAfterApplyChanges();
this.updateContainers(evt);
}
private updateContainers(evt: DiagramMouseEvent) : void {
this.visualizerManager.setExtensionLines(this.selection.getSelectedShapes(false, true));
const container = ModelUtils.findContainerByEventKey(this.model, this.selection, evt.source.key);
if(container && this.allowInsertToContainer(evt, container))
this.visualizerManager.setContainerTarget(container, evt.source.type);
else
this.visualizerManager.resetContainerTarget();
}
onMouseUp(evt: DiagramMouseEvent) : void {
super.onMouseUp(evt);
if(this.handler.canRemoveDiagramItemToSelection(evt) && this.handler.canMultipleSelection(evt))
this.handler.removeDiagramItemFromSelection(evt.button, evt.source.key);
}
onApplyChanges(evt: DiagramMouseEvent): void {
this.calculateFixedPosition(evt);
this.dragHelper.move(this.shouldClone, (pt) => this.getSnappedPoint(evt, pt), () => {
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
},
(shape, connectionPointIndex) => {
this.visualizerManager.setConnectionTarget(shape, MouseEventElementType.Shape);
this.visualizerManager.setConnectionPoints(shape, MouseEventElementType.Shape, connectionPointIndex, true);
});
const container = ModelUtils.findContainerByEventKey(this.model, this.selection, evt.source.key);
if(container && this.allowInsertToContainer(evt, container))
ModelUtils.insertSelectionToContainer(this.history, this.model, this.selection, container);
else
ModelUtils.removeSelectionFromContainer(this.history, this.model, this.selection);
this.handler.tryUpdateModelSize((offsetLeft, offsetTop) => this.dragHelper.onTryUpdateModelSize(offsetLeft, offsetTop));
}
getDraggingElementKeys(): ItemKey[] {
return this.dragHelper.draggingShapes.map(x => x.shape.key).concat(this.dragHelper.draggingConnectors.map(x => x.connector.key));
}
getSnappedPoint(evt: DiagramMouseEvent, point: Point): Point {
return this.handler.getSnappedPointOnDragDiagramItem(evt, point, this.fixedX, this.fixedY, this.startPoint);
}
private initDrag() : void {
this.dragHelper = new SelectionDragHelper(this.history, this.model, this.handler.permissionsProvider, this.startPoint, this.selection.getSelectedItems(true));
this.initDraggingShapes();
if(!this.areValidDraggingShapes) {
this.handler.switchToDefaultState();
return;
}
this.initDraggingConnectors();
if(!this.areValidDraggingConnectors) {
this.handler.switchToDefaultState();
return;
}
}
private initDraggingShapes() {
this.dragHelper.initDraggingShapes(this.selection.getSelectedShapes(false, true), this.shouldClone);
}
private initDraggingConnectors(): void {
this.dragHelper.initDraggingConnectors(this.selection.getSelectedConnectors(false, true), this.shouldClone);
}
private copySelection() : void {
ModelUtils.cloneSelectionToOffset(this.history, this.model, (key: ItemKey) => {
const item = this.model.findItem(key);
if(item)
this.handler.addInteractingItem(item, DiagramModelOperation.AddShape);
}, this.selection, 0, 0);
}
private calculateFixedPosition(evt: DiagramMouseEvent) {
this.fixedX = false;
this.fixedY = false;
if(this.handler.canCalculateFixedPosition(evt)) {
const dx = Math.abs(this.startPoint.x - evt.modelPoint.x);
const dy = Math.abs(this.startPoint.y - evt.modelPoint.y);
if(dx < dy)
this.fixedX = true;
else
this.fixedY = true;
}
}
private allowInsertToContainer(evt: DiagramMouseEvent, container: Shape): boolean {
if(this.handler.canMultipleSelection(evt))
return false;
return container && container.expanded && ModelUtils.canInsertSelectionToContainer(this.model, this.selection, container);
}
}