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     _rightMousePressed:false,
353     _mouseDelegateHandlers:null,
354     _dispatchEvents:false,
355 
356     init:function () {
357         this._dispatchEvents = true;
358         this._mouseDelegateHandlers = [];
359         this._mousePressed = false;
360         this._rightMousePressed = false;
361 
362         cc.MouseDispatcher._registerHtmlElementEvent(cc.canvas);
363         return true;
364     },
365 
366     _setMousePressed:function (pressed) {
367         this._mousePressed = pressed;
368     },
369 
370     _getMousePressed:function () {
371         return this._mousePressed;
372     },
373     
374     _setRightMousePressed:function (pressed) {
375         this._rightMousePressed = pressed;
376     },
377 
378     _getRightMousePressed:function () {
379         return this._rightMousePressed;
380     },
381 
382     /**
383      * Adds a mouse delegate to the dispatcher's list.  <br/>
384      * Delegates with a lower priority value will be called before higher priority values.   <br/>
385      * All the events will be propagated to all the delegates, unless the one delegate returns YES.      </br>
386      * @param delegate
387      * @param priority
388      */
389     addMouseDelegate:function (delegate, priority) {
390         var handler = cc.MouseHandler.create(delegate, priority);
391 
392         this._mouseDelegateHandlers = this.forceAddHandler(handler, this._mouseDelegateHandlers);
393     },
394 
395     /**
396      *  Force add handler
397      * @param {cc.TouchHandler} handler
398      * @param {Array} array
399      * @return {Array}
400      */
401     forceAddHandler:function (handler, array) {
402         var u = 0;
403 
404         for (var i = 0; i < array.length; i++) {
405             var h = array[i];
406             if (h) {
407                 if (h.getPriority() < handler.getPriority())
408                     ++u;
409                 if (h.getDelegate() == handler.getDelegate()) {
410                     cc.log("cc.MouseDispatcher.forceAddHandler(): handler has been added.") ;
411                     return array;
412                 }
413             }
414         }
415         return cc.ArrayAppendObjectToIndex(array, handler, u);
416     },
417 
418     /**
419      * removes a mouse delegate
420      * @param delegate
421      */
422     removeMouseDelegate:function (delegate) {
423         if (delegate == null)
424             return;
425 
426         for (var i = 0; i < this._mouseDelegateHandlers.length; i++) {
427             var handler = this._mouseDelegateHandlers[i];
428             if (handler && handler.getDelegate() == delegate) {
429                 cc.ArrayRemoveObject(this._mouseDelegateHandlers, handler);
430                 break;
431             }
432         }
433     },
434 
435     _findHandler:function (delegate) {
436         for (var i = 0; i < this._mouseDelegateHandlers.length; i++) {
437             if (this._mouseDelegateHandlers[i] && this._mouseDelegateHandlers[i].getDelegate() == delegate) {
438                 return this._mouseDelegateHandlers[i];
439             }
440         }
441         return null;
442     },
443 
444     setPriority:function (priority, delegate) {
445         if(!delegate)
446             throw "cc.MouseDispatcher.setPriority(): delegate should be non-null";
447         var handler = this._findHandler(delegate);
448         if(!handler) {
449             cc.log("cc.MouseDispatcher.setPriority(): Can't find MouseHandler in array");
450             return;
451         }
452 
453 
454         if (handler.getPriority() != priority) {
455             handler.setPriority(priority);
456             this._mouseDelegateHandlers.sort(cc.less);
457         }
458     },
459 
460     /**
461      * Removes all mouse delegates, releasing all the delegates
462      */
463     removeAllMouseDelegates:function () {
464         this._mouseDelegateHandlers.length = 0;
465     },
466 
467     mouseHandle:function (mouseObj, event, index) {
468         for (var i = 0; i < this._mouseDelegateHandlers.length; i++) {
469             var handler = this._mouseDelegateHandlers[i];
470 
471             switch (index) {
472                 case cc.MOUSE_DOWN:
473                     if (mouseObj.getButton() == cc.MOUSE_RIGHTBUTTON) {
474                         if (handler.getDelegate().onRightMouseDown)
475                             handler.getDelegate().onRightMouseDown(mouseObj);
476                     } else {
477 	                   if (handler.getDelegate().onMouseDown)
478 	                       handler.getDelegate().onMouseDown(mouseObj);
479                      }
480                     break;
481                 case cc.MOUSE_UP:
482                     if (mouseObj.getButton() == cc.MOUSE_RIGHTBUTTON) {
483                         if (handler.getDelegate().onRightMouseUp)
484                             handler.getDelegate().onRightMouseUp(mouseObj);
485                     } else {
486                         if (handler.getDelegate().onMouseUp)
487                             handler.getDelegate().onMouseUp(mouseObj);
488                     }
489                     break;
490                 case cc.MOUSE_MOVED:
491                     if (this._mousePressed) {                        
492                         if (handler.getDelegate().onMouseDragged)
493                             handler.getDelegate().onMouseDragged(mouseObj);
494                     } else if (this._rightMousePressed) {
495                         if (handler.getDelegate().onRightMouseDragged)
496                             handler.getDelegate().onRightMouseDragged(mouseObj);
497                     } else {
498                         if (handler.getDelegate().onMouseMoved)
499                             handler.getDelegate().onMouseMoved(mouseObj);
500                     }
501                     break;
502                 case cc.MOUSE_ENTERED:
503                     if (handler.getDelegate().onMouseEntered)
504                         handler.getDelegate().onMouseEntered(mouseObj);
505                     break;
506                 case cc.MOUSE_EXITED:
507                     if (handler.getDelegate().onMouseExited)
508                         handler.getDelegate().onMouseExited(mouseObj);
509                     break;
510                 case cc.SCROLL_WHEEL:
511                     if (handler.getDelegate().onScrollWheel)
512                         handler.getDelegate().onScrollWheel(mouseObj);
513                     break;
514             }
515         }
516     }
517 });
518 
519 cc.MouseDispatcher._preMousePoint = cc.p(0, 0);
520 
521 cc.MouseDispatcher._isRegisterEvent = false;
522 
523 cc.MouseDispatcher._registerHtmlElementEvent = function (element) {
524     if (cc.MouseDispatcher._isRegisterEvent)
525         return;
526 
527     window.addEventListener('mousedown', function (event) {
528         if (event.button == cc.MOUSE_RIGHTBUTTON) {
529             cc.Director.getInstance().getMouseDispatcher()._setRightMousePressed(true);	       
530         } else {
531             cc.Director.getInstance().getMouseDispatcher()._setMousePressed(true);
532         }
533     });
534 
535     window.addEventListener('mouseup', function (event) {
536         if (event.button == cc.MOUSE_RIGHTBUTTON) {
537             cc.Director.getInstance().getMouseDispatcher()._setRightMousePressed(false);	       
538         } else {
539             cc.Director.getInstance().getMouseDispatcher()._setMousePressed(false);
540         }
541     });
542 
543     function getMouseByEvent(event) {
544         var pos = cc.getHTMLElementPosition(element);
545 
546         var tx = event.pageX;
547         var ty = event.pageY;
548         var eglViewer = cc.EGLView.getInstance();
549 
550         var mouseX = (tx - pos.left) / eglViewer.getScaleX();
551         var mouseY = (pos.height - (ty - pos.top)) / eglViewer.getScaleY();
552 
553         var mouse = new cc.Mouse(mouseX, mouseY);
554         mouse._setPrevPoint(cc.MouseDispatcher._preMousePoint.x, cc.MouseDispatcher._preMousePoint.y);
555         mouse.setButton(event.button);
556         cc.MouseDispatcher._preMousePoint.x = mouseX;
557         cc.MouseDispatcher._preMousePoint.y = mouseY;
558 
559         return mouse;
560     }
561 
562     //register canvas mouse event
563     element.addEventListener("mousedown", function (event) {
564         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_DOWN);
565     });
566 
567     element.addEventListener("mouseup", function (event) {
568         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_UP);
569     });
570 
571     element.addEventListener("mousemove", function (event) {
572         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_MOVED);
573     });
574 
575     element.addEventListener("mousewheel", function (event) {
576         var mouse = getMouseByEvent(event);
577         mouse.setWheelDelta(event.wheelDelta);
578         cc.Director.getInstance().getMouseDispatcher().mouseHandle(mouse, event, cc.SCROLL_WHEEL);
579     }, false);
580     
581     /* firefox fix */
582     element.addEventListener("DOMMouseScroll", function(event) {
583     	var mouse = getMouseByEvent(event);
584         mouse.setWheelDelta(event.detail * -120);
585         cc.Director.getInstance().getMouseDispatcher().mouseHandle(mouse, event, cc.SCROLL_WHEEL);
586     });
587 
588     element.addEventListener("mouseout", function (event) {
589         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_EXITED);
590     }, false);
591 
592     element.addEventListener("mouseover", function (event) {
593         cc.Director.getInstance().getMouseDispatcher().mouseHandle(getMouseByEvent(event), event, cc.MOUSE_ENTERED);
594     }, false);
595 };
596 
597 
598