X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scenegraph%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fg2d%2Fnodes%2Fconnection%2FHighlightActionPointsAction.java;h=ff5871bc10363befcce43bccb3c804ba513fdf9d;hb=c684e246101adc478671274a9aae1979bfc02820;hp=7f7bd3cd9b99f434f16c68b6a55adfcd2ab3b357;hpb=6d390db460fe34d6b4f4ca29737f4e997c2d2d64;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java index 7f7bd3cd9..ff5871bc1 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/connection/HighlightActionPointsAction.java @@ -1,293 +1,293 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 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 - initial API and implementation - *******************************************************************************/ -package org.simantics.scenegraph.g2d.nodes.connection; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Collection; - -import org.simantics.diagram.connection.RouteGraph; -import org.simantics.diagram.connection.RouteLineHalf; -import org.simantics.diagram.connection.actions.IAction; -import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; -import org.simantics.scenegraph.utils.Quality; -import org.simantics.scenegraph.utils.QualityHints; - -/** - * @author Tuukka Lehtonen - */ -public class HighlightActionPointsAction implements IAction { - - public static enum Action { - REMOVE, - RECONNECT - } - - public static class Pick { - public static final Pick MISS = new Pick(null, null); - - Action action; - RouteLineHalf line; - - public Pick(Action action, RouteLineHalf line) { - this.action = action; - this.line = line; - } - - public boolean hasAction(Action action) { - return this.action == action; - } - - public boolean hasResult() { - return action != null && line != null; - } - - public boolean matches(Action action, RouteLineHalf line) { - if (this.action == null || this.line == null) - return false; - return this.action.equals(action) && this.line.equals(line); - } - } - - private static final Shape CROSS_SHAPE = ActionShapes.CROSS_SHAPE; - private static final Shape SCISSOR_SHAPE = ActionShapes.transformShape(ActionShapes.SCISSOR_SHAPE, 1, 1, 0, 0, -Math.PI/2); - - private static final Color CROSS_COLOR = new Color(0xe4, 0x40, 0x61); - private static final Color SCISSOR_COLOR = new Color(20, 20, 20); - - public static final Stroke STROKE = new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - public static final AlphaComposite NO_HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.8f); - public static final AlphaComposite HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.2f); - - public static final double DEGENERATED_LINE_LENGTH = 1; - public static final double CUT_DIST_FROM_END = 0.75; - - RouteGraph rg; - - transient Collection lhs = new ArrayList(); - transient AffineTransform transform = new AffineTransform(); - transient Rectangle2D rect = new Rectangle2D.Double(); - transient Point2D point = new Point2D.Double(); - - public HighlightActionPointsAction(RouteGraph rg) { - this.rg = rg; - } - - public void setRouteGraph(RouteGraph rg) { - this.rg = rg; - } - - @Override - public void render(Graphics2D g, IRouteGraphRenderer renderer, double mouseX, double mouseY) { - // Cannot perform cut or delete segment actions - // on connections between 2 terminals. - boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); - boolean branchedConnection = rg.getTerminals().size() > 2; - if (!branchedConnection || simpleConnection) - return; - - AffineTransform preTr = g.getTransform(); - double realViewScale = 1.0 / getScale(preTr); - //System.out.println(realViewScale); - // Don't render any of the actions if they could not be seen anyway. - if (realViewScale > 0.7) - return; - - lhs.clear(); - rg.getLineHalves(lhs); - - Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY); - - Composite originalComposite = g.getComposite(); - Composite basicComposite = pick.action != null ? HIT_COMPOSITE : NO_HIT_COMPOSITE; - g.setComposite(basicComposite); - - // Always render these in high quality because otherwise the shapes - // will render with ugly artifacts when zoom level is a bit higher. - QualityHints origQualityHints = QualityHints.getQuality(g); - QualityHints.getHints(Quality.HIGH).setQuality(g); - - // Render line removal markers - if (!simpleConnection) { - g.setPaint(CROSS_COLOR); - for (RouteLineHalf lh : lhs) { - if (removeLocation(lh, point) == null) - continue; - boolean hit = pick.matches(Action.REMOVE, lh); - if (hit) - g.setComposite(originalComposite); - g.translate(point.getX(), point.getY()); - g.fill(CROSS_SHAPE); - g.setTransform(preTr); - if (hit) - g.setComposite(basicComposite); - } - } - - // Render reconnection markers if the connection is branched. - if (branchedConnection) { - g.setPaint(SCISSOR_COLOR); - for (RouteLineHalf lh : lhs) { - if (reconnectLocation(lh, point) == null) - continue; - boolean hit = pick.matches(Action.RECONNECT, lh); - if (hit) - g.setComposite(originalComposite); - transform.setToTranslation(point.getX(), point.getY()); - if (!lh.getLine().isHorizontal()) - transform.rotate(Math.PI/2); - transform.translate(0, 0.35); - g.transform(transform); - g.fill(SCISSOR_SHAPE); - g.setTransform(preTr); - if (hit) - g.setComposite(basicComposite); - } - } - - origQualityHints.setQuality(g); - g.setComposite(originalComposite); - } - - public Pick pickAction(RouteGraph rg, AffineTransform viewTr, double mouseX, double mouseY) { - boolean branchedConnection = rg.getTerminals().size() > 2; - boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); - if (!branchedConnection || simpleConnection) - return null; - - lhs.clear(); - return pickAction(rg, rg.getLineHalves(lhs), viewTr, mouseX, mouseY); - } - - public Pick pickAction(RouteGraph rg, Collection lhs, AffineTransform viewTr, double mouseX, double mouseY) { - boolean branchedConnection = rg.getTerminals().size() > 2; - boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); - if (!branchedConnection || simpleConnection || viewTr == null) - return Pick.MISS; - - double viewScale = 1.0 / getScale(viewTr); - if (viewScale > 0.7) - return Pick.MISS; - - double nearest = Double.MAX_VALUE; - RouteLineHalf selected = null; - Action selectedAction = null; - - // Pick line removal markers - if (!simpleConnection) { - double s = ActionShapes.CROSS_WIDTH * 0.25; - for (RouteLineHalf lh : lhs) { - if (removeLocation(lh, point) == null) - continue; - double x = point.getX(); - double y = point.getY(); - rect.setFrameFromCenter(x, y, x-s, y-s); - boolean hit = rect.contains(mouseX, mouseY); - if (hit) { - double distSq = distSq(x, y, mouseX, mouseY); - if (distSq < nearest) { - nearest = distSq; - selected = lh; - selectedAction = Action.REMOVE; - } - } - } - } - - // Pick reconnection markers if the connection is branched. - if (branchedConnection) { - double w = ActionShapes.SCISSOR_HEIGHT * 0.4; - double h = ActionShapes.SCISSOR_WIDTH * 0.3; - for (RouteLineHalf lh : lhs) { - if (reconnectLocation(lh, point) == null) - continue; - double x = point.getX(); - double y = point.getY(); - rect.setFrameFromCenter(x, y, x-w, y-h); - boolean hit = rect.contains(mouseX, mouseY); - if (hit) { - double distSq = distSq(x, y, mouseX, mouseY); - if (distSq < nearest) { - nearest = distSq; - selected = lh; - selectedAction = Action.RECONNECT; - } - } - } - } - - return selected == null ? Pick.MISS : new Pick(selectedAction, selected); - } - - private static Point2D removeLocation(RouteLineHalf lh, Point2D p) { - if (lh.getLine().getTerminal() == null) - return null; - - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5; - } else { - y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5; - } - p.setLocation(x, y); - return p; - } - - private static Point2D reconnectLocation(RouteLineHalf lh, Point2D p) { - if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3) - return null; - - final double dist = CUT_DIST_FROM_END; - double x = lh.getLink().getX(); - double y = lh.getLink().getY(); - if (lh.getLine().isHorizontal()) { - if (lh.getLink() == lh.getLine().getBegin()) - x += dist*2; - else - x -= dist*2; - } else { - if (lh.getLink() == lh.getLine().getBegin()) - y += dist*2; - else - y -= dist*2; - } - p.setLocation(x, y); - return p; - } - - private static double distSq(double x1, double y1, double x2, double y2) { - double dx = x2 - x1; - double dy = y2 - y1; - return dx * dx + dy * dy; - } - - private static double getScale(AffineTransform at) - { - double m00 = at.getScaleX(); - double m11 = at.getScaleY(); - double m10 = at.getShearY(); - double m01 = at.getShearX(); - - return Math.sqrt(Math.abs(m00*m11 - m10*m01)); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2011 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 - initial API and implementation + *******************************************************************************/ +package org.simantics.scenegraph.g2d.nodes.connection; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.diagram.connection.RouteGraph; +import org.simantics.diagram.connection.RouteLineHalf; +import org.simantics.diagram.connection.actions.IAction; +import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; +import org.simantics.scenegraph.utils.Quality; +import org.simantics.scenegraph.utils.QualityHints; + +/** + * @author Tuukka Lehtonen + */ +public class HighlightActionPointsAction implements IAction { + + public static enum Action { + REMOVE, + RECONNECT + } + + public static class Pick { + public static final Pick MISS = new Pick(null, null); + + Action action; + RouteLineHalf line; + + public Pick(Action action, RouteLineHalf line) { + this.action = action; + this.line = line; + } + + public boolean hasAction(Action action) { + return this.action == action; + } + + public boolean hasResult() { + return action != null && line != null; + } + + public boolean matches(Action action, RouteLineHalf line) { + if (this.action == null || this.line == null) + return false; + return this.action.equals(action) && this.line.equals(line); + } + } + + private static final Shape CROSS_SHAPE = ActionShapes.CROSS_SHAPE; + private static final Shape SCISSOR_SHAPE = ActionShapes.transformShape(ActionShapes.SCISSOR_SHAPE, 1, 1, 0, 0, -Math.PI/2); + + private static final Color CROSS_COLOR = new Color(0xe4, 0x40, 0x61); + private static final Color SCISSOR_COLOR = new Color(20, 20, 20); + + public static final Stroke STROKE = new BasicStroke(0.1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + public static final AlphaComposite NO_HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.8f); + public static final AlphaComposite HIT_COMPOSITE = AlphaComposite.SrcOver.derive(0.2f); + + public static final double DEGENERATED_LINE_LENGTH = 1; + public static final double CUT_DIST_FROM_END = 0.75; + + RouteGraph rg; + + transient Collection lhs = new ArrayList(); + transient AffineTransform transform = new AffineTransform(); + transient Rectangle2D rect = new Rectangle2D.Double(); + transient Point2D point = new Point2D.Double(); + + public HighlightActionPointsAction(RouteGraph rg) { + this.rg = rg; + } + + public void setRouteGraph(RouteGraph rg) { + this.rg = rg; + } + + @Override + public void render(Graphics2D g, IRouteGraphRenderer renderer, double mouseX, double mouseY) { + // Cannot perform cut or delete segment actions + // on connections between 2 terminals. + boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); + boolean branchedConnection = rg.getTerminals().size() > 2; + if (!branchedConnection || simpleConnection) + return; + + AffineTransform preTr = g.getTransform(); + double realViewScale = 1.0 / getScale(preTr); + //System.out.println(realViewScale); + // Don't render any of the actions if they could not be seen anyway. + if (realViewScale > 0.7) + return; + + lhs.clear(); + rg.getLineHalves(lhs); + + Pick pick = pickAction(rg, lhs, preTr, mouseX, mouseY); + + Composite originalComposite = g.getComposite(); + Composite basicComposite = pick.action != null ? HIT_COMPOSITE : NO_HIT_COMPOSITE; + g.setComposite(basicComposite); + + // Always render these in high quality because otherwise the shapes + // will render with ugly artifacts when zoom level is a bit higher. + QualityHints origQualityHints = QualityHints.getQuality(g); + QualityHints.getHints(Quality.HIGH).setQuality(g); + + // Render line removal markers + if (!simpleConnection) { + g.setPaint(CROSS_COLOR); + for (RouteLineHalf lh : lhs) { + if (removeLocation(lh, point) == null) + continue; + boolean hit = pick.matches(Action.REMOVE, lh); + if (hit) + g.setComposite(originalComposite); + g.translate(point.getX(), point.getY()); + g.fill(CROSS_SHAPE); + g.setTransform(preTr); + if (hit) + g.setComposite(basicComposite); + } + } + + // Render reconnection markers if the connection is branched. + if (branchedConnection) { + g.setPaint(SCISSOR_COLOR); + for (RouteLineHalf lh : lhs) { + if (reconnectLocation(lh, point) == null) + continue; + boolean hit = pick.matches(Action.RECONNECT, lh); + if (hit) + g.setComposite(originalComposite); + transform.setToTranslation(point.getX(), point.getY()); + if (!lh.getLine().isHorizontal()) + transform.rotate(Math.PI/2); + transform.translate(0, 0.35); + g.transform(transform); + g.fill(SCISSOR_SHAPE); + g.setTransform(preTr); + if (hit) + g.setComposite(basicComposite); + } + } + + origQualityHints.setQuality(g); + g.setComposite(originalComposite); + } + + public Pick pickAction(RouteGraph rg, AffineTransform viewTr, double mouseX, double mouseY) { + boolean branchedConnection = rg.getTerminals().size() > 2; + boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); + if (!branchedConnection || simpleConnection) + return null; + + lhs.clear(); + return pickAction(rg, rg.getLineHalves(lhs), viewTr, mouseX, mouseY); + } + + public Pick pickAction(RouteGraph rg, Collection lhs, AffineTransform viewTr, double mouseX, double mouseY) { + boolean branchedConnection = rg.getTerminals().size() > 2; + boolean simpleConnection = (rg.isSimpleConnection() || rg.getTerminals().size() <= 2); + if (!branchedConnection || simpleConnection || viewTr == null) + return Pick.MISS; + + double viewScale = 1.0 / getScale(viewTr); + if (viewScale > 0.7) + return Pick.MISS; + + double nearest = Double.MAX_VALUE; + RouteLineHalf selected = null; + Action selectedAction = null; + + // Pick line removal markers + if (!simpleConnection) { + double s = ActionShapes.CROSS_WIDTH * 0.25; + for (RouteLineHalf lh : lhs) { + if (removeLocation(lh, point) == null) + continue; + double x = point.getX(); + double y = point.getY(); + rect.setFrameFromCenter(x, y, x-s, y-s); + boolean hit = rect.contains(mouseX, mouseY); + if (hit) { + double distSq = distSq(x, y, mouseX, mouseY); + if (distSq < nearest) { + nearest = distSq; + selected = lh; + selectedAction = Action.REMOVE; + } + } + } + } + + // Pick reconnection markers if the connection is branched. + if (branchedConnection) { + double w = ActionShapes.SCISSOR_HEIGHT * 0.4; + double h = ActionShapes.SCISSOR_WIDTH * 0.3; + for (RouteLineHalf lh : lhs) { + if (reconnectLocation(lh, point) == null) + continue; + double x = point.getX(); + double y = point.getY(); + rect.setFrameFromCenter(x, y, x-w, y-h); + boolean hit = rect.contains(mouseX, mouseY); + if (hit) { + double distSq = distSq(x, y, mouseX, mouseY); + if (distSq < nearest) { + nearest = distSq; + selected = lh; + selectedAction = Action.RECONNECT; + } + } + } + } + + return selected == null ? Pick.MISS : new Pick(selectedAction, selected); + } + + private static Point2D removeLocation(RouteLineHalf lh, Point2D p) { + if (lh.getLine().getTerminal() == null) + return null; + + double x = lh.getLink().getX(); + double y = lh.getLink().getY(); + if (lh.getLine().isHorizontal()) { + x = (lh.getLine().getBegin().getX() + lh.getLine().getEnd().getX()) * .5; + } else { + y = (lh.getLine().getBegin().getY() + lh.getLine().getEnd().getY()) * .5; + } + p.setLocation(x, y); + return p; + } + + private static Point2D reconnectLocation(RouteLineHalf lh, Point2D p) { + if (lh.getLine().getLength() < DEGENERATED_LINE_LENGTH*3) + return null; + + final double dist = CUT_DIST_FROM_END; + double x = lh.getLink().getX(); + double y = lh.getLink().getY(); + if (lh.getLine().isHorizontal()) { + if (lh.getLink() == lh.getLine().getBegin()) + x += dist*2; + else + x -= dist*2; + } else { + if (lh.getLink() == lh.getLine().getBegin()) + y += dist*2; + else + y -= dist*2; + } + p.setLocation(x, y); + return p; + } + + private static double distSq(double x1, double y1, double x2, double y2) { + double dx = x2 - x1; + double dy = y2 - y1; + return dx * dx + dy * dy; + } + + private static double getScale(AffineTransform at) + { + double m00 = at.getScaleX(); + double m11 = at.getScaleY(); + double m10 = at.getShearY(); + double m01 = at.getShearX(); + + return Math.sqrt(Math.abs(m00*m11 - m10*m01)); + } + +}