Tuesday, April 10, 2012

Creating a Flex AIR Annotator app: Part 51

In this part of the tutorial we will add an ability to move the crop area, images and annotations using the arrow keys on your keyboard in our application.

First of all, we need to listen to the 4 arrow keys. Go to keyDown() function and add 4 lines that check if the pressed key is one of the arrow keys and call one of the four functions: moveUp(), moveDown(), moveLeft(), moveRight():

if (evt.keyCode == 38) moveUp();
if (evt.keyCode == 40) moveDown();
if (evt.keyCode == 37) moveLeft();
if (evt.keyCode == 39) moveRight();

The keyDown() function then looks like this:

private function keyDown(evt:KeyboardEvent):void {
var hasBitmap:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.BITMAP_FORMAT);
var hasUrl:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.URL_FORMAT);
if (evt.ctrlKey && evt.keyCode == 86 && hasBitmap) {
if (stack.selectedIndex == 0) {
importScreenshot();
}
if (stack.selectedIndex == 1) {
if (hasUrl) {
addDropImage(Clipboard.generalClipboard.getData(ClipboardFormats.URL_FORMAT) as String);
}
if (!hasUrl) {
addBitmapImage(Clipboard.generalClipboard.getData(ClipboardFormats.BITMAP_FORMAT) as BitmapData);
}
}
}
if (evt.keyCode == 16) {
isShift = true;
}
if (evt.keyCode == 17) {
isCtrl = true;
}
if (evt.ctrlKey && evt.keyCode == 90 && undo_canUndo && toolbarStack.selectedIndex == 2) doUndo();
if (evt.ctrlKey && evt.keyCode == 89 && undo_canRedo && toolbarStack.selectedIndex == 2) doRedo();
if (evt.keyCode == 38) moveUp();
if (evt.keyCode == 40) moveDown();
if (evt.keyCode == 37) moveLeft();
if (evt.keyCode == 39) moveRight();
}

Now we need to go and delcare a new variable called currentlyMoving. Set its class to * (any):

private var currentlyMoving:*;

We'll have to set this variable's value to evt.currentTarget in annDown() and imgDown():

private function annDown(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 3) {
currentlyDragging = evt.currentTarget;
currentlyMoving = evt.currentTarget;
dragOffsetX = evt.currentTarget.mouseX;
dragOffsetY = evt.currentTarget.mouseY;
}
}

private function imgDown(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 1) {
currentlyDragging = evt.currentTarget;
currentlyMoving = evt.currentTarget;
dragOffsetX = evt.currentTarget.mouseX;
dragOffsetY = evt.currentTarget.mouseY;
}
}

The reason we can't use currentlyDragging variable is because it gets set to null once the key mouse has been released. Now go to toolbarChange() function and set currentlyMoving to null there.

private function toolbarChange():void {
if (toolbarStack.selectedIndex == 1) {
drawHitArea.mouseEnabled = false;
annotations.buttonMode = false;
annotations.mouseEnabled = false;
annotations.mouseChildren = false;
images.buttonMode = true;
images.mouseEnabled = true;
images.mouseChildren = true;
}else if 
(toolbarStack.selectedIndex == 2) {
updateLineExample();
drawHitArea.mouseEnabled = true;
}else if 
(toolbarStack.selectedIndex == 3) {
drawHitArea.mouseEnabled = false;
annotations.buttonMode = true;
annotations.mouseEnabled = true;
annotations.mouseChildren = true;
images.buttonMode = false;
images.mouseEnabled = false;
images.mouseChildren = false;
}else if 
(toolbarStack.selectedIndex == 4) {
drawHitArea.mouseEnabled = true;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
drawHitArea.x = -1;
drawHitArea.y = 1;
}else {
drawHitArea.mouseEnabled = false;
}
currentlyMoving = null;
}

Now let's create these move functions. The first one is moveUp(). Here, we need to check if the current screen is the crop screen, or annotation/image. We group annotation and image handling together, because they both apply the image or annotation that needs to be moved to the currentlyMoving variable, while the crop functionality is a bit different. There is only one object that can be moved on the crop screen - that is the crop selection. We do it by adjusting coordinates of the selection in crop_rectangle array, and then calling crop_updateDraw().

If the current screen is not the crop screen, we check if it is either annotation or image screen, and we also check if currentlyMoving variable doesn't equal null. Then we just work with the coordinates of the currentlyMoving object and call positionAnnResize() or positionResize() functions (depending on whether its an annotation or image we're moving) to update the anchor positions.

private function moveUp():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[1] > 0) {
crop_rectangle[1]--;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.y > 0) {
currentlyMoving.y--;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

The other 3 functions are similar.

private function moveDown():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[1] < content.height - crop_rectangle[3] - 1) {
crop_rectangle[1]++;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.y < content.height - currentlyMoving.height) {
currentlyMoving.y++;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function moveRight():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[0] < content.width - crop_rectangle[2] - 1) {
crop_rectangle[0]++;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.x < content.width - currentlyMoving.width) {
currentlyMoving.x++;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function moveLeft():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[0] > 0) {
crop_rectangle[0]--;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.x > 0) {
currentlyMoving.x--;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

Full code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx" 
   xmlns:custom="*"
   showStatusBar="false"
   creationComplete="init();" 
   applicationComplete="listeners();"
   minWidth="800" minHeight="400"
   width="800" height="500">

<fx:Script>
<![CDATA[
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.FocusDirection;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.InvokeEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.FileFilter;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.utils.ByteArray;
import mx.containers.Canvas;
import mx.containers.TitleWindow;
import mx.controls.Alert;
import flash.filesystem.FileMode;
import mx.controls.Image;
import mx.controls.Label;
import mx.controls.TextArea;
import mx.core.FlexGlobals;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.graphics.codec.IImageEncoder;
import mx.graphics.codec.JPEGEncoder;
import mx.graphics.codec.PNGEncoder;
import spark.components.Group;
import spark.core.SpriteVisualElement;
import spark.primitives.Rect;
import flash.text.TextFieldAutoSize;
import mx.managers.PopUpManager;
import mx.utils.ObjectUtil;
import flash.display.BlendMode;
import flash.system.System;
import flash.desktop.Clipboard;
import flash.desktop.ClipboardFormats;
import flash.events.NativeDragEvent;
import flash.desktop.NativeDragManager;
import flash.desktop.NativeApplication;

private var bitmapData:BitmapData;
private var content:*;
[Bindable]
private var buttonsEnabled:Boolean = false;
[Bindable]
private var lineThickness:int = 5;
[Bindable]
private var lineColor:uint = 0xff0000;
[Bindable]
private var aBodyColor:uint = 0xffff88;
[Bindable]
private var aBodyAlpha:Number = 1;
[Bindable]
private var aTextSize:Number = 12;
[Bindable]
private var aTextColor:uint = 0x000000;

[Embed(source="../lib/cursor_cross.png")]
private var crossCursor:Class;
[Embed(source="../lib/cursor_move.png")]
private var moveCursor:Class;
[Embed(source="../lib/ic_eyedropper.png")]
private var pickerCursor:Class;
[Embed(source="../lib/cursor_resize_vertical.png")]
private var resizeVerticalCursor:Class;
[Embed(source="../lib/cursor_resize_horizontal.png")]
private var resizeHorizontalCursor:Class;
[Embed(source="../lib/cursor_resize_diag1.png")]
private var resizeDiag1Cursor:Class;
[Embed(source="../lib/cursor_resize_diag2.png")]
private var resizeDiag2Cursor:Class;
[Embed(source="../lib/cursor_empty.png")]
private var emptyCursor:Class;

private var drawMode:String = "";
private var anchorX:Number;
private var anchorY:Number;
private var lastX:Number = -1;
private var lastY:Number = -1;
private var isShift:Boolean = false;
private var isCtrl:Boolean = false;
private var temporaryBitmap:BitmapData;
private var currentlyEditing:*;
private var currentlyDragging:*;
private var dragOffsetX:Number;
private var dragOffsetY:Number;
private var currentImage:*;
private var imageAnchors:Array;
private var currentRatio:Number;
private var firstTimeEditing:Boolean = true;
private var currentAnn:*;
[Bindable]
private var screenshotAvailable:Boolean = false;
private var checkScreenshot:Boolean = true;

private var preferences:SharedObject = SharedObject.getLocal("kirannotatorPreferences");
private var selectedFormat:String;
private var selectedQuality:int;

private var img_resizing:Boolean = false;
private var img_currentDir:String = "";
private var img_anchorX:Number;
private var img_anchorY:Number;
private var img_rectangle:Array;

private var crop_rectangle:Array;
private var crop_anchorX:Number;
private var crop_anchorY:Number;
private var crop_drawing:Boolean = false;
private var crop_selectionType:Boolean;
private var crop_inSelection:Boolean = false;
private var crop_offsetX:Number;
private var crop_offsetY:Number;
private var crop_dragging:Boolean = false;
private var crop_inResize:Boolean = false;
private var crop_resizing:Boolean = false;
private var crop_resizeDir:String = "";
private var crop_resizeRadius:Number = 6;

[Bindable]
private var undo_canUndo:Boolean = false;
[Bindable]
private var undo_canRedo:Boolean = false;
private var undo_memory:Array;
private var undo_currentMemory:int;
private var undo_memoryLimit:int = 4;
private var undo_lastPointsMemory:Array;

private var annAnchors:Array;
private var ann_currentDir:String = "";
private var ann_anchorX:Number;
private var ann_resizing:Boolean;
private var ann_positions:Array;

private var erasing:Boolean = false;

[Bindable]
private var saved:Boolean = false;
private var savedAlpha:Number = 0;

private var currentlyMoving:*;

private function init():void {
/* Uncomment this line to reset locally saved preferences: */
//preferences.data.firsttime = null;

// Set preferences if loaded for the first time
if (preferences.data.firsttime == null) {
preferences.data.firsttime = true;
preferences.data.selectedFormat = 'jpg';
preferences.data.selectedQuality = 70;
preferences.data.selectionType = true;
preferences.flush();
}

// Set preferences loaded from local storage
selectedFormat = preferences.data.selectedFormat;
selectedQuality = preferences.data.selectedQuality;
crop_selectionType = preferences.data.selectionType;

drawArea.filters = [new DropShadowFilter(4, 60, 0, 0.7, 10, 10, 1, 3)];
eraser.filters = [new GlowFilter(0xffffff, 1, 2, 2, 10, 1)];
}

private function listeners():void {
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);
addEventListener(MouseEvent.MOUSE_UP, drawUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
addEventListener(Event.ENTER_FRAME, everyFrame);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragIn);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDrop);
PopUpManager.addPopUp(imageWindow, this, true);
PopUpManager.centerPopUp(imageWindow);
PopUpManager.removePopUp(imageWindow);
}

private function onInvoke(evt:InvokeEvent):void {
var file:File;
if (evt.arguments[0]) {
file = new File(evt.arguments[0]);
if(file.exists){
switch (file.extension.toLowerCase()) {
case "jpg":
case "jpeg":
case "png":
case "gif":
if(stack.selectedIndex == 0){
importDropImage(file);
}
if(stack.selectedIndex == 1){
addDropImage(file.url, file.nativePath);
}
break;
default:
Alert.show("Unsupported file format.");
break;
}
}
}
}

private function onDragIn(evt:NativeDragEvent):void {
NativeDragManager.acceptDragDrop(this);
}

private function onDrop(evt:NativeDragEvent):void {
var files:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
if (files){
var file:File = files[0];
switch (file.extension.toLowerCase()) {
case "jpg":
case "jpeg":
case "png":
case "gif":
if(stack.selectedIndex == 0){
importDropImage(file);
}
if(stack.selectedIndex == 1){
addDropImage(file.url, file.nativePath);
}
break;
default:
Alert.show("Unsupported file format.");
break;
}
}
}

private function addDropImage(url:String, path:String = "Clipboard data"):void {
toolbarStack.selectedIndex = 1;
openImage();
imageWindow.validateNow();

var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComp);
loader.load(new URLRequest(url));

function loadComp(evt:Event):void {
iPreview.source = evt.target.content;
iPreviewHidden.source = evt.target.content;
iPath.text = path;
updatePreviewImage();
}
}

private function addBitmapImage(bdata:BitmapData):void {
toolbarStack.selectedIndex = 1;
openImage();
imageWindow.validateNow();

iPreview.source = new Bitmap(bdata);
iPreviewHidden.source = new Bitmap(bdata);
iPath.text = "Clipboard data"
updatePreviewImage();
}

private function importDropImage(file:File):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
loader.load(new URLRequest(file.url));
}

private function everyFrame(evt:Event):void{
if (checkScreenshot) {
var hasData:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.BITMAP_FORMAT);
screenshotAvailable = hasData;
}
if (savedAlpha != savedGroup.alpha) {
savedGroup.alpha += (savedAlpha - savedGroup.alpha) / 5;
if (Math.abs(savedAlpha - savedGroup.alpha) < 0.1) savedGroup.alpha = savedAlpha;
}
if (stack.selectedIndex == 1){
if (mouseX > width - 130 && mouseY > 60 && mouseY < 80) {
savedAlpha = 0;
}else {
savedAlpha = 1;
}
}
}

private function keyDown(evt:KeyboardEvent):void {
var hasBitmap:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.BITMAP_FORMAT);
var hasUrl:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.URL_FORMAT);
if (evt.ctrlKey && evt.keyCode == 86 && hasBitmap) {
if (stack.selectedIndex == 0) {
importScreenshot();
}
if (stack.selectedIndex == 1) {
if (hasUrl) {
addDropImage(Clipboard.generalClipboard.getData(ClipboardFormats.URL_FORMAT) as String);
}
if (!hasUrl) {
addBitmapImage(Clipboard.generalClipboard.getData(ClipboardFormats.BITMAP_FORMAT) as BitmapData);
}
}
}
if (evt.keyCode == 16) {
isShift = true;
}
if (evt.keyCode == 17) {
isCtrl = true;
}
if (evt.ctrlKey && evt.keyCode == 90 && undo_canUndo && toolbarStack.selectedIndex == 2) doUndo();
if (evt.ctrlKey && evt.keyCode == 89 && undo_canRedo && toolbarStack.selectedIndex == 2) doRedo();
if (evt.keyCode == 38) moveUp();
if (evt.keyCode == 40) moveDown();
if (evt.keyCode == 37) moveLeft();
if (evt.keyCode == 39) moveRight();
}

private function keyUp(evt:KeyboardEvent):void {
if (evt.keyCode == 16) {
isShift = false;
}
if (evt.keyCode == 17) {
isCtrl = false;
}
}

private function moveUp():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[1] > 0) {
crop_rectangle[1]--;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.y > 0) {
currentlyMoving.y--;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function moveDown():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[1] < content.height - crop_rectangle[3] - 1) {
crop_rectangle[1]++;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.y < content.height - currentlyMoving.height) {
currentlyMoving.y++;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function moveRight():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[0] < content.width - crop_rectangle[2] - 1) {
crop_rectangle[0]++;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.x < content.width - currentlyMoving.width) {
currentlyMoving.x++;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function moveLeft():void {
if (toolbarStack.selectedIndex == 4) {
if (crop_rectangle[0] > 0) {
crop_rectangle[0]--;
crop_updateDraw();
}
}
if (currentlyMoving && (toolbarStack.selectedIndex == 1 || toolbarStack.selectedIndex == 3)) {
if (currentlyMoving.x > 0) {
currentlyMoving.x--;
if (toolbarStack.selectedIndex == 3) positionAnnResize();
if (toolbarStack.selectedIndex == 1) positionResize();
}
}
}

private function canvasOver():void {
if ((toolbarStack.selectedIndex == 3 || toolbarStack.selectedIndex == 1) && currentlyDragging != null) {
cursorManager.setCursor(moveCursor, 2, -9, -10);
}
if (toolbarStack.selectedIndex == 2 && drawTools) {
if (drawTools.selectedIndex < 5) cursorManager.setCursor(crossCursor, 2, -10, -10);
if (drawMode == "pen" || drawMode == "line" || drawMode == "arrow") {
cursorManager.removeAllCursors();
cursorManager.setCursor(emptyCursor, 2, -10, -10);
}
if (drawTools.selectedIndex == 5) cursorManager.setCursor(pickerCursor, 2, 0, -18);
if (drawTools.selectedIndex == 6) {
cursorManager.setCursor(emptyCursor, 2, -10, -10);
eraser.alpha = 1;
};
}
if (toolbarStack.selectedIndex == 4) {
if (!crop_dragging && !crop_resizing) cursorManager.setCursor(crossCursor, 2, -9, -10);
if (crop_dragging) cursorManager.setCursor(moveCursor, 2, -9, -10);
if (crop_resizing) {
switch(crop_resizeDir) {
case "up": case "down": cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10); break;
case "right": case "left": cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10); break;
case "upLeft": case "downRight": cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10); break;
case "upRight": case "downLeft": cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10); break;
}
};
};
}

private function canvasOut():void {
eraser.alpha = 0;
cursorManager.removeAllCursors();
}

private function updateErase():void {
eraser.graphics.clear();
eraser.graphics.lineStyle(1, 0x000000);
eraser.graphics.drawCircle(canvas.mouseX + canvas.horizontalScrollPosition, canvas.mouseY + canvas.verticalScrollPosition, lineThickness*2);
}

private function moveErase():void {
updateErase();
if (erasing) doErase();
}

private function startErase():void {
if (toolbarStack.selectedIndex == 2 && drawTools && drawTools.selectedIndex == 6) {
erasing = true;
doErase();
}
}

private function doErase():void {
var hole:Group = new Group();
hole.graphics.beginFill(0x000000);
hole.graphics.drawCircle(0, 0, lineThickness * 2);
var holeMatrix:Matrix = new Matrix();
holeMatrix.translate(canvas.mouseX - drawArea.x + canvas.horizontalScrollPosition, canvas.mouseY - drawArea.y  + canvas.verticalScrollPosition);
Bitmap(drawBitmap.content).bitmapData.draw(hole, holeMatrix, null, BlendMode.ERASE);
savedOff();
}

private function drawDown():void {
savedOff();
// cropping
if(toolbarStack.selectedIndex == 4 && mouseY>60) crop_mouseDown(drawArea.mouseX, drawArea.mouseY);

// drawing
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 0) {
drawMode = "pen";
tempSprite.graphics.clear();
tempSprite.graphics.moveTo(drawArea.mouseX, drawArea.mouseY);
cursorManager.removeAllCursors();
cursorManager.setCursor(emptyCursor, 2, -10, -10);
}
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 3) {
drawMode = "line";
if (isCtrl && undo_lastPointsMemory[undo_currentMemory] && undo_lastPointsMemory[undo_currentMemory].x>=0 && undo_lastPointsMemory[undo_currentMemory].y>=0) {
tempSprite.graphics.moveTo(undo_lastPointsMemory[undo_currentMemory].x, undo_lastPointsMemory[undo_currentMemory].y);
anchorX = undo_lastPointsMemory[undo_currentMemory].x;
anchorY = undo_lastPointsMemory[undo_currentMemory].y;
}else {
tempSprite.graphics.moveTo(drawArea.mouseX, drawArea.mouseY);
anchorX = drawArea.mouseX;
anchorY = drawArea.mouseY;
}
cursorManager.removeAllCursors();
cursorManager.setCursor(emptyCursor, 2, -10, -10);
}
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 2) {
drawMode = "rect";
anchorX = drawArea.mouseX;
anchorY = drawArea.mouseY;
}
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 1) {
drawMode = "ellipse";
anchorX = drawArea.mouseX;
anchorY = drawArea.mouseY;
}
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 4) {
drawMode = "arrow";
if (isCtrl && undo_lastPointsMemory[undo_currentMemory] && undo_lastPointsMemory[undo_currentMemory].x>=0 && undo_lastPointsMemory[undo_currentMemory].y>=0) {
tempSprite.graphics.moveTo(undo_lastPointsMemory[undo_currentMemory].x, undo_lastPointsMemory[undo_currentMemory].y);
anchorX = undo_lastPointsMemory[undo_currentMemory].x;
anchorY = undo_lastPointsMemory[undo_currentMemory].y;
}else {
tempSprite.graphics.moveTo(drawArea.mouseX, drawArea.mouseY);
anchorX = drawArea.mouseX;
anchorY = drawArea.mouseY;
}
cursorManager.removeAllCursors();
cursorManager.setCursor(emptyCursor, 2, -10, -10);
}
if (toolbarStack.selectedIndex == 2 && drawTools.selectedIndex == 5) {
drawMode = "picker";
drawTempBitmap();
getPickerColor();
}
}

private function drawUp(evt:MouseEvent):void {
if (erasing) {
erasing = false
var newBd:BitmapData = new BitmapData(content.width, content.height, true, 0xff0000);
newBd.draw(drawBitmap, null, null, null, null, true);
addUndo(newBd);
};
img_resizing = false;
ann_resizing = false;

// cropping
if (toolbarStack.selectedIndex == 4 && mouseY>60) crop_stopDraw();

// drawing
if (drawMode == "pen" || drawMode == "line" || drawMode == "rect" || drawMode == "ellipse" || drawMode == "arrow") {
doDrawBitmap();
tempSprite.graphics.clear();
cursorManager.removeAllCursors();
cursorManager.setCursor(crossCursor, 2, -9, -10);
}
drawMode = "";
currentlyDragging = null;
if (toolbarStack.selectedIndex == 3 || toolbarStack.selectedIndex == 1) {
drawHitArea.mouseEnabled = false;
cursorManager.removeAllCursors();
disableResize();
updateDrawHitArea();
}
}

private function addUndo(bd:BitmapData):void {
savedOff();
undo_canRedo = false;
if (undo_currentMemory < undo_memoryLimit - 1) {
undo_currentMemory++;
undo_memory[undo_currentMemory] = bd.clone();
undo_lastPointsMemory[undo_currentMemory] = new Point(lastX, lastY).clone();
undo_canUndo = true;
}else
if (undo_currentMemory == undo_memoryLimit - 1) {
undo_memory.shift();
undo_memory[undo_memoryLimit - 1] = bd.clone();
undo_lastPointsMemory.shift();
undo_lastPointsMemory[undo_memoryLimit - 1] = new Point(lastX, lastY).clone();
undo_canUndo = true;
}
}

private function doUndo():void {
savedOff();
undo_currentMemory--;
drawBitmap.source = new Bitmap(bdClone(undo_memory[undo_currentMemory]), "auto", true);
undo_canRedo = true;
if (undo_currentMemory > 0) undo_canUndo = true;
if (undo_currentMemory <= 0) undo_canUndo = false;
}

private function doRedo():void {
savedOff();
undo_currentMemory++;
drawBitmap.source = new Bitmap(bdClone(undo_memory[undo_currentMemory]), "auto", true);
undo_canUndo = true;
if (undo_currentMemory < undo_memory.length-1) undo_canRedo = true;
if (undo_currentMemory >= undo_memory.length-1) undo_canRedo = false;
}

private function bdClone(bd:BitmapData):BitmapData {
if (bd) {
return bd.clone();
}
else return new BitmapData(content.width, content.height, true, 0xff0000);
}

private function doDrawBitmap():void {
savedOff();
drawBitmap.width = content.width;
drawBitmap.height = content.height;
drawBitmap.validateNow();
var tempBd:BitmapData = new BitmapData(content.width, content.height, true, 0xff0000);
tempBd.draw(tempSprite, null, null, null, null, true);
var bd:BitmapData = new BitmapData(content.width, content.height, true, 0x00ff00);
bd.draw(drawBitmap, null, null, null, null, true);
bd.copyPixels(tempBd, new Rectangle(0, 0, content.width, content.height), new Point(0, 0), null, null, true);
drawBitmap.source = new Bitmap(bd, "auto", true);
addUndo(bd);
}

private function clearDrawBitmap():void {
savedOff();
undo_canRedo = false;
undo_canUndo = false;
undo_currentMemory = 0;
undo_memory = [];
undo_lastPointsMemory = [];
drawBitmap.source = new Bitmap(new BitmapData(content.width, content.height, true, 0x00ffffff));
lastX = -1;
lastY = -1;
}

private function drawMove():void {
// debug
if (toolbarStack.selectedIndex == 2 && mouseY > 100 && focusManager.getFocus() != saveBtn) {
focusManager.setFocus(saveBtn);
}

// image resizing
imageResize();

// annotation resizing
annResize();

// cropping
if(toolbarStack.selectedIndex == 4) crop_moveDraw(drawArea.mouseX, drawArea.mouseY);

// drawing
if (drawMode == "pen") {
tempSprite.graphics.lineStyle(lineThickness, lineColor);
tempSprite.graphics.lineTo(drawArea.mouseX, drawArea.mouseY);
tempSprite.validateNow();
}
if (drawMode == "line") {
if (!isShift) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
tempSprite.graphics.moveTo(anchorX, anchorY);
tempSprite.graphics.lineTo(drawArea.mouseX, drawArea.mouseY);
lastX = drawArea.mouseX;
lastY = drawArea.mouseY;
}
if (isShift) {
var straightLinePoint:Point = straightLine(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY);
if (straightLinePoint.x > lineThickness / 2 && straightLinePoint.x < drawArea.width - lineThickness / 2 &&
straightLinePoint.y > lineThickness/2 && straightLinePoint.y < drawArea.height - lineThickness /2) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
tempSprite.graphics.moveTo(anchorX, anchorY);
tempSprite.graphics.lineTo(straightLinePoint.x, straightLinePoint.y);
lastX = straightLinePoint.x;
lastY = straightLinePoint.y;
}
}
}
if (drawMode == "rect") {
var newRectValues:Array;
if (!isShift) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newRectValues = calculateRectValues(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY);
}
if(isShift){
newRectValues = calculateSquareValues(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY);
}
tempSprite.graphics.drawRect(newRectValues[0], newRectValues[1], newRectValues[2], newRectValues[3]);
lastX = drawArea.mouseX;
lastY = drawArea.mouseY;
}
if (drawMode == "ellipse") {
var newEllipseValues:Array;
if (!isShift) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newEllipseValues = calculateRectValues(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY);
}
if(isShift){
newEllipseValues = calculateSquareValues(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY);
}
tempSprite.graphics.drawEllipse(newEllipseValues[0], newEllipseValues[1], newEllipseValues[2], newEllipseValues[3]);
lastX = drawArea.mouseX;
lastY = drawArea.mouseY;
}
if (drawMode == "arrow") {
var mouseX:Number = (isShift)?(straightLine(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY).x):(drawArea.mouseX);
var mouseY:Number = (isShift)?(straightLine(drawArea.mouseX, drawArea.mouseY, anchorX, anchorY).y):(drawArea.mouseY);
var angle:Number = Math.atan2(anchorY - mouseY, anchorX - mouseX);
var armlength:Number = 10 + 2.5 * lineThickness;
var offset:Number = (24 - 0.5 * lineThickness) * Math.PI / 180;
var arm1x:Number = armlength * Math.cos(angle + offset) + mouseX;
var arm1y:Number = armlength * Math.sin(angle + offset) + mouseY;
var arm2x:Number = armlength * Math.cos(angle - offset) + mouseX;
var arm2y:Number = armlength * Math.sin(angle - offset) + mouseY;

if (arm1x > 0 + lineThickness / 2 && arm1x < drawArea.width - lineThickness / 2 &&
arm1y > 0 + lineThickness / 2 && arm1y < drawArea.height - lineThickness / 2 &&
arm2x > 0 + lineThickness / 2 && arm2x < drawArea.width - lineThickness / 2 &&
arm2y > 0 + lineThickness / 2 && arm2y < drawArea.height - lineThickness / 2 &&
mouseX > 9 + lineThickness / 2 && mouseX < drawArea.width - lineThickness / 2 - 9 &&
mouseY > 9 + lineThickness / 2 && mouseY < drawArea.height - lineThickness / 2 - 9){
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor, 1, false, "normal", CapsStyle.NONE, JointStyle.MITER);
tempSprite.graphics.moveTo(anchorX, anchorY);
tempSprite.graphics.lineTo(mouseX, mouseY);

tempSprite.graphics.beginFill(lineColor, 1);
tempSprite.graphics.moveTo(arm1x, arm1y);
tempSprite.graphics.lineTo(mouseX, mouseY);
tempSprite.graphics.lineTo(arm2x, arm2y);
tempSprite.graphics.lineTo(arm1x, arm1y);
tempSprite.graphics.endFill();

lastX = mouseX;
lastY = mouseY;
}
}
if (drawMode == "picker") {
getPickerColor();
}
if ((toolbarStack.selectedIndex == 3 || toolbarStack.selectedIndex == 1) && currentlyDragging != null) {
var nextDragX:Number = drawArea.mouseX - dragOffsetX;
var nextDragY:Number = drawArea.mouseY - dragOffsetY;
if (nextDragX >= 0 && nextDragX + currentlyDragging.width <= content.width) currentlyDragging.x = nextDragX;
if (nextDragY >= 0 && nextDragY + currentlyDragging.height <= content.height) currentlyDragging.y = nextDragY;
if (nextDragX < 0) currentlyDragging.x = 0;
if (nextDragY < 0) currentlyDragging.y = 0;
if (nextDragX + currentlyDragging.width > content.width) currentlyDragging.x = content.width - currentlyDragging.width;
if (nextDragY + currentlyDragging.height > content.height) currentlyDragging.y = content.height - currentlyDragging.height;
if (toolbarStack.selectedIndex == 1) positionResize();
if (toolbarStack.selectedIndex == 3) positionAnnResize();
}
}

private function straightLine(mouseX:Number, mouseY:Number, anchX:Number, anchY:Number):Point {
var p:Point = new Point(0, 0);
var rotation:Number = Math.atan2(mouseY - anchY, mouseX - anchX) * 180 / Math.PI;
if (rotation<-35 && rotation>-55) {
p = new Point(mouseX, anchY - (mouseX - anchX));
}else
if (rotation<-125 && rotation>-145) {
p = new Point(mouseX, (mouseX - anchX) + anchY);
}else
if (rotation>35 && rotation<55) {
p = new Point(mouseX, (mouseX - anchX) + anchY);
}else
if (rotation>125 && rotation<145) {
p = new Point(mouseX, anchY - (mouseX - anchX));
}else
if (Math.abs(mouseX - anchX) > Math.abs(mouseY - anchY)) {
p = new Point(mouseX, anchY);
}else
if (Math.abs(mouseX - anchX) < Math.abs(mouseY - anchY)) {
p = new Point(anchX, mouseY);
}
return p;
}

private function calculateRectValues(currentX:Number, currentY:Number, anchX:Number, anchY:Number):Array {
var newrect:Array = [0, 0, 0, 0];
// bottom - right
if (currentX > anchX  && currentY > anchY) {
newrect[0] = anchX;
newrect[1] = anchY-1;
newrect[2] = currentX - anchX;
newrect[3] = currentY - anchY;
}
// bottom - left
if (currentX < anchX  && currentY > anchY) {
newrect[0] = currentX;
newrect[1] = anchY-1;
newrect[2] = anchX - currentX;
newrect[3] = currentY - anchY;
}
// top - right
if (currentX > anchX  && currentY < anchY) {
newrect[0] = anchX;
newrect[1] = currentY-1;
newrect[2] = currentX - anchX;
newrect[3] = anchY - currentY;
}
// top - left
if (currentX < anchX  && currentY < anchY) {
newrect[0] = currentX;
newrect[1] = currentY-1;
newrect[2] = anchX - currentX;
newrect[3] = anchY - currentY;
}
return newrect;
}

private function calculateSquareValues(currentX:Number, currentY:Number, anchX:Number, anchY:Number):Array {
var newrect:Array = [0, 0, 0, 0];
// bottom - right
if (currentX > anchX  && currentY > anchY) {
currentY = (currentX - anchX) + anchY;
if (currentY > 0 + lineThickness/2 && currentY < drawArea.height - lineThickness/2) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newrect[0] = anchX;
newrect[1] = anchY-1;
newrect[2] = currentX - anchX;
newrect[3] = currentY - anchY;
}
}
// bottom - left
if (currentX < anchX  && currentY > anchY) {
currentY = anchY - (currentX - anchX);
if (currentY > 0 + lineThickness/2 && currentY < drawArea.height - lineThickness/2) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newrect[0] = currentX;
newrect[1] = anchY-1;
newrect[2] = anchX - currentX;
newrect[3] = currentY - anchY;
}
}
// top - right
if (currentX > anchX  && currentY < anchY) {
currentY = anchY - (currentX - anchX);
if (currentY > 0 + lineThickness/2 && currentY < drawArea.height - lineThickness/2) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newrect[0] = anchX;
newrect[1] = currentY-1;
newrect[2] = currentX - anchX;
newrect[3] = anchY - currentY;
}
}
// top - left
if (currentX < anchX  && currentY < anchY) {
currentY = (currentX - anchX) + anchY;
if (currentY > 0 + lineThickness/2 && currentY < drawArea.height - lineThickness/2) {
tempSprite.graphics.clear();
tempSprite.graphics.lineStyle(lineThickness, lineColor);
newrect[0] = currentX;
newrect[1] = currentY-1;
newrect[2] = anchX - currentX;
newrect[3] = anchY - currentY;
}
}
return newrect;
}

private function importPicture():void {
var file:File = new File();
var imageFilter:FileFilter = new FileFilter("Images", "*.jpg;*jpeg;*.gif;*.png");
file.browseForOpen("Import picture", [imageFilter]);
file.addEventListener(Event.SELECT, fileSelect);
}

private function importScreenshot():void {
var hasUrl:Boolean = Clipboard.generalClipboard.hasFormat(ClipboardFormats.URL_FORMAT);
if (!hasUrl){
content = Clipboard.generalClipboard.getData(ClipboardFormats.BITMAP_FORMAT) as BitmapData;
bitmapData = Clipboard.generalClipboard.getData(ClipboardFormats.BITMAP_FORMAT) as BitmapData;
stackChange(); // needed if selectedIndex was already 1 when the function was called
stack.selectedIndex = 1;
}
if (hasUrl) {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
loader.load(new URLRequest(Clipboard.generalClipboard.getData(ClipboardFormats.URL_FORMAT)+""));
}
}

private function fileSelect(evt:Event):void {
var file:File = evt.target as File;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
loader.load(new URLRequest(file.url));
}

private function loadComplete(evt:Event):void {
content = evt.target.content;
bitmapData = new BitmapData(content.width, content.height, false);
bitmapData.draw(content, new Matrix(), null, null, null, true);
stackChange(); // needed if selectedIndex was already 1 when the function was called
stack.selectedIndex = 1;
savedOff();
}

private function stackChange():void {
if (stack.selectedIndex == 1) {
imgHolder.source = new Bitmap(bitmapData);
drawArea.width = content.width;
drawArea.height = content.height;
drawGroup.width = content.width;
drawGroup.height = content.height;
cropDraw.width = content.width;
cropDraw.height = content.height;
eraser.width = content.width;
eraser.height = content.height;
buttonsEnabled = true;
clearDrawBitmap();
var anns:Number = annotations.numChildren;
for (var i:int = 0; i < anns; i++){
annotations.removeElementAt(0);
}
var imgs:Number = images.numChildren;
for (var u:int = 0; u < imgs; u++){
images.removeElementAt(0);
}
drawTempBitmap();
updateDrawHitArea();
crop_deselect();
undo_canRedo = false;
undo_canUndo = false;
undo_currentMemory = 0;
undo_memory = [];
undo_lastPointsMemory = [];
lastX = -1;
lastY = -1;
savedAlpha = 1;
savedOff();
}
}

private function toolbarChange():void {
if (toolbarStack.selectedIndex == 1) {
drawHitArea.mouseEnabled = false;
annotations.buttonMode = false;
annotations.mouseEnabled = false;
annotations.mouseChildren = false;
images.buttonMode = true;
images.mouseEnabled = true;
images.mouseChildren = true;
}else if 
(toolbarStack.selectedIndex == 2) {
updateLineExample();
drawHitArea.mouseEnabled = true;
}else if 
(toolbarStack.selectedIndex == 3) {
drawHitArea.mouseEnabled = false;
annotations.buttonMode = true;
annotations.mouseEnabled = true;
annotations.mouseChildren = true;
images.buttonMode = false;
images.mouseEnabled = false;
images.mouseChildren = false;
}else if 
(toolbarStack.selectedIndex == 4) {
drawHitArea.mouseEnabled = true;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
drawHitArea.x = -1;
drawHitArea.y = 1;
}else {
drawHitArea.mouseEnabled = false;
}
currentlyMoving = null;
}

private function updateLineExample():void{
lineExample.graphics.clear();
lineExample.graphics.lineStyle(lineThickness, lineColor);
lineExample.graphics.moveTo(10, 10);
lineExample.graphics.lineTo(30, 10);

updateDrawHitArea();
}

private function updateDrawHitArea():void {
drawHitArea.width = content.width - lineThickness;
drawHitArea.height = content.height - lineThickness;
drawHitArea.x = lineThickness / 2;
drawHitArea.y = lineThickness / 2;

annHitArea.width = content.width;
annHitArea.height = content.height;
annHitArea.x = 0;
annHitArea.y = 0;
}

private function drawTempBitmap():void {
temporaryBitmap = new BitmapData(content.width, content.height, false, 0xffffff);
temporaryBitmap.draw(drawArea);
}

private function getPickerColor():void {
lineColor = temporaryBitmap.getPixel(drawArea.mouseX, drawArea.mouseY);
if (isShift) {
var myClip:Clipboard = Clipboard.generalClipboard;
myClip.setData(ClipboardFormats.TEXT_FORMAT, "#" + lineColor.toString(16));
}
}

private function openAnnotation(createX:Number = 0, createY:Number = 0):void {
if(toolbarStack.selectedIndex==3){
PopUpManager.addPopUp(annotationWindow, this, true);
PopUpManager.centerPopUp(annotationWindow);
annText.text = "Enter text here";
annotationWindow.title = "Create new annotation";
annWidth.maximum = drawArea.width;
if (firstTimeEditing) annWidth.value = 200;
firstTimeEditing = false;
annX.value = createX;
annY.value = createY;
updateAnnCoordLimits();
baNew.enabled = true;
baEdit.enabled = false;
baDelete.enabled = false;
}
}

private function closeAnnotation():void {
PopUpManager.removePopUp(annotationWindow);
}

private function addAnnotation():void {
var newAnn:spark.components.TextArea = new spark.components.TextArea();
newAnn.text = annText.text;
newAnn.width = annWidth.value;
newAnn.setStyle("contentBackgroundColor", aBodyColor);
newAnn.setStyle("color", aTextColor);
newAnn.setStyle("borderVisible", annBorder.selected);
newAnn.setStyle("contentBackgroundAlpha", aBodyAlpha)
newAnn.setStyle("fontSize", aTextSize);
newAnn.editable = false;
newAnn.selectable = false;
annotations.addElement(newAnn);
newAnn.validateNow();
newAnn.heightInLines = NaN;
newAnn.x = annX.value;
newAnn.y = annY.value;
newAnn.addEventListener(MouseEvent.ROLL_OVER, annOver);
newAnn.addEventListener(MouseEvent.ROLL_OUT, annOut);
newAnn.addEventListener(MouseEvent.DOUBLE_CLICK, annClick);
newAnn.addEventListener(MouseEvent.MOUSE_DOWN, annDown);
newAnn.addEventListener(MouseEvent.MOUSE_MOVE, annMove);
newAnn.buttonMode = true;
savedOff();
}

private function editAnnotation():void {
var editAnn:* = currentlyEditing;
editAnn.text = annText.text;
editAnn.width = annWidth.value;
editAnn.setStyle("contentBackgroundColor", aBodyColor);
editAnn.setStyle("borderVisible", annBorder.selected);
editAnn.setStyle("color", aTextColor);
editAnn.setStyle("contentBackgroundAlpha", aBodyAlpha);
editAnn.setStyle("fontSize", aTextSize);
editAnn.heightInLines = NaN;
editAnn.x = annX.value;
editAnn.y = annY.value;
savedOff();
}

private function deleteAnnotation():void {
annotations.removeElement(currentlyEditing);
savedOff();
}

private function annOver(evt:MouseEvent):void {
disableResize();
if (toolbarStack.selectedIndex == 3) {
evt.target.alpha = 0.8;
currentAnn = evt.currentTarget;
createAnnAnchors();
enableAnnResize();
positionAnnResize();
}
}

private function annOut(evt:MouseEvent):void{
evt.target.alpha = 1;
if (toolbarStack.selectedIndex == 3 && currentlyDragging == null) {
cursorManager.removeAllCursors();
}
}

private function annClick(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 3) {
currentlyEditing = evt.currentTarget;
PopUpManager.addPopUp(annotationWindow, this, true);
PopUpManager.centerPopUp(annotationWindow);
annText.text = currentlyEditing.text;
annotationWindow.title = "Edit annotation";
annWidth.maximum = drawArea.width;
annWidth.value = currentlyEditing.width;
aBodyColor = currentlyEditing.getStyle("contentBackgroundColor");
aTextColor = currentlyEditing.getStyle("color");
aBodyAlpha = currentlyEditing.getStyle("contentBackgroundAlpha");
aTextSize = currentlyEditing.getStyle("fontSize");
annBorder.selected = currentlyEditing.getStyle("borderVisible");
annX.value = currentlyEditing.x;
annY.value = currentlyEditing.y;
updateAnnCoordLimits();
baNew.enabled = false;
baEdit.enabled = true;
baDelete.enabled = true;
}
}

private function annDown(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 3) {
currentlyDragging = evt.currentTarget;
currentlyMoving = evt.currentTarget;
dragOffsetX = evt.currentTarget.mouseX;
dragOffsetY = evt.currentTarget.mouseY;
}
}

private function annMove(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 3 && currentlyDragging && !drawHitArea.mouseEnabled) {
annotations.setElementIndex(currentlyDragging, annotations.numElements - 1);
cursorManager.setCursor(moveCursor, 2, -10, -10);
drawHitArea.mouseEnabled = true;
drawHitArea.x = -1;
drawHitArea.y = 0;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
}
}

private function updateAnnCoordLimits():void{
annX.maximum = content.width - annWidth.value;
annY.maximum = content.height;
}

private function newFile():void {
PopUpManager.addPopUp(newfileWindow, this, true);
PopUpManager.centerPopUp(newfileWindow);
newfileStack.selectedIndex = 0;
newfileWindow.width = 200;
newfileWindow.height = 130;
checkScreenshot = true;
}

private function closeNewfile():void {
PopUpManager.removePopUp(newfileWindow);
checkScreenshot = false;
}

private function blankPicture():void {
content = new Image();
bitmapData = new BitmapData(newWidth.value, newHeight.value, false, newColor.selectedColor);
content.width = newWidth.value;
content.height = newHeight.value;
stackChange();
stack.selectedIndex = 1;
}

private function saveFile():void {
PopUpManager.addPopUp(saveWindow, this, true);
PopUpManager.centerPopUp(saveWindow);
if (selectedFormat == 'jpg') {
radioJPG.selected = true;
}
if (selectedFormat == 'png') {
radioPNG.selected = true;
}
sliderJPG.value = selectedQuality;
}

private function closeSave():void {
PopUpManager.removePopUp(saveWindow);
}

private function changeSelectedFormat(format:String):void {
selectedFormat = format;
preferences.data.selectedFormat = selectedFormat;
preferences.flush();
}

private function changeSelectedQuality():void {
selectedQuality = sliderJPG.value;
preferences.data.selectedQuality = selectedQuality;
preferences.flush();
}

private function startExport():void {
var encoder:IImageEncoder;
var byteArray:ByteArray;
var file:File;
var fileStream:FileStream;
var bd:BitmapData;

if (selectedFormat == "jpg") {
encoder = new JPEGEncoder(selectedQuality);
}
if (selectedFormat == "png") {
encoder = new PNGEncoder();
}

if(crop_rectangle[2]==0 || crop_rectangle[3]==0){
bd = new BitmapData(content.width, content.height, false);
bd.draw(drawArea);
}else {
cropDraw.visible = false;
cropDraw.validateNow();
bd = new BitmapData(crop_rectangle[2] + 1, crop_rectangle[3] + 1, false);
bd.draw(drawArea, new Matrix(1, 0, 0, 1, -crop_rectangle[0], -crop_rectangle[1]));
cropDraw.visible = true;
}

byteArray = encoder.encode(bd);
file = File.documentsDirectory.resolvePath("annotation");
file.browseForSave("Save annotated image");
file.addEventListener(Event.SELECT, saveSelect);

function saveSelect():void {
file.nativePath += "." + selectedFormat;
if (!file.exists) {
savedOn();
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(byteArray);
fileStream.close();
} else {
Alert.show("File already exists. Overwrite?", "Hey!", Alert.YES | Alert.NO, null, onCloseOverwrite);
}
}

function onCloseOverwrite(evt:CloseEvent):void {
if (evt.detail == Alert.YES) {
savedOn();
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeBytes(byteArray);
fileStream.close();
}
}
}

private function crop_mouseDown(mouseX:Number, mouseY:Number):void {
if (!crop_inSelection && !crop_inResize) crop_startDraw(mouseX, mouseY);
if (crop_inSelection && !crop_inResize) crop_startDrag(mouseX - crop_rectangle[0], mouseY - crop_rectangle[1]);
if (crop_inResize) crop_startResize();
}

private function crop_startDraw(mouseX:Number, mouseY:Number):void {
crop_anchorX = mouseX;
crop_anchorY = mouseY;
crop_drawing = true;

crop_rectangle = [crop_anchorX, crop_anchorY, 0, 0];
crop_updateDraw();
savedOff();
}

private function crop_startDrag(offX:Number, offY:Number):void {
crop_offsetX = offX;
crop_offsetY = offY;
crop_dragging = true;
savedOff();
}

private function crop_startResize():void {
crop_resizing = true;
if (crop_resizeDir == "up" || crop_resizeDir == "upLeft" || crop_resizeDir == "upRight") crop_anchorY = crop_rectangle[1] + crop_rectangle[3];
if (crop_resizeDir == "down" || crop_resizeDir == "downLeft" || crop_resizeDir == "downRight") crop_anchorY = crop_rectangle[1];
if (crop_resizeDir == "left" || crop_resizeDir == "upLeft" || crop_resizeDir == "downLeft") crop_anchorX = crop_rectangle[0] + crop_rectangle[2];
if (crop_resizeDir == "right" || crop_resizeDir == "upRight" || crop_resizeDir == "downRight") crop_anchorX = crop_rectangle[0];
savedOff();
}

private function crop_stopDraw():void {
crop_drawing = false;
crop_dragging = false;
crop_resizing = false;
if (new Rectangle(drawArea.x, drawArea.y, content.width, content.height).containsPoint(new Point(canvas.mouseX, canvas.mouseY)) == false && mouseY>=canvas.y){
cursorManager.removeAllCursors();
cursorManager.setCursor(crossCursor, 2, -9, -10);
}
}

private function crop_areaRollOut():void {
if(!crop_drawing && !crop_dragging && !crop_resizing && toolbarStack.selectedIndex == 4){
cursorManager.removeAllCursors();
cursorManager.setCursor(crossCursor, 2, -9, -10);
}
}

private function crop_moveDraw(mouseX:Number, mouseY:Number):void {
if(!crop_drawing && !crop_resizing && !crop_dragging){
cursorManager.removeAllCursors();
crop_inSelection = new Rectangle(crop_rectangle[0], crop_rectangle[1], crop_rectangle[2], crop_rectangle[3]).containsPoint(new Point(mouseX, mouseY));
if (new Rectangle(crop_rectangle[0] - crop_resizeRadius, crop_rectangle[1] - crop_resizeRadius, crop_resizeRadius * 2, crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "upLeft";
crop_inResize = true;
cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0] + crop_rectangle[2] - crop_resizeRadius, crop_rectangle[1] - crop_resizeRadius, crop_resizeRadius * 2, crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "upRight";
crop_inResize = true;
cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0] - crop_resizeRadius, crop_rectangle[1] + crop_rectangle[3] - crop_resizeRadius, crop_resizeRadius * 2, crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "downLeft";
crop_inResize = true;
cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0] + crop_rectangle[2] - crop_resizeRadius, crop_rectangle[1] + crop_rectangle[3] - crop_resizeRadius, crop_resizeRadius * 2, crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "downRight";
crop_inResize = true;
cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0], crop_rectangle[1] - crop_resizeRadius, crop_rectangle[2], crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "up";
crop_inResize = true;
cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0], crop_rectangle[1] + crop_rectangle[3] - crop_resizeRadius, crop_rectangle[2], crop_resizeRadius * 2).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "down";
crop_inResize = true;
cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0] - crop_resizeRadius, crop_rectangle[1], crop_resizeRadius * 2, crop_rectangle[3]).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "left";
crop_inResize = true;
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10)
}else
if (new Rectangle(crop_rectangle[0] + crop_rectangle[2] - crop_resizeRadius, crop_rectangle[1], crop_resizeRadius * 2, crop_rectangle[3]).containsPoint(new Point(mouseX, mouseY))) {
crop_resizeDir = "right";
crop_inResize = true;
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10)
}else
{crop_inResize = false; }
if (crop_inSelection && !crop_inResize) cursorManager.setCursor(moveCursor, 2, -9, -10);
if (!crop_inSelection && !crop_inResize) cursorManager.setCursor(crossCursor, 2, -9, -10);
}
if (crop_drawing) {
crop_rectangle = calculateRectValues(mouseX, mouseY, crop_anchorX, crop_anchorY);
crop_updateDraw();
}
if (crop_dragging) {
var newX:Number = mouseX - crop_offsetX;
var newY:Number = mouseY - crop_offsetY;
if (newX >= 0 && newX + crop_rectangle[2] < content.width) crop_rectangle[0] = newX;
if (newX < 0) crop_rectangle[0] = 0;
if (newX + crop_rectangle[2] >= content.width) crop_rectangle[0] = content.width - crop_rectangle[2] - 1;
if (newY >= 0 && newY + crop_rectangle[3] < content.height) crop_rectangle[1] = newY;
if (newY < 0) crop_rectangle[1] = 0;
if (newY + crop_rectangle[3] >= content.height) crop_rectangle[1] = content.height - crop_rectangle[3] - 1;
crop_updateDraw();
}
if (crop_resizing) {
var prevRect:Array = crop_rectangle;
if (crop_resizeDir == "up" && mouseY >= 0 && mouseY < crop_anchorY) crop_rectangle = [prevRect[0], mouseY - 1, prevRect[2], crop_anchorY - mouseY + 1];
if (crop_resizeDir == "down" && mouseY < content.height && mouseY > crop_anchorY) crop_rectangle = [prevRect[0], crop_anchorY, prevRect[2], mouseY - crop_anchorY];
if (crop_resizeDir == "left" && mouseX >= 0 && mouseX < crop_anchorX) crop_rectangle = [mouseX, prevRect[1], crop_anchorX - mouseX, prevRect[3]];
if (crop_resizeDir == "right" && mouseX < content.width && mouseX > crop_anchorX) crop_rectangle = [crop_anchorX, prevRect[1], mouseX - crop_anchorX, prevRect[3]];
if (crop_resizeDir == "upLeft" && mouseY >= 0 && mouseY < crop_anchorY && mouseX >= 0 && mouseX < crop_anchorX) crop_rectangle = [mouseX, mouseY - 1, crop_anchorX - mouseX, crop_anchorY - mouseY + 1];
if (crop_resizeDir == "upRight" && mouseY >= 0 && mouseY < crop_anchorY && mouseX < content.width && mouseX > crop_anchorX) crop_rectangle = [crop_anchorX, mouseY - 1, mouseX - crop_anchorX, crop_anchorY - mouseY + 1];
if (crop_resizeDir == "downLeft" && mouseY < content.height && mouseY > crop_anchorY && mouseX >= 0 && mouseX < crop_anchorX) crop_rectangle = [mouseX, crop_anchorY, crop_anchorX - mouseX, mouseY - crop_anchorY];
if (crop_resizeDir == "downRight" && mouseY < content.height && mouseY > crop_anchorY && mouseX < content.width && mouseX > crop_anchorX) crop_rectangle = [crop_anchorX, crop_anchorY, mouseX - crop_anchorX, mouseY - crop_anchorY];
crop_updateDraw();
}
}

private function crop_updateDraw():void {
cropDraw.graphics.clear();
if(!crop_selectionType){
cropDraw.graphics.lineStyle(1, 0xff0000);
cropDraw.graphics.beginFill(0x00ff00, 0.2);
cropDraw.graphics.drawRect(crop_rectangle[0] - 1, crop_rectangle[1] - 1, crop_rectangle[2] + 2, crop_rectangle[3] + 2);
}
if(crop_selectionType){
cropDraw.graphics.beginFill(0x000000, 0.4);
cropDraw.graphics.lineStyle(1, 0x000000, 0);
cropDraw.graphics.drawRect(0, 0, content.width, crop_rectangle[1]);
cropDraw.graphics.drawRect(0, crop_rectangle[1], crop_rectangle[0], crop_rectangle[3] + 1);
cropDraw.graphics.drawRect(crop_rectangle[0] + crop_rectangle[2] + 1, crop_rectangle[1], content.width - crop_rectangle[0] - crop_rectangle[2] - 1, crop_rectangle[3] + 1);
cropDraw.graphics.drawRect(0, crop_rectangle[1] + crop_rectangle[3] + 1, content.width, content.height - crop_rectangle[1] - crop_rectangle[3] - 1);
}
if (crop_rectangle[2] == 0 || crop_rectangle[3] == 0) cropDraw.graphics.clear();
}

private function crop_deselect():void {
crop_rectangle = [0, -1000, 0, 0];
cropDraw.graphics.clear();
savedOff();
}

private function crop_changeSelectionType():void {
crop_selectionType = !crop_selectionType;
preferences.data.selectionType = crop_selectionType;
preferences.flush();
crop_updateDraw();
}

private function openImage():void {
if(toolbarStack.selectedIndex==1){
PopUpManager.addPopUp(imageWindow, this, true);
PopUpManager.centerPopUp(imageWindow);
imageWindow.title = "Add new image";
biNew.enabled = false;
biUpdate.enabled = false;
biDelete.enabled = false;
iPath.text = "";
iPreview.source = null;
iWidth.value = 10;
iHeight.value = 10;
iX.value = 0;
iY.value = 0;
updateImgLimits();
}
}

private function closeImage():void {
PopUpManager.removePopUp(imageWindow);
}

private function imageBrowse():void {
var file:File = new File();
var imageFilter:FileFilter = new FileFilter("Images", "*.jpg;*jpeg;*.gif;*.png");
file.browseForOpen("Import picture", [imageFilter]);
file.addEventListener(Event.SELECT, fileSel);

function fileSel(evt:Event):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComp);
loader.load(new URLRequest(file.url));
}

function loadComp(evt:Event):void {
iPreview.source = evt.target.content;
iPreviewHidden.source = evt.target.content;
iPath.text = file.nativePath;
updatePreviewImage();
}
}

private function updatePreviewImage():void {
var ratio:Number;
smoothImage(iPreview);
iPreviewHidden.validateNow();
iWidth.value = iPreviewHidden.contentWidth;
iHeight.value = iPreviewHidden.contentHeight;
if (iWidth.value > content.width) {
ratio = iHeight.value / iWidth.value;
iWidth.value = content.width;
iHeight.value = content.width * ratio;
}
if (iHeight.value > content.height) {
ratio = iWidth.value / iHeight.value;
iHeight.value = content.height;
iWidth.value = content.height * ratio;
}
imgOriginal.text = "Original size: " + iPreviewHidden.contentWidth + "x" + iPreviewHidden.contentHeight;
if (!biUpdate.enabled) biNew.enabled = true;
}

private function smoothImage(target:Image):void{
var bitmap:Bitmap = ((target as Image).content as Bitmap);
if (bitmap != null) {
bitmap.smoothing = true;
}
}

private function addImage():void {
var newImg:Image = new Image();
newImg.source = new Bitmap(Bitmap(iPreview.content).bitmapData);
newImg.toolTip = iPath.text;
newImg.maintainAspectRatio = false;
newImg.scaleContent = true;
newImg.width = iWidth.value;
newImg.height = iHeight.value;
images.addElement(newImg);
smoothImage(newImg);
newImg.validateNow();
newImg.x = iX.value;
newImg.y = iY.value;
newImg.doubleClickEnabled = true;
newImg.addEventListener(MouseEvent.ROLL_OVER, imgOver);
newImg.addEventListener(MouseEvent.ROLL_OUT, imgOut);
newImg.addEventListener(MouseEvent.DOUBLE_CLICK, imgClick);
newImg.addEventListener(MouseEvent.MOUSE_DOWN, imgDown);
newImg.addEventListener(MouseEvent.MOUSE_MOVE, imgMove);
newImg.buttonMode = true;
savedOff();
}

private function editImage():void {
var editImg:* = currentlyEditing;
editImg.source = new Bitmap(Bitmap(iPreview.content).bitmapData);
editImg.toolTip = iPath.text;
editImg.width = iWidth.value;
editImg.height = iHeight.value;
editImg.x = iX.value;
editImg.y = iY.value;
updateImgLimits();
savedOff();
}

private function deleteImage():void {
images.removeElement(currentlyEditing);
savedOff();
}

private function imgOver(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 1) {
evt.target.alpha = 0.7;
currentImage = evt.currentTarget;
createAnchors();
enableResize();
positionResize();
}
}

private function imgOut(evt:MouseEvent):void{
evt.target.alpha = 1;
if (toolbarStack.selectedIndex == 1 && currentlyDragging == null) {
cursorManager.removeAllCursors();
}
}

private function imgClick(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 1) {
currentlyEditing = evt.currentTarget;
PopUpManager.addPopUp(imageWindow, this, true);
PopUpManager.centerPopUp(imageWindow);
imageWindow.title = "Edit image";
iPath.text = evt.currentTarget.toolTip;
iPreview.source = new Bitmap(Bitmap(evt.currentTarget.content).bitmapData);
iWidth.value = evt.currentTarget.width;
iHeight.value = evt.currentTarget.height;
iX.value = evt.currentTarget.x;
iY.value = evt.currentTarget.y;
iX.maximum = content.width;
iY.maximum = content.height;
biNew.enabled = false;
biUpdate.enabled = true;
biDelete.enabled = true;
}
}

private function imgDown(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 1) {
currentlyDragging = evt.currentTarget;
currentlyMoving = evt.currentTarget;
dragOffsetX = evt.currentTarget.mouseX;
dragOffsetY = evt.currentTarget.mouseY;
}
}

private function imgMove(evt:MouseEvent):void {
if (toolbarStack.selectedIndex == 1 && currentlyDragging && !drawHitArea.mouseEnabled) {
images.setElementIndex(currentlyDragging, images.numElements - 1);
cursorManager.setCursor(moveCursor, 2, -10, -10);
drawHitArea.mouseEnabled = true;
drawHitArea.x = -1;
drawHitArea.y = 0;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
}
}

private function updateImgLimits():void {
iX.maximum = content.width - iWidth.value;
iY.maximum = content.height - iHeight.value;
iWidth.maximum = content.width;
iHeight.maximum = content.height;
}

private function createAnnAnchors():void {
if (annAnchors == null) {
annAnchors = [];
for (var i:int = 0; i < 2; i++) {
var newAnchor:SpriteVisualElement = new SpriteVisualElement();
newAnchor.width = 10;
newAnchor.height = 10;
newAnchor.graphics.lineStyle(2, 0x000000);
newAnchor.graphics.beginFill(0xffffff);
newAnchor.graphics.drawRect(0, 0, 10, 10);
anchorsAnn.addElement(newAnchor);
annAnchors.push(newAnchor);
newAnchor.addEventListener(MouseEvent.ROLL_OVER, anchorAnnOver);
newAnchor.addEventListener(MouseEvent.ROLL_OUT, anchorAnnOut);
newAnchor.addEventListener(MouseEvent.MOUSE_DOWN, anchorAnnDown);
}
}
/* Layout:
- - -
0 - 1
- - -*/
}

private function anchorAnnOver(evt:MouseEvent):void {
if(anchorsAnn.alpha>0){
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10);
}
}

private function anchorAnnOut(evt:MouseEvent):void {
cursorManager.removeAllCursors();
}

private function anchorAnnDown(evt:MouseEvent):void {
ann_positions = [currentAnn.x, currentAnn.width];
switch(evt.currentTarget) {
case annAnchors[0]: ann_currentDir = "left"; ann_anchorX = currentAnn.x + currentAnn.width; break;
case annAnchors[1]: ann_currentDir = "right"; ann_anchorX = currentAnn.x; break;
}
ann_resizing = true;
drawHitArea.mouseEnabled = true;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
drawHitArea.x = -1;
drawHitArea.y = 1;
savedOff();
}

private function annResize():void {
if (ann_resizing) {
cursorManager.removeAllCursors();
var mouseX:Number = drawArea.mouseX;
if (ann_currentDir == "left" && mouseX >= 0 && mouseX < ann_anchorX) {
ann_positions = [mouseX, ann_anchorX - mouseX];
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10);
}
if (ann_currentDir == "right" && mouseX < content.width && mouseX > ann_anchorX) {
ann_positions = [ann_anchorX, mouseX - ann_anchorX];
cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10);
}

if(ann_positions[0] >=0 && ann_positions[1] + ann_positions[0]<=content.width){
updateAnn();
positionAnnResize();
}
}
}

private function updateAnn():void {
currentAnn.x = ann_positions[0];
currentAnn.width = ann_positions[1];
currentAnn.heightInLines = NaN;
annWidth.value = currentAnn.width;
updateAnnCoordLimits();
}

private function enableAnnResize():void {
anchorsAnn.alpha = 0.8;
anchorsAnn.mouseEnabled = true;
anchorsAnn.mouseChildren = true;
}

private function disableAnnResize():void {
if(toolbarStack.selectedIndex==3 && !ann_resizing){
anchorsAnn.alpha = 0;
anchorsAnn.mouseEnabled = false;
anchorsAnn.mouseChildren = false;
}
}

private function positionAnnResize():void {
currentAnn.heightInLines = NaN;
var cX:Number = currentAnn.x;
var cY:Number = currentAnn.y;
var cW:Number = currentAnn.width;
var cH:Number = currentAnn.height;
annAnchors[0].x = cX - 5;
annAnchors[0].y = cY + cH/2 - 5;
annAnchors[1].x = cX + cW - 5;
annAnchors[1].y = cY + cH/2 - 5;
}

/////////////////////////////////////////////////

private function createAnchors():void {
if (imageAnchors == null) {
imageAnchors = [];
for (var i:int = 0; i < 8; i++) {
var newAnchor:SpriteVisualElement = new SpriteVisualElement();
newAnchor.width = 10;
newAnchor.height = 10;
newAnchor.graphics.lineStyle(2, 0x000000);
newAnchor.graphics.beginFill(0xffffff);
newAnchor.graphics.drawRect(0, 0, 10, 10);
anchors.addElement(newAnchor);
imageAnchors.push(newAnchor);
newAnchor.addEventListener(MouseEvent.ROLL_OVER, anchorOver);
newAnchor.addEventListener(MouseEvent.ROLL_OUT, anchorOut);
newAnchor.addEventListener(MouseEvent.MOUSE_DOWN, anchorDown);
}
}
/* Layout:
0 1 2
3 - 4
5 6 7*/
}

private function anchorOver(evt:MouseEvent):void {
if(anchors.alpha>0){
switch(evt.currentTarget) {
case imageAnchors[0]: case imageAnchors[7]: cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10); break;
case imageAnchors[2]: case imageAnchors[5]: cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10); break;
case imageAnchors[1]: case imageAnchors[6]: cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10); break;
case imageAnchors[3]: case imageAnchors[4]: cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10); break;
}
}
}

private function anchorOut(evt:MouseEvent):void {
cursorManager.removeAllCursors();
}

private function anchorDown(evt:MouseEvent):void {
currentRatio = currentImage.width / currentImage.height;
img_rectangle = [currentImage.x, currentImage.y, currentImage.width, currentImage.height];
switch(evt.currentTarget) {
case imageAnchors[0]: img_currentDir = "upLeft"; img_anchorY = img_rectangle[1] + img_rectangle[3]; img_anchorX = img_rectangle[0] + img_rectangle[2]; break;
case imageAnchors[1]: img_currentDir = "up"; img_anchorY = img_rectangle[1] + img_rectangle[3]; break;
case imageAnchors[2]: img_currentDir = "upRight"; img_anchorY = img_rectangle[1] + img_rectangle[3]; img_anchorX = img_rectangle[0]; break;
case imageAnchors[3]: img_currentDir = "left"; img_anchorX = img_rectangle[0] + img_rectangle[2]; break;
case imageAnchors[4]: img_currentDir = "right"; img_anchorX = img_rectangle[0]; break;
case imageAnchors[5]: img_currentDir = "downLeft"; img_anchorY = img_rectangle[1]; img_anchorX = img_rectangle[0] + img_rectangle[2]; break;
case imageAnchors[6]: img_currentDir = "down"; img_anchorY = img_rectangle[1]; break;
case imageAnchors[7]: img_currentDir = "downRight"; img_anchorY = img_rectangle[1]; img_anchorX = img_rectangle[0]; break;
}
img_resizing = true;
drawHitArea.mouseEnabled = true;
drawHitArea.width = content.width;
drawHitArea.height = content.height;
drawHitArea.x = -1;
drawHitArea.y = 1;
savedOff();
}

private function imageResize():void {
if (img_resizing) {
cursorManager.removeAllCursors();
var prevRect:Array = img_rectangle;
var mouseX:Number = drawArea.mouseX;
var mouseY:Number = drawArea.mouseY;
if (img_currentDir == "up" && mouseY >= 0 && mouseY < img_anchorY) {
img_rectangle = [prevRect[0], mouseY - 1, prevRect[2], img_anchorY - mouseY + 1]; cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10);
}
if (img_currentDir == "down" && mouseY < content.height && mouseY > img_anchorY) { 
img_rectangle = [prevRect[0], img_anchorY, prevRect[2], mouseY - img_anchorY]; cursorManager.setCursor(resizeVerticalCursor, 2, -9, -10);
}
if (img_currentDir == "left" && mouseX >= 0 && mouseX < img_anchorX) { 
img_rectangle = [mouseX, prevRect[1], img_anchorX - mouseX, prevRect[3]]; cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10);
}
if (img_currentDir == "right" && mouseX < content.width && mouseX > img_anchorX) { 
img_rectangle = [img_anchorX, prevRect[1], mouseX - img_anchorX, prevRect[3]]; cursorManager.setCursor(resizeHorizontalCursor, 2, -9, -10);
}
if (img_currentDir == "upLeft" && mouseY >= 0 && mouseY < img_anchorY && mouseX >= 0 && mouseX < img_anchorX) { 
if (!isShift) img_rectangle = [mouseX, mouseY - 1, img_anchorX - mouseX, img_anchorY - mouseY + 1]; cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10);
if (isShift) img_rectangle = [mouseX, img_anchorY - (img_anchorX - mouseX)/currentRatio, img_anchorX - mouseX, (img_anchorX - mouseX)/currentRatio]; cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10);
}
if (img_currentDir == "upRight" && mouseY >= 0 && mouseY < img_anchorY && mouseX < content.width && mouseX > img_anchorX) { 
if (!isShift) img_rectangle = [img_anchorX, mouseY - 1, mouseX - img_anchorX, img_anchorY - mouseY + 1]; cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10);
if (isShift) img_rectangle = [img_anchorX, img_anchorY - (mouseX - img_anchorX)/currentRatio, mouseX - img_anchorX, (mouseX - img_anchorX)/currentRatio]; cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10);
}
if (img_currentDir == "downLeft" && mouseY < content.height && mouseY > img_anchorY && mouseX >= 0 && mouseX < img_anchorX) { 
if (!isShift) img_rectangle = [mouseX, img_anchorY, img_anchorX - mouseX, mouseY - img_anchorY]; cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10);
if (isShift) img_rectangle = [mouseX, img_anchorY, img_anchorX - mouseX, (img_anchorX - mouseX)/currentRatio]; cursorManager.setCursor(resizeDiag1Cursor, 2, -9, -10);
}
if (img_currentDir == "downRight" && mouseY < content.height && mouseY > img_anchorY && mouseX < content.width && mouseX > img_anchorX) { 
if (!isShift) img_rectangle = [img_anchorX, img_anchorY, mouseX - img_anchorX, mouseY - img_anchorY]; cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10);
if (isShift) img_rectangle = [img_anchorX, img_anchorY, mouseX - img_anchorX, (mouseX - img_anchorX)/currentRatio]; cursorManager.setCursor(resizeDiag2Cursor, 2, -9, -10);
}

if(img_rectangle[0]>=0 && img_rectangle[1]>=0 && img_rectangle[2] + img_rectangle[0]<=content.width && img_rectangle[3] + img_rectangle[1]<=content.height){
updateImage();
positionResize();
}
}
}

private function updateImage():void {
currentImage.x = img_rectangle[0];
currentImage.y = img_rectangle[1];
currentImage.width = img_rectangle[2];
currentImage.height = img_rectangle[3];
}

private function enableResize():void {
anchors.alpha = 0.8;
anchors.mouseEnabled = true;
anchors.mouseChildren = true;
}

private function disableResize():void {
if(toolbarStack.selectedIndex==1 && !img_resizing){
anchors.alpha = 0;
anchors.mouseEnabled = false;
anchors.mouseChildren = false;
}
}

private function positionResize():void {
var cX:Number = currentImage.x;
var cY:Number = currentImage.y;
var cW:Number = currentImage.width;
var cH:Number = currentImage.height;
imageAnchors[0].x = cX - 5;
imageAnchors[0].y = cY - 5;
imageAnchors[1].x = cX + cW/2 - 5;
imageAnchors[1].y = cY - 5;
imageAnchors[2].x = cX + cW - 5;
imageAnchors[2].y = cY - 5;
imageAnchors[3].x = cX - 5;
imageAnchors[3].y = cY + cH/2 - 5;
imageAnchors[4].x = cX + cW - 5;
imageAnchors[4].y = cY + cH/2 - 5;
imageAnchors[5].x = cX - 5;
imageAnchors[5].y = cY + cH - 5;
imageAnchors[6].x = cX + cW/2 - 5;
imageAnchors[6].y = cY + cH - 5;
imageAnchors[7].x = cX + cW - 5;
imageAnchors[7].y = cY + cH - 5;
}

private function openAbout():void{
PopUpManager.addPopUp(aboutWindow, this, true);
PopUpManager.centerPopUp(aboutWindow);
}

private function closeAbout():void{
PopUpManager.removePopUp(aboutWindow);
}

private function savedOff():void{
saved = false;
}

private function savedOn():void{
saved = true;
}
]]>
</fx:Script>

<fx:Declarations>
<mx:ArrayCollection id="toolbarToggle">
<fx:Object icon="@Embed('../lib/ic_pen.png')" />
<fx:Object icon="@Embed('../lib/ic_ellipse.png')"/>
<fx:Object icon="@Embed('../lib/ic_rect.png')"/>
<fx:Object icon="@Embed('../lib/ic_line.png')"/>
<fx:Object icon="@Embed('../lib/ic_arrow.png')"/>
<fx:Object icon="@Embed('../lib/ic_eyedropper.png')"/>
<fx:Object icon="@Embed('../lib/ic_eraser.png')"/>
</mx:ArrayCollection>
<s:TitleWindow id="imageWindow" width="450" height="370" close="closeImage();" >
<s:VGroup width="500" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<s:HGroup width="100%">
<s:TextInput editable="false" width="350" id="iPath" />
<s:Button label="Browse.." click="imageBrowse();" />
</s:HGroup>
<mx:Box backgroundColor="#dddddd" width="430" height="180" verticalAlign="middle" horizontalAlign="center" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:Image id="iPreview" scaleContent="true" maxWidth="430" maxHeight="180" maintainAspectRatio="true" smoothBitmapContent="true"/>
</mx:Box>
<s:HGroup verticalAlign="middle">
<s:Label>Width:</s:Label>
<s:NumericStepper minimum="10" maximum="2000" id="iWidth" change="updateImgLimits();" />
<s:Label>Height:</s:Label>
<s:NumericStepper minimum="10" maximum="2000" id="iHeight" change="updateImgLimits();" />
<s:Label id="imgOriginal" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Coordinates: X</s:Label>
<s:NumericStepper minimum="0" id="iX" change="updateImgLimits();" />
<s:Label>Y</s:Label>
<s:NumericStepper minimum="0" id="iY" change="updateImgLimits();" />
</s:HGroup>
<s:HGroup>
<s:Button label="Add image" click="addImage(); closeImage();" id="biNew" />
<s:Button label="Update image" click="editImage(); closeImage();" id="biUpdate" />
<s:Button label="Delete image" click="deleteImage(); closeImage();" id="biDelete" />
</s:HGroup>
<mx:Image id="iPreviewHidden" scaleContent="false" visible="false" maintainAspectRatio="true" smoothBitmapContent="true"/>
</s:VGroup>
</s:TitleWindow>
<s:TitleWindow id="saveWindow" title="Save picture" width="200" height="120" close="closeSave();" >
<s:VGroup width="200" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<s:HGroup verticalAlign="middle">
<s:Label>Export format:</s:Label>
<s:RadioButton id="radioJPG" label="JPG" groupName="saveFormat" change="changeSelectedFormat('jpg');" /> 
<s:RadioButton id="radioPNG" label="PNG" groupName="saveFormat" change="changeSelectedFormat('png');" /> 
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label enabled="{radioJPG.selected}">JPG quality:</s:Label>
<s:HSlider id="sliderJPG" minimum="1" maximum="100" enabled="{radioJPG.selected}" change="changeSelectedQuality();" />
</s:HGroup>
<s:Button label="Export file" width="100%" click="closeSave(); startExport();" />
</s:VGroup>
</s:TitleWindow>
<s:TitleWindow id="newfileWindow" title="Start new..." width="200" height="100" close="closeNewfile();" >
<mx:ViewStack id="newfileStack">
<s:NavigatorContent>
<s:VGroup width="200" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<s:Button label="Import new picture" width="100%" click="closeNewfile(); importPicture();" />
<s:Button label="Create blank page" width="100%" click="newfileStack.selectedIndex = 1; newfileWindow.height = 160;" />
<s:Button label="Import screenshot" width="100%" click="closeNewfile(); importScreenshot();" enabled="{screenshotAvailable}" />
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<s:VGroup width="200" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<s:HGroup verticalAlign="middle">
<s:Label>Width:</s:Label>
<s:NumericStepper minimum="10" maximum="2000" value="400" id="newWidth" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Height:</s:Label>
<s:NumericStepper minimum="10" maximum="2000" value="300" id="newHeight" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Background color:</s:Label>
<mx:ColorPicker id="newColor" selectedColor="0xffffff" />
</s:HGroup>
<s:Button label="Create blank" width="100%" click="closeNewfile(); blankPicture();" />
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
</s:TitleWindow>
<s:TitleWindow id="annotationWindow" width="500" height="400" close="closeAnnotation();" >
<s:VGroup width="500" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<s:Label>Text:</s:Label>
<s:TextArea width="100%" height="100" id="annText"/>
<s:HGroup verticalAlign="middle">
<s:Label>Rectangle color:</s:Label>
<mx:ColorPicker selectedColor="@{aBodyColor}" toolTip="Annotation body color" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Rectangle visibility:</s:Label>
<mx:HSlider value="@{aBodyAlpha}" toolTip="Annotation body visibility" minimum="0" maximum="1" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Text color:</s:Label>
<mx:ColorPicker selectedColor="@{aTextColor}" toolTip="Annotation text color" />
</s:HGroup>
<s:HGroup verticalAlign="middle" >
<s:Label>Text size:</s:Label>
<s:NumericStepper value="@{aTextSize}" toolTip="Text size" minimum="8" maximum="100" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Annotation width:</s:Label>
<s:NumericStepper minimum="10" id="annWidth" change="updateAnnCoordLimits();" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:Label>Coordinates: X</s:Label>
<s:NumericStepper minimum="0" id="annX"/>
<s:Label>Y</s:Label>
<s:NumericStepper minimum="0" id="annY" />
</s:HGroup>
<s:HGroup verticalAlign="middle">
<s:CheckBox label="Enable border?" id="annBorder" />
</s:HGroup>
<s:HGroup>
<s:Button label="Create annotation" click="addAnnotation(); closeAnnotation();" id="baNew" />
<s:Button label="Edit annotation" click="editAnnotation(); closeAnnotation();" id="baEdit" />
<s:Button label="Delete annotation" click="deleteAnnotation(); closeAnnotation();" id="baDelete" />
</s:HGroup>
</s:VGroup>
</s:TitleWindow>
<s:TitleWindow id="aboutWindow" width="500" height="160" close="closeAbout();" title="About KirAnnotator">
<s:HGroup>
<mx:Image source="@Embed('../bin/icons/KirAnnotator128.png')"/>
<s:Group width="372">
<s:VGroup top="10" left="10" right="10" bottom="10" width="100%">
<s:Label width="100%">KirAnnotator is a free open-source AIR application developed by Kirill Poletaev.</s:Label>
<s:Label width="100%">You can find a step-by-step tutorial series of making this program at kirill-poletaev.blogspot.com.</s:Label>
<s:Label width="100%">Contact me at lirx3m@hotmail.com.</s:Label>
<s:Label width="100%">I hope you enjoy this app and find it useful!</s:Label>
</s:VGroup>
</s:Group>
</s:HGroup>
</s:TitleWindow>
</fx:Declarations>

<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#ccccdd" width="100%" height="60">
<s:VGroup gap="0" width="100%" height="100%">
<s:HGroup gap="0" width="100%">
<custom:IconButton icon="@Embed('../lib/new.png')" toolTip="New" enabled="{buttonsEnabled}" buttonMode="true" click="newFile();" focusEnabled="false" />
<custom:IconButton icon="@Embed('../lib/images.png')" toolTip="Images" enabled="{buttonsEnabled}" buttonMode="true" click="toolbarStack.selectedIndex=1;" focusEnabled="false"/>
<custom:IconButton icon="@Embed('../lib/draw.png')" toolTip="Draw" enabled="{buttonsEnabled}" buttonMode="true" click="toolbarStack.selectedIndex=2;" focusEnabled="false"/>
<custom:IconButton icon="@Embed('../lib/bubble.png')" toolTip="Annotation" enabled="{buttonsEnabled}" buttonMode="true" click="toolbarStack.selectedIndex=3;" focusEnabled="false"/>
<custom:IconButton icon="@Embed('../lib/cut.png')" toolTip="Cut" enabled="{buttonsEnabled}" buttonMode="true" click="toolbarStack.selectedIndex=4;" focusEnabled="false"/>
<custom:IconButton id="saveBtn" icon="@Embed('../lib/save.png')" toolTip="Save" enabled="{buttonsEnabled}" buttonMode="true" click="saveFile();" focusEnabled="false"/>
<mx:ViewStack id="toolbarStack" width="466" height="100%" change="toolbarChange();">
<s:NavigatorContent>

</s:NavigatorContent>
<s:NavigatorContent>
<s:VGroup width="100%" height="44" top="4">
<s:Label fontSize="18" color="#333333">Selected: Images</s:Label>
<s:HGroup verticalAlign="middle">
<s:Label>Move and resize images with mouse, double-click to edit.</s:Label>
<custom:SmallButton label="Add a new image" icon="@Embed('../lib/bubble_add.png')" click="openImage();"/>
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<s:VGroup width="100%" height="44" top="4">
<s:Label fontSize="18" color="#333333">Selected: Draw</s:Label>
<s:HGroup>
<custom:SmallButton icon="@Embed('../lib/arrow_undo.png')" enabled="{undo_canUndo}" click="doUndo();" />
<custom:SmallButton icon="@Embed('../lib/arrow_redo.png')" enabled="{undo_canRedo}" click="doRedo();" />
<mx:ToggleButtonBar dataProvider="{toolbarToggle}" width="150" id="drawTools" />
<mx:ColorPicker selectedColor="@{lineColor}" change="updateLineExample();" />
<mx:Slider minimum="1" maximum="10" change="updateLineExample();" value="@{lineThickness}" width="80" liveDragging="true"/>
<s:SpriteVisualElement width="40" height="20" id="lineExample"/>
<s:Button click="clearDrawBitmap();" label="Clear all" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<s:VGroup width="100%" height="44" top="4">
<s:Label fontSize="18" color="#333333">Selected: Annotation</s:Label>
<s:HGroup verticalAlign="middle">
<s:Label>Move annotations by dragging them, double-click to edit.</s:Label>
<custom:SmallButton label="Add a new annotation" icon="@Embed('../lib/bubble_add.png')" click="openAnnotation();"/>
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<s:VGroup width="100%" height="44" top="4">
<s:Label fontSize="18" color="#333333">Selected: Cut</s:Label>
<s:HGroup verticalAlign="middle">
<s:Label>Select an area to crop.</s:Label>
<custom:SmallButton label="Deselect" icon="@Embed('../lib/cross.png')" click="crop_deselect();"/>
<custom:SmallButton label="Change selection display" icon="@Embed('../lib/shape_handles.png')" click="crop_changeSelectionType();"/>
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>
</mx:ViewStack>
<mx:Box width="100%" horizontalAlign="right">
<custom:SmallButton width="16" icon="@Embed('../lib/help.png')" click="openAbout();" />
</mx:Box>
</s:HGroup>
<mx:Box backgroundColor="#bbbbcc" width="100%" height="100%">
<s:Group width="100%" height="100%">
<mx:Box backgroundColor="#ffffff" width="52" height="100%" left="{52 * toolbarStack.selectedIndex}" visible="{buttonsEnabled}" />
</s:Group>
</mx:Box>
</s:VGroup>
</mx:HBox>
<s:Group width="100%" height="100%">
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="on" verticalScrollPolicy="on" rollOver="canvasOver();" rollOut="canvasOut();" id="canvas" mouseMove="moveErase();" mouseDown="startErase();" scroll="updateErase();">
<s:Group width="100%" height="100%">
<mx:Box backgroundColor="#eeeeee" width="100%" height="100%" verticalAlign="middle" horizontalAlign="center" horizontalScrollPolicy="off" verticalScrollPolicy="off" >
<mx:Box id="drawArea" backgroundColor="#ffffff" width="600" height="200" horizontalScrollPolicy="off" verticalScrollPolicy="off" rollOut="crop_areaRollOut();">
<mx:ViewStack id="stack" change="stackChange();">
<s:NavigatorContent>
<s:HGroup gap="0">
<custom:BigButton icon="@Embed('../lib/folder.png')" subtext="Import picture" toolTip="Open file" enabled="true" buttonMode="true" bWidth="200" bHeight="200" click="importPicture();" />
<custom:BigButton icon="@Embed('../lib/blank.png')" subtext="Create blank" toolTip="Blank page" enabled="true" buttonMode="true" bWidth="200" bHeight="200" click="newFile(); newfileStack.selectedIndex = 1; newfileWindow.height = 160;" />
<custom:BigButton icon="@Embed('../lib/camera.png')" subtext="Screenshot" toolTip="Use current screenshot in the clipboard" buttonMode="true" bWidth="200" bHeight="200" click="importScreenshot(); checkScreenshot = false;" enabled="{screenshotAvailable}" />
</s:HGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<mx:Image id="imgHolder" />
<s:Group id="drawGroup">
<mx:Image id="drawBitmap" />
<s:Group id="tempSprite" />
</s:Group>
<mx:Box id="annHitArea" alpha="0" backgroundColor="#000000" click="openAnnotation(drawArea.mouseX, drawArea.mouseY);" rollOver="disableResize(); disableAnnResize();"/>
<s:Group id="images" />
<s:Group id="annotations" />
<s:Group id="cropDraw" mouseEnabled="false" />
<s:Group id="anchors"/>
<s:Group id="anchorsAnn"/>
<mx:Box id="drawHitArea" alpha="0" backgroundColor="#000000" mouseDown="drawDown();" mouseMove="drawMove();"/>
</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</mx:Box>
<s:Group id="eraser" mouseEnabled="false" mouseChildren="false" alpha="0" />
</s:Group>
</mx:Canvas>
<s:Group id="savedGroup" width="90" height="20" left="{canvas.width - 130}" alpha="0" mouseChildren="false" mouseEnabled="false">
<mx:Image source="@Embed('../lib/saved_bg.png')"/>
<mx:ViewStack selectedIndex="{(saved)?(1):(0)}">
<s:NavigatorContent>
<s:HGroup width="90" height="20" left="10" verticalAlign="middle">
<mx:Image source="@Embed('../lib/flag_yellow.png')"/>
<s:Label color="#333333">Not saved</s:Label>
</s:HGroup>
</s:NavigatorContent>
<s:NavigatorContent>
<s:HGroup width="90" height="20" left="10" verticalAlign="middle">
<mx:Image source="@Embed('../lib/flag_green.png')"/>
<s:Label color="#333333">Saved</s:Label>
</s:HGroup>
</s:NavigatorContent>
</mx:ViewStack>
</s:Group>
</s:Group>
</s:VGroup>

</s:WindowedApplication>

Thanks for reading!

No comments:

Post a Comment