DN.VertexSymbolStyle : DIA.Style
DN.ConnectionLineStyle : DIA.Style
+// Style for user component-specified text grid entries
+DN.DistrictNetworkHoverInfoStyle : DIA.Style
+
// Function for dynamic selection of symbols for a vertex
// The input of the function is a DN.Vertex
// The output of the function should be SVG
public final Resource Diagram_splitToMultipleEnabled_Inverse;
public final Resource Diagram_trackChangesEnabled;
public final Resource Diagram_trackChangesEnabled_Inverse;
+ public final Resource DistrictNetworkHoverInfoStyle;
public final Resource DistrictNodeGroup;
public final Resource DistrictNodeGroup_hasComponentTypeName;
public final Resource DistrictNodeGroup_hasComponentTypeName_Inverse;
public static final String Diagram_splitToMultipleEnabled_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/splitToMultipleEnabled/Inverse";
public static final String Diagram_trackChangesEnabled = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/trackChangesEnabled";
public static final String Diagram_trackChangesEnabled_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/trackChangesEnabled/Inverse";
+ public static final String DistrictNetworkHoverInfoStyle = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkHoverInfoStyle";
public static final String DistrictNodeGroup = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup";
public static final String DistrictNodeGroup_hasComponentTypeName = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup/hasComponentTypeName";
public static final String DistrictNodeGroup_hasComponentTypeName_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup/hasComponentTypeName/Inverse";
Diagram_splitToMultipleEnabled_Inverse = getResourceOrNull(graph, URIs.Diagram_splitToMultipleEnabled_Inverse);
Diagram_trackChangesEnabled = getResourceOrNull(graph, URIs.Diagram_trackChangesEnabled);
Diagram_trackChangesEnabled_Inverse = getResourceOrNull(graph, URIs.Diagram_trackChangesEnabled_Inverse);
+ DistrictNetworkHoverInfoStyle = getResourceOrNull(graph, URIs.DistrictNetworkHoverInfoStyle);
DistrictNodeGroup = getResourceOrNull(graph, URIs.DistrictNodeGroup);
DistrictNodeGroup_hasComponentTypeName = getResourceOrNull(graph, URIs.DistrictNodeGroup_hasComponentTypeName);
DistrictNodeGroup_hasComponentTypeName_Inverse = getResourceOrNull(graph, URIs.DistrictNodeGroup_hasComponentTypeName_Inverse);
<resource uri="http://www.simantics.org/DistrictNetwork-1.0/ConnectionLineStyle"
class="org.simantics.district.network.ui.nodes.ConnectionLineStyle">
</resource>
+ <resource uri="http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkHoverInfoStyle"
+ class="org.simantics.district.network.ui.nodes.DistrictNetworkHoverInfoStyle">
+ <this />
+ </resource>
</target>
<target interface="org.simantics.g2d.diagram.DiagramClass">
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
+import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement;
import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement;
+import org.simantics.district.network.ui.nodes.DistrictNetworkEdgeNode;
import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
+import org.simantics.district.network.ui.nodes.HoverSensitiveNode;
import org.simantics.district.network.ui.nodes.NetworkDrawingNode;
import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
import org.simantics.g2d.element.IElement;
import org.simantics.scenegraph.Node;
import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.IG2DNode;
import org.simantics.utils.datastructures.hints.IHintContext.Key;
import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
node.setDiagram(newDiagram);
}
- public boolean pickHoveredElement(Point2D currentMousePos) {
- PickRequest req = new PickRequest(currentMousePos).context(getContext());
+ public boolean pickHoveredElement(Point2D currentMousePos, boolean isConnectionTool) {
+ PickRequest req = new PickRequest(new Rectangle2D.Double(currentMousePos.getX(), currentMousePos.getY(), 1e-8, 1e-8)).context(getContext());
List<IElement> pickables = new ArrayList<IElement>();
pick.pick(diagram, req, pickables);
List<IElement> snap = new ArrayList<>(diagram.getSnapshot());
- snap.removeAll(pickables);
+ // snap.removeAll(pickables);
boolean changed = false;
- for (IElement sn : snap) {
- Node node = sn.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
+ changed = hoverVertexNodes(snap, false, isConnectionTool, changed);
+ changed = hoverEdgeNodes(snap, false, isConnectionTool, changed);
+ changed = hoverVertexNodes(pickables, true, isConnectionTool, changed);
+ changed = hoverEdgeNodes(pickables, true, isConnectionTool, changed);
+ return changed;
+ }
+
+ private boolean hoverVertexNodes(List<IElement> elements, boolean hover, boolean isConnectionTool, boolean changed) {
+ for (IElement elem : elements) {
+ Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
if (node instanceof DistrictNetworkVertexNode) {
- if (((DistrictNetworkVertexNode) node).hover(false) && !changed) {
- changed = true;
- }
+ changed = ((DistrictNetworkVertexNode) node).hover(hover, isConnectionTool) || changed;
}
}
-
- for (IElement elem : pickables) {
- Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
- if (node instanceof DistrictNetworkVertexNode) {
- if (((DistrictNetworkVertexNode) node).hover(true) && !changed) {
- changed = true;
+ return changed;
+ }
+
+ private boolean hoverEdgeNodes(List<IElement> elements, boolean hover, boolean isConnectionTool, boolean changed) {
+ for (IElement elem : elements) {
+ Node node = elem.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
+ if (node instanceof DistrictNetworkEdgeNode) {
+ for (IG2DNode n : ((DistrictNetworkEdgeNode) node).getNodes()) {
+ if (n instanceof HoverSensitiveNode) {
+ changed = ((HoverSensitiveNode)n).hover(hover, isConnectionTool) || changed;
+ }
}
}
}
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import org.simantics.maps.MapScalingTransform;
import org.simantics.scenegraph.g2d.G2DParentNode;
import org.simantics.scenegraph.g2d.nodes.SVGNode;
+import org.simantics.scenegraph.utils.NodeUtil;
import org.simantics.utils.datastructures.hints.IHintContext.Key;
import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
import org.slf4j.Logger;
Rectangle2D bounds = getBounds(s);
switch (policy) {
case PICK_CONTAINED_OBJECTS: return pickContainedObjects(edge, bounds);
- case PICK_INTERSECTING_OBJECTS: return pickIntersectingObjects(edge, bounds);
+ case PICK_INTERSECTING_OBJECTS: return pickIntersectingObjects(e, edge, bounds);
}
return false;
}
return eminx >= bsminx && eminy >= boundsMinY && emaxx <= bsmaxx && emaxy <= boundsMaxY;
}
- private boolean pickIntersectingObjects(DistrictNetworkEdge edge, Rectangle2D bounds) {
- double tolerance = (bounds.getHeight() + bounds.getHeight()) * 1 / MapScalingTransform.getScaleX();
- Line2D line = new Line2D.Double(edge.getStartPoint(), edge.getEndPoint());
+ private boolean pickIntersectingObjects(IElement e, DistrictNetworkEdge edge, Rectangle2D bounds) {
+ double dx = bounds.getWidth() / MapScalingTransform.getScaleX();
+ double dy = bounds.getHeight() / MapScalingTransform.getScaleY();
+
+ // Half the diagonal + half of the line width
+ DistrictNetworkEdgeNode node = e.getHint(KEY_DN_EDGE_NODE);
+ AffineTransform at = NodeUtil.getLocalToGlobalTransform(node);
+
+ Path2D path = node.getPath();
+ if (path == null)
+ return false;
+
+ double lineWidth = node.getStrokeWidth(at, true);
+ double tolerance = Math.sqrt(dx * dx + dy * dy) / 2 + lineWidth / 2;
+
double sx = bounds.getCenterX() / MapScalingTransform.getScaleX();
double sy = bounds.getCenterY() / MapScalingTransform.getScaleY();
- double ssx = ModelledCRS.xToLongitude(sx);
- double ssy = ModelledCRS.yToLatitude(-sy); // Invert for Simantics diagram coordinate system
- double distSq = line.ptSegDistSq(ssx, ssy);
-// System.out.println("s: " + sx + ", " + sy);
-// System.out.println("ss: " + ssx + ", " + ssy);
-// System.out.println("p1: " + edge.getStartPoint());
-// System.out.println("p2: " + edge.getEndPoint());
-// System.out.println("line: " + "(" + line.getX1() + ", " + line.getY1() + ", " + line.getX2() + ", " + line.getY2() + ")");
-// System.out.println("distance from line is " + Math.sqrt(distSq) + " with tolerance " + tolerance);
- return distSq <= tolerance * tolerance;
+
+ double coords[] = new double[6];
+ Point2D prevPoint = new Point2D.Double(), curPoint = new Point2D.Double();
+ Line2D line = new Line2D.Double();
+ for (PathIterator it = path.getPathIterator(null); !it.isDone(); it.next()) {
+ int type = it.currentSegment(coords);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ curPoint.setLocation(coords[0], coords[1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ prevPoint.setLocation(curPoint);
+ curPoint.setLocation(coords[0], coords[1]);
+ line.setLine(prevPoint, curPoint);
+ double distSq = line.ptSegDistSq(sx, sy);
+// System.out.println("s: " + sx + ", " + sy);
+// System.out.println("ss: " + ssx + ", " + ssy);
+// System.out.println("p1: " + edge.getStartPoint());
+// System.out.println("p2: " + edge.getEndPoint());
+// System.out.println("line: " + "(" + line.getX1() + ", " + line.getY1() + ", " + line.getX2() + ", " + line.getY2() + ")");
+// System.out.println("distance from line is " + Math.sqrt(distSq) + " with tolerance " + tolerance);
+ if (distSq <= tolerance * tolerance)
+ return true;
+ break;
+ default:
+ LOGGER.error("Invalid edge path", new IllegalStateException());
+ return false;
+ }
+ }
+
+ return false;
}
private Rectangle2D getBounds(Shape shape) {
public boolean pickTest(IElement e, Shape s, PickPolicy policy) {
DistrictNetworkVertexNode node = e.getHint(KEY_DN_VERTEX_NODE);
Rectangle2D boundsInLocal = node.getBounds();
- ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node);
- AffineTransform canvasTransform = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM);
- Rectangle2D scaledBounds = new Rectangle2D.Double(boundsInLocal.getX(), boundsInLocal.getY(), boundsInLocal.getWidth() / canvasTransform.getScaleX() * 2, boundsInLocal.getHeight() / canvasTransform.getScaleY() * 2);
Rectangle2D bounds = getBounds(s);
switch (policy) {
case PICK_CONTAINED_OBJECTS:
BasicStroke bs = null;
double scale = 1.0;
if (scaleStroke) {
- scale = GeometryUtils.getScale(g2d.getTransform());
- scale = Math.max(10000, Math.min(scale, 50000));
- double str = stroke != null ? Math.abs(stroke) : 1.0;
- bs = GeometryUtils.scaleStroke(STROKE, (float) (str / scale));
+ AffineTransform tr = g2d.getTransform();
+ scale = DistrictNetworkNodeUtils.getScale(tr);
+ bs = GeometryUtils.scaleStroke(STROKE, getStrokeWidth(scale));
} else {
bs = STROKE;
}
if (isSelected()) {
g2d.setColor(SELECTION_COLOR);
- g2d.setStroke(GeometryUtils.scaleStroke(bs, 4f));
+ g2d.setStroke(GeometryUtils.scaleAndOffsetStrokeWidth(bs, 1.f, (float)(2 * STROKE.getLineWidth() / scale)));
g2d.draw(path);
}
g2d.setTransform(ot);
}
+ public float getStrokeWidth(AffineTransform tr, boolean selection) {
+ double scale = DistrictNetworkNodeUtils.getScale(tr);
+ float width = STROKE.getLineWidth() * getStrokeWidth(scale);
+ if (selection) width = width + (float) (2 * STROKE.getLineWidth() / scale);
+ return width;
+ }
+
+ private float getStrokeWidth(double scale) {
+ if (scaleStroke) {
+ double str = stroke != null ? Math.abs(stroke) : 1.0;
+ float strokeWidth = (float) (str / scale);
+ return strokeWidth;
+ }
+ else {
+ return 1.f;
+ }
+ }
+
+ public Path2D getPath() {
+ return path;
+ }
+
private Point2D getCenterPoint() {
if (centerPoint == null)
centerPoint = new Point2D.Double();
--- /dev/null
+package org.simantics.district.network.ui.nodes;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.simantics.scenegraph.g2d.G2DNode;
+import org.simantics.scl.runtime.Lists;
+import org.simantics.scl.runtime.tuple.Tuple3;
+
+public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensitiveNode {
+
+ private static final Font FONT = new Font(Font.DIALOG, Font.PLAIN, 12);
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
+
+ private static final int W1 = 50;
+ private static final int W2 = 30;
+ private static final int PAD = 5;
+
+ private List<Tuple3> labels;
+
+ private Point2D origin;
+
+ private boolean hover = false;
+
+ private static AtomicReference<DistrictNetworkHoverInfoNode> activeNode = new AtomicReference<>();
+
+ @Override
+ public void render(Graphics2D g) {
+ if (!hover || activeNode.get() != this)
+ return;
+
+ AffineTransform ot = g.getTransform();
+ Font of = g.getFont();
+ doRender(g);
+ g.setFont(of);
+ g.setTransform(ot);
+ }
+
+ private void doRender(Graphics2D g) {
+ g.translate(origin.getX(), origin.getY());
+ double scale = 1.5 / g.getTransform().getScaleX();
+ g.scale(scale, scale);
+
+ g.setFont(FONT);
+ double rowHeight = g.getFontMetrics().getHeight() * 1.1;
+
+ g.setColor(Color.BLACK);
+
+ for (Tuple3 t : labels) {
+ g.translate(0.f, -rowHeight);
+
+ if (t.c0 != null) {
+ g.drawString((String) t.c0, -(W1 + PAD + W2), 0.f);
+ }
+
+ if (t.c1 != null) {
+ int width1 = g.getFontMetrics().stringWidth((String) t.c1);
+ g.drawString((String) t.c1, - width1, 0.f);
+ }
+
+ if (t.c2 != null) {
+ g.drawString((String) t.c2, PAD, 0.f);
+ }
+ }
+ }
+
+ @Override
+ public Rectangle2D getBoundsInLocal() {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void setLabels(List<Tuple3> list) {
+ this.labels = Lists.reverse(list);
+ }
+
+ public void setOrigin(Point2D origin) {
+ this.origin = origin;
+ }
+
+ @Override
+ public boolean hover(boolean hover, boolean isConnectionTool) {
+ hover = hover && activeNode.updateAndGet(current -> current == null ? this : current) == this;
+ boolean changed = hover != this.hover;
+ this.hover = hover;
+
+ if (changed) {
+ if (!hover) activeNode.updateAndGet(current -> current == this ? null : current);
+ repaint();
+ }
+
+ return changed;
+ }
+
+ @Override
+ public void delete() {
+ super.delete();
+ activeNode.getAndUpdate(current -> current == this ? null : current);
+ }
+}
--- /dev/null
+package org.simantics.district.network.ui.nodes;
+
+import java.awt.geom.Point2D;
+import java.util.Collections;
+import java.util.List;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.exception.PendingVariableException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.diagram.profile.StyleBase;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.district.network.DistrictNetworkUtil;
+import org.simantics.district.network.ontology.DistrictNetworkResource;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.common.ProfileVariables;
+import org.simantics.scl.compiler.top.ValueNotFound;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.scl.runtime.tuple.Tuple3;
+import org.simantics.structural.stubs.StructuralResource2;
+
+public class DistrictNetworkHoverInfoStyle extends StyleBase<DistrictNetworkHoverInfoStyle.StyleResult> {
+
+ private static final String ACTIONS_MODULE = "Actions";
+ private static final String HOVER_CONTRIBUTION = "hoverContribution";
+
+ public class StyleResult {
+ Point2D origin;
+ List<Tuple3> labels;
+
+ public StyleResult(Point2D origin, List<Tuple3> labels) {
+ this.origin = origin;
+ this.labels = labels;
+ }
+
+ public Point2D getOrigin() {
+ return origin;
+ }
+
+ public List<Tuple3> getLabels() {
+ return labels;
+ }
+ }
+
+ public DistrictNetworkHoverInfoStyle(Resource style) throws DatabaseException {
+ super(style);
+ }
+
+ String currentRowKey;
+
+ protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
+ ModelingResources MOD = ModelingResources.getInstance(graph);
+ DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+
+ Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
+ return mappedElement != null ? graph.getPossibleObject(mappedElement, MOD.ElementToComponent) : null;
+ }
+
+ @Override
+ public StyleResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry,
+ Resource mapElement, Variable configuration) throws DatabaseException {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+ String variableURI = graph.getPossibleRelatedValue(runtimeDiagram, DIA.RuntimeDiagram_HasVariable, Bindings.STRING);
+ Variable activeVariable = org.simantics.db.layer0.variable.Variables.getPossibleVariable(graph, variableURI);
+ if (activeVariable == null)
+ return null;
+
+ Resource module = DistrictNetworkUtil.getMappedComponentCached(graph, mapElement);
+ if (module == null)
+ return null;
+
+ Resource moduleType = graph.getPossibleType(module, STR.Component);
+ if (moduleType == null)
+ return null;
+
+ Function1<Variable, List<Tuple3>> function = getUCTextGridFunctionCached(graph, moduleType);
+ if (function == null)
+ return null;
+
+ List<Tuple3> result;
+ try {
+ Variable variable = Variables.getVariable(graph, module);
+ Variable moduleVariable = Variables.possibleActiveVariable(graph, variable);
+ if (moduleVariable == null)
+ moduleVariable = variable;
+
+ result = Simantics.applySCLRead(graph, function, moduleVariable);
+ } catch (PendingVariableException e) {
+ result = Collections.singletonList(new Tuple3("<pending>", "", ""));
+ }
+
+ Point2D point;
+ DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+ if (graph.isInstanceOf(mapElement, DN.Vertex)) {
+ double[] coords = graph.getRelatedValue(mapElement, DIA.HasLocation);
+ point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double(coords[0], coords[1]), null);
+ }
+ else if (graph.isInstanceOf(mapElement, DN.Edge)) {
+ Resource v1 = graph.getSingleObject(mapElement, DN.HasStartVertex);
+ double[] coords1 = graph.getRelatedValue(v1, DIA.HasLocation);
+ Resource v2 = graph.getSingleObject(mapElement, DN.HasEndVertex);
+ double[] coords2 = graph.getRelatedValue(v2, DIA.HasLocation);
+ point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double((coords1[0] + coords2[0]) / 2, (coords1[1] + coords2[1]) / 2), null);
+ }
+ else {
+ return null;
+ }
+
+ return new StyleResult(point, result);
+ }
+
+ @Override
+ public void applyStyleForNode(EvaluationContext observer, INode parent, StyleResult results) {
+ if (results == null) {
+ cleanupStyleForNode(observer, parent);
+ return;
+ }
+
+ DistrictNetworkHoverInfoNode node = ProfileVariables.claimChild(parent, "*", DistrictNetworkHoverInfoNode.NODE_KEY, DistrictNetworkHoverInfoNode.class, observer);
+ if (node == null)
+ return;
+
+ node.setLabels(results.getLabels());
+ node.setOrigin(results.getOrigin());
+ }
+
+ @Override
+ protected void cleanupStyleForNode(EvaluationContext observer, INode node) {
+ ProfileVariables.denyChild(node, "*", DistrictNetworkHoverInfoNode.NODE_KEY);
+ }
+
+ private static Function1<Variable, List<Tuple3>> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType)
+ throws DatabaseException {
+ return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance());
+ }
+
+ private static final class UCTextGridFunctionRequest extends ResourceRead<Function1<Variable, List<Tuple3>>> {
+ public UCTextGridFunctionRequest(Resource resource) {
+ super(resource);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Function1<Variable, List<Tuple3>> perform(ReadGraph graph) throws DatabaseException {
+ Resource actionsModule = Layer0Utils.getPossibleChild(graph, resource, ACTIONS_MODULE);
+ if (actionsModule == null || !graph.isInstanceOf(actionsModule, Layer0.getInstance(graph).SCLModule))
+ return null;
+
+ String uri = graph.getURI(actionsModule);
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.get("graph");
+ try {
+ sclContext.put("graph", graph);
+ return (Function1<Variable, List<Tuple3>>) SCLOsgi.MODULE_REPOSITORY.getValue(uri, HOVER_CONTRIBUTION);
+ } catch (ValueNotFound e1) {
+ return null;
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+ }
+}
import org.simantics.district.network.ModelledCRS;
import org.simantics.maps.MapScalingTransform;
+import org.simantics.scenegraph.utils.GeometryUtils;
public class DistrictNetworkNodeUtils {
public static double calculateScaleRecip(AffineTransform tr) {
int zoomLevel = MapScalingTransform.zoomLevel(tr);
- double t = 1.0 / Math.sqrt(zoomLevel);
+ double t = 1.0 / (getScale(tr) * Math.sqrt(zoomLevel));
return t;
}
+
+ static double getScale(AffineTransform tr) {
+ double scale;
+ scale = GeometryUtils.getScale(tr);
+ scale = Math.max(4096, Math.min(scale, 32768));
+ return scale;
+ }
}
import java.awt.geom.Rectangle2D;
import org.simantics.district.network.ui.adapters.DistrictNetworkVertex;
+import org.simantics.maps.MapScalingTransform;
import org.simantics.scenegraph.INode;
import org.simantics.scenegraph.ISelectionPainterNode;
import org.simantics.scenegraph.g2d.G2DNode;
import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.IG2DNode;
import org.simantics.scenegraph.g2d.nodes.SVGNode;
import org.simantics.scenegraph.utils.GeometryUtils;
import org.simantics.scenegraph.utils.NodeUtil;
-public class DistrictNetworkVertexNode extends G2DParentNode implements ISelectionPainterNode {
+public class DistrictNetworkVertexNode extends G2DParentNode implements ISelectionPainterNode, HoverSensitiveNode {
//private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkVertexNode.class);
private static final long serialVersionUID = -2641639101400236719L;
- private static final double left = -0.00005;
+ private static final double left = -15;
private static final double top = left;
- public static final double width = 0.0001;
+ public static final double width = 30;
private static final double height = width;
private static final BasicStroke STROKE = new BasicStroke((float)width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
private static final Color SELECTION_COLOR = new Color(255, 0, 255, 96);
private static final Rectangle2D NORMAL = new Rectangle2D.Double(left, top, width, height);
- private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 3, top * 3, width * 3, height * 3);
+ private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 2, top * 2, width * 2, height * 2);
private DistrictNetworkVertex vertex;
private transient Rectangle2D rect;
private transient AffineTransform symbolTransform;
- private double nodeSize = 3;
+ private double nodeSize = 1.0;
@Override
public void init() {
if (NodeUtil.isSelected(this, 1)) {
changeColor = true;
g2d.setColor(SELECTION_COLOR);
- BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float) (viewScaleRecip * nodeSize));
+ BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float)viewScaleRecip);
g2d.setStroke(ss);
g2d.draw(toDraw);
}
@Override
public Rectangle2D getBoundsInLocal() {
+ updateBounds();
return bounds;
}
private Rectangle2D calculateBounds(Rectangle2D rect) {
Point2D calcPoint = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), point);
- AffineTransform at = getTransform();
+ AffineTransform at = NodeUtil.getLocalToGlobalTransform(this);
+ at.concatenate(MapScalingTransform.INSTANCE);
double x = calcPoint.getX();
double y = calcPoint.getY();
- double widthh = width / at.getScaleX();
- double heighth = height / at.getScaleY();
- return new Rectangle2D.Double(x - widthh, y - heighth, widthh * 2, heighth * 2).getBounds2D();
+ double scaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(at);
+ double widthh = width * scaleRecip * nodeSize;
+ double heighth = height * scaleRecip * nodeSize;
+ if (rect == null)
+ rect = new Rectangle2D.Double();
+ rect.setRect(x - widthh/2, y - heighth/2, widthh, heighth);
+ return rect;
}
public void setVertex(DistrictNetworkVertex vertex) {
updateBounds();
}
- public boolean hover(boolean hover) {
-// if (hover && LOGGER.isDebugEnabled())
-// LOGGER.debug("Hovering " + this);
- boolean changed = false;
- if (this.hover != hover) {
- this.hover = hover;
- changed = true;
+ @Override
+ public boolean hover(boolean hover, boolean isConnectionTool) {
+ // Only react to hover when the connection tool is active
+ boolean doHover = hover && isConnectionTool;
+ boolean changed = this.hover != doHover;
+ this.hover = doHover;
+
+ for (IG2DNode child : getNodes()) {
+ if (child instanceof HoverSensitiveNode)
+ changed = ((HoverSensitiveNode)child).hover(hover, isConnectionTool) || changed;
}
+
return changed;
}
--- /dev/null
+package org.simantics.district.network.ui.nodes;
+
+public interface HoverSensitiveNode {
+ boolean hover(boolean hover, boolean isConnectionTool);
+}
@Override
protected boolean mouseMoved(MouseMovedEvent e) {
IToolMode mode = getToolMode();
- if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
- boolean repaint = false;
- Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
- if (participant.pickHoveredElement(p)) {
- repaint = true;
- }
- if (!nodes.isEmpty()) {
- currentMousePos = p;
-
- repaint();
- return true;
- }
- currentMousePos = null;
- if (repaint == true)
- repaint();
+ boolean repaint = false;
+ Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
+ boolean isConnectionTool = mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK);
+ if (participant.pickHoveredElement(p, isConnectionTool)) {
+ repaint = true;
+ }
+ if (!nodes.isEmpty()) {
+ currentMousePos = p;
+
+ repaint();
+ return true;
}
+ currentMousePos = null;
+ if (repaint == true)
+ repaint();
return super.mouseMoved(e);
}