Skip to content

Commit

Permalink
[1071] Support the border node label display
Browse files Browse the repository at this point in the history
The auto layout uses the CoreOptions.PORT_LABELS_PLACEMENT with the
value PortLabelPlacement.outside(). It means that the label is
positioned on a corner of the border node without entering the parent
node.
The incremental layout uses, for the border nodes label, the same
policy. It is applied when the border node is moved on its container and
when it is newly created.

Bug: #1071
Signed-off-by: Laurent Fasani <[email protected]>
  • Loading branch information
lfasani authored and sbegaudeau committed Mar 7, 2022
1 parent c7ac914 commit 9930786
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
- https://github.com/eclipse-sirius/sirius-components/issues/1081[#1081] [workbench] It is now possible to specify the component to display in the main area when no representation is open instead of the `OnboardArea` (which is still the default when there is no override)
- https://github.com/eclipse-sirius/sirius-components/issues/1070[#1070] [explorer] When selecting an element or opening a representation (for example from its URL or from the onboard area), it is automatically made visible and selected in the explorer.
- https://github.com/eclipse-sirius/sirius-components/issues/919[#919] [diagram] Support the parent container resize for the border nodes on back-end
- https://github.com/eclipse-sirius/sirius-components/issues/1071[#1071] [diagram] Add a label for the border nodes.

=== New features

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Obeo.
* Copyright (c) 2019, 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -355,8 +355,8 @@ private void convertBorderNode(Node borderNode, ElkNode elkNode, Map<String, Elk
elkPort.setProperty(PROPERTY_TYPE, borderNode.getType());

TextBounds textBounds = this.textBoundsService.getBounds(borderNode.getLabel());
double width = Math.max(textBounds.getSize().getWidth(), borderNode.getSize().getWidth());
double height = Math.max(textBounds.getSize().getHeight(), borderNode.getSize().getHeight());
double width = borderNode.getSize().getWidth();
double height = borderNode.getSize().getHeight();

elkPort.setDimensions(width, height);
elkPort.setParent(elkNode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.elk.core.options.FixedLayouterOptions;
import org.eclipse.elk.core.options.HierarchyHandling;
import org.eclipse.elk.core.options.NodeLabelPlacement;
import org.eclipse.elk.core.options.PortLabelPlacement;
import org.eclipse.elk.core.options.SizeConstraint;
import org.eclipse.elk.core.options.SizeOptions;
import org.eclipse.elk.graph.ElkEdge;
Expand Down Expand Up @@ -96,7 +97,8 @@ public ISiriusWebLayoutConfigurator getDefaultLayoutConfigurator() {
.setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(LayoutOptionValues.MIN_WIDTH_CONSTRAINT, LayoutOptionValues.MIN_HEIGHT_CONSTRAINT))
.setProperty(CoreOptions.NODE_LABELS_PLACEMENT, NodeLabelPlacement.insideTopCenter())
.setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(MIN_WIDTH_CONSTRAINT, MIN_HEIGHT_CONSTRAINT))
.setProperty(CoreOptions.PORT_BORDER_OFFSET, DEFAULT_PORT_BORDER_OFFSET);
.setProperty(CoreOptions.PORT_BORDER_OFFSET, DEFAULT_PORT_BORDER_OFFSET)
.setProperty(CoreOptions.PORT_LABELS_PLACEMENT, PortLabelPlacement.outside());

configurator.configureByType(NodeType.NODE_LIST)
.setProperty(CoreOptions.ALGORITHM, FixedLayouterOptions.ALGORITHM_ID)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.diagrams.layout.incremental;

import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.components.diagrams.layout.incremental.data.NodeLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.utils.RectangleSide;

/**
* Class representing border node on a parent side.
*
* @author lfasani
*/
public class BorderNodesOnSide {

private final List<NodeLayoutData> borderNodes;

private final RectangleSide side;

BorderNodesOnSide(RectangleSide side, List<NodeLayoutData> borderNodes) {
this.side = Objects.requireNonNull(side);
this.borderNodes = Objects.requireNonNull(borderNodes);
}

public List<NodeLayoutData> getBorderNodes() {
return this.borderNodes;
}

public RectangleSide getSide() {
return this.side;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.elk.core.options.CoreOptions;
import org.eclipse.sirius.components.diagrams.Position;
Expand All @@ -34,6 +34,7 @@
import org.eclipse.sirius.components.diagrams.layout.incremental.data.EdgeLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.IContainerLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.NodeLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.provider.BorderNodeLabelPositionProvider;
import org.eclipse.sirius.components.diagrams.layout.incremental.provider.EdgeLabelPositionProvider;
import org.eclipse.sirius.components.diagrams.layout.incremental.provider.EdgeRoutingPointsProvider;
import org.eclipse.sirius.components.diagrams.layout.incremental.provider.NodeLabelPositionProvider;
Expand Down Expand Up @@ -66,6 +67,8 @@ public class IncrementalLayoutEngine {

private NodeLabelPositionProvider nodeLabelPositionProvider;

private BorderNodeLabelPositionProvider borderNodeLabelPositionProvider;

private final EdgeRoutingPointsProvider edgeRoutingPointsProvider = new EdgeRoutingPointsProvider();

private EdgeLabelPositionProvider edgeLabelPositionProvider;
Expand All @@ -80,6 +83,7 @@ public IncrementalLayoutEngine(NodeSizeProvider nodeSizeProvider) {

public void layout(Optional<IDiagramEvent> optionalDiagramElementEvent, DiagramLayoutData diagram, ISiriusWebLayoutConfigurator layoutConfigurator) {
this.nodePositionProvider.reset();
this.borderNodeLabelPositionProvider = new BorderNodeLabelPositionProvider();
this.nodeLabelPositionProvider = new NodeLabelPositionProvider(layoutConfigurator);
this.edgeLabelPositionProvider = new EdgeLabelPositionProvider(layoutConfigurator);

Expand Down Expand Up @@ -175,18 +179,32 @@ private void layoutBorderNodes(Optional<IDiagramEvent> optionalDiagramElementEve
}

// 2- recompute the border node
EnumMap<RectangleSide, List<NodeLayoutData>> borderNodesPerSide = this.snapBorderNodes(borderNodesLayoutData, initialNodeBounds.getSize(), layoutConfigurator);
List<BorderNodesOnSide> borderNodesPerSide = this.snapBorderNodes(borderNodesLayoutData, initialNodeBounds.getSize(), layoutConfigurator);

// 3 - move the border node along the side according to the side change
this.updateBorderNodeAccordingParentResize(optionalDiagramElementEvent, initialNodeBounds, newNodeBounds, borderNodesPerSide, borderNodesLayoutData.get(0).getParent().getId());

// 4- set the label position if the border is newly created
this.updateBorderNodeLabel(optionalDiagramElementEvent, borderNodesPerSide);
}
}

private void updateBorderNodeLabel(Optional<IDiagramEvent> optionalDiagramElementEvent, List<BorderNodesOnSide> borderNodesPerSideList) {

for (BorderNodesOnSide borderNodesOnSide : borderNodesPerSideList) {
RectangleSide side = borderNodesOnSide.getSide();
List<NodeLayoutData> borderNodes = borderNodesOnSide.getBorderNodes();
for (NodeLayoutData borderNodeLayoutData : borderNodes) {
this.borderNodeLabelPositionProvider.updateLabelPosition(optionalDiagramElementEvent, side, borderNodeLayoutData);
}
}
}

/**
* Move the border node along the side according to the parent Size changes.
*/
private void updateBorderNodeAccordingParentResize(Optional<IDiagramEvent> optionalDiagramElementEvent, Bounds initialNodeBounds, Bounds newNodeBounds,
EnumMap<RectangleSide, List<NodeLayoutData>> borderNodesPerSide, String parentId) {
List<BorderNodesOnSide> borderNodesPerSideList, String parentId) {
// @formatter:off
boolean isParentRectangleResized = optionalDiagramElementEvent
.filter(ResizeEvent.class::isInstance)
Expand All @@ -202,11 +220,11 @@ private void updateBorderNodeAccordingParentResize(Optional<IDiagramEvent> optio
Size initialSize = initialNodeBounds.getSize();
Size newSize = newNodeBounds.getSize();

for (Entry<RectangleSide, List<NodeLayoutData>> entry : borderNodesPerSide.entrySet()) {
RectangleSide side = entry.getKey();
List<NodeLayoutData> borderNodeOnSide = entry.getValue();
double homotheticRatio = sideHomotheticRatio.get(entry.getKey());
for (NodeLayoutData borderNodeLayoutData : borderNodeOnSide) {
for (BorderNodesOnSide borderNodesOnSide : borderNodesPerSideList) {
RectangleSide side = borderNodesOnSide.getSide();
List<NodeLayoutData> borderNodes = borderNodesOnSide.getBorderNodes();
double homotheticRatio = sideHomotheticRatio.get(side);
for (NodeLayoutData borderNodeLayoutData : borderNodes) {
// The border node position is done in the parent node coordinate system
Position position = borderNodeLayoutData.getPosition();
Size size = borderNodeLayoutData.getSize();
Expand Down Expand Up @@ -249,10 +267,9 @@ private void updateBorderNodePosition(Optional<IDiagramEvent> optionalDiagramEle
*
* @param borderNodesLayoutData
* the border nodes which position is given in the rectangle upper right corner coordinates system
* @param layoutConfigurator
* @return for each side of the given parentRectangle, the list of the updates border node
*/
private EnumMap<RectangleSide, List<NodeLayoutData>> snapBorderNodes(List<NodeLayoutData> borderNodesLayoutData, Size parentRectangle, ISiriusWebLayoutConfigurator layoutConfigurator) {
private List<BorderNodesOnSide> snapBorderNodes(List<NodeLayoutData> borderNodesLayoutData, Size parentRectangle, ISiriusWebLayoutConfigurator layoutConfigurator) {
EnumMap<RectangleSide, List<NodeLayoutData>> borderNodesPerSide = new EnumMap<>(RectangleSide.class);

Geometry geometry = new Geometry();
Expand All @@ -268,7 +285,12 @@ private EnumMap<RectangleSide, List<NodeLayoutData>> snapBorderNodes(List<NodeLa
borderNodesPerSide.computeIfAbsent(borderNodePositionOnSide.getSide(), side -> new ArrayList<>());
borderNodesPerSide.get(borderNodePositionOnSide.getSide()).add(borderNodeLayoutData);
}
return borderNodesPerSide;

// @formatter:off
return borderNodesPerSide.entrySet().stream()
.map(entry -> new BorderNodesOnSide(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
// @formatter:on
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright (c) 2022 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.diagrams.layout.incremental.provider;

import java.util.Optional;

import org.eclipse.sirius.components.diagrams.Position;
import org.eclipse.sirius.components.diagrams.events.IDiagramEvent;
import org.eclipse.sirius.components.diagrams.events.MoveEvent;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.LabelLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.data.NodeLayoutData;
import org.eclipse.sirius.components.diagrams.layout.incremental.utils.RectangleSide;

/**
* Provides the position logic to apply to a BorderNode Label.
*
* @author lfasani
*/
public class BorderNodeLabelPositionProvider {

public void updateLabelPosition(Optional<IDiagramEvent> optionalDiagramElementEvent, RectangleSide side, NodeLayoutData borderNodeLayoutData) {
LabelLayoutData label = borderNodeLayoutData.getLabel();
if (label != null) {
// @formatter:off
Boolean isBorderNodeMoved = optionalDiagramElementEvent
.filter(MoveEvent.class::isInstance)
.map(MoveEvent.class::cast)
.map(MoveEvent::getNodeId)
.filter(borderNodeLayoutData.getId()::equals)
.isPresent();
// @formatter:on

if (borderNodeLayoutData.getLabel().getPosition().getX() == -1 || Boolean.TRUE.equals(isBorderNodeMoved)) {
if (RectangleSide.NORTH.equals(side)) {
label.setPosition(Position.at(-label.getTextBounds().getSize().getWidth(), -label.getTextBounds().getSize().getHeight()));
} else if (RectangleSide.EAST.equals(side)) {
label.setPosition(Position.at(borderNodeLayoutData.getSize().getWidth(), borderNodeLayoutData.getSize().getHeight()));
} else {
label.setPosition(Position.at(-label.getTextBounds().getSize().getWidth(), borderNodeLayoutData.getSize().getHeight()));
}
}
}
}
}
Loading

0 comments on commit 9930786

Please sign in to comment.