]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/elements/TextElementNoBounds.java
Use element transform when doing pick check
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / elements / TextElementNoBounds.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.elements;
13
14 import java.awt.Color;
15 import java.awt.Font;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Rectangle2D;
18 import java.util.function.Consumer;
19
20 import org.simantics.g2d.canvas.ICanvasContext;
21 import org.simantics.g2d.diagram.DiagramUtils;
22 import org.simantics.g2d.diagram.IDiagram;
23 import org.simantics.g2d.element.ElementHints;
24 import org.simantics.g2d.element.ElementUtils;
25 import org.simantics.g2d.element.IElement;
26 import org.simantics.g2d.element.SceneGraphNodeKey;
27 import org.simantics.g2d.element.handler.HandleMouseEvent;
28 import org.simantics.g2d.element.handler.SceneGraph;
29 import org.simantics.g2d.utils.Alignment;
30 import org.simantics.scenegraph.g2d.G2DParentNode;
31 import org.simantics.scenegraph.g2d.events.MouseEvent;
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;
33 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
34 import org.simantics.utils.datastructures.hints.IHintContext.Key;
35
36 /**
37  * ElementHandler for text elements
38  * In-line editing supported.
39  * 
40  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
41  */
42 public class TextElementNoBounds implements SceneGraph, HandleMouseEvent {
43
44     private static final long serialVersionUID = -148784588840819612L;
45
46     public static final TextElementNoBounds INSTANCE         = new TextElementNoBounds();
47
48     public static final Key                 SG_NODE          = new SceneGraphNodeKey(TextNode.class, "TEXT_SG_NODE");
49     
50     protected static final double DEFAULT_PADDING_X = 0.5;
51     protected static final double DEFAULT_PADDING_Y = 0.5;
52     protected static final double DEFAULT_SCALE = 0.235;
53
54     protected final double originX;
55     protected final double originY;
56     protected final Alignment horizontalAlignment;
57     protected final Alignment verticalAlignment;
58     protected final double borderWidth;
59     protected final boolean editable;
60     protected final double paddingX;
61     protected final double paddingY;
62     protected final double scale;
63
64
65     public TextElementNoBounds() {
66         this(0, 0, Alignment.LEADING, 0);
67     }
68
69     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment) {
70         this(originX, originY, horizontalAlignment, 0);
71     }
72
73     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth) {
74         this(originX, originY, horizontalAlignment, borderWidth, DEFAULT_PADDING_X, DEFAULT_PADDING_Y, true);
75     }
76     
77     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable) {
78         this(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable, DEFAULT_SCALE);
79     }
80     
81     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable, double scale) {
82         this(originX, originY, horizontalAlignment, Alignment.BASELINE, borderWidth, paddingX, paddingY, editable, scale);
83     }
84     
85     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, Alignment verticalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable, double scale) {
86         if (horizontalAlignment == null)
87             throw new NullPointerException("null horizontal alignment");
88
89         this.originX = originX;
90         this.originY = originY;
91         this.horizontalAlignment = horizontalAlignment;
92         this.verticalAlignment = verticalAlignment;
93         this.borderWidth = borderWidth;
94         this.editable = editable;
95         this.paddingX = paddingX;
96         this.paddingY = paddingY;
97         this.scale = scale;
98     }
99     
100     @Override
101     public void init(final IElement e, G2DParentNode parent) {
102         TextNode node = getOrCreateTextNode(e, parent);
103
104         Font font = ElementUtils.getTextFont(e);
105         Color color = ElementUtils.getTextColor(e);
106         Color fillColor = ElementUtils.getFillColor(e);
107         Color borderColor = ElementUtils.getBorderColor(e, Color.BLACK);
108         String text = ElementUtils.getText(e);
109         AffineTransform at = ElementUtils.getTransform(e);
110         Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, horizontalAlignment);
111         Alignment vAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_VERTICAL_ALIGN, verticalAlignment);
112         Double borderWidth = ElementUtils.getHintOrDefault(e, MonitorClass.KEY_BORDER_WIDTH, this.borderWidth);
113
114         node.init(text, font, color, originX, originY, scale);
115         node.setBackgroundColor(fillColor);
116         node.setBorderColor(borderColor);
117         node.setHorizontalAlignment((byte) hAlign.ordinal());
118         node.setVerticalAlignment((byte) vAlign.ordinal());
119         node.setPadding(paddingX, paddingY);
120         node.setBorderWidth(borderWidth.floatValue());
121         node.setEditable(editable);
122         if (at != null)
123             node.setTransform(at);
124         
125         if(Boolean.TRUE.equals(ElementUtils.getHintOrDefault(e, ElementHints.KEY_RESIZABLE, false))) {
126             Rectangle2D bounds = e.getHint(ElementHints.KEY_BOUNDS);
127             if(bounds != null) {
128                 node.setTargetBounds(bounds);
129                 node.setWrapText(true);
130             }
131         }
132     }
133     
134     protected TextNode getOrCreateTextNode(IElement e, G2DParentNode parent) {
135         return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", TextNode.class, new TextNodeCallBack(e));
136     }
137     
138     private class TextNodeCallBack implements Consumer<TextNode> {
139         
140         IElement e;
141         
142         public TextNodeCallBack(IElement e) {
143             this.e = e;
144         }
145         
146         @Override
147         public void accept(TextNode node) {
148             node.setTextListener(new ITextListener() {
149                 @Override
150                 public void textChanged() {}
151
152                 @Override
153                 public void textEditingStarted() {}
154
155                 @Override
156                 public void textEditingCancelled() {
157                     TextNode node = (TextNode) e.getHint(SG_NODE);
158                     if (node != null)
159                         endEdit(node);
160                 }
161
162                 @Override
163                 public void textEditingEnded() {
164                     TextNode node = (TextNode) e.getHint(SG_NODE);
165                     if (node == null)
166                         return;
167                     //System.out.println("Node text changed: " + node.getText());
168                     ElementUtils.setText(e, node.getText());
169                     IDiagram diagram = ElementUtils.getDiagram(e);
170                     DiagramUtils.synchronizeHintsToBackend(diagram, e);
171                     endEdit(node);
172                 }
173             });
174         }
175     }
176
177     @Override
178     public void cleanup(IElement e) {
179         ElementUtils.removePossibleNode(e, SG_NODE);
180     }
181
182     // FIXME: hazardous with TextElementHandler.INSTANCE
183     TextEditActivation editActivation = null;
184
185     @Override
186     public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) {
187         if (me instanceof MouseEnterEvent) {
188             e.setHint(ElementHints.KEY_HOVER, true);
189         } else if (me instanceof MouseExitEvent) {
190             e.setHint(ElementHints.KEY_HOVER, false);
191         }
192
193         return false;
194     }
195
196     protected void endEdit(TextNode node) {
197         if (editActivation != null) {
198             editActivation.release();
199             editActivation = null;
200
201             node.setEditMode(false);
202             node.repaint();
203         }
204     }
205
206     @Override
207     public int hashCode() {
208         final int prime = 31;
209         int result = 1;
210         long temp;
211         temp = Double.doubleToLongBits(borderWidth);
212         result = prime * result + (int) (temp ^ (temp >>> 32));
213         result = prime * result + horizontalAlignment.hashCode();
214         temp = Double.doubleToLongBits(originX);
215         result = prime * result + (int) (temp ^ (temp >>> 32));
216         temp = Double.doubleToLongBits(originY);
217         result = prime * result + (int) (temp ^ (temp >>> 32));
218         temp = Double.doubleToLongBits(paddingX);
219         result = prime * result + (int) (temp ^ (temp >>> 32));
220         temp = Double.doubleToLongBits(paddingY);
221         result = prime * result + (int) (temp ^ (temp >>> 32));
222         return result;
223     }
224
225     @Override
226     public boolean equals(Object obj) {
227         if (this == obj)
228             return true;
229         if (obj == null)
230             return false;
231         if (getClass() != obj.getClass())
232             return false;
233         TextElementNoBounds other = (TextElementNoBounds) obj;
234         if (Double.doubleToLongBits(borderWidth) != Double.doubleToLongBits(other.borderWidth))
235             return false;
236         if (horizontalAlignment != other.horizontalAlignment)
237             return false;
238         if (Double.doubleToLongBits(originX) != Double.doubleToLongBits(other.originX))
239             return false;
240         if (Double.doubleToLongBits(originY) != Double.doubleToLongBits(other.originY))
241             return false;
242         if (Double.doubleToLongBits(paddingX) != Double.doubleToLongBits(other.paddingX))
243             return false;
244         if (Double.doubleToLongBits(paddingY) != Double.doubleToLongBits(other.paddingY))
245             return false;
246         return true;
247     }
248     
249     
250
251 }