issue #2087: Sorts listeners only when flag is dirty. setPriority is only valid in fixed priority listener.

This commit is contained in:
James Chen 2013-09-18 17:45:25 +08:00
parent d38dee32a0
commit f7fa92aea9
7 changed files with 133 additions and 105 deletions

View File

@ -825,7 +825,7 @@ void Node::visit()
}
// self draw
this->draw();
_eventPriority = ++_globalEventPriorityIndex;
updateEventPriorityIndex();
for( ; i < _children->count(); i++ )
{
@ -837,7 +837,7 @@ void Node::visit()
else
{
this->draw();
_eventPriority = ++_globalEventPriorityIndex;
updateEventPriorityIndex();
}
// reset for next frame
@ -1317,6 +1317,16 @@ void Node::removeAllEventListeners()
}
}
void Node::setDirtyForAllEventListeners()
{
auto dispatcher = EventDispatcher::getInstance();
for (auto& listener : _eventlisteners)
{
dispatcher->setDirtyForEventType(listener->type, true);
}
}
// NodeRGBA
NodeRGBA::NodeRGBA()
: _displayedOpacity(255)

View File

@ -1382,11 +1382,21 @@ private:
protected:
/// Upates event priority for this node.
inline void updateEventPriorityIndex() { _eventPriority = ++_globalEventPriorityIndex; };
inline void updateEventPriorityIndex() {
_oldEventPriority = _eventPriority;
_eventPriority = ++_globalEventPriorityIndex;
if (_oldEventPriority != _eventPriority)
{
setDirtyForAllEventListeners();
}
};
/// Removes all event listeners that associated with this node.
void removeAllEventListeners();
/// Sets dirty for event listener.
void setDirtyForAllEventListeners();
/// lazy allocs
void childrenAlloc(void);

View File

@ -67,7 +67,6 @@ EventDispatcher::EventListenerItem::~EventListenerItem()
EventDispatcher::EventDispatcher()
: _inDispatch(0)
, _listeners(nullptr)
, _isEnabled(true)
{
_toAddedListeners.reserve(50);
@ -95,28 +94,25 @@ void EventDispatcher::destroyInstance()
void EventDispatcher::addEventListenerWithItem(EventListenerItem* item)
{
if (!_listeners)
{
_listeners = new std::map<std::string, std::vector<EventListenerItem*>*>();
}
if (_inDispatch == 0)
{
std::vector<EventListenerItem*>* listenerList = nullptr;
auto itr = _listeners->find(item->listener->type);
if (itr == _listeners->end())
auto iter = _listeners.find(item->listener->type);
if (iter == _listeners.end())
{
listenerList = new std::vector<EventListenerItem*>();
listenerList->reserve(100);
_listeners->insert(std::make_pair(item->listener->type, listenerList));
_listeners.insert(std::make_pair(item->listener->type, listenerList));
}
else
{
listenerList = itr->second;
listenerList = iter->second;
}
listenerList->insert(listenerList->begin(), item);
setDirtyForEventType(item->listener->type, true);
}
else
{
@ -166,17 +162,19 @@ void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener,
void EventDispatcher::removeEventListener(EventListener* listener)
{
if (_listeners == nullptr || listener == nullptr)
if (listener == nullptr)
return;
bool isFound = false;
for (auto iter = _listeners->begin(); iter != _listeners->end();)
for (auto iter = _listeners.begin(); iter != _listeners.end();)
{
for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter)
{
if ((*itemIter)->listener == listener)
{
listener->retain();
if (_inDispatch == 0)
{
(*itemIter)->listener->release();
@ -196,8 +194,10 @@ void EventDispatcher::removeEventListener(EventListener* listener)
if (iter->second->empty())
{
auto list = iter->second;
iter = _listeners->erase(iter);
iter = _listeners.erase(iter);
CC_SAFE_DELETE(list);
_priorityDirtyFlagMap.erase(listener->type);
}
else
{
@ -208,52 +208,30 @@ void EventDispatcher::removeEventListener(EventListener* listener)
break;
}
if (_listeners->empty())
if (isFound)
{
CC_SAFE_DELETE(_listeners);
listener->release();
}
}
void EventDispatcher::setPriorityWithSceneGraph(EventListener* listener, Node* node)
void EventDispatcher::setPriority(EventListener* listener, int fixedPriority)
{
if (_listeners == nullptr || listener == nullptr || node == nullptr)
if (listener == nullptr)
return;
for (auto iter = _listeners->begin(); iter != _listeners->end(); ++iter)
for (auto iter = _listeners.begin(); iter != _listeners.end(); ++iter)
{
for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter)
{
auto item = *itemIter;
if (item->listener == listener)
{
item->fixedPriority = 0;
CCASSERT(item->node, "Can't set fixed priority with scene graph based listener.");
CC_SAFE_RETAIN(node);
CC_SAFE_RELEASE(item->node);
item->node = node;
return;
}
}
}
}
void EventDispatcher::setPriorityWithFixedValue(EventListener* listener, int fixedPriority)
{
if (_listeners == nullptr || listener == nullptr)
return;
for (auto iter = _listeners->begin(); iter != _listeners->end(); ++iter)
{
for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter)
{
auto item = *itemIter;
if (item->listener == listener)
{
item->fixedPriority = fixedPriority;
if (item->node != nullptr)
if (item->fixedPriority != fixedPriority)
{
item->node->dissociateEventListener(listener);
CC_SAFE_RELEASE_NULL(item->node);
item->fixedPriority = fixedPriority;
setDirtyForEventType(listener->type, true);
}
return;
}
@ -263,12 +241,24 @@ void EventDispatcher::setPriorityWithFixedValue(EventListener* listener, int fix
void EventDispatcher::dispatchEvent(Event* event, bool forceSortListeners)
{
if (_listeners == nullptr || !_isEnabled)
if (!_isEnabled)
return;
if (forceSortListeners)
bool isDirty = false;
auto dirtyIter = _priorityDirtyFlagMap.find(event->_type);
if (dirtyIter != _priorityDirtyFlagMap.end())
{
isDirty = dirtyIter->second;
}
if (forceSortListeners || isDirty)
{
sortAllEventListenerItemsForType(event->_type);
// Sets the dirty flag to false
if (isDirty)
{
dirtyIter->second = false;
}
}
DispatchGuard guard(_inDispatch);
@ -279,22 +269,19 @@ void EventDispatcher::dispatchEvent(Event* event, bool forceSortListeners)
return;
}
if (_listeners)
auto iter = _listeners.find(event->getType());
if (iter != _listeners.end())
{
auto iter = _listeners->find(event->getType());
if (iter != _listeners->end())
auto listenerList = iter->second;
for (auto& item : *listenerList)
{
auto listenerList = iter->second;
for (auto& item : *listenerList)
{
CCASSERT(item, "listener item is invalid.");
CCASSERT(item, "listener item is invalid.");
event->setCurrentTarget(item->node);
item->listener->onEvent(event);
event->setCurrentTarget(item->node);
item->listener->onEvent(event);
if (event->isStopped())
break;
}
if (event->isStopped())
break;
}
}
@ -500,11 +487,8 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
void EventDispatcher::updateListenerItems()
{
if (!_listeners)
return;
auto listenerItemIter = _listeners->begin();
while (listenerItemIter != _listeners->end())
auto listenerItemIter = _listeners.begin();
while (listenerItemIter != _listeners.end())
{
for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end();)
{
@ -521,8 +505,9 @@ void EventDispatcher::updateListenerItems()
if (listenerItemIter->second->empty())
{
_priorityDirtyFlagMap.erase(listenerItemIter->first);
delete listenerItemIter->second;
listenerItemIter = _listeners->erase(listenerItemIter);
listenerItemIter = _listeners.erase(listenerItemIter);
}
else
{
@ -536,12 +521,12 @@ void EventDispatcher::updateListenerItems()
for (auto& item : _toAddedListeners)
{
auto itr = _listeners->find(item->listener->type);
if (itr == _listeners->end())
auto itr = _listeners.find(item->listener->type);
if (itr == _listeners.end())
{
listenerList = new std::vector<EventListenerItem*>();
listenerList->reserve(100);
_listeners->insert(std::make_pair(item->listener->type, listenerList));
_listeners.insert(std::make_pair(item->listener->type, listenerList));
}
else
{
@ -549,20 +534,16 @@ void EventDispatcher::updateListenerItems()
}
listenerList->push_back(item);
setDirtyForEventType(item->listener->type, true);
}
_toAddedListeners.clear();
}
if (_listeners->empty())
{
delete _listeners;
_listeners = nullptr;
}
}
void EventDispatcher::sortAllEventListenerItemsForType(const std::string &eventType)
{
if (_listeners == nullptr)
if (eventType.empty())
return;
auto listenerList = getListenerItemsForType(eventType);
@ -610,13 +591,10 @@ void EventDispatcher::sortAllEventListenerItemsForType(const std::string &eventT
std::vector<EventDispatcher::EventListenerItem*>* EventDispatcher::getListenerItemsForType(const std::string &eventType)
{
if (_listeners != nullptr)
auto iter = _listeners.find(eventType);
if (iter != _listeners.end())
{
auto iter = _listeners->find(eventType);
if (iter != _listeners->end())
{
return iter->second;
}
return iter->second;
}
return nullptr;
@ -624,11 +602,11 @@ std::vector<EventDispatcher::EventListenerItem*>* EventDispatcher::getListenerIt
void EventDispatcher::removeListenersForEventType(const std::string& eventType)
{
if (_listeners == nullptr)
if (eventType.empty())
return;
auto listenerItemIter = _listeners->find(eventType);
if (listenerItemIter != _listeners->end())
auto listenerItemIter = _listeners.find(eventType);
if (listenerItemIter != _listeners.end())
{
for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter)
{
@ -647,17 +625,15 @@ void EventDispatcher::removeListenersForEventType(const std::string& eventType)
{
listenerItemIter->second->clear();
delete listenerItemIter->second;
_listeners->erase(listenerItemIter);
_listeners.erase(listenerItemIter);
_priorityDirtyFlagMap.erase(eventType);
}
}
}
void EventDispatcher::removeAllListeners()
{
if (_listeners == nullptr)
return;
for (auto listenerItemIter = _listeners->begin(); listenerItemIter != _listeners->end(); ++listenerItemIter)
for (auto listenerItemIter = _listeners.begin(); listenerItemIter != _listeners.end(); ++listenerItemIter)
{
for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter)
{
@ -676,13 +652,14 @@ void EventDispatcher::removeAllListeners()
{
listenerItemIter->second->clear();
delete listenerItemIter->second;
_priorityDirtyFlagMap.clear();
}
}
if (!_inDispatch)
{
delete _listeners;
_listeners = nullptr;
_listeners.clear();
}
}
@ -697,4 +674,29 @@ bool EventDispatcher::isEnabled() const
return _isEnabled;
}
void EventDispatcher::setDirtyForEventType(const std::string& eventType, bool isDirty)
{
auto iter = _priorityDirtyFlagMap.find(eventType);
if (iter == _priorityDirtyFlagMap.end())
{
_priorityDirtyFlagMap.insert(std::make_pair(eventType, isDirty));
}
else
{
iter->second = isDirty;
}
}
bool EventDispatcher::isDirtyForEventType(const std::string& eventType)
{
bool isDirty = false;
auto iter = _priorityDirtyFlagMap.find(eventType);
if (iter != _priorityDirtyFlagMap.end())
{
isDirty = iter->second;
}
return isDirty;
}
NS_CC_END

View File

@ -84,12 +84,9 @@ public:
/** Removes all listeners */
void removeAllListeners();
/** Sets listener's priority with node's draw order. */
void setPriorityWithSceneGraph(EventListener* listener, Node* node);
/** Sets listener's priority with fixed value. */
void setPriorityWithFixedValue(EventListener* listener, int fixedPriority);
void setPriority(EventListener* listener, int fixedPriority);
/** Whether to enable dispatching events */
void setEnabled(bool isEnabled);
@ -101,8 +98,12 @@ public:
* Also removes all EventListeners marked for deletion from the
* event dispatcher list.
*/
void dispatchEvent(Event* event, bool forceSortListeners = true);
void dispatchEvent(Event* event, bool forceSortListeners = false);
void setDirtyForEventType(const std::string& eventType, bool isDirty);
bool isDirtyForEventType(const std::string& eventType);
public:
/** Destructor of EventDispatcher */
~EventDispatcher();
@ -141,7 +142,11 @@ private:
/**
* Listeners map.
*/
std::map<std::string, std::vector<EventListenerItem*>*>* _listeners;
std::map<std::string, std::vector<EventListenerItem*>*> _listeners;
/// Priority dirty flag
std::map<std::string, bool> _priorityDirtyFlagMap;
std::vector<EventListenerItem*> _toAddedListeners;
int _inDispatch; ///< Whether it's in dispatching event

View File

@ -87,6 +87,7 @@ protected:
bool _isRegistered; /// Whether the listener has been added to dispatcher.
friend class EventDispatcher;
friend class Node;
};
NS_CC_END

View File

@ -213,7 +213,7 @@ public:
auto listener = TouchEventListener::create(Touch::DispatchMode::ONE_BY_ONE);
listener->setSwallowTouches(true);
listener->onTouchBegan = [&](Touch* touch, Event* event){
listener->onTouchBegan = [=](Touch* touch, Event* event){
Point locationInNode = this->convertToNodeSpace(touch->getLocation());
Size s = this->getContentSize();
@ -227,11 +227,11 @@ public:
return false;
};
listener->onTouchMoved = [&](Touch* touch, Event* event){
listener->onTouchMoved = [=](Touch* touch, Event* event){
//this->setPosition(this->getPosition() + touch->getDelta());
};
listener->onTouchEnded = [&](Touch* touch, Event* event){
listener->onTouchEnded = [=](Touch* touch, Event* event){
this->setColor(Color3B::WHITE);
};

View File

@ -260,7 +260,7 @@ void TouchesPerformTest3::onEnter()
{
CC_PROFILER_START(TOUCH_PROFILER_NAME);
dispatcher->dispatchEvent(&event, true);
dispatcher->dispatchEvent(&event, false);
CC_PROFILER_STOP(TOUCH_PROFILER_NAME);
}