From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/tools/BrushTool.js | 288 +++++++++ js/tools/EraserTool.js | 32 + js/tools/EyedropperTool.js | 152 +++++ js/tools/FillTool.js | 65 ++ js/tools/InkBottleTool.js | 69 ++ js/tools/LineTool.js | 251 ++++++++ js/tools/OvalTool.js | 103 +++ js/tools/PanTool.js | 378 +++++++++++ js/tools/PenTool.js | 1245 +++++++++++++++++++++++++++++++++++++ js/tools/PencilTool.js | 32 + js/tools/RectTool.js | 126 ++++ js/tools/Rotate3DToolBase.js | 637 +++++++++++++++++++ js/tools/RotateObject3DTool.js | 64 ++ js/tools/RotateStage3DTool.js | 148 +++++ js/tools/SelectionTool.js | 829 ++++++++++++++++++++++++ js/tools/ShapeTool.js | 217 +++++++ js/tools/SubSelectTool.js | 32 + js/tools/TagTool.js | 273 ++++++++ js/tools/TextTool.js | 87 +++ js/tools/ToolBase.js | 192 ++++++ js/tools/Translate3DToolBase.js | 357 +++++++++++ js/tools/TranslateObject3DTool.js | 132 ++++ js/tools/ZoomTool.js | 442 +++++++++++++ js/tools/drawing-tool-base.js | 673 ++++++++++++++++++++ js/tools/drawing-tool.js | 370 +++++++++++ js/tools/modifier-tool-base.js | 1007 ++++++++++++++++++++++++++++++ 26 files changed, 8201 insertions(+) create mode 100644 js/tools/BrushTool.js create mode 100644 js/tools/EraserTool.js create mode 100644 js/tools/EyedropperTool.js create mode 100644 js/tools/FillTool.js create mode 100644 js/tools/InkBottleTool.js create mode 100644 js/tools/LineTool.js create mode 100644 js/tools/OvalTool.js create mode 100644 js/tools/PanTool.js create mode 100644 js/tools/PenTool.js create mode 100644 js/tools/PencilTool.js create mode 100644 js/tools/RectTool.js create mode 100644 js/tools/Rotate3DToolBase.js create mode 100644 js/tools/RotateObject3DTool.js create mode 100644 js/tools/RotateStage3DTool.js create mode 100644 js/tools/SelectionTool.js create mode 100644 js/tools/ShapeTool.js create mode 100644 js/tools/SubSelectTool.js create mode 100644 js/tools/TagTool.js create mode 100644 js/tools/TextTool.js create mode 100644 js/tools/ToolBase.js create mode 100644 js/tools/Translate3DToolBase.js create mode 100644 js/tools/TranslateObject3DTool.js create mode 100644 js/tools/ZoomTool.js create mode 100644 js/tools/drawing-tool-base.js create mode 100644 js/tools/drawing-tool.js create mode 100644 js/tools/modifier-tool-base.js (limited to 'js/tools') diff --git a/js/tools/BrushTool.js b/js/tools/BrushTool.js new file mode 100644 index 00000000..ce8ffbb9 --- /dev/null +++ b/js/tools/BrushTool.js @@ -0,0 +1,288 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var ShapeTool = require("js/tools/ShapeTool").ShapeTool; +var DrawingToolBase = require("js/tools/drawing-tool-base").DrawingToolBase; +var defaultEventManager = require("montage/core/event/event-manager").defaultEventManager; +var Montage = require("montage/core/core").Montage; +var NJUtils = require("js/lib/NJUtils").NJUtils; +var ElementMediator = require("js/mediators/element-mediator").ElementMediator; +var TagTool = require("js/tools/TagTool").TagTool; +var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager; + +exports.BrushTool = Montage.create(ShapeTool, { + hasReel: { value: false }, + _toolID: { value: "brushTool" }, + _imageID: { value: "brushToolImg" }, + _toolImageClass: { value: "brushToolUp" }, + _selectedToolImageClass: { value: "brushToolDown" }, + _toolTipText: { value: "Brush Tool" }, + _brushView: { value: null, writable: true }, + + _selectedToolClass: { value: "brushToolSpecificProperties" }, + _penToolProperties: { enumerable: false, value: null, writable: true }, + _parentNode: { enumerable: false, value: null, writable: true }, + _toolsPropertiesContainer: { enumerable: false, value: null, writable: true }, + + //config options + _useWebGL: {value: false, writable: false}, + + //view options + _brushStrokeCanvas: {value: null, writable: true}, + _brushStrokePlaneMat: {value: null, writable: true}, + + //the current brush stroke + _selectedBrushStroke: {value: null, writable: true}, + + ShowToolProperties: { + value: function () { + this._brushView = PenView.create(); + this._brushView.element = document.getElementById('topPanelContainer').children[0]; + this._brushView.needsDraw = true; + this._brushView.addEventListener(ToolEvents.TOOL_OPTION_CHANGE, this, false); + } + }, + + HandleLeftButtonDown: { + value: function (event) { + //ignore any right or middle clicks + if (event.button !== 0) { + //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2) + return; + } + if (this._canDraw) { + this._isDrawing = true; + } + + this.startDraw(event); + if (this._brushStrokePlaneMat === null) { + this._brushStrokePlaneMat = this.mouseDownHitRec.getPlaneMatrix(); + } + //start a new brush stroke + if (this._selectedBrushStroke === null){ + this._selectedBrushStroke = new GLBrushStroke(); + } + console.log("BrushTool Start"); + NJevent("enableStageMove");//stageManagerModule.stageManager.enableMouseMove(); + } //value: function (event) { + }, //HandleLeftButtonDown + + + //need to override this function because the ShapeTool's definition contains a clearDrawingCanvas call - Pushkar + // might not need to override once we draw using OpenGL instead of SVG + // Also took out all the snapping code for now...need to add that back + HandleMouseMove: + { + value: function (event) { + //ignore any right or middle clicks + if (event.button !== 0) { + //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2) + return; + } + + if (this._isDrawing) { + snapManager.enableElementSnap(false); + snapManager.enableGridSnap(false); + snapManager.enableSnapAlign(false); + //this.doDraw(event); + //var currMousePos = this.getMouseUpPos(); + //instead of doDraw call own DrawingTool + var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY)); + var hitRecSnapPoint = DrawingToolBase.getUpdatedSnapPointNoAppLevelEnabling(point.x, point.y, true, this.mouseDownHitRec); + var currMousePos = DrawingToolBase.getHitRecPos(hitRecSnapPoint); + + if (this._selectedBrushStroke){ + this._selectedBrushStroke.addPoint(currMousePos); + } + + this.ShowCurrentBrushStrokeOnStage(); + } //if (this._isDrawing) { + + //this.drawLastSnap(); //TODO.. is this line necessary if we're not snapping? // Required cleanup for both Draw/Feedbacks + + }//value: function(event) + }, + + + + HandleLeftButtonUp: { + value: function (event) { + /*var drawData = this.getDrawingData(); + if (drawData) { + if (this._brushStrokePlaneMat === null) { + this._brushStrokePlaneMat = drawData.planeMat; + } + } + if (this._isDrawing) { + this.doDraw(event); + }*/ + this.endDraw(event); + + this._isDrawing = false; + this._hasDraw = false; + console.log("BrushTool Stop"); + + //TODO get these values from the options + if (this._selectedBrushStroke){ + this._selectedBrushStroke.setStrokeWidth(20); + } + //display the previously drawn stroke in a separate canvas + this.RenderCurrentBrushStroke(); + + this._selectedBrushStroke = null; + this._brushStrokeCanvas = null; + NJevent("disableStageMove"); + } + }, + + ShowCurrentBrushStrokeOnStage:{ + value: function() { + //clear the canvas before we draw anything else + this.application.ninja.stage.clearDrawingCanvas(); + if (this._selectedBrushStroke && this._selectedBrushStroke.getNumPoints()>0){ + this._selectedBrushStroke.computeMetaGeometry(); + var ctx = this.application.ninja.stage.drawingContext;//stageManagerModule.stageManager.drawingContext; + if (ctx === null) + throw ("null drawing context in Brushtool::ShowCurrentBrushStrokeOnStage"); + ctx.save(); + + var horizontalOffset = this.application.ninja.stage.userContentLeft; + var verticalOffset = this.application.ninja.stage.userContentTop; + + var numPoints = this._selectedBrushStroke.getNumPoints(); + ctx.lineWidth = 1; + ctx.strokeStyle = "black"; + ctx.beginPath(); + var pt = this._selectedBrushStroke.getPoint(0); + ctx.moveTo(pt[0]+ horizontalOffset,pt[1]+ verticalOffset); + for (var i = 1; i < numPoints; i++) { + pt = this._selectedBrushStroke.getPoint(i); + var x = pt[0]+ horizontalOffset; + var y = pt[1]+ verticalOffset; + ctx.lineTo(x,y); + } + ctx.stroke(); + ctx.restore(); + + } + } + }, + + RenderCurrentBrushStroke:{ + value: function() { + if (this._selectedBrushStroke){ + this._selectedBrushStroke.computeMetaGeometry(); + var bboxMin = this._selectedBrushStroke.getBBoxMin(); + var bboxMax = this._selectedBrushStroke.getBBoxMax(); + var bboxWidth = bboxMax[0] - bboxMin[0]; + var bboxHeight = bboxMax[1] - bboxMin[1]; + var bboxMid = Vector.create([0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]); + + this._selectedBrushStroke.setCanvasX(bboxMid[0]); + this._selectedBrushStroke.setCanvasY(bboxMid[1]); + + //call render shape with the bbox width and height + this.RenderShape(bboxWidth, bboxHeight, this._brushStrokePlaneMat, bboxMid, this._brushStrokeCanvas); + } + } + }, + + + RenderShape: { + value: function (w, h, planeMat, midPt, canvas) { + if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { + return; + } + + var left = Math.round(midPt[0] - 0.5 * w); + var top = Math.round(midPt[1] - 0.5 * h); + + if (!canvas) { + var newCanvas = NJUtils.makeNJElement("canvas", "Brushstroke", "shape", null, true); + var elementModel = TagTool.makeElement(w, h, planeMat, midPt, newCanvas); + ElementMediator.addElement(newCanvas, elementModel.data, true); + + // create all the GL stuff + var world = this.getGLWorld(newCanvas, this._useWebGL); + //store a reference to this newly created canvas + this._brushStrokeCanvas = newCanvas; + + var brushStroke = this._selectedBrushStroke; + if (brushStroke){ + brushStroke.setWorld(world); + + brushStroke.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + brushStroke.setPlaneMatrixInverse(planeMatInv); + brushStroke.setPlaneCenter(midPt); + + world.addObject(brushStroke); + world.render(); + //TODO this will not work if there are multiple shapes in the same canvas + newCanvas.elementModel.shapeModel.GLGeomObj = brushStroke; + } + } //if (!canvas) { + else { + + var world = null; + if (canvas.elementModel.shapeModel && canvas.elementModel.shapeModel.GLWorld) { + world = canvas.elementModel.shapeModel.GLWorld; + } else { + world = this.getGLWorld(canvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, canvas, this._useWebGL);//fillMaterial, strokeMaterial); + } + + + if (this._entryEditMode !== this.ENTRY_SELECT_CANVAS){ + //update the left and top of the canvas element + var canvasArray=[canvas]; + ElementMediator.setProperty(canvasArray, "left", [parseInt(left)+"px"],"Changing", "brushTool"); + ElementMediator.setProperty(canvasArray, "top", [parseInt(top) + "px"],"Changing", "brushTool"); + canvas.width = w; + canvas.height = h; + //update the viewport and projection to reflect the new canvas width and height + world.setViewportFromCanvas(canvas); + if (this._useWebGL){ + var cam = world.renderer.cameraManager().getActiveCamera(); + cam.setPerspective(world.getFOV(), world.getAspect(), world.getZNear(), world.getZFar()); + } + } + + var brushStroke = this._selectedBrushStroke; + + if (brushStroke){ + brushStroke.setDrawingTool(this); + + brushStroke.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + brushStroke.setPlaneMatrixInverse(planeMatInv); + brushStroke.setPlaneCenter(midPt); + + brushStroke.setWorld(world); + world.addIfNewObject(brushStroke); + //world.addObject(subpath); + world.render(); + //TODO this will not work if there are multiple shapes in the same canvas + canvas.elementModel.shapeModel.GLGeomObj = brushStroke; + } + } //else of if (!canvas) { + } //value: function (w, h, planeMat, midPt, canvas) { + }, //RenderShape: { + Configure: { + value: function (wasSelected) { + if (wasSelected) { + console.log("Picked BrushTool"); + //todo these calls have no effect because the drawing-tool-base (in getInitialSnapPoint) overrides them with what's set at the application level + snapManager.enableElementSnap(false); + snapManager.enableGridSnap(false); + snapManager.enableSnapAlign(false); + } + else { + console.log("Left BrushTool"); + } + } + } + +}); \ No newline at end of file diff --git a/js/tools/EraserTool.js b/js/tools/EraserTool.js new file mode 100644 index 00000000..c12a14b1 --- /dev/null +++ b/js/tools/EraserTool.js @@ -0,0 +1,32 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + DrawingTool = require("js/tools/drawing-tool").DrawingTool; + +exports.EraserTool = Montage.create(DrawingTool, { + drawingFeedback: { value: { mode: "Draw2D", type: "" } }, + + HandleLeftButtonDown: { + value: function(event) { + NJevent("enableStageMove"); + + } + }, + + HandleMouseMove: { + value: function(event) { + this.doDraw(event); + } + }, + + HandleLeftButtonUp: { + value: function(event) { + this.endDraw(event); + NJevent("disableStageMove"); + } + } +}); \ No newline at end of file diff --git a/js/tools/EyedropperTool.js b/js/tools/EyedropperTool.js new file mode 100644 index 00000000..795753d2 --- /dev/null +++ b/js/tools/EyedropperTool.js @@ -0,0 +1,152 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ElementsMediator = require("js/mediators/element-mediator").ElementMediator, + + toolBase = require("js/tools/ToolBase").toolBase; + +exports.EyedropperTool = Montage.create(toolBase, { + + _isMouseDown: { value: false }, + _previousColor: { value: null}, + _color: { value: null}, + + Configure: { + value: function ( doActivate ) + { + if (doActivate) + { + NJevent("enableStageMove"); + } + else + { + NJevent("disableStageMove"); + } + } + }, + + HandleLeftButtonDown: { + value : function ( event ) { + this._isMouseDown = true; + this._previousColor = + this.application.ninja.colorController[this.application.ninja.colorController.colorModel.input].css; + + this._updateColorFromPoint(event); + } + }, + + HandleMouseMove: { + value : function (event) + { + if(this._escape) + { + this._isMouseDown = false; + this._escape = false; + } + if(this._isMouseDown) + { + this._updateColorFromPoint(event); + } + } + }, + + HandleLeftButtonUp: { + value : function (event) { + { + this._isMouseDown = false; + + if(this._escape) + { + this._escape = false; + } + + this._updateColor(this._color); + + this._color = null; + } + } + }, + + HandleEscape: { + value: function(event) { + if(this._color && this._color.value) + { + var color = this.application.ninja.colorController.getColorObjFromCss(this._previousColor); + + if (color && color.value) { + color.value.wasSetByCode = true; + color.value.type = 'change'; + if (color.value.a) { + this.application.ninja.colorController.colorModel.alpha = {value: color.value.a, + wasSetByCode: true, + type: 'change'}; + } + this.application.ninja.colorController.colorModel[color.mode] = color.value; + this._color = null; + } + } + this._escape = true; + } + }, + + _updateColorFromPoint: { + value : function (event) { + var obj = this.application.ninja.stage.GetElement(event); + if (obj) + { + // TODO - figure out if user clicked on a border - for now, just get fill + var c = ElementsMediator.getColor(obj, true); + if(c) + { + var color = this.application.ninja.colorController.getColorObjFromCss(c); + if (color && color.value) { + color.value.wasSetByCode = true; + color.value.type = 'changing'; + if (color.value.a) { + this.application.ninja.colorController.colorModel.alpha = {value: color.value.a, + wasSetByCode: true, + type: 'changing'}; + } + this.application.ninja.colorController.colorModel[color.mode] = color.value; + this._color = color; + } + } + } + } + }, + + _updateColor: { + value: function(color) { + if (color && color.value) { + var input = this.application.ninja.colorController.colorModel.input; + + if(input === "fill") + { + this.application.ninja.colorController.colorToolbar.fill_btn.color(color.mode, color.value); + } + else + { + this.application.ninja.colorController.colorToolbar.stroke_btn.color(color.mode, color.value); + } + + // Updating color chips will set the input type to "chip", so set it back here. + this.application.ninja.colorController.colorModel.input = input; + + color.value.wasSetByCode = true; + color.value.type = 'change'; + if (color.value.a) { + this.application.ninja.colorController.colorModel.alpha = {value: color.value.a, + wasSetByCode: true, + type: 'change'}; + } + this.application.ninja.colorController.colorModel[color.mode] = color.value; + this._previousColor = color.value.css; + } + } + } + +}); \ No newline at end of file diff --git a/js/tools/FillTool.js b/js/tools/FillTool.js new file mode 100644 index 00000000..477966da --- /dev/null +++ b/js/tools/FillTool.js @@ -0,0 +1,65 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase, + ElementsMediator = require("js/mediators/element-mediator").ElementMediator; + +exports.FillTool = Montage.create(ModifierToolBase, { + _canSnap: { value: false }, + _canColor: { value: true }, + + HandleMouseMove: { + value : function (event) + { + var obj = this.application.ninja.stage.GetElement(event); + var cursor = "url('images/cursors/fill.png') 17 12, default"; + var canColor = true; + if (obj) + { + var name = obj.nodeName; + if ((name !== 'CANVAS') && (name !== 'DIV')) + { + cursor = "url('images/cursors/nofill.png') 17 12, default"; + canColor = false; + } + } + this.application.ninja.stage.drawingCanvas.style.cursor = cursor; + this._canColor = canColor; + } + }, + + HandleLeftButtonUp: { + value : function () { + //if(this._isDrawing) + { + this.application.ninja.stage.clearDrawingCanvas(); + this._hasDraw = false; + this._isDrawing = false; + } + } + }, + + // Called by modifier tool base's HandleLeftButtonDown after updating selection (if needed) + startDraw: { + value: function(event) { + this.isDrawing = true; + + if(this._canColor) + { + var color = this.application.ninja.colorController.colorToolbar.fill; + ElementsMediator.setColor(this.application.ninja.selectedElements, color, true, "Change", "fillTool"); + } + } + } + +}); \ No newline at end of file diff --git a/js/tools/InkBottleTool.js b/js/tools/InkBottleTool.js new file mode 100644 index 00000000..cc20d94c --- /dev/null +++ b/js/tools/InkBottleTool.js @@ -0,0 +1,69 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase, + ElementsMediator = require("js/mediators/element-mediator").ElementMediator; + +exports.InkBottleTool = Montage.create(ModifierToolBase, { + _canSnap: { value: false }, + _canColor: { value: true }, + + HandleMouseMove: { + value : function (event) + { + var obj = this.application.ninja.stage.GetElement(event); + var cursor = "url('images/cursors/ink.png') 17 12, default"; + var canColor = true; + if (obj) + { + var name = obj.nodeName; + if ((name !== 'CANVAS') && (name !== 'DIV')) + { + cursor = "url('images/cursors/ink_no.png') 17 12, default"; + canColor = false; + } + } + this.application.ninja.stage.drawingCanvas.style.cursor = cursor; + this._canColor = canColor; + } + }, + + HandleLeftButtonUp: { + value : function () { + //if(this._isDrawing) + { + this.application.ninja.stage.clearDrawingCanvas(); + this._hasDraw = false; + this._isDrawing = false; + } + } + }, + + // Called by modifier tool base's HandleLeftButtonDown after updating selection (if needed) + startDraw: { + value: function(event) { + this.isDrawing = true; + + if(this._canColor) + { +// var color = this.application.ninja.colorController.colorToolbar.stroke; +// ElementsMediator.setColor(this.application.ninja.selectedElements, color, false, "Change", "inkBottleTool"); + + var strokeInfo = { borderStyle:this.options._borderStyle.value, + borderWidth:this.options._borderWidth.value, + borderUnits:this.options._borderWidth.units, + strokeSize:this.options._strokeSize.value, + strokeUnits:this.options._strokeSize.units, + color:this.application.ninja.colorController.colorToolbar.stroke + }; + + ElementsMediator.setStroke(this.application.ninja.selectedElements, strokeInfo, "Change", "inkBottleTool"); + } + } + } + +}); \ No newline at end of file diff --git a/js/tools/LineTool.js b/js/tools/LineTool.js new file mode 100644 index 00000000..042ba0b2 --- /dev/null +++ b/js/tools/LineTool.js @@ -0,0 +1,251 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ShapeTool = require("js/tools/ShapeTool").ShapeTool, + DrawingToolBase = require("js/tools/drawing-tool-base").DrawingToolBase, + ElementMediator = require("js/mediators/element-mediator").ElementMediator, + NJUtils = require("js/lib/NJUtils").NJUtils, + TagTool = require("js/tools/TagTool").TagTool, + ShapesController = require("js/controllers/elements/shapes-controller").ShapesController, + ShapeModel = require("js/models/shape-model").ShapeModel; + +exports.LineTool = Montage.create(ShapeTool, { + _toolID: { value: "lineTool" }, + _imageID: { value: "lineToolImg" }, + _toolImageClass: { value: "lineToolUp" }, + _selectedToolImageClass: { value: "lineToolDown" }, + _toolTipText: { value: "Line Tool (L)" }, + + _tmpDrawIndex : { value : 1, writable:true}, + + _mode: {value: null, writable:true}, + + // Need to keep track of current mouse position for KEY modifiers event which do not have mouse coordinates + _currentX: {value: 0, writable: true}, + _currentY: {value: 0, writable: true}, + _lineView: {value: null, writable:true}, + _ovalView: {value: null, writable:true}, + + _strokeSize: { value: 1 }, + _strokeColor: { value: null }, + + HandleLeftButtonDown: + { + value: function (event) + { + if(this._canDraw) { + this._isDrawing = true; + } + + this._strokeSize = ShapesController.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units, null); + this._strokeColor = this.application.ninja.colorController.colorToolbar.stroke.color.css; + this.startDraw(event); + } + }, + + HandleLeftButtonUp: + { + value: function (event) + { + var slope = this._getSlope(), + drawData = this.getDrawingData(); + + if(drawData) { + var canvas, + xAdj = 0, + yAdj = 0, + w = ~~drawData.width, + h = ~~drawData.height; + if(!this._useExistingCanvas()) + { + // set the dimensions + if(slope === "horizontal") + { + h = Math.max(this._strokeSize, 1); + } + else if(slope === "vertical") + { + w = Math.max(this._strokeSize, 1); + } + else + { + // else make the line's stroke fit inside the canvas by growing the canvas + var theta = Math.atan(slope); + xAdj = Math.abs((this._strokeSize/2)*Math.sin(theta)); + yAdj = Math.abs((this._strokeSize/2)*Math.cos(theta)); + + w += ~~(xAdj*2); + h += ~~(yAdj*2); + } + + canvas = NJUtils.makeNJElement("canvas", "Canvas", "shape", null, true); + var elementModel = TagTool.makeElement(w, h, drawData.planeMat, drawData.midPt, canvas); + + ElementMediator.addElement(canvas, elementModel.data, true); + canvas.elementModel.isShape = true; + } + else + { + canvas = this._targetedElement; + canvas.elementModel.controller = ShapesController; + if(!canvas.elementModel.shapeModel) + { + canvas.elementModel.shapeModel = Montage.create(ShapeModel); + } + } + this.RenderShape(w, h, drawData.planeMat, drawData.midPt, + canvas, slope, xAdj, yAdj); + } + + this.endDraw(event); + + this._isDrawing = false; + this._hasDraw=false; + + + this.DrawHandles(); + } + }, + + _getSlope: { + value: function() { + var hitRec0 = this._mouseDownHitRec, + hitRec1 = this._mouseUpHitRec, + slope; + + if (hitRec0 && hitRec1) + { + var p0 = hitRec0.getLocalPoint(), + p1 = hitRec1.getLocalPoint(); + + // check for divide by 0 for vertical line: + if( Math.round(p0[0] - p1[0]) === 0 ) + { + // vertical line + slope = "vertical"; + } + else if (Math.round(p0[1] - p1[1]) === 0 ) + { + // horizontal line + slope = "horizontal"; + } + else + { + // if slope is positive, draw a line from top-left to bottom-right + slope = (p0[1] - p1[1])/(p0[0] - p1[0]); + } + } + + return slope; + } + }, + + _doDraw: { + value: function () { + if (this.mouseDownHitRec !== null) { + DrawingToolBase.stageComponent = this.application.ninja.stage; + DrawingToolBase.drawLine(this.mouseDownHitRec, this.mouseUpHitRec, this._strokeSize, this._strokeColor); + } + } + }, + + HandleShiftKeyDown: { + value: function (event) { + if (this._isDrawing) { + var slope = Math.abs((this.downPoint.y - this.currentY)/(this.downPoint.x - this.currentX)); + // If slope is less than 0.5, make it a horizontal line + if(slope < 0.5) + { + this._mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(this.currentX, this.downPoint.y, false, this._mouseDownHitRec); + } + // If slope is greater than 2, make it a vertical line + else if(slope > 2) + { + this._mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(this.downPoint.x, this.currentY, false, this._mouseDownHitRec); + } + // make it a 45 degree line + else + { + var square = this.toSquare(this.downPoint.x, this.currentX, this.downPoint.y, this.currentY); + this._mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(square[0] + square[2], square[1] + square[3], false, this._mouseDownHitRec); + } + this._doDraw(); + } + } + }, + + HandleShiftKeyUp: { + value: function () { + if (this._isDrawing) { + this.mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(this.currentX, this.currentY, false, this.mouseDownHitRec); + this._doDraw(); + } + } + }, + + RenderShape: { + value: function (w, h, planeMat, midPt, canvas, slope, xAdj, yAdj) + { + + var strokeStyleIndex = this.options.strokeStyleIndex; + var strokeStyle = this.options.strokeStyle; + var strokeSize = this._strokeSize; + + var left = Math.round(midPt[0] - 0.5*w); + var top = Math.round(midPt[1] - 0.5*h); + + var strokeColor = this.application.ninja.colorController.colorToolbar.stroke.webGlColor; + // for default stroke and fill/no materials + var strokeMaterial = null; + + var strokeIndex = parseInt(this.options.strokeMaterial); + if(strokeIndex > 0) + { + strokeMaterial = Object.create(MaterialsLibrary.getMaterialAt(strokeIndex-1)); + } + + var world = this.getGLWorld(canvas, this.options.use3D); + + var xOffset = ((left - canvas.offsetLeft + w/2) - canvas.width/2); + var yOffset = (canvas.height/2 - (top - canvas.offsetTop + h/2)); + + var line = new GLLine(world, xOffset, yOffset, w, h, slope, strokeSize, strokeColor, strokeMaterial, strokeStyle, xAdj, yAdj); + + world.addObject(line); + world.render(); + + canvas.elementModel.shapeModel.shapeCount++; + if(canvas.elementModel.shapeModel.shapeCount === 1) + { + canvas.elementModel.selection = "Line"; + canvas.elementModel.pi = "LinePi"; + canvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; + canvas.elementModel.shapeModel.stroke = strokeColor; + + canvas.elementModel.shapeModel.strokeMaterial = strokeMaterial; + canvas.elementModel.shapeModel.strokeMaterialIndex = strokeIndex; + + canvas.elementModel.shapeModel.strokeStyleIndex = strokeStyleIndex; + canvas.elementModel.shapeModel.strokeStyle = strokeStyle; + + canvas.elementModel.shapeModel.GLGeomObj = line; + } + else + { + // TODO - update the shape's info only. shapeModel will likely need an array of shapes. + } + + if(canvas.elementModel.isShape) + { + this.application.ninja.selectionController.selectElement(canvas); + } + + } + } +}); + + diff --git a/js/tools/OvalTool.js b/js/tools/OvalTool.js new file mode 100644 index 00000000..e0f1f03f --- /dev/null +++ b/js/tools/OvalTool.js @@ -0,0 +1,103 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + ShapeTool = require("js/tools/ShapeTool").ShapeTool, + ShapesController = require("js/controllers/elements/shapes-controller").ShapesController; + +exports.OvalTool = Montage.create(ShapeTool, { + + _toolID: { value: "ovalTool" }, + _imageID: { value: "ovalToolImg" }, + _toolImageClass: { value: "ovalToolUp" }, + _selectedToolImageClass: { value: "ovalToolDown" }, + _toolTipText: { value: "Oval Tool (O)" }, + _selectedToolClass:{value:"ovalToolSpecificProperties"}, + _ovalView : { value: null, writable: true}, + + RenderShape: { + value: function (w, h, planeMat, midPt, canvas) + { + if( (Math.floor(w) === 0) || (Math.floor(h) === 0) ) + { + return; + } + + var left = Math.round(midPt[0] - 0.5*w); + var top = Math.round(midPt[1] - 0.5*h); + + var strokeStyleIndex = this.options.strokeStyleIndex; + var strokeStyle = this.options.strokeStyle; + + var strokeSize = ShapesController.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units, h); + + var innerRadius = this.options.innerRadius.value / 100; + + var strokeColor = this.application.ninja.colorController.colorToolbar.stroke.webGlColor; + var fillColor = this.application.ninja.colorController.colorToolbar.fill.webGlColor; + + // for default stroke and fill/no materials + var strokeMaterial = null; + var fillMaterial = null; + + var strokeIndex = parseInt(this.options.strokeMaterial); + if(strokeIndex > 0) + { + strokeMaterial = Object.create(MaterialsLibrary.getMaterialAt(strokeIndex-1)); + } + + var fillIndex = parseInt(this.options.fillMaterial); + if(fillIndex > 0) + { + fillMaterial = Object.create(MaterialsLibrary.getMaterialAt(fillIndex-1)); + } + + + var world = this.getGLWorld(canvas, this.options.use3D); + + var xOffset = ((left - canvas.offsetLeft + w/2) - canvas.width/2); + var yOffset = (canvas.height/2 - (top - canvas.offsetTop + h/2)); + + var oval = new GLCircle(); + oval.init(world, xOffset, yOffset, w, h, strokeSize, strokeColor, fillColor, innerRadius, strokeMaterial, fillMaterial, strokeStyle); + + world.addObject(oval); + world.render(); + + canvas.elementModel.shapeModel.shapeCount++; + if(canvas.elementModel.shapeModel.shapeCount === 1) + { + canvas.elementModel.selection = "Oval"; + canvas.elementModel.pi = "OvalPi"; + canvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; + canvas.elementModel.shapeModel.stroke = strokeColor; + canvas.elementModel.shapeModel.fill = fillColor; + + canvas.elementModel.shapeModel.innerRadius = this.options.innerRadius.value + " " + this.options.innerRadius.units; + + canvas.elementModel.shapeModel.strokeMaterial = strokeMaterial; + canvas.elementModel.shapeModel.fillMaterial = fillMaterial; + canvas.elementModel.shapeModel.strokeMaterialIndex = strokeIndex; + canvas.elementModel.shapeModel.fillMaterialIndex = fillIndex; + + canvas.elementModel.shapeModel.strokeStyleIndex = strokeStyleIndex; + canvas.elementModel.shapeModel.strokeStyle = strokeStyle; + + canvas.elementModel.shapeModel.GLGeomObj = oval; + } + else + { + // TODO - update the shape's info only. shapeModel will likely need an array of shapes. + } + + if(canvas.elementModel.isShape) + { + this.application.ninja.selectionController.selectElement(canvas); + } + + } + } +}); \ No newline at end of file diff --git a/js/tools/PanTool.js b/js/tools/PanTool.js new file mode 100644 index 00000000..ba40b020 --- /dev/null +++ b/js/tools/PanTool.js @@ -0,0 +1,378 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var Montage = require("montage/core/core").Montage, + drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils, + vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils, + viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils, + snapManager = require("js/helper-classes/3D/snap-manager").SnapManager, + Keyboard = require("js/mediators/keyboard-mediator").Keyboard; + toolBase = require("js/tools/ToolBase").toolBase; + +exports.PanTool = Montage.create(toolBase, +{ + _localPt :{value: [0,0] , writable:true}, + _worldPt :{value: [0,0] , writable:true}, + _globalPt :{value: [0,0] , writable:true}, + _globalToUCWorld :{value: [] , writable:true}, + _lastGPt :{value: [0,0], writable:true}, + + Configure: { + value: function ( doActivate ) + { + if (doActivate) + { + NJevent("enableStageMove"); + this.eventManager.addEventListener( "toolDoubleClick", this, false); + this.application.ninja.stage.canvas.addEventListener("mousewheel", this, false); + this.activate(); + } + else + { + NJevent("disableStageMove"); + this.eventManager.removeEventListener( "toolDoubleClick", this, false); + this.application.ninja.stage.canvas.removeEventListener("mousewheel", this, false); + this.deactivate(); + } + } + }, + + HandleLeftButtonDown: { + value : function ( event ) { + this._isDrawing = true; + + this.mouseDown( event ); + } + }, + + HandleMouseMove: + { + value : function (event) + { + this.mouseMove( event ); + } + }, + + HandleLeftButtonUp: + { + value : function ( event ) + { + //if(this._isDrawing) + { + // do one final mouse move to update the scrollbars + this.mouseUp( event ); + + this.application.ninja.stage.clearDrawingCanvas(); + this._hasDraw = false; + this._isDrawing = false; + } + } + }, + + HandleKeyPress: { + value: function(event) { + if(event.altKey) + { + this._altKeyDown = true; + //console.log( "altKeyDown" ); + } + } + }, + + HandleKeyUp: { + value: function(event) { + if(event.keyCode === Keyboard.ALT) + { + this._altKeyDown = false; + console.log( "altKeyUp" ); + } + } + }, + + handleToolDoubleClick: + { + value: function () + { + var uc = this.application.ninja.currentDocument.documentRoot; + //var uc = documentManagerModule.DocumentManager.activeDocument + var ucMat = viewUtils.getMatrixFromElement(uc); + + var noTrans = ucMat.slice(); + noTrans[12] = 0; noTrans[13] = 0; noTrans[14] = 0; + var ucMatInv = glmat4.inverse( ucMat, [] ); + var deltaMat = glmat4.multiply( noTrans, ucMatInv, [] ); + + this.application.ninja.stage.centerStage(); + + this.applyDeltaMat( deltaMat ); + } + }, + + handleMousewheel : + { + value:function(event) + { + var zoom = this.application.ninja.documentBar.zoomFactor/100.0; + if (!zoom) zoom = 1.0; + + var delta = 0; + if (event.wheelDelta) + delta = 10*event.wheelDelta/120; + //console.log( "delta: " + delta ); + + this.application.ninja.stage._iframeContainer.scrollLeft += delta; + this.application.ninja.stage._scrollLeft += delta; + + delta *= zoom; + + var uc = this.application.ninja.currentDocument.documentRoot; + var ucMat = viewUtils.getMatrixFromElement(uc); + var offset = viewUtils.getElementOffset( uc ); + //console.log( "uc offset: " + offset[0] ); + + var localToGlobalMat = viewUtils.getLocalToGlobalMatrix( uc ); + var globalToLocalMat = glmat4.inverse( localToGlobalMat, []); + + var w = uc.offsetWidth, + h = uc.offsetHeight; + if(uc.width) + w = uc.width; + if(uc.height) + h = uc.height; + var localPt = [ w/2, h/2, 0]; + var globalPt = MathUtils.transformAndDivideHomogeneousPoint( localPt, localToGlobalMat ); + this.doMouseDown( { x:globalPt[0], y:globalPt[1] } ); + + globalPt[0] += delta; + this._isDrawing = true; + this.doMouseMove( { x:globalPt[0], y:globalPt[1] } ); + this._isDrawing = false; + } + }, + + + ///////////////////////////////////////////////////////////////////// + // Simple tool API + activate: + { + value: function() + { + //console.log( "PanTool.activate" ); + } + }, + + deactivate: + { + value: function() + { + //console.log( "PanTool.deactivate" ); + } + }, + + mouseDown: + { + value: function( event ) + { + //console.log( "PanTool.mouseDown" ); + if (!this.application.ninja.currentDocument) return; + + var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, + new WebKitPoint(event.pageX, event.pageY)); + this.doMouseDown( point ); + } + }, + + + doMouseDown: + { + value: function( point ) + { + //var tmpPt, tmpPt2, tmpPt3, tmpPt4, tmpMat, tmpMat2; // DEBUG. (see use of these points below) + var hitRec = snapManager.snap( point.x, point.y, true ); + if (hitRec) + { + //console.log( "hit: " + hitRec.getElement().id ); + var globalPt = [point.x, point.y]; + var elt = hitRec.getElement(); + if (elt) + { + // get the userContent object (stage) and its matrix + var userContent = this.application.ninja.currentDocument.documentRoot; + var ucMat = viewUtils.getMatrixFromElement(userContent); + + var localToGlobalMat = viewUtils.getLocalToGlobalMatrix( elt ); + var globalToLocalMat = glmat4.inverse( localToGlobalMat, []); + + if (elt != userContent) + this._localPt = hitRec.calculateElementPreTransformScreenPoint(); + else + { + var localPt = hitRec.calculateElementWorldPoint(); + viewUtils.pushViewportObj( userContent ); + var cop = viewUtils.getCenterOfProjection(); + this._localPt = [cop[0] + localPt[0], cop[1] + localPt[1], localPt[2]]; + viewUtils.popViewportObj(); + } + this._globalPt = MathUtils.transformAndDivideHomogeneousPoint( this._localPt, localToGlobalMat ); + var tmpLocal = MathUtils.transformAndDivideHomogeneousPoint( this._globalPt, globalToLocalMat ); + + this._lastGPt = this._globalPt.slice(); + + // set up the matrices we will be needing + var eltToStageWorldMat = glmat4.multiply( ucMat, viewUtils.getObjToStageWorldMatrix(elt, true), []); + this._worldPt = MathUtils.transformAndDivideHomogeneousPoint( this._localPt, eltToStageWorldMat ); +// console.log( "screenPt: " + globalPt ); +// console.log( "_worldPt: " + this._worldPt ); +// console.log( "_localPt: " + this._localPt ); +// console.log( "_globalPt: " + this._globalPt ); +// console.log( "hit localPt: " + hitRec.calculateElementPreTransformScreenPoint() ); + + // get a matrix from user content world space to the screen + viewUtils.pushViewportObj( userContent ); + var cop = viewUtils.getCenterOfProjection(); + var pDist = viewUtils.getPerspectiveDistFromElement(userContent); + var projMat = glmat4.scale(Matrix.I(4), [pDist,pDist,pDist], []); + projMat[11] = -1; + projMat[15] = 1400; + var v2s = Matrix.Translation([cop[0], cop[1], 0]); + var ucWorldToGlobal = glmat4.multiply( v2s, projMat, [] ); + var offset = viewUtils.getElementOffset( userContent ); + var offMat = Matrix.Translation([offset[0], offset[1], 0]); + glmat4.multiply( offMat, ucWorldToGlobal, ucWorldToGlobal ); + this._globalToUCWorld = glmat4.inverse(ucWorldToGlobal, []); + viewUtils.popViewportObj(); + + /* + tmpPt = MathUtils.transformAndDivideHomogeneousPoint( this._globalPt, this._globalToUCWorld ); // DEBUG - tmpPt should equal this._worldPt + tmpPt2 = MathUtils.transformAndDivideHomogeneousPoint( this._worldPt, ucWorldToGlobal ); // DEBUG - tmpPt2 should equal globalPt + tmpPt3 = viewUtils.localToGlobal( this._localPt, elt ); + tmpPt4 = MathUtils.transformAndDivideHomogeneousPoint( tmpPt3, this._globalToUCWorld ); + tmpMat = glmat4.multiply(ucWorldToGlobal, eltToStageWorldMat, []); + tmpMat2 = viewUtils.getLocalToGlobalMatrix( elt ); + */ + } + } + } + }, + + mouseMove: + { + value: function( event ) + { + var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, + new WebKitPoint(event.pageX, event.pageY)); + this.doMouseMove( point ); + + } + }, + + doMouseMove: + { + value: function( point ) + { + if (this._isDrawing) + { + //console.log( "PanTool.mouseMove (drag)" ); + + // get the global screen point + var gPt = [point.x, point.y, this._globalPt[2]]; + + // update the scrollbars + var deltaGPt = VecUtils.vecSubtract(2, gPt, this._lastGPt); + this._lastGPt = gPt.slice(); + + var oldLeft = this.application.ninja.stage._iframeContainer.scrollLeft, + oldTop = this.application.ninja.stage._iframeContainer.scrollTop; + this.application.ninja.stage._iframeContainer.scrollLeft -= deltaGPt[0]; + this.application.ninja.stage._iframeContainer.scrollTop -= deltaGPt[1]; + deltaGPt[0] = oldLeft - this.application.ninja.stage._iframeContainer.scrollLeft; + deltaGPt[1] = oldTop - this.application.ninja.stage._iframeContainer.scrollTop; + + gPt[0] -= deltaGPt[0]; + gPt[1] -= deltaGPt[1]; + + this.updateGlobalToUCWorldMatrix(); + + var wPt = MathUtils.transformAndDivideHomogeneousPoint( gPt, this._globalToUCWorld ); + //console.log( "wPt: " + wPt ); + var delta = vecUtils.vecSubtract( 3, wPt, this._worldPt ); + if (this._altKeyDown) + { + //console.log( "moveZ" ); + var dist = vecUtils.vecMag(2, delta); + delta[0] = 0; delta[1] = 0; delta[2] = dist; + var dy = point.y - this._globalPt[1]; + if (dy < 0) delta[2] = -delta[2]; + } + else + { + console.log( "NOT MOVING Z" ); + delta[2] = 0; + } + var transMat = Matrix.Translation( delta ); + this._worldPt = wPt; + + if (this._altKeyDown) + this._globalPt[1] = point.y; + + // update everything + this.applyDeltaMat( transMat ); + } + } + }, + + mouseUp: + { + value: function( event ) + { + //console.log( "PanTool.mouseUp" ); + this.application.ninja.stage.updatedStage = true; + } + }, + + applyDeltaMat: + { + value: function( transMat ) + { + // update the user content matrix + var uc = this.application.ninja.currentDocument.documentRoot; + var ucMat = viewUtils.getMatrixFromElement(uc); + var newUCMat = glmat4.multiply( transMat, ucMat, [] ); + viewUtils.setMatrixForElement( uc, newUCMat ); + + // redraw everything + this.application.ninja.stage.updatedStage = true; + } + }, + + updateGlobalToUCWorldMatrix: + { + value: function() + { + // get the userContent object + var userContent = this.application.ninja.currentDocument.documentRoot; + + // get a matrix from user content world space to the screen + viewUtils.pushViewportObj( userContent ); + var cop = viewUtils.getCenterOfProjection(); + var pDist = viewUtils.getPerspectiveDistFromElement(userContent); + var projMat = glmat4.scale(Matrix.I(4), [pDist,pDist,pDist], []); + projMat[11] = -1; + projMat[15] = 1400; + var v2s = Matrix.Translation([cop[0], cop[1], 0]); + var ucWorldToGlobal = glmat4.multiply( v2s, projMat, [] ); + var offset = viewUtils.getElementOffset( userContent ); + var offMat = Matrix.Translation([offset[0], offset[1], 0]); + glmat4.multiply( offMat, ucWorldToGlobal, ucWorldToGlobal ); + this._globalToUCWorld = glmat4.inverse(ucWorldToGlobal, []); + viewUtils.popViewportObj(); + } + } +} +); + + + diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js new file mode 100644 index 00000000..78344d18 --- /dev/null +++ b/js/tools/PenTool.js @@ -0,0 +1,1245 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var ShapeTool = require("js/tools/ShapeTool").ShapeTool; +var DrawingToolBase = require("js/tools/drawing-tool-base").DrawingToolBase; +var defaultEventManager = require("montage/core/event/event-manager").defaultEventManager; +var Montage = require("montage/core/core").Montage; +var NJUtils = require("js/lib/NJUtils").NJUtils; +var ElementMediator = require("js/mediators/element-mediator").ElementMediator; +var TagTool = require("js/tools/TagTool").TagTool; +var ElementController = require("js/controllers/elements/element-controller").ElementController; + +exports.PenTool = Montage.create(ShapeTool, { + + _toolID: { value: "penTool" }, + _imageID: { value: "penToolImg" }, + _toolImageClass: { value: "penToolUp" }, + _selectedToolImageClass: { value: "penToolDown" }, + _toolTipText: { value: "Pen Tool" }, + _penView: { value: null, writable: true }, + + _selectedToolClass: { value: "penToolSpecificProperties" }, + _penToolProperties: { enumerable: false, value: null, writable: true }, + _parentNode: { enumerable: false, value: null, writable: true }, + _toolsPropertiesContainer: { enumerable: false, value: null, writable: true }, + + // Need to keep track of current mouse position for KEY modifiers event which do not have mouse coordinates + _currentX: { value: 0, writable: true }, + _currentY: { value: 0, writable: true }, + + //the subpaths are what is displayed on the screen currently, with _selectedSubpath being the active one currently being edited + _subpaths: { value: [], writable: true }, + _selectedSubpath: { value: null, writable: true }, + _makeMultipleSubpaths: { value: true, writable: true }, //set this to true if you want to keep making subpaths after closing current subpath + + + //whether or not to display the guides for debugging + _showGuides: { value: true, writable: true }, + + //whether the user has held down the Alt key + _isAltDown: { value: false, writable: true }, + + //whether the user has held down the Esc key + _isEscapeDown: {value: false, writable: true }, + + //whether we have just started a new path (set true in mousedown, and set false in mouse up + _isNewPath: {value: false, writable: true}, + + //whether we have clicked one of the endpoints after entering the pen tool in ENTRY_SELECT_PATH edit mode + _isPickedEndPointInSelectPathMode: {value: false, writable: true}, + + //when the user wants to place a selected anchor point on top of another point, this is the target where the point will be placed + _snapTarget: { value: null, writable: true }, + + //whether or not we're using webgl for drawing + _useWebGL: {value: false, writable: false }, + + //the canvas created by the pen tool...this is grown or shrunk with the path (if the canvas was not already provided) + _penCanvas: { value: null, writable: true }, + + //the plane matrix for the first click...so the entire path is on the same plane + _penPlaneMat: { value: null, writable: true }, + + //constants used for picking points --- NOTE: these should be user-settable parameters + _PICK_POINT_RADIUS: { value: 10, writable: false }, + _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false }, + _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false }, + _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 5, writable: false }, + _DISPLAY_SELECTED_ANCHOR_NEXT_RADIUS: { value: 5, writable: false }, + + //constants used for editing modes (can be OR-ed) + EDIT_NONE: { value: 0, writable: false }, + EDIT_ANCHOR: { value: 1, writable: false }, + EDIT_PREV: { value: 2, writable: false }, + EDIT_NEXT: { value: 4, writable: false }, + EDIT_PREV_NEXT: { value: 8, writable: false }, + _editMode: { value: this.EDIT_NONE, writable: true }, + + //constants used for selection modes on entry to pen tool (mutually exclusive) + ENTRY_SELECT_NONE: { value: 0, writable: false}, + ENTRY_SELECT_CANVAS: { value: 1, writable: false}, + ENTRY_SELECT_PATH: { value: 2, writable: false}, + _entryEditMode: {value: this.ENTRY_SELECT_NONE, writable: true}, + + // ******** Logic for selection ******* + // (update if you change functionality!) + // NOTE: this is out of date...needs to be updated + // + // Start by setting edit mode to EDIT_NONE + // + // DOUBLE_CLICK (Left mouse button only): + // + // + // SINGLE_CLICK (Left mouse button only): + // If LeftClick selects an anchor point + // append EDIT_ANCHOR mode + // If LeftClick selects a previous point of selected anchor + // append EDIT_PREV mode + // If LeftClick selects a next point of selected anchor + // append EDIT_NEXT mode + // + + // ********* Logic for editing ******* + // (update if you change functionality!) + // NOTE: this is out of date...needs to be updated + // + // Start by computing mouse disp + // + // If EDIT_PREV_NEXT mode + // add disp to next and mirror it to prev + // ELSE + // If EDIT_ANCHOR (or _PREV, _NEXT) + // map displacement to anchor (similarly to prev and next) + // + // + + + ShowToolProperties: { + value: function () { + this._penView = PenView.create(); + this._penView.element = document.getElementById('topPanelContainer').children[0]; + this._penView.needsDraw = true; + + this._penView.addEventListener(ToolEvents.TOOL_OPTION_CHANGE, this, false); + } + + }, + + HandleLeftButtonDown: + { + value: function (event) { + //ignore any right or middle clicks + if (event.button !== 0) { + //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2) + return; + } + //BEGIN ShapeTool code + if (this._canDraw) { + this._isDrawing = true; + } + + //this._targetedCanvas = stageManagerModule.stageManager.GetObjectFromPoint(event.layerX, event.layerY, this._canOperateOnStage); + + this.startDraw(event); + //END ShapeTool code + + //assume we are not starting a new path as we will set this to true if we create a new GLSubpath() + this._isNewPath = false; + + //add an anchor point by computing position of mouse down + var mouseDownPos = this.getMouseDownPos(); + if (mouseDownPos) { + //if we had closed the selected subpath previously, or if we have not yet started anything, create a subpath + if (this._selectedSubpath === null) { + this._selectedSubpath = new GLSubpath(); + this._isNewPath = true; + if (this._entryEditMode === this.ENTRY_SELECT_PATH){ + //this should not happen, as ENTRY_SELECT_PATH implies there was a selected subpath + this._entryEditMode = this.ENTRY_SELECT_NONE; + } + } else if (this._selectedSubpath.getIsClosed() && this._entryEditMode !== this.ENTRY_SELECT_PATH) { + //since we're not in ENTRY_SELECT_PATH mode, we don't edit the closed path...we start a new path regardless of where we clicked + if (this._makeMultipleSubpaths) { + this._subpaths.push(this._selectedSubpath); + this._penCanvas = null; + this._penPlaneMat = null; + this._snapTarget = null; + this._selectedSubpath = new GLSubpath(); + this._isNewPath = true; + } + } + + var prevSelectedAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex(); + // ************* Add/Select Anchor Point ************* + //check if the clicked location is close to an anchor point...if so, make that anchor the selected point and do nothing else + // BUT if the anchor point selected is the first anchor point, check if the previous selected anchor was the last anchor point...in that case, close the path + var selParam = this._selectedSubpath.pickPath(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2], this._PICK_POINT_RADIUS); + var whichPoint = this._selectedSubpath.getSelectedMode(); + if (whichPoint & this._selectedSubpath.SEL_ANCHOR) { + //if we're in ENTRY_SELECT_PATH mode AND we have not yet clicked on the endpoint AND if we have now clicked on the endpoint + if (this._entryEditMode === this.ENTRY_SELECT_PATH && this._isPickedEndPointInSelectPathMode === false){ + var selAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex(); + if (selAnchorIndex===0 || selAnchorIndex===this._selectedSubpath.getNumAnchors()-1){ + //we have picked the endpoint of this path...reverse the path if necessary + if (selAnchorIndex ===0){ + //reverse this path + } +