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: true, // 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 * <p>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<br/> 200 * You will need to retain an object if you created a listener and haven't added it any target node during the same frame.<br/> 201 * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,<br/> 202 * when you want to use it later, a "Invalid Native Object" error will be raised.<br/> 203 * The retain function can increase a reference count for the native object to avoid it being released,<br/> 204 * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.<br/> 205 * retain and release function call should be paired in developer's game code.</p> 206 * @function 207 * @see cc.EventListener#release 208 */ 209 retain:function () { 210 }, 211 /** 212 * <p>Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, 213 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. 214 * This is a hack, and should be removed once JSB fixes the retain/release bug<br/> 215 * You will need to retain an object if you created a listener and haven't added it any target node during the same frame.<br/> 216 * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,<br/> 217 * when you want to use it later, a "Invalid Native Object" error will be raised.<br/> 218 * The retain function can increase a reference count for the native object to avoid it being released,<br/> 219 * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.<br/> 220 * retain and release function call should be paired in developer's game code.</p> 221 * @function 222 * @see cc.EventListener#retain 223 */ 224 release:function () { 225 } 226 }); 227 228 // event listener type 229 /** 230 * The type code of unknown event listener. 231 * @constant 232 * @type {number} 233 */ 234 cc.EventListener.UNKNOWN = 0; 235 /** 236 * The type code of one by one touch event listener. 237 * @constant 238 * @type {number} 239 */ 240 cc.EventListener.TOUCH_ONE_BY_ONE = 1; 241 /** 242 * The type code of all at once touch event listener. 243 * @constant 244 * @type {number} 245 */ 246 cc.EventListener.TOUCH_ALL_AT_ONCE = 2; 247 /** 248 * The type code of keyboard event listener. 249 * @constant 250 * @type {number} 251 */ 252 cc.EventListener.KEYBOARD = 3; 253 /** 254 * The type code of mouse event listener. 255 * @constant 256 * @type {number} 257 */ 258 cc.EventListener.MOUSE = 4; 259 /** 260 * The type code of acceleration event listener. 261 * @constant 262 * @type {number} 263 */ 264 cc.EventListener.ACCELERATION = 5; 265 /** 266 * The type code of focus event listener. 267 * @constant 268 * @type {number} 269 */ 270 cc.EventListener.ACCELERATION = 6; 271 /** 272 * The type code of custom event listener. 273 * @constant 274 * @type {number} 275 */ 276 cc.EventListener.CUSTOM = 8; 277 278 /** 279 * The type code of Focus change event listener. 280 * @constant 281 * @type {number} 282 */ 283 cc.EventListener.FOCUS = 7; 284 285 cc._EventListenerCustom = cc.EventListener.extend({ 286 _onCustomEvent: null, 287 ctor: function (listenerId, callback) { 288 this._onCustomEvent = callback; 289 var selfPointer = this; 290 var listener = function (event) { 291 if (selfPointer._onCustomEvent !== null) 292 selfPointer._onCustomEvent(event); 293 }; 294 295 cc.EventListener.prototype.ctor.call(this, cc.EventListener.CUSTOM, listenerId, listener); 296 }, 297 298 checkAvailable: function () { 299 return (cc.EventListener.prototype.checkAvailable.call(this) && this._onCustomEvent !== null); 300 }, 301 302 clone: function () { 303 return new cc._EventListenerCustom(this._listenerID, this._onCustomEvent); 304 } 305 }); 306 307 cc._EventListenerCustom.create = function (eventName, callback) { 308 return new cc._EventListenerCustom(eventName, callback); 309 }; 310 311 cc._EventListenerMouse = cc.EventListener.extend({ 312 onMouseDown: null, 313 onMouseUp: null, 314 onMouseMove: null, 315 onMouseScroll: null, 316 317 ctor: function () { 318 var selfPointer = this; 319 var listener = function (event) { 320 var eventType = cc.EventMouse; 321 switch (event._eventType) { 322 case eventType.DOWN: 323 if (selfPointer.onMouseDown) 324 selfPointer.onMouseDown(event); 325 break; 326 case eventType.UP: 327 if (selfPointer.onMouseUp) 328 selfPointer.onMouseUp(event); 329 break; 330 case eventType.MOVE: 331 if (selfPointer.onMouseMove) 332 selfPointer.onMouseMove(event); 333 break; 334 case eventType.SCROLL: 335 if (selfPointer.onMouseScroll) 336 selfPointer.onMouseScroll(event); 337 break; 338 default: 339 break; 340 } 341 }; 342 cc.EventListener.prototype.ctor.call(this, cc.EventListener.MOUSE, cc._EventListenerMouse.LISTENER_ID, listener); 343 }, 344 345 clone: function () { 346 var eventListener = new cc._EventListenerMouse(); 347 eventListener.onMouseDown = this.onMouseDown; 348 eventListener.onMouseUp = this.onMouseUp; 349 eventListener.onMouseMove = this.onMouseMove; 350 eventListener.onMouseScroll = this.onMouseScroll; 351 return eventListener; 352 }, 353 354 checkAvailable: function () { 355 return true; 356 } 357 }); 358 359 cc._EventListenerMouse.LISTENER_ID = "__cc_mouse"; 360 361 cc._EventListenerMouse.create = function () { 362 return new cc._EventListenerMouse(); 363 }; 364 365 cc._EventListenerTouchOneByOne = cc.EventListener.extend({ 366 _claimedTouches: null, 367 swallowTouches: false, 368 onTouchBegan: null, 369 onTouchMoved: null, 370 onTouchEnded: null, 371 onTouchCancelled: null, 372 373 ctor: function () { 374 cc.EventListener.prototype.ctor.call(this, cc.EventListener.TOUCH_ONE_BY_ONE, cc._EventListenerTouchOneByOne.LISTENER_ID, null); 375 this._claimedTouches = []; 376 }, 377 378 setSwallowTouches: function (needSwallow) { 379 this.swallowTouches = needSwallow; 380 }, 381 382 isSwallowTouches: function(){ 383 return this.swallowTouches; 384 }, 385 386 clone: function () { 387 var eventListener = new cc._EventListenerTouchOneByOne(); 388 eventListener.onTouchBegan = this.onTouchBegan; 389 eventListener.onTouchMoved = this.onTouchMoved; 390 eventListener.onTouchEnded = this.onTouchEnded; 391 eventListener.onTouchCancelled = this.onTouchCancelled; 392 eventListener.swallowTouches = this.swallowTouches; 393 return eventListener; 394 }, 395 396 checkAvailable: function () { 397 if(!this.onTouchBegan){ 398 cc.log(cc._LogInfos._EventListenerTouchOneByOne_checkAvailable); 399 return false; 400 } 401 return true; 402 } 403 }); 404 405 cc._EventListenerTouchOneByOne.LISTENER_ID = "__cc_touch_one_by_one"; 406 407 cc._EventListenerTouchOneByOne.create = function () { 408 return new cc._EventListenerTouchOneByOne(); 409 }; 410 411 cc._EventListenerTouchAllAtOnce = cc.EventListener.extend({ 412 onTouchesBegan: null, 413 onTouchesMoved: null, 414 onTouchesEnded: null, 415 onTouchesCancelled: null, 416 417 ctor: function(){ 418 cc.EventListener.prototype.ctor.call(this, cc.EventListener.TOUCH_ALL_AT_ONCE, cc._EventListenerTouchAllAtOnce.LISTENER_ID, null); 419 }, 420 421 clone: function(){ 422 var eventListener = new cc._EventListenerTouchAllAtOnce(); 423 eventListener.onTouchesBegan = this.onTouchesBegan; 424 eventListener.onTouchesMoved = this.onTouchesMoved; 425 eventListener.onTouchesEnded = this.onTouchesEnded; 426 eventListener.onTouchesCancelled = this.onTouchesCancelled; 427 return eventListener; 428 }, 429 430 checkAvailable: function(){ 431 if (this.onTouchesBegan === null && this.onTouchesMoved === null 432 && this.onTouchesEnded === null && this.onTouchesCancelled === null) { 433 cc.log(cc._LogInfos._EventListenerTouchAllAtOnce_checkAvailable); 434 return false; 435 } 436 return true; 437 } 438 }); 439 440 cc._EventListenerTouchAllAtOnce.LISTENER_ID = "__cc_touch_all_at_once"; 441 442 cc._EventListenerTouchAllAtOnce.create = function(){ 443 return new cc._EventListenerTouchAllAtOnce(); 444 }; 445 446 /** 447 * Create a EventListener object by json object 448 * @function 449 * @static 450 * @param {object} argObj a json object 451 * @returns {cc.EventListener} 452 * todo: It should be the direct use new 453 * @example 454 * cc.EventListener.create({ 455 * event: cc.EventListener.TOUCH_ONE_BY_ONE, 456 * swallowTouches: true, 457 * onTouchBegan: function (touch, event) { 458 * //do something 459 * return true; 460 * } 461 * }); 462 */ 463 cc.EventListener.create = function(argObj){ 464 465 cc.assert(argObj&&argObj.event, cc._LogInfos.EventListener_create); 466 467 var listenerType = argObj.event; 468 delete argObj.event; 469 470 var listener = null; 471 if(listenerType === cc.EventListener.TOUCH_ONE_BY_ONE) 472 listener = new cc._EventListenerTouchOneByOne(); 473 else if(listenerType === cc.EventListener.TOUCH_ALL_AT_ONCE) 474 listener = new cc._EventListenerTouchAllAtOnce(); 475 else if(listenerType === cc.EventListener.MOUSE) 476 listener = new cc._EventListenerMouse(); 477 else if(listenerType === cc.EventListener.CUSTOM){ 478 listener = new cc._EventListenerCustom(argObj.eventName, argObj.callback); 479 delete argObj.eventName; 480 delete argObj.callback; 481 } else if(listenerType === cc.EventListener.KEYBOARD) 482 listener = new cc._EventListenerKeyboard(); 483 else if(listenerType === cc.EventListener.ACCELERATION){ 484 listener = new cc._EventListenerAcceleration(argObj.callback); 485 delete argObj.callback; 486 } else if(listenerType === cc.EventListener.FOCUS) 487 listener = new cc._EventListenerFocus(); 488 489 for(var key in argObj) { 490 listener[key] = argObj[key]; 491 } 492 493 return listener; 494 }; 495 496 cc._EventListenerFocus = cc.EventListener.extend({ 497 clone: function(){ 498 var listener = new cc._EventListenerFocus(); 499 listener.onFocusChanged = this.onFocusChanged; 500 return listener; 501 }, 502 checkAvailable: function(){ 503 if(!this.onFocusChanged){ 504 cc.log("Invalid EventListenerFocus!"); 505 return false; 506 } 507 return true; 508 }, 509 onFocusChanged: null, 510 ctor: function(){ 511 var listener = function(event){ 512 if(this.onFocusChanged) 513 this.onFocusChanged(event._widgetLoseFocus, event._widgetGetFocus); 514 }; 515 cc.EventListener.prototype.ctor.call(this, cc.EventListener.FOCUS, cc._EventListenerFocus.LISTENER_ID, listener); 516 } 517 }); 518 519 cc._EventListenerFocus.LISTENER_ID = "__cc_focus_event";