]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/handler/HighlightMode.java
(refs #7595) Started SCL/Reflection module
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / handler / HighlightMode.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.handler;
13
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Shape;
17 import java.awt.geom.Area;
18 import java.awt.geom.Path2D;
19 import java.util.Collection;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.TimeUnit;
22
23 import org.simantics.g2d.canvas.ICanvasContext;
24 import org.simantics.g2d.canvas.SGDesignation;
25 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
26 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;
27 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
28 import org.simantics.g2d.element.ElementClass;
29 import org.simantics.g2d.element.ElementHints;
30 import org.simantics.g2d.element.ElementUtils;
31 import org.simantics.g2d.element.IElement;
32 import org.simantics.g2d.element.handler.SelectionOutline;
33 import org.simantics.scenegraph.g2d.G2DParentNode;
34 import org.simantics.scenegraph.g2d.nodes.ShapeNode;
35 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
36 import org.simantics.utils.datastructures.hints.IHintContext.Key;
37 import org.simantics.utils.datastructures.hints.IHintListener;
38 import org.simantics.utils.datastructures.hints.IHintObservable;
39 import org.simantics.utils.threads.ThreadUtils;
40
41 /**
42  * This participant highlights the specified DiagramSelection on its source
43  * diagram as a stroked frame tightly surrounding the selected elements.
44  * 
45  * @author Tuukka Lehtonen
46  */
47 public class HighlightMode extends AbstractCanvasParticipant implements IHintListener {
48
49     private final Color  CUT_COLOR  = Color.ORANGE;
50     private final Color  COPY_COLOR = new Color(128, 220, 150);
51
52     private final BasicStroke DEFAULT_STROKE = new BasicStroke(3.0f);
53
54     DiagramSelection     selection;
55     int                  selectionId;
56     int                  paintPriority;
57
58     SingleElementNode    highlightNode;
59     Collection<IElement> highlightElements;
60
61     public HighlightMode(DiagramSelection selection, int selectionId, int paintPriority) {
62         this.selection = selection;
63         this.selectionId = selectionId;
64         this.paintPriority = paintPriority;
65     }
66
67     @SGInit(designation = SGDesignation.CANVAS)
68     public void init(G2DParentNode parent) {
69         highlightNode = parent.addNode("cut/copy source highlight", SingleElementNode.class);
70         highlightNode.setZIndex(paintPriority);
71         highlightNode.setVisible(false);
72
73         // This slows rendering down too much to use.
74         //highlightNode.setComposite(AlphaComposite.SrcOver.derive(0.4f));
75
76         this.highlightElements = selection.getOriginalElements();
77
78         for (IElement e : highlightElements)
79             e.addHintListener(this);
80
81         paintSelectionFrames(highlightNode, selection, selectionId);
82     }
83
84     @SGCleanup
85     public void cleanupSG() {
86         for (IElement e : highlightElements)
87             e.removeHintListener(this);
88
89         highlightNode.remove();
90     }
91
92     void paintSelectionFrames(G2DParentNode parentNode, DiagramSelection selection, int selectionId) {
93         Area cutArea = new Area();
94         for (IElement e : selection.getOriginalElements()) {
95             ElementClass ec = e.getElementClass();
96             SelectionOutline so = ec.getAtMostOneItemOfClass(SelectionOutline.class);
97             Shape shape = so != null ? so.getSelectionShape(e) : ElementUtils.getElementShapeOrBoundsOnDiagram(e);
98             cutArea.add(new Area(shape));
99         }
100         if (!cutArea.isEmpty()) {
101             // Is rendering of Area slower than Path2D?
102             Path2D.Double path = new Path2D.Double(cutArea);
103
104             ShapeNode shapeNode = parentNode.getOrCreateNode("highlight", ShapeNode.class);
105             shapeNode.setShape(path);
106             shapeNode.setScaleStroke(true);
107             shapeNode.setStroke(DEFAULT_STROKE);
108             shapeNode.setFill(false);
109             shapeNode.setColor(selection.isCut() ? CUT_COLOR : COPY_COLOR);
110
111             highlightNode.setVisible(true);
112         }
113     }
114
115     @Override
116     public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
117         if (key == ElementHints.KEY_TRANSFORM) {
118             //System.out.println("transform changed for " + sender + " to " + newValue);
119             highlightNode.setVisible(false);
120             deferredHighlightUpdate();
121         }
122     }
123
124     @Override
125     public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {
126     }
127
128     Future<?> updateTask;
129
130     private synchronized void deferredHighlightUpdate() {
131         if (updateTask == null) {
132             updateTask = ThreadUtils.getNonBlockingWorkExecutor().schedule(
133                     updateScheduler,
134                     100,
135                     TimeUnit.MILLISECONDS);
136         }
137     }
138
139     Runnable updateScheduler = new Runnable() {
140         @Override
141         public void run() {
142             ICanvasContext ctx = getContext();
143             if (ctx != null)
144                 ThreadUtils.asyncExec(ctx.getThreadAccess(), painter);
145         }
146     };
147
148     Runnable painter = new Runnable() {
149         @Override
150         public void run() {
151             if (!isRemoved())
152                 paintSelectionFrames(highlightNode, selection, selectionId);
153             updateTask = null;
154         }
155     };
156
157 }