CCEventManager.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /****************************************************************************
  2. Copyright (c) 2011-2012 cocos2d-x.org
  3. Copyright (c) 2013-2014 Chukong Technologies Inc.
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. cc._EventListenerVector = cc.Class.extend({
  22. _fixedListeners: null,
  23. _sceneGraphListeners: null,
  24. gt0Index: 0,
  25. ctor: function () {
  26. this._fixedListeners = [];
  27. this._sceneGraphListeners = [];
  28. },
  29. size: function () {
  30. return this._fixedListeners.length + this._sceneGraphListeners.length;
  31. },
  32. empty: function () {
  33. return (this._fixedListeners.length === 0) && (this._sceneGraphListeners.length === 0);
  34. },
  35. push: function (listener) {
  36. if (listener._getFixedPriority() == 0)
  37. this._sceneGraphListeners.push(listener);
  38. else
  39. this._fixedListeners.push(listener);
  40. },
  41. clearSceneGraphListeners: function () {
  42. this._sceneGraphListeners.length = 0;
  43. },
  44. clearFixedListeners: function () {
  45. this._fixedListeners.length = 0;
  46. },
  47. clear: function () {
  48. this._sceneGraphListeners.length = 0;
  49. this._fixedListeners.length = 0;
  50. },
  51. getFixedPriorityListeners: function () {
  52. return this._fixedListeners;
  53. },
  54. getSceneGraphPriorityListeners: function () {
  55. return this._sceneGraphListeners;
  56. }
  57. });
  58. cc.__getListenerID = function (event) {
  59. var eventType = cc.Event, getType = event.getType();
  60. if(getType === eventType.ACCELERATION)
  61. return cc._EventListenerAcceleration.LISTENER_ID;
  62. if(getType === eventType.CUSTOM)
  63. return event.getEventName();
  64. if(getType === eventType.KEYBOARD)
  65. return cc._EventListenerKeyboard.LISTENER_ID;
  66. if(getType === eventType.MOUSE)
  67. return cc._EventListenerMouse.LISTENER_ID;
  68. if(getType === eventType.TOUCH){
  69. // Touch listener is very special, it contains two kinds of listeners, EventListenerTouchOneByOne and EventListenerTouchAllAtOnce.
  70. // return UNKNOWN instead.
  71. cc.log(cc._LogInfos.__getListenerID);
  72. }
  73. return "";
  74. };
  75. /**
  76. * <p>
  77. * cc.eventManager is a singleton object which manages event listener subscriptions and event dispatching. <br/>
  78. * <br/>
  79. * The EventListener list is managed in such way so that event listeners can be added and removed <br/>
  80. * while events are being dispatched.
  81. * </p>
  82. * @class
  83. * @name cc.eventManager
  84. */
  85. cc.eventManager = /** @lends cc.eventManager# */{
  86. //Priority dirty flag
  87. DIRTY_NONE:0,
  88. DIRTY_FIXED_PRIORITY:1 <<0,
  89. DIRTY_SCENE_GRAPH_PRIORITY : 1<< 1,
  90. DIRTY_ALL: 3,
  91. _listenersMap: {},
  92. _priorityDirtyFlagMap: {},
  93. _nodeListenersMap: {},
  94. _nodePriorityMap: {},
  95. _globalZOrderNodeMap: {},
  96. _toAddedListeners: [],
  97. _dirtyNodes: [],
  98. _inDispatch: 0,
  99. _isEnabled: false,
  100. _nodePriorityIndex: 0,
  101. _internalCustomListenerIDs:[cc.game.EVENT_HIDE, cc.game.EVENT_SHOW],
  102. _setDirtyForNode: function (node) {
  103. // Mark the node dirty only when there is an event listener associated with it.
  104. if (this._nodeListenersMap[node.__instanceId] != null)
  105. this._dirtyNodes.push(node);
  106. var _children = node.getChildren();
  107. for(var i = 0, len = _children.length; i < len; i++)
  108. this._setDirtyForNode(_children[i]);
  109. },
  110. /**
  111. * Pauses all listeners which are associated the specified target.
  112. * @param {cc.Node} node
  113. * @param {Boolean} [recursive=false]
  114. */
  115. pauseTarget: function (node, recursive) {
  116. var listeners = this._nodeListenersMap[node.__instanceId], i, len;
  117. if (listeners) {
  118. for ( i = 0, len = listeners.length; i < len; i++)
  119. listeners[i]._setPaused(true);
  120. }
  121. if (recursive === true) {
  122. var locChildren = node.getChildren();
  123. for ( i = 0, len = locChildren.length; i< len; i++)
  124. this.pauseTarget(locChildren[i], true);
  125. }
  126. },
  127. /**
  128. * Resumes all listeners which are associated the specified target.
  129. * @param {cc.Node} node
  130. * @param {Boolean} [recursive=false]
  131. */
  132. resumeTarget: function (node, recursive) {
  133. var listeners = this._nodeListenersMap[node.__instanceId], i, len;
  134. if (listeners){
  135. for ( i = 0, len = listeners.length; i < len; i++)
  136. listeners[i]._setPaused(false);
  137. }
  138. this._setDirtyForNode(node);
  139. if (recursive === true) {
  140. var locChildren = node.getChildren();
  141. for ( i = 0, len = locChildren.length; i< len; i++)
  142. this.resumeTarget(locChildren[i], true);
  143. }
  144. },
  145. _addListener: function (listener) {
  146. if (this._inDispatch === 0)
  147. this._forceAddEventListener(listener);
  148. else
  149. this._toAddedListeners.push(listener);
  150. },
  151. _forceAddEventListener: function (listener) {
  152. var listenerID = listener._getListenerID();
  153. var listeners = this._listenersMap[listenerID];
  154. if (!listeners) {
  155. listeners = new cc._EventListenerVector();
  156. this._listenersMap[listenerID] = listeners;
  157. }
  158. listeners.push(listener);
  159. if (listener._getFixedPriority() == 0) {
  160. this._setDirty(listenerID, this.DIRTY_SCENE_GRAPH_PRIORITY);
  161. var node = listener._getSceneGraphPriority();
  162. if (node == null)
  163. cc.log(cc._LogInfos.eventManager__forceAddEventListener);
  164. this._associateNodeAndEventListener(node, listener);
  165. if (node.isRunning())
  166. this.resumeTarget(node);
  167. } else
  168. this._setDirty(listenerID, this.DIRTY_FIXED_PRIORITY);
  169. },
  170. _getListeners: function (listenerID) {
  171. return this._listenersMap[listenerID];
  172. },
  173. _updateDirtyFlagForSceneGraph: function () {
  174. if (this._dirtyNodes.length == 0)
  175. return;
  176. var locDirtyNodes = this._dirtyNodes, selListeners, selListener, locNodeListenersMap = this._nodeListenersMap;
  177. for (var i = 0, len = locDirtyNodes.length; i < len; i++) {
  178. selListeners = locNodeListenersMap[locDirtyNodes[i].__instanceId];
  179. if (selListeners) {
  180. for (var j = 0, listenersLen = selListeners.length; j < listenersLen; j++) {
  181. selListener = selListeners[j];
  182. if (selListener)
  183. this._setDirty(selListener._getListenerID(), this.DIRTY_SCENE_GRAPH_PRIORITY);
  184. }
  185. }
  186. }
  187. this._dirtyNodes.length = 0;
  188. },
  189. _removeAllListenersInVector: function (listenerVector) {
  190. if (!listenerVector)
  191. return;
  192. var selListener;
  193. for (var i = 0; i < listenerVector.length;) {
  194. selListener = listenerVector[i];
  195. selListener._setRegistered(false);
  196. if (selListener._getSceneGraphPriority() != null){
  197. this._dissociateNodeAndEventListener(selListener._getSceneGraphPriority(), selListener);
  198. selListener._setSceneGraphPriority(null); // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
  199. }
  200. if (this._inDispatch === 0)
  201. cc.arrayRemoveObject(listenerVector, selListener);
  202. else
  203. ++i;
  204. }
  205. },
  206. _removeListenersForListenerID: function (listenerID) {
  207. var listeners = this._listenersMap[listenerID], i;
  208. if (listeners) {
  209. var fixedPriorityListeners = listeners.getFixedPriorityListeners();
  210. var sceneGraphPriorityListeners = listeners.getSceneGraphPriorityListeners();
  211. this._removeAllListenersInVector(sceneGraphPriorityListeners);
  212. this._removeAllListenersInVector(fixedPriorityListeners);
  213. // Remove the dirty flag according the 'listenerID'.
  214. // No need to check whether the dispatcher is dispatching event.
  215. delete this._priorityDirtyFlagMap[listenerID];
  216. if (!this._inDispatch) {
  217. listeners.clear();
  218. delete this._listenersMap[listenerID];
  219. }
  220. }
  221. var locToAddedListeners = this._toAddedListeners, listener;
  222. for (i = 0; i < locToAddedListeners.length;) {
  223. listener = locToAddedListeners[i];
  224. if (listener && listener._getListenerID() == listenerID)
  225. cc.arrayRemoveObject(locToAddedListeners, listener);
  226. else
  227. ++i;
  228. }
  229. },
  230. _sortEventListeners: function (listenerID) {
  231. var dirtyFlag = this.DIRTY_NONE, locFlagMap = this._priorityDirtyFlagMap;
  232. if (locFlagMap[listenerID])
  233. dirtyFlag = locFlagMap[listenerID];
  234. if (dirtyFlag != this.DIRTY_NONE) {
  235. // Clear the dirty flag first, if `rootNode` is null, then set its dirty flag of scene graph priority
  236. locFlagMap[listenerID] = this.DIRTY_NONE;
  237. if (dirtyFlag & this.DIRTY_FIXED_PRIORITY)
  238. this._sortListenersOfFixedPriority(listenerID);
  239. if (dirtyFlag & this.DIRTY_SCENE_GRAPH_PRIORITY){
  240. var rootNode = cc.director.getRunningScene();
  241. if(rootNode)
  242. this._sortListenersOfSceneGraphPriority(listenerID, rootNode);
  243. else
  244. locFlagMap[listenerID] = this.DIRTY_SCENE_GRAPH_PRIORITY;
  245. }
  246. }
  247. },
  248. _sortListenersOfSceneGraphPriority: function (listenerID, rootNode) {
  249. var listeners = this._getListeners(listenerID);
  250. if (!listeners)
  251. return;
  252. var sceneGraphListener = listeners.getSceneGraphPriorityListeners();
  253. if(!sceneGraphListener || sceneGraphListener.length === 0)
  254. return;
  255. // Reset priority index
  256. this._nodePriorityIndex = 0;
  257. this._nodePriorityMap = {};
  258. this._visitTarget(rootNode, true);
  259. // After sort: priority < 0, > 0
  260. listeners.getSceneGraphPriorityListeners().sort(this._sortEventListenersOfSceneGraphPriorityDes);
  261. },
  262. _sortEventListenersOfSceneGraphPriorityDes : function(l1, l2){
  263. var locNodePriorityMap = cc.eventManager._nodePriorityMap;
  264. if(!l1 || !l2 || !l1._getSceneGraphPriority() || !l2._getSceneGraphPriority())
  265. return -1;
  266. return locNodePriorityMap[l2._getSceneGraphPriority().__instanceId] - locNodePriorityMap[l1._getSceneGraphPriority().__instanceId];
  267. },
  268. _sortListenersOfFixedPriority: function (listenerID) {
  269. var listeners = this._listenersMap[listenerID];
  270. if (!listeners)
  271. return;
  272. var fixedListeners = listeners.getFixedPriorityListeners();
  273. if(!fixedListeners || fixedListeners.length === 0)
  274. return;
  275. // After sort: priority < 0, > 0
  276. fixedListeners.sort(this._sortListenersOfFixedPriorityAsc);
  277. // FIXME: Should use binary search
  278. var index = 0;
  279. for (var len = fixedListeners.length; index < len;) {
  280. if (fixedListeners[index]._getFixedPriority() >= 0)
  281. break;
  282. ++index;
  283. }
  284. listeners.gt0Index = index;
  285. },
  286. _sortListenersOfFixedPriorityAsc: function (l1, l2) {
  287. return l1._getFixedPriority() - l2._getFixedPriority();
  288. },
  289. _onUpdateListeners: function (listenerID) {
  290. var listeners = this._listenersMap[listenerID];
  291. if (!listeners)
  292. return;
  293. var fixedPriorityListeners = listeners.getFixedPriorityListeners();
  294. var sceneGraphPriorityListeners = listeners.getSceneGraphPriorityListeners();
  295. var i, selListener;
  296. if (sceneGraphPriorityListeners) {
  297. for (i = 0; i < sceneGraphPriorityListeners.length;) {
  298. selListener = sceneGraphPriorityListeners[i];
  299. if (!selListener._isRegistered()) {
  300. cc.arrayRemoveObject(sceneGraphPriorityListeners, selListener);
  301. } else
  302. ++i;
  303. }
  304. }
  305. if (fixedPriorityListeners) {
  306. for (i = 0; i < fixedPriorityListeners.length;) {
  307. selListener = fixedPriorityListeners[i];
  308. if (!selListener._isRegistered())
  309. cc.arrayRemoveObject(fixedPriorityListeners, selListener);
  310. else
  311. ++i;
  312. }
  313. }
  314. if (sceneGraphPriorityListeners && sceneGraphPriorityListeners.length === 0)
  315. listeners.clearSceneGraphListeners();
  316. if (fixedPriorityListeners && fixedPriorityListeners.length === 0)
  317. listeners.clearFixedListeners();
  318. },
  319. _updateListeners: function (event) {
  320. var locInDispatch = this._inDispatch;
  321. cc.assert(locInDispatch > 0, cc._LogInfos.EventManager__updateListeners);
  322. if (event.getType() == cc.Event.TOUCH) {
  323. this._onUpdateListeners(cc._EventListenerTouchOneByOne.LISTENER_ID);
  324. this._onUpdateListeners(cc._EventListenerTouchAllAtOnce.LISTENER_ID);
  325. } else
  326. this._onUpdateListeners(cc.__getListenerID(event));
  327. if(locInDispatch > 1)
  328. return;
  329. cc.assert(locInDispatch == 1, cc._LogInfos.EventManager__updateListeners_2);
  330. var locListenersMap = this._listenersMap, locPriorityDirtyFlagMap = this._priorityDirtyFlagMap;
  331. for (var selKey in locListenersMap) {
  332. if (locListenersMap[selKey].empty()) {
  333. delete locPriorityDirtyFlagMap[selKey];
  334. delete locListenersMap[selKey];
  335. }
  336. }
  337. var locToAddedListeners = this._toAddedListeners;
  338. if (locToAddedListeners.length !== 0) {
  339. for (var i = 0, len = locToAddedListeners.length; i < len; i++)
  340. this._forceAddEventListener(locToAddedListeners[i]);
  341. this._toAddedListeners.length = 0;
  342. }
  343. },
  344. _onTouchEventCallback: function(listener, argsObj){
  345. // Skip if the listener was removed.
  346. if (!listener._isRegistered)
  347. return false;
  348. var event = argsObj.event, selTouch = argsObj.selTouch;
  349. event._setCurrentTarget(listener._node);
  350. var isClaimed = false, removedIdx;
  351. var getCode = event.getEventCode(), eventCode = cc.EventTouch.EventCode;
  352. if (getCode == eventCode.BEGAN) {
  353. if (listener.onTouchBegan) {
  354. isClaimed = listener.onTouchBegan(selTouch, event);
  355. if (isClaimed && listener._registered)
  356. listener._claimedTouches.push(selTouch);
  357. }
  358. } else if (listener._claimedTouches.length > 0
  359. && ((removedIdx = listener._claimedTouches.indexOf(selTouch)) != -1)) {
  360. isClaimed = true;
  361. if(getCode === eventCode.MOVED && listener.onTouchMoved){
  362. listener.onTouchMoved(selTouch, event);
  363. } else if(getCode === eventCode.ENDED){
  364. if (listener.onTouchEnded)
  365. listener.onTouchEnded(selTouch, event);
  366. if (listener._registered)
  367. listener._claimedTouches.splice(removedIdx, 1);
  368. } else if(getCode === eventCode.CANCELLED){
  369. if (listener.onTouchCancelled)
  370. listener.onTouchCancelled(selTouch, event);
  371. if (listener._registered)
  372. listener._claimedTouches.splice(removedIdx, 1);
  373. }
  374. }
  375. // If the event was stopped, return directly.
  376. if (event.isStopped()) {
  377. cc.eventManager._updateListeners(event);
  378. return true;
  379. }
  380. if (isClaimed && listener._registered && listener.swallowTouches) {
  381. if (argsObj.needsMutableSet)
  382. argsObj.touches.splice(selTouch, 1);
  383. return true;
  384. }
  385. return false;
  386. },
  387. _dispatchTouchEvent: function (event) {
  388. this._sortEventListeners(cc._EventListenerTouchOneByOne.LISTENER_ID);
  389. this._sortEventListeners(cc._EventListenerTouchAllAtOnce.LISTENER_ID);
  390. var oneByOneListeners = this._getListeners(cc._EventListenerTouchOneByOne.LISTENER_ID);
  391. var allAtOnceListeners = this._getListeners(cc._EventListenerTouchAllAtOnce.LISTENER_ID);
  392. // If there aren't any touch listeners, return directly.
  393. if (null == oneByOneListeners && null == allAtOnceListeners)
  394. return;
  395. var originalTouches = event.getTouches(), mutableTouches = cc.copyArray(originalTouches);
  396. var oneByOneArgsObj = {event: event, needsMutableSet: (oneByOneListeners && allAtOnceListeners), touches: mutableTouches, selTouch: null};
  397. //
  398. // process the target handlers 1st
  399. //
  400. if (oneByOneListeners) {
  401. for (var i = 0; i < originalTouches.length; i++) {
  402. oneByOneArgsObj.selTouch = originalTouches[i];
  403. this._dispatchEventToListeners(oneByOneListeners, this._onTouchEventCallback, oneByOneArgsObj);
  404. if (event.isStopped())
  405. return;
  406. }
  407. }
  408. //
  409. // process standard handlers 2nd
  410. //
  411. if (allAtOnceListeners && mutableTouches.length > 0) {
  412. this._dispatchEventToListeners(allAtOnceListeners, this._onTouchesEventCallback, {event: event, touches: mutableTouches});
  413. if (event.isStopped())
  414. return;
  415. }
  416. this._updateListeners(event);
  417. },
  418. _onTouchesEventCallback: function (listener, callbackParams) {
  419. // Skip if the listener was removed.
  420. if (!listener._registered)
  421. return false;
  422. var eventCode = cc.EventTouch.EventCode, event = callbackParams.event, touches = callbackParams.touches, getCode = event.getEventCode();
  423. event._setCurrentTarget(listener._node);
  424. if(getCode == eventCode.BEGAN && listener.onTouchesBegan)
  425. listener.onTouchesBegan(touches, event);
  426. else if(getCode == eventCode.MOVED && listener.onTouchesMoved)
  427. listener.onTouchesMoved(touches, event);
  428. else if(getCode == eventCode.ENDED && listener.onTouchesEnded)
  429. listener.onTouchesEnded(touches, event);
  430. else if(getCode == eventCode.CANCELLED && listener.onTouchesCancelled)
  431. listener.onTouchesCancelled(touches, event);
  432. // If the event was stopped, return directly.
  433. if (event.isStopped()) {
  434. cc.eventManager._updateListeners(event);
  435. return true;
  436. }
  437. return false;
  438. },
  439. _associateNodeAndEventListener: function (node, listener) {
  440. var listeners = this._nodeListenersMap[node.__instanceId];
  441. if (!listeners) {
  442. listeners = [];
  443. this._nodeListenersMap[node.__instanceId] = listeners;
  444. }
  445. listeners.push(listener);
  446. },
  447. _dissociateNodeAndEventListener: function (node, listener) {
  448. var listeners = this._nodeListenersMap[node.__instanceId];
  449. if (listeners) {
  450. cc.arrayRemoveObject(listeners, listener);
  451. if (listeners.length === 0)
  452. delete this._nodeListenersMap[node.__instanceId];
  453. }
  454. },
  455. _dispatchEventToListeners: function (listeners, onEvent, eventOrArgs) {
  456. var shouldStopPropagation = false;
  457. var fixedPriorityListeners = listeners.getFixedPriorityListeners();
  458. var sceneGraphPriorityListeners = listeners.getSceneGraphPriorityListeners();
  459. var i = 0, j, selListener;
  460. if (fixedPriorityListeners) { // priority < 0
  461. if (fixedPriorityListeners.length !== 0) {
  462. for (; i < listeners.gt0Index; ++i) {
  463. selListener = fixedPriorityListeners[i];
  464. if (selListener.isEnabled() && !selListener._isPaused() && selListener._isRegistered() && onEvent(selListener, eventOrArgs)) {
  465. shouldStopPropagation = true;
  466. break;
  467. }
  468. }
  469. }
  470. }
  471. if (sceneGraphPriorityListeners && !shouldStopPropagation) { // priority == 0, scene graph priority
  472. for (j = 0; j < sceneGraphPriorityListeners.length; j++) {
  473. selListener = sceneGraphPriorityListeners[j];
  474. if (selListener.isEnabled() && !selListener._isPaused() && selListener._isRegistered() && onEvent(selListener, eventOrArgs)) {
  475. shouldStopPropagation = true;
  476. break;
  477. }
  478. }
  479. }
  480. if (fixedPriorityListeners && !shouldStopPropagation) { // priority > 0
  481. for (; i < fixedPriorityListeners.length; ++i) {
  482. selListener = fixedPriorityListeners[i];
  483. if (selListener.isEnabled() && !selListener._isPaused() && selListener._isRegistered() && onEvent(selListener, eventOrArgs)) {
  484. shouldStopPropagation = true;
  485. break;
  486. }
  487. }
  488. }
  489. },
  490. _setDirty: function (listenerID, flag) {
  491. var locDirtyFlagMap = this._priorityDirtyFlagMap;
  492. if (locDirtyFlagMap[listenerID] == null)
  493. locDirtyFlagMap[listenerID] = flag;
  494. else
  495. locDirtyFlagMap[listenerID] = flag | locDirtyFlagMap[listenerID];
  496. },
  497. _visitTarget: function (node, isRootNode) {
  498. var children = node.getChildren(), i = 0;
  499. var childrenCount = children.length, locGlobalZOrderNodeMap = this._globalZOrderNodeMap, locNodeListenersMap = this._nodeListenersMap;
  500. if (childrenCount > 0) {
  501. var child;
  502. // visit children zOrder < 0
  503. for (; i < childrenCount; i++) {
  504. child = children[i];
  505. if (child && child.getLocalZOrder() < 0)
  506. this._visitTarget(child, false);
  507. else
  508. break;
  509. }
  510. if (locNodeListenersMap[node.__instanceId] != null) {
  511. if (!locGlobalZOrderNodeMap[node.getGlobalZOrder()])
  512. locGlobalZOrderNodeMap[node.getGlobalZOrder()] = [];
  513. locGlobalZOrderNodeMap[node.getGlobalZOrder()].push(node.__instanceId);
  514. }
  515. for (; i < childrenCount; i++) {
  516. child = children[i];
  517. if (child)
  518. this._visitTarget(child, false);
  519. }
  520. } else {
  521. if (locNodeListenersMap[node.__instanceId] != null) {
  522. if (!locGlobalZOrderNodeMap[node.getGlobalZOrder()])
  523. locGlobalZOrderNodeMap[node.getGlobalZOrder()] = [];
  524. locGlobalZOrderNodeMap[node.getGlobalZOrder()].push(node.__instanceId);
  525. }
  526. }
  527. if (isRootNode) {
  528. var globalZOrders = [];
  529. for (var selKey in locGlobalZOrderNodeMap)
  530. globalZOrders.push(selKey);
  531. globalZOrders.sort(this._sortNumberAsc);
  532. var zOrdersLen = globalZOrders.length, selZOrders, j, locNodePriorityMap = this._nodePriorityMap;
  533. for (i = 0; i < zOrdersLen; i++) {
  534. selZOrders = locGlobalZOrderNodeMap[globalZOrders[i]];
  535. for (j = 0; j < selZOrders.length; j++)
  536. locNodePriorityMap[selZOrders[j]] = ++this._nodePriorityIndex;
  537. }
  538. this._globalZOrderNodeMap = {};
  539. }
  540. },
  541. _sortNumberAsc : function (a, b) {
  542. return a - b;
  543. },
  544. /**
  545. * <p>
  546. * Adds a event listener for a specified event. <br/>
  547. * if the parameter "nodeOrPriority" is a node, it means to add a event listener for a specified event with the priority of scene graph. <br/>
  548. * if the parameter "nodeOrPriority" is a Number, it means to add a event listener for a specified event with the fixed priority. <br/>
  549. * </p>
  550. * @param {cc.EventListener|Object} listener The listener of a specified event or a object of some event parameters.
  551. * @param {cc.Node|Number} nodeOrPriority The priority of the listener is based on the draw order of this node or fixedPriority The fixed priority of the listener.
  552. * @note The priority of scene graph will be fixed value 0. So the order of listener item in the vector will be ' <0, scene graph (0 priority), >0'.
  553. * A lower priority will be called before the ones that have a higher value. 0 priority is forbidden for fixed priority since it's used for scene graph based priority.
  554. * The listener must be a cc.EventListener object when adding a fixed priority listener, because we can't remove a fixed priority listener without the listener handler,
  555. * except calls removeAllListeners().
  556. */
  557. addListener: function (listener, nodeOrPriority) {
  558. cc.assert(listener && nodeOrPriority, cc._LogInfos.eventManager_addListener_2);
  559. if(!(listener instanceof cc.EventListener)){
  560. cc.assert(typeof nodeOrPriority !== "number", cc._LogInfos.eventManager_addListener_3);
  561. listener = cc.EventListener.create(listener);
  562. } else {
  563. if(listener._isRegistered()){
  564. cc.log(cc._LogInfos.eventManager_addListener_4);
  565. return;
  566. }
  567. }
  568. if (!listener.checkAvailable())
  569. return;
  570. if (typeof nodeOrPriority == "number") {
  571. if (nodeOrPriority == 0) {
  572. cc.log(cc._LogInfos.eventManager_addListener);
  573. return;
  574. }
  575. listener._setSceneGraphPriority(null);
  576. listener._setFixedPriority(nodeOrPriority);
  577. listener._setRegistered(true);
  578. listener._setPaused(false);
  579. this._addListener(listener);
  580. } else {
  581. listener._setSceneGraphPriority(nodeOrPriority);
  582. listener._setFixedPriority(0);
  583. listener._setRegistered(true);
  584. this._addListener(listener);
  585. }
  586. },
  587. /**
  588. * Adds a Custom event listener. It will use a fixed priority of 1.
  589. * @param {string} eventName
  590. * @param {function} callback
  591. * @return {cc.EventListener} the generated event. Needed in order to remove the event from the dispatcher
  592. */
  593. addCustomListener: function (eventName, callback) {
  594. var listener = cc._EventListenerCustom.create(eventName, callback);
  595. this.addListener(listener, 1);
  596. return listener;
  597. },
  598. /**
  599. * Remove a listener
  600. * @param {cc.EventListener} listener an event listener or a registered node target
  601. */
  602. removeListener: function (listener) {
  603. if (listener == null)
  604. return;
  605. var isFound, locListener = this._listenersMap;
  606. for (var selKey in locListener) {
  607. var listeners = locListener[selKey];
  608. var fixedPriorityListeners = listeners.getFixedPriorityListeners(), sceneGraphPriorityListeners = listeners.getSceneGraphPriorityListeners();
  609. isFound = this._removeListenerInVector(sceneGraphPriorityListeners, listener);
  610. if (isFound){
  611. // fixed #4160: Dirty flag need to be updated after listeners were removed.
  612. this._setDirty(listener._getListenerID(), this.DIRTY_SCENE_GRAPH_PRIORITY);
  613. }else{
  614. isFound = this._removeListenerInVector(fixedPriorityListeners, listener);
  615. if (isFound)
  616. this._setDirty(listener._getListenerID(), this.DIRTY_FIXED_PRIORITY);
  617. }
  618. if (listeners.empty()) {
  619. delete this._priorityDirtyFlagMap[listener._getListenerID()];
  620. delete locListener[selKey];
  621. }
  622. if (isFound)
  623. break;
  624. }
  625. if (!isFound) {
  626. var locToAddedListeners = this._toAddedListeners;
  627. for (var i = 0, len = locToAddedListeners.length; i < len; i++) {
  628. var selListener = locToAddedListeners[i];
  629. if (selListener == listener) {
  630. cc.arrayRemoveObject(locToAddedListeners, selListener);
  631. break;
  632. }
  633. }
  634. }
  635. },
  636. _removeListenerInVector : function(listeners, listener){
  637. if (listeners == null)
  638. return false;
  639. for (var i = 0, len = listeners.length; i < len; i++) {
  640. var selListener = listeners[i];
  641. if (selListener == listener) {
  642. selListener._setRegistered(false);
  643. if (selListener._getSceneGraphPriority() != null){
  644. this._dissociateNodeAndEventListener(selListener._getSceneGraphPriority(), selListener);
  645. selListener._setSceneGraphPriority(null); // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
  646. }
  647. if (this._inDispatch == 0)
  648. cc.arrayRemoveObject(listeners, selListener);
  649. return true;
  650. }
  651. }
  652. return false;
  653. },
  654. /**
  655. * Removes all listeners with the same event listener type or removes all listeners of a node
  656. * @param {Number|cc.Node} listenerType listenerType or a node
  657. * @param {Boolean} [recursive=false]
  658. */
  659. removeListeners: function (listenerType, recursive) {
  660. var _t = this;
  661. if (listenerType instanceof cc.Node) {
  662. // Ensure the node is removed from these immediately also.
  663. // Don't want any dangling pointers or the possibility of dealing with deleted objects..
  664. delete _t._nodePriorityMap[listenerType.__instanceId];
  665. cc.arrayRemoveObject(_t._dirtyNodes, listenerType);
  666. var listeners = _t._nodeListenersMap[listenerType.__instanceId], i;
  667. if (listeners) {
  668. var listenersCopy = cc.copyArray(listeners);
  669. for (i = 0; i < listenersCopy.length; i++)
  670. _t.removeListener(listenersCopy[i]);
  671. listenersCopy.length = 0;
  672. }
  673. // Bug fix: ensure there are no references to the node in the list of listeners to be added.
  674. // If we find any listeners associated with the destroyed node in this list then remove them.
  675. // This is to catch the scenario where the node gets destroyed before it's listener
  676. // is added into the event dispatcher fully. This could happen if a node registers a listener
  677. // and gets destroyed while we are dispatching an event (touch etc.)
  678. var locToAddedListeners = _t._toAddedListeners;
  679. for (i = 0; i < locToAddedListeners.length; ) {
  680. var listener = locToAddedListeners[i];
  681. if (listener._getSceneGraphPriority() == listenerType) {
  682. listener._setSceneGraphPriority(null); // Ensure no dangling ptr to the target node.
  683. listener._setRegistered(false);
  684. locToAddedListeners.splice(i, 1);
  685. } else
  686. ++i;
  687. }
  688. if (recursive === true) {
  689. var locChildren = listenerType.getChildren(), len;
  690. for (i = 0, len = locChildren.length; i< len; i++)
  691. _t.removeListeners(locChildren[i], true);
  692. }
  693. } else {
  694. if (listenerType == cc.EventListener.TOUCH_ONE_BY_ONE)
  695. _t._removeListenersForListenerID(cc._EventListenerTouchOneByOne.LISTENER_ID);
  696. else if (listenerType == cc.EventListener.TOUCH_ALL_AT_ONCE)
  697. _t._removeListenersForListenerID(cc._EventListenerTouchAllAtOnce.LISTENER_ID);
  698. else if (listenerType == cc.EventListener.MOUSE)
  699. _t._removeListenersForListenerID(cc._EventListenerMouse.LISTENER_ID);
  700. else if (listenerType == cc.EventListener.ACCELERATION)
  701. _t._removeListenersForListenerID(cc._EventListenerAcceleration.LISTENER_ID);
  702. else if (listenerType == cc.EventListener.KEYBOARD)
  703. _t._removeListenersForListenerID(cc._EventListenerKeyboard.LISTENER_ID);
  704. else
  705. cc.log(cc._LogInfos.eventManager_removeListeners);
  706. }
  707. },
  708. /**
  709. * Removes all custom listeners with the same event name
  710. * @param {string} customEventName
  711. */
  712. removeCustomListeners: function (customEventName) {
  713. this._removeListenersForListenerID(customEventName);
  714. },
  715. /**
  716. * Removes all listeners
  717. */
  718. removeAllListeners: function () {
  719. var locListeners = this._listenersMap, locInternalCustomEventIDs = this._internalCustomListenerIDs;
  720. for (var selKey in locListeners){
  721. if(locInternalCustomEventIDs.indexOf(selKey) === -1)
  722. this._removeListenersForListenerID(selKey);
  723. }
  724. },
  725. /**
  726. * Sets listener's priority with fixed value.
  727. * @param {cc.EventListener} listener
  728. * @param {Number} fixedPriority
  729. */
  730. setPriority: function (listener, fixedPriority) {
  731. if (listener == null)
  732. return;
  733. var locListeners = this._listenersMap;
  734. for (var selKey in locListeners) {
  735. var selListeners = locListeners[selKey];
  736. var fixedPriorityListeners = selListeners.getFixedPriorityListeners();
  737. if (fixedPriorityListeners) {
  738. var found = fixedPriorityListeners.indexOf(listener);
  739. if (found != -1) {
  740. if(listener._getSceneGraphPriority() != null)
  741. cc.log(cc._LogInfos.eventManager_setPriority);
  742. if (listener._getFixedPriority() !== fixedPriority) {
  743. listener._setFixedPriority(fixedPriority);
  744. this._setDirty(listener._getListenerID(), this.DIRTY_FIXED_PRIORITY);
  745. }
  746. return;
  747. }
  748. }
  749. }
  750. },
  751. /**
  752. * Whether to enable dispatching events
  753. * @param {boolean} enabled
  754. */
  755. setEnabled: function (enabled) {
  756. this._isEnabled = enabled;
  757. },
  758. /**
  759. * Checks whether dispatching events is enabled
  760. * @returns {boolean}
  761. */
  762. isEnabled: function () {
  763. return this._isEnabled;
  764. },
  765. /**
  766. * Dispatches the event, also removes all EventListeners marked for deletion from the event dispatcher list.
  767. * @param {cc.Event} event
  768. */
  769. dispatchEvent: function (event) {
  770. if (!this._isEnabled)
  771. return;
  772. this._updateDirtyFlagForSceneGraph();
  773. this._inDispatch++;
  774. if(!event || !event.getType)
  775. throw "event is undefined";
  776. if (event.getType() == cc.Event.TOUCH) {
  777. this._dispatchTouchEvent(event);
  778. this._inDispatch--;
  779. return;
  780. }
  781. var listenerID = cc.__getListenerID(event);
  782. this._sortEventListeners(listenerID);
  783. var selListeners = this._listenersMap[listenerID];
  784. if (selListeners != null)
  785. this._dispatchEventToListeners(selListeners, this._onListenerCallback, event);
  786. this._updateListeners(event);
  787. this._inDispatch--;
  788. },
  789. _onListenerCallback: function(listener, event){
  790. event._setCurrentTarget(listener._getSceneGraphPriority());
  791. listener._onEvent(event);
  792. return event.isStopped();
  793. },
  794. /**
  795. * Dispatches a Custom Event with a event name an optional user data
  796. * @param {string} eventName
  797. * @param {*} optionalUserData
  798. */
  799. dispatchCustomEvent: function (eventName, optionalUserData) {
  800. var ev = new cc.EventCustom(eventName);
  801. ev.setUserData(optionalUserData);
  802. this.dispatchEvent(ev);
  803. }
  804. };