From: Reino Ruusu Date: Tue, 9 Apr 2019 13:13:53 +0000 (+0300) Subject: Hover label profile for district elements. X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fdistrict.git;a=commitdiff_plain;h=731368eea74c3292199315a38d6914b09b813632 Hover label profile for district elements. Also includes some improvements in edge and vertex rendering and selection. gitlab #44 Change-Id: I007153a4ccb0417f9c1ee6a745876d024f5e2c8d --- diff --git a/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph b/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph index a853d85e..b25be6f5 100644 --- a/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph +++ b/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph @@ -27,6 +27,9 @@ DN.HideStyle : DIA.Style 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 diff --git a/org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java b/org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java index a48137cf..bb845617 100644 --- a/org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java +++ b/org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java @@ -58,6 +58,7 @@ public class DistrictNetworkResource { 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; @@ -357,6 +358,7 @@ public class DistrictNetworkResource { 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"; @@ -666,6 +668,7 @@ public class DistrictNetworkResource { 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); diff --git a/org.simantics.district.network.ui/adapters.xml b/org.simantics.district.network.ui/adapters.xml index 590cb0c6..77d82eb4 100644 --- a/org.simantics.district.network.ui/adapters.xml +++ b/org.simantics.district.network.ui/adapters.xml @@ -23,6 +23,10 @@ + + + diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java index d420edc7..91e48251 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java @@ -3,11 +3,15 @@ package org.simantics.district.network.ui; 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; @@ -18,6 +22,7 @@ import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant; 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; @@ -58,30 +63,41 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant { 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 pickables = new ArrayList(); pick.pick(diagram, req, pickables); List 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 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 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; + } } } } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java index 34424739..ef2e21fe 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java @@ -4,6 +4,8 @@ import java.awt.Color; 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; @@ -29,6 +31,7 @@ import org.simantics.g2d.element.handler.impl.SimpleElementLayers; 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; @@ -129,7 +132,7 @@ public class DistrictNetworkEdgeElement { 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; } @@ -162,21 +165,54 @@ public class DistrictNetworkEdgeElement { 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) { diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java index a989c561..1ff5eefa 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java @@ -115,9 +115,6 @@ public class DistrictNetworkVertexElement { 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: diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java index 74e8acdc..61aec5ce 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java @@ -79,10 +79,9 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection 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; } @@ -91,7 +90,7 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection 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); } @@ -157,6 +156,28 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection 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(); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java new file mode 100644 index 00000000..cb7053a0 --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java @@ -0,0 +1,109 @@ +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 labels; + + private Point2D origin; + + private boolean hover = false; + + private static AtomicReference 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 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); + } +} diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java new file mode 100644 index 00000000..590903e0 --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java @@ -0,0 +1,176 @@ +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 { + + private static final String ACTIONS_MODULE = "Actions"; + private static final String HOVER_CONTRIBUTION = "hoverContribution"; + + public class StyleResult { + Point2D origin; + List labels; + + public StyleResult(Point2D origin, List labels) { + this.origin = origin; + this.labels = labels; + } + + public Point2D getOrigin() { + return origin; + } + + public List 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> function = getUCTextGridFunctionCached(graph, moduleType); + if (function == null) + return null; + + List 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("", "", "")); + } + + 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> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType) + throws DatabaseException { + return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance()); + } + + private static final class UCTextGridFunctionRequest extends ResourceRead>> { + public UCTextGridFunctionRequest(Resource resource) { + super(resource); + } + + @SuppressWarnings("unchecked") + @Override + public Function1> 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>) SCLOsgi.MODULE_REPOSITORY.getValue(uri, HOVER_CONTRIBUTION); + } catch (ValueNotFound e1) { + return null; + } finally { + sclContext.put("graph", oldGraph); + } + } + } +} diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java index 20479a78..21e49b58 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java @@ -6,6 +6,7 @@ import java.awt.geom.Rectangle2D; import org.simantics.district.network.ModelledCRS; import org.simantics.maps.MapScalingTransform; +import org.simantics.scenegraph.utils.GeometryUtils; public class DistrictNetworkNodeUtils { @@ -38,7 +39,14 @@ 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; + } } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java index 929ad935..0533e311 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java @@ -9,30 +9,32 @@ import java.awt.geom.Point2D; 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; @@ -47,7 +49,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti private transient Rectangle2D rect; private transient AffineTransform symbolTransform; - private double nodeSize = 3; + private double nodeSize = 1.0; @Override public void init() { @@ -90,7 +92,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti 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); } @@ -127,6 +129,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti @Override public Rectangle2D getBoundsInLocal() { + updateBounds(); return bounds; } @@ -151,12 +154,17 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti 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) { @@ -164,14 +172,18 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti 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; } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java new file mode 100644 index 00000000..bf767851 --- /dev/null +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java @@ -0,0 +1,5 @@ +package org.simantics.district.network.ui.nodes; + +public interface HoverSensitiveNode { + boolean hover(boolean hover, boolean isConnectionTool); +} diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java index 524bf722..00728e89 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java @@ -276,22 +276,21 @@ public class NetworkDrawingNode extends G2DNode { @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); }