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/PenTool.js | 1245 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1245 insertions(+) create mode 100644 js/tools/PenTool.js (limited to 'js/tools/PenTool.js') 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 + } + this._isPickedEndPointInSelectPathMode = true; + } + } + this._editMode = this.EDIT_ANCHOR; + //if we have selected the first anchor point, and previously had selected the last anchor point, close the path + var numAnchors = this._selectedSubpath.getNumAnchors(); + if (numAnchors>1 && !this._selectedSubpath.getIsClosed() && this._selectedSubpath.getSelectedAnchorIndex()===0 && prevSelectedAnchorIndex === numAnchors-1){ + //setting the selection mode to NONE will effectively add a new anchor point at the click location and also give us snapping + whichPoint = this._selectedSubpath.SEL_NONE; + //set the snap target in case the mouse move handler doesn't get called + this._snapTarget = this._selectedSubpath.getAnchor(0); + } + } + //check if the clicked location is close to prev and next of the selected anchor point..if so select that anchor, set mode to PREV or NEXT and do nothing else + // but if the selectedAnchor index is not -1 and neither prev nor next are selected, it means click selected a point selParam along bezier segment starting at selectedAnchor + else if (this._selectedSubpath.getSelectedAnchorIndex() !== -1) { + if (whichPoint & this._selectedSubpath.SEL_PREV){ + this._editMode = this.EDIT_PREV; + } + else if (whichPoint & this._selectedSubpath.SEL_NEXT){ + this._editMode = this.EDIT_NEXT; + } + else if (whichPoint & this._selectedSubpath.SEL_PATH) { + //the click point is close enough to insert point in bezier segment after selected anchor at selParam + if (selParam > 0 && selParam < 1) { + this._selectedSubpath.insertAnchorAtParameter(this._selectedSubpath.getSelectedAnchorIndex(), selParam); + //set the mode so that dragging will update anchor point positions + //this._editMode = this.EDIT_ANCHOR; + } + } + } + if (whichPoint === this._selectedSubpath.SEL_NONE) { + if (this._entryEditMode !== this.ENTRY_SELECT_PATH) { + //add an anchor point to end of the subpath, and make it the selected anchor point + if (!this._selectedSubpath.getIsClosed() || this._makeMultipleSubpaths) { + this._selectedSubpath.addAnchor(new GLAnchorPoint()); + var newAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + newAnchor.setPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]); + newAnchor.setPrevPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]); + newAnchor.setNextPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]); + + //set the mode so that dragging will update the next and previous locations + this._editMode = this.EDIT_PREV_NEXT; + } + } else { + if (this._isPickedEndPointInSelectPathMode){ + + } + //if the edit mode was ENTRY_SELECT_PATH and no anchor point was selected, so we should de-select this path and revert to ENTRY_SELECT_NONE + //this._entryEditMode = this.ENTRY_SELECT_NONE; //TODO revisit this after implementing code for adding points to any end of selected path + } + } //if (whichPoint === this._selectedSubpath.SEL_NONE) (i.e. no anchor point was selected) + + //display the curve overlay + this.DrawSubpathAnchors(this._selectedSubpath); + this.DrawSubpathsSVG(); + } //if (mouseDownPos) { i.e. if mouse down yielded a valid position + + + 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) { + if (!this._isAltDown) + this.doDraw(event); //if Alt was down, doDraw prevents this.mouseUpHitRec from being written to + else{ + var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY)); + this.mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(point.x, point.y, false, this.mouseDownHitRec); + } + + + // ******* begin new code ********* + //get the current mouse position from the drawing-tool knowing that the mouse up position is set to current mouse pos in this.doDraw above + var currMousePos = this.getMouseUpPos(); + if (currMousePos && this._selectedSubpath && (this._selectedSubpath.getSelectedAnchorIndex() >= 0 && this._selectedSubpath.getSelectedAnchorIndex() < this._selectedSubpath.getNumAnchors())) { + //var scoord = this._getScreenCoord(this._mouseUpHitRec); + var selAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + var selX = selAnchor.getPosX(); + var selY = selAnchor.getPosY(); + var selZ = selAnchor.getPosZ(); + if (this._editMode & this.EDIT_ANCHOR) { + selAnchor.translateAll(currMousePos[0] - selX, currMousePos[1] - selY, currMousePos[2] - selZ); + } + else if (this._editMode & this.EDIT_PREV) { + var oldPX = selAnchor.getPrevX(); + var oldPY = selAnchor.getPrevY(); + var oldPZ = selAnchor.getPrevZ(); + selAnchor.translatePrev(currMousePos[0] - oldPX, currMousePos[1] - oldPY, currMousePos[2] - oldPZ); + + //move the next point if Alt key is down to ensure relative angle between prev and next + if (this._isAltDown) { + selAnchor.translateNextFromPrev(currMousePos[0] - oldPX, currMousePos[1] - oldPY, currMousePos[2] - oldPZ); + } + } + else if (this._editMode & this.EDIT_NEXT) { + var oldNX = selAnchor.getNextX(); + var oldNY = selAnchor.getNextY(); + var oldNZ = selAnchor.getNextZ(); + selAnchor.translateNext(currMousePos[0] - oldNX, currMousePos[1] - oldNY, currMousePos[2] - oldNZ); + + //move the prev point if Alt key is down to ensure relative angle between prev and next + if (this._isAltDown) { + selAnchor.translatePrevFromNext(currMousePos[0] - oldNX, currMousePos[1] - oldNY, currMousePos[2] - oldNZ); + } + } + else if (this._editMode & this.EDIT_PREV_NEXT) { + selAnchor.setNextPos(currMousePos[0], currMousePos[1], currMousePos[2]); + selAnchor.setPrevFromNext(); + } + + //snapping...check if the new location of the anchor point is close to another anchor point + this._snapTarget = null; + var numAnchors = this._selectedSubpath.getNumAnchors(); + for (var i = 0; i < numAnchors; i++) { + //check if the selected anchor is close to any other anchors + if (i === this._selectedSubpath.getSelectedAnchorIndex()) + continue; + var currAnchor = this._selectedSubpath.getAnchor(i); + var distSq = currAnchor.getDistanceSq(selX, selY, selZ); + if (distSq < this._PICK_POINT_RADIUS * this._PICK_POINT_RADIUS) { + //set the snap target to the location of the first close-enough anchor + this._snapTarget = currAnchor; + break; + } + } + + //make the subpath dirty so it will get re-drawn + this._selectedSubpath.makeDirty(); + //clear the canvas before we draw anything else + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + this.DrawSubpathAnchors(this._selectedSubpath); + } + // ********* end new code *********** + + } else { + this.doSnap(event); + this.DrawHandles(); + } //else of if (this._isDrawing) { + + this.drawLastSnap(); // Required cleanup for both Draw/Feedbacks + + this.DrawSubpathsSVG(); + }//value: function(event) + }, + + //TODO Optimize! This function is probably no longer needed + TranslateSelectedSubpathPerPenCanvas:{ + value: function() { + if (this._penCanvas!==null) { + //obtain the 2D translation of the canvas due to the Selection tool...assuming this is called in Configure + var penCanvasLeft = parseFloat(ElementMediator.getProperty(this._penCanvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left")); + var penCanvasTop = parseFloat(ElementMediator.getProperty(this._penCanvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top")); + var penCanvasWidth = this._penCanvas.width; + var penCanvasHeight = this._penCanvas.height; + var penCanvasOldX = penCanvasLeft + 0.5 * penCanvasWidth; + var penCanvasOldY = penCanvasTop + 0.5 * penCanvasHeight; + + var translateCanvasX = penCanvasOldX - this._selectedSubpath.getCanvasX(); + var translateCanvasY = penCanvasOldY - this._selectedSubpath.getCanvasY(); + + //update the canvasX and canvasY parameters for this subpath and also translate the subpath points (since they're stored in stage world space) + this._selectedSubpath.setCanvasX(translateCanvasX + this._selectedSubpath.getCanvasX()); + this._selectedSubpath.setCanvasY(translateCanvasY + this._selectedSubpath.getCanvasY()); + this._selectedSubpath.translate(translateCanvasX, translateCanvasY, 0); + this._selectedSubpath.createSamples(); //updates the bounding box + } + } + }, + + ShowSelectedSubpath:{ + value: function() { + var bboxMin = this._selectedSubpath.getBBoxMin(); + var bboxMax = this._selectedSubpath.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._selectedSubpath.setCanvasX(bboxMid[0]); + this._selectedSubpath.setCanvasY(bboxMid[1]); + + //call render shape with the bbox width and height + this.RenderShape(bboxWidth, bboxHeight, this._penPlaneMat, bboxMid, this._penCanvas); + } + }, + + HandleLeftButtonUp: { + value: function (event) { + if (this._isDrawing) { + this.doDraw(event); //needed to get the mouse up point in case there was no mouse move + } + + //snapping...if there was a snapTarget and a selected anchor, move the anchor to the snap target + if (this._snapTarget !== null && this._selectedSubpath && this._selectedSubpath.getSelectedAnchorIndex() !== -1) { + var selAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + selAnchor.setPos(this._snapTarget.getPosX(), this._snapTarget.getPosY(), this._snapTarget.getPosZ()); + this._selectedSubpath.makeDirty(); + + //if the first or last anchor point were snapped for an open path, check if the first and last anchor point are at the same position + if (!this._selectedSubpath.getIsClosed()) { + var lastAnchorIndex = this._selectedSubpath.getNumAnchors() - 1; + var firstAnchor = this._selectedSubpath.getAnchor(0); + var lastAnchor = this._selectedSubpath.getAnchor(lastAnchorIndex); + if ((this._selectedSubpath.getSelectedAnchorIndex() === 0 && this._snapTarget === lastAnchor) || (this._selectedSubpath.getSelectedAnchorIndex() === lastAnchorIndex && this._snapTarget === firstAnchor)) { + this._selectedSubpath.setIsClosed(true); + //set the prev of the first anchor to the be prev of the last anchor + firstAnchor.setPrevPos(lastAnchor.getPrevX(), lastAnchor.getPrevY(), lastAnchor.getPrevZ()); + + //only if we have more than two anchor points, remove the last point + if (lastAnchorIndex > 1) { + //remove the last anchor from the subpath + this._selectedSubpath.removeAnchor(lastAnchorIndex); + } else { + //set the next of the last anchor to the be next of the first anchor + lastAnchor.setPrevPos(firstAnchor.getNextX(), firstAnchor.getNextY(), firstAnchor.getNextZ()); + } + } + } + } + this._snapTarget = null; + + var drawData = this.getDrawingData(); + if (drawData) { + if (!this._penPlaneMat) { + this._penPlaneMat = drawData.planeMat; + } + + if (this._isNewPath) { + var strokeSize = 10.0; + if (this.options.strokeSize) { + strokeSize = this.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units); + } + this._selectedSubpath.setStrokeWidth(strokeSize); + } + + this._selectedSubpath.makeDirty(); + + this._selectedSubpath.createSamples(); + //if we have some samples to render... + if (this._selectedSubpath.getNumAnchors() > 1) { + this.ShowSelectedSubpath(); + } //if (this._selectedSubpath.getNumPoints() > 0) { + } //if drawData + + //always assume that we're not starting a new path anymore + this._isNewPath = false; + this.endDraw(event); + + this._isDrawing = false; + this._hasDraw = false; + this._editMode = this.EDIT_NONE; + + this.DrawHandles(); + if (this._entryEditMode === this.ENTRY_SELECT_PATH || !this._selectedSubpath.getIsClosed()){ + this.DrawSubpathAnchors(this._selectedSubpath);//render the subpath anchors on canvas (not GL) + } + + NJevent("disableStageMove");//stageManagerModule.stageManager.disableMouseMove(); + } + }, + + //override the Alt key handlers from drawing-tool.js + HandleAltKeyDown: { + value: function (event) { + this._isAltDown = true; + } + }, + HandleAltKeyUp: { + value: function (event) { + this._isAltDown = false; + } + }, + + HandleEscape: { + value: function(event) { + this._isEscapeDown = true; + //close the current subpath and reset the pen tool + this._subpaths.push(this._selectedSubpath); + this._penCanvas = null; + this._penPlaneMat = null; + this._snapTarget = null; + this._selectedSubpath = null; + this.application.ninja.stage.clearDrawingCanvas(); + } + }, + + HandleKeyUp: { + value: function(event){ + if (!(event.target instanceof HTMLInputElement)) { + if(event.altKey || event.keyCode === 18) { //for key up, the event.altKey is false when it should be true, so I also check keyCode + this.HandleAltKeyUp(event); + } else { + console.log("Pen tool Unhandled key up:", event.keyCode); + } + } + } + }, + HandleKeyPress: { + value: function(event){ + var inc, currentValue, moveCommand; + + if (!(event.target instanceof HTMLInputElement)) { + if(event.shiftKey) { + this.HandleShiftKeyDown(event); + } else if(event.altKey) { + this.HandleAltKeyDown(event); + } else if (event.keyCode === Keyboard.SPACE) { + event.preventDefault(); + this.HandleSpaceKeyDown(event); + } else if (event.keyCode == Keyboard.BACKSPACE || event.keyCode === Keyboard.DELETE) { + //TODO this is probably unnecessary since we handle delete and backspace via the delete delegate + event.stopImmediatePropagation(); + event.preventDefault(); + } else if (event.keyCode === Keyboard.ESCAPE){ + this.HandleEscape(event); + } else { + console.log("Pen tool Unhandled key press:", event.keyCode); + } + } + + + } + }, + + handleScroll: { + value: function(event) { + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + this.DrawSubpathAnchors(this._selectedSubpath); + } + }, + + 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 strokeStyle = this.options.strokeStyle; + var strokeSize = 4.0; + if (this.options.strokeSize) { + strokeSize = this.GetValueInPixels(this.options.strokeSize.value, this.options.strokeSize.units, h); + } + var strokeColor = [1.0, 0.3, 0.3, 1.0]; + var fillColor = [1, .2, .5, 1.0]; + //var s = ColorPanelModule.ColorPanel.strokeToolbar.webGlColor; + var s = strokeColor; + if(s) + { + strokeColor = [s.r/255, s.g/255, s.b/255, s.a]; + } + + + //var f = ColorPanelModule.ColorPanel.fillToolbar.webGlColor; + var f = fillColor; + if(f) + { + fillColor = [f.r/255, f.g/255, f.b/255, f.a]; + } + + // 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)); + } + + if (!canvas) { + var newCanvas = null; + //if (this._useExistingCanvas()) { + // newCanvas = this._targetedCanvas; //TODO...when is this condition true? I would like to reuse canvas when continuing path or when drawing on div tool canvas + //}else { + //newCanvas = this.createCanvas(left, top, w, h,"Subpath"); + //} + + newCanvas = NJUtils.makeNJElement("canvas", "Subpath", "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);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, newCanvas, this._useWebGL);//fillMaterial, strokeMaterial); + //store a reference to this newly created canvas + this._penCanvas = newCanvas; + + var subpath = this._selectedSubpath; //new GLSubpath(); + subpath.setWorld(world); + subpath.setStrokeMaterial(strokeMaterial); + subpath.setFillMaterial(fillMaterial); + subpath.setFillColor(fillColor); + subpath.setStrokeColor(strokeColor); + subpath.setStrokeStyle(strokeStyle); + + subpath.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + subpath.setPlaneMatrixInverse(planeMatInv); + subpath.setPlaneCenter(midPt); + + world.addObject(subpath); + world.render(); + newCanvas.elementModel.shapeModel.GLGeomObj = subpath; + } //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", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "left", parseInt(left) + "px"); + ElementMediator.setProperty(canvasArray, "top", [parseInt(top) + "px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "top", parseInt(top) + "px"); + 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 subpath = this._selectedSubpath; + + subpath.setDrawingTool(this); + subpath.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + subpath.setPlaneMatrixInverse(planeMatInv); + subpath.setPlaneCenter(midPt); + + subpath.setWorld(world); + subpath.setStrokeMaterial(strokeMaterial); + subpath.setStrokeColor(strokeColor); + subpath.setStrokeStyle(strokeStyle); + subpath.setFillMaterial(fillMaterial); + subpath.setFillColor(fillColor); + + world.addIfNewObject(subpath); + //world.addObject(subpath); + world.render(); + + //TODO this will not work if there are multiple shapes in the same canvas + canvas.elementModel.shapeModel.GLGeomObj = subpath; + } //else of if (!canvas) { + } //value: function (w, h, planeMat, midPt, canvas) { + }, //RenderShape: { + + BuildSecondCtrlPoint:{ + value: function(p0, p2, p3) { + var baselineOrig = VecUtils.vecSubtract(3, p3, p0); + var baseline = VecUtils.vecNormalize(3, baselineOrig); + var delta = VecUtils.vecSubtract(3, p2, p3); + //component of the delta along baseline + var deltaB = Vector.create(baseline); + VecUtils.vecScale(3, deltaB, VecUtils.vecDot(3, baseline, delta)); + //component of the delta orthogonal to baseline + var deltaO = VecUtils.vecSubtract(3, delta, deltaB); + + var p1 = VecUtils.vecInterpolate(3, p0, p3, 0.3333); + p1= VecUtils.vecAdd(3, p1,deltaO); + + return p1; + } //value: function(p0, p2, p3) { + }, //BuildSecondCtrlPoint:{ + + + deleteSelection: { + value: function() { + //clear the selected subpath...the only new additions to this function w.r.t. ToolBase + if (this._selectedSubpath){ + if (this._selectedSubpath.getSelectedAnchorIndex()>=0){ + this._selectedSubpath.removeAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + //clear the canvas + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + this.DrawSubpathAnchors(this._selectedSubpath); + this.ShowSelectedSubpath(); + } + else { + this._selectedSubpath.clearAllAnchors(); + + this._selectedSubpath.createSamples(); + this._selectedSubpath = null; + //clear the canvas + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + + //TODO begin code block taken from ToolBase...figure out how to override it correctly + var item; + /* + if(!selectionManagerModule.selectionManager.isDocument) { + for(var i=0; item = selectionManagerModule.selectionManager.selectedItems[i]; i++) { + drawUtils.removeElement(item._element); // TODO This was called twice - After the event. + window.snapManager.removeElementFrom2DCache( item._element ); // TODO Check with Nivesh about it. + DocumentControllerModule.DocumentController.RemoveElement(item._element); + } + + NJevent( "deleteSelection" ); + } + */ + //end code block taken from ToolBase + + this._penCanvas = null; + } + } + } + }, + + HandleDoubleClick: { + value: function () { + //if there is a selected anchor point + if (this._selectedSubpath && this._selectedSubpath.getSelectedAnchorIndex() !== -1) { + var selAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + var pos = Vector.create([selAnchor.getPosX(), selAnchor.getPosY(), selAnchor.getPosZ()]); + //var prev = Vector.create([selAnchor.getPrevX(), selAnchor.getPrevY(), selAnchor.getPrevZ()]); + //var next = Vector.create([selAnchor.getNextX(), selAnchor.getNextY(), selAnchor.getNextZ()]); + + var distToPrev = selAnchor.getPrevDistanceSq(pos[0], pos[1], pos[2]); + var distToNext = selAnchor.getNextDistanceSq(pos[0], pos[1], pos[2]); + var threshSq = 0; // 4 * this._PICK_POINT_RADIUS * this._PICK_POINT_RADIUS; + //if either prev or next are within threshold distance to anchor position + if (distToPrev <= threshSq || distToNext <= threshSq) { + var haveNext = false; + var havePrev = false; + var numAnchors = this._selectedSubpath.getNumAnchors(); + if (numAnchors>1 && (this._selectedSubpath.getSelectedAnchorIndex() < (numAnchors-1) || this._selectedSubpath.getIsClosed())){ + //there is an anchor point after this one + var nextAnchor = null; + if (this._selectedSubpath.getSelectedAnchorIndex() < (numAnchors-1)) + nextAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()+1); + else + nextAnchor = this._selectedSubpath.getAnchor(0); + var nextAnchorPrev = Vector.create([nextAnchor.getPrevX(), nextAnchor.getPrevY(), nextAnchor.getPrevZ()]); + var nextAnchorPos = Vector.create([nextAnchor.getPosX(), nextAnchor.getPosY(), nextAnchor.getPosZ()]) + var newNext = this.BuildSecondCtrlPoint(pos, nextAnchorPrev, nextAnchorPos); + selAnchor.setNextPos(newNext[0], newNext[1], newNext[2]); + //check if the next is still not over the threshSq..if so, add a constant horizontal amount + if (selAnchor.getNextDistanceSq(pos[0], pos[1], pos[2]) <= threshSq) { + selAnchor.setNextPos(newNext[0]+ (3 * this._PICK_POINT_RADIUS), newNext[1], newNext[2]); + } + haveNext = true; + } + if (numAnchors>1 && (this._selectedSubpath.getSelectedAnchorIndex() > 0 || this._selectedSubpath.getIsClosed())){ + //there is an anchor point before this one + var prevAnchor = null; + if (this._selectedSubpath.getSelectedAnchorIndex() > 0) + prevAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()-1); + else + prevAnchor = this._selectedSubpath.getAnchor(numAnchors-1); + var prevAnchorNext = Vector.create([prevAnchor.getNextX(), prevAnchor.getNextY(), prevAnchor.getNextZ()]); + var prevAnchorPos = Vector.create([prevAnchor.getPosX(), prevAnchor.getPosY(), prevAnchor.getPosZ()]) + var newPrev = this.BuildSecondCtrlPoint(pos, prevAnchorNext, prevAnchorPos); + selAnchor.setPrevPos(newPrev[0], newPrev[1], newPrev[2]); + //check if the prev is still not over the threshSq..if so, add a constant horizontal amount + if (selAnchor.getPrevDistanceSq(pos[0], pos[1], pos[2]) <= threshSq) { + selAnchor.setPrevPos(newPrev[0]+ (3 * this._PICK_POINT_RADIUS), newPrev[1], newPrev[2]); + } + havePrev = true; + } + + if (haveNext && !havePrev){ + selAnchor.setPrevFromNext(); + } else if (havePrev && !haveNext){ + selAnchor.setNextFromPrev(); + } else if (!haveNext && !havePrev){ + selAnchor.setNextPos(pos[0]+ (3 * this._PICK_POINT_RADIUS), pos[1], pos[2]); + selAnchor.setPrevFromNext(); + } + } // if (distToPrev < threshSq) { + else { + //bring points close (to exactly same position) + selAnchor.setNextPos(pos[0], pos[1], pos[2]); + selAnchor.setPrevPos(pos[0], pos[1], pos[2]); + } // else of if (distToPrev < threshSq) { + + this._selectedSubpath.makeDirty(); + this._selectedSubpath.createSamples(); + this.ShowSelectedSubpath(); + + //clear the canvas before we draw anything else + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + + this.DrawSubpathAnchors(this._selectedSubpath); + } //if (this._selectedSubpath && this._selectedSubpath.getSelectedAnchorIndex() !== -1) + + } //value: function () { + }, //HandleDoubleClick: { + + + _getScreenCoord: + { + value: function (hitRec) { + var sRet = hitRec.getScreenPoint(); + sRet[2] = 0; + return sRet; + } + }, //_getScreenCoord: + + + // DrawSubpathSVG + // Draw the subpath using the SVG drawing capability (i.e. not WebGL) + DrawSubpathSVG: + { + value: function (subpath) { + if (subpath === null) + return; + + subpath.createSamples(); //dirty bit will be checked inside this function + var numAnchors = subpath.getNumAnchors(); + if (numAnchors === 0) + return; + + var ctx = this.application.ninja.stage.drawingContext;//stageManagerModule.stageManager.drawingContext; + if (ctx === null) + throw ("null drawing context in Pentool::DrawSubpathSVG"); + ctx.save(); + + var horizontalOffset = this.application.ninja.stage.userContentLeft;//stageManagerModule.stageManager.userContentLeft; + var verticalOffset = this.application.ninja.stage.userContentTop;//stageManagerModule.stageManager.userContentTop; + + + if (this._showGuides) { + var leftOffsetSamples = subpath.getLeftOffsetPoints(); + var rightOffsetSamples = subpath.getRightOffsetPoints(); + /* + //display the subpath samples as a sequence of circles + ctx.lineWidth = 2; + ctx.fillStyle = "pink"; + ctx.strokeStyle = "black"; + for (var i = 0; i < samples.length; i += 3) { + ctx.beginPath(); + ctx.arc(samples[i], samples[i + 1], this._DISPLAY_ANCHOR_RADIUS, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + } + */ + + /* + //display circles near all offset sample points + ctx.fillStyle = "#44FF44"; + ctx.lineWidth = 2; + ctx.strokeStyle = "black"; + for (var i = 0; i < leftOffsetSamples.length; i++) { + var px = leftOffsetSamples[i].Pos[0]+ horizontalOffset; + var py = leftOffsetSamples[i].Pos[1]+ verticalOffset; + ctx.beginPath(); + ctx.arc(px, py, this._DISPLAY_ANCHOR_RADIUS * 0.75, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + } + */ + + /* + //display mapping of subpath samples to offset samples + + ctx.strokeStyle = "black"; + ctx.lineWidth = 1; + ctx.beginPath(); + for (var i = 0; i < leftOffsetSamples.length; i++) { + var px = leftOffsetSamples[i].Pos[0]+ horizontalOffset; + var py = leftOffsetSamples[i].Pos[1]+ verticalOffset; + var ox = leftOffsetSamples[i].CurveMapPos[0] + horizontalOffset; + var oy = leftOffsetSamples[i].CurveMapPos[1] + verticalOffset; + + ctx.moveTo(px, py); + ctx.lineTo(ox,oy); + } + ctx.stroke(); + ctx.strokeStyle = "black"; + ctx.lineWidth = 1; + ctx.beginPath(); + for (var i = 0; i < rightOffsetSamples.length; i++) { + var px = rightOffsetSamples[i].Pos[0]+ horizontalOffset; + var py = rightOffsetSamples[i].Pos[1]+ verticalOffset; + var ox = rightOffsetSamples[i].CurveMapPos[0] + horizontalOffset; + var oy = rightOffsetSamples[i].CurveMapPos[1] + verticalOffset; + + ctx.moveTo(px, py); + ctx.lineTo(ox,oy); + } + ctx.stroke(); + */ + + /* + //display triangles generated + var leftOffsetTriangles = subpath.getLeftOffsetTriangles(); + ctx.strokeStyle = "black"; + ctx.lineWidth = 1; + ctx.beginPath(); + for (var i = 0; i < leftOffsetTriangles.length; i++) { + ctx.moveTo(leftOffsetTriangles[i].v0[0] + horizontalOffset, leftOffsetTriangles[i].v0[1] + verticalOffset); + ctx.lineTo(leftOffsetTriangles[i].v1[0] + horizontalOffset, leftOffsetTriangles[i].v1[1] + verticalOffset); + ctx.lineTo(leftOffsetTriangles[i].v2[0] + horizontalOffset, leftOffsetTriangles[i].v2[1] + verticalOffset); + } + ctx.stroke(); + + var rightOffsetTriangles = subpath.getRightOffsetTriangles(); + ctx.strokeStyle = "black"; + ctx.lineWidth = 1; + ctx.beginPath(); + for (var i = 0; i < rightOffsetTriangles.length; i++) { + ctx.moveTo(rightOffsetTriangles[i].v0[0] + horizontalOffset, rightOffsetTriangles[i].v0[1] + verticalOffset); + ctx.lineTo(rightOffsetTriangles[i].v1[0] + horizontalOffset, rightOffsetTriangles[i].v1[1] + verticalOffset); + ctx.lineTo(rightOffsetTriangles[i].v2[0] + horizontalOffset, rightOffsetTriangles[i].v2[1] + verticalOffset); + } + ctx.stroke(); + */ + } //if this._showGuides + + + + //display the subpath as a sequence of cubic beziers + ctx.lineWidth = 1;//subpath.getStrokeWidth(); //TODO replace hardcoded stroke width with some programmatically set value (should not be same as stroke width) + if (ctx.lineWidth == subpath.getStrokeWidth()) + ctx.lineWidth = 3; + ctx.strokeStyle = "black"; + if (subpath.getStrokeColor()) + ctx.strokeStyle = MathUtils.colorToHex( subpath.getStrokeColor() ); + ctx.beginPath(); + var p0x = subpath.getAnchor(0).getPosX()+ horizontalOffset; + var p0y = subpath.getAnchor(0).getPosY()+ verticalOffset; + ctx.moveTo(p0x, p0y); + for (var i = 1; i < numAnchors; i++) { + var p1x = subpath.getAnchor(i - 1).getNextX()+ horizontalOffset; + var p1y = subpath.getAnchor(i - 1).getNextY()+ verticalOffset; + var p2x = subpath.getAnchor(i).getPrevX()+ horizontalOffset; + var p2y = subpath.getAnchor(i).getPrevY()+ verticalOffset; + var p3x = subpath.getAnchor(i).getPosX()+ horizontalOffset; + var p3y = subpath.getAnchor(i).getPosY()+ verticalOffset; + ctx.bezierCurveTo(p1x, p1y, p2x, p2y, p3x, p3y); + } + if (subpath.getIsClosed()) { + var i = numAnchors - 1; + var p1x = subpath.getAnchor(i).getNextX()+ horizontalOffset; + var p1y = subpath.getAnchor(i).getNextY()+ verticalOffset; + var p2x = subpath.getAnchor(0).getPrevX()+ horizontalOffset; + var p2y = subpath.getAnchor(0).getPrevY()+ verticalOffset; + var p3x = subpath.getAnchor(0).getPosX()+ horizontalOffset; + var p3y = subpath.getAnchor(0).getPosY()+ verticalOffset; + ctx.bezierCurveTo(p1x, p1y, p2x, p2y, p3x, p3y); + } + ctx.stroke(); + + ctx.restore(); + } //function (subpath) + }, //DrawSubpathSVG + + DrawSubpathAnchors: + { + value: function (subpath) { + if (subpath === null) + return; + var numAnchors = subpath.getNumAnchors(); + if (numAnchors === 0) + return; + + var ctx = this.application.ninja.stage.drawingContext;//stageManagerModule.stageManager.drawingContext; + if (ctx === null) + throw ("null drawing context in Pentool::DrawSelectedSubpathAnchors"); + ctx.save(); + + var horizontalOffset = this.application.ninja.stage.userContentLeft;//stageManagerModule.stageManager.userContentLeft; + var verticalOffset = this.application.ninja.stage.userContentTop;//stageManagerModule.stageManager.userContentTop; + + /* + //display the sampled left offset of subpath as a sequence of line segments + var leftOffsetSamples = subpath.getLeftOffsetPoints(); + if (leftOffsetSamples.length) { + ctx.strokeStyle = "blue"; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(leftOffsetSamples[0].Pos[0] + horizontalOffset, leftOffsetSamples[0].Pos[1] + verticalOffset); + for (var i = 0; i < leftOffsetSamples.length; i++) { + ctx.lineTo(leftOffsetSamples[i].Pos[0] + horizontalOffset, leftOffsetSamples[i].Pos[1] + verticalOffset); + } + ctx.stroke(); + } + + + //display the sampled right offset of subpath as a sequence of line segments + var rightOffsetSamples = subpath.getRightOffsetPoints(); + if (rightOffsetSamples.length) { + ctx.strokeStyle = "red"; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(rightOffsetSamples[0].Pos[0] + horizontalOffset, rightOffsetSamples[0].Pos[1] + verticalOffset); + for (var i = 0; i < rightOffsetSamples.length; i++) { + ctx.lineTo(rightOffsetSamples[i].Pos[0] + horizontalOffset, rightOffsetSamples[i].Pos[1] + verticalOffset); + } + ctx.stroke(); + } + */ + + //display circles and squares near all control points + ctx.fillStyle = "#FF4444"; + ctx.lineWidth = 2; + ctx.strokeStyle = "black"; + for (var i = 0; i < numAnchors; i++) { + //display the anchor point with its prev. and next + var px = subpath.getAnchor(i).getPosX(); + var py = subpath.getAnchor(i).getPosY(); + var prevx = subpath.getAnchor(i).getPrevX(); + var prevy = subpath.getAnchor(i).getPrevY(); + var nextx = subpath.getAnchor(i).getNextX(); + var nexty = subpath.getAnchor(i).getNextY(); + + //anchor point + ctx.beginPath(); + ctx.arc(px + horizontalOffset, py + verticalOffset, this._DISPLAY_ANCHOR_RADIUS, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + } + + + //display selected anchor and its prev. and next points + if (this._selectedSubpath && subpath === this._selectedSubpath && this._selectedSubpath.getSelectedAnchorIndex()!== -1) { + ctx.lineWidth = 2; + ctx.strokeStyle = "black"; + var selAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + + //line from prev to anchor + ctx.beginPath(); + ctx.moveTo(selAnchor.getPrevX() + horizontalOffset, selAnchor.getPrevY() + verticalOffset); + ctx.lineTo(selAnchor.getPosX() + horizontalOffset, selAnchor.getPosY() + verticalOffset); + ctx.stroke(); + + //selected anchor prev + ctx.fillStyle = "#AAAAAA"; + ctx.beginPath(); + ctx.arc(selAnchor.getPrevX() + horizontalOffset, selAnchor.getPrevY() + verticalOffset, this._DISPLAY_SELECTED_ANCHOR_PREV_RADIUS, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + + //line from next to anchor + ctx.beginPath(); + ctx.moveTo(selAnchor.getNextX() + horizontalOffset, selAnchor.getNextY() + verticalOffset); + ctx.lineTo(selAnchor.getPosX() + horizontalOffset, selAnchor.getPosY() + verticalOffset); + ctx.stroke(); + + //selected anchor next + ctx.fillStyle = "#666666"; + ctx.beginPath(); + ctx.arc(selAnchor.getNextX() + horizontalOffset, selAnchor.getNextY() + verticalOffset, this._DISPLAY_SELECTED_ANCHOR_NEXT_RADIUS, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + + //selected anchor point + ctx.fillStyle = "#8ED6FF"; + ctx.beginPath(); + ctx.arc(selAnchor.getPosX() + horizontalOffset, selAnchor.getPosY() + verticalOffset, this._DISPLAY_SELECTED_ANCHOR_RADIUS, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + + //display the snap target if it isn't null + if (this._snapTarget) { + ctx.lineWidth = 2; + ctx.strokeStyle = "red"; + ctx.beginPath(); + ctx.arc(this._snapTarget.getPosX() + horizontalOffset, this._snapTarget.getPosY() + verticalOffset, this._DISPLAY_SELECTED_ANCHOR_RADIUS * 2, 0, 2 * Math.PI, false); + ctx.stroke(); + } + } //if this._selectedSubpath && subpath === this._selectedSubpath && this._selectedSubpath.getSelectedAnchorIndex()!== -1 + ctx.restore(); + } //value: function() { + }, //DrawSubpathAnchors { + + // DrawSubpathsSVG + // Draw all the subpaths using the SVG drawing capability (i.e. not WebGL) + // NOTE: testing only...in final version, we do not need this function + DrawSubpathsSVG: + { + value: function () { + if (!this._useWebGL){ + //display the selected subpath (which is not yet in the list of finished subpaths) + if (this._selectedSubpath) { + this.DrawSubpathSVG(this._selectedSubpath); + } + return; + } + + + + if (this._subpaths === null) { + return; + } + //clear the canvas before we draw anything else + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + + //display the subpaths currently in the list of finished subpaths + for (var i = 0; i < this._subpaths.length; i++) { + this.DrawSubpathSVG(this._subpaths[i]); + } //for (var i = 0; i < this._subpaths.length; i++) { + + //display the selected subpath (which is not yet in the list of finished subpaths) + if (this._selectedSubpath) { + this.DrawSubpathSVG(this._selectedSubpath); + } + + } // function() { + }, //DrawSubpathsSVG + + + + + + Configure: { + value: function (wasSelected) { + if (wasSelected) { + defaultEventManager.addEventListener("resetPenTool", this, false); + //stageManagerModule.stageManager._iframeContainer.addEventListener("scroll", this, false); + /*if (this._selectedSubpath){ + //todo this if block is probably unnecessary because the subpath rendering now happens independent of canvas position + this.TranslateSelectedSubpathPerPenCanvas(); + this.DrawSubpathAnchors(this._selectedSubpath); + }*/ + + this.application.ninja.elementMediator.deleteDelegate = this; + + if (this.application.ninja.selectedElements.length === 0){ + this._entryEditMode = this.ENTRY_SELECT_NONE; + } + else{ + for (var i=0;i=0){ + this._selectedSubpath.removeAnchor(this._selectedSubpath.getSelectedAnchorIndex()); + this._selectedSubpath.createSamples(); + //clear the canvas + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + this.DrawSubpathAnchors(this._selectedSubpath); + this.ShowSelectedSubpath(); + } + else { + this._selectedSubpath.clearAllAnchors(); //perhaps unnecessary + this._selectedSubpath = null; + //clear the canvas + this.application.ninja.stage.clearDrawingCanvas();//stageManagerModule.stageManager.clearDrawingCanvas(); + + //TODO is this the correct way to remove the pen canvas? Undo/Redo, etc.? + // see handleDeleteSelection in selected-controller.js + // Add the Undo/Redo -- taken from element-mediator.js + var els = []; + ElementController.removeElement(this._penCanvas); + els.push(this._penCanvas); + NJevent( "deleteSelection", els ); + this._penCanvas = null; + } + } + } + }, + handleResetPenTool: { + value: function (event) { + this.Reset(); + this.DrawHandles(); + } + }, + + handleToolOptionChange: { + value: function (event) { + if (event._event.type === ToolEvents.TOOL_OPTION_CHANGE) { + this.Reset(); + this.DrawHandles(); + } + } + }, + + Reset: { + value: function () { + this._isDrawing = false; + + this._selectedSubpath = null; + this.DrawHandles(); + this.Configure(true); + } + } + +}); \ No newline at end of file -- cgit v1.2.3