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-06-15 20:27:08 +0300 $
 21  */
 22 
 23 /**
 24  * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a>
 25  * @fileOverview Holds the hand tool implementation.
 26  */
 27 
 28 /**
 29  * @class The hand tool. This tool allows the user to drag the image canvas 
 30  * inside the viewport.
 31  *
 32  * @param {PaintWeb} app Reference to the main paint application object.
 33  */
 34 pwlib.tools.hand = function (app) {
 35   var _self         = this,
 36       bufferCanvas  = app.buffer.canvas,
 37       bufferStyle   = bufferCanvas.style,
 38       config        = app.config;
 39       clearInterval = app.win.clearInterval,
 40       image         = app.image,
 41       MathRound     = Math.round,
 42       mouse         = app.mouse,
 43       viewport      = app.gui.elems.viewport,
 44       vheight       = 0,
 45       vwidth        = 0,
 46       setInterval   = app.win.setInterval;
 47 
 48   /**
 49    * The interval ID used for invoking the viewport drag operation every few 
 50    * milliseconds.
 51    *
 52    * @private
 53    * @see PaintWeb.config.toolDrawDelay
 54    */
 55   var timer = null;
 56 
 57   /**
 58    * Tells if the viewport needs to be scrolled.
 59    *
 60    * @private
 61    * @type Boolean
 62    * @default false
 63    */
 64   var needsScroll = false;
 65 
 66   /**
 67    * Holds the previous tool ID.
 68    *
 69    * @private
 70    * @type String
 71    */
 72   this.prevTool = null;
 73 
 74   var x0 = 0, y0 = 0,
 75       x1 = 0, y1 = 0,
 76       l0 = 0, t0 = 0;
 77 
 78   /**
 79    * Tool preactivation event handler.
 80    *
 81    * @returns {Boolean} True if the tool can become active, or false if not.
 82    */
 83   this.preActivate = function () {
 84     if (!viewport) {
 85       return false;
 86     }
 87 
 88     _self.prevTool = app.tool._id;
 89 
 90     // Check if the image canvas can be scrolled within the viewport.
 91 
 92     var cs      = app.win.getComputedStyle(viewport, null),
 93         bwidth  = parseInt(bufferStyle.width),
 94         bheight = parseInt(bufferStyle.height);
 95 
 96     vwidth  = parseInt(cs.width),
 97     vheight = parseInt(cs.height);
 98 
 99     if (vheight < bheight || vwidth < bwidth) {
100       return true;
101     } else {
102       return false;
103     }
104   };
105 
106   /**
107    * Tool activation event handler.
108    */
109   this.activate = function () {
110     bufferStyle.cursor = 'move';
111     app.shadowDisallow();
112   };
113 
114   /**
115    * Tool deactivation event handler.
116    */
117   this.deactivate = function (ev) {
118     if (timer) {
119       clearInterval(timer);
120       timer = null;
121       app.doc.removeEventListener('mousemove', ev_mousemove, false);
122       app.doc.removeEventListener('mouseup',   ev_mouseup, false);
123     }
124 
125     bufferStyle.cursor = '';
126     app.shadowAllow();
127   };
128 
129   /**
130    * Initialize the canvas drag.
131    *
132    * @param {Event} ev The DOM event object.
133    */
134   this.mousedown = function (ev) {
135     x0 = ev.clientX;
136     y0 = ev.clientY;
137     l0 = viewport.scrollLeft;
138     t0 = viewport.scrollTop;
139 
140     needsScroll = false;
141 
142     app.doc.addEventListener('mousemove', ev_mousemove, false);
143     app.doc.addEventListener('mouseup',   ev_mouseup, false);
144 
145     if (!timer) {
146       timer = setInterval(viewportScroll, config.toolDrawDelay);
147     }
148 
149     return true;
150   };
151 
152   /**
153    * The <code>mousemove</code> event handler. This simply stores the current 
154    * mouse location.
155    *
156    * @param {Event} ev The DOM Event object.
157    */
158   function ev_mousemove (ev) {
159     x1 = ev.clientX;
160     y1 = ev.clientY;
161     needsScroll = true;
162   };
163 
164   /**
165    * Perform the canvas drag operation. This function is called every few 
166    * milliseconds.
167    *
168    * <p>Press <kbd>Escape</kbd> to stop dragging and to get back to the previous 
169    * tool.
170    */
171   function viewportScroll () {
172     if (needsScroll) {
173       viewport.scrollTop  = t0 - y1 + y0;
174       viewport.scrollLeft = l0 - x1 + x0;
175       needsScroll = false;
176     }
177   };
178 
179   /**
180    * The <code>mouseup</code> event handler.
181    */
182   function ev_mouseup (ev) {
183     if (timer) {
184       clearInterval(timer);
185       timer = null;
186     }
187 
188     ev_mousemove(ev);
189     viewportScroll();
190 
191     app.doc.removeEventListener('mousemove', ev_mousemove, false);
192     app.doc.removeEventListener('mouseup',   ev_mouseup, false);
193 
194     mouse.buttonDown = false;
195   };
196 
197   /**
198    * Allows the user to press <kbd>Escape</kbd> to stop dragging the canvas, and 
199    * to return to the previous tool.
200    *
201    * @param {Event} ev The DOM Event object.
202    *
203    * @returns {Boolean} True if the key was recognized, or false if not.
204    */
205   this.keydown = function (ev) {
206     if (!_self.prevTool || ev.kid_ != 'Escape') {
207       return false;
208     }
209 
210     app.toolActivate(_self.prevTool, ev);
211     return true;
212   };
213 };
214 
215 // vim:set spell spl=en fo=wan1croqlt tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix:
216 
217