Search in sources :

Example 1 with DockedShape

use of org.osate.ge.gef.DockedShape 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);
                    }
                }
            }
        }
    }
}
Also used : LabelNode(org.osate.ge.gef.LabelNode) DockSide(org.osate.ge.gef.DockSide) Point2D(javafx.geometry.Point2D) LabelNode(org.osate.ge.gef.LabelNode) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) Node(javafx.scene.Node) ConnectionNode(org.osate.ge.gef.ConnectionNode) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) Bounds(javafx.geometry.Bounds) DockedShape(org.osate.ge.gef.DockedShape) ContainerShape(org.osate.ge.gef.ContainerShape) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) Transform(javafx.scene.transform.Transform)

Example 2 with DockedShape

use of org.osate.ge.gef.DockedShape in project osate2 by osate.

the class GefAgeDiagram method ensureSceneNodeExists.

/**
 * Ensures that a scene node exists for the specified GEF diagram element.
 * Creates or recreates scene nodes and adds to the scene graph as necessary. Updates the specified GEF diagram element.
 * @param gefDiagramElement the GEF diagram element for which to ensure that the scene node exists.
 * @param parentDiagramElementSceneNode the scene node for the parent of the GEF diagram element. This is specified instead of using
 * the value contained in the GEF diagram element because it may not be up to date.
 * @return the scene node for the diagram element. This specified GEF diagram element will be updated to hold this value.
 */
private Node ensureSceneNodeExists(GefDiagramElement gefDiagramElement, final Node parentDiagramElementSceneNode) {
    Objects.requireNonNull(parentDiagramElementSceneNode, "parentDiagramElementScenenNode must not be null");
    final Graphic graphic = Objects.requireNonNull(gefDiagramElement.diagramElement.getGraphic(), "graphic must not be null");
    final DiagramElement childDiagramElement = gefDiagramElement.diagramElement;
    // 
    // The following final variables determine the operations that needs to be performed by the remainder of the function.
    // They are set by comparing the previous state with the current state of the diagram element.
    // 
    final boolean docked = childDiagramElement.getDockArea() != null;
    final boolean parentIsConnection = parentDiagramElementSceneNode instanceof BaseConnectionNode;
    final boolean create = !Objects.equals(graphic, gefDiagramElement.sourceGraphic) || docked != gefDiagramElement.sceneNode instanceof DockedShape || parentIsConnection != gefDiagramElement.parentDiagramNodeSceneNode instanceof BaseConnectionNode;
    final boolean addToScene = create || gefDiagramElement.parentDiagramNodeSceneNode != parentDiagramElementSceneNode;
    final boolean removeFromScene = addToScene && gefDiagramElement.sceneNode != null;
    // Update other fields
    gefDiagramElement.sourceGraphic = graphic;
    // Remove the node for the scene graph
    if (removeFromScene) {
        removeNode(gefDiagramElement.sceneNode);
    }
    // 
    if (create) {
        // Remove mapping to old scene node
        if (gefDiagramElement.sceneNode != null) {
            sceneNodeToGefDiagramElementMap.remove(gefDiagramElement.sceneNode);
        }
        // Create the new node. Create a graphic and then a wrapper as appropriate
        final Node graphicNode = GraphicToFx.createNode(graphic);
        if (graphicNode instanceof BaseConnectionNode) {
            final BaseConnectionNode newConnectionNode = (BaseConnectionNode) graphicNode;
            gefDiagramElement.sceneNode = graphicNode;
            // Create the primary label node
            final LabelNode primaryLabel = new LabelNode();
            newConnectionNode.getPrimaryLabels().add(primaryLabel);
            gefDiagramElement.primaryLabel = primaryLabel;
        } else if (graphicNode instanceof LabelNode) {
            gefDiagramElement.sceneNode = graphicNode;
        } else if (parentIsConnection) {
            // NOTE: This should only occur for fixed sized graphics
            // Rotate midpoint decorations 180.0 degrees because our connection not expects midpoint decorations to be oriented as if
            // the connection was left to right and that is not how graphics are specified in the graphical editor.
            final Group rotationWrapper = new Group();
            rotationWrapper.getChildren().add(graphicNode);
            rotationWrapper.setRotate(180.0);
            gefDiagramElement.sceneNode = rotationWrapper;
        } else {
            if (docked) {
                final DockedShape newDockedShape = new DockedShape();
                newDockedShape.setGraphic(graphicNode);
                gefDiagramElement.sceneNode = newDockedShape;
                // Create the primary label node
                final LabelNode primaryLabel = new LabelNode();
                newDockedShape.getPrimaryLabels().add(primaryLabel);
                gefDiagramElement.primaryLabel = primaryLabel;
                // Create annotation node
                final LabelNode annotationLabel = new LabelNode();
                newDockedShape.getSecondaryLabels().add(annotationLabel);
                gefDiagramElement.annotationLabel = annotationLabel;
            } else {
                final ContainerShape newContainerShape = new ContainerShape();
                newContainerShape.setGraphic(graphicNode);
                gefDiagramElement.sceneNode = newContainerShape;
                // Create the primary label node
                final LabelNode primaryLabel = new LabelNode();
                newContainerShape.getPrimaryLabels().add(primaryLabel);
                gefDiagramElement.primaryLabel = primaryLabel;
            }
        }
        // Add mapping to scene node
        if (gefDiagramElement.sceneNode != null) {
            sceneNodeToGefDiagramElementMap.put(gefDiagramElement.sceneNode, gefDiagramElement);
        }
        StyleRoot.set(gefDiagramElement.sceneNode, true);
    }
    // 
    if (addToScene) {
        if (gefDiagramElement.sceneNode instanceof BaseConnectionNode) {
            diagramNode.getChildren().add(gefDiagramElement.sceneNode);
            // Flow indicators are positioned relative to the scene node of the parent diagram element
            if (gefDiagramElement.sceneNode instanceof FlowIndicatorNode) {
                if (parentDiagramElementSceneNode instanceof ContainerShape) {
                    ((FlowIndicatorNode) gefDiagramElement.sceneNode).setPositioningReference(parentDiagramElementSceneNode);
                } else {
                    throw new AgeGefRuntimeException("Unexpected parent diagram element scene node for flow indicator: " + parentDiagramElementSceneNode);
                }
            }
        } else if (gefDiagramElement.sceneNode instanceof LabelNode) {
            // Add label to parent
            if (parentDiagramElementSceneNode instanceof ContainerShape) {
                ((ContainerShape) parentDiagramElementSceneNode).getSecondaryLabels().add(gefDiagramElement.sceneNode);
            } else if (parentDiagramElementSceneNode instanceof DockedShape) {
                ((DockedShape) parentDiagramElementSceneNode).getSecondaryLabels().add(gefDiagramElement.sceneNode);
            } else if (parentDiagramElementSceneNode instanceof BaseConnectionNode) {
                ((BaseConnectionNode) parentDiagramElementSceneNode).getSecondaryLabels().add(gefDiagramElement.sceneNode);
            } else {
                throw new AgeGefRuntimeException("Unexpected parent node for label: " + parentDiagramElementSceneNode);
            }
        } else if (parentIsConnection) {
            ((BaseConnectionNode) parentDiagramElementSceneNode).getMidpointDecorations().add(gefDiagramElement.sceneNode);
        } else {
            final DockArea dockArea = childDiagramElement.getDockArea();
            if (gefDiagramElement.sceneNode instanceof DockedShape) {
                final DockedShape dockedShape = (DockedShape) gefDiagramElement.sceneNode;
                // Add the docked shape to the appropriate list
                if (parentDiagramElementSceneNode instanceof ContainerShape) {
                    final ContainerShape containerShapeParent = (ContainerShape) parentDiagramElementSceneNode;
                    containerShapeParent.addOrUpdateDockedChild(dockedShape, GefAgeDiagramUtil.toDockSide(dockArea));
                } else if (parentDiagramElementSceneNode instanceof DockedShape) {
                    final DockedShape dockedShapeParent = (DockedShape) parentDiagramElementSceneNode;
                    dockedShapeParent.getNestedChildren().add(dockedShape);
                } else {
                    throw new AgeGefRuntimeException("Unexpected parent for docked shape: " + parentDiagramElementSceneNode);
                }
            } else {
                if (parentDiagramElementSceneNode instanceof ContainerShape) {
                    final ContainerShape containerShapeParent = (ContainerShape) parentDiagramElementSceneNode;
                    containerShapeParent.getFreeChildren().add(gefDiagramElement.sceneNode);
                } else if (parentDiagramElementSceneNode instanceof Group) {
                    ((Group) parentDiagramElementSceneNode).getChildren().add(gefDiagramElement.sceneNode);
                } else {
                    throw new AgeGefRuntimeException("Unexpected parent node for container shape: " + parentDiagramElementSceneNode);
                }
            }
        }
        gefDiagramElement.parentDiagramNodeSceneNode = parentDiagramElementSceneNode;
    }
    return gefDiagramElement.sceneNode;
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) LabelNode(org.osate.ge.gef.LabelNode) Group(javafx.scene.Group) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) Graphic(org.osate.ge.graphics.Graphic) FeatureGraphic(org.osate.ge.graphics.internal.FeatureGraphic) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) DockedShape(org.osate.ge.gef.DockedShape) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) DiagramRootNode(org.osate.ge.gef.DiagramRootNode) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) FeatureGroupNode(org.osate.ge.gef.FeatureGroupNode) LabelNode(org.osate.ge.gef.LabelNode) Node(javafx.scene.Node) ConnectionNode(org.osate.ge.gef.ConnectionNode) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) ContainerShape(org.osate.ge.gef.ContainerShape) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) AgeGefRuntimeException(org.osate.ge.gef.AgeGefRuntimeException)

Example 3 with DockedShape

use of org.osate.ge.gef.DockedShape 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;
}
Also used : DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) DiagramRootNode(org.osate.ge.gef.DiagramRootNode) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) FeatureGroupNode(org.osate.ge.gef.FeatureGroupNode) LabelNode(org.osate.ge.gef.LabelNode) Node(javafx.scene.Node) ConnectionNode(org.osate.ge.gef.ConnectionNode) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) DockedShape(org.osate.ge.gef.DockedShape) Bounds(javafx.geometry.Bounds) Point(org.osate.ge.graphics.Point) Dimension(org.osate.ge.graphics.Dimension) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) DockSide(org.osate.ge.gef.DockSide) Point2D(javafx.geometry.Point2D) ContainerShape(org.osate.ge.gef.ContainerShape) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode)

Example 4 with DockedShape

use of org.osate.ge.gef.DockedShape 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);
    }
}
Also used : LabelNode(org.osate.ge.gef.LabelNode) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode) DiagramRootNode(org.osate.ge.gef.DiagramRootNode) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) FeatureGroupNode(org.osate.ge.gef.FeatureGroupNode) LabelNode(org.osate.ge.gef.LabelNode) Node(javafx.scene.Node) ConnectionNode(org.osate.ge.gef.ConnectionNode) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) DockedShape(org.osate.ge.gef.DockedShape) Point(org.osate.ge.graphics.Point) Dimension(org.osate.ge.graphics.Dimension) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) DockSide(org.osate.ge.gef.DockSide) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) ContainerShape(org.osate.ge.gef.ContainerShape) BaseConnectionNode(org.osate.ge.gef.BaseConnectionNode)

Example 5 with DockedShape

use of org.osate.ge.gef.DockedShape 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;
}
Also used : Node(javafx.scene.Node) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) DockedShape(org.osate.ge.gef.DockedShape) Bounds(javafx.geometry.Bounds) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) FlowIndicatorNode(org.osate.ge.gef.FlowIndicatorNode) DockSide(org.osate.ge.gef.DockSide) Point2D(javafx.geometry.Point2D) ContainerShape(org.osate.ge.gef.ContainerShape) ConfigureSize(org.osate.ge.gef.ConfigureSize) Transform(javafx.scene.transform.Transform) Vector(org.eclipse.gef.geometry.euclidean.Vector)

Aggregations

Node (javafx.scene.Node)6 ContainerShape (org.osate.ge.gef.ContainerShape)6 DockedShape (org.osate.ge.gef.DockedShape)6 BaseConnectionNode (org.osate.ge.gef.BaseConnectionNode)5 FlowIndicatorNode (org.osate.ge.gef.FlowIndicatorNode)5 LabelNode (org.osate.ge.gef.LabelNode)5 DiagramElement (org.osate.ge.internal.diagram.runtime.DiagramElement)5 ConnectionNode (org.osate.ge.gef.ConnectionNode)4 DockSide (org.osate.ge.gef.DockSide)4 DiagramNode (org.osate.ge.internal.diagram.runtime.DiagramNode)4 Bounds (javafx.geometry.Bounds)3 Point2D (javafx.geometry.Point2D)3 DiagramRootNode (org.osate.ge.gef.DiagramRootNode)3 FeatureGroupNode (org.osate.ge.gef.FeatureGroupNode)3 Transform (javafx.scene.transform.Transform)2 Dimension (org.osate.ge.graphics.Dimension)2 Point (org.osate.ge.graphics.Point)2 DockArea (org.osate.ge.internal.diagram.runtime.DockArea)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 Group (javafx.scene.Group)1