aboutsummaryrefslogtreecommitdiff
path: root/js/tools/PenTool.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/tools/PenTool.js')
-rw-r--r--js/tools/PenTool.js1245
1 files changed, 1245 insertions, 0 deletions
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 @@
1/* <copyright>
2This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
3No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
4(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
5</copyright> */
6
7var ShapeTool = require("js/tools/ShapeTool").ShapeTool;
8var DrawingToolBase = require("js/tools/drawing-tool-base").DrawingToolBase;
9var defaultEventManager = require("montage/core/event/event-manager").defaultEventManager;
10var Montage = require("montage/core/core").Montage;
11var NJUtils = require("js/lib/NJUtils").NJUtils;
12var ElementMediator = require("js/mediators/element-mediator").ElementMediator;
13var TagTool = require("js/tools/TagTool").TagTool;
14var ElementController = require("js/controllers/elements/element-controller").ElementController;
15
16exports.PenTool = Montage.create(ShapeTool, {
17
18 _toolID: { value: "penTool" },
19 _imageID: { value: "penToolImg" },
20 _toolImageClass: { value: "penToolUp" },
21 _selectedToolImageClass: { value: "penToolDown" },
22 _toolTipText: { value: "Pen Tool" },
23 _penView: { value: null, writable: true },
24
25 _selectedToolClass: { value: "penToolSpecificProperties" },
26 _penToolProperties: { enumerable: false, value: null, writable: true },
27 _parentNode: { enumerable: false, value: null, writable: true },
28 _toolsPropertiesContainer: { enumerable: false, value: null, writable: true },
29
30 // Need to keep track of current mouse position for KEY modifiers event which do not have mouse coordinates
31 _currentX: { value: 0, writable: true },
32 _currentY: { value: 0, writable: true },
33
34 //the subpaths are what is displayed on the screen currently, with _selectedSubpath being the active one currently being edited
35 _subpaths: { value: [], writable: true },
36 _selectedSubpath: { value: null, writable: true },
37 _makeMultipleSubpaths: { value: true, writable: true }, //set this to true if you want to keep making subpaths after closing current subpath
38
39
40 //whether or not to display the guides for debugging
41 _showGuides: { value: true, writable: true },
42
43 //whether the user has held down the Alt key
44 _isAltDown: { value: false, writable: true },
45
46 //whether the user has held down the Esc key
47 _isEscapeDown: {value: false, writable: true },
48
49 //whether we have just started a new path (set true in mousedown, and set false in mouse up
50 _isNewPath: {value: false, writable: true},
51
52 //whether we have clicked one of the endpoints after entering the pen tool in ENTRY_SELECT_PATH edit mode
53 _isPickedEndPointInSelectPathMode: {value: false, writable: true},
54
55 //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
56 _snapTarget: { value: null, writable: true },
57
58 //whether or not we're using webgl for drawing
59 _useWebGL: {value: false, writable: false },
60
61 //the canvas created by the pen tool...this is grown or shrunk with the path (if the canvas was not already provided)
62 _penCanvas: { value: null, writable: true },
63
64 //the plane matrix for the first click...so the entire path is on the same plane
65 _penPlaneMat: { value: null, writable: true },
66
67 //constants used for picking points --- NOTE: these should be user-settable parameters
68 _PICK_POINT_RADIUS: { value: 10, writable: false },
69 _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false },
70 _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false },
71 _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 5, writable: false },
72 _DISPLAY_SELECTED_ANCHOR_NEXT_RADIUS: { value: 5, writable: false },
73
74 //constants used for editing modes (can be OR-ed)
75 EDIT_NONE: { value: 0, writable: false },
76 EDIT_ANCHOR: { value: 1, writable: false },
77 EDIT_PREV: { value: 2, writable: false },
78 EDIT_NEXT: { value: 4, writable: false },
79 EDIT_PREV_NEXT: { value: 8, writable: false },
80 _editMode: { value: this.EDIT_NONE, writable: true },
81
82 //constants used for selection modes on entry to pen tool (mutually exclusive)
83 ENTRY_SELECT_NONE: { value: 0, writable: false},
84 ENTRY_SELECT_CANVAS: { value: 1, writable: false},
85 ENTRY_SELECT_PATH: { value: 2, writable: false},
86 _entryEditMode: {value: this.ENTRY_SELECT_NONE, writable: true},
87
88 // ******** Logic for selection *******
89 // (update if you change functionality!)
90 // NOTE: this is out of date...needs to be updated
91 //
92 // Start by setting edit mode to EDIT_NONE
93 //
94 // DOUBLE_CLICK (Left mouse button only):
95 //
96 //
97 // SINGLE_CLICK (Left mouse button only):
98 // If LeftClick selects an anchor point
99 // append EDIT_ANCHOR mode
100 // If LeftClick selects a previous point of selected anchor
101 // append EDIT_PREV mode
102 // If LeftClick selects a next point of selected anchor
103 // append EDIT_NEXT mode
104 //
105
106 // ********* Logic for editing *******
107 // (update if you change functionality!)
108 // NOTE: this is out of date...needs to be updated
109 //
110 // Start by computing mouse disp
111 //
112 // If EDIT_PREV_NEXT mode
113 // add disp to next and mirror it to prev
114 // ELSE
115 // If EDIT_ANCHOR (or _PREV, _NEXT)
116 // map displacement to anchor (similarly to prev and next)
117 //
118 //
119
120
121 ShowToolProperties: {
122 value: function () {
123 this._penView = PenView.create();
124 this._penView.element = document.getElementById('topPanelContainer').children[0];
125 this._penView.needsDraw = true;
126
127 this._penView.addEventListener(ToolEvents.TOOL_OPTION_CHANGE, this, false);
128 }
129
130 },
131
132 HandleLeftButtonDown:
133 {
134 value: function (event) {
135 //ignore any right or middle clicks
136 if (event.button !== 0) {
137 //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2)
138 return;
139 }
140 //BEGIN ShapeTool code
141 if (this._canDraw) {
142 this._isDrawing = true;
143 }
144
145 //this._targetedCanvas = stageManagerModule.stageManager.GetObjectFromPoint(event.layerX, event.layerY, this._canOperateOnStage);
146
147 this.startDraw(event);
148 //END ShapeTool code
149
150 //assume we are not starting a new path as we will set this to true if we create a new GLSubpath()
151 this._isNewPath = false;
152
153 //add an anchor point by computing position of mouse down
154 var mouseDownPos = this.getMouseDownPos();
155 if (mouseDownPos) {
156 //if we had closed the selected subpath previously, or if we have not yet started anything, create a subpath
157 if (this._selectedSubpath === null) {
158 this._selectedSubpath = new GLSubpath();
159 this._isNewPath = true;
160 if (this._entryEditMode === this.ENTRY_SELECT_PATH){
161 //this should not happen, as ENTRY_SELECT_PATH implies there was a selected subpath
162 this._entryEditMode = this.ENTRY_SELECT_NONE;
163 }
164 } else if (this._selectedSubpath.getIsClosed() && this._entryEditMode !== this.ENTRY_SELECT_PATH) {
165 //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
166 if (this._makeMultipleSubpaths) {
167 this._subpaths.push(this._selectedSubpath);
168 this._penCanvas = null;
169 this._penPlaneMat = null;
170 this._snapTarget = null;
171 this._selectedSubpath = new GLSubpath();
172 this._isNewPath = true;
173 }
174 }
175
176 var prevSelectedAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex();
177 // ************* Add/Select Anchor Point *************
178 //check if the clicked location is close to an anchor point...if so, make that anchor the selected point and do nothing else
179 // 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
180 var selParam = this._selectedSubpath.pickPath(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2], this._PICK_POINT_RADIUS);
181 var whichPoint = this._selectedSubpath.getSelectedMode();
182 if (whichPoint & this._selectedSubpath.SEL_ANCHOR) {
183 //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
184 if (this._entryEditMode === this.ENTRY_SELECT_PATH && this._isPickedEndPointInSelectPathMode === false){
185 var selAnchorIndex = this._selectedSubpath.getSelectedAnchorIndex();
186 if (selAnchorIndex===0 || selAnchorIndex===this._selectedSubpath.getNumAnchors()-1){
187 //we have picked the endpoint of this path...reverse the path if necessary
188 if (selAnchorIndex ===0){
189 //reverse this path
190 }
191 this._isPickedEndPointInSelectPathMode = true;
192 }
193 }
194 this._editMode = this.EDIT_ANCHOR;
195 //if we have selected the first anchor point, and previously had selected the last anchor point, close the path
196 var numAnchors = this._selectedSubpath.getNumAnchors();
197 if (numAnchors>1 && !this._selectedSubpath.getIsClosed() && this._selectedSubpath.getSelectedAnchorIndex()===0 && prevSelectedAnchorIndex === numAnchors-1){
198 //setting the selection mode to NONE will effectively add a new anchor point at the click location and also give us snapping
199 whichPoint = this._selectedSubpath.SEL_NONE;
200 //set the snap target in case the mouse move handler doesn't get called
201 this._snapTarget = this._selectedSubpath.getAnchor(0);
202 }
203 }
204 //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
205 // 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
206 else if (this._selectedSubpath.getSelectedAnchorIndex() !== -1) {
207 if (whichPoint & this._selectedSubpath.SEL_PREV){
208 this._editMode = this.EDIT_PREV;
209 }
210 else if (whichPoint & this._selectedSubpath.SEL_NEXT){
211 this._editMode = this.EDIT_NEXT;
212 }
213 else if (whichPoint & this._selectedSubpath.SEL_PATH) {
214 //the click point is close enough to insert point in bezier segment after selected anchor at selParam
215 if (selParam > 0 && selParam < 1) {
216 this._selectedSubpath.insertAnchorAtParameter(this._selectedSubpath.getSelectedAnchorIndex(), selParam);
217 //set the mode so that dragging will update anchor point positions
218 //this._editMode = this.EDIT_ANCHOR;
219 }
220 }
221 }
222 if (whichPoint === this._selectedSubpath.SEL_NONE) {
223 if (this._entryEditMode !== this.ENTRY_SELECT_PATH) {
224 //add an anchor point to end of the subpath, and make it the selected anchor point
225 if (!this._selectedSubpath.getIsClosed() || this._makeMultipleSubpaths) {
226 this._selectedSubpath.addAnchor(new GLAnchorPoint());
227 var newAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex());
228 newAnchor.setPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]);
229 newAnchor.setPrevPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]);
230 newAnchor.setNextPos(mouseDownPos[0], mouseDownPos[1], mouseDownPos[2]);
231
232