License text

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER 
 * Copyright  2008, 2010 Oracle and/or its affiliates.  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 Oracle Corporation 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 screenshotmaker;

import java.lang.Math;
import java.lang.System;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.ext.swing.SwingButton;
import javafx.ext.swing.SwingLabel;
import javafx.ext.swing.SwingTextField;
import javafx.geometry.Rectangle2D;
import javafx.lang.FX;
import javafx.scene.control.TextBox;
import javafx.scene.Cursor;
import javafx.scene.CustomNode;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.Scene;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import screenshotmaker.ScreenCapturer;
import screenshotmaker.Util;

// FLICKR credentials,
// You can provide your own credentials there
var SECRET:String = "<Your Shared Secret>";
var API_KEY:String = "<Your API Key>";
var AUTH_TOKEN:String = "<Your Authentication Token>";
def FLICKR_EMPTY_TAGS:String = "<Your Tags>";
//Screen dimensions
def screenW:Integer =
ScreenCapturer.getScreenDimension().width;
def screenH:Integer =
ScreenCapturer.getScreenDimension().height;
// Captured screen displayed in a window 85% of the original size
def screenShotW:Number = screenW * 0.85;
def screenShotH:Number = screenH * 0.85;
def maxHiddenX:Number  = screenW - screenShotW;
def maxHiddenY:Number  = screenH - screenShotH;
def defaultRect:Rectangle2D = Rectangle2D{
width:screenShotW height:screenShotH }
// Right menu constants
def wp:Integer = 130;
// Some variable used to bridge the Palette events and the Stage
var movedX:Number;
var movedY:Number;
var translatedRect:Rectangle2D = defaultRect;
var imgView:ImageView;
var dragPossible:Boolean = true;
var arrow:Boolean;
var text:Boolean;
var select:Boolean;
var drag:Boolean;
// The Palette that contains the image tools
def buttonEffect:Effect = DropShadow{
    offsetX: 0
    offsetY: 0
    color: Color.WHITE 
    radius: 30
};
def palette:Palette = Palette{
    cache: true
    translateX: screenShotW  + 3
    translateY: 2
    transforms: Scale{
        x: 0.38
        y: 0.38
    }
};
// Tooltips are displayed after a delay.
var timeline:Timeline;
function delayToolTip(currentToolTip:Palette.Tooltip):Void{
    timeline = Timeline {
        repeatCount: Timeline.INDEFINITE
        keyFrames :
            KeyFrame {
                time : 1000ms
                action:function() {
                // The tooltip needs to be displayed on top of
                // any other component.
                    currentToolTip.toFront();
                    currentToolTip.visible = true;
                }
            }
    };
    timeline.play();
}
// Palette selection events handling
def dragMouseOver:Boolean = bind palette.dragBtn.hover on replace {
    // Effect is set only if the button is active and the button is selected
    if(not palette.dragBtn.disable and
    palette.currentButton != palette.dragBtn) {
        palette.dragBtn.effect =
        if (dragMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(dragMouseOver) {
        delayToolTip(palette.dragToolTip);
    } else {
        palette.dragToolTip.visible = false;
        timeline.stop();
    }
};
palette.dragBtn.onMousePressed = function(e:MouseEvent) {
    if(not palette.dragBtn.disable){
        arrow = false;
        text = false;
        select = false;
        drag = true;
        palette.currentButton = palette.dragBtn;
    }
}
def fitToScreenMouseOver:Boolean = bind palette.fitToScreenBtn.hover
on replace {
    // Effect is set only if the button is active and the button is selected
    if(not palette.fitToScreenBtn.disable) {
        palette.fitToScreenBtn.effect =
        if (fitToScreenMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(fitToScreenMouseOver) {
        delayToolTip(palette.fitToolTip);
    } else {
        palette.fitToolTip.visible = false;
        timeline.stop();
    }
};
palette.fitToScreenBtn.onMousePressed = function(e:MouseEvent) {
    movedX = 0;
    movedY = 0;
    translatedRect = null;
    imgView.fitHeight = screenShotH;
    imgView.fitWidth = screenShotW;
    //Cant drag when the image fits to screen.
    dragPossible = false;
    palette.currentButton = palette.fitToScreenBtn;
}

palette.fitToScreenBtn.onMouseReleased = function(e:MouseEvent) {
    if(not palette.fitToScreenBtn.disable) {
        palette.fitToScreenBtn.disable = true;
        palette.currentButton = null;
        palette.dragBtn.disable = true;
        palette.originalSizeBtn.disable = false;
    }
}

def origMouseOver:Boolean = bind palette.originalSizeBtn.hover on replace {
    // Effect is set only if the button is active and the button is selected
    if(not palette.originalSizeBtn.disable) {
        palette.originalSizeBtn.effect =
        if (origMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(origMouseOver) {
        delayToolTip(palette.originalToolTip);
    } else {
        palette.originalToolTip.visible = false;
        timeline.stop();
    }
};

palette.originalSizeBtn.onMousePressed = function(e:MouseEvent) {
    movedX = 0;
    movedY = 0;
    translatedRect = defaultRect;
    imgView.fitHeight = 0;
    imgView.fitWidth = 0;
    dragPossible = true;
    palette.currentButton = palette.originalSizeBtn;
}

palette.originalSizeBtn.onMouseReleased = function(e:MouseEvent) {
    if(not palette.originalSizeBtn.disable) {
        palette.originalSizeBtn.disable = true;
        palette.dragBtn.disable = false;
        palette.fitToScreenBtn.disable = false;
        palette.currentButton = null;
    }
}

palette.arrowBtn.onMousePressed = function(e:MouseEvent) {
    arrow = true;
    text = false;
    select = false;
    drag = false;
    palette.currentButton = palette.arrowBtn;
}
def arrowMouseOver:Boolean = bind palette.arrowBtn.hover on replace {
    // Effect is set only if the selected button is not the arrow one.
    if(palette.currentButton != palette.arrowBtn) {
        palette.arrowBtn.effect =
        if (arrowMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(arrowMouseOver) {
        delayToolTip(palette.arrowToolTip);
    } else {
        palette.arrowToolTip.visible = false;
        timeline.stop();
    }
};

def textMouseOver:Boolean = bind palette.textBtn.hover on replace {
    // Effect is set only if the selected button is not the text one.
    if(palette.currentButton != palette.textBtn) {
        palette.textBtn.effect =
        if (textMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(textMouseOver) {
        delayToolTip(palette.textToolTip);
    } else {
        palette.textToolTip.visible = false;
        timeline.stop();
    }
};
palette.textBtn.onMousePressed = function(e:MouseEvent) {
    arrow = false;
    select = false;
    drag = false;
    text = true;
    palette.currentButton = palette.textBtn
}
def selectMouseOver:Boolean = bind palette.selectBtn.hover on replace {
    // Effect is set only if the selected button is not the select region one.
    if(palette.currentButton != palette.selectBtn) {
        palette.selectBtn.effect =
        if (selectMouseOver)
        then buttonEffect else null;
    }
    //Tooltip is displayed with a delay only is pointer on top of the button.
    if(selectMouseOver) {
        delayToolTip(palette.selectToolTip);
    } else {
        palette.selectToolTip.visible = false;
        timeline.stop();
    }
};

palette.selectBtn.onMousePressed = function(e:MouseEvent) {
    arrow = false;
    text = false;
    drag = false;
    select = true;
    palette.currentButton = palette.selectBtn;
}
/**
* An arrow that rotates following mouse drag direction
*/
class Arrow extends CustomNode {
    public-init var x:Number;
    public-init var y:Number;
    var line:Line;
    var l1:Line;
    var l2:Line;
    var group:Group;
    var startDragX:Number;
    var startDragY:Number;
    var previousX:Number;
    var previousY:Number;
    function freeze() {
        line.strokeDashArray = null;
        var angle = Math.atan2(line.endY - line.startY,
        line.endX - line.startX);
        angle = (angle * 180 / Math.PI);
        l1 = Line {
            transforms:Rotate{
                angle: angle
                pivotX: line.endX
                pivotY: line.endY
            }
            startX: line.endX
            startY: line.endY
            endX: line.endX - 7
            endY: line.endY - 7
            stroke: Color.BLACK
            strokeWidth: 2.0
            visible: true
        }
        l2 = Line {
            transforms:Rotate{
                angle: angle
                pivotX:line.endX 
                pivotY:line.endY
            }
            startX: line.endX
            startY: line.endY
            endX: line.endX - 7
            endY: line.endY + 7
            stroke: Color.BLACK
            strokeWidth: 2.0
            visible: true
        }
        insert l1 into group.content;
        insert l2 into group.content;
        //Make the dragability visible
        group.cursor = Cursor.MOVE;
    }

    function stretch(x:Number, y:Number) {
        line.endX = x;
        line.endY = y;
    }
    override function create():Node {
        group = Group{
            onMousePressed:function(e:MouseEvent) {
                //Reset the drag state.
                startDragX = e.sceneX;
                startDragY = e.sceneY;
                previousX = 0;
                previousY = 0;
                // Back to creation state.
                delete l1 from group.content;
                delete l2 from group.content;
                line.strokeDashArray = [5,5]
            }
            onMouseReleased:function(e:MouseEvent) {
                //When drag stop, freeze the arrow.
                freeze();
            }
            onMouseDragged:function(e:MouseEvent) {
                var constrainedX:Number;
                var constrainedY:Number;
                // Need to compute direction for boundaries computation
                var directionX:Number = (e.sceneX - startDragX) - previousX;
                var directionY:Number = (e.sceneY - startDragY) - previousY;
                // X boundaries
                var maxX:Number = Math.max(line.startX, line.endX);
                var minX:Number = Math.min(line.startX, line.endX);
                if((minX <= 0 and directionX < 0) or
                ((e.sceneX + (maxX - e.sceneX) >= screenShotW)
                    and directionX > 0)) {
                    constrainedX = previousX;
                }else {
                    constrainedX = e.sceneX - startDragX;
                }
                // Y boundaries, 7 is the height of the head.
                var maxY:Number = Math.max(line.startY, line.endY);
                var minY:Number = Math.min(line.startY, line.endY);
                if((minY <= 7 and directionY < 0) or
                ((e.sceneY + (maxY - e.sceneY) + 7 >= screenShotH)
                    and directionY > 0)) {
                    constrainedY = previousY;
                }else {
                    constrainedY = e.sceneY - startDragY;
                }
                // Compute move delta
                var deltaX:Number = constrainedX - previousX;
                var deltaY:Number = constrainedY - previousY;
                line.startX = line.startX + deltaX;
                line.startY = line.startY + deltaY;
                line.endX = line.endX + deltaX;
                line.endY = line.endY + deltaY;
                // Store current coordinates for next computation.
                previousX = constrainedX;
                previousY = constrainedY;
            }
            content: [
                line = Line{
                    endX: x
                    endY: y
                    startX: x
                    startY: y
                    stroke: Color.BLACK
                    strokeDashOffset: 0
                    strokeWidth: 2.0
                    strokeDashArray: [ 5, 5 ]
                }
            ]
        }
    }
}
/**
* An editable text.
* Double click on the text to go to edition. Type Return key to stop editing.
* Click and drag the text to change its location.
*/
class EditableText extends CustomNode {
    public-init var x:Number;
    public-init var y:Number;
    var tb:TextBox;
    function stopEditing():Void{
        tb.unselect();
        tb.editable = false;
    }

    override function create():Node {
        var group = Group {
            content: [
                tb = TextBox {
                    style: "font-family: 'Verdana'; font-size: 20pt; border-fill:transparent; "
                           "background-fill:transparent; focus-fill:transparent;shadow-fill:transparent"
            // Need to substract the border to make the text displayed where
            // the mouse pointer is.
                    translateX: x - 7
                    translateY: y - 20
                    visible: true
                    focusTraversable:true
                    columns:15
            // Height is set to 40 to cope with font size.
                    height: 40
                    text: "Type some text"
                    selectOnFocus: true
                    onKeyTyped: function(k:KeyEvent){
                // Increase the width to avoid the text to
                // be cropped. Only if width inside the borders
                        if(tb.translateX + tb.width < screenShotW - 5)
                        tb.width +=10;
                    }
                    onMousePressed:function(e:MouseEvent){
                        if(e.clickCount >= 2) {
                            tb.editable = true;
                        }
                    }
                    onMouseDragged:function(e:MouseEvent) {
                        tb.unselect();
                        tb.cursor = Cursor.MOVE;
                        // Change the style to display the borders
                        tb.style = "font-family: 'Verdana'; font-size: 20pt; "
                        "border-fill:gray; background-fill:transparent; focus-fill:transparent;shadow-fill:transparent";
                        // Compute constraints
                        var constrainedX:Number;
                        var constrainedY:Number;
                        if(e.sceneX < 0){
                            constrainedX = 0;
                        }else {
                            constrainedX = e.sceneX;
                        }
                        if(constrainedX + tb.width > screenShotW)
                            constrainedX = screenShotW - tb.width;
                        if(e.sceneY < 0) {
                            constrainedY = 0;
                        } else {
                            constrainedY = e.sceneY;
                        }
                        if(constrainedY + tb.height > screenShotH)
                            constrainedY = screenShotH - tb.height;
                            tb.translateX = constrainedX;
                            tb.translateY = constrainedY;
                        }
                        onMouseReleased:function(e:MouseEvent) {
                            // Back to default values
                            tb.cursor = Cursor.DEFAULT;
                            tb.style = "font-family: 'Verdana'; font-size: 20pt; "
                            "border-fill:transparent; background-fill:transparent; focus-fill:transparent;shadow-fill:transparent";
                        }
                        action:function() {
                            stopEditing();
                        }
                    }
                ]
        }
        // Text can"t expend outside the borders of the image.
        if(tb.translateX + tb.width > screenShotW - 5)
            tb.width = screenShotW - x;
        tb.requestFocus();
        return group;
    }
}
/**
* A Image region selector. Composed of a Label and a Rectangle.
* The image region covered by the rectangle is what is exported to Flickr or
* saved to disk.
*/
class SelectRegionRectangle extends CustomNode {
    public-init var originX:Number;
    public-init var originY:Number;
    public var width:Number = bind selectRectangle.width;
    public var height:Number = bind selectRectangle.height;
    var labelValue:String;
    var labelRectangle:Rectangle;
    var selectRectangle:Rectangle;
    override var visible = false;
    function freeze() {
        labelValue="";
        labelRectangle.visible = false;
    }
    function enlarge(x:Number, y:Number) {
        selectRectangle.width= x - originX;
        selectRectangle.height = y - originY;
        labelValue = "width={
            java.lang.Integer.valueOf(selectRectangle.width)}height={
            java.lang.Integer.valueOf(selectRectangle.height)}";
    }
    function reset() {
        enlarge(0,0);
        visible = true;
        labelRectangle.visible = true;
    }
    override function create():Node {
        var group = Group {
            content: [
                labelRectangle = Rectangle {
                    x: bind originX
                    y: bind originY - 22
                    width: 185
                    height:20
                    opacity: 0.4
                    visible: true
                    fill: Color.CHARTREUSE
                },
                Text {
                    content: bind labelValue
                    x: bind originX
                    y: bind originY - 5
                    visible: true
                    font:Font { 
                        name: "Verdana"
                        size: 15
                    }
                },
                selectRectangle = Rectangle {
                    x: bind originX
                    y: bind originY
                    opacity: 0.4
                    visible: bind visible
                    fill: Color.CHARTREUSE
                }
            ]
        }
    }
}
// Small frame displayed on the bottom of the screen
// Screenshot capture is operated from this widget
def widget: Stage = Stage {
    x: screenW - 150
    y: screenH - 100
    resizable: false
    visible: true
    scene:Scene {
        content:  {
            SwingButton {
                text: "Capture screen"
                action:function():Void {
                    widget.visible = false;
                    FX.deferAction(function() { captureAndRetouch(); } );
                }
            }
            }
        }
    onClose: function() {
        System.exit(0);
}
}
/**
* The palette being reused each time a screenshot is captured,
* we reset the state.
*/
function resetPalette() {
    movedX = 0;
    movedY = 0;
    translatedRect = defaultRect;
    dragPossible = true;
    arrow = false;
    text = false;
    select= false;
    drag = false;
    palette.reset();
}

function captureAndRetouch():Void{
    var screenFile = ScreenCapturer.capture();
    var imgURL = screenFile.toURL().toString();
    //reset the palette
   resetPalette();
   // Picture retouch frame
    var f:Stage = Stage {
        title: "Screenshot Maker";
        visible: true
        resizable: false
        var originX:Number;
        var originY:Number;
        var disabledRectangleVisibility:Boolean = false;
        var selectRectangle:SelectRegionRectangle;
        var groupRef:Group;
        var currentArrow:Arrow;
        var status:String = "                 ";
        var currentCursor:Cursor = Cursor.DEFAULT;
        var disabled:Boolean = false;
        var previousX:Number;
        var previousY:Number;
        var selectionRectangle = function() :
        java.awt.Rectangle {
            // To retrieve the absolute screen coordinates of the selection,
            // we need to get the Stage coordinates (that are
            // absolute to the screen, add the Scene ones (to remove the window
            // decoration) and add the Selection Rectangle ones if visible.
            var x:Number = f.x + f.scene.x;
            var y:Number = f.y + f.scene.y;
            var w:Number;
            var h:Number;
            if(selectRectangle.visible) {
                x += selectRectangle.originX;
                y += selectRectangle.originY;
                w = selectRectangle.width;
                h = selectRectangle.height;
                selectRectangle.visible = false;
            } else {
                w = screenShotW;
                h = screenShotH;
            }
            return
            new java.awt.Rectangle(x, y, w, h);
        }

        var disable = function():Void {
            disabledRectangleVisibility=true;
            currentCursor = Cursor.WAIT;
            disabled = true;
        }

        var enable = function():Void {
            disabledRectangleVisibility = false;
            currentCursor = Cursor.DEFAULT;
            disabled = false;
        }

        var computeTranslation = function(maxHidden:Number,
        current:Number, increment:Number):Number {
            var coordinate:Number;
            if(Math.abs(current) >= maxHidden)
            {
                if(increment > 0) {
                    coordinate = current + increment;
                } else {
                    coordinate  = current;
                }

            }else {
                if(current + increment > 0) {
                    coordinate = 0;
                } else {
                    coordinate = current + increment;
                }
            }
            return coordinate;
        }

        onClose:function() {
                displayStage(widget);
            }

        scene:
            Scene {
                content: [
                    groupRef = Group {
                        cursor: bind currentCursor;
                        content: [
                            Rectangle {
                                width: screenShotW + wp + 3
                                height: screenShotH + 3
                                fill: Color.BLACK
                            },
                            Rectangle {
                                width: screenShotW
                                height: screenShotH
                                fill: null
                                stroke: Color.WHITE
                            },
                            imgView = ImageView{
                                viewport: bind translatedRect
                                transforms: Translate {
                                    x: bind movedX
                                    y: bind movedY
                                }
                                image:Image { url: imgURL }
                                onMouseDragged:function(e:MouseEvent) {
                                    if(disabled)
                                    return;
                                    var constrainedX:Number;
                                    var constrainedY:Number;
                                    // Frame boundaries computation
                                    constrainedX = e.sceneX;
                                    if(constrainedX > screenShotW)
                                    constrainedX = screenShotW;

                                    constrainedY = e.sceneY;
                                    if(constrainedY > screenShotH)
                                    constrainedY = screenShotH;

                                    if(arrow){
                                        currentArrow.stretch(constrainedX,
                                        constrainedY);
                                        return;
                                    }
                                    if(select){
                                        selectRectangle.enlarge(constrainedX,
                                            constrainedY);
                                        return;
                                    }
                                    if(drag){
                                        if(dragPossible){
                                        // Outside the imgView, the mouse sceneX
                                        // and sceneY positions are invalid
                                        // No image dragging in these contexts.
                                            if(constrainedX == screenShotW or
                                               constrainedY == screenShotH or
                                               constrainedX < 0 or
                                            constrainedY < 0) {
                                                previousX = constrainedX;
                                                previousY = constrainedY;
                                                return;
                                            }

                                        var incrementX = constrainedX-previousX;
                                        var incrementY = constrainedY-previousY;
                                        previousX = constrainedX;
                                        previousY = constrainedY;
                                        movedX = computeTranslation(maxHiddenX,
                                            movedX, incrementX);
                                        movedY = computeTranslation(maxHiddenY,
                                            movedY, incrementY);
                                        translatedRect = Rectangle2D {
                                                width: screenShotW - movedX
                                                height: screenShotH - movedY
                                            }
                                        }
                                        return;
                                    }
                                }

                                onMouseReleased:function (e:MouseEvent){
                                    if(disabled)
                                    return;
                                    imgView.cursor = Cursor.DEFAULT;
                                    arrow = false;
                                    text = false;
                                    select = false;
                                    drag = false;
                                    palette.currentButton = null;
                                    if(currentArrow != null) {
                                        currentArrow.freeze();
                                        currentArrow = null;
                                    }
                                    selectRectangle.freeze();
                                }
                                onMousePressed:function (e:MouseEvent){
                                    if(disabled)
                                    return;
                                    // We stop editing all texts.
                                    for(node in groupRef.content) {
                                        if(node instanceof EditableText)
                                        (node as EditableText).stopEditing();
                                    }
                                    if(palette.currentButton == null)
                                    return;

                                    originX = e.sceneX;
                                    originY = e.sceneY;
                                    selectRectangle.visible = false;
                                    if(arrow){
                                        currentArrow = Arrow {
                                            x: e.sceneX
                                            y: e.sceneY
                                        }
                                      insert currentArrow into groupRef.content;
                                        return;
                                    }
                                    if(text){
                                        var currentText = EditableText {
                                            x: originX
                                            y: originY
                                        }
                                       insert currentText into groupRef.content;
                                        return;
                                    }
                                    if(select){
                                        selectRectangle.reset();
                                        return;
                                    }
                                    if(drag){
                                        previousX = originX;
                                        previousY = originY;
                                        imgView.cursor = Cursor.MOVE;
                                        return;
                                    }
                                }
                            },
                            selectRectangle = SelectRegionRectangle {
                                originX: bind originX
                                originY: bind originY
                            },
                            Rectangle {
                                x: 0
                                y: 0
                                width: screenShotW
                                height: screenShotH
                                opacity: 0.5
                                visible: bind disabledRectangleVisibility
                                fill: Color.BLACK
                            },
                            palette,
                            VBox {
                                translateX: screenShotW
                                translateY: 170
                                width: wp
                                height: screenShotH
                                content: [
                                    SwingButton {
                                        text: "Save To Disk"
                                        width: wp
                                        action:function():Void {
                                           saveFileToDisk();
                                        }
                                    },
                                    SwingButton {
                                        text: "Flickr Upload"
                                        width: wp
                                        action:function():Void {
                                            status = "";
                                            var screenRect:java.awt.Rectangle =
                                            selectionRectangle();
                                            FX.deferAction(function() {
                                                var file = ScreenCapturer.
                                                capture(screenRect);
                                                disable();
                                           var flickrFrame:Stage = Stage {
                                            var wf:Number = 400;
                                            var hf:Number = 250;
                                            title: "Upload"
                                            resizable: false
                                            width: wf
                                            height: hf
                                            visible: true
                                            var tags:SwingTextField;
                                            var api_key:SwingTextField;
                                            var api_secret:SwingTextField;
                                            var auth_token:SwingTextField;
                                            onClose:function() {
                                               enable();
                                            }
                                            scene:Scene {
                                                content:Group {
                                                  content: [
                                                        Rectangle {
                                                            width: wf
                                                            height: hf
                                                            fill: Color.BLACK
                                                        },
                                                        VBox {
                                                            translateX: 5
                                                            width: wf
                                                            height:hf
                                                            content: [
                                                        SwingLabel {
                                                            text: "Flickr Tags: (Optional)"
                                                            foreground: Color.WHITE},
                                                            tags = SwingTextField {
                                                            text: FLICKR_EMPTY_TAGS
                                                            width: wf - 15
                                                        } ,
                                                        SwingLabel {
                                                            text: "Flickr Api Key:"
                                                            foreground: Color.WHITE},
                                                            api_key =  SwingTextField {
                                                                text: API_KEY
                                                                width: wf - 15
                                                            },
                                                        SwingLabel {
                                                            text: "Flickr Shared Secret:"
                                                            foreground: Color.WHITE},
                                                            api_secret =
                                                                SwingTextField {
                                                                text: SECRET
                                                                width:wf - 15
                                                            },
                                                        SwingLabel {
                                                            text:"Flickr Authentication Token:"
                                                            foreground:
                                                                Color.WHITE},
                                                            auth_token =
                                                            SwingTextField {
                                                                text: AUTH_TOKEN
                                                            width:wf - 15 }
                                                        ,
                                                        SwingButton {
                                                          text: "Upload"
                                                          translateX: 20
                                                          translateY: 10
                                                          action :
                                                          function():Void {
                                                           flickrFrame.visible =
                                                               false;
                                                           FX.deferAction(function() {
                                                            if(api_key.text.length() == 0
                                                            or api_secret.text.length() == 0
                                                            or auth_token.text.length() == 0)
                                                            {
                                                                status =
                                                                "Invalid keys";
                                                                return
                                                            }
                                                            API_KEY = api_key.text;
                                                            SECRET = api_secret.text;
                                                            AUTH_TOKEN = auth_token.text;
                                                            if(FLICKR_EMPTY_TAGS.equals(tags.text))
                                                                tags.text = null;
                                                            var req = FlickrPhotoUpload {
                                                                api_key: api_key.text
                                                                secret: api_secret.text
                                                                auth_token: auth_token.text
                                                                tags: tags.text
                                                                file: file
                                                                type: "jpg"
                                                                override var done on replace{
                                                                if(done) {
                                                                enable();
                                                                if(not success){
                                                                  status = "Upload failed";
                                                                } else {
                                                                 displayStage(widget);
                                                                 closeStage(f);
                                                                }
                                                               }
                                                             }
                                                            }
                                                            req.start();
                                                            return;
                                                            });
                                                        }
                                                        },
                                                        SwingButton {
                                                            text: "Cancel"
                                                            translateX: 95
                                                            translateY: -18
                                                            action :
                                                             function( ):Void {
                                                               flickrFrame.
                                                               close();
                                                            }
                                                        }
                                                            ]
                                                        }
                                                    ]
                                                    }
                                                }
                                        }
                                        return;
                                    });
                                }
                            },
                            SwingButton {
                                text:"Back to Capture"
                                width:wp
                                action:function() : Void {
                                    closeStage(f);
                                }
                            },
                            SwingLabel {text:bind status width:120
                            foreground:Color.RED}
                            ]}
                    ]}
            ]}
    var saveFileToDisk = function ():Void {
        status = "";
        var screenRect:java.awt.Rectangle =
        selectionRectangle();

        FX.deferAction(function() {
            var file:java.io.File =
                ScreenCapturer.
                   capture(screenRect);

                var fc =
                javax.swing.JFileChooser{};
                var target =
                new java.io.File(
                       fc.getCurrentDirectory(),
                    "screenshot.jpg");
                    fc.setSelectedFile(target);
                var ff = Util.JPGFileFilter{};
                    fc.setFileFilter(ff);

                disable();
                if (fc.showSaveDialog(null) ==
                javax.swing.JFileChooser.APPROVE_OPTION) {
                    try {
                        var imgFile:java.io.File =
                            fc.getSelectedFile();
                        var cancel:SwingButton;
                        if(imgFile.exists()) {
                         var confirmFrame :
                           Stage = Stage {
                         var yesClicked:Boolean;
                         var wf:Number = 290;
                         var hf:Number = 100;
                         title: "Warning"
                         resizable:false
                         width:wf
                         height:hf
                         visible: true
                         onClose:function() {
                          if(yesClicked) {
                           imgFile.createNewFile();
                           Util.copyFile(file,
                             imgFile);
                           displayStage(widget);
                           closeStage(f);
                          } else {
                           enable();
                          }
                         }
                         scene: Scene {
                          content: Group {
                           content: [
                            Rectangle {
                                width: 290
                                height: 100
                                fill: Color.BLACK
                            },
                            VBox {
                                translateX: 10
                                width: wf
                                height:hf
                                content: [
                                 SwingLabel {
                                  text:
                          "The file already exists, do you want to replace it?"
                                  foreground:
                                   Color.WHITE
                                 },
                                 SwingButton {
                                  text: "Replace"
                                  translateX: 55
                                  translateY: 10
                                  action:
                                   function( ): Void {
                                   yesClicked = true;
                                   confirmFrame.close();
                                  }
                                 },
                                 cancel = SwingButton {

                                  text: "Cancel"
                                  translateX: 150
                                  translateY: -18
                                  action: function( ):Void {
                                   yesClicked = false;
                                   confirmFrame.close();
                                  }
                                 }
                                ]
                              }
                             ]
                            }
                          }
                       }
                       cancel.requestFocus();
                     } else {
                        imgFile.createNewFile();
                        Util.copyFile(file,
                        imgFile);
                        displayStage(widget);
                        closeStage(f);

                     }
                    }catch(e:java.lang.Exception){
                       e.printStackTrace();
                       FX.print("Exception  {e}");
                        status = e.getMessage();
                    }
                } else {
                  enable();
                }
        });
    }
}
displayStage(f);
}

function displayStage(f:Stage):Void{
    // Simple effect to make the stage to be opened smoothly
    def temp = f;
    def temp1 = f.scene.content[0];
    def displayStage = Timeline {
        keyFrames: [
            at (0s) {temp.visible => true},
            at (0s) {temp1.opacity => 0.0},
            at (1s) {temp1.opacity => 1.0}
        ]
    }
    displayStage.play();
}
function closeStage(f:Stage):Void{
    // Simple effect to make the stage to be closed smoothly
    def temp = f.scene.content[0];
    def closeStage = Timeline {
        keyFrames: [
            at (0s) {temp.opacity => 1.0},
            at (0.5s) {temp.opacity => 0.0},
            KeyFrame {
                time : 0.5s
                action: function() {
                    f.close();
                }
            }
        ]
    }
    closeStage.play();
}