\r
import java.awt.AlphaComposite;\r
import java.awt.BasicStroke;\r
+import java.awt.Color;\r
import java.awt.Composite;\r
import java.awt.Graphics2D;\r
+import java.awt.Shape;\r
import java.awt.Stroke;\r
import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
import java.awt.geom.Rectangle2D;\r
-import java.awt.image.BufferedImage;\r
-import java.io.IOException;\r
-import java.net.URL;\r
import java.util.ArrayList;\r
import java.util.Collection;\r
\r
-import javax.imageio.ImageIO;\r
-\r
import org.simantics.diagram.connection.RouteGraph;\r
import org.simantics.diagram.connection.RouteLineHalf;\r
import org.simantics.diagram.connection.actions.IAction;\r
import org.simantics.diagram.connection.rendering.IRouteGraphRenderer;\r
+import org.simantics.scenegraph.utils.Quality;\r
+import org.simantics.scenegraph.utils.QualityHints;\r
\r
/**\r
* @author Tuukka Lehtonen\r
}\r
}\r
\r
- static BufferedImage cross;\r
- static BufferedImage cut;\r
+ private static final Shape CROSS_SHAPE = ActionShapes.CROSS_SHAPE;\r
+ private static final Shape SCISSOR_SHAPE = ActionShapes.transformShape(ActionShapes.SCISSOR_SHAPE, 1, 1, 0, 0, -Math.PI/2);\r
\r
- static {\r
- cross = safeReadImage("cross.png");\r
- cut = safeReadImage("cut.png");\r
- }\r
+ private static final Color CROSS_COLOR = new Color(0xe4, 0x40, 0x61);\r
+ private static final Color SCISSOR_COLOR = new Color(20, 20, 20);\r
\r
public static final Stroke STROKE = new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);\r
- public static final AlphaComposite COMPOSITE = AlphaComposite.SrcOver.derive(0.6f);\r
+ public static final AlphaComposite NO_HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.8f);\r
+ public static final AlphaComposite HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.2f);\r
\r
public static final double DEGENERATED_LINE_LENGTH = 1;\r
- public static final double CUT_DIST_FROM_END = 0.5;\r
+ public static final double CUT_DIST_FROM_END = 0.75;\r
\r
RouteGraph rg;\r
\r
transient Collection<RouteLineHalf> lhs = new ArrayList<RouteLineHalf>();\r
transient AffineTransform transform = new AffineTransform();\r
- transient AffineTransform transform2 = new AffineTransform();\r
transient Rectangle2D rect = new Rectangle2D.Double();\r
+ transient Point2D point = new Point2D.Double();\r
\r
public HighlightActionPointsAction(RouteGraph rg) {\r
this.rg = rg;\r
\r
@Override\r
public void render(Graphics2D g, IRouteGraphRenderer renderer, double mouseX, double mouseY) {\r
- // Cannot perform cut or delete segment actions on connections between 2\r
- // terminals.\r
+ // Cannot perform cut or delete segment actions\r
+ // on connections between 2 terminals.\r
boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2);\r
boolean branchedConnection = rg.getTerminals().size() > 2;\r
+ if (!branchedConnection || simpleConnection)\r
+ return;\r
+\r
+ AffineTransform preTr = g.getTransform();\r
+ double realViewScale = 1.0 / getScale(preTr);\r
+ //System.out.println(realViewScale);\r
+ // Don't render any of the actions if they could not be seen anyway.\r
+ if (realViewScale > 0.7)\r
+ return;\r
\r
lhs.clear();\r
rg.getLineHalves(lhs);\r
\r
- AffineTransform preTr = g.getTransform();\r
- double viewScale = 1.0 / getScale(preTr);\r
- transform2.setToScale(viewScale, viewScale);\r
+ Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY);\r
+\r
Composite originalComposite = g.getComposite();\r
- g.setComposite(COMPOSITE);\r
+ Composite basicComposite = pick.action != null ? HIT_COMPOSITE : NO_HIT_COMPOSITE;\r
+ g.setComposite(basicComposite);\r
\r
- Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY);\r
+ // Always render these in high quality because otherwise the shapes\r
+ // will render with ugly artifacts when zoom level is a bit higher.\r
+ QualityHints origQualityHints = QualityHints.getQuality(g);\r
+ QualityHints.getHints(Quality.HIGH).setQuality(g);\r
\r
+ // Render line removal markers\r
if (!simpleConnection) {\r
- double crossW = cross.getWidth()*viewScale*.5;\r
- double crossH = cross.getHeight()*viewScale*.5;\r
-\r
- // Render line removal markers\r
+ g.setPaint(CROSS_COLOR);\r
for (RouteLineHalf lh : lhs) {\r
-// if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH)\r
-// continue;\r
-// if (!lh.getLine().isTransient())\r
-// continue;\r
- if (lh.getLine().getTerminal() == null)\r
+ if (removeLocation(lh, point) == null)\r
continue;\r
- double x = lh.getLink().getX();\r
- double y = lh.getLink().getY();\r
- if (lh.getLine().isHorizontal()) {\r
- x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
- } else {\r
- y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
- }\r
-\r
boolean hit = pick.matches(Action.REMOVE, lh);\r
-\r
if (hit)\r
g.setComposite(originalComposite);\r
- transform.setToTranslation(x-crossW, y-crossH);\r
- g.transform(transform);\r
- g.drawImage(cross, transform2, null);\r
+ g.translate(point.getX(), point.getY());\r
+ g.fill(CROSS_SHAPE);\r
g.setTransform(preTr);\r
if (hit)\r
- g.setComposite(COMPOSITE);\r
+ g.setComposite(basicComposite);\r
}\r
}\r
\r
// Render reconnection markers if the connection is branched.\r
if (branchedConnection) {\r
- double cutW = cut.getWidth()*viewScale*.5;\r
- double cutH = cut.getHeight()*viewScale*.5;\r
-\r
- final double dist = CUT_DIST_FROM_END;\r
+ g.setPaint(SCISSOR_COLOR);\r
for (RouteLineHalf lh : lhs) {\r
- if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+ if (reconnectLocation(lh, point) == null)\r
continue;\r
- double x = lh.getLink().getX();\r
- double y = lh.getLink().getY();\r
- if (lh.getLine().isHorizontal()) {\r
- if (lh.getLink() == lh.getLine().getBegin())\r
- x += dist*2;\r
- else\r
- x -= dist*2;\r
- } else {\r
- if (lh.getLink() == lh.getLine().getBegin())\r
- y += dist*2;\r
- else\r
- y -= dist*2;\r
- }\r
-\r
boolean hit = pick.matches(Action.RECONNECT, lh);\r
-\r
if (hit)\r
g.setComposite(originalComposite);\r
- transform.setToTranslation(x-cutW, y-cutH);\r
- if (!lh.getLine().isHorizontal()) {\r
- transform.rotate(Math.PI/2, cutW, cutH);\r
- }\r
+ transform.setToTranslation(point.getX(), point.getY());\r
+ if (!lh.getLine().isHorizontal())\r
+ transform.rotate(Math.PI/2);\r
+ transform.translate(0, 0.35);\r
g.transform(transform);\r
- g.drawImage(cut, transform2, null);\r
+ g.fill(SCISSOR_SHAPE);\r
g.setTransform(preTr);\r
if (hit)\r
- g.setComposite(COMPOSITE);\r
+ g.setComposite(basicComposite);\r
}\r
}\r
\r
+ origQualityHints.setQuality(g);\r
g.setComposite(originalComposite);\r
}\r
\r
if (!branchedConnection || simpleConnection || viewTr == null)\r
return Pick.MISS;\r
\r
- lhs.clear();\r
- rg.getLineHalves(lhs);\r
+ double viewScale = 1.0 / getScale(viewTr);\r
+ if (viewScale > 0.7)\r
+ return Pick.MISS;\r
\r
+ double nearest = Double.MAX_VALUE;\r
RouteLineHalf selected = null;\r
Action selectedAction = null;\r
- double nearest = Double.MAX_VALUE;\r
- double viewScale = 1.0 / getScale(viewTr);\r
\r
+ // Pick line removal markers\r
if (!simpleConnection) {\r
- double crossW = cross.getWidth()*viewScale*.5;\r
- double crossH = cross.getHeight()*viewScale*.5;\r
-\r
- // Render line removal markers\r
+ double s = ActionShapes.CROSS_WIDTH * 0.25;\r
for (RouteLineHalf lh : lhs) {\r
-// if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH)\r
-// continue;\r
-// if (!lh.getLine().isTransient())\r
-// continue;\r
- if (lh.getLine().getTerminal() == null)\r
+ if (removeLocation(lh, point) == null)\r
continue;\r
- double x = lh.getLink().getX();\r
- double y = lh.getLink().getY();\r
- if (lh.getLine().isHorizontal()) {\r
- x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
- } else {\r
- y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
- }\r
-\r
- rect.setFrameFromCenter(x, y, x-crossW, y-crossH);\r
+ double x = point.getX();\r
+ double y = point.getY();\r
+ rect.setFrameFromCenter(x, y, x-s, y-s);\r
boolean hit = rect.contains(mouseX, mouseY);\r
if (hit) {\r
double distSq = distSq(x, y, mouseX, mouseY);\r
}\r
}\r
\r
- // Render reconnection markers if the connection is branched.\r
+ // Pick reconnection markers if the connection is branched.\r
if (branchedConnection) {\r
- double cutW = cut.getWidth()*viewScale*.5;\r
- double cutH = cut.getHeight()*viewScale*.5;\r
-\r
- final double dist = CUT_DIST_FROM_END;\r
+ double w = ActionShapes.SCISSOR_HEIGHT * 0.4;\r
+ double h = ActionShapes.SCISSOR_WIDTH * 0.3;\r
for (RouteLineHalf lh : lhs) {\r
- if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+ if (reconnectLocation(lh, point) == null)\r
continue;\r
- double x = lh.getLink().getX();\r
- double y = lh.getLink().getY();\r
- if (lh.getLine().isHorizontal()) {\r
- if (lh.getLink() == lh.getLine().getBegin())\r
- x += dist*2;\r
- else\r
- x -= dist*2;\r
- } else {\r
- if (lh.getLink() == lh.getLine().getBegin())\r
- y += dist*2;\r
- else\r
- y -= dist*2;\r
- }\r
-\r
- rect.setFrameFromCenter(x, y, x-cutW, y-cutH);\r
+ double x = point.getX();\r
+ double y = point.getY();\r
+ rect.setFrameFromCenter(x, y, x-w, y-h);\r
boolean hit = rect.contains(mouseX, mouseY);\r
if (hit) {\r
double distSq = distSq(x, y, mouseX, mouseY);\r
if (distSq < nearest) {\r
- nearest = dist;\r
+ nearest = distSq;\r
selected = lh;\r
selectedAction = Action.RECONNECT;\r
}\r
return selected == null ? Pick.MISS : new Pick(selectedAction, selected);\r
}\r
\r
+ private static Point2D removeLocation(RouteLineHalf lh, Point2D p) {\r
+ if (lh.getLine().getTerminal() == null)\r
+ return null;\r
+\r
+ double x = lh.getLink().getX();\r
+ double y = lh.getLink().getY();\r
+ if (lh.getLine().isHorizontal()) {\r
+ x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5;\r
+ } else {\r
+ y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5;\r
+ }\r
+ p.setLocation(x, y);\r
+ return p;\r
+ }\r
+\r
+ private static Point2D reconnectLocation(RouteLineHalf lh, Point2D p) {\r
+ if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3)\r
+ return null;\r
+\r
+ final double dist = CUT_DIST_FROM_END;\r
+ double x = lh.getLink().getX();\r
+ double y = lh.getLink().getY();\r
+ if (lh.getLine().isHorizontal()) {\r
+ if (lh.getLink() == lh.getLine().getBegin())\r
+ x += dist*2;\r
+ else\r
+ x -= dist*2;\r
+ } else {\r
+ if (lh.getLink() == lh.getLine().getBegin())\r
+ y += dist*2;\r
+ else\r
+ y -= dist*2;\r
+ }\r
+ p.setLocation(x, y);\r
+ return p;\r
+ }\r
+\r
private static double distSq(double x1, double y1, double x2, double y2) {\r
double dx = x2 - x1;\r
double dy = y2 - y1;\r
return Math.sqrt(Math.abs(m00*m11 - m10*m01));\r
}\r
\r
- private static BufferedImage safeReadImage(String name) {\r
- try {\r
- URL url = HighlightActionPointsAction.class.getResource(name);\r
- return ImageIO.read(url);\r
- } catch (IOException e) {\r
- return null;\r
- }\r
- }\r
-\r
}\r