1 /*
  2  * © 2009 ROBO Design
  3  * http://www.robodesign.ro
  4  *
  5  * $Date: 2009-04-21 14:47:09 +0300 $
  6  */
  7 
  8 /**
  9  * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a>
 10  * @fileOverview The drawing tools for the paint application.
 11  */
 12 
 13 /**
 14  * Holds the implementation of each drawing tool.
 15  */
 16 var PaintTools = {};
 17 
 18 /**
 19  * @class The drawing pencil.
 20  *
 21  * @param {Painter} app Reference to the main paint application object.
 22  */
 23 PaintTools.pencil = function (app) {
 24   var _self   = this,
 25       context = app.buffer.context,
 26       update  = app.layerUpdate;
 27 
 28   /**
 29    * Tells if the user has started the drawing operation or not.
 30    *
 31    * @private
 32    * @type Boolean
 33    */
 34   var started = false;
 35 
 36   /**
 37    * Initialize the drawing operation.
 38    *
 39    * @param {Event} ev The DOM Event object.
 40    */
 41   this.mousedown = function (ev) {
 42     context.beginPath();
 43     context.moveTo(ev.x_, ev.y_);
 44     started = true;
 45   };
 46 
 47   /**
 48    * Perform the drawing operation, while the user moves the mouse.
 49    *
 50    * @param {Event} ev The DOM Event object.
 51    */
 52   this.mousemove = function (ev) {
 53     if (started) {
 54       context.lineTo(ev.x_, ev.y_);
 55       context.stroke();
 56     }
 57   };
 58 
 59   /**
 60    * End the drawing operation, once the user releases the mouse button.
 61    *
 62    * @param {Event} ev The DOM Event object.
 63    */
 64   this.mouseup = function (ev) {
 65     if (started) {
 66       _self.mousemove(ev);
 67       context.closePath();
 68       update();
 69       started = false;
 70     }
 71   };
 72 };
 73 
 74 /**
 75  * @class The rectangle tool.
 76  *
 77  * @param {Painter} app Reference to the main paint application object.
 78  */
 79 PaintTools.rect = function (app) {
 80   var _self   = this,
 81       context = app.buffer.context,
 82       canvas  = app.buffer.canvas,
 83       update  = app.layerUpdate;
 84 
 85   /**
 86    * Tells if the user has started the drawing operation or not.
 87    *
 88    * @private
 89    * @type Boolean
 90    */
 91   var started = false;
 92 
 93   /**
 94    * Holds the starting point on the <var>x</var> axis of the image, for the 
 95    * current drawing operation.
 96    *
 97    * @private
 98    * @type Number
 99    */
100   var x0 = 0;
101 
102   /**
103    * Holds the starting point on the <var>y</var> axis of the image, for the 
104    * current drawing operation.
105    *
106    * @private
107    * @type Number
108    */
109   var y0 = 0;
110 
111   /**
112    * Initialize the drawing operation, by storing the location of the pointer, 
113    * the start position.
114    *
115    * @param {Event} ev The DOM Event object.
116    */
117   this.mousedown = function (ev) {
118     started = true;
119     x0 = ev.x_;
120     y0 = ev.y_;
121   };
122 
123   /**
124    * Perform the drawing operation, while the user moves the mouse.
125    *
126    * <p>Hold down the <kbd>Shift</kbd> key to draw a square.
127    * <p>Press <kbd>Escape</kbd> to cancel the drawing operation.
128    *
129    * @param {Event} ev The DOM Event object.
130    */
131   this.mousemove = function (ev) {
132     if (!started) {
133       return;
134     }
135 
136     var x = Math.min(ev.x_,  x0),
137         y = Math.min(ev.y_,  y0),
138         w = Math.abs(ev.x_ - x0),
139         h = Math.abs(ev.y_ - y0);
140 
141     context.clearRect(0, 0, canvas.width, canvas.height);
142 
143     if (!w || !h) {
144       return;
145     }
146 
147     // Constrain the shape to a square when the user holds down the Shift key.
148     if (ev.shiftKey) {
149       if (w > h) {
150         if (y == ev.y_) {
151           y -= w-h;
152         }
153         h = w;
154       } else {
155         if (x == ev.x_) {
156           x -= h-w;
157         }
158         w = h;
159       }
160     }
161 
162     context.strokeRect(x, y, w, h);
163   };
164 
165   /**
166    * End the drawing operation, once the user releases the mouse button.
167    *
168    * @param {Event} ev The DOM Event object.
169    */
170   this.mouseup = function (ev) {
171     if (started) {
172       _self.mousemove(ev);
173       update();
174       started = false;
175     }
176   };
177 
178   /**
179    * Allows the user to press <kbd>Escape</kbd> to cancel the drawing operation.
180    *
181    * @param {Event} ev The DOM Event object.
182    *
183    * @returns {Boolean} True if the drawing operation was cancelled, or false if 
184    * not.
185    */
186   this.keydown = function (ev) {
187     if (!started || ev.kid_ != 'Escape') {
188       return false;
189     }
190 
191     context.clearRect(0, 0, canvas.width, canvas.height);
192     started = false;
193   };
194 };
195 
196 /**
197  * @class The line tool.
198  *
199  * @param {Painter} app Reference to the main paint application object.
200  */
201 PaintTools.line = function (app) {
202   var _self   = this,
203       context = app.buffer.context,
204       canvas  = app.buffer.canvas,
205       update  = app.layerUpdate;
206 
207   /**
208    * Tells if the user has started the drawing operation or not.
209    *
210    * @private
211    * @type Boolean
212    */
213   var started = false;
214 
215   /**
216    * Holds the starting point on the <var>x</var> axis of the image, for the 
217    * current drawing operation.
218    *
219    * @private
220    * @type Number
221    */
222   var x0 = 0;
223 
224   /**
225    * Holds the starting point on the <var>y</var> axis of the image, for the 
226    * current drawing operation.
227    *
228    * @private
229    * @type Number
230    */
231   var y0 = 0;
232 
233   /**
234    * Initialize the drawing operation, by storing the location of the pointer, 
235    * the start position.
236    *
237    * @param {Event} ev The DOM Event object.
238    */
239   this.mousedown = function (ev) {
240     started = true;
241     x0 = ev.x_;
242     y0 = ev.y_;
243   };
244 
245   /**
246    * Perform the drawing operation, while the user moves the mouse.
247    *
248    * <p>Hold down the <kbd>Shift</kbd> key to draw a straight 
249    * horizontal/vertical line.
250    * <p>Press <kbd>Escape</kbd> to cancel the drawing operation.
251    *
252    * @param {Event} ev The DOM Event object.
253    */
254   this.mousemove = function (ev) {
255     if (!started) {
256       return;
257     }
258 
259     context.clearRect(0, 0, canvas.width, canvas.height);
260 
261     context.beginPath();
262     context.moveTo(x0, y0);
263 
264     // Snap the line to be horizontal or vertical, when the Shift key is down.
265     if (ev.shiftKey) {
266       var diffx = Math.abs(ev.x_ - x0),
267           diffy = Math.abs(ev.y_ - y0);
268 
269       if (diffx > diffy) {
270         ev.y_ = y0;
271       } else {
272         ev.x_ = x0;
273       }
274     }
275 
276     context.lineTo(ev.x_, ev.y_);
277     context.stroke();
278     context.closePath();
279   };
280 
281   /**
282    * End the drawing operation, once the user releases the mouse button.
283    *
284    * @param {Event} ev The DOM Event object.
285    */
286   this.mouseup = function (ev) {
287     if (started) {
288       _self.mousemove(ev);
289       update();
290       started = false;
291     }
292   };
293 
294   /**
295    * Allows the user to press <kbd>Escape</kbd> to cancel the drawing operation.
296    *
297    * @param {Event} ev The DOM Event object.
298    *
299    * @returns {Boolean} True if the drawing operation was cancelled, or false if 
300    * not.
301    */
302   this.keydown = function (ev) {
303     if (!started || ev.kid_ != 'Escape') {
304       return false;
305     }
306 
307     context.clearRect(0, 0, canvas.width, canvas.height);
308     started = false;
309   };
310 };
311 
312 // vim:set spell spl=en fo=wan1croql tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix:
313