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