1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g2d.elementclass.button;
\r
14 import java.awt.AlphaComposite;
\r
15 import java.awt.Font;
\r
16 import java.awt.FontMetrics;
\r
17 import java.awt.Graphics2D;
\r
18 import java.awt.geom.Line2D;
\r
19 import java.awt.geom.Rectangle2D;
\r
21 import org.simantics.g2d.element.ElementClass;
\r
22 import org.simantics.g2d.element.ElementHints;
\r
23 import org.simantics.g2d.element.ElementUtils;
\r
24 import org.simantics.g2d.element.IElement;
\r
25 import org.simantics.g2d.element.SceneGraphNodeKey;
\r
26 import org.simantics.g2d.element.handler.Clickable.PressStatus;
\r
27 import org.simantics.g2d.element.handler.SceneGraph;
\r
28 import org.simantics.g2d.element.handler.Stateful;
\r
29 import org.simantics.g2d.element.handler.Text;
\r
30 import org.simantics.g2d.element.handler.Togglable;
\r
31 import org.simantics.g2d.element.handler.impl.AbstractClickable;
\r
32 import org.simantics.g2d.element.handler.impl.AbstractTogglable;
\r
33 import org.simantics.g2d.element.handler.impl.DefaultTransform;
\r
34 import org.simantics.g2d.element.handler.impl.Resizeable;
\r
35 import org.simantics.scenegraph.Node;
\r
36 import org.simantics.scenegraph.g2d.G2DNode;
\r
37 import org.simantics.scenegraph.g2d.G2DParentNode;
\r
38 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
\r
39 import org.simantics.utils.datastructures.hints.IHintContext.Key;
\r
40 import org.simantics.utils.datastructures.hints.IHintObservable;
\r
42 public class ToggleButtonClass {
\r
44 public static final ElementClass BUTTON_CLASS =
\r
45 ElementClass.compile(
\r
48 Resizeable.UNCONSTRICTED,
\r
49 DefaultTransform.INSTANCE,
\r
50 ToggleButtonPaint.INSTANCE,
\r
51 Stateful.ENABLED_BY_DEFAULT
\r
56 static class ToggleButtonPaint implements SceneGraph {
\r
57 private static final long serialVersionUID = 1114908644204400590L;
\r
58 public static final ToggleButtonPaint INSTANCE = new ToggleButtonPaint();
\r
60 public static final Key SG_NODE = new SceneGraphNodeKey(Node.class, "SUB_SG_NODE");
\r
64 public void cleanup(IElement e) {
\r
65 Node node = e.removeHint(SG_NODE);
\r
71 public void init(IElement e, G2DParentNode parent) {
\r
72 ToggleButtonNode node = (ToggleButtonNode) e.getHint(SG_NODE);
\r
74 node = parent.addNode(ToggleButtonNode.class);
\r
75 e.setHint(SG_NODE, node);
\r
76 e.addKeyHintListener(AbstractTogglable.TOGGLE_KEY, new HintListenerAdapter() {
\r
79 public void hintChanged(IHintObservable sender, Key key, Object oldValue,
\r
81 if (sender instanceof IElement) {
\r
82 ToggleButtonNode node = (ToggleButtonNode) ((IElement)sender).getHint(SG_NODE);
\r
83 node.setToggle((Boolean)newValue);
\r
88 e.addKeyHintListener(ElementHints.KEY_TEXT, new HintListenerAdapter() {
\r
91 public void hintChanged(IHintObservable sender, Key key, Object oldValue,
\r
93 if (sender instanceof IElement) {
\r
94 ToggleButtonNode node = (ToggleButtonNode) ((IElement)sender).getHint(SG_NODE);
\r
95 node.buttonText = (String)newValue;
\r
101 e.addKeyHintListener(AbstractClickable.PRESS_STATUS_KEY, new HintListenerAdapter() {
\r
104 public void hintChanged(IHintObservable sender, Key key, Object oldValue,
\r
106 if (sender instanceof IElement) {
\r
107 ToggleButtonNode node = (ToggleButtonNode) ((IElement)sender).getHint(SG_NODE);
\r
108 node.status = (PressStatus)newValue;
\r
115 Rectangle2D rect = ElementUtils.getElementBounds(e);
\r
116 ButtonColorProfile colors = ButtonColorProfile.DEFAULT;
\r
117 double height = rect.getHeight();
\r
118 boolean enabled = isEnabled(e);
\r
120 // FIXME: context not supported by scenegraph
\r
121 PressStatus status = PressStatus.NORMAL;//ElementUtils.getPressStatus(e, ctx);
\r
123 Font font = new Font("Tahoma", 0, (int) height-6);
\r
124 Font selFont = new Font("Tahoma", Font.BOLD, (int) height-6);
\r
125 Text text = e.getElementClass().getAtMostOneItemOfClass(Text.class);
\r
126 String buttonText = null;
\r
127 if (text!=null) buttonText = text.getText(e);
\r
128 if (buttonText==null) buttonText = "";
\r
129 boolean checked = isChecked(e);
\r
131 System.out.println("ToggleButtonClass.init " + e + " " + status + " " + checked);
\r
132 node.init(status, rect, enabled, checked, colors, font, selFont, buttonText);
\r
134 // e.addKeyHintListener(AbstractClickable.PRESS_STATUS_KEY, new HintListenerAdapter() {
\r
137 // public void hintChanged(IHintObservable sender, Key key, Object oldValue,
\r
138 // Object newValue) {
\r
139 // if (sender instanceof IElement) {
\r
140 // ToggleButtonNode node = (ToggleButtonNode) ((IElement)sender).getHint(SG_NODE);
\r
141 // node.setPressStatus((PressStatus)newValue);
\r
149 public static class ToggleButtonNode extends G2DNode {
\r
153 private static final long serialVersionUID = -7968142805282971747L;
\r
155 PressStatus status = null;
\r
156 Rectangle2D rect = null;
\r
157 Boolean enabled = null;
\r
158 Boolean checked = null;
\r
159 ButtonColorProfile colors = null;
\r
161 Font selFont = null;
\r
162 String buttonText = null;
\r
163 boolean toggle = false;
\r
166 public Rectangle2D getBoundsInLocal() {
\r
170 @SyncField("pressStatus") void setPressStatus(PressStatus pressStatus) {
\r
171 this.status = pressStatus;
\r
174 @SyncField("toggle") void setToggle(Boolean toggle) {
\r
175 this.checked = toggle;
\r
178 public void init(PressStatus status, Rectangle2D rect, boolean enabled, boolean checked,
\r
179 ButtonColorProfile colors, Font font, Font selFont, String buttonText) {
\r
180 this.status = status;
\r
182 this.enabled = enabled;
\r
183 this.checked = checked;
\r
184 this.colors = colors;
\r
186 this.selFont = selFont;
\r
187 this.buttonText = buttonText;
\r
191 public void render(Graphics2D g) {
\r
194 drawNormal(g, rect, enabled, checked, colors, font, selFont, buttonText);
\r
197 drawHeld(g, rect, enabled, colors, font, selFont, buttonText);
\r
200 drawPressed(g, rect, enabled, colors, font, selFont, buttonText);
\r
203 drawHover(g, rect, enabled, colors, font, selFont, buttonText);
\r
208 protected void drawNormal(Graphics2D g, Rectangle2D rect, boolean enabled, boolean checked, ButtonColorProfile colors, Font font, Font selectedFont, String text)
\r
211 drawPressed(g, rect, enabled, colors, font, selectedFont, text);
\r
214 g.translate(rect.getX(), rect.getY());
\r
215 double width = rect.getWidth();
\r
216 double height = rect.getHeight();
\r
218 g.setColor(colors.BACKGROUND);
\r
219 g.fill(new Rectangle2D.Double(0, 0, width-1, height-1));
\r
221 g.setColor(colors.BORDER1);
\r
222 Line2D line = new Line2D.Double();
\r
223 line.setLine(0, 0, width-1, 0); g.draw(line);
\r
224 line.setLine(0, 0, 0, height-1); g.draw(line);
\r
226 g.setColor(colors.BORDER2);
\r
227 line.setLine(1, height-2, width-2, height-2); g.draw(line);
\r
228 line.setLine(width-2, height-2, width-2, 1); g.draw(line);
\r
230 g.setColor(colors.BORDER3);
\r
231 line.setLine(0, height-1, width-1, height-1); g.draw(line);
\r
232 line.setLine(width-1, height-1, width-1, 0); g.draw(line);
\r
235 g.setColor(colors.TEXT_BLACK);
\r
236 FontMetrics fm = g.getFontMetrics(font);
\r
237 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
240 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
241 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
242 g.drawString(text, x, (float)height-6);
\r
244 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
246 g.setFont(selectedFont);
\r
248 FontMetrics fm = g.getFontMetrics(selectedFont);
\r
249 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
250 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
252 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
\r
253 g.setColor(colors.TEXT_WHITE);
\r
254 g.drawString(text, x+1, (float)height-6+1);
\r
256 g.setColor(colors.TEXT_BLACK);
\r
257 g.drawString(text, x, (float)height-6);
\r
261 protected void drawHeld(Graphics2D g, Rectangle2D rect, boolean enabled, ButtonColorProfile colors, Font font, Font selectedFont, String text)
\r
263 g.translate(rect.getX(), rect.getY());
\r
264 double width = rect.getWidth();
\r
265 double height = rect.getHeight();
\r
267 g.setColor(colors.BACKGROUND);
\r
268 g.fill(new Rectangle2D.Double(0, 0, width-1, height-1));
\r
270 Line2D line = new Line2D.Double();
\r
272 g.setColor(colors.BORDER3);
\r
273 line.setLine(0, 0, width-2, 0); g.draw(line);
\r
274 line.setLine(0, 0, 0, height-2); g.draw(line);
\r
276 g.setColor(colors.BORDER2);
\r
277 line.setLine(1, 1, width-3, 1); g.draw(line);
\r
278 line.setLine(1, 1, 1, height-3); g.draw(line);
\r
280 g.setColor(colors.BORDER1);
\r
281 line.setLine(0, height-1, width-1, height-1); g.draw(line);
\r
282 line.setLine(width-1, height-1, width-1, 0); g.draw(line);
\r
284 g.setColor(colors.TEXT_BLACK);
\r
285 FontMetrics fm = g.getFontMetrics(font);
\r
286 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
289 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
290 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
291 g.drawString(text, x+1, (float)height-6+1);
\r
295 protected void drawPressed(Graphics2D g, Rectangle2D rect, boolean enabled, ButtonColorProfile colors, Font font, Font selectedFont, String text)
\r
297 g.translate(rect.getX(), rect.getY());
\r
298 double width = rect.getWidth();
\r
299 double height = rect.getHeight();
\r
301 g.setColor(colors.SELECTEDBACKGROUND);
\r
302 g.fill(new Rectangle2D.Double(0, 0, width-1, height-1));
\r
304 Line2D line = new Line2D.Double();
\r
306 g.setColor(colors.BORDER3);
\r
307 line.setLine(0, 0, width-2, 0); g.draw(line);
\r
308 line.setLine(0, 0, 0, height-2); g.draw(line);
\r
310 g.setColor(colors.BORDER2);
\r
311 line.setLine(1, 1, width-3, 1); g.draw(line);
\r
312 line.setLine(1, 1, 1, height-3); g.draw(line);
\r
314 g.setColor(colors.BORDER1);
\r
315 line.setLine(0, height-1, width-1, height-1); g.draw(line);
\r
316 line.setLine(width-1, height-1, width-1, 0); g.draw(line);
\r
319 g.setColor(colors.TEXT_BLACK);
\r
321 FontMetrics fm = g.getFontMetrics(font);
\r
322 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
325 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
326 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
327 g.drawString(text, x+1, (float)height-6+1);
\r
329 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
331 g.setFont(selectedFont);
\r
333 FontMetrics fm = g.getFontMetrics(selectedFont);
\r
334 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
335 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
337 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
\r
338 g.setColor(colors.TEXT_WHITE);
\r
339 g.drawString(text, x+2, (float)height-6+2);
\r
341 g.setColor(colors.TEXT_BLACK);
\r
342 g.drawString(text, x+1, (float)height-6+1);
\r
347 protected void drawHover(Graphics2D g, Rectangle2D rect, boolean enabled, ButtonColorProfile colors, Font font, Font selectedFont, String text)
\r
350 drawPressed(g, rect, enabled, colors, font, selectedFont, text);
\r
353 g.translate(rect.getX(), rect.getY());
\r
354 double width = rect.getWidth();
\r
355 double height = rect.getHeight();
\r
357 g.setColor(colors.HOVERBACKGROUND);
\r
358 g.fill(new Rectangle2D.Double(0, 0, width-1, height-1));
\r
360 //g.setStroke(HOVER_STROKE);
\r
362 g.setColor(colors.BORDER1);
\r
363 Line2D line = new Line2D.Double();
\r
364 line.setLine(0, 0, width-1, 0); g.draw(line);
\r
365 line.setLine(0, 0, 0, height-1); g.draw(line);
\r
367 g.setColor(colors.BORDER2);
\r
368 line.setLine(1, height-2, width-2, height-2); g.draw(line);
\r
369 line.setLine(width-2, height-2, width-2, 1); g.draw(line);
\r
371 g.setColor(colors.BORDER3);
\r
372 line.setLine(0, height-1, width-1, height-1); g.draw(line);
\r
373 line.setLine(width-1, height-1, width-1, 0); g.draw(line);
\r
376 g.setColor(colors.TEXT_BLACK);
\r
377 FontMetrics fm = g.getFontMetrics(font);
\r
378 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
381 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
382 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
383 g.drawString(text, x, (float)height-6);
\r
385 Rectangle2D clipRect = new Rectangle2D.Double(2, 2, width-4, height-4);
\r
387 g.setFont(selectedFont);
\r
389 FontMetrics fm = g.getFontMetrics(selectedFont);
\r
390 Rectangle2D stringRect = fm.getStringBounds(text, g);
\r
391 float x = ((float)((width - 4) / 2)) - ((float)stringRect.getWidth()) / 2;
\r
393 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
\r
394 g.setColor(colors.TEXT_WHITE);
\r
395 g.drawString(text, x+1, (float)height-6+1);
\r
397 g.setColor(colors.TEXT_BLACK);
\r
398 g.drawString(text, x, (float)height-6);
\r
404 protected ButtonColorProfile getColorProfile(IElement e)
\r
406 return ButtonColorProfile.DEFAULT;
\r
409 protected boolean isToggleButton()
\r
414 public boolean isEnabled(IElement e) {
\r
415 Stateful enabled = e.getElementClass().getAtMostOneItemOfClass(Stateful.class);
\r
416 if (enabled==null) return true;
\r
417 return enabled.isEnabled(e);
\r
420 public boolean isChecked(IElement e){
\r
421 Boolean b = e.getHint(AbstractTogglable.TOGGLE_KEY);
\r