use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.
the class ElkGraphBuilder method createPort.
/**
* @param parent
* @param side
* @param dockedElement
* @param portBorderOffset additional offset from the border. Used to set the ELK port border offset for nested ports.
* @param mapping
* @return
*/
private ElkPort createPort(final ElkNode parent, final PortSide side, final DiagramElement dockedElement, final double portBorderOffset, final LayoutMapping mapping) {
final List<DiagramElement> dockedChildren = getDockedChildren(dockedElement);
final Dimension untransformedGraphicSize = layoutInfoProvider.getPortGraphicSize(dockedElement);
final Dimension transformedGraphicSize = transformDimension(untransformedGraphicSize, side);
final Dimension untransformedLabelsSize = layoutInfoProvider.getDockedElementLabelsSize(dockedElement);
final Dimension transformedLabelsSize = transformDimension(untransformedLabelsSize, side);
// Create child ports and sort them by the size of the dimension parallel to the docked side
final List<ElkPort> childPorts = dockedChildren.stream().map(ce -> createPort(parent, side, ce, getOrthogonalSize(transformedGraphicSize, side), mapping)).sorted((p1, p2) -> Double.compare(getSize(p1, side), getSize(p1, side))).collect(Collectors.toCollection(ArrayList::new));
// If the port has child ports, then we assume it is a feature group.
// The child ports are split into two bins and positioned such that they do not overlap the center of the feature group.
// The parent port will be sized accordingly.
final double maxChildBinSize;
if (childPorts.size() > 0) {
// Split the ports into two lists which have roughly equal heights/widths(depending on the docked side)
double[] binSize = { 0.0, 0.0 };
@SuppressWarnings("unchecked") final List<ElkPort>[] binLists = new ArrayList[] { new ArrayList<>(), new ArrayList<>() };
for (final ElkPort childPort : childPorts) {
final double size = getSize(childPort, side);
final int binIndex = binSize[0] <= binSize[1] ? 0 : 1;
binLists[binIndex].add(childPort);
binSize[binIndex] += size + paddingSize;
}
// Determine the total size of the feature
maxChildBinSize = Math.max(binSize[0], binSize[1]);
// Set the position of the port relative to its parent because the size and position of the parent will be selected after its children are sized.
for (int i = 0; i < 2; i++) {
double childPosition = transformedLabelsSize.height + i * (maxChildBinSize + transformedGraphicSize.height);
for (final ElkPort childPort : binLists[i]) {
setPositionAlongSide(childPort, side, childPosition);
childPosition += getSize(childPort, side) + paddingSize;
}
}
} else {
maxChildBinSize = 0.0;
}
// Size the parent port based on the bin size.
final double newGraphicSize = 2.0 * maxChildBinSize + transformedGraphicSize.height;
final double totalSize = transformedLabelsSize.height + newGraphicSize;
final ElkPort newPort = ElkGraphUtil.createPort(parent);
mapping.getGraphMap().put(newPort, dockedElement);
newPort.setProperty(CoreOptions.PORT_SIDE, side);
// Determine max orthogonal size of children
double maxChildOrthogonalSize = 0;
for (final ElkPort childPort : childPorts) {
maxChildOrthogonalSize = Math.max(maxChildOrthogonalSize, getOrthogonalSize(childPort, side));
}
// Determine size and position
final Dimension newSize;
if (DiagramElementPredicates.isResizeable(dockedElement)) {
newSize = new Dimension(Math.max(untransformedLabelsSize.width, maxChildOrthogonalSize + getOrthogonalSize(transformedGraphicSize, side)), totalSize);
} else {
newSize = new Dimension(Math.max(untransformedLabelsSize.width, untransformedGraphicSize.width), transformedLabelsSize.height + untransformedGraphicSize.height);
}
// final graph.
if (omitNestedPorts) {
for (final ElkPort childPort : childPorts) {
mapping.getGraphMap().remove(childPort);
EcoreUtil.remove(childPort);
}
}
final Dimension transformedNewSize = transformDimension(newSize, side);
newPort.setWidth(transformedNewSize.width);
newPort.setHeight(transformedNewSize.height);
// Set port border offset
if (PortSide.SIDES_NORTH_SOUTH.contains(side)) {
newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getHeight() - portBorderOffset);
} else {
newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getWidth() - portBorderOffset);
}
// Set the port anchor based on where the actual graphic will be.
final Dimension transformedPortAnchor = transformDimension(new Dimension(untransformedGraphicSize.width / 2, transformedLabelsSize.height + maxChildBinSize + untransformedGraphicSize.height / 2.0), side);
newPort.setProperty(CoreOptions.PORT_ANCHOR, new KVector(transformedPortAnchor.width, transformedPortAnchor.height));
return newPort;
}
use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.
the class ElkGraphBuilder method addPositionOffsets.
/**
* Adds position offset along axis for the specified port, graphic port, and children
* @param de
* @param offset
* @param side
* @param mapping
*/
private void addPositionOffsets(final DiagramElement de, final double offset, final PortSide side, final LayoutMapping mapping) {
final ElkPort childPort = (ElkPort) mapping.getGraphMap().inverse().get(de);
final double newPosition = addPositionOffset(childPort, side, offset);
// Only attempt to update child ports if nested ports are not being omitted.
if (!omitNestedPorts) {
de.getChildren().stream().filter(child -> child.getGraphic() instanceof AgeShape && !(child.getGraphic() instanceof Label) && child.getDockArea() != null).forEach(childDiagramElement -> addPositionOffsets(childDiagramElement, newPosition, side, mapping));
}
}
use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.
the class ElkGraphBuilder method createAndPositionPorts.
// Create and position ports for an elk node
private void createAndPositionPorts(final ElkNode parentNode, final List<DiagramElement> dockedDiagramElements, final PortSide side, final double additionalPadding, final LayoutMapping mapping, final boolean parentHasNestedPorts) {
// Create and position ports
double position = paddingSize + additionalPadding;
double maxPosition = position;
for (final DiagramElement dockedElement : dockedDiagramElements) {
final ElkPort newPort = createPort(parentNode, side, dockedElement, 0, mapping);
// Determine if the position has been provided by the fixed port position provider
if (parentHasNestedPorts) {
final Double overridePosition = fixedPortPositionProvider.getPortPosition(dockedElement);
if (overridePosition != null) {
position = overridePosition;
}
}
setPositionAlongSide(newPort, side, position);
addPositionOffsets((DiagramElement) mapping.getGraphMap().get(newPort), 0.0, side, mapping);
position += getSize(newPort, side) + paddingSize;
// The max position may not always be increasing because the fixed port position provider may override the position.
maxPosition = Math.max(maxPosition, position);
}
// Additional padding
maxPosition += 5;
if (parentHasNestedPorts) {
// Create a dummy port so that the last port on the side will have the minimum padding
final ElkPort newPort = ElkGraphUtil.createPort(parentNode);
newPort.setProperty(CoreOptions.PORT_SIDE, side);
newPort.setY(maxPosition);
newPort.setWidth(0);
newPort.setHeight(0);
}
}
use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.
the class ElkGraphBuilder method createElkGraphElementsForConnections.
/**
* Creates ELK edges for connection diagram nodes which are descendants of the specified node.
* Even though the results of the ELK edge routing are not used, it is still important because it affects the placements of shapes.
*/
private void createElkGraphElementsForConnections(final DiagramNode dn, final LayoutMapping mapping) {
for (final DiagramElement de : dn.getChildren()) {
if (de.getGraphic() instanceof AgeConnection) {
final AgeConnection connection = (AgeConnection) de.getGraphic();
// Flow indicators are represented by a node in the container which has a port and an edge connecting that port to the starting element
final ElkConnectableShape edgeStart = getConnectableShape(de.getStartElement(), mapping);
ElkConnectableShape edgeEnd = null;
if (connection.isFlowIndicator) {
// Find the first undocked ancestor for the flow indicator
final DiagramElement undockedContainer = DiagramElementUtil.getUndockedDiagramElement(de.getParent());
if (undockedContainer == null) {
// Ignore the flow indicator if unable to find a containing element which isn't docked.
continue;
}
// Find the ELK shape for the ancestor
final ElkConnectableShape endContainer = getConnectableShape(undockedContainer, mapping);
if (!(endContainer instanceof ElkNode)) {
// Ignore the flow indicator if the container isn't a node.
continue;
}
// Create the node for the end of the flow indicator
final ElkNode endNode = ElkGraphUtil.createNode((ElkNode) endContainer);
endContainer.setDimensions(0, 0);
endNode.setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, EnumSet.noneOf(SizeConstraint.class));
endNode.setProperty(CoreOptions.NODE_SIZE_OPTIONS, EnumSet.noneOf(SizeOptions.class));
// Create port
final ElkPort endPort = ElkGraphUtil.createPort(endNode);
endPort.setProperty(CoreOptions.PORT_SIDE, PortSide.WEST);
endPort.setX(0);
endPort.setY(0);
endPort.setWidth(0);
endPort.setHeight(0);
edgeEnd = endPort;
} else {
edgeEnd = getConnectableShape(de.getEndElement(), mapping);
}
if (edgeStart != null && edgeEnd != null) {
final ElkConnectableShape start = edgeStart;
final ElkConnectableShape end = edgeEnd;
boolean insideSelfLoopsYo = true;
// An example of this sort of edge is a steady state state transition in the EMV2
if (start == end) {
insideSelfLoopsYo = false;
}
final ElkEdge newEdge = ElkGraphUtil.createSimpleEdge(start, end);
// Allow edges with the same start and end shape because they layout as intended.
if (start == end && start instanceof ElkPort) {
continue;
}
// Ensure the edge has at least one section. Fixes NPE that can occur when laying out connections
// with the same source and destination port.
ElkGraphUtil.createEdgeSection(newEdge);
newEdge.setProperty(CoreOptions.INSIDE_SELF_LOOPS_YO, insideSelfLoopsYo);
mapping.getGraphMap().put(newEdge, de);
createElkLabels(de, newEdge, mapping);
// along with other edges
if (connection.isFlowIndicator && newEdge.getLabels().isEmpty()) {
final ElkLabel spacingLabel = createElkLabel(newEdge, "<Spacing>", new Dimension(10, 10));
if (!layoutConnectionLabels) {
spacingLabel.setProperty(CoreOptions.NO_LAYOUT, true);
}
}
}
}
createElkGraphElementsForConnections(de, mapping);
}
}
use of org.eclipse.elk.graph.ElkPort in project glsp-server by eclipse-glsp.
the class ElkLayoutEngine method processChildren.
/*
* Transform the children of a sprotty model element to their ELK graph
* counterparts.
*/
@SuppressWarnings({ "checkstyle:CyclomaticComplexity", "checkstyle:NestedIfDepth" })
protected int processChildren(final GModelElement sParent, final ElkGraphElement elkParent, final LayoutContext context) {
int childrenCount = 0;
if (sParent.getChildren() != null) {
for (GModelElement schild : sParent.getChildren()) {
context.parentMap.put(schild, sParent);
ElkGraphElement elkChild = null;
if (shouldInclude(schild, sParent, elkParent, context)) {
if (schild instanceof GNode) {
GNode snode = (GNode) schild;
ElkNode elkNode = createNode(snode);
if (elkParent instanceof ElkNode) {
elkNode.setParent((ElkNode) elkParent);
childrenCount++;
}
context.shapeMap.put(snode, elkNode);
elkChild = elkNode;
} else if (schild instanceof GPort) {
GPort gport = (GPort) schild;
ElkPort elkPort = createPort(gport);
if (elkParent instanceof ElkNode) {
elkPort.setParent((ElkNode) elkParent);
childrenCount++;
}
context.shapeMap.put(gport, elkPort);
elkChild = elkPort;
} else if (schild instanceof GEdge) {
GEdge gedge = (GEdge) schild;
ElkEdge elkEdge = createEdge(gedge);
// The most suitable container for the edge is determined later
childrenCount++;
context.edgeMap.put(gedge, elkEdge);
elkChild = elkEdge;
} else if (schild instanceof GLabel) {
GLabel glabel = (GLabel) schild;
ElkLabel elkLabel = createLabel(glabel);
elkLabel.setParent(elkParent);
childrenCount++;
context.shapeMap.put(glabel, elkLabel);
elkChild = elkLabel;
}
}
int grandChildrenCount = processChildren(schild, elkChild != null ? elkChild : elkParent, context);
childrenCount += grandChildrenCount;
if (grandChildrenCount > 0 && sParent instanceof GLayouting && schild instanceof GBoundsAware) {
handleClientLayout((GBoundsAware) schild, (GLayouting) sParent, elkParent, context);
}
}
}
return childrenCount;
}
Aggregations