.h #ifndef __CC_EVENT_DISPATCHER_H__ #define __CC_EVENT_DISPATCHER_H__ #include "CCPlatformMacros.h" #include "CCEventListener.h" #include "CCEvent.h" #include <functional> #include <string> #include <unordered_map> #include <list> #include <vector> NS_CC_BEGIN class Event; class EventTouch; class Node; /** 管理 event listener 服务以及事件分发 (event dispatching). The EventListener list is managed in such a way that event listeners can be added and removed even from within an EventListener, while events are being dispatched. */ class EventDispatcher : public Object { public: /** 注册监听事件 (优先级 基于 Node绘制顺序 ) * 在消息路由时,先处理优先级<0的,在处理优先级=0(按Node绘制顺序),最后处理优先级>0的 * @param listener 监听器 * @param node 监听的node * @note fixedProprity必须是0 */ void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node); /** 注册监听事件 (指定优先级) * @param listener The listener of a specified event. * @param fixedPriority The fixed priority of the listener. * @note 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. */ void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority); /** 删除某一个监听器 * @param listener The specified event listener which needs to be removed. */ void removeEventListener(EventListener* listener); /** 删除某一类监听器 */ void removeEventListeners(EventListener::Type listenerType); /** Removes all custom listeners with the same event name */ void removeCustomEventListeners(const std::string& customEventName); /** 删除所有监听器 */ void removeAllEventListeners(); /** 修改某监听器的优先级 */ void setPriority(EventListener* listener, int fixedPriority); /** 设置事件分发器是否可用 */ void setEnabled(bool isEnabled); /** Checks whether dispatching events is enabled */ bool isEnabled() const; /** 分发事件 * 同时从dispatcher list 中删除标记为deletion的监听器 */ void dispatchEvent(Event* event); /** Constructor of EventDispatcher */ EventDispatcher(); /** Destructor of EventDispatcher */ ~EventDispatcher(); private: friend class Node; /** 将Node记为Dirty 即将Node加入_dirtyNodes*/ void setDirtyForNode(Node* node); /** 跟node相关联的所有listener都暂停 */ void pauseTarget(Node* node); /** 跟node相关联的所有listener都唤醒 */ void resumeTarget(Node* node); /** 删除所有跟node相关联的listener */ void cleanTarget(Node* node); /** * The vector to store event listeners with scene graph based priority and fixed priority. */ class EventListenerVector { public: EventListenerVector(); ~EventListenerVector(); size_t size() const; bool empty() const; void push_back(EventListener* item); void clearSceneGraphListeners(); void clearFixedListeners(); void clear(); inline std::vector<EventListener*>* getFixedPriorityListeners() const { return _fixedListeners; }; inline std::vector<EventListener*>* getSceneGraphPriorityListeners() const { return _sceneGraphListeners; }; inline long getGt0Index() const { return _gt0Index; }; inline void setGt0Index(long index) { _gt0Index = index; }; private: std::vector<EventListener*>* _fixedListeners; std::vector<EventListener*>* _sceneGraphListeners; long _gt0Index; }; /** Adds event listener with item */ void addEventListener(EventListener* listener); /** Gets event the listener list for the event listener type. */ EventListenerVector* getListeners(EventListener::ListenerID listenerID); /** Update dirty flag */ void updateDirtyFlagForSceneGraph(); /** Removes all listeners with the same event listener ID */ void removeEventListenersForListenerID(EventListener::ListenerID listenerID); /** 排序 */ void sortEventListeners(EventListener::ListenerID listenerID); /** 根据node优先级排序 */ void sortEventListenersOfSceneGraphPriority(EventListener::ListenerID listenerID); /** 根据优先级排序 */ void sortEventListenersOfFixedPriority(EventListener::ListenerID listenerID); /** Updates all listeners * 1) 删除所有标记为 deleted 的监听器. * 2) 添加_toAddedListeners中的监听器. */ void updateListeners(Event* event); /** Touch event needs to be processed different with other events since it needs support ALL_AT_ONCE and ONE_BY_NONE mode. */ void dispatchTouchEvent(EventTouch* event); /** Associates node with event listener */ void associateNodeAndEventListener(Node* node, EventListener* listener); /** Dissociates node with event listener */ void dissociateNodeAndEventListener(Node* node, EventListener* listener); /** Dispatches event to listeners with a specified listener type */ void dispatchEventToListeners(EventListenerVector* listeners, std::function<bool(EventListener*)> onEvent); /// Priority dirty flag enum class DirtyFlag { NONE = 0, FIXED_PRITORY = 1 << 0, SCENE_GRAPH_PRIORITY = 1 << 1, ALL = FIXED_PRITORY | SCENE_GRAPH_PRIORITY }; /** Sets the dirty flag for a specified listener ID */ void setDirty(EventListener::ListenerID listenerID, DirtyFlag flag); /** 遍历场景,获取每个Node的绘制顺序; 此函数在sortEventListenersOfSceneGraphPriority之前调用 */ void visitTarget(Node* node); private: /** map 存储所有监听器 map::key 监听器类型 */ std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listeners; /** map 存储一类监听器是否被污染。 即:按优先级分类,可以把所有监听器分为两类(Node, fixd priority)。 如果_listenner[type] 里的监听器全是Node priority, 则DirtyFlag为SCENE_GRAPH_PRIORITY; 若全为fixd priority 则为 FIXED_PRITORY;若两种都有, 则为ALL = FIXED_PRITORY | SCENE_GRAPH_PRIORITY */ std::unordered_map<EventListener::ListenerID, DirtyFlag> _priorityDirtyFlagMap; /** map 关联Node与监听器 */ std::unordered_map<Node*, std::vector<EventListener*>*> _nodeListenersMap; /** 存储每个Node的优先级(即绘制顺序); 在visitTarge中更新该值, 在sortEventListenersOfSceneGraphPriority中使用该值*/ std::unordered_map<Node*, int> _nodePriorityMap; /** 如果注册监听器时正在dispathch event,则将该监听器加到_toAddedListeners中, 等dispatch完成后,在将其从_toAddedListeners中移到其他容器,*/ std::vector<EventListener*> _toAddedListeners; /** 优先级发生改变的Node 此集合中的Node所对应的Listener所在的那个vector(_listeners[ID])将会重排序*/ std::set<Node*> _dirtyNodes; /** 判断是否正在dispatch */ int _inDispatch; /** Whether to enable dispatching event */ bool _isEnabled; int _nodePriorityIndex; }; NS_CC_END #endif // __CC_EVENT_DISPATCHER_H__ cpp #include "CCEventDispatcher.h" #include "CCEvent.h" #include "CCEventTouch.h" #include "CCEventCustom.h" #include "CCEventListenerTouch.h" #include "CCNode.h" #include "CCDirector.h" #include <algorithm> #define DUMP_LISTENER_ITEM_PRIORITY_INFO 0 namespace { /************************************************************************/ /* 用于自动处理count。 一般用于构造一个局部变量。与指针计数器原理相同。 构造时 +1, 析构时 -1. 若函数中有多处return,而每次renturn前都要处理某变量的值,则可以采用此机制优化代码; 此机制只需利用变量a构造一个局部变量, 无需在每次返回前再处理变量a。 */ class DispatchGuard { public: DispatchGuard(int& count) : _count(count) { ++_count; } ~DispatchGuard() { --_count; } private: int& _count; }; } NS_CC_BEGIN // 根据Event 的type 确定EventListener的Type // 关于EventListener的ListenerId 与 EventListener的Type(注意这里不是Event::Type)映射关系 // 出自定制类型外,其他类型都是用枚举一一映射的,而自定制类型则是计算hash值 static EventListener::ListenerID getListenerID(Event* event) { EventListener::ListenerID ret; switch (event->getType()) { case Event::Type::ACCELERATION: ret = static_cast<EventListener::ListenerID>(EventListener::Type::ACCELERATION); break; case Event::Type::CUSTOM: { auto customEvent = static_cast<EventCustom*>(event); auto listenerID = std::hash<std::string>()(customEvent->getEventName()); ret = static_cast<EventListener::ListenerID>(listenerID); } break; case Event::Type::KEYBOARD: ret = static_cast<EventListener::ListenerID>(EventListener::Type::KEYBOARD); break; case Event::Type::MOUSE: ret = static_cast<EventListener::ListenerID>(EventListener::Type::MOUSE); break; case Event::Type::TOUCH: // Touch listener is very special, it contains two kinds of listeners, EventListenerTouchOneByOne and EventListenerTouchAllAtOnce. // return UNKNOW instead. ret = static_cast<EventListener::ListenerID>(EventListener::Type::UNKNOWN); break; default: CCASSERT(false, "Invalid type!"); break; } return ret; } EventDispatcher::EventListenerVector::EventListenerVector() : _sceneGraphListeners(nullptr) , _fixedListeners(nullptr) , _gt0Index(0) { } EventDispatcher::EventListenerVector::~EventListenerVector() { CC_SAFE_DELETE(_sceneGraphListeners); CC_SAFE_DELETE(_fixedListeners); } size_t EventDispatcher::EventListenerVector::size() const { size_t ret = 0; if (_sceneGraphListeners) ret += _sceneGraphListeners->size(); if (_fixedListeners) ret += _fixedListeners->size(); return ret; } bool EventDispatcher::EventListenerVector::empty() const { return (_sceneGraphListeners == nullptr || _sceneGraphListeners->empty()) && (_fixedListeners == nullptr || _fixedListeners->empty()); } void EventDispatcher::EventListenerVector::push_back(EventListener* listener) { if (listener->getFixedPriority() == 0) { if (_sceneGraphListeners == nullptr) { _sceneGraphListeners = new std::vector<EventListener*>(); _sceneGraphListeners->reserve(100); } _sceneGraphListeners->push_back(listener); } else { if (_fixedListeners == nullptr) { _fixedListeners = new std::vector<EventListener*>(); _fixedListeners->reserve(100); } _fixedListeners->push_back(listener); } } void EventDispatcher::EventListenerVector::clearSceneGraphListeners() { if (_sceneGraphListeners) { _sceneGraphListeners->clear(); delete _sceneGraphListeners; _sceneGraphListeners = nullptr; } } void EventDispatcher::EventListenerVector::clearFixedListeners() { if (_fixedListeners) { _fixedListeners->clear(); delete _fixedListeners; _fixedListeners = nullptr; } } void EventDispatcher::EventListenerVector::clear() { clearSceneGraphListeners(); clearFixedListeners(); } EventDispatcher::EventDispatcher() : _inDispatch(0) , _isEnabled(true) , _nodePriorityIndex(0) { _toAddedListeners.reserve(50); } EventDispatcher::~EventDispatcher() { removeAllEventListeners(); } void EventDispatcher::visitTarget(Node* node) { int i = 0; Array* children = node->getChildren(); int childrenCount = children ? children->count() : 0; if (childrenCount > 0) { Node* child = nullptr; // 只计算子节点中 zOrder < 0 的 for (; i < childrenCount; i++) { child = static_cast<Node*>(children->getObjectAtIndex(i)); if (child && child->getZOrder() < 0) visitTarget(child); else break; } // 记录Node的优先级 _nodePriorityMap.insert(std::make_pair(node, ++_nodePriorityIndex)); for (; i < childrenCount; i++) { child = static_cast<Node*>(children->getObjectAtIndex(i)); if (child) visitTarget(child); } } else { _nodePriorityMap.insert(std::make_pair(node, ++_nodePriorityIndex)); } } void EventDispatcher::pauseTarget(Node* node) { auto listenerIter = _nodeListenersMap.find(node); if (listenerIter != _nodeListenersMap.end()) { auto listeners = listenerIter->second; for (auto& l : *listeners) { l->setPaused(true); } } } void EventDispatcher::resumeTarget(Node* node) { auto listenerIter = _nodeListenersMap.find(node); if (listenerIter != _nodeListenersMap.end()) { auto listeners = listenerIter->second; for (auto& l : *listeners) { l->setPaused(false); } } setDirtyForNode(node); } void EventDispatcher::cleanTarget(Node* node) { auto listenerIter = _nodeListenersMap.find(node); if (listenerIter != _nodeListenersMap.end()) { auto listeners = listenerIter->second; auto listenersCopy = *listeners; for (auto& l : listenersCopy) { removeEventListener(l); } } } void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener) { std::vector<EventListener*>* listeners = nullptr; auto found = _nodeListenersMap.find(node); if (found != _nodeListenersMap.end()) { listeners = found->second; } else { listeners = new std::vector<EventListener*>(); } listeners->push_back(listener); _nodeListenersMap.insert(std::make_pair(node, listeners)); } void EventDispatcher::dissociateNodeAndEventListener(Node* node, EventListener* listener) { std::vector<EventListener*>* listeners = nullptr; auto found = _nodeListenersMap.find(node); if (found != _nodeListenersMap.end()) { listeners = found->second; auto iter = std::find(listeners->begin(), listeners->end(), listener); if (iter != listeners->end()) { listeners->erase(iter); } if (listeners->empty()) { _nodeListenersMap.erase(found); delete listeners; } } } void EventDispatcher::addEventListener(EventListener* listener) { // 如果不是正在路由事件 if (_inDispatch == 0) { EventListenerVector* listenerList = nullptr; // 根据listenerID获取相应vector auto iter = _listeners.find(listener->getListenerID()); if (iter == _listeners.end()) { listenerList = new EventListenerVector(); _listeners.insert(std::make_pair(listener->getListenerID(), listenerList)); } else { listenerList = iter->second; } listenerList->push_back(listener); if (listener->getFixedPriority() == 0) { // 如果优先级根据Node而定 setDirty(listener->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); } else { // 如果优先级根据Fixed而定 setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRITORY); } } else { // 如果正在路由事件,则直接加入_toAddedListeners _toAddedListeners.push_back(listener); } } void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node) { CCASSERT(listener && node, "Invalid parameters."); CCASSERT(!listener->isRegistered(), "The listener has been registered."); if (!listener->checkAvailable()) return; listener->setSceneGraphPriority(node); listener->setFixedPriority(0); listener->setRegistered(true); listener->retain(); // 存储listener, addEventListener(listener); // 关联node与listener associateNodeAndEventListener(node, listener); if (node->isRunning()) { resumeTarget(node); } } void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority) { CCASSERT(listener, "Invalid parameters."); CCASSERT(!listener->isRegistered(), "The listener has been registered."); CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority."); if (!listener->checkAvailable()) return; listener->setSceneGraphPriority(nullptr); listener->setFixedPriority(fixedPriority); listener->setRegistered(true); listener->setPaused(false); listener->retain(); addEventListener(listener); } void EventDispatcher::removeEventListener(EventListener* listener) { if (listener == nullptr) return; bool isFound = false; auto removeListenerInVector = [&](std::vector<EventListener*>* listeners){ if (listeners == nullptr) return; for (auto iter = listeners->begin(); iter != listeners->end(); ++iter) { auto l = *iter; if (l == listener) { CC_SAFE_RETAIN(l); l->setRegistered(false); if (l->getSceneGraphPriority() != nullptr) { // 撤销node与listener的关联 dissociateNodeAndEventListener(l->getSceneGraphPriority(), l); } if (_inDispatch == 0) { listeners->erase(iter); CC_SAFE_RELEASE(l); } isFound = true; break; } } }; for (auto iter = _listeners.begin(); iter != _listeners.end();) { auto listeners = iter->second; auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); removeListenerInVector(sceneGraphPriorityListeners); if (!isFound) { removeListenerInVector(fixedPriorityListeners); } if (iter->second->empty()) { _priorityDirtyFlagMap.erase(listener->getListenerID()); auto list = iter->second; iter = _listeners.erase(iter); CC_SAFE_DELETE(list); } else { ++iter; } if (isFound) break; } if (isFound) { CC_SAFE_RELEASE(listener); } else { // 若没有找到,则在_toAddedListeners中找 for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ++iter) { if (*iter == listener) { _toAddedListeners.erase(iter); break; } } } } void EventDispatcher::setPriority(EventListener* listener, int fixedPriority) { if (listener == nullptr) return; for (auto iter = _listeners.begin(); iter != _listeners.end(); ++iter) { auto fixedPriorityListeners = iter->second->getFixedPriorityListeners(); if (fixedPriorityListeners) { auto found = std::find(fixedPriorityListeners->begin(), fixedPriorityListeners->end(), listener); if (found != fixedPriorityListeners->end()) { CCASSERT(listener->getSceneGraphPriority() == nullptr, "Can't set fixed priority with scene graph based listener."); if (listener->getFixedPriority() != fixedPriority) { listener->setFixedPriority(fixedPriority); setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRITORY); } return; } } } } void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, std::function<bool(EventListener*)> onEvent) { bool shouldStopPropagation = false; auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); long i = 0; // priority < 0 if (fixedPriorityListeners) { for (; !fixedPriorityListeners->empty() && i < listeners->getGt0Index(); ++i) { auto l = fixedPriorityListeners->at(i); if (!l->isPaused() && l->isRegistered() && onEvent(l)) { shouldStopPropagation = true; break; } } } if (sceneGraphPriorityListeners) { if (!shouldStopPropagation) { // priority == 0, scene graph priority for (auto& l : *sceneGraphPriorityListeners) { if (!l->isPaused() && l->isRegistered() && onEvent(l)) { shouldStopPropagation = true; break; } } } } if (fixedPriorityListeners) { if (!shouldStopPropagation) { // priority > 0 for (; i < static_cast<long>(fixedPriorityListeners->size()); ++i) { auto l = fixedPriorityListeners->at(i); if (!l->isPaused() && l->isRegistered() && onEvent(fixedPriorityListeners->at(i))) { shouldStopPropagation = true; break; } } } } } void EventDispatcher::dispatchEvent(Event* event) { if (!_isEnabled) return; updateDirtyFlagForSceneGraph(); DispatchGuard guard(_inDispatch); if (event->getType() == Event::Type::TOUCH) { dispatchTouchEvent(static_cast<EventTouch*>(event)); return; } auto listenerID = getListenerID(event); sortEventListeners(listenerID); auto iter = _listeners.find(listenerID); if (iter != _listeners.end()) { auto listeners = iter->second; auto onEvent = [&event](EventListener* listener) -> bool{ event->setCurrentTarget(listener->getSceneGraphPriority()); listener->_onEvent(event); return event->isStopped(); }; dispatchEventToListeners(listeners, onEvent); } updateListeners(event); } void EventDispatcher::dispatchTouchEvent(EventTouch* event) { auto touchOneByOneID = static_cast<EventListener::ListenerID>(EventListener::Type::TOUCH_ONE_BY_ONE); auto touchAllAtOnceID = static_cast<EventListener::ListenerID>(EventListener::Type::TOUCH_ALL_AT_ONCE); sortEventListeners(touchOneByOneID); sortEventListeners(touchAllAtOnceID); auto oneByOnelisteners = getListeners(touchOneByOneID); auto allAtOncelisteners = getListeners(touchAllAtOnceID); // If there aren't any touch listeners, return directly. if (nullptr == oneByOnelisteners && nullptr == allAtOncelisteners) return; bool isNeedsMutableSet = (oneByOnelisteners && allAtOncelisteners); std::vector<Touch*> orignalTouches = event->getTouches(); std::vector<Touch*> mutableTouches(orignalTouches.size()); std::copy(orignalTouches.begin(), orignalTouches.end(), mutableTouches.begin()); // // process the target handlers 1st // if (oneByOnelisteners) { auto mutableTouchesIter = mutableTouches.begin(); auto touchesIter = orignalTouches.begin(); for (; touchesIter != orignalTouches.end(); ++touchesIter) { bool isSwallowed = false; auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l); // Skip if the listener was removed. if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); bool isClaimed = false; std::vector<Touch*>::iterator removedIter; EventTouch::EventCode eventCode = event->getEventCode(); if (eventCode == EventTouch::EventCode::BEGAN) { if (listener->onTouchBegan) { isClaimed = listener->onTouchBegan(*touchesIter, event); if (isClaimed && listener->_isRegistered) { listener->_claimedTouches.push_back(*touchesIter); } } } else if (listener->_claimedTouches.size() > 0 && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end())) { isClaimed = true; switch (eventCode) { case EventTouch::EventCode::MOVED: if (listener->onTouchMoved) { listener->onTouchMoved(*touchesIter, event); } break; case EventTouch::EventCode::ENDED: if (listener->onTouchEnded) { listener->onTouchEnded(*touchesIter, event); } if (listener->_isRegistered) { listener->_claimedTouches.erase(removedIter); } break; case EventTouch::EventCode::CANCELLED: if (listener->onTouchCancelled) { listener->onTouchCancelled(*touchesIter, event); } if (listener->_isRegistered) { listener->_claimedTouches.erase(removedIter); } break; default: CCASSERT(false, "The eventcode is invalid."); break; } } // If the event was stopped, return directly. if (event->isStopped()) { updateListeners(event); return true; } CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); if (isClaimed && listener->_isRegistered && listener->_needSwallow) { if (isNeedsMutableSet) { mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); isSwallowed = true; } return true; } return false; }; // dispatchEventToListeners(oneByOnelisteners, onTouchEvent); if (event->isStopped()) { return; } if (!isSwallowed) ++mutableTouchesIter; } } // // process standard handlers 2nd // if (allAtOncelisteners && mutableTouches.size() > 0) { auto onTouchesEvent = [&](EventListener* l) -> bool{ EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l); // Skip if the listener was removed. if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); switch (event->getEventCode()) { case EventTouch::EventCode::BEGAN: if (listener->onTouchesBegan) { listener->onTouchesBegan(mutableTouches, event); } break; case EventTouch::EventCode::MOVED: if (listener->onTouchesMoved) { listener->onTouchesMoved(mutableTouches, event); } break; case EventTouch::EventCode::ENDED: if (listener->onTouchesEnded) { listener->onTouchesEnded(mutableTouches, event); } break; case EventTouch::EventCode::CANCELLED: if (listener->onTouchesCancelled) { listener->onTouchesCancelled(mutableTouches, event); } break; default: CCASSERT(false, "The eventcode is invalid."); break; } // If the event was stopped, return directly. if (event->isStopped()) { updateListeners(event); return false; } return false; }; dispatchEventToListeners(allAtOncelisteners, onTouchesEvent); if (event->isStopped()) { return; } } updateListeners(event); } void EventDispatcher::updateListeners(Event* event) { auto onUpdateListeners = [this](EventListener::ListenerID listenerID) { auto listenersIter = _listeners.find(listenerID); if (listenersIter == _listeners.end()) return; auto listeners = listenersIter->second; auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); if (sceneGraphPriorityListeners) { for (auto iter = sceneGraphPriorityListeners->begin(); iter != sceneGraphPriorityListeners->end();) { auto l = *iter; if (!l->isRegistered()) { iter = sceneGraphPriorityListeners->erase(iter); l->release(); } else { ++iter; } } } if (fixedPriorityListeners) { for (auto iter = fixedPriorityListeners->begin(); iter != fixedPriorityListeners->end();) { auto l = *iter; if (!l->isRegistered()) { iter = fixedPriorityListeners->erase(iter); l->release(); } else { ++iter; } } } if (sceneGraphPriorityListeners && sceneGraphPriorityListeners->empty()) { listeners->clearSceneGraphListeners(); } if (fixedPriorityListeners && fixedPriorityListeners->empty()) { listeners->clearFixedListeners(); } if (listenersIter->second->empty()) { _priorityDirtyFlagMap.erase(listenersIter->first); delete listenersIter->second; listenersIter = _listeners.erase(listenersIter); } else { ++listenersIter; } }; if (event->getType() == Event::Type::TOUCH) { onUpdateListeners(static_cast<EventListener::ListenerID>(EventListener::Type::TOUCH_ONE_BY_ONE)); onUpdateListeners(static_cast<EventListener::ListenerID>(EventListener::Type::TOUCH_ALL_AT_ONCE)); } else { onUpdateListeners(getListenerID(event)); } if (!_toAddedListeners.empty()) { EventListenerVector* listeners = nullptr; for (auto& listener : _toAddedListeners) { EventListener::ListenerID listenerID = listener->getListenerID(); auto itr = _listeners.find(listenerID); if (itr == _listeners.end()) { listeners = new EventListenerVector(); _listeners.insert(std::make_pair(listenerID, listeners)); } else { listeners = itr->second; } listeners->push_back(listener); if (listener->getFixedPriority() == 0) { setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY); } else { setDirty(listenerID, DirtyFlag::FIXED_PRITORY); } } _toAddedListeners.clear(); } } void EventDispatcher::updateDirtyFlagForSceneGraph() { if (!_dirtyNodes.empty()) { for (auto& node : _dirtyNodes) { auto iter = _nodeListenersMap.find(node); if (iter != _nodeListenersMap.end()) { for (auto& l : *iter->second) { setDirty(l->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); } } } _dirtyNodes.clear(); } } void EventDispatcher::sortEventListeners(EventListener::ListenerID listenerID) { DirtyFlag dirtyFlag = DirtyFlag::NONE; auto dirtyIter = _priorityDirtyFlagMap.find(listenerID); if (dirtyIter != _priorityDirtyFlagMap.end()) { dirtyFlag = dirtyIter->second; } if (dirtyFlag != DirtyFlag::NONE) { if ((int)dirtyFlag & (int)DirtyFlag::FIXED_PRITORY) { sortEventListenersOfFixedPriority(listenerID); } if ((int)dirtyFlag & (int)DirtyFlag::SCENE_GRAPH_PRIORITY) { sortEventListenersOfSceneGraphPriority(listenerID); } dirtyIter->second = DirtyFlag::NONE; } } void EventDispatcher::sortEventListenersOfSceneGraphPriority(EventListener::ListenerID listenerID) { auto listeners = getListeners(listenerID); if (listeners == nullptr) return; Node* rootNode = (Node*)Director::getInstance()->getRunningScene(); // Reset priority index _nodePriorityIndex = 0; _nodePriorityMap.clear(); visitTarget(rootNode); // After sort: priority < 0, > 0 auto sceneGraphlisteners = listeners->getSceneGraphPriorityListeners(); std::sort(sceneGraphlisteners->begin(), sceneGraphlisteners->end(), [this](const EventListener* l1, const EventListener* l2) { return _nodePriorityMap[l1->getSceneGraphPriority()] > _nodePriorityMap[l2->getSceneGraphPriority()]; }); #if DUMP_LISTENER_ITEM_PRIORITY_INFO log("-----------------------------------"); for (auto& l : *sceneGraphlisteners) { log("listener priority: node ([%s]%p), priority (%d)", typeid(*l->_node).name(), l->_node, _nodePriorityMap[l->_node]); } #endif } void EventDispatcher::sortEventListenersOfFixedPriority(EventListener::ListenerID listenerID) { auto listeners = getListeners(listenerID); if (listeners == nullptr) return; // After sort: priority < 0, > 0 auto fixedlisteners = listeners->getFixedPriorityListeners(); std::sort(fixedlisteners->begin(), fixedlisteners->end(), [](const EventListener* l1, const EventListener* l2) { return l1->getFixedPriority() < l2->getFixedPriority(); }); // FIXME: Should use binary search long index = 0; for (auto& listener : *fixedlisteners) { if (listener->getFixedPriority() >= 0) break; ++index; } listeners->setGt0Index(index); #if DUMP_LISTENER_ITEM_PRIORITY_INFO log("-----------------------------------"); for (auto& l : *fixedlisteners) { log("listener priority: node (%p), fixed (%d)", l->_node, l->_fixedPriority); } #endif } EventDispatcher::EventListenerVector* EventDispatcher::getListeners(EventListener::ListenerID listenerID) { auto iter = _listeners.find(listenerID); if (iter != _listeners.end()) { return iter->second; } return nullptr; } void EventDispatcher::removeEventListenersForListenerID(EventListener::ListenerID listenerID) { auto listenerItemIter = _listeners.find(listenerID); if (listenerItemIter != _listeners.end()) { auto listeners = listenerItemIter->second; auto fixedPriorityListeners = listeners->getFixedPriorityListeners(); auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners(); auto removeAllListenersInVector = [&](std::vector<EventListener*>* listenerVector){ if (listenerVector == nullptr) return; for (auto iter = listenerVector->begin(); iter != listenerVector->end();) { auto l = *iter; l->setRegistered(false); if (l->getSceneGraphPriority() != nullptr) { dissociateNodeAndEventListener(l->getSceneGraphPriority(), l); } if (_inDispatch == 0) { iter = listenerVector->erase(iter); CC_SAFE_RELEASE(l); } else { ++iter; } } }; removeAllListenersInVector(sceneGraphPriorityListeners); removeAllListenersInVector(fixedPriorityListeners); if (!_inDispatch) { listeners->clear(); delete listeners; _listeners.erase(listenerItemIter); _priorityDirtyFlagMap.erase(listenerID); } } for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end();) { if ((*iter)->getListenerID() == listenerID) { iter = _toAddedListeners.erase(iter); } else { ++iter; } } } void EventDispatcher::removeEventListeners(EventListener::Type listenerType) { CCASSERT(listenerType != EventListener::Type::CUSTOM, "Not support custom event listener type, please use EventDispatcher::removeCustomEventListeners instead."); removeEventListenersForListenerID(static_cast<EventListener::ListenerID>(listenerType)); } void EventDispatcher::removeCustomEventListeners(const std::string& customEventName) { removeEventListenersForListenerID(std::hash<std::string>()(customEventName)); } void EventDispatcher::removeAllEventListeners() { std::vector<int> types(_listeners.size()); for (auto iter = _listeners.begin(); iter != _listeners.end(); ++iter) { types.push_back(iter->first); } for (auto& type : types) { removeEventListenersForListenerID(type); } if (!_inDispatch) { _listeners.clear(); } } void EventDispatcher::setEnabled(bool isEnabled) { _isEnabled = isEnabled; } bool EventDispatcher::isEnabled() const { return _isEnabled; } void EventDispatcher::setDirtyForNode(Node* node) { // Mark the node dirty only when there was an eventlistener associates with it. if (_nodeListenersMap.find(node) != _nodeListenersMap.end()) { _dirtyNodes.insert(node); } } void EventDispatcher::setDirty(EventListener::ListenerID listenerID, DirtyFlag flag) { auto iter = _priorityDirtyFlagMap.find(listenerID); if (iter == _priorityDirtyFlagMap.end()) { _priorityDirtyFlagMap.insert(std::make_pair(listenerID, flag)); } else { int ret = (int)flag | (int)iter->second; iter->second = (DirtyFlag)ret; } } NS_CC_END
cocos2dx-3.0 : EventDispatcher
最新推荐文章于 2020-03-23 15:09:42 发布