diff options
Diffstat (limited to 'js/tools/PenTool.js')
-rwxr-xr-x | js/tools/PenTool.js | 1251 |
1 files changed, 774 insertions, 477 deletions
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js index 7fc8dd95..4258593e 100755 --- a/js/tools/PenTool.js +++ b/js/tools/PenTool.js | |||
@@ -14,12 +14,10 @@ var ElementMediator = require("js/mediators/element-mediator").ElementMediator; | |||
14 | var TagTool = require("js/tools/TagTool").TagTool; | 14 | var TagTool = require("js/tools/TagTool").TagTool; |
15 | var ElementController = require("js/controllers/elements/element-controller").ElementController; | 15 | var ElementController = require("js/controllers/elements/element-controller").ElementController; |
16 | var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager; | 16 | var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager; |
17 | 17 | var ViewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; | |
18 | var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint; | 18 | var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint; |
19 | var SubPath = require("js/lib/geom/sub-path").SubPath; | 19 | var SubPath = require("js/lib/geom/sub-path").SubPath; |
20 | 20 | ||
21 | //todo remove this global var | ||
22 | var g_DoPenToolMouseMove = true; | ||
23 | 21 | ||
24 | exports.PenTool = Montage.create(ShapeTool, { | 22 | exports.PenTool = Montage.create(ShapeTool, { |
25 | 23 | ||
@@ -35,14 +33,11 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
35 | _parentNode: { enumerable: false, value: null, writable: true }, | 33 | _parentNode: { enumerable: false, value: null, writable: true }, |
36 | _toolsPropertiesContainer: { enumerable: false, value: null, writable: true }, | 34 | _toolsPropertiesContainer: { enumerable: false, value: null, writable: true }, |
37 | 35 | ||
38 | // Need to keep track of current mouse position for KEY modifiers event which do not have mouse coordinates | 36 | //set this to true if you want to keep making subpaths after closing current subpath (debugging only) |
39 | _currentX: { value: 0, writable: true }, | 37 | _makeMultipleSubpaths: { value: true, writable: true }, |
40 | _currentY: { value: 0, writable: true }, | ||
41 | |||
42 | //the subpaths are what is displayed on the screen currently, with _selectedSubpath being the active one currently being edited | ||
43 | _selectedSubpath: { value: null, writable: true }, | ||
44 | _makeMultipleSubpaths: { value: true, writable: true }, //set this to true if you want to keep making subpaths after closing current subpath | ||
45 | 38 | ||
39 | //set this to false if you don't want the mouse move handler being called when the mouse is not down (debugging only) | ||
40 | _trackMouseMoveWhenUp: {value: true, writable: false}, | ||
46 | 41 | ||
47 | //whether the user has held down the Alt key | 42 | //whether the user has held down the Alt key |
48 | _isAltDown: { value: false, writable: true }, | 43 | _isAltDown: { value: false, writable: true }, |
@@ -50,29 +45,37 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
50 | //whether the user has held down the Esc key | 45 | //whether the user has held down the Esc key |
51 | _isEscapeDown: {value: false, writable: true }, | 46 | _isEscapeDown: {value: false, writable: true }, |
52 | 47 | ||
53 | //whether we have just started a new path (set true in mousedown, and set false in mouse up | 48 | //whether we have just started a new path (may set true in mousedown, and always set false in mouse up |
49 | //todo this seems to be unnecessary | ||
54 | _isNewPath: {value: false, writable: true}, | 50 | _isNewPath: {value: false, writable: true}, |
55 | 51 | ||
56 | //whether we have clicked one of the endpoints after entering the pen tool in ENTRY_SELECT_PATH edit mode | 52 | //whether we have clicked one of the endpoints after entering the pen tool in ENTRY_SELECT_PATH edit mode |
57 | _isPickedEndPointInSelectPathMode: {value: false, writable: true}, | 53 | _isPickedEndPointInSelectPathMode: {value: false, writable: true}, |
58 | 54 | ||
59 | //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 | 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 |
60 | _snapTarget: { value: null, writable: true }, | 56 | _snapTargetIndex: { value: -1, writable: true }, |
57 | |||
58 | //index of the anchor point that the user has hovered over | ||
59 | _hoveredAnchorIndex: {value: -1, writable: true}, | ||
61 | 60 | ||
62 | //whether or not we're using webgl for drawing | 61 | //whether or not we're using webgl for drawing (set to false until we have webgl-ready stroke and fill regions) |
63 | _useWebGL: {value: false, writable: false }, | 62 | _useWebGL: {value: false, writable: false }, |
64 | 63 | ||
65 | //the canvas created by the pen tool...this is grown or shrunk with the path (if the canvas was not already provided) | 64 | //the _selectedSubpath is the active subpath currently being edited |
66 | _penCanvas: { value: null, writable: true }, | 65 | _selectedSubpath: { value: null, writable: true }, |
67 | 66 | ||
68 | //the plane matrix for the first click...so the entire path is on the same plane | 67 | //the canvas for the selected subpath...this is grown or shrunk by the pen tool with the subpath (if the canvas was not already provided) |
69 | _penPlaneMat: { value: null, writable: true }, | 68 | _selectedSubpathCanvas: { value: null, writable: true }, |
70 | 69 | ||
71 | //index of the anchor point that the user has hovered over | 70 | //the plane matrix for the first click...so the entire path is on the same plane |
72 | _hoveredAnchorIndex: {value: -1, writable: true}, | 71 | // todo this might be unnecessary as we can get this from element mediator (but that may be slow) |
72 | _selectedSubpathPlaneMat: { value: null, writable: true }, | ||
73 | 73 | ||
74 | //constants used for picking points --- NOTE: these should be user-settable parameters | 74 | //the center of the subpath center in stageworld space |
75 | _PICK_POINT_RADIUS: { value: 10, writable: false }, | 75 | _selectedSubpathCanvasCenter: {value: null, writable: true}, |
76 | |||
77 | //constants used for picking points --- todo: these should be user-settable parameters | ||
78 | _PICK_POINT_RADIUS: { value: 4, writable: false }, | ||
76 | _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false }, | 79 | _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false }, |
77 | _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false }, | 80 | _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false }, |
78 | _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 2, writable: false }, | 81 | _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 2, writable: false }, |
@@ -86,34 +89,49 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
86 | EDIT_PREV_NEXT: { value: 8, writable: false }, | 89 | EDIT_PREV_NEXT: { value: 8, writable: false }, |
87 | _editMode: { value: this.EDIT_NONE, writable: true }, | 90 | _editMode: { value: this.EDIT_NONE, writable: true }, |
88 | 91 | ||
89 | //constants used for selection modes on entry to pen tool (mutually exclusive) | 92 | //constants used for selection modes on entry to pen tool (mutually exclusive i.e. cannot be OR-ed) |
90 | ENTRY_SELECT_NONE: { value: 0, writable: false}, | 93 | ENTRY_SELECT_NONE: { value: 0, writable: false}, |
91 | ENTRY_SELECT_CANVAS: { value: 1, writable: false}, | 94 | ENTRY_SELECT_CANVAS: { value: 1, writable: false}, |
92 | ENTRY_SELECT_PATH: { value: 2, writable: false}, | 95 | ENTRY_SELECT_PATH: { value: 2, writable: false}, |
93 | _entryEditMode: {value: this.ENTRY_SELECT_NONE, writable: true}, | 96 | _entryEditMode: {value: this.ENTRY_SELECT_NONE, writable: true}, |
94 | |||
95 | 97 | ||
98 | //constants used for limiting size of the subpath canvas | ||
99 | _MAX_CANVAS_DIMENSION: {value: 3000, writable: false}, | ||
96 | 100 | ||
97 | _getUnsnappedPosition: { | 101 | /* |
98 | value: function(x,y){ | 102 | // get the stage world position corresponding to the (x,y) mouse event position by querying the snap manager |
103 | // but temporarily turning off all snapping | ||
104 | _getMouseEventPosition : { | ||
105 | value: function(x,y, getStageWorld, doSnap){ | ||
99 | var elemSnap = snapManager.elementSnapEnabled(); | 106 | var elemSnap = snapManager.elementSnapEnabled(); |
100 | var gridSnap = snapManager.gridSnapEnabled(); | 107 | var gridSnap = snapManager.gridSnapEnabled(); |
101 | var alignSnap = snapManager.snapAlignEnabled(); | 108 | var alignSnap = snapManager.snapAlignEnabled(); |
102 | 109 | ||
103 | snapManager.enableElementSnap(false); | 110 | if (!doSnap){ |
104 | snapManager.enableGridSnap(false); | 111 | snapManager.enableElementSnap(false); |
105 | snapManager.enableSnapAlign(false); | 112 | snapManager.enableGridSnap(false); |
113 | snapManager.enableSnapAlign(false); | ||
114 | } | ||
106 | 115 | ||
107 | var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); | 116 | var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); |
108 | var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); | 117 | var pos; |
118 | if (getStageWorld){ | ||
119 | pos = (snapManager.snap(point.x, point.y, false)).calculateStageWorldPoint(); | ||
120 | } else { | ||
121 | pos = (snapManager.snap(point.x, point.y, false)).getScreenPoint(); | ||
122 | } | ||
123 | var dragPlane = snapManager.getDragPlane(); | ||
109 | 124 | ||
110 | snapManager.enableElementSnap(elemSnap); | 125 | if (!doSnap){ |
111 | snapManager.enableGridSnap(gridSnap); | 126 | snapManager.enableElementSnap(elemSnap); |
112 | snapManager.enableSnapAlign(alignSnap); | 127 | snapManager.enableGridSnap(gridSnap); |
128 | snapManager.enableSnapAlign(alignSnap); | ||
129 | } | ||
113 | 130 | ||
114 | return unsnappedpos; | 131 | return [pos, dragPlane]; |
115 | } | 132 | } |
116 | }, | 133 | }, |
134 | */ | ||
117 | 135 | ||
118 | ShowToolProperties: { | 136 | ShowToolProperties: { |
119 | value: function () { | 137 | value: function () { |
@@ -126,6 +144,61 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
126 | 144 | ||
127 | }, | 145 | }, |
128 | 146 | ||
147 | //use the snap manager to build a hit record corresponding to the screen X, Y position | ||
148 | // will use the plane of the selected path as the working plane if available, else use stage | ||
149 | getHitRecord:{ | ||
150 | value: function(x,y, doSnap){ | ||
151 | var elemSnap = snapManager.elementSnapEnabled(); | ||
152 | var gridSnap = snapManager.gridSnapEnabled(); | ||
153 | var alignSnap = snapManager.snapAlignEnabled(); | ||
154 | |||
155 | if (!doSnap){ | ||
156 | snapManager.enableElementSnap(false); | ||
157 | snapManager.enableGridSnap(false); | ||
158 | snapManager.enableSnapAlign(false); | ||
159 | } | ||
160 | |||
161 | if (this._selectedSubpathCanvas){ | ||
162 | var drawingCanvas = this._selectedSubpathCanvas; | ||
163 | var contentPlane = ViewUtils.getUnprojectedElementPlane(drawingCanvas); | ||
164 | snapManager.pushWorkingPlane(contentPlane); | ||
165 | |||
166 | } | ||
167 | var tmpPoint = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); | ||
168 | var hitRec = snapManager.snap(tmpPoint.x, tmpPoint.y, false); | ||
169 | if (this._selectedSubpathCanvas){ | ||
170 | snapManager.popWorkingPlane(); | ||
171 | } | ||
172 | |||
173 | if (!doSnap){ | ||
174 | snapManager.enableElementSnap(elemSnap); | ||
175 | snapManager.enableGridSnap(gridSnap); | ||
176 | snapManager.enableSnapAlign(alignSnap); | ||
177 | } | ||
178 | return hitRec; | ||
179 | } | ||
180 | }, | ||
181 | |||
182 | // ********************************************************************************************************** | ||
183 | // Mouse down handler | ||
184 | // IF the selected subpath is null, it means we're going to start a new subpath | ||
185 | // Create a new subpath | ||
186 | // Compute the mouse position in stage world space (lying on stage or selected subpath canvas) | ||
187 | // IF selected subpath does not have a canvas yet, | ||
188 | // IF this is the first anchor point of the selected subpath | ||
189 | // Store the plane mat and drag plane of this hit record (will be used for creating a canvas) | ||
190 | // Add the mouse position (in stage world space) as an anchor point | ||
191 | // ELSE (we may add to the selected subpath) | ||
192 | // Compute the mouse position in local (selected subpath canvas) space | ||
193 | // IF we hit the path: | ||
194 | // Either select an anchor or insert an anchor and select it | ||
195 | // (also set proper flags when select endpoint of open path in ENTRY_SELECT_PATH mode) | ||
196 | // ELSE | ||
197 | // If selected subpath is closed (and we're not in ENTRY_SELECT_PATH mode) | ||
198 | // Create a new subpath | ||
199 | // Add the mouse position (in selected subpath's local space) as an anchor point (call global to local) | ||
200 | // Draw the selected subpath anchors and the selected subpath itself in the stage's context | ||
201 | // ********************************************************************************************************** | ||
129 | HandleLeftButtonDown: | 202 | HandleLeftButtonDown: |
130 | { | 203 | { |
131 | value: function (event) { | 204 | value: function (event) { |
@@ -134,69 +207,151 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
134 | //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2) | 207 | //NOTE: this will work on Webkit only...IE has different codes (left: 1, middle: 4, right: 2) |
135 | return; | 208 | return; |
136 | } | 209 | } |