1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * <p>
 28  *     The base class of event listener.                                                                        <br/>
 29  *     If you need custom listener which with different callback, you need to inherit this class.               <br/>
 30  *     For instance, you could refer to EventListenerAcceleration, EventListenerKeyboard,                       <br/>
 31  *      EventListenerTouchOneByOne, EventListenerCustom.
 32  * </p>
 33  * @class
 34  * @extends cc.Class
 35  */
 36 cc.EventListener = cc.Class.extend(/** @lends cc.EventListener# */{
 37     _onEvent: null,                          // Event callback function
 38     _type: 0,                                 // Event listener type
 39     _listenerID: null,                       // Event listener ID
 40     _registered: false,                     // Whether the listener has been added to dispatcher.
 41 
 42     _fixedPriority: 0,                      // The higher the number, the higher the priority, 0 is for scene graph base priority.
 43     _node: null,                           // scene graph based priority
 44     _paused: false,                        // Whether the listener is paused
 45     _isEnabled: true,                      // Whether the listener is enabled
 46 
 47     /**
 48      * Initializes event with type and callback function
 49      * @param {number} type
 50      * @param {string} listenerID
 51      * @param {function} callback
 52      */
 53     ctor: function (type, listenerID, callback) {
 54         this._onEvent = callback;
 55         this._type = type || 0;
 56         this._listenerID = listenerID || "";
 57     },
 58 
 59     /**
 60      * <p>
 61      *     Sets paused state for the listener
 62      *     The paused state is only used for scene graph priority listeners.
 63      *     `EventDispatcher::resumeAllEventListenersForTarget(node)` will set the paused state to `true`,
 64      *     while `EventDispatcher::pauseAllEventListenersForTarget(node)` will set it to `false`.
 65      *     @note 1) Fixed priority listeners will never get paused. If a fixed priority doesn't want to receive events,
 66      *              call `setEnabled(false)` instead.
 67      *            2) In `Node`'s onEnter and onExit, the `paused state` of the listeners which associated with that node will be automatically updated.
 68      * </p>
 69      * @param {boolean} paused
 70      * @private
 71      */
 72     _setPaused: function (paused) {
 73         this._paused = paused;
 74     },
 75 
 76     /**
 77      * Checks whether the listener is paused
 78      * @returns {boolean}
 79      * @private
 80      */
 81     _isPaused: function () {
 82         return this._paused;
 83     },
 84 
 85     /**
 86      * Marks the listener was registered by EventDispatcher
 87      * @param {boolean} registered
 88      * @private
 89      */
 90     _setRegistered: function (registered) {
 91         this._registered = registered;
 92     },
 93 
 94     /**
 95      * Checks whether the listener was registered by EventDispatcher
 96      * @returns {boolean}
 97      * @private
 98      */
 99     _isRegistered: function () {
100         return this._registered;
101     },
102 
103     /**
104      * Gets the type of this listener
105      * @note It's different from `EventType`, e.g. TouchEvent has two kinds of event listeners - EventListenerOneByOne, EventListenerAllAtOnce
106      * @returns {number}
107      * @private
108      */
109     _getType: function () {
110         return this._type;
111     },
112 
113     /**
114      *  Gets the listener ID of this listener
115      *  When event is being dispatched, listener ID is used as key for searching listeners according to event type.
116      * @returns {string}
117      * @private
118      */
119     _getListenerID: function () {
120         return this._listenerID;
121     },
122 
123     /**
124      * Sets the fixed priority for this listener
125      *  @note This method is only used for `fixed priority listeners`, it needs to access a non-zero value. 0 is reserved for scene graph priority listeners
126      * @param {number} fixedPriority
127      * @private
128      */
129     _setFixedPriority: function (fixedPriority) {
130         this._fixedPriority = fixedPriority;
131     },
132 
133     /**
134      * Gets the fixed priority of this listener
135      * @returns {number} 0 if it's a scene graph priority listener, non-zero for fixed priority listener
136      * @private
137      */
138     _getFixedPriority: function () {
139         return this._fixedPriority;
140     },
141 
142     /**
143      * Sets scene graph priority for this listener
144      * @param {cc.Node} node
145      * @private
146      */
147     _setSceneGraphPriority: function (node) {
148         this._node = node;
149     },
150 
151     /**
152      * Gets scene graph priority of this listener
153      * @returns {cc.Node} if it's a fixed priority listener, non-null for scene graph priority listener
154      * @private
155      */
156     _getSceneGraphPriority: function () {
157         return this._node;
158     },
159 
160     /**
161      * Checks whether the listener is available.
162      * @returns {boolean}
163      */
164     checkAvailable: function () {
165         return this._onEvent != null;
166     },
167 
168     /**
169      * Clones the listener, its subclasses have to override this method.
170      * @returns {cc.EventListener}
171      */
172     clone: function () {
173         return null;
174     },
175 
176     /**
177      *  Enables or disables the listener
178      *  @note Only listeners with `enabled` state will be able to receive events.
179      *          When an listener was initialized, it's enabled by default.
180      *          An event listener can receive events when it is enabled and is not paused.
181      *          paused state is always false when it is a fixed priority listener.
182      * @param {boolean} enabled
183      */
184     setEnabled: function(enabled){
185         this._isEnabled = enabled;
186     },
187 
188     /**
189      * Checks whether the listener is enabled
190      * @returns {boolean}
191      */
192     isEnabled: function(){
193         return this._isEnabled;
194     },
195 
196     /**
197      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
198      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
199      * This is a hack, and should be removed once JSB fixes the retain/release bug
200      */
201     retain:function () {
202     },
203     release:function () {
204     }
205 });
206 
207 // event listener type
208 /**
209  * The type code of unknown event listener.
210  * @constant
211  * @type {number}
212  */
213 cc.EventListener.UNKNOWN = 0;
214 /**
215  * The type code of one by one touch event listener.
216  * @constant
217  * @type {number}
218  */
219 cc.EventListener.TOUCH_ONE_BY_ONE = 1;
220 /**
221  * The type code of all at once touch event listener.
222  * @constant
223  * @type {number}
224  */
225 cc.EventListener.TOUCH_ALL_AT_ONCE = 2;
226 /**
227  * The type code of keyboard event listener.
228  * @constant
229  * @type {number}
230  */
231 cc.EventListener.KEYBOARD = 3;
232 /**
233  * The type code of mouse event listener.
234  * @constant
235  * @type {number}
236  */
237 cc.EventListener.MOUSE = 4;
238 /**
239  * The type code of acceleration event listener.
240  * @constant
241  * @type {number}
242  */
243 cc.EventListener.ACCELERATION = 5;
244 /**
245  * The type code of custom event listener.
246  * @constant
247  * @type {number}
248  */
249 cc.EventListener.CUSTOM = 6;
250 
251 cc._EventListenerCustom = cc.EventListener.extend({
252     _onCustomEvent: null,
253     ctor: function (listenerId, callback) {
254         this._onCustomEvent = callback;
255         var selfPointer = this;
256         var listener = function (event) {
257             if (selfPointer._onCustomEvent != null)
258                 selfPointer._onCustomEvent(event);
259         };
260 
261         cc.EventListener.prototype.ctor.call(this, cc.EventListener.CUSTOM, listenerId, listener);
262     },
263 
264     checkAvailable: function () {
265         return (cc.EventListener.prototype.checkAvailable.call(this) && this._onCustomEvent != null);
266     },
267 
268     clone: function () {
269         return new cc._EventListenerCustom(this._listenerID, this._onCustomEvent);
270     }
271 });
272 
273 cc._EventListenerCustom.create = function (eventName, callback) {
274     return new cc._EventListenerCustom(eventName, callback);
275 };
276 
277 cc._EventListenerMouse = cc.EventListener.extend({
278     onMouseDown: null,
279     onMouseUp: null,
280     onMouseMove: null,
281     onMouseScroll: null,
282 
283     ctor: function () {
284         var selfPointer = this;
285         var listener = function (event) {
286             var eventType = cc.EventMouse;
287             switch (event._eventType) {
288                 case eventType.DOWN:
289                     if (selfPointer.onMouseDown)
290                         selfPointer.onMouseDown(event);
291                     break;
292                 case eventType.UP:
293                     if (selfPointer.onMouseUp)
294                         selfPointer.onMouseUp(event);
295                     break;
296                 case eventType.MOVE:
297                     if (selfPointer.onMouseMove)
298                         selfPointer.onMouseMove(event);
299                     break;
300                 case eventType.SCROLL:
301                     if (selfPointer.onMouseScroll)
302                         selfPointer.onMouseScroll(event);
303                     break;
304                 default:
305                     break;
306             }
307         };
308         cc.EventListener.prototype.ctor.call(this, cc.EventListener.MOUSE, cc._EventListenerMouse.LISTENER_ID, listener);
309     },
310 
311     clone: function () {
312         var eventListener = new cc._EventListenerMouse();
313         eventListener.onMouseDown = this.onMouseDown;
314         eventListener.onMouseUp = this.onMouseUp;
315         eventListener.onMouseMove = this.onMouseMove;
316         eventListener.onMouseScroll = this.onMouseScroll;
317         return eventListener;
318     },
319 
320     checkAvailable: function () {
321         return true;
322     }
323 });
324 
325 cc._EventListenerMouse.LISTENER_ID = "__cc_mouse";
326 
327 cc._EventListenerMouse.create = function () {
328     return new cc._EventListenerMouse();
329 };
330 
331 cc._EventListenerTouchOneByOne = cc.EventListener.extend({
332     _claimedTouches: null,
333     swallowTouches: false,
334     onTouchBegan: null,
335     onTouchMoved: null,
336     onTouchEnded: null,
337     onTouchCancelled: null,
338 
339     ctor: function () {
340         cc.EventListener.prototype.ctor.call(this, cc.EventListener.TOUCH_ONE_BY_ONE, cc._EventListenerTouchOneByOne.LISTENER_ID, null);
341         this._claimedTouches = [];
342     },
343 
344     setSwallowTouches: function (needSwallow) {
345         this.swallowTouches = needSwallow;
346     },
347 
348     clone: function () {
349         var eventListener = new cc._EventListenerTouchOneByOne();
350         eventListener.onTouchBegan = this.onTouchBegan;
351         eventListener.onTouchMoved = this.onTouchMoved;
352         eventListener.onTouchEnded = this.onTouchEnded;
353         eventListener.onTouchCancelled = this.onTouchCancelled;
354         eventListener.swallowTouches = this.swallowTouches;
355         return eventListener;
356     },
357 
358     checkAvailable: function () {
359         if(!this.onTouchBegan){
360             cc.log(cc._LogInfos._EventListenerTouchOneByOne_checkAvailable);
361             return false;
362         }
363         return true;
364     }
365 });
366 
367 cc._EventListenerTouchOneByOne.LISTENER_ID = "__cc_touch_one_by_one";
368 
369 cc._EventListenerTouchOneByOne.create = function () {
370     return new cc._EventListenerTouchOneByOne();
371 };
372 
373 cc._EventListenerTouchAllAtOnce = cc.EventListener.extend({
374     onTouchesBegan: null,
375     onTouchesMoved: null,
376     onTouchesEnded: null,
377     onTouchesCancelled: null,
378 
379     ctor: function(){
380        cc.EventListener.prototype.ctor.call(this, cc.EventListener.TOUCH_ALL_AT_ONCE, cc._EventListenerTouchAllAtOnce.LISTENER_ID, null);
381     },
382 
383     clone: function(){
384         var eventListener = new cc._EventListenerTouchAllAtOnce();
385         eventListener.onTouchesBegan = this.onTouchesBegan;
386         eventListener.onTouchesMoved = this.onTouchesMoved;
387         eventListener.onTouchesEnded = this.onTouchesEnded;
388         eventListener.onTouchesCancelled = this.onTouchesCancelled;
389         return eventListener;
390     },
391 
392     checkAvailable: function(){
393         if (this.onTouchesBegan == null && this.onTouchesMoved == null
394             && this.onTouchesEnded == null && this.onTouchesCancelled == null) {
395             cc.log(cc._LogInfos._EventListenerTouchAllAtOnce_checkAvailable);
396             return false;
397         }
398         return true;
399     }
400 });
401 
402 cc._EventListenerTouchAllAtOnce.LISTENER_ID = "__cc_touch_all_at_once";
403 
404 cc._EventListenerTouchAllAtOnce.create = function(){
405      return new cc._EventListenerTouchAllAtOnce();
406 };
407 
408 /**
409  * Create a EventListener object by json object
410  * @param {object} argObj a json object
411  * @returns {cc.EventListener}
412  * @example
413  * cc.EventListener.create({
414  *       event: cc.EventListener.TOUCH_ONE_BY_ONE,
415  *       swallowTouches: true,
416  *       onTouchBegan: function (touch, event) {
417  *           //do something
418  *           return true;
419  *       }
420  *    });
421  */
422 cc.EventListener.create = function(argObj){
423 
424     cc.assert(argObj&&argObj.event, cc._LogInfos.EventListener_create);
425 
426     var listenerType = argObj.event;
427     delete argObj.event;
428 
429     var listener = null;
430     if(listenerType === cc.EventListener.TOUCH_ONE_BY_ONE)
431         listener = new cc._EventListenerTouchOneByOne();
432     else if(listenerType === cc.EventListener.TOUCH_ALL_AT_ONCE)
433         listener = new cc._EventListenerTouchAllAtOnce();
434     else if(listenerType === cc.EventListener.MOUSE)
435         listener = new cc._EventListenerMouse();
436     else if(listenerType === cc.EventListener.CUSTOM){
437         listener = new cc._EventListenerCustom(argObj.eventName, argObj.callback);
438         delete argObj.eventName;
439         delete argObj.callback;
440     } else if(listenerType === cc.EventListener.KEYBOARD)
441         listener = new cc._EventListenerKeyboard();
442     else if(listenerType === cc.EventListener.ACCELERATION){
443         listener = new cc._EventListenerAcceleration(argObj.callback);
444         delete argObj.callback;
445     }
446 
447     for(var key in argObj) {
448         listener[key] = argObj[key];
449     }
450 
451     return listener;
452 };