1 /*
  2  * Copyright (C) 2008, 2009 Mihai Şucan
  3  *
  4  * This file is part of PaintWeb.
  5  *
  6  * PaintWeb is free software: you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation, either version 3 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * PaintWeb is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with PaintWeb.  If not, see <http://www.gnu.org/licenses/>.
 18  *
 19  * $URL: http://code.google.com/p/paintweb $
 20  * $Date: 2009-07-29 20:34:06 +0300 $
 21  */
 22 
 23 /**
 24  * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a>
 25  * @fileOverview Holds the eraser tool implementation.
 26  */
 27 
 28 /**
 29  * @class The eraser tool.
 30  *
 31  * @param {PaintWeb} app Reference to the main paint application object.
 32  */
 33 pwlib.tools.eraser = function (app) {
 34   var _self         = this,
 35       bufferContext = app.buffer.context,
 36       clearInterval = app.win.clearInterval,
 37       config        = app.config,
 38       history       = app.history.pos,
 39       image         = app.image,
 40       layerContext  = app.layer.context,
 41       mouse         = app.mouse,
 42       setInterval   = app.win.setInterval;
 43 
 44   /**
 45    * The interval ID used for running the erasing operation every few 
 46    * milliseconds.
 47    *
 48    * @private
 49    * @see PaintWeb.config.toolDrawDelay
 50    */
 51   var timer = null;
 52 
 53   /**
 54    * Holds the points needed to be drawn. Each point is added by the 
 55    * <code>mousemove</code> event handler.
 56    *
 57    * @private
 58    * @type Array
 59    */
 60   var points = [];
 61 
 62   /**
 63    * Holds the starting point on the <var>x</var> axis of the image, for the 
 64    * current drawing operation.
 65    *
 66    * @private
 67    * @type Number
 68    */
 69   var x0 = 0;
 70 
 71   /**
 72    * Holds the starting point on the <var>y</var> axis of the image, for the 
 73    * current drawing operation.
 74    *
 75    * @private
 76    * @type Number
 77    */
 78   var y0 = 0;
 79 
 80   var globalOp_  = null,
 81       lineWidth_ = null;
 82 
 83   /**
 84    * The tool deactivation event handler. This function clears timers, clears 
 85    * the canvas and allows shadows to be rendered again.
 86    */
 87   this.deactivate = function () {
 88     if (timer) {
 89       clearInterval(timer);
 90       timer = null;
 91     }
 92 
 93     if (mouse.buttonDown) {
 94       if (globalOp_) {
 95         layerContext.globalCompositeOperation = globalOp_;
 96       }
 97       if (lineWidth_) {
 98         layerContext.lineWidth = lineWidth_;
 99       }
100 
101       app.historyGoto(history.pos);
102     }
103 
104     points = [];
105 
106     // Allow Canvas shadows.
107     app.shadowAllow();
108   };
109 
110   /**
111    * The tool activation event handler. This is run after the tool construction 
112    * and after the deactivation of the previous tool. This function simply 
113    * disallows the rendering of shadows.
114    */
115   this.activate = function () {
116     // Do not allow Canvas shadows.
117     app.shadowDisallow();
118   };
119 
120   /**
121    * Initialize the drawing operation.
122    */
123   this.mousedown = function () {
124     globalOp_  = layerContext.globalCompositeOperation;
125     lineWidth_ = layerContext.lineWidth;
126 
127     layerContext.globalCompositeOperation = 'destination-out';
128     layerContext.lineWidth = bufferContext.lineWidth;
129 
130     x0 = mouse.x;
131     y0 = mouse.y;
132 
133     points = [];
134     if (!timer) {
135       timer = setInterval(_self.draw, config.toolDrawDelay);
136     }
137 
138     return true;
139   };
140 
141   /**
142    * Save the mouse coordinates in the array.
143    */
144   this.mousemove = function () {
145     if (mouse.buttonDown) {
146       points.push(mouse.x, mouse.y);
147     }
148   };
149 
150   /**
151    * Draw the points in the stack. This function is called every few 
152    * milliseconds.
153    *
154    * @see PaintWeb.config.toolDrawDelay
155    */
156   this.draw = function () {
157     var i = 0, n = points.length;
158     if (!n) {
159       return;
160     }
161 
162     layerContext.beginPath();
163     layerContext.moveTo(x0, y0);
164 
165     while (i < n) {
166       x0 = points[i++];
167       y0 = points[i++];
168       layerContext.lineTo(x0, y0);
169     }
170 
171     layerContext.stroke();
172     layerContext.closePath();
173 
174     points = [];
175   };
176 
177   /**
178    * End the drawing operation, once the user releases the mouse button.
179    */
180   this.mouseup = function () {
181     if (mouse.x == x0 && mouse.y == y0) {
182       points.push(x0+1, y0+1);
183     }
184 
185     if (timer) {
186       clearInterval(timer);
187       timer = null;
188     }
189     _self.draw();
190 
191     layerContext.globalCompositeOperation = globalOp_;
192     layerContext.lineWidth = lineWidth_;
193 
194     app.historyAdd();
195 
196     return true;
197   };
198 
199   /**
200    * Allows the user to press <kbd>Escape</kbd> to cancel the drawing operation.
201    *
202    * @param {Event} ev The DOM Event object.
203    *
204    * @returns {Boolean} True if the drawing operation was cancelled, or false if 
205    * not.
206    */
207   this.keydown = function (ev) {
208     if (!mouse.buttonDown || ev.kid_ != 'Escape') {
209       return false;
210     }
211 
212     if (timer) {
213       clearInterval(timer);
214       timer = null;
215     }
216 
217     layerContext.globalCompositeOperation = globalOp_;
218     layerContext.lineWidth = lineWidth_;
219 
220     mouse.buttonDown = false;
221     points = [];
222 
223     app.historyGoto(history.pos);
224 
225     return true;
226   };
227 };
228 
229 // vim:set spell spl=en fo=wan1croqlt tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix:
230 
231 
232