1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * @constant
 29  * @type Number
 30  */
 31 cc.MOUSE_DOWN = 1 << 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.MOUSE_MOVED = 1 << 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.MOUSE_DRAGGED = 1 << 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.MOUSE_UP = 1 << 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.RIGHT_MOUSE_DOWN = 1 << 4;
 56 
 57 /**
 58  * @constant
 59  * @type Number
 60  */
 61 cc.RIGHT_MOUSE_DRAGGED = 1 << 5;
 62 
 63 /**
 64  * @constant
 65  * @type Number
 66  */
 67 cc.RIGHT_MOUSE_UP = 1 << 6;
 68 
 69 /**
 70  * @constant
 71  * @type Number
 72  */
 73 cc.OTHER_MOUSE_DOWN = 1 << 7;
 74 
 75 /**
 76  * @constant
 77  * @type Number
 78  */
 79 cc.OTHER_MOUSE_DRAGGED = 1 << 8;
 80 
 81 /**
 82  * @constant
 83  * @type Number
 84  */
 85 cc.OTHER_MOUSE_UP = 1 << 9;
 86 
 87 /**
 88  * @constant
 89  * @type Number
 90  */
 91 cc.SCROLL_WHEEL = 1 << 10;
 92 
 93 /**
 94  * @constant
 95  * @type Number
 96  */
 97 cc.MOUSE_ENTERED = 1 << 11;
 98 
 99 /**
100  * @constant
101  * @type Number
102  */
103 cc.MOUSE_EXITED = 1 << 12;
104 
105 /**
106  * @constant
107  * @type Number
108  */
109 cc.MOUSE_LEFTBUTTON = 0;
110 
111 /**
112  * @constant
113  * @type Number
114  */
115 cc.MOUSE_MIDDLEBUTTON = 1;
116 
117 /**
118  * @constant
119  * @type Number
120  */
121 cc.MOUSE_RIGHTBUTTON = 2;
122 
123 /**
124  *     CCMouseEventDelegate protocol.
125  * Implement it in your node to receive any of mouse events
126  */
127 cc.MouseEventDelegate = cc.Class.extend({
128     /**
129      * <p>called when the "mouseDown" event is received. <br/>
130      * Return YES to avoid propagating the event to other delegates.  </p>
131      * @param {cc.Mouse} event
132      * @return {Boolean}
133      */
134     onMouseDown:function (event) {
135         return false;
136     },
137 
138     /**
139      * <p>called when the "mouseDragged" event is received.         <br/>
140      * Return YES to avoid propagating the event to other delegates.</p>
141      * @param {cc.Mouse} event
142      * @return {Boolean}
143      */
144     onMouseDragged:function (event) {
145         return false;
146     },
147 
148     /**
149      * <p> called when the "mouseMoved" event is received.            <br/>
150      * Return YES to avoid propagating the event to other delegates.  </p>
151      * @param {cc.Mouse} event
152      * @return {Boolean}
153      */
154     onMouseMoved:function (event) {
155         return false;
156     },
157 
158     /**
159      * <p> called when the "mouseUp" event is received.               <br/>
160      * Return YES to avoid propagating the event to other delegates.  </p>
161      * @param {cc.Mouse} event
162      * @return {Boolean}
163      */
164     onMouseUp:function (event) {
165         return false;
166     },
167 
168     //right
169     /**
170      * <p> called when the "rightMouseDown" event is received.        <br/>
171      * Return YES to avoid propagating the event to other delegates.  </p>
172      * @param {cc.Mouse} event
173      * @return {Boolean}
174      */
175     onRightMouseDown:function (event) {
176         return false;
177     },
178 
179     /**
180      * <p> called when the "rightMouseDragged" event is received.    <br/>
181      * Return YES to avoid propagating the event to other delegates. </p>
182      * @param {cc.Mouse} event
183      * @return {Boolean}
184      */
185     onRightMouseDragged:function (event) {
186         return false;
187     },
188 
189     /**
190      * <p> called when the "rightMouseUp" event is received.          <br/>
191      * Return YES to avoid propagating the event to other delegates.  </p>
192      * @param {cc.Mouse} event
193      * @return {Boolean}
194      */
195     onRightMouseUp:function (event) {
196         return false;
197     },
198 
199     //other
200     /**
201      * <p>called when the "otherMouseDown" event is received.         <br/>
202      * Return YES to avoid propagating the event to other delegates.  </p>
203      * @param {cc.Mouse} event
204      * @return {Boolean}
205      */
206     onOtherMouseDown:function (event) {
207         return false;
208     },
209 
210     /**
211      * <p> called when the "otherMouseDragged" event is received.     <br/>
212      * Return YES to avoid propagating the event to other delegates.  </p>
213      * @param {cc.Mouse} event
214      * @return {Boolean}
215      */
216     onOtherMouseDragged:function (event) {
217         return false;
218     },
219 
220     /**
221      * <p> called when the "otherMouseUp" event is received.          <br/>
222      * Return YES to avoid propagating the event to other delegates.  </p>
223      * @param {cc.Mouse} event
224      * @return {Boolean}
225      */
226     onOtherMouseUp:function (event) {
227         return false;
228     },
229 
230     //scroll wheel
231     /**
232      * <p> called when the "scrollWheel" event is received.           <br/>
233      * Return YES to avoid propagating the event to other delegates.  </p>
234      * @param {cc.Mouse} event
235      * @return {Boolean}
236      */
237     onScrollWheel:function (event) {
238         return false;
239     },
240 
241     // enter / exit
242     /**
243      *  <p> called when the "mouseEntered" event is received.         <br/>
244      *  Return YES to avoid propagating the event to other delegates. </p>
245      * @param {cc.Mouse} theEvent
246      * @return {Boolean}
247      */
248     onMouseEntered:function (theEvent) {
249         return false;
250     },
251 
252     /**
253      * <p> called when the "mouseExited" event is received.          <br/>
254      * Return YES to avoid propagating the event to other delegates. </p>
255      * @param {cc.Mouse} theEvent
256      * @return {Boolean}
257      */
258     onMouseExited:function (theEvent) {
259         return false;
260     }
261 });
262 
263 cc.Mouse = cc.Touch.extend({
264     _wheelDelta:0,
265     _button:cc.MOUSE_LEFTBUTTON,
266 
267     getWheelDelta:function () {
268         return this._wheelDelta;
269     },
270 
271     setWheelDelta:function (delta) {
272         this._wheelDelta = delta;
273     },
274 
275     getButton:function () {
276         return this._button;
277     },
278 
279     setButton:function (button) {
280         this._button = button;
281     }
282 });
283 
284 /**
285  * cc.MouseHandler
286  * Object than contains the delegate and priority of the event handler.
287  * @class
288  * @extends cc.Class
289  */
290 cc.MouseHandler = cc.Class.extend(/** @lends cc.MouseHandler# */{
291     _delegate:null,
292     _priority:0,
293     _enabledSelectors:0,
294 
295     /**
296      * @return {cc.MouseEventDelegate}
297      */
298     getDelegate:function () {
299         return this._delegate;
300     },
301 
302     /**
303      * @param {cc.TouchDelegate} delegate
304      */
305     setDelegate:function (delegate) {
306         this._delegate = delegate;
307     },
308 
309     /**
310      * @return {Number}
311      */
312     getPriority:function () {
313         return this._priority;
314     },
315 
316     /**
317      * @param {Number} priority
318      */
319     setPriority:function (priority) {
320         this._priority = priority;
321     },
322 
323     /**
324      *  Enabled selectors
325      * @return {Number}
326      */
327     getEnabledSelectors:function () {
328         return this._enabledSelectors;
329     },
330 
331     /**
332      * @param {Number} value
333      */
334     setEnalbedSelectors:function (value) {
335         this._enabledSelectors = value;
336     },
337 
338     initWithDelegate:function (delegate, priority) {
339         this._delegate = delegate;
340         this._priority = priority;
341     }
342 });
343 
344 cc.MouseHandler.create = function (delegate, priority) {
345     var handler = new cc.MouseHandler();
346     handler.initWithDelegate(delegate, priority);
347     return handler;
348 };
349 
350 cc.MouseDispatcher = cc.Class.extend({
351     _mousePressed:false,
352     _mouseDelegateHandlers:null,
353     _dispatchEvents:false,
354 
355     init:function () {
356         this._dispatchEvents = true;
357         this._mouseDelegateHandlers = [];
358         this._mousePressed = false;
359 
360         cc.MouseDispatcher._registerHtmlElementEvent(cc.canvas);
361         return true;
362     },
363 
364     _setMousePressed:function (pressed) {
365         this._mousePressed = pressed;
366     },
367 
368     _getMousePressed:function () {
369         return this._mousePressed;
370     },
371 
372     /**
373      * Adds a mouse delegate to the dispatcher's list.  <br/>
374      * Delegates with a lower priority value will be called before higher priority values.   <br/>
375      * All the events will be propagated to all the delegates, unless the one delegate returns YES.      </br>
376      * @param delegate
377      * @param priority
378      */
379     addMouseDelegate:function (delegate, priority) {
380         var handler = cc.MouseHandler.create(delegate, priority);
381 
382         this._mouseDelegateHandlers = this.forceAddHandler(handler, this._mouseDelegateHandlers);
383     },
384 
385     /**
386      *  Force add handler
387      * @param {cc.TouchHandler} handler
388      * @param {Array} array
389      * @return {Array}
390      */
391     forceAddHandler:function (handler, array) {
392         var u = 0;
393 
394         for (var i = 0; i < array.length; i++) {
395             var h = array[i];
396             if (h) {
397                 if (h.getPriority() < handler.getPriority()) {
398                     ++u;
399                 }
400                 if (h.getDelegate() == handler.getDelegate()) {
401                     cc.Assert(0, "TouchDispatcher.forceAddHandler()");
402                     return array;
403                 }
404             }
405         }
406         return cc.ArrayAppendObjectToIndex(array, handler, u);
407     },
408 
409     /**
410      * removes a mouse delegate
411      * @param delegate
412      */
413     removeMouseDelegate:function (delegate) {
414         if (delegate == null)
415             return;
416 
417         for (var i = 0; i < this._mouseDelegateHandlers.length; i++) {
418             var handler = this._mouseDelegateHandlers[i];
419             if (handler && handler.getDelegate() == delegate) {
420                 cc.ArrayRemoveObject(this._mouseDelegateHandlers, handler);
421                 break;
422             }
423         }
424     },
425 
426     _findHandler:function (delegate) {
427         for (i = 0; i < this._mouseDelegateHandlers.length; i++) {
428             if (this._mouseDelegateHandlers[i] && this._mouseDelegateHandlers[i].getDelegate() == delegate) {
429                 return this._mouseDelegateHandlers[i];
430             }
431         }
432     },
433 
434     setPriority:function (priority, delegate) {
435         cc.Assert(delegate != null, "MouseDispatcher.setPriority():Arguments is null");
436         var handler = this._findHandler(delegate);
437         cc.Assert(handler != null, "MouseDispatcher.setPriority():Cant find MouseHandler");
438 
439         if (handler.getPriority() != priority) {
440             handler.setPriority(priority);
441             this._mouseDelegateHandlers.sort(cc.less);
442         }
443     },
444 
445     /**
446      * Removes all mouse delegates, releasing all the delegates
447      */
448     removeAllMouseDelegates:function () {
449         this._mouseDelegateHandlers.length = 0;
450     },
451 
452     mouseHandle:function (mouseObj, event, index) {
453         for (var i = 0; i < this._mouseDelegateHandlers.length; i++) {
454             var handler = this._mouseDelegateHandlers[i];
455 
456             switch (index) {
457                 case cc.MOUSE_DOWN:
458                     if (handler.getDelegate().onMouseDown)
459                         handler.getDelegate().onMouseDown(mouseObj);
460                     break;
461                 case cc.MOUSE_UP:
462                     if (handler.getDelegate().onMouseUp)
463                         handler.getDelegate().onMouseUp(mouseObj);
464                     break;
465                 case cc.MOUSE_MOVED:
466                     if (this._mousePressed) {
467                         if (handler.getDelegate().onMouseDragged)
468                             handler.getDelegate().onMouseDragged(mouseObj);
469                     } else {
470                         if (handler.getDelegate().onMouseMoved)
471                             handler.getDelegate().onMouseMoved(mouseObj);
472                     }
473                     break;
474                 case cc.MOUSE_ENTERED:
475                     if (handler.getDelegate().onMouseEntered)
476                         handler.getDelegate().onMouseEntered(mouseObj);
477                     break;
478                 case cc.MOUSE_EXITED:
479                     if (handler.getDelegate().onMouseExited)
480                         handler.getDelegate().onMouseExited(mouseObj);
481                     break;
482                 case cc.SCROLL_WHEEL:
483                     if (handler.getDelegate().onScrollWheel)
484                         handler.getDelegate().onScrollWheel(mouseObj);
485                     break;
486             }
487         }
488     }
489 });
490 
491 cc.MouseDispatcher._preMousePoint = cc.p(0, 0);
492 
493 cc.MouseDispatcher._isRegisterEvent = false;
494 
495 cc.MouseDispatcher._registerHtmlElementEvent = function (element) {
496     if (cc.MouseDispatcher._isRegisterEvent)
497         return;
498 
499     window.addEventListener('mousedown', function (event) {
500         cc.Director.getInstance().getMouseDispatcher()._setMousePressed(true);
501     });
502 
503     window.addEventListener('mouseup', function (event) {
504         cc.Director.getInstance().getMouseDispatcher()._setMousePressed(false);
505     });
506 
507     function getMouseByEvent(event) {
508         var pos = cc.getHTMLElementPosition(element);
509 
510         var tx = event.pageX;
511         var ty = event.pageY;
512 
513         var mouseX = (tx - pos.left) / cc.Director.getInstance().getContentScaleFactor();
514         var mouseY = (pos.height - (ty - pos.top)) / cc.Director.getInstance().getContentScaleFactor();
515 
516         var mouse = new cc.Mouse(mouseX, mouseY);
517         mouse._setPrevPoint(cc.MouseDispatcher._preMousePoint.x, cc.MouseDispatcher._preMousePoint.y);
518         mouse.setButton(event.button);
519         cc.MouseDispatcher._preMousePoint.x = mouseX;
520         cc.MouseDispatcher._preMousePoint.y = mouseY;
521 
522         return mouse;
523     }
524 
525     //register canvas mouse event
526     element.addEventListener("mousedown", function (event) {
527         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_DOWN);
528     });
529 
530     element.addEventListener("mouseup", function (event) {
531         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_UP);
532     });
533 
534     element.addEventListener("mousemove", function (event) {
535         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_MOVED);
536     });
537 
538     element.addEventListener("mousewheel", function (event) {
539         var mouse = getMouseByEvent(event);
540         mouse.setWheelDelta(event.wheelDelta);
541         cc.Director.getInstance().getMouseDispatcher().mouseHandle(mouse, event, cc.SCROLL_WHEEL);
542     }, false);
543 
544     element.addEventListener("mouseout", function (event) {
545         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_EXITED);
546     }, false);
547 
548     element.addEventListener("mouseover", function (event) {
549         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_ENTERED);
550     }, false);
551 };
552 
553 
554 
555