X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fdiagram%2Fparticipant%2FTerminalPainter.java;h=e4c7ac2011e0b0dcf2a70f29dd9dc800e8593a22;hb=c26409b1caf2f1e560d37c5befd11b442399c3fe;hp=54e4a8eb7b9b7031e02948a563064b03ed98f15c;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/TerminalPainter.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/TerminalPainter.java index 54e4a8eb7..e4c7ac201 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/TerminalPainter.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/TerminalPainter.java @@ -1,304 +1,304 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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.g2d.diagram.participant; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.geom.AffineTransform; -import java.awt.geom.Path2D; -import java.awt.geom.Rectangle2D; -import java.util.Collection; -import java.util.List; - -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; -import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; -import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor; -import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil; -import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo; -import org.simantics.g2d.participant.MouseUtil; -import org.simantics.g2d.participant.TransformUtil; -import org.simantics.g2d.participant.MouseUtil.MouseInfo; -import org.simantics.g2d.utils.GeometryUtils; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; -import org.simantics.scenegraph.g2d.nodes.ShapeNode; -import org.simantics.scenegraph.utils.ColorUtil; -import org.simantics.utils.datastructures.hints.HintListenerAdapter; -import org.simantics.utils.datastructures.hints.IHintListener; -import org.simantics.utils.datastructures.hints.IHintObservable; -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; - -/** - * Paints terminals of elements. - * - * @author Toni Kalajainen - */ -public class TerminalPainter extends AbstractDiagramParticipant { - - public static final int PAINT_PRIORITY = ElementPainter.ELEMENT_PAINT_PRIORITY + 10; - - public interface TerminalHoverStrategy { - /** - * - * @return true if highlighting is enabled at the moment in - * general. This may depend on the current modifier key state - * for example. - */ - boolean highlightEnabled(); - - /** - * Checks whether the specified terminal should be highlighted at the - * moment or not. Whether to highlight or not may depend for example on - * the current modifier key state. - * - * @param ti - * @return - */ - boolean highlight(TerminalInfo ti); - }; - - public static abstract class ChainedHoverStrategy implements TerminalHoverStrategy { - TerminalHoverStrategy orig; - public ChainedHoverStrategy(TerminalHoverStrategy orig) { - this.orig = orig; - } - @Override - public boolean highlightEnabled() { - return orig == null ? false : orig.highlightEnabled(); - } - @Override - public final boolean highlight(TerminalInfo ti) { - boolean ret = canHighlight(ti); - return (ret || orig == null) ? ret : orig.highlight(ti); - } - public abstract boolean canHighlight(TerminalInfo ti); - } - - /** - * If this hint is set to a Callable, the terminal painter will use - * the callable to evaluate whether it should highlight terminal hovers or - * not. - */ - public static final Key TERMINAL_HOVER_STRATEGY = new KeyOf(TerminalHoverStrategy.class); - -// private static final Stroke STROKE1 = new BasicStroke(1.0f); -// private static final Stroke STROKE15 = new BasicStroke(1.5f); - private static final Stroke STROKE25 = new BasicStroke(2.5f); - -// private final static Stroke TERMINAL_STROKE = new BasicStroke(1.0f); - public static final Shape TERMINAL_SHAPE; - - @Dependency - protected TransformUtil util; - @Dependency - protected MouseUtil mice; - - @Dependency - protected PointerInteractor pointerInteractor; - - protected boolean paintPointTerminals; - protected boolean paintAreaTerminals; - protected boolean paintHoverPointTerminals; - protected boolean paintHoverAreaTerminals; - - public TerminalPainter(boolean paintPointTerminals, boolean paintHoverPointTerminals, boolean paintAreaTerminals, boolean paintHoverAreaTerminals) - { - this.paintAreaTerminals = paintAreaTerminals; - this.paintPointTerminals = paintPointTerminals; - this.paintHoverAreaTerminals = paintHoverAreaTerminals; - this.paintHoverPointTerminals = paintHoverPointTerminals; - } - - @Override - public void addedToContext(ICanvasContext ctx) { - super.addedToContext(ctx); - - ctx.getHintStack().addKeyHintListener(getContext().getThreadAccess(), TERMINAL_HOVER_STRATEGY, hoverStrategyListener); - } - - @Override - public void removedFromContext(ICanvasContext ctx) { - ctx.getHintStack().removeKeyHintListener(getContext().getThreadAccess(), TERMINAL_HOVER_STRATEGY, hoverStrategyListener); - - super.removedFromContext(ctx); - } - - public boolean highlightEnabled() { - TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); - return strategy != null ? strategy.highlightEnabled() : true; - } - - public boolean highlightTerminal(TerminalInfo ti) { - TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); - return strategy != null ? strategy.highlight(ti) : true; - } - - @EventHandler(priority = 0) - public boolean handleMove(MouseMovedEvent me) { - if ( (paintHoverAreaTerminals && paintAreaTerminals) || - (paintHoverPointTerminals && paintPointTerminals) ) { - update(highlightEnabled()); - } - return false; - } - - protected G2DParentNode node = null; - - @SGInit - public void initSG(G2DParentNode parent) { - node = parent.addNode("hovering terminals", G2DParentNode.class); - node.setZIndex(PAINT_PRIORITY); - } - - @SGCleanup - public void cleanupSG() { - node.remove(); - node = null; - } - - public void update(boolean enabled) { - if (isRemoved()) - return; - - boolean repaint = false; - if(node == null) return; - if(node.getNodeCount() > 0) { - node.removeNodes(); - repaint = true; - } - if (enabled) { - - // Paint terminals normally - if (paintAreaTerminals || paintPointTerminals) { - List pickedTerminals = TerminalUtil.pickTerminals(diagram, null, paintPointTerminals, paintAreaTerminals); - paintTerminals(node, Color.BLUE, diagram, null, pickedTerminals, null); - if(pickedTerminals.size() > 0) repaint = true; - } - - if (paintHoverAreaTerminals || paintHoverPointTerminals) { - TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); - - AffineTransform invTx = util.getInverseTransform(); - if (invTx == null) { - System.err.println("NO CANVAS TRANSFORM INVERSE AVAILABLE, CANVAS TRANSFORM IS: " + util.getTransform()); - return; - } - - // Pick terminals - for (MouseInfo mi : mice.getMiceInfo().values()) { - Rectangle2D controlPickRect = getPickRectangle(mi.controlPosition.getX(), mi.controlPosition.getY()); - Shape canvasPickRect = GeometryUtils.transformShape(controlPickRect, invTx); - - List tis = TerminalUtil.pickTerminals(diagram, canvasPickRect, paintHoverAreaTerminals, paintHoverPointTerminals); - paintTerminals(node, Color.RED, diagram, canvasPickRect.getBounds2D(), tis, strategy); - if(tis.size() > 0) repaint = true; - } - } - } - if (repaint) { - setDirty(); - } - } - - public void paintTerminals(G2DParentNode parent, Color color, IDiagram diagram, Rectangle2D pickRect, Collection tis, TerminalHoverStrategy strategy) { - if (tis.isEmpty()) { - return; - } - G2DParentNode node = parent.getOrCreateNode(""+tis.hashCode(), G2DParentNode.class); - - double minDist = Double.MAX_VALUE; - double maxDist = 0; - TerminalInfo nearest = null; - if (pickRect != null) { - for (TerminalInfo ti : tis) { - double dx = ti.posDia.getTranslateX() - pickRect.getCenterX(); - double dy = ti.posDia.getTranslateY() - pickRect.getCenterY(); - double dist = Math.sqrt(dx*dx+dy*dy); - if (dist > maxDist) { - maxDist = dist; - } - if (dist < minDist) { - minDist = dist; - nearest = ti; - } - } - } - - for (TerminalInfo ti : tis) { - if (strategy != null && !strategy.highlight(ti)) - continue; - Shape shape = ti.shape != null ? ti.shape : getTerminalShape(); - //System.out.println("painting terminal " + ti + ": " + shape); - ShapeNode sn = node.getOrCreateNode("terminal_"+ti.hashCode(), ShapeNode.class); - sn.setShape(shape); - sn.setStroke(STROKE25); - sn.setScaleStroke(true); - if (pickRect != null) { - Color blendedColor = color; - if (ti != nearest) { - double dx = ti.posDia.getTranslateX() - pickRect.getCenterX(); - double dy = ti.posDia.getTranslateY() - pickRect.getCenterY(); - double dist = Math.sqrt(dx*dx+dy*dy); - double normalizedDistance = dist / maxDist; - final double maxFade = 0.5; - float alpha = (float)(1 - normalizedDistance*maxFade); - blendedColor = ColorUtil.withAlpha(ColorUtil.blend(color, Color.WHITE, normalizedDistance*maxFade), alpha); - } - sn.setColor(blendedColor); - } else { - sn.setColor(color); - } - sn.setTransform(ti.posDia); - sn.setFill(false); - } - } - - public Rectangle2D getTerminalShape() { - double pickDist = pointerInteractor.getPickDistance(); - return new Rectangle2D.Double(-pickDist - 0.5, -pickDist - 0.5, pickDist * 2 + 1, pickDist * 2 + 1); - } - - public Rectangle2D getPickRectangle(double x, double y) { - double pickDist = pointerInteractor.getPickDistance(); - Rectangle2D controlPickRect = new Rectangle2D.Double(x-pickDist, y-pickDist, pickDist*2+1, pickDist*2+1); - return controlPickRect; - } - - static { - Path2D.Double cross = new Path2D.Double(); - double s = 2; - cross.moveTo(-s, -s); - cross.lineTo(s, s); - cross.moveTo(-s, s); - cross.lineTo(s, -s); - TERMINAL_SHAPE = cross; - } - - IHintListener hoverStrategyListener = new HintListenerAdapter() { - @Override - public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { - hoverStrategyChanged((TerminalHoverStrategy) newValue); - } - }; - - protected void hoverStrategyChanged(TerminalHoverStrategy strategy) { - update(strategy != null ? strategy.highlightEnabled() : false); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 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.g2d.diagram.participant; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.Rectangle2D; +import java.util.Collection; +import java.util.List; + +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor; +import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil; +import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo; +import org.simantics.g2d.participant.MouseUtil; +import org.simantics.g2d.participant.TransformUtil; +import org.simantics.g2d.participant.MouseUtil.MouseInfo; +import org.simantics.g2d.utils.GeometryUtils; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; +import org.simantics.scenegraph.g2d.nodes.ShapeNode; +import org.simantics.scenegraph.utils.ColorUtil; +import org.simantics.utils.datastructures.hints.HintListenerAdapter; +import org.simantics.utils.datastructures.hints.IHintListener; +import org.simantics.utils.datastructures.hints.IHintObservable; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +/** + * Paints terminals of elements. + * + * @author Toni Kalajainen + */ +public class TerminalPainter extends AbstractDiagramParticipant { + + public static final int PAINT_PRIORITY = ElementPainter.ELEMENT_PAINT_PRIORITY + 10; + + public interface TerminalHoverStrategy { + /** + * + * @return true if highlighting is enabled at the moment in + * general. This may depend on the current modifier key state + * for example. + */ + boolean highlightEnabled(); + + /** + * Checks whether the specified terminal should be highlighted at the + * moment or not. Whether to highlight or not may depend for example on + * the current modifier key state. + * + * @param ti + * @return + */ + boolean highlight(TerminalInfo ti); + }; + + public static abstract class ChainedHoverStrategy implements TerminalHoverStrategy { + TerminalHoverStrategy orig; + public ChainedHoverStrategy(TerminalHoverStrategy orig) { + this.orig = orig; + } + @Override + public boolean highlightEnabled() { + return orig == null ? false : orig.highlightEnabled(); + } + @Override + public final boolean highlight(TerminalInfo ti) { + boolean ret = canHighlight(ti); + return (ret || orig == null) ? ret : orig.highlight(ti); + } + public abstract boolean canHighlight(TerminalInfo ti); + } + + /** + * If this hint is set to a Callable, the terminal painter will use + * the callable to evaluate whether it should highlight terminal hovers or + * not. + */ + public static final Key TERMINAL_HOVER_STRATEGY = new KeyOf(TerminalHoverStrategy.class); + +// private static final Stroke STROKE1 = new BasicStroke(1.0f); +// private static final Stroke STROKE15 = new BasicStroke(1.5f); + private static final Stroke STROKE25 = new BasicStroke(2.5f); + +// private final static Stroke TERMINAL_STROKE = new BasicStroke(1.0f); + public static final Shape TERMINAL_SHAPE; + + @Dependency + protected TransformUtil util; + @Dependency + protected MouseUtil mice; + + @Dependency + protected PointerInteractor pointerInteractor; + + protected boolean paintPointTerminals; + protected boolean paintAreaTerminals; + protected boolean paintHoverPointTerminals; + protected boolean paintHoverAreaTerminals; + + public TerminalPainter(boolean paintPointTerminals, boolean paintHoverPointTerminals, boolean paintAreaTerminals, boolean paintHoverAreaTerminals) + { + this.paintAreaTerminals = paintAreaTerminals; + this.paintPointTerminals = paintPointTerminals; + this.paintHoverAreaTerminals = paintHoverAreaTerminals; + this.paintHoverPointTerminals = paintHoverPointTerminals; + } + + @Override + public void addedToContext(ICanvasContext ctx) { + super.addedToContext(ctx); + + ctx.getHintStack().addKeyHintListener(getContext().getThreadAccess(), TERMINAL_HOVER_STRATEGY, hoverStrategyListener); + } + + @Override + public void removedFromContext(ICanvasContext ctx) { + ctx.getHintStack().removeKeyHintListener(getContext().getThreadAccess(), TERMINAL_HOVER_STRATEGY, hoverStrategyListener); + + super.removedFromContext(ctx); + } + + public boolean highlightEnabled() { + TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); + return strategy != null ? strategy.highlightEnabled() : true; + } + + public boolean highlightTerminal(TerminalInfo ti) { + TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); + return strategy != null ? strategy.highlight(ti) : true; + } + + @EventHandler(priority = 0) + public boolean handleMove(MouseMovedEvent me) { + if ( (paintHoverAreaTerminals && paintAreaTerminals) || + (paintHoverPointTerminals && paintPointTerminals) ) { + update(highlightEnabled()); + } + return false; + } + + protected G2DParentNode node = null; + + @SGInit + public void initSG(G2DParentNode parent) { + node = parent.addNode("hovering terminals", G2DParentNode.class); + node.setZIndex(PAINT_PRIORITY); + } + + @SGCleanup + public void cleanupSG() { + node.remove(); + node = null; + } + + public void update(boolean enabled) { + if (isRemoved()) + return; + + boolean repaint = false; + if(node == null) return; + if(node.getNodeCount() > 0) { + node.removeNodes(); + repaint = true; + } + if (enabled) { + + // Paint terminals normally + if (paintAreaTerminals || paintPointTerminals) { + List pickedTerminals = TerminalUtil.pickTerminals(diagram, null, paintPointTerminals, paintAreaTerminals); + paintTerminals(node, Color.BLUE, diagram, null, pickedTerminals, null); + if(pickedTerminals.size() > 0) repaint = true; + } + + if (paintHoverAreaTerminals || paintHoverPointTerminals) { + TerminalHoverStrategy strategy = getHint(TERMINAL_HOVER_STRATEGY); + + AffineTransform invTx = util.getInverseTransform(); + if (invTx == null) { + System.err.println("NO CANVAS TRANSFORM INVERSE AVAILABLE, CANVAS TRANSFORM IS: " + util.getTransform()); + return; + } + + // Pick terminals + for (MouseInfo mi : mice.getMiceInfo().values()) { + Rectangle2D controlPickRect = getPickRectangle(mi.controlPosition.getX(), mi.controlPosition.getY()); + Shape canvasPickRect = GeometryUtils.transformShape(controlPickRect, invTx); + + List tis = TerminalUtil.pickTerminals(diagram, canvasPickRect, paintHoverAreaTerminals, paintHoverPointTerminals); + paintTerminals(node, Color.RED, diagram, canvasPickRect.getBounds2D(), tis, strategy); + if(tis.size() > 0) repaint = true; + } + } + } + if (repaint) { + setDirty(); + } + } + + public void paintTerminals(G2DParentNode parent, Color color, IDiagram diagram, Rectangle2D pickRect, Collection tis, TerminalHoverStrategy strategy) { + if (tis.isEmpty()) { + return; + } + G2DParentNode node = parent.getOrCreateNode(""+tis.hashCode(), G2DParentNode.class); + + double minDist = Double.MAX_VALUE; + double maxDist = 0; + TerminalInfo nearest = null; + if (pickRect != null) { + for (TerminalInfo ti : tis) { + double dx = ti.posDia.getTranslateX() - pickRect.getCenterX(); + double dy = ti.posDia.getTranslateY() - pickRect.getCenterY(); + double dist = Math.sqrt(dx*dx+dy*dy); + if (dist > maxDist) { + maxDist = dist; + } + if (dist < minDist) { + minDist = dist; + nearest = ti; + } + } + } + + for (TerminalInfo ti : tis) { + if (strategy != null && !strategy.highlight(ti)) + continue; + Shape shape = ti.shape != null ? ti.shape : getTerminalShape(); + //System.out.println("painting terminal " + ti + ": " + shape); + ShapeNode sn = node.getOrCreateNode("terminal_"+ti.hashCode(), ShapeNode.class); + sn.setShape(shape); + sn.setStroke(STROKE25); + sn.setScaleStroke(true); + if (pickRect != null) { + Color blendedColor = color; + if (ti != nearest) { + double dx = ti.posDia.getTranslateX() - pickRect.getCenterX(); + double dy = ti.posDia.getTranslateY() - pickRect.getCenterY(); + double dist = Math.sqrt(dx*dx+dy*dy); + double normalizedDistance = dist / maxDist; + final double maxFade = 0.5; + float alpha = (float)(1 - normalizedDistance*maxFade); + blendedColor = ColorUtil.withAlpha(ColorUtil.blend(color, Color.WHITE, normalizedDistance*maxFade), alpha); + } + sn.setColor(blendedColor); + } else { + sn.setColor(color); + } + sn.setTransform(ti.posDia); + sn.setFill(false); + } + } + + public Rectangle2D getTerminalShape() { + double pickDist = pointerInteractor.getPickDistance(); + return new Rectangle2D.Double(-pickDist - 0.5, -pickDist - 0.5, pickDist * 2 + 1, pickDist * 2 + 1); + } + + public Rectangle2D getPickRectangle(double x, double y) { + double pickDist = pointerInteractor.getPickDistance(); + Rectangle2D controlPickRect = new Rectangle2D.Double(x-pickDist, y-pickDist, pickDist*2+1, pickDist*2+1); + return controlPickRect; + } + + static { + Path2D.Double cross = new Path2D.Double(); + double s = 2; + cross.moveTo(-s, -s); + cross.lineTo(s, s); + cross.moveTo(-s, s); + cross.lineTo(s, -s); + TERMINAL_SHAPE = cross; + } + + IHintListener hoverStrategyListener = new HintListenerAdapter() { + @Override + public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { + hoverStrategyChanged((TerminalHoverStrategy) newValue); + } + }; + + protected void hoverStrategyChanged(TerminalHoverStrategy strategy) { + update(strategy != null ? strategy.highlightEnabled() : false); + } + +}