]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/elements/TextElementNoBounds.java
Merge "Fixed Path2D creation to work with overlapping RoutePoints"
[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         if (horizontalAlignment == null)
83             throw new NullPointerException("null horizontal alignment");
84
85         this.originX = originX;
86         this.originY = originY;
87         this.horizontalAlignment = horizontalAlignment;
88         this.verticalAlignment = Alignment.BASELINE;
89         this.borderWidth = borderWidth;
90         this.editable = editable;
91         this.paddingX = paddingX;
92         this.paddingY = paddingY;
93         this.scale = scale;
94     }
95     
96     @Override
97     public void init(final IElement e, G2DParentNode parent) {
98         TextNode node = getOrCreateTextNode(e, parent);
99
100         Font font = ElementUtils.getTextFont(e);
101         Color color = ElementUtils.getTextColor(e);
102         Color fillColor = ElementUtils.getFillColor(e);
103         Color borderColor = ElementUtils.getBorderColor(e, Color.BLACK);
104         String text = ElementUtils.getText(e);
105         AffineTransform at = ElementUtils.getTransform(e);
106         Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, horizontalAlignment);
107         Alignment vAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_VERTICAL_ALIGN, verticalAlignment);
108         Double borderWidth = ElementUtils.getHintOrDefault(e, MonitorClass.KEY_BORDER_WIDTH, this.borderWidth);
109
110         node.init(text, font, color, originX, originY, scale);
111         node.setBackgroundColor(fillColor);
112         node.setBorderColor(borderColor);
113         node.setHorizontalAlignment((byte) hAlign.ordinal());
114         node.setVerticalAlignment((byte) vAlign.ordinal());
115         node.setPadding(paddingX, paddingY);
116         node.setBorderWidth(borderWidth.floatValue());
117         node.setEditable(editable);
118         if (at != null)
119             node.setTransform(at);
120         
121         if(Boolean.TRUE.equals(ElementUtils.getHintOrDefault(e, ElementHints.KEY_RESIZABLE, false))) {
122             Rectangle2D bounds = e.getHint(ElementHints.KEY_BOUNDS);
123             if(bounds != null) {
124                 node.setTargetBounds(bounds);
125                 node.setWrapText(true);
126             }
127         }
128     }
129     
130     protected TextNode getOrCreateTextNode(IElement e, G2DParentNode parent) {
131         return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", TextNode.class, new TextNodeCallBack(e));
132     }
133     
134     private class TextNodeCallBack implements Consumer<TextNode> {
135         
136         IElement e;
137         
138         public TextNodeCallBack(IElement e) {
139             this.e = e;
140         }
141         
142         @Override
143         public void accept(TextNode node) {
144             node.setTextListener(new ITextListener() {
145                 @Override
146                 public void textChanged() {}
147
148                 @Override
149                 public void textEditingStarted() {}
150
151                 @Override
152                 public void textEditingCancelled() {
153                     TextNode node = (TextNode) e.getHint(SG_NODE);
154                     if (node != null)
155                         endEdit(node);
156                 }
157
158                 @Override
159                 public void textEditingEnded() {
160                     TextNode node = (TextNode) e.getHint(SG_NODE);
161                     if (node == null)
162                         return;
163                     //System.out.println("Node text changed: " + node.getText());
164                     ElementUtils.setText(e, node.getText());
165                     IDiagram diagram = ElementUtils.getDiagram(e);
166                     DiagramUtils.synchronizeHintsToBackend(diagram, e);
167                     endEdit(node);
168                 }
169             });
170         }
171     }
172
173     @Override
174     public void cleanup(IElement e) {
175         ElementUtils.removePossibleNode(e, SG_NODE);
176     }
177
178     // FIXME: hazardous with TextElementHandler.INSTANCE
179     TextEditActivation editActivation = null;
180
181     @Override
182     public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) {
183         if (me instanceof MouseEnterEvent) {
184             e.setHint(ElementHints.KEY_HOVER, true);
185         } else if (me instanceof MouseExitEvent) {
186             e.setHint(ElementHints.KEY_HOVER, false);
187         }
188
189         return false;
190     }
191
192     protected void endEdit(TextNode node) {
193         if (editActivation != null) {
194             editActivation.release();
195             editActivation = null;
196
197             node.setEditMode(false);
198             node.repaint();
199         }
200     }
201
202     @Override
203     public int hashCode() {
204         final int prime = 31;
205         int result = 1;
206         long temp;
207         temp = Double.doubleToLongBits(borderWidth);
208         result = prime * result + (int) (temp ^ (temp >>> 32));
209         result = prime * result + horizontalAlignment.hashCode();
210         temp = Double.doubleToLongBits(originX);
211         result = prime * result + (int) (temp ^ (temp >>> 32));
212         temp = Double.doubleToLongBits(originY);
213         result = prime * result + (int) (temp ^ (temp >>> 32));
214         temp = Double.doubleToLongBits(paddingX);
215         result = prime * result + (int) (temp ^ (temp >>> 32));
216         temp = Double.doubleToLongBits(paddingY);
217         result = prime * result + (int) (temp ^ (temp >>> 32));
218         return result;
219     }
220
221     @Override
222     public boolean equals(Object obj) {
223         if (this == obj)
224             return true;
225         if (obj == null)
226             return false;
227         if (getClass() != obj.getClass())
228             return false;
229         TextElementNoBounds other = (TextElementNoBounds) obj;
230         if (Double.doubleToLongBits(borderWidth) != Double.doubleToLongBits(other.borderWidth))
231             return false;
232         if (horizontalAlignment != other.horizontalAlignment)
233             return false;
234         if (Double.doubleToLongBits(originX) != Double.doubleToLongBits(other.originX))
235             return false;
236         if (Double.doubleToLongBits(originY) != Double.doubleToLongBits(other.originY))
237             return false;
238         if (Double.doubleToLongBits(paddingX) != Double.doubleToLongBits(other.paddingX))
239             return false;
240         if (Double.doubleToLongBits(paddingY) != Double.doubleToLongBits(other.paddingY))
241             return false;
242         return true;
243     }
244     
245     
246
247 }