import javafx.ui.*; import javafx.ui.canvas.*; import javafx.ui.filter.*; import java.util.Date; import java.lang.System; import com.sun.jna.examples.WindowUtils; import javax.swing.JPopupMenu; import java.awt.event.MouseEvent; import javax.swing.SwingUtilities; public class Timer { private attribute elapsed: Number; public attribute minutes: Number; public attribute seconds: Number; public attribute hours: Number; public attribute running: Boolean; } attribute Timer.elapsed = bind if running then [1..60] dur 60000 linear while running continue if true else 0; trigger on Timer.elapsed = value { var now = new Date(); minutes = now.getMinutes(); seconds = now.getSeconds() + [.35,0.34 .. 0.0] dur 350 + (now.getTime() % 1000)/1000; hours = now.getHours(); } public class Clock extends CompositeNode { public attribute ticking: Boolean; public attribute scale: Number; } operation Clock.composeNode() { var t = Timer {running: bind ticking}; scale = 1; return Group { transform: bind [translate(5,5),scale(scale,scale)] var secs = bind t.seconds var mins = bind t.minutes + secs/60 var hrs = bind t.hours + mins/60 content: [ ImageView { transform: [] image: Image {url: "com/sellmic/jfx/clock/images/clock_face.png"} }, Group { var hourHand = ImageView { transform: bind rotate(hrs*30,255,245) image: Image {url: "com/sellmic/jfx/clock/images/hour_hand.png"} } var minuteHand = ImageView { transform: bind rotate(mins *6,255,245) image: Image {url: "com/sellmic/jfx/clock/images/minute_hand.png"} } var secondHand = ImageView { transform: bind rotate(t.seconds * 6,255,245) image: Image {url: "com/sellmic/jfx/clock/images/second_hand.png"} } content: [hourHand, minuteHand, secondHand] }, ImageView { transform: [] image: Image {url: "com/sellmic/jfx/clock/images/pin.png"} }] }; } var frame = new Frame(); frame.title = "Clock"; frame.width = 525; frame.height=550; var clock = Clock { ticking: true var x = 0 var y = 0 onMousePressed: operation(e:CanvasMouseEvent) { x = e.x + frame.screenx; y = e.y + frame.screeny; } onMouseDragged: operation(e:CanvasMouseEvent) { if (e.button == 1) { frame.move(e.x+frame.screenx - x,e.y+frame.screeny - y); } x = e.x + frame.screenx; y = e.y + frame.screeny; } }; frame.content = Canvas { content:clock }; var popupMenu = new JPopupMenu(); popupMenu.add( CheckBoxMenuItem{ text: "Active" selected: bind clock.ticking }.getComponent() ); popupMenu.add( Menu{ var zooms:Number = [100,75,50,25,15] text: "Zoom" items: [ foreach (zoom in zooms) MenuItem { text: "{zoom}%" action: operation() { clock.scale = zoom / 100.0; } } ] }.getComponent() ); popupMenu.addSeparator(); popupMenu.add( MenuItem{ text: "Close" action: operation() { System.exit(0); } }.getComponent()); frame.content.getComponent().setComponentPopupMenu(popupMenu); if (System.getProperty("JFXClock.opaque", "false").equals("true")) { frame.background = white; frame.visible = true; } else { frame.undecorated = true; frame.visible = true; WindowUtils.setWindowTransparent(frame.getWindow(), true); }