X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2Fdiagram%2Fstyle%2FConnectionPointNameStyle.java;fp=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2Fdiagram%2Fstyle%2FConnectionPointNameStyle.java;h=a4f32e81139a5f22d699af3e7d15a5ee7ba3578b;hp=0000000000000000000000000000000000000000;hb=7f206f186acf9bb44f86f5b191c38cddb4508c48;hpb=e358219a999d271f489dc6e3821aa9b76b2d39fe diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/ConnectionPointNameStyle.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/ConnectionPointNameStyle.java new file mode 100644 index 000000000..a4f32e811 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/ConnectionPointNameStyle.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - #7107 original implementation + * Semantum Oy - #7107 adaptation for general use + *******************************************************************************/ +package org.simantics.modeling.ui.diagram.style; + +import java.awt.Color; +import java.awt.Font; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.primitiverequest.OrderedSet; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.diagram.adapter.RouteGraphUtils; +import org.simantics.diagram.connection.RouteGraphConnectionClass; +import org.simantics.diagram.connection.RouteTerminal; +import org.simantics.diagram.elements.TextNode; +import org.simantics.diagram.profile.StyleBase; +import org.simantics.diagram.synchronization.graph.BasicResources; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.g2d.utils.Alignment; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; +import org.simantics.scenegraph.profile.EvaluationContext; +import org.simantics.scenegraph.profile.common.ProfileVariables; +import org.simantics.scenegraph.utils.NodeUtil; +import org.simantics.utils.datastructures.map.Tuple; + +/** + * @author Teemu Mätäsniemi + * @author Tuukka Lehtonen + * @since 1.28.0 + */ +public class ConnectionPointNameStyle extends StyleBase> { + + protected static class Result extends Tuple { + public Result(String string, AffineTransform tr, Integer direction) { + super(string, tr, direction); + } + public String getString() { + return (String) getField(0); + } + public AffineTransform getTransform() { + return (AffineTransform) getField(1); + } + public Integer getAllowedDirections() { + return (Integer) getField(2); + } + } + + protected static final String PARENT_NODE_NAME_PREFIX = "_tNames"; + protected static final String NODE_NAME_PREFIX = "_"; + + protected static final Font FONT = Font.decode("Arial 6"); + + protected static final double DEFAULT_SCALE = 0.05; + + private Color backgroundColor = Color.WHITE; + private Color textColor = Color.BLACK; + + private double textScale; + + public ConnectionPointNameStyle() { + this(DEFAULT_SCALE); + } + + public ConnectionPointNameStyle(double textScale) { + this.textScale = textScale; + } + + @Override + public List calculateStyle( + ReadGraph graph, + Resource runtimeDiagram, + Resource entry, + Resource element, + Variable configuration) + throws DatabaseException + { + BasicResources BR = BasicResources.getInstance(graph); + Layer0 L0 = BR.L0; + ModelingResources MOD = ModelingResources.getInstance(graph); + + Resource comp = graph.getPossibleObject(element, MOD.ElementToComponent); + if (comp == null) + return Collections.emptyList(); + String compName = graph.getPossibleRelatedValue(comp, L0.HasName, Bindings.STRING); + if (compName == null) + return Collections.emptyList(); + + // Only process defined elements since those can contain terminal definitions + Resource elementType = graph.getPossibleType(element, BR.DIA.DefinedElement); + if (elementType == null) + return Collections.emptyList(); + + // Need parent information to calculate absolute positions of terminals + // and to make the result unique for instances of the same symbol. + AffineTransform parentTransform = DiagramGraphUtil.getAffineTransform(graph, element); + List result = new ArrayList<>(); + result.add(new Result(compName, parentTransform, null)); + + Resource orderedSet = graph.getPossibleObject(elementType, BR.STR.IsDefinedBy); + if (orderedSet != null) { + for (Resource el : graph.syncRequest(new OrderedSet(orderedSet))) { + Resource gcp = graph.getPossibleObject(el, BR.DIA.HasConnectionPoint); + if (gcp != null) { + Resource cpRel = graph.getPossibleObject(gcp, MOD.DiagramConnectionRelationToConnectionRelation); + if (cpRel == null) + continue; + String name = graph.getPossibleRelatedValue(cpRel, L0.HasName, Bindings.STRING); + if (name != null) { + Integer allowedDirections = graph.getPossibleRelatedValue(el, BR.DIA.Terminal_AllowedDirections, Bindings.INTEGER); + result.add(new Result(name, DiagramGraphUtil.getAffineTransform(graph, el), allowedDirections)); + } + } + } + } + + return result; + } + + protected static AffineTransform translateAndScaleIfNeeded(AffineTransform tr, double rotation, double offsetX, double offsetY, double scale) { + if (rotation != 0 || offsetX != 0.0 || offsetY != 0.0 || scale != 1.0) { + tr = new AffineTransform(tr); + if (rotation != 0) + tr.rotate(rotation); + if (offsetX != 0 || offsetY != 0) + tr.translate(offsetX, offsetY); + if (scale != 1.0) + tr.scale(scale, scale); + } + return tr; + } + + protected AffineTransform getTerminalTransform(AffineTransform transform, double rotation, double offsetX, double offsetY, double scale) { + return translateAndScaleIfNeeded(transform, rotation, offsetX, offsetY, scale); + } + + @Override + public void applyStyleForNode(EvaluationContext observer, INode _node, List resultList) { + // always clean up old items before drawing new items + cleanupStyleForNode(_node); + + int count = resultList.size(); + if (resultList == null || count < 2) + return; + + G2DParentNode parentNode = ProfileVariables.claimChild(_node, "", PARENT_NODE_NAME_PREFIX, G2DParentNode.class, observer); + parentNode.setTransform(resultList.get(0).getTransform()); + parentNode.setZIndex(Integer.MAX_VALUE >> 1); + + Rectangle2D eBounds = NodeUtil.getLocalElementBounds(_node); + + for (int i = 1; i < count; ++i) { + Result result = resultList.get(i); + TextNode node = ProfileVariables.claimChild(parentNode, "", NODE_NAME_PREFIX + i, TextNode.class, observer); + node.setZIndex(i); + node.setBackgroundColor(backgroundColor); + node.setColor(textColor); + node.setText(result.getString()); + node.setVerticalAlignment((byte) Alignment.CENTER.ordinal()); + node.setAutomaticTextFlipping(TextNode.TextFlipping.VerticalTextDownwards); + + Alignment hAlign = Alignment.LEADING; + AffineTransform tr = result.getTransform(); + double trX = tr.getTranslateX(), + trY = tr.getTranslateY(); + double dx = 0, dy = 0, r = 0; + double ts = 0.6; + + Integer dir = result.getAllowedDirections(); + int directions = dir != null + ? RouteGraphUtils.rotateDirection(dir, tr) + : RouteGraphConnectionClass.shortestDirectionOutOfBounds(trX, trY, eBounds); + + //System.out.format("%24s: DIR %d (%s)%n", result.getString(), directions, tr.toString()); + + if (trX == 0 && trY == 0) { + hAlign = Alignment.CENTER; + } else { + boolean up = (directions & RouteTerminal.DIR_UP) != 0; + boolean down = (directions & RouteTerminal.DIR_DOWN) != 0; + boolean left = (directions & RouteTerminal.DIR_LEFT) != 0; + boolean right = (directions & RouteTerminal.DIR_RIGHT) != 0; + + double ldx = Math.abs(eBounds.getMinX() - trX); + double rdx = Math.abs(eBounds.getMaxX() - trX); + double tdy = Math.abs(eBounds.getMinY() - trY); + double bdy = Math.abs(eBounds.getMaxY() - trY); + + if (left && ldx <= rdx && ldx <= tdy && ldx <= bdy) { + dx = -ts; + hAlign = Alignment.TRAILING; + } else if (right && rdx <= ldx && rdx <= tdy && rdx <= bdy) { + dx = ts; + hAlign = Alignment.LEADING; + } else if (up && tdy <= ldx && tdy <= rdx && tdy <= bdy) { + dx = -ts; + r = Math.PI/2; + hAlign = Alignment.TRAILING; + } else if (down && bdy <= ldx && bdy <= rdx && bdy <= tdy) { + dx = ts; + r = Math.PI/2; + hAlign = Alignment.LEADING; + } + } + + node.setHorizontalAlignment((byte) hAlign.ordinal()); + node.setTransform(getTerminalTransform(tr, r, dx, dy, textScale)); + } + } + + @Override + protected void cleanupStyleForNode(INode node) { + if (node instanceof SingleElementNode) { + ProfileVariables.denyChild(node, "", PARENT_NODE_NAME_PREFIX); + } + } + +}