use of org.osate.ge.gef.DockSide in project osate2 by osate.
the class SelectedElementsMover method updateSceneGraph.
/**
* Updates the positions of scene graph nodes.
* @param totalPositionDelta the total movement since the beginning of the interaction.
* @param snapToGrid whether the positions should be snapped to grid. Ignored for connection labels.
*/
public void updateSceneGraph(final Point2D totalPositionDelta, final boolean snapToGrid) {
final Transform sceneToDiagramTransform = editor.getGefDiagram().getSceneNode().getSceneToLocalTransform();
// Reset guide
guides.reset();
// Move nodes
for (final DiagramElementSnapshot snapshot : elementsToMove) {
if (snapshot.sceneNode instanceof LabelNode) {
final BaseConnectionNode cn = InputEventHandlerUtil.getClosestConnection(snapshot.sceneNode);
// Secondary connection label
if (cn != null) {
// Determine the new position in diagram coordinates
final double newPositionX = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMinX() + totalPositionDelta.getX(), false);
final double newPositionY = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMinY() + totalPositionDelta.getY(), false);
// Set the new position relative to the midpoint
final Point2D connectionMidpointPositionInDiagram = sceneToDiagramTransform.transform(cn.getLocalToSceneTransform().transform(cn.getMidpointAnchorPosition()));
PreferredPosition.set(snapshot.sceneNode, new Point2D(newPositionX - connectionMidpointPositionInDiagram.getX(), newPositionY - connectionMidpointPositionInDiagram.getY()));
}
} else {
// Determine snapped position
double newPositionX = snapshot.positionInLocal.getX() + (InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMinX() + totalPositionDelta.getX(), snapToGrid) - snapshot.boundsInDiagram.getMinX());
double newPositionY = snapshot.positionInLocal.getY() + (InputEventHandlerUtil.snapY(editor, snapshot.boundsInDiagram.getMinY() + totalPositionDelta.getY(), snapToGrid) - snapshot.boundsInDiagram.getMinY());
// Constrain the position to the container
final Node container = InputEventHandlerUtil.getLogicalShapeContainer(snapshot.sceneNode);
if (container instanceof ContainerShape) {
final Bounds parentBounds = container.getLayoutBounds();
newPositionX = Math.max(0, Math.min(newPositionX, parentBounds.getWidth() - snapshot.boundsInDiagram.getWidth()));
newPositionY = Math.max(0, Math.min(newPositionY, parentBounds.getHeight() - snapshot.boundsInDiagram.getHeight()));
}
// Update guide overlay
if (guides.shouldUpdate()) {
guides.update(sceneToDiagramTransform.transform(snapshot.sceneNode.getLocalToSceneTransform().transform(snapshot.sceneNode.getLayoutBounds())));
}
// Adjust the position and size
final Point2D currentPreferredPosition = PreferredPosition.get(snapshot.sceneNode);
if (currentPreferredPosition == null || currentPreferredPosition.getX() != newPositionX || currentPreferredPosition.getY() != newPositionY) {
PreferredPosition.set(snapshot.sceneNode, new Point2D(newPositionX, newPositionY));
if (showAffectedConnections) {
final double dx = currentPreferredPosition == null ? 0 : (newPositionX - currentPreferredPosition.getX());
final double dy = currentPreferredPosition == null ? 0 : (newPositionY - currentPreferredPosition.getY());
shiftAffectedConnections(snapshot, dx, dy);
}
// Update side for docked shapes
if (snapshot.sceneNode instanceof DockedShape) {
final DockedShape ds = (DockedShape) snapshot.sceneNode;
if (container instanceof ContainerShape) {
final ContainerShape cs = (ContainerShape) container;
final Bounds containerBounds = cs.getLayoutBounds();
final DockSide side = GefAgeDiagramUtil.toDockSide(DockArea.fromDockingPosition(AgeDiagramUtil.determineDockingPosition(containerBounds.getWidth(), containerBounds.getHeight(), newPositionX, newPositionY, snapshot.boundsInDiagram.getWidth(), snapshot.boundsInDiagram.getHeight())));
cs.addOrUpdateDockedChild(ds, side);
}
}
}
}
}
}
use of org.osate.ge.gef.DockSide in project osate2 by osate.
the class GefAgeDiagram method updateDiagramFromSceneGraph.
/**
* Triggers a layout of the scene graph nodes and then updates the diagram based on the layout of the scene graph nodes.
* Updates position and size. Optionally updates bendpoints.
* Should only be called after the root node has been added to a scene.
* @param updateBendpoints whether to update bendpoints in addition to the position and size of elements.
*/
public void updateDiagramFromSceneGraph(final boolean updateBendpoints) {
updatingDiagramFromSceneGraph = true;
forceSceneGraphLayout();
diagram.modify("Update Diagram from Scene Graph", m -> {
for (final Entry<DiagramElement, GefDiagramElement> e : this.diagramElementToGefDiagramElementMap.entrySet()) {
final DiagramElement de = e.getKey();
final GefDiagramElement ge = e.getValue();
final Node sceneNode = ge.sceneNode;
final DiagramNode parent = de.getParent();
if (DiagramElementPredicates.isMoveable(de)) {
if (parent instanceof DiagramElement && DiagramElementPredicates.isConnection((DiagramElement) parent)) {
// Store the preferred position.
final Point2D p = PreferredPosition.get(sceneNode);
m.setPosition(de, GefAgeDiagramUtil.toAgePoint(p));
} else {
final double newX = sceneNode.getLayoutX();
final double newY = sceneNode.getLayoutY();
if (de.hasPosition() || (newX != 0.0 || newY != 0)) {
m.setPosition(de, new Point(newX, newY));
}
}
if (sceneNode instanceof DockedShape && ge.parentDiagramNodeSceneNode instanceof ContainerShape) {
final DockedShape ds = (DockedShape) sceneNode;
final DockSide side = ds.getSide();
if (side != null) {
m.setDockArea(de, GefAgeDiagramUtil.toDockArea(side));
}
}
}
// Set the size for all elements. Even for non-resizable elements, the layout engine uses the sizes in the diagram.
// This is important for secondary labels of connections.
final Bounds layoutBounds = sceneNode.getLayoutBounds();
if (de.hasSize() || (layoutBounds.getWidth() != 0.0 || layoutBounds.getHeight() != 0)) {
m.setSize(de, new Dimension(layoutBounds.getWidth(), layoutBounds.getHeight()));
}
if (DiagramElementPredicates.isConnection(de) && sceneNode instanceof BaseConnectionNode) {
final BaseConnectionNode cn = (BaseConnectionNode) sceneNode;
// Primary label position
if (!cn.getPrimaryLabels().isEmpty()) {
// Store the preferred position of the connection label
final Node primaryLabel = cn.getPrimaryLabels().get(0);
final Point2D p = PreferredPosition.get(primaryLabel);
m.setConnectionPrimaryLabelPosition(de, GefAgeDiagramUtil.toAgePoint(p));
}
// Bendpoints
if (updateBendpoints) {
final List<org.eclipse.gef.geometry.planar.Point> controlPoints = cn.getInnerConnection().getControlPoints();
if (!controlPoints.isEmpty() || !de.getBendpoints().isEmpty()) {
final Point controlPointOrigin = getControlPointOriginFromSceneGraph(sceneNode);
m.setBendpoints(de, cn.getInnerConnection().getControlPoints().stream().map(p -> new Point(p.x + controlPointOrigin.x, p.y + controlPointOrigin.y)).collect(Collectors.toList()));
}
}
}
}
});
updatingDiagramFromSceneGraph = false;
}
use of org.osate.ge.gef.DockSide in project osate2 by osate.
the class GefAgeDiagram method updateSceneNode.
/**
* Updates the scene nodes related to the specified GEF diagram element based on the diagram element.
* Only updates properties which do not effect the structure of the scene graph. Not-recursive
* @param gefDiagramElement is the GEF diagram element for which scene nodes will be updated.
*/
private void updateSceneNode(final GefDiagramElement gefDiagramElement) {
final DiagramElement diagramElement = gefDiagramElement.diagramElement;
final Node sceneNode = gefDiagramElement.sceneNode;
// Update connections
if (sceneNode instanceof BaseConnectionNode) {
final BaseConnectionNode connectionNode = (BaseConnectionNode) sceneNode;
final Point controlPointOrigin = getControlPointOriginFromDiagram(diagramElement, sceneNode);
if (sceneNode instanceof FlowIndicatorNode) {
PreferredPosition.set(sceneNode, convertPoint(diagramElement.getPosition()));
}
// Update the connection anchor
updateConnectionAnchors(diagramElement, (BaseConnectionNode) sceneNode);
// Set control points. Coordinates are specified in the diagram model relative to the diagram. The need to be specified relative to the
// connection position. For regular connection this is the same because the node's parent is the diagram node.
// However, flow indicators have a position and have parent nodes other than the diagram.
connectionNode.getInnerConnection().setControlPoints(diagramElement.getBendpoints().stream().map(p -> new org.eclipse.gef.geometry.planar.Point(p.x - controlPointOrigin.x, p.y - controlPointOrigin.y)).collect(Collectors.toList()));
PreferredPosition.set(gefDiagramElement.primaryLabel, convertPoint(diagramElement.getConnectionPrimaryLabelPosition()));
} else if (sceneNode instanceof LabelNode) {
// Such a label represents a secondary label
final LabelNode label = (LabelNode) sceneNode;
label.setText(Strings.nullToEmpty(diagramElement.getLabelName()));
setLabelVisibility(label);
// Update element position
if (gefDiagramElement.parentDiagramNodeSceneNode instanceof BaseConnectionNode) {
PreferredPosition.set(label, convertPoint(diagramElement.getPosition()));
}
} else if (sceneNode instanceof ContainerShape) {
final ContainerShape containerShape = (ContainerShape) sceneNode;
PreferredPosition.set(sceneNode, convertPoint(diagramElement.getPosition()));
// Set configured size
final Dimension size = diagramElement.getSize();
if (size == null) {
containerShape.setConfiguredWidth(ContainerShape.NOT_SPECIFIED);
containerShape.setConfiguredHeight(ContainerShape.NOT_SPECIFIED);
} else {
containerShape.setConfiguredWidth(size.width);
containerShape.setConfiguredHeight(size.height);
}
} else if (sceneNode instanceof DockedShape) {
final DockedShape n = (DockedShape) sceneNode;
PreferredPosition.set(sceneNode, convertPoint(diagramElement.getPosition()));
// Set configured size
final Dimension size = diagramElement.getSize();
if (size == null) {
n.setConfiguredWidth(ContainerShape.NOT_SPECIFIED);
n.setConfiguredHeight(ContainerShape.NOT_SPECIFIED);
} else {
n.setConfiguredWidth(size.width);
n.setConfiguredHeight(size.height);
}
final DockArea dockArea = diagramElement.getDockArea();
if (dockArea != null && dockArea != DockArea.GROUP && gefDiagramElement.parentDiagramNodeSceneNode instanceof ContainerShape) {
final DockSide side = GefAgeDiagramUtil.toDockSide(dockArea);
final ContainerShape cs = (ContainerShape) gefDiagramElement.parentDiagramNodeSceneNode;
cs.addOrUpdateDockedChild(n, side);
}
}
// Update the primary label
if (gefDiagramElement.primaryLabel != null) {
gefDiagramElement.primaryLabel.setText(getPrimaryLabelText(diagramElement));
setLabelVisibility(gefDiagramElement.primaryLabel);
gefDiagramElement.primaryLabel.setWrapText(diagramElement.getGraphicalConfiguration().isPrimaryLabelIsMultiline());
}
// Update the secondary label
if (gefDiagramElement.annotationLabel != null) {
final String annotation = diagramElement.getGraphicalConfiguration().getAnnotation();
gefDiagramElement.annotationLabel.setText(Strings.nullToEmpty(annotation));
setLabelVisibility(gefDiagramElement.annotationLabel);
}
}
use of org.osate.ge.gef.DockSide in project osate2 by osate.
the class ResizeInteraction method onMouseDragged.
@Override
protected Interaction.InteractionState onMouseDragged(final MouseEvent e) {
if (e.getButton() != MouseButton.PRIMARY) {
return super.onMouseDragged(e);
}
guides.reset();
final Transform sceneToDiagramTransform = editor.getGefDiagram().getSceneNode().getSceneToLocalTransform();
final Point2D eventInDiagram = sceneToDiagramTransform.transform(e.getSceneX(), e.getSceneY());
final Point2D totalDelta = eventInDiagram.subtract(initialClickLocationInDiagram);
final boolean snapToGrid = !e.isAltDown();
// Resize all selection diagram elements
for (final DiagramElementSnapshot snapshot : elementsToResize) {
// Determine position adjustment and new size
double newPositionX = snapshot.sceneNode.getLayoutX();
double newPositionY = snapshot.sceneNode.getLayoutY();
double newWidth = snapshot.boundsInDiagram.getWidth();
double newHeight = snapshot.boundsInDiagram.getHeight();
final Vector dir = handle.getDirection();
final Node container = InputEventHandlerUtil.getLogicalShapeContainer(snapshot.sceneNode);
//
// Determine the minimum layout X and Y values for shapes which will be repositioned during the resize.
// This value is used to constrain the new position of the node when the resize results in both a movement
// and a size change.
//
double minChildLayoutX = Double.POSITIVE_INFINITY;
double minChildLayoutY = Double.POSITIVE_INFINITY;
for (final DiagramElement childDiagramElement : snapshot.diagramElement.getChildren()) {
final Node childSceneNode = editor.getGefDiagram().getSceneNode(childDiagramElement);
if (childSceneNode instanceof ContainerShape) {
minChildLayoutX = Math.min(minChildLayoutX, childSceneNode.getLayoutX());
minChildLayoutY = Math.min(minChildLayoutY, childSceneNode.getLayoutY());
}
// Docked shapes are only repositioned in one axis.
if (childSceneNode instanceof DockedShape) {
final DockSide side = ((DockedShape) childSceneNode).getSide();
if (side.vertical) {
minChildLayoutY = Math.min(minChildLayoutY, childSceneNode.getLayoutY());
} else {
minChildLayoutX = Math.min(minChildLayoutX, childSceneNode.getLayoutX());
}
}
}
if (dir.x < 0) {
double newPositionDiagramX = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMinX() + totalDelta.getX(), snapToGrid);
// It is critical to not consider children that are being repositioned. Otherwise the minimum width
// will change as the node is resized. The layout of such children are considered to ensure that the resize
// does not clip children not included in the minimum width.
final double minWidthOfNotRepositionedChildren = snapshot.sceneNode instanceof ContainerShape ? ((ContainerShape) snapshot.sceneNode).computeMinWidth(false) : snapshot.sceneNode.minWidth(-1);
newPositionDiagramX = Math.min(newPositionDiagramX, snapshot.boundsInDiagram.getMaxX() - minWidthOfNotRepositionedChildren);
newPositionX = snapshot.positionInLocal.getX() + (newPositionDiagramX - snapshot.boundsInDiagram.getMinX());
newPositionX = Math.min(newPositionX, snapshot.sceneNode.getLayoutX() + minChildLayoutX);
if (container instanceof ContainerShape) {
newPositionX = Math.max(newPositionX, 0);
}
newWidth = snapshot.boundsInDiagram.getWidth() + (snapshot.positionInLocal.getX() - newPositionX);
} else if (dir.x > 0) {
final double newMaxX = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMaxX() + totalDelta.getX(), snapToGrid);
newWidth = newMaxX - snapshot.boundsInDiagram.getMinX();
}
if (dir.y < 0) {
double newPositionDiagramY = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMinY() + totalDelta.getY(), snapToGrid);
// It is critical to not consider children that are being repositioned. Otherwise the minimum height
// will change as the node is resized. The layout of such children are considered to ensure that the resize
// does not clip children not included in the minimum height.
final double minHeightWithoutFreeChildren = snapshot.sceneNode instanceof ContainerShape ? ((ContainerShape) snapshot.sceneNode).computeMinHeight(false) : snapshot.sceneNode.minHeight(-1);
newPositionDiagramY = Math.min(newPositionDiagramY, snapshot.boundsInDiagram.getMaxY() - minHeightWithoutFreeChildren);
newPositionY = snapshot.positionInLocal.getY() + (newPositionDiagramY - snapshot.boundsInDiagram.getMinY());
newPositionY = Math.min(newPositionY, snapshot.sceneNode.getLayoutY() + minChildLayoutY);
if (container instanceof ContainerShape) {
newPositionY = Math.max(newPositionY, 0);
}
newHeight = snapshot.boundsInDiagram.getHeight() + (snapshot.positionInLocal.getY() - newPositionY);
} else if (dir.y > 0) {
final double newMaxY = InputEventHandlerUtil.snapX(editor, snapshot.boundsInDiagram.getMaxY() + totalDelta.getY(), snapToGrid);
newHeight = newMaxY - snapshot.boundsInDiagram.getMinY();
}
// Adjust the position and size
final Point2D currentPreferredPosition = PreferredPosition.get(snapshot.sceneNode);
if (currentPreferredPosition == null || currentPreferredPosition.getX() != newPositionX || currentPreferredPosition.getY() != newPositionY) {
PreferredPosition.set(snapshot.sceneNode, new Point2D(newPositionX, newPositionY));
final double dx = currentPreferredPosition == null ? 0 : (newPositionX - currentPreferredPosition.getX());
final double dy = currentPreferredPosition == null ? 0 : (newPositionY - currentPreferredPosition.getY());
// Reposition children so that their absolute positions do not change.
for (final DiagramElement childDiagramElement : snapshot.diagramElement.getChildren()) {
final Node childSceneNode = editor.getGefDiagram().getSceneNode(childDiagramElement);
if (childSceneNode instanceof ContainerShape || childSceneNode instanceof DockedShape || childSceneNode instanceof FlowIndicatorNode) {
final Point2D childPosition = PreferredPosition.get(childSceneNode);
if (childPosition != null) {
final double newPreferredPositionX;
final double newPreferredPositionY;
// This assumes the flow indicator is attaches to a vertical side.
if (childSceneNode instanceof FlowIndicatorNode) {
newPreferredPositionX = childPosition.getX();
newPreferredPositionY = childPosition.getY() - dy;
} else {
newPreferredPositionX = childPosition.getX() - dx;
newPreferredPositionY = childPosition.getY() - dy;
}
PreferredPosition.set(childSceneNode, new Point2D(newPreferredPositionX, newPreferredPositionY));
}
}
}
}
final ConfigureSize configureSize = (ConfigureSize) snapshot.sceneNode;
final double minWidth = snapshot.sceneNode.minWidth(-1);
final double minHeight = snapshot.sceneNode.minHeight(-1);
configureSize.setConfiguredWidth(Math.max(newWidth, minWidth));
configureSize.setConfiguredHeight(Math.max(newHeight, minHeight));
// Update guide overlay
if (guides.shouldUpdate()) {
final Bounds newBoundsInDiagram = sceneToDiagramTransform.transform(snapshot.sceneNode.getLocalToSceneTransform().transform(snapshot.sceneNode.getLayoutBounds()));
// Show guides for the values in the bounds that are being changed as part of the resize
if (dir.x < 0) {
guides.updateX(newBoundsInDiagram.getMinX());
guides.updateCenterX(newBoundsInDiagram.getCenterX());
} else if (dir.x > 0) {
guides.updateX(newBoundsInDiagram.getMaxX());
guides.updateCenterX(newBoundsInDiagram.getCenterX());
}
if (dir.y < 0) {
guides.updateY(newBoundsInDiagram.getMinY());
guides.updateCenterY(newBoundsInDiagram.getCenterY());
} else if (dir.y > 0) {
guides.updateY(newBoundsInDiagram.getMaxY());
guides.updateCenterY(newBoundsInDiagram.getCenterY());
}
}
}
return InteractionState.IN_PROGRESS;
}
Aggregations