X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fparticipant%2FRouteGraphConnectTool.java;h=7454a2f3986cfff025242c5d9557876eaa53f809;hb=617b9475710b80a125597f222f9777224972ce72;hp=4cccea938270b6b8ac0b50baf6ac91d2b190528a;hpb=c8cce62f9952ab3f6db451d2f22d969b4e777eaa;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java index 4cccea938..7454a2f39 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/RouteGraphConnectTool.java @@ -16,6 +16,7 @@ import java.awt.AlphaComposite; import java.awt.Composite; import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayDeque; @@ -24,6 +25,7 @@ import java.util.Collection; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; import org.simantics.Simantics; @@ -32,7 +34,6 @@ import org.simantics.db.WriteGraph; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.connection.RouteGraph; -import org.simantics.diagram.connection.RouteGraphConnectionClass; import org.simantics.diagram.connection.RouteLine; import org.simantics.diagram.connection.RoutePoint; import org.simantics.diagram.connection.RouteTerminal; @@ -41,6 +42,7 @@ import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; import org.simantics.diagram.connection.rendering.arrows.ArrowLineEndStyle; import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle; import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle; +import org.simantics.diagram.connection.segments.Segment; import org.simantics.diagram.synchronization.ISynchronizationContext; import org.simantics.diagram.synchronization.SynchronizationHints; import org.simantics.diagram.synchronization.graph.RouteGraphConnection; @@ -76,6 +78,7 @@ import org.simantics.g2d.element.handler.impl.BranchPointTerminal; import org.simantics.g2d.element.impl.Element; import org.simantics.g2d.elementclass.FlagClass; import org.simantics.g2d.elementclass.FlagHandler; +import org.simantics.g2d.elementclass.RouteGraphConnectionClass; import org.simantics.g2d.participant.TransformUtil; import org.simantics.g2d.utils.geom.DirectionSet; import org.simantics.scenegraph.g2d.G2DParentNode; @@ -85,6 +88,7 @@ import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent; import org.simantics.scenegraph.g2d.events.MouseEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; import org.simantics.scenegraph.g2d.events.command.CommandEvent; import org.simantics.scenegraph.g2d.events.command.Commands; @@ -477,6 +481,10 @@ public class RouteGraphConnectTool extends AbstractMode { if (me instanceof MouseButtonPressedEvent) return processMouseButtonPress((MouseButtonPressedEvent) me); + // #7653: Support creating connections between terminals without lifting mouse button in between. + if (me instanceof MouseButtonReleasedEvent) + return processMouseButtonRelease((MouseButtonReleasedEvent) me); + return false; } @@ -497,29 +505,31 @@ public class RouteGraphConnectTool extends AbstractMode { endFlagNode.setTransform(AffineTransform.getTranslateInstance(mouseCanvasPos.getX(), mouseCanvasPos.getY())); } - TerminalInfo ti = pi.pickTerminal(me.controlPosition); - if (ti != null) { - Object canConnect = canConnect(ti.e, ti.t); - if (canConnect != null) { - connectionJudgment = (ConnectionJudgement) canConnect; + List tis = pi.pickTerminals(me.controlPosition); + tis = TerminalUtil.findNearestOverlappingTerminals(tis); + if (!tis.isEmpty()) { + for (TerminalInfo ti : tis) { + Object canConnect = canConnect(ti.e, ti.t); - if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) { - controlPoints.getLast() - .setPosition(ti.posDia) - .setAttachedToTerminal(ti); + if (canConnect != null) { + connectionJudgment = (ConnectionJudgement) canConnect; - endTerminal = ti; + if (!isEndingInFlag() || !TerminalUtil.isSameTerminal(ti, endTerminal)) { + controlPoints.getLast().setPosition(ti.posDia).setAttachedToTerminal(ti); - connect(ti); - - } + endTerminal = ti; + + connect(ti); - // Make sure that we are ending with a flag if ALT is pressed - // and no end terminal is defined. - endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)); + } - updateSG(new Point2D.Double(ti.posDia.getTranslateX(), ti.posDia.getTranslateY())); - return false; + // Make sure that we are ending with a flag if ALT is pressed + // and no end terminal is defined. + endWithoutTerminal(lastMouseCanvasPos, shouldEndWithFlag(me)); + + updateSG(new Point2D.Double(ti.posDia.getTranslateX(), ti.posDia.getTranslateY())); + return false; + } } } @@ -566,10 +576,8 @@ public class RouteGraphConnectTool extends AbstractMode { protected void disconnect(Point2D mouseCanvasPos) { setEndTerminal(mouseCanvasPos.getX(), mouseCanvasPos.getY(), null, 0xf); } - - protected boolean processMouseButtonPress(MouseButtonPressedEvent e) { - MouseButtonEvent me = e; + protected boolean processMouseButtonPress(MouseButtonEvent me) { // Do nothing before the mouse has moved at least a little. // This prevents the user from ending the connection right where // it started. @@ -585,9 +593,7 @@ public class RouteGraphConnectTool extends AbstractMode { snapAdvisor.snap(mouseCanvasPos); // Clicked on an allowed end terminal. End connection & end mode. - if (isEndTerminalDefined()) { - createConnection(); - remove(); + if (tryEndConnection()) { return true; } else { // Finish connection in thin air only if the @@ -617,6 +623,28 @@ public class RouteGraphConnectTool extends AbstractMode { return false; } + private int mouseLeftReleaseCount = 0; + + protected boolean processMouseButtonRelease(MouseButtonReleasedEvent me) { + if (me.button == MouseEvent.LEFT_BUTTON + && ++mouseLeftReleaseCount == 1) { + return tryEndConnection(); + } + return false; + } + + /** + * @return true if connection was successfully ended + */ + private boolean tryEndConnection() { + if (isEndTerminalDefined()) { + createConnection(); + remove(); + return true; + } + return false; + } + protected boolean cancelPreviousBend() { if (!routePointsAllowed()) return false; @@ -816,9 +844,9 @@ public class RouteGraphConnectTool extends AbstractMode { // ------------------------------------------------------------------------ - static RouteGraphTarget pickRouteGraphConnection(IDiagram diagram, Shape pickShape, double pickDistance) { + static RouteGraphTarget pickRouteGraphConnection(ICanvasContext ctx, IDiagram diagram, Shape pickShape, double pickDistance) { ArrayList elements = new ArrayList(); - PickRequest req = new PickRequest(pickShape); + PickRequest req = new PickRequest(pickShape).context(ctx); DiagramUtils.pick(diagram, req, elements); for (Iterator it = elements.iterator(); it.hasNext();) { IElement e = it.next(); @@ -837,56 +865,53 @@ public class RouteGraphConnectTool extends AbstractMode { } private static RouteGraphTarget pickNearestRouteGraphConnection(ArrayList elements, double x, double y, double pd) { - // Find the nearest distance at which we get hits. - double hi = pd + 1; - double lo = hi * .01; - double limit = 0.5; - while (true) { - double delta = (hi - lo); - if (delta <= limit) - break; + Segment nearestSegment = null; + RouteLine nearestLine = null; + IElement nearestConnection = null; - pd = (lo + hi) * .5; - - boolean hit = false; - for (IElement connection : elements) { - RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE); - RouteLine line = rgn.getRouteGraph().pickLine(x, y, pd); - if (line != null) { - hit = true; - break; + double minDistanceSq = Double.MAX_VALUE; + + for (IElement connection : elements) { + RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE); + for (RouteLine line : rgn.getRouteGraph().getAllLines()) { + ArrayList segments = new ArrayList(); + line.collectSegments(segments); + for (Segment segment : segments) { + RoutePoint p1 = segment.p1; + RoutePoint p2 = segment.p2; + + double distanceSq = Line2D.ptSegDistSq(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y); + if (distanceSq < minDistanceSq && distanceSq < Math.pow(pd + rgn.getSelectionStrokeWidth() / 2, 2)) { + minDistanceSq = distanceSq; + nearestSegment = segment; + nearestLine = line; + nearestConnection = connection; + } } } - - if (hit) - hi = pd; - else - lo = pd; } - // Now that the nearest hitting distance is found, find the nearest intersection. - RouteGraphTarget nearestTarget = null; - double nearest = Double.MAX_VALUE; - for (IElement connection : elements) { - RouteGraphNode rgn = connection.getHint(RouteGraphConnectionClass.KEY_RG_NODE); - RouteLine line = rgn.getRouteGraph().pickLine(x, y, pd); - if (line == null) - continue; - - Point2D intersection = intersectionPoint(x, y, line); - if (intersection == null) - continue; - - double dx = intersection.getX() - x; - double dy = intersection.getY() - y; - double dist = Math.sqrt(dx*dx + dy*dy); - if (dist < nearest) { - nearest = dist; - nearestTarget = new RouteGraphTarget(connection, rgn, line, new Point2D.Double(x, y), intersection); + if (nearestSegment != null) { + RoutePoint p1 = nearestSegment.p1; + RoutePoint p2 = nearestSegment.p2; + double d = Math.pow(p2.getX() - p1.getX(), 2.0) + Math.pow(p2.getY() - p1.getY(), 2.0); + Point2D p; + if (d == 0) { + p = new Point2D.Double(p1.getX(), p1.getY()); + } else { + double u = ((x - p1.getX()) * (p2.getX() - p1.getX()) + (y - p1.getY()) * (p2.getY() - p1.getY())) / d; + if (u > 1.0) { + p = new Point2D.Double(p2.getX(), p2.getY()); + } else if (u <= 0.0) { + p = new Point2D.Double(p1.getX(), p1.getY()); + } else { + p = new Point2D.Double(p2.getX() * u + p1.getX() * (1.0-u), (p2.getY() * u + p1.getY() * (1.0- u))); + } } + return new RouteGraphTarget(nearestConnection, nearestConnection.getHint(RouteGraphConnectionClass.KEY_RG_NODE), nearestLine, new Point2D.Double(x, y), p); + } else { + return null; } - - return nearestTarget; } static Point2D intersectionPoint(double x, double y, RouteLine line) {