diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo.freehep/src/de/cau/cs/kieler/klighd/piccolo/freehep/SemanticSVGGraphics2D.java b/plugins/de.cau.cs.kieler.klighd.piccolo.freehep/src/de/cau/cs/kieler/klighd/piccolo/freehep/SemanticSVGGraphics2D.java
index 8a518d1b2..143f0a486 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo.freehep/src/de/cau/cs/kieler/klighd/piccolo/freehep/SemanticSVGGraphics2D.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo.freehep/src/de/cau/cs/kieler/klighd/piccolo/freehep/SemanticSVGGraphics2D.java
@@ -1566,7 +1566,7 @@ protected static String getPathContent(PathIterator path) {
StringBuffer result = new StringBuffer();
double[] coords = new double[6];
- result.append("d=\"");
+ result.append(" d=\"");
while (!path.isDone()) {
int segType = path.currentSegment(coords);
@@ -1628,7 +1628,7 @@ protected static String getPathContent(PathIterator path) {
protected String getPath(PathIterator path) {
StringBuffer result = new StringBuffer();
- result.append("");
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/KlighdNode.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/KlighdNode.java
index 56c5ca569..929d3050c 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/KlighdNode.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/KlighdNode.java
@@ -554,6 +554,8 @@ public KlighdFigureNode(final T rendering) {
private T rendering;
+ private boolean isBackgroundFigure;
+
/**
* Configures the {@link KRendering} element being represented by this {@link KlighdFigureNode}.
*
@@ -567,6 +569,8 @@ public void setRendering(final T rendering) {
return;
}
+ this.isBackgroundFigure = rendering.getProperty(KlighdProperties.BACKGROUND_FIGURE);
+
setVisibilityOn(
rendering.getProperty(KlighdProperties.OUTLINE_INVISIBLE).booleanValue(),
rendering.getProperty(KlighdProperties.EXPORTED_IMAGE_INVISIBLE).booleanValue(),
@@ -678,6 +682,16 @@ protected boolean pickAfterChildren(final PPickPath pickPath) {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isNotVisibleOn(KlighdPaintContext kpc) {
+ return kpc.isBackgroundFiguresOnly() && !this.isBackgroundFigure
+ || kpc.isNonBackgroundFiguresOnly() && this.isBackgroundFigure
+ || super.isNotVisibleOn(kpc);
+ }
+
/**
* {@inheritDoc}
*
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/AbstractKGERenderingController.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/AbstractKGERenderingController.java
index bb8a4aacc..4c6fdc76f 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/AbstractKGERenderingController.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/AbstractKGERenderingController.java
@@ -156,6 +156,9 @@ enum ElementMovement {
/** whether to synchronize the rendering with the model. */
private boolean syncRendering = false;
+ /** A flag for capturing whether some figure description parts are tagged as background figures. */
+ protected boolean backgroundFiguresPresent = false;
+
/**
* A flag indicating the availability of {@link KStyle KStyles} with valid modifier ids in
* {@link #currentRendering}.
@@ -324,6 +327,9 @@ void updateRendering() {
// this call updates the 'currentRendering' field
getCurrentRendering();
+ // reset the flag before re-evaluating the current figure description
+ backgroundFiguresPresent = false;
+
// reset that flag as potentially available styles with a modifier might be removed now
modifiableStylesPresent = false;
@@ -1172,6 +1178,9 @@ protected PNodeController> createRendering(final KRendering rendering,
final boolean isRenderingRef =
rendering.eClass() == KRenderingPackage.eINSTANCE.getKRenderingRef();
+ this.backgroundFiguresPresent = this.backgroundFiguresPresent
+ || rendering.getProperty(KlighdProperties.BACKGROUND_FIGURE);
+
final List renderingStyles = rendering.getStyles();
processModifiableStyles(renderingStyles);
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/KNodeRenderingController.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/KNodeRenderingController.java
index c0d93ad25..d5248ee05 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/KNodeRenderingController.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/KNodeRenderingController.java
@@ -72,6 +72,8 @@ protected PNodeController> internalUpdateRendering() {
handleAreaAndPointPlacementRendering(createDefaultRendering(), repNode);
}
+ repNode.setHasBackgroundFigures(this.backgroundFiguresPresent);
+
// make sure the child area is attached to something
if (childAreaNode.getParent() == null) {
// if the childArea is not part of the above created PNode rendering tree
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KChildAreaNode.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KChildAreaNode.java
index 60023c193..e413b8c98 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KChildAreaNode.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KChildAreaNode.java
@@ -16,9 +16,15 @@
*/
package de.cau.cs.kieler.klighd.piccolo.internal.nodes;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.BasicEMap;
+
+import de.cau.cs.kieler.klighd.kgraph.KGraphPackage;
import de.cau.cs.kieler.klighd.krendering.KChildArea;
import de.cau.cs.kieler.klighd.piccolo.IKlighdNode;
import de.cau.cs.kieler.klighd.piccolo.internal.util.KlighdPaintContext;
+import de.cau.cs.kieler.klighd.util.KlighdProperties;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.util.PBounds;
@@ -41,14 +47,17 @@ public class KChildAreaNode extends KlighdDisposingLayer implements IKlighdNode.
private final KNodeAbstractNode parentNodeNode;
- private final boolean edgesFirst;
+ private boolean edgesFirst;
/** the node layer. */
- private PLayer nodeLayer;
+ private PLayer belowEdgesNodeLayer;
/** the edge layer. */
private PLayer edgeLayer;
+ /** 2nd node layer containing nodes being drawn on top of edges. */
+ private PLayer aboveEdgesNodeLayer;
+
/** the {@link KChildArea} represented by this {@link KChildAreaNode}, may be null
. */
private KChildArea childArea;
@@ -69,6 +78,37 @@ public KChildAreaNode(final KNodeAbstractNode parentNodeNode, final boolean edge
this.setPickable(false);
this.parentNodeNode = parentNodeNode;
this.edgesFirst = edgesFirst;
+
+ if (!edgesFirst && parentNodeNode instanceof KNodeTopNode) {
+ // special handling for the KNodeTopNode since the root KNode and the KNodeTopNode are
+ // kept for the entire diagram life time and the update strategy transfers settings on
+ // the root node after this constructor call;
+ // hence, 'edgesFirst' will always be false except KlighdProperties.EDGES_FIRST is set
+ // on the viewContext;
+ // thus, if no activation is done on the view context we need to listen for changes on
+ // the properties of the root node being performed by the update strategy, so...
+
+ parentNodeNode.getViewModelElement().eAdapters().add(new AdapterImpl() {
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ if (msg.getFeature() == KGraphPackage.eINSTANCE.getEMapPropertyHolder_Properties()) {
+ final Object newValue = msg.getNewValue();
+ if (msg.getEventType() == Notification.REMOVE_MANY && newValue == null) {
+ KChildAreaNode.this.edgesFirst =
+ KlighdProperties.EDGES_FIRST.getDefault().booleanValue();
+
+ } else if (msg.getEventType() == Notification.ADD
+ && newValue instanceof BasicEMap.Entry, ?>
+ && KlighdProperties.EDGES_FIRST
+ .equals(((BasicEMap.Entry, ?>) newValue).getKey())) {
+ KChildAreaNode.this.edgesFirst =
+ (Boolean) ((BasicEMap.Entry, ?>) newValue).getValue();
+ }
+ }
+ }
+ });
+ }
}
/**
@@ -103,8 +143,8 @@ public PLayer getEdgeLayer() {
*
* @return a dedicated layer accommodating all attached {@link KNodeNode KNodeNodes}.
*/
- public PLayer getNodeLayer() {
- return this.nodeLayer;
+ public PLayer getDefaultNodeLayer() {
+ return this.belowEdgesNodeLayer;
}
/**
@@ -124,12 +164,22 @@ public void setClip(final boolean clip) {
* the node representation
*/
public void addNode(final KNodeNode node) {
- if (nodeLayer == null) {
- nodeLayer = new KlighdDisposingLayer();
- addChild(edgesFirst ? getChildrenCount() : 0, nodeLayer);
+ if (edgesFirst || node.isTaggedAsForeground()) {
+ if (aboveEdgesNodeLayer == null) {
+ aboveEdgesNodeLayer = new KlighdDisposingLayer();
+ addChild(getChildrenCount(), aboveEdgesNodeLayer);
+ }
+ aboveEdgesNodeLayer.addChild(node);
+ node.setParentNode(parentNodeNode, true);
+
+ } else {
+ if (belowEdgesNodeLayer == null) {
+ belowEdgesNodeLayer = new KlighdDisposingLayer();
+ addChild(0, belowEdgesNodeLayer);
+ }
+ belowEdgesNodeLayer.addChild(node);
+ node.setParentNode(parentNodeNode, false);
}
- nodeLayer.addChild(node);
- node.setParentNode(parentNodeNode);
}
/**
@@ -141,7 +191,7 @@ public void addNode(final KNodeNode node) {
public void addEdge(final KEdgeNode edge) {
if (edgeLayer == null) {
edgeLayer = new KlighdDisposingLayer();
- addChild(edgesFirst ? 0 : getChildrenCount(), edgeLayer);
+ addChild(belowEdgesNodeLayer == null ? 0 : 1, edgeLayer);
}
edgeLayer.addChild(edge);
}
@@ -264,6 +314,26 @@ public void fullPaint(final PPaintContext paintContext) {
super.validateFullBounds();
super.validateFullPaint();
- super.fullPaint(paintContext);
+ if (this.aboveEdgesNodeLayer == null || this.aboveEdgesNodeLayer.getChildrenCount() == 0) {
+ // no nodes to be drawn above edges, so draw as usual
+ super.fullPaint(paintContext);
+
+ } else if (getVisible() && fullIntersects(paintContext.getLocalClip())) {
+ final KlighdPaintContext kpc = (KlighdPaintContext) paintContext;
+
+ // assigning selected nodes explicitly to the 'aboveEdgesNodeLayer' or 'belowEdgesNodeLayer'
+ // is not supported as of now, and therefore a mixture of nodes to be drawn underneath the edge layer
+ // and nodes to be drawn on top of the edge layer should not occur at the time of writing this.
+
+ kpc.pushFigureFilterBackgroundOnly();
+ paintContext.pushTransform(getTransformReference(false));
+ this.aboveEdgesNodeLayer.fullPaint(paintContext);
+ paintContext.popTransform(getTransformReference(false));
+ kpc.popFigureFilter();
+
+ kpc.pushFigureFilterNonBackgroundOnly();
+ super.fullPaint(paintContext);
+ kpc.popFigureFilter();
+ }
}
}
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
index 7911e8426..fb577c6c8 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
@@ -75,6 +75,15 @@ public class KNodeNode extends KNodeAbstractNode implements
*/
private final PCamera childAreaCamera;
+ /** Flag indicating that this node is tagged to be drawn on top of the edge layer within the parent child area. */
+ private final boolean isTaggedAsForeground;
+
+ /** Flag indicating that this node is considered be drawn on top of the edge layer within the parent child area by its containing child area. */
+ private boolean isDrawnAsForeground = false;
+
+ /** Flag indicating whether this node's figure contains background parts to be drawn before drawing all the edges within the parent child area. */
+ private boolean hasBackgroundFigures = false;
+
/** this flag indicates whether this node is currently observed by the {@link KlighdMainCamera}. */
private boolean isRootLayer = false;
@@ -114,6 +123,8 @@ public class KNodeNode extends KNodeAbstractNode implements
public KNodeNode(final KNode node, final boolean edgesFirst) {
super(node, edgesFirst);
+ this.isTaggedAsForeground = node.getProperty(KlighdProperties.FOREGROUND_NODE).booleanValue();
+
this.visibilityHelper = KGraphElementNode.evaluateVisibilityDefinitions(node, null);
this.childAreaCamera = new PCamera() {
@@ -395,8 +406,9 @@ public KNodeAbstractNode getParentKNodeNode() {
* @param parentINode
* the {@link AbstractKNodeNode} being the new parent in terms of the structural nodes
*/
- public void setParentNode(final KNodeAbstractNode parentINode) {
+ public void setParentNode(final KNodeAbstractNode parentINode, final boolean addedAsForeground) {
this.parent = parentINode;
+ this.isDrawnAsForeground = addedAsForeground;
}
/**
@@ -408,6 +420,27 @@ public void removeFromParent() {
this.parent = null;
}
+ /**
+ * Getter.
+ *
+ * @return the value of getProperty({@link KlighdProperties#FOREGROUND_NODE}) for the
+ * corresponding {@link KNode}.
+ */
+ public boolean isTaggedAsForeground() {
+ return this.isTaggedAsForeground;
+ }
+
+ /**
+ * Setter.
+ *
+ * @param hasBackgroundFigures
+ * value denoting whether the attached node figure contains parts being tagged as
+ * background figure parts.
+ */
+ public void setHasBackgroundFigures(final boolean hasBackgroundFigures) {
+ this.hasBackgroundFigures = hasBackgroundFigures;
+ }
+
/**
* {@inheritDoc}
*/
@@ -645,8 +678,17 @@ protected void notifyCameras(PBounds parentBounds) {
*/
@Override
public void fullPaint(final PPaintContext paintContext) {
- final boolean isRootLayer = this.isRootLayer;
final KlighdPaintContext kpc = (KlighdPaintContext) paintContext;
+
+ final boolean backgroundFiguresOnly = kpc.isBackgroundFiguresOnly();
+ if (backgroundFiguresOnly && !(this.isDrawnAsForeground && this.hasBackgroundFigures)) {
+ // if parent child area preforms the background figure drawings and this
+ // node is not to be drawn in foreground or doesn't have background figure parts
+ // exit early!
+ return;
+ }
+
+ final boolean isRootLayer = this.isRootLayer;
if (!isRootLayer && this.visibilityHelper != null
&& this.visibilityHelper.isNotVisibleOn(kpc)) {
return;
@@ -671,6 +713,14 @@ public void fullPaint(final PPaintContext paintContext) {
paintContext.pushTransform(transform);
paintContext.pushTransparency(getTransparency());
+ final boolean pushAllFilter = !this.isDrawnAsForeground && kpc.isNonBackgroundFiguresOnly();
+ if (pushAllFilter) {
+ // in case this node is to be drawn as a regular (non-foreground) node but has figure parts tagged as background figures
+ // and we're in non-background drawing mode override the configured non-background figure filter with the all filter,
+ // and revert the override below, of course!
+ kpc.pushFigureFilterAll();
+ }
+
this.hasBeenDrawn = true;
final boolean applyScale = this.nodeScale != null;
@@ -678,13 +728,16 @@ public void fullPaint(final PPaintContext paintContext) {
kpc.pushNodeScale(this.nodeScale.doubleValue());
}
- if (!getOccluded()) {
+ if (!getOccluded() && !backgroundFiguresOnly) {
+ // contributes the opening group tag during SVG exports if semantic data are attached,
+ // don't do that during the background figure drawing
paint(paintContext);
}
final int count = getChildrenCount();
+ final List> children = getChildrenReference();
for (int i = 0; i < count; i++) {
- final PNode each = (PNode) getChildrenReference().get(i);
+ final PNode each = (PNode) children.get(i);
if (isRootLayer) {
if (isRootAndDrawnViaMainCamera) {
@@ -705,17 +758,31 @@ public void fullPaint(final PPaintContext paintContext) {
// Hence, it must be that of the outline diagram or any further one.
continue;
}
+
+ } else if (backgroundFiguresOnly) {
+ if (i != 0 || each == this.childArea) {
+ // do not draw anything except the node's figure if just background drawing is requested
+ break;
+ }
}
each.fullPaint(paintContext);
}
- paintAfterChildren(paintContext);
+ if (!backgroundFiguresOnly) {
+ // contributes the closing group tag during SVG exports if semantic data are attached,
+ // don't do that during the background figure drawing
+ paintAfterChildren(paintContext);
+ }
if (applyScale) {
kpc.popNodeScale();
}
+ if (pushAllFilter) {
+ kpc.popFigureFilter();
+ }
+
paintContext.popTransparency(getTransparency());
paintContext.popTransform(transform);
}
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/util/KlighdPaintContext.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/util/KlighdPaintContext.java
index 8197a03e2..6acaf1b55 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/util/KlighdPaintContext.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/util/KlighdPaintContext.java
@@ -18,13 +18,13 @@
import java.awt.Graphics2D;
import java.awt.Shape;
-import java.util.Stack;
import de.cau.cs.kieler.klighd.piccolo.KlighdSWTGraphics;
import de.cau.cs.kieler.klighd.piccolo.internal.nodes.KlighdMagnificationLensCamera;
import de.cau.cs.kieler.klighd.piccolo.internal.nodes.KlighdMainCamera;
import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.util.PPaintContext;
+import edu.umd.cs.piccolo.util.PStack;
/**
* This is a specialization of {@link PPaintContext} suppressing the super class' clipping
@@ -36,6 +36,14 @@
*/
public class KlighdPaintContext extends PPaintContext {
+ /**
+ * Enum defining the figure filter values required for drawing foreground nodes with background
+ * figure parts.
+ */
+ public static enum FigureFilter {
+ ALL, BG_ONLY, nBG_ONLY
+ }
+
/**
* Factory method creating a {@link KlighdPaintContext} configured for on screen (main) diagram
* drawing.
@@ -143,6 +151,8 @@ protected KlighdPaintContext(final KlighdSWTGraphics graphics, final boolean out
}
private double cameraZoomScale = 1d;
+ private FigureFilter figureFilter = FigureFilter.ALL;
+
private final boolean mainDiagram;
private final boolean outline;
private final boolean export;
@@ -151,7 +161,8 @@ protected KlighdPaintContext(final KlighdSWTGraphics graphics, final boolean out
private final boolean addSemanticData;
private final boolean setTextLengths;
- private final Stack cameraScales = new Stack();
+ private final PStack cameraScales = new PStack();
+ private final PStack figureFilters = new PStack();
/**
* Provides the current diagram zoom factor as determined by the active {@link KlighdMainCamera}'s
@@ -271,7 +282,7 @@ public PCamera getTopCamera() {
/**
* {@inheritDoc}
- * This specialization suppresses the original clipping behavior as we don't need it or event
+ * This specialization suppresses the original clipping behavior as we don't need it or even
* don't want to have it. Thus, this method does nothing.
*/
@Override
@@ -281,7 +292,7 @@ public void pushClip(final Shape clip) {
/**
* {@inheritDoc}
- * This specialization suppresses the original clipping behavior as we don't need it or event
+ * This specialization suppresses the original clipping behavior as we don't need it or even
* don't want to have it. Thus, this method does nothing.
*/
@Override
@@ -327,6 +338,54 @@ public void pushNodeScale(final double scale) {
* {@link de.cau.cs.kieler.klighd.piccolo.internal.nodes.KChildAreaNode KChildAreaNode} only!
*/
public void popNodeScale() {
- cameraZoomScale = cameraScales.pop();
+ cameraZoomScale = (double) cameraScales.pop();
+ }
+
+ /**
+ * @return true
if this paint context expects only background figure parts of node
+ * figures to be drawn, and false
otherwise.
+ */
+ public boolean isBackgroundFiguresOnly() {
+ return this.figureFilter == FigureFilter.BG_ONLY;
+ }
+
+ /**
+ * @return true
if this paint context expects everything to be drawn except
+ * background figure parts of node figures, and false
otherwise.
+ */
+ public boolean isNonBackgroundFiguresOnly() {
+ return this.figureFilter == FigureFilter.nBG_ONLY;
+ }
+
+ /**
+ * Saves the current figure filter and overrides it with {@link FigureFilter#ALL}.
+ */
+ public void pushFigureFilterAll() {
+ this.figureFilters.push(this.figureFilter);
+ this.figureFilter = FigureFilter.ALL;
+ }
+
+ /**
+ * Saves the current figure filter and overrides it with {@link FigureFilter#BG_ONLY}.
+ */
+ public void pushFigureFilterBackgroundOnly() {
+ this.figureFilters.push(this.figureFilter);
+ this.figureFilter = FigureFilter.BG_ONLY;
+ }
+
+ /**
+ * Saves the current figure filter and overrides it with {@link FigureFilter#nBG_ONLY}.
+ */
+ public void pushFigureFilterNonBackgroundOnly() {
+ this.figureFilters.push(this.figureFilter);
+ this.figureFilter = FigureFilter.nBG_ONLY;
+ }
+
+ /**
+ * Discards the current filter and restores the previous one. Must be called in sync with one of
+ * the pushFigureFilter...
methods.
+ */
+ public void popFigureFilter() {
+ this.figureFilter = (FigureFilter) this.figureFilters.pop();
}
}
\ No newline at end of file
diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/syntheses/DiagramSyntheses.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/syntheses/DiagramSyntheses.java
index 41641c33f..6e6844305 100644
--- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/syntheses/DiagramSyntheses.java
+++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/syntheses/DiagramSyntheses.java
@@ -547,6 +547,41 @@ public static T propagateVisibilityBoundsToChildren(final
return setPropagateVisibilityBoundsToChildren(krendering, true);
}
+ /**
+ * Configures the provided {@link KNode} to be drawn as foreground node on top of the edges
+ * within the common parent node. This avoids overlaps of node drawings by edge paths, which can
+ * be relevant for special diagram types with predefined layout.
+ *
+ * @see {@link KlighdProperties#FOREGROUND_NODE}
+ *
+ * @param node
+ * the {@link KNode} to be configured
+ * @return node
for convenience
+ */
+ public static KNode drawAsForegroundNode(final KNode node) {
+ node.setProperty(KlighdProperties.FOREGROUND_NODE, true);
+ return node;
+ }
+
+ /**
+ * Configures the provided {@link KRendering} to be drawn as background figure that avoids
+ * overlaps of edge drawings by node figures parts, provided the node is drawn as foreground
+ * node, i.e. on top of the edge drawings within containing parent node.
+ *
+ * @see {@link KlighdProperties#BACKGROUND_FIGURE}
+ *
+ * @param
+ * the concrete type of krendering
+ * @param krendering
+ * the {@link KRendering} to be configured, has no effect for
+ * {@link de.cau.cs.kieler.klighd.krendering.KChildArea KChildAreas}
+ * @return krendering
for convenience
+ */
+ public static T drawAsBackgroundFigure(final T krendering) {
+ krendering.setProperty(KlighdProperties.BACKGROUND_FIGURE, true);
+ return krendering;
+ }
+
/**
* Configures the provided {@link KRendering} to be excluded from the outline diagram view.
*
diff --git a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java
index 09e56a876..d7c897289 100644
--- a/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java
+++ b/plugins/de.cau.cs.kieler.klighd/src/de/cau/cs/kieler/klighd/util/KlighdProperties.java
@@ -169,6 +169,28 @@ public static boolean isSelectable(final EObject viewElement) {
|| (viewElement instanceof KText && isSelectable((KText) viewElement));
}
+ /**
+ * Property for distinguishing a {@link KNode} to be drawn on top of the edge drawings within
+ * the parent {@link KNode}, in contrast to the default behavior of drawing edges on top of
+ * nodes. If set to true
for a particular node the corresponding drawing node shall
+ * be drawn after all edges within the parent node are drawn and should receive precedence in
+ * the element picking.
+ */
+ public static final IProperty FOREGROUND_NODE = new Property(
+ "de.cau.cs.kieler.klighd.foregroundNode", false);
+
+ /**
+ * Property for distinguishing a {@link de.cau.cs.kieler.klighd.krendering.KRendering
+ * KRendering} being part of a {@link KNode}'s figure description (!) to be drawn underneath
+ * (before) the edge drawings within the parent {@link KNode}. This property setting shall have
+ * no effect for standard diagram descriptions, but is supposed to have an effect if
+ * {@link KlighdProperties#FOREGROUND_NODE} is set to true
for the corresponding
+ * {@link KNode}, or {@link KlighdProperties#EDGES_FIRST} is configured on the
+ * {@link de.cau.cs.kieler.klighd.ViewContext ViewContext}. This setting is ignored for
+ * {@link de.cau.cs.kieler.klighd.krendering.KChildArea KChildAreas}.
+ */
+ public static final IProperty BACKGROUND_FIGURE = new Property(
+ "de.cau.cs.kieler.klighd.backgroundFigure", false);
/**
* Property determining the visibility of a certain
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/AdapterTest.launch b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/AdapterTest.launch
index c8f09e5ab..dd5178883 100644
--- a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/AdapterTest.launch
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/AdapterTest.launch
@@ -1,45 +1,169 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.launch b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.launch
new file mode 100644
index 000000000..369eb5df0
--- /dev/null
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.launch
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.launch b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.launch
new file mode 100644
index 000000000..80f788fca
--- /dev/null
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.launch
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/HighlightedEdgeToForegroundTest.launch b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/HighlightedEdgeToForegroundTest.launch
index 1eaf256d3..8904248df 100644
--- a/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/HighlightedEdgeToForegroundTest.launch
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/runConfigs/HighlightedEdgeToForegroundTest.launch
@@ -25,6 +25,7 @@
+
@@ -157,6 +158,7 @@
+
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/AdapterTest.java b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/AdapterTest.java
index a36d1e9f4..19a6f1ca9 100644
--- a/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/AdapterTest.java
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/AdapterTest.java
@@ -87,7 +87,7 @@ public void layoutTest() {
);
final KNodeAbstractNode node = controller.getNode();
- final PLayer nodeLayer = node.getChildAreaNode().getNodeLayer();
+ final PLayer nodeLayer = node.getChildAreaNode().getDefaultNodeLayer();
final PNode pnext = nodeLayer.getChild(0);
final PLayer portlayer = ((KNodeNode) pnext).getPortLayer();
final PNode pport = portlayer.getChild(3);
@@ -380,9 +380,7 @@ private boolean checkStructure(final KNode kgraph, final KNodeAbstractNode picco
if (!piccoloTree.getViewModelElement().toString().equals(kgraph.toString())) {
return false;
}
- final PLayer nodeLayer = piccoloTree.getChildAreaNode().getNodeLayer() != null
- ? piccoloTree.getChildAreaNode().getNodeLayer() : new PLayer();
- // chsch: added some hotfix here
+ final PLayer nodeLayer = piccoloTree.getChildAreaNode().getDefaultNodeLayer();
PLayer edgeLayer = null;
if (piccoloTree.getParentKNodeNode() != null) {
@@ -439,7 +437,7 @@ private boolean checkStructure(final KNode kgraph, final KNodeAbstractNode picco
}
}
// check recursively for children
- if (kgraph.getChildren() != null && nodeLayer.getChildrenCount() == 0) {
+ if (kgraph.getChildren() != null && (nodeLayer == null || nodeLayer.getChildrenCount() == 0)) {
return false;
}
if (!checkStructure(kgraph.getChildren().get(i), (KNodeAbstractNode) nodeLayer.getChild(i))) {
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.xtend b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.xtend
new file mode 100644
index 000000000..e35723b79
--- /dev/null
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest.xtend
@@ -0,0 +1,347 @@
+/*
+ * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
+ *
+ * http://rtsys.informatik.uni-kiel.de/kieler
+ *
+ * Copyright 2020 by
+ * + Kiel University
+ * + Department of Computer Science
+ * + Real-Time and Embedded Systems Group
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package de.cau.cs.kieler.klighd.piccolo.test.freehep
+
+import de.cau.cs.kieler.klighd.kgraph.KNode
+import de.cau.cs.kieler.klighd.krendering.Colors
+import de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions
+import de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions
+import de.cau.cs.kieler.klighd.util.KlighdSemanticDiagramData
+import org.eclipse.elk.alg.layered.options.LayeredOptions
+import org.eclipse.elk.core.options.CoreOptions
+import org.eclipse.swt.widgets.Display
+import org.junit.BeforeClass
+import org.junit.FixMethodOrder
+import org.junit.Test
+
+import static de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil.*
+
+import static extension de.cau.cs.kieler.klighd.piccolo.test.freehep.FreeHEPSVGOffscreenRenderingTest.*
+import static extension de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses.*
+
+/**
+ * @author chsch
+ */
+ @FixMethodOrder(NAME_ASCENDING)
+class FreeHEPSVGOffscreenRenderingWithEdgesFirstAndBackgroundTest {
+
+ static extension KRenderingExtensions = new KRenderingExtensions()
+
+ static extension KContainerRenderingExtensions = new KContainerRenderingExtensions()
+
+ @BeforeClass
+ def static void initDisplay() {
+ Display.getDefault()
+ }
+
+ // Note: The diagrams are auto-arranged by ELK Layered with the root's padding being fixed to 'ElkPadding(10)'.
+ // This way the additional space required by the oversized background figures exactly matches the padding, and
+ // the left-most located node's drawing starts at (x,y) == (0,0). Thus, no whitespace is trimmed/compensated
+ // on the left and top border by the exporter. (The exporter accumulates the nested transforms.)
+ // Otherwise we would see unexpected transforms on the KEdges' drawings, as their points always refer to the
+ // coordinate system of the source and target nodes' common parent node.
+
+ @Test
+ def void test01_singleKNode() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ addNode(null, Colors.RED)
+ ]
+ }
+
+ @Test
+ def void test01b_singleKNodeBGfigureInvisible() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ addNode(null, Colors.RED).KContainerRendering.children.head.invisible = true
+ ]
+ }
+
+ @Test
+ def void test02_twoKNodes() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ setLayoutOption(CoreOptions.SPACING_COMPONENT_COMPONENT, 25d)
+ addNode("node1", Colors.RED)
+ addNode("node2", Colors.BLUE)
+ ]
+ }
+
+ @Test
+ def void test02b_twoKNodesWithSemanticData() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ setLayoutOption(CoreOptions.SPACING_COMPONENT_COMPONENT, 25d)
+ addNode("node1", Colors.RED).semanticData = KlighdSemanticDiagramData.of(it).putID("node1")
+ addNode("node2", Colors.BLUE).semanticData = KlighdSemanticDiagramData.of(it).putID("node2")
+ ]
+ }
+
+ @Test
+ def void test03_twoKNodesWithAnEdge() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ setLayoutOption(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, 25d)
+ val n1 = addNode("node1", Colors.RED)
+ val n2 = addNode("node2", Colors.BLUE)
+
+ createInitializedEdge() => [
+ source = n1
+ target = n2
+
+ semanticData = KlighdSemanticDiagramData.of(it).putID("theEdge")
+ ];
+ ]
+ }
+
+ @Test
+ def void test03b_twoKNodesWithAnEdgeAndSemanticData() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGwithEdgesFirstOf[
+ setLayoutOption(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, 25d)
+ val n1 = addNode("node1", Colors.RED).semanticData = KlighdSemanticDiagramData.of(it).putID("node1")
+ val n2 = addNode("node2", Colors.BLUE).semanticData = KlighdSemanticDiagramData.of(it).putID("node2")
+
+ createInitializedEdge() => [
+ source = n1
+ target = n2
+
+ semanticData = KlighdSemanticDiagramData.of(it).putID("theEdge")
+ ];
+ ]
+ }
+
+
+ def private static KNode addNode(KNode it, String id, Colors bgColor) {
+ val extension contExts = _kContainerRenderingExtensions
+ return addKNodeWithSizeOf(100, 100) => [
+ addRectangle() => [
+ invisible = true;
+ addRectangle().setAreaPlacementData().from(LEFT, -10, 0, TOP, -10, 0).to(RIGHT, -10, 0, BOTTOM, -10, 0).drawAsBackgroundFigure().setBackground(bgColor).setSemanticData(
+ KlighdSemanticDiagramData.of(it).putID((id !== null ? id + "-" : "") + "backgroundFigure")
+ );
+ addRectangle().setBackground(Colors.WHITE).setSemanticData(
+ KlighdSemanticDiagramData.of(it).putID((id !== null ? id + "-" : "") + "non-backgroundFigure")
+ );
+ ]
+ ]
+ }
+
+ def private static equalsSVGwithEdgesFirstOf(CharSequence expectation, (KNode) => void viewModelBuilder) {
+ expectation.equalsSVGof(viewModelBuilder, true, false)
+ }
+}
diff --git a/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.xtend b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.xtend
new file mode 100644
index 000000000..a2efa9132
--- /dev/null
+++ b/test/de.cau.cs.kieler.klighd.piccolo.test/src/de/cau/cs/kieler/klighd/piccolo/test/freehep/FreeHEPSVGOffscreenRenderingWithForegroundNodesTest.xtend
@@ -0,0 +1,256 @@
+/*
+ * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
+ *
+ * http://rtsys.informatik.uni-kiel.de/kieler
+ *
+ * Copyright 2020 by
+ * + Kiel University
+ * + Department of Computer Science
+ * + Real-Time and Embedded Systems Group
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package de.cau.cs.kieler.klighd.piccolo.test.freehep
+
+import de.cau.cs.kieler.klighd.kgraph.KNode
+import de.cau.cs.kieler.klighd.krendering.Colors
+import de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions
+import de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions
+import de.cau.cs.kieler.klighd.util.KlighdSemanticDiagramData
+import org.eclipse.elk.alg.layered.options.LayeredOptions
+import org.eclipse.elk.core.options.CoreOptions
+import org.eclipse.swt.widgets.Display
+import org.junit.BeforeClass
+import org.junit.FixMethodOrder
+import org.junit.Test
+
+import static de.cau.cs.kieler.klighd.kgraph.util.KGraphUtil.*
+
+import static extension de.cau.cs.kieler.klighd.piccolo.test.freehep.FreeHEPSVGOffscreenRenderingTest.*
+import static extension de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses.*
+
+/**
+ * @author chsch
+ */
+ @FixMethodOrder(NAME_ASCENDING)
+class FreeHEPSVGOffscreenRenderingWithForegroundNodesTest {
+
+ static extension KRenderingExtensions = new KRenderingExtensions()
+
+ static extension KContainerRenderingExtensions = new KContainerRenderingExtensions()
+
+ @BeforeClass
+ def static void initDisplay() {
+ Display.getDefault()
+ }
+
+ // Note: The diagrams are auto-arranged by ELK Layered with the root's padding being fixed to 'ElkPadding(10)'.
+ // This way the additional space required by the oversized background figures exactly matches the padding, and
+ // the left-most located node's drawing starts at (x,y) == (0,0). Thus, no whitespace is trimmed/compensated
+ // on the left and top border by the exporter. (The exporter accumulates the nested transforms.)
+ // Otherwise we would see unexpected transforms on the KEdges' drawings, as their points always refer to the
+ // coordinate system of the source and target nodes' common parent node.
+
+ @Test
+ def void test01_twoKNodesWithAnEdgeAndSomeForegroundNode() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGof[
+ setLayoutOption(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, 100d)
+ val n1 = addNode("node1", Colors.RED)
+ val n2 = addNode("node2", Colors.BLUE)
+
+ addNode("node3", Colors.GREEN) => [
+ setSize(60, 60)
+ setPos(130, 30)
+ setProperty(CoreOptions.NO_LAYOUT, true)
+ drawAsForegroundNode()
+ ]
+
+ createInitializedEdge() => [
+ source = n1
+ target = n2
+
+ semanticData = KlighdSemanticDiagramData.of(it).putID("theEdge")
+ ];
+
+
+ ]
+ }
+
+ @Test
+ def void test01b_twoKNodesWithAnEdgeAndSomeForegroundNodeAndSemanticData() {
+ '''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''.equalsSVGof[
+ setLayoutOption(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, 100d)
+ val n1 = addNode("node1", Colors.RED).semanticData = KlighdSemanticDiagramData.of(it).putID("node1")
+ val n2 = addNode("node2", Colors.BLUE).semanticData = KlighdSemanticDiagramData.of(it).putID("node2")
+
+ createInitializedEdge() => [
+ source = n1
+ target = n2
+
+ semanticData = KlighdSemanticDiagramData.of(it).putID("theEdge")
+ ];
+
+ addNode("node3", Colors.GREEN) => [
+ setSize(60, 60)
+ setPos(130, 30)
+ setProperty(CoreOptions.NO_LAYOUT, true)
+ drawAsForegroundNode()
+ semanticData = KlighdSemanticDiagramData.of(it).putID("node3")
+ ]
+ ]
+ }
+
+
+ def private static KNode addNode(KNode it, String id, Colors bgColor) {
+ val extension contExts = _kContainerRenderingExtensions
+ return addKNodeWithSizeOf(100, 100) => [
+ addRectangle() => [
+ invisible = true;
+ addRectangle().setAreaPlacementData().from(LEFT, -10, 0, TOP, -10, 0).to(RIGHT, -10, 0, BOTTOM, -10, 0).drawAsBackgroundFigure().setBackground(bgColor).setSemanticData(
+ KlighdSemanticDiagramData.of(it).putID((id !== null ? id + "-" : "") + "backgroundFigure")
+ );
+ addRectangle().setBackground(Colors.WHITE).setSemanticData(
+ KlighdSemanticDiagramData.of(it).putID((id !== null ? id + "-" : "") + "non-backgroundFigure")
+ );
+ ]
+ ]
+ }
+}