--- /dev/null
+package org.simantics.diagram.profile;\r
+\r
+import java.awt.Graphics2D;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.datatypes.literal.RGB;\r
+import org.simantics.datatypes.literal.Vec2d;\r
+import org.simantics.diagram.elements.DiagramNodeUtil;\r
+import org.simantics.diagram.internal.Activator;\r
+import org.simantics.diagram.profile.ButtonResult.A;\r
+import org.simantics.diagram.profile.ButtonResult.B;\r
+import org.simantics.scenegraph.g2d.G2DNode;\r
+import org.simantics.scenegraph.g2d.events.EventTypes;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
+import org.simantics.scenegraph.g2d.nodes.SVGNode;\r
+import org.simantics.scenegraph.utils.NodeUtil;\r
+import org.simantics.scl.runtime.function.Function1;\r
+\r
+public class ButtonNode extends IconButtonNode {\r
+ \r
+ private static final long serialVersionUID = -1963362069190362275L;\r
+ \r
+ private B config;\r
+ private boolean isDown = false;\r
+ private Function1<Boolean, Boolean> pressed;\r
+ \r
+ private static SVGNode ON = new SVGNode();\r
+ private static SVGNode OFF = new SVGNode();\r
+ private static boolean initialized = false;\r
+ \r
+ Rectangle2D EMPTY = new Rectangle2D.Double(0, 0, 0, 0);\r
+ \r
+ private SVGNode current = OFF;\r
+ private Rectangle2D lastBounds = EMPTY; \r
+\r
+ public void staticInit() {\r
+ if(!initialized) {\r
+ ON.setData(createSVG("BUTTON_ON"));\r
+ OFF.setData(createSVG("BUTTON_OFF"));\r
+ initialized = true;\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void init() {\r
+ staticInit();\r
+ addEventHandler(this);\r
+ }\r
+ \r
+ @Override\r
+ public void cleanup() {\r
+ removeEventHandler(this);\r
+ super.cleanup();\r
+ }\r
+ \r
+ private void setValue(double value) {\r
+ \r
+ // Value does not affect LATCH buttons\r
+ if(ButtonMode.LATCH.equals(config.mode)) return;\r
+ \r
+ if(value < 0.5) {\r
+ current = OFF;\r
+ } else {\r
+ current = ON;\r
+ } \r
+ \r
+ }\r
+ \r
+ private void setConfig(B config) {\r
+\r
+ if(this.config == config) return;\r
+ this.config = config;\r
+ \r
+ }\r
+ \r
+ public void setA(A data) {\r
+\r
+ setConfig(data.config);\r
+ setValue(data.value);\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void render(Graphics2D g2d) {\r
+\r
+ AffineTransform ot = null;\r
+ if (!transform.isIdentity()) {\r
+ ot = g2d.getTransform();\r
+ g2d.transform(transform);\r
+ }\r
+ \r
+ current.render(g2d);\r
+ lastBounds = current.getBounds();\r
+\r
+ if (ot != null)\r
+ g2d.setTransform(ot);\r
+ \r
+ }\r
+\r
+ @Override\r
+ public Rectangle2D getBoundsInLocal() {\r
+ return lastBounds;\r
+ }\r
+\r
+ @Override\r
+ void setData(IconButtonResult state) {\r
+ ButtonResult br = (ButtonResult)state;\r
+ setA(br.getA());\r
+ pressed = br.getPressed();\r
+ }\r
+\r
+ private boolean hitTest(MouseEvent event) {\r
+ Rectangle2D bounds = getBounds();\r
+ if (bounds == null)\r
+ return false;\r
+ Point2D localPos = NodeUtil.worldToLocal(this, event.controlPosition, new Point2D.Double());\r
+ double x = localPos.getX();\r
+ double y = localPos.getY();\r
+ return bounds.contains(x, y);\r
+ }\r
+ \r
+ @Override\r
+ protected boolean mouseButtonPressed(MouseButtonPressedEvent e) {\r
+ if(!e.hasAnyButton(MouseEvent.LEFT_BUTTON)) return false;\r
+ if(!hitTest(e)) return false; \r
+ if(pressed != null) {\r
+ pressed.apply(true);\r
+ isDown = true;\r
+ if(ButtonMode.LATCH.equals(config.mode)) {\r
+ current = ON;\r
+ DiagramNodeUtil.getCanvasContext((G2DNode)this).getContentContext().setDirty();\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) {\r
+ if(e.hasAnyButton(MouseEvent.LEFT_BUTTON)) return false;\r
+ if(!hitTest(e) && !isDown) return false; \r
+ if(pressed != null) {\r
+ pressed.apply(false);\r
+ isDown = false;\r
+ if(ButtonMode.LATCH.equals(config.mode)) {\r
+ current = OFF;\r
+ DiagramNodeUtil.getCanvasContext((G2DNode)this).getContentContext().setDirty();\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ @Override\r
+ public int getEventMask() {\r
+ return EventTypes.MouseButtonPressedMask\r
+ | EventTypes.MouseButtonReleasedMask\r
+ ;\r
+ } \r
+ \r
+ public String createSVG(String iconName) {\r
+ return Activator.ICON_PROVIDER.apply(iconName, new RGB.Integer(0, 0, 0), new Vec2d(1,1));\r
+ }\r
+ \r
+}
\ No newline at end of file