/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
* Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Sun Microsystems nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package sketch;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import sketch.ColorPicker;
def TOOLBAR_WIDTH = 40;
var backupPaths:Path[];
var lines = Group{ translateX: TOOLBAR_WIDTH };
var currentPath:Path;
var scene:Scene;
var strokeSize:Number = 5.0;
var mouseX:Number = 1.0;
var mouseY:Number = 1.0;
var colorPicker:ColorPicker;
var bottomButtonBox:HBox;
var replayTimeline:Timeline;
var pathIndex:Integer = 0;
var pointIndex:Integer = 0;
var oldPath:Path;
var newPath:Path;
function replay() {
backupPaths = null;
for (n in lines.content) {
insert n as Path into backupPaths;
}
lines.content = null;
pathIndex = 0;
pointIndex = 0;
oldPath = null;
newPath = null;
replayTimeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: KeyFrame {
time: 5ms
action: function() {
if (pathIndex >= sizeof backupPaths) stopReplay();
if (oldPath == null) {
oldPath = backupPaths[pathIndex];
newPath = Path {
strokeWidth: oldPath.strokeWidth
strokeLineCap: StrokeLineCap.ROUND
strokeLineJoin: StrokeLineJoin.ROUND
stroke: oldPath.stroke
};
insert newPath into lines.content;
}
if (pointIndex == (sizeof oldPath.elements -1)) {
oldPath = null;
newPath = null;
pointIndex = 0;
pathIndex ++;
} else {
insert oldPath.elements[pointIndex] into newPath.elements;
pointIndex ++;
}
}
}
};
replayTimeline.play();
}
function stopReplay() {
replayTimeline.stop();
replayTimeline = null;
pathIndex = 0;
pointIndex = 0;
oldPath = null;
newPath = null;
lines.content = [backupPaths];
}
var oldStageX = 0.0;
var oldStageY = 0.0;
var oldStageW = 0.0;
var oldStageH = 0.0;
function toggleFullscreen(e:MouseEvent):Void {
if(not stage.fullScreen) {
oldStageX = stage.x;
oldStageY = stage.y;
oldStageW = stage.width;
oldStageH = stage.height;
}
stage.fullScreen = not stage.fullScreen;
if(not stage.fullScreen) {
stage.x = oldStageX;
stage.y = oldStageY;
stage.width = oldStageW;
stage.height = oldStageH;
}
}
var stage:Stage = Stage{
title: "Sketch"
scene:
scene = Scene{
width: 600+TOOLBAR_WIDTH
height: 450
content: [
lines,
Rectangle {
translateY: bind scene.height - TOOLBAR_WIDTH
width: bind scene.width
height: bind TOOLBAR_WIDTH
fill: Color.web("#DDDDDD")
}
bottomButtonBox = HBox {
translateX: bind (scene.width - bottomButtonBox.layoutBounds.width)/2
translateY: bind 5 + scene.height - TOOLBAR_WIDTH
spacing: 3
content: [
Group {
content: [
Rectangle {
width: 45 height: 30
fill: Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Text {
translateX: 8
translateY: 20
content: "Clear"
}
]
onMouseClicked: function(e) { lines.content = null }
}
Group {
content: [
Rectangle {
width: 55 height: 30
fill: Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Text {
translateX: 8
translateY: 20
content: bind if (replayTimeline.running) then " Stop" else "Replay"
}
]
onMouseClicked: function(e) {
if (replayTimeline.running) stopReplay() else replay();
}
}
Group {
content: [
Rectangle {
width: 79 height: 30
fill: Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Text {
translateX: 8
translateY: 20
content: bind if (stage.fullScreen) then " Normal " else "Full Screen"
}
]
onMouseClicked: toggleFullscreen
}
]
}
Rectangle {
width: TOOLBAR_WIDTH
height: bind scene.height
fill: Color.web("#DDDDDD")
}
VBox {
translateX: 5
translateY: 5
spacing: 3
content: [
Group {
content: [
Rectangle {
width: 30 height: 30
fill: bind if (strokeSize==1) then Color.web("#AAAAAA") else Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Circle { centerX: 15 centerY: 15 radius: 1 fill: Color.BLACK }
]
onMouseClicked: function(e) { strokeSize = 1.0 }
}
Group {
content: [
Rectangle {
width: 30 height: 30
fill: bind if (strokeSize==3) then Color.web("#AAAAAA") else Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Circle { centerX: 15 centerY: 15 radius: 2 fill: Color.BLACK }
]
onMouseClicked: function(e) { strokeSize = 3.0 }
}
Group {
content: [
Rectangle {
width: 30 height: 30
fill: bind if (strokeSize==5) then Color.web("#AAAAAA") else Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Circle { centerX: 15 centerY: 15 radius: 3 fill: Color.BLACK }
]
onMouseClicked: function(e) { strokeSize = 5.0 }
}
Group {
content: [
Rectangle {
width: 30 height: 30
fill: bind if (strokeSize==10) then Color.web("#AAAAAA") else Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Circle { centerX: 15 centerY: 15 radius: 5 fill: Color.BLACK }
]
onMouseClicked: function(e) { strokeSize = 10.0 }
}
Group {
content: [
Rectangle {
width: 30 height: 30
fill: bind if (strokeSize==50) then Color.web("#AAAAAA") else Color.web("#CCCCCC")
stroke: Color.web("#BBBBBB")
}
Circle { centerX: 15 centerY: 15 radius: 13 fill: Color.BLACK }
]
onMouseClicked: function(e) { strokeSize = 50.0 }
}
colorPicker = ColorPicker{ width: 30 height: 180}
Rectangle {
width: 30 height: 30
fill: bind if (colorPicker.previewColor !=null) colorPicker.previewColor else colorPicker.color
stroke: Color.web("#BBBBBB")
}
]
}
Rectangle {
translateX: TOOLBAR_WIDTH
width: bind scene.width-TOOLBAR_WIDTH
height: bind scene.height-TOOLBAR_WIDTH
fill: Color.TRANSPARENT
onMousePressed: function (e:MouseEvent) {
mouseX = if(e.x < 0) 0 else if (e.x > (scene.width - TOOLBAR_WIDTH)) (scene.width - TOOLBAR_WIDTH) else e.x;
mouseY = if(e.y < 0) 0 else if (e.y > scene.height) scene.height else e.y;
insert currentPath = Path{
elements: MoveTo{ x: mouseX y: mouseY }
strokeWidth: strokeSize
strokeLineCap: StrokeLineCap.ROUND
strokeLineJoin: StrokeLineJoin.ROUND
stroke: colorPicker.color
} into lines.content;
}
onMouseDragged: function (e:MouseEvent) {
mouseX = if(e.x < 0) 0 else if (e.x > (scene.width - TOOLBAR_WIDTH)) (scene.width - TOOLBAR_WIDTH) else e.x;
mouseY = if(e.y < 0) 0 else if (e.y > scene.height) scene.height else e.y;
insert LineTo{ x: mouseX y: mouseY } into currentPath.elements;
}
onMouseReleased: function (e:MouseEvent) {
mouseX = if(e.x < 0) 0 else if (e.x > (scene.width - TOOLBAR_WIDTH)) (scene.width - TOOLBAR_WIDTH) else e.x;
mouseY = if(e.y < 0) 0 else if (e.y > scene.height) scene.height else e.y;
insert LineTo{ x: mouseX y: mouseY } into currentPath.elements;
currentPath = null;
}
onMouseMoved: function (e:MouseEvent) {
mouseX = e.x;
mouseY = e.y;
}
}
Circle {
fill: null
stroke: bind colorPicker.color
radius: bind strokeSize / 2
translateX: bind mouseX + TOOLBAR_WIDTH
translateY: bind mouseY
}
Rectangle {
width: bind scene.width-1
height: bind scene.height-1
fill: null
stroke: Color.web("#AAAAAA")
}
]
}
}