mirror of https://github.com/axmolengine/axmol.git
285 lines
6.4 KiB
C++
285 lines
6.4 KiB
C++
|
#include "UIEventDispatcher.h"
|
||
|
#include "GComponent.h"
|
||
|
#include "InputProcessor.h"
|
||
|
#include "utils/WeakPtr.h"
|
||
|
|
||
|
USING_NS_CC;
|
||
|
NS_FGUI_BEGIN
|
||
|
|
||
|
const EventTag EventTag::None;
|
||
|
|
||
|
EventTag::EventTag() :_value(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
EventTag::EventTag(void * ptr) : _value((uintptr_t)ptr)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
EventTag::EventTag(int value) : _value(value)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
EventTag::EventTag(const EventTag & other)
|
||
|
{
|
||
|
*this = other;
|
||
|
}
|
||
|
|
||
|
EventTag::EventTag(EventTag && other)
|
||
|
{
|
||
|
*this = std::move(other);
|
||
|
}
|
||
|
|
||
|
EventTag::~EventTag()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
EventTag & EventTag::operator=(const EventTag & other)
|
||
|
{
|
||
|
if (this != &other)
|
||
|
_value = other._value;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
EventTag & EventTag::operator=(EventTag && other)
|
||
|
{
|
||
|
if (this != &other)
|
||
|
{
|
||
|
_value = other._value;
|
||
|
other._value = 0;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
EventTag & EventTag::operator=(void * ptr)
|
||
|
{
|
||
|
_value = (uintptr_t)ptr;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
EventTag & EventTag::operator=(int v)
|
||
|
{
|
||
|
_value = v;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
bool EventTag::operator!=(const EventTag & v)
|
||
|
{
|
||
|
return _value != v._value;
|
||
|
}
|
||
|
|
||
|
bool EventTag::operator!=(const EventTag & v) const
|
||
|
{
|
||
|
return _value != v._value;
|
||
|
}
|
||
|
|
||
|
bool EventTag::operator==(const EventTag & v)
|
||
|
{
|
||
|
return _value == v._value;
|
||
|
}
|
||
|
|
||
|
bool EventTag::operator==(const EventTag & v) const
|
||
|
{
|
||
|
return _value == v._value;
|
||
|
}
|
||
|
|
||
|
UIEventDispatcher::UIEventDispatcher() :_dispatching(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
UIEventDispatcher::~UIEventDispatcher()
|
||
|
{
|
||
|
_dispatching = 0;
|
||
|
removeEventListeners();
|
||
|
}
|
||
|
|
||
|
void UIEventDispatcher::addEventListener(int eventType, const EventCallback& callback, const EventTag& tag)
|
||
|
{
|
||
|
if (!tag.isNone())
|
||
|
{
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
|
||
|
{
|
||
|
if ((*it)->eventType == eventType && (*it)->tag == tag)
|
||
|
{
|
||
|
(*it)->callback = callback;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EventCallbackItem* item = new EventCallbackItem();
|
||
|
item->callback = callback;
|
||
|
item->eventType = eventType;
|
||
|
item->tag = tag;
|
||
|
item->dispatching = 0;
|
||
|
_callbacks.push_back(item);
|
||
|
}
|
||
|
|
||
|
void UIEventDispatcher::removeEventListener(int eventType, const EventTag& tag)
|
||
|
{
|
||
|
if (_callbacks.empty())
|
||
|
return;
|
||
|
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); )
|
||
|
{
|
||
|
if ((*it)->eventType == eventType && ((*it)->tag == tag || tag.isNone()))
|
||
|
{
|
||
|
if (_dispatching > 0)
|
||
|
{
|
||
|
(*it)->callback = nullptr;
|
||
|
it++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete (*it);
|
||
|
it = _callbacks.erase(it);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
it++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UIEventDispatcher::removeEventListeners()
|
||
|
{
|
||
|
if (_callbacks.empty())
|
||
|
return;
|
||
|
|
||
|
if (_dispatching > 0)
|
||
|
{
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
|
||
|
(*it)->callback = nullptr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); it++)
|
||
|
delete (*it);
|
||
|
_callbacks.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool UIEventDispatcher::hasEventListener(int eventType, const EventTag& tag) const
|
||
|
{
|
||
|
if (_callbacks.empty())
|
||
|
return false;
|
||
|
|
||
|
for (auto it = _callbacks.cbegin(); it != _callbacks.cend(); ++it)
|
||
|
{
|
||
|
if ((*it)->eventType == eventType && ((*it)->tag == tag || tag.isNone()) && (*it)->callback != nullptr)
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool UIEventDispatcher::dispatchEvent(int eventType, void* data, const Value& dataValue)
|
||
|
{
|
||
|
if (_callbacks.size() == 0)
|
||
|
return false;
|
||
|
|
||
|
EventContext context;
|
||
|
context._sender = this;
|
||
|
context._type = eventType;
|
||
|
if (InputProcessor::_activeProcessor)
|
||
|
context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
|
||
|
context._dataValue = dataValue;
|
||
|
context._data = data;
|
||
|
|
||
|
doDispatch(eventType, &context);
|
||
|
|
||
|
return context._defaultPrevented;
|
||
|
}
|
||
|
|
||
|
bool UIEventDispatcher::bubbleEvent(int eventType, void* data, const Value& dataValue)
|
||
|
{
|
||
|
EventContext context;
|
||
|
if (InputProcessor::_activeProcessor)
|
||
|
context._inputEvent = InputProcessor::_activeProcessor->getRecentInput();
|
||
|
context._type = eventType;
|
||
|
context._dataValue = dataValue;
|
||
|
context._data = data;
|
||
|
|
||
|
doBubble(eventType, &context);
|
||
|
|
||
|
return context._defaultPrevented;
|
||
|
}
|
||
|
|
||
|
bool UIEventDispatcher::isDispatchingEvent(int eventType)
|
||
|
{
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); ++it)
|
||
|
{
|
||
|
if ((*it)->eventType == eventType)
|
||
|
return (*it)->dispatching > 0;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void UIEventDispatcher::doDispatch(int eventType, EventContext* context)
|
||
|
{
|
||
|
retain();
|
||
|
|
||
|
_dispatching++;
|
||
|
context->_sender = this;
|
||
|
bool hasDeletedItems = false;
|
||
|
|
||
|
size_t cnt = _callbacks.size(); //dont use iterator, because new item would be added in callback.
|
||
|
for (size_t i = 0; i < cnt; i++)
|
||
|
{
|
||
|
EventCallbackItem* ci = _callbacks[i];
|
||
|
if (ci->callback == nullptr)
|
||
|
{
|
||
|
hasDeletedItems = true;
|
||
|
continue;
|
||
|
}
|
||
|
if (ci->eventType == eventType)
|
||
|
{
|
||
|
ci->dispatching++;
|
||
|
context->_touchCapture = 0;
|
||
|
ci->callback(context);
|
||
|
ci->dispatching--;
|
||
|
if (context->_touchCapture != 0 && dynamic_cast<GObject*>(this))
|
||
|
{
|
||
|
if (context->_touchCapture == 1 && eventType == UIEventType::TouchBegin)
|
||
|
context->getInput()->getProcessor()->addTouchMonitor(context->getInput()->getTouchId(), dynamic_cast<GObject*>(this));
|
||
|
else if (context->_touchCapture == 2)
|
||
|
context->getInput()->getProcessor()->removeTouchMonitor(dynamic_cast<GObject*>(this));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_dispatching--;
|
||
|
if (hasDeletedItems && _dispatching == 0)
|
||
|
{
|
||
|
for (auto it = _callbacks.begin(); it != _callbacks.end(); )
|
||
|
{
|
||
|
if ((*it)->callback == nullptr)
|
||
|
{
|
||
|
delete (*it);
|
||
|
it = _callbacks.erase(it);
|
||
|
}
|
||
|
else
|
||
|
it++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
release();
|
||
|
}
|
||
|
|
||
|
void UIEventDispatcher::doBubble(int eventType, EventContext* context)
|
||
|
{
|
||
|
//parent maybe disposed in callbacks
|
||
|
WeakPtr wptr(((GObject*)this)->findParent());
|
||
|
|
||
|
if (!_callbacks.empty())
|
||
|
{
|
||
|
context->_isStopped = false;
|
||
|
doDispatch(eventType, context);
|
||
|
if (context->_isStopped)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GObject* p = wptr.ptr();
|
||
|
if (p)
|
||
|
p->doBubble(eventType, context);
|
||
|
}
|
||
|
|
||
|
NS_FGUI_END
|