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