Skip to content

Add mouse events listener for Widgets #2580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions core/base/EventDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,11 @@ void EventDispatcher::dispatchEvent(Event* event, bool forced)
dispatchTouchEvent(static_cast<EventTouch*>(event));
return;
}
else if (event->getType() == Event::Type::MOUSE)
{
dispatchMouseEvent(static_cast<EventMouse*>(event));
return;
}

auto listenerID = __getListenerID(event);

Expand Down Expand Up @@ -1207,6 +1212,88 @@ void EventDispatcher::dispatchTouchEvent(EventTouch* event)
updateListeners(event);
}

void EventDispatcher::dispatchMouseEvent(EventMouse* event)
{
sortEventListeners(EventListenerMouse::LISTENER_ID);

auto listeners = getListeners(EventListenerMouse::LISTENER_ID);

// If there aren't any mouse listeners, return directly.
if (nullptr == listeners)
return;

bool isSwallowed = false;

auto onMouseEvent = [&](EventListener* l) -> bool { // Return true to break
EventListenerMouse* listener = static_cast<EventListenerMouse*>(l);

// Skip if the listener was removed.
if (!listener->_isRegistered)
return false;

event->setCurrentTarget(listener->_node);

bool isClaimed = false;

switch (event->getMouseEventType())
{
case EventMouse::MouseEventType::MOUSE_UP:
if (listener->onMouseUp)
{
isClaimed = listener->onMouseUp(event);
}
break;
case EventMouse::MouseEventType::MOUSE_DOWN:
if (listener->onMouseDown)
{
isClaimed = listener->onMouseDown(event);
}
break;
case EventMouse::MouseEventType::MOUSE_MOVE:
if (listener->onMouseMove)
{
isClaimed = listener->onMouseMove(event);
}
break;
case EventMouse::MouseEventType::MOUSE_SCROLL:
if (listener->onMouseScroll)
{
isClaimed = listener->onMouseScroll(event);
}
break;
case EventMouse::MouseEventType::MOUSE_NONE:
break;
default:
AXASSERT(false, "The type is invalid.");
break;
}


// If the event was stopped, return directly.
if (event->isStopped())
{
updateListeners(event);
return true;
}

if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
return true;
}

return false;
};

//
dispatchTouchEventToListeners(listeners, onMouseEvent);
if (event->isStopped())
{
return;
}

updateListeners(event);
}

void EventDispatcher::updateListeners(Event* event)
{
AXASSERT(_inDispatch > 0, "If program goes here, there should be event in dispatch.");
Expand Down
5 changes: 5 additions & 0 deletions core/base/EventDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace ax

class Event;
class EventTouch;
class EventMouse;
class Node;
class EventCustom;
class EventListenerCustom;
Expand Down Expand Up @@ -282,6 +283,10 @@ class AX_DLL EventDispatcher : public Object
* mode. */
void dispatchTouchEvent(EventTouch* event);

/** Mouse Scroll event needs to be processed different with other events since it needs support ALL_AT_ONCE and ONE_BY_NONE
* mode. */
void dispatchMouseEvent(EventMouse* event);

/** Associates node with event listener */
void associateNodeAndEventListener(Node* node, EventListener* listener);

Expand Down
17 changes: 16 additions & 1 deletion core/base/EventListenerMouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ bool EventListenerMouse::checkAvailable()
return true;
}

void EventListenerMouse::setSwallowMouse(bool needSwallow)
{
_needSwallow = needSwallow;
}

bool EventListenerMouse::isSwallowMouse()
{
return _needSwallow;
}

EventListenerMouse* EventListenerMouse::create()
{
auto ret = new EventListenerMouse();
Expand All @@ -60,6 +70,7 @@ EventListenerMouse* EventListenerMouse::clone()
ret->onMouseDown = onMouseDown;
ret->onMouseMove = onMouseMove;
ret->onMouseScroll = onMouseScroll;
ret->_needSwallow = _needSwallow;
}
else
{
Expand All @@ -69,7 +80,11 @@ EventListenerMouse* EventListenerMouse::clone()
}

EventListenerMouse::EventListenerMouse()
: onMouseDown(nullptr), onMouseUp(nullptr), onMouseMove(nullptr), onMouseScroll(nullptr)
: onMouseDown(nullptr)
, onMouseUp(nullptr)
, onMouseMove(nullptr)
, onMouseScroll(nullptr)
, _needSwallow(false)
{}

bool EventListenerMouse::init()
Expand Down
24 changes: 20 additions & 4 deletions core/base/EventListenerMouse.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,33 @@ class AX_DLL EventListenerMouse : public EventListener
*/
static EventListenerMouse* create();

/** Whether or not to swall scrolls.
*
* @param needSwallow True if needs to swall scroll.
*/
void setSwallowMouse(bool needSwallow);
/** Is swall scroll or not.
*
* @return True if needs to swall scroll.
*/
bool isSwallowMouse();

/// Overrides
virtual EventListenerMouse* clone() override;
virtual bool checkAvailable() override;

std::function<void(EventMouse* event)> onMouseDown;
std::function<void(EventMouse* event)> onMouseUp;
std::function<void(EventMouse* event)> onMouseMove;
std::function<void(EventMouse* event)> onMouseScroll;
std::function<bool(EventMouse* event)> onMouseDown;
std::function<bool(EventMouse* event)> onMouseUp;
std::function<bool(EventMouse* event)> onMouseMove;
std::function<bool(EventMouse* event)> onMouseScroll;

EventListenerMouse();
bool init();

private:
bool _needSwallow;

friend class EventDispatcher;
};

}
Expand Down
6 changes: 6 additions & 0 deletions core/base/EventMouse.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ class AX_DLL EventMouse : public Event
*/
EventMouse(MouseEventType mouseEventCode);

/** Get mouse event type.
*
* @return The type of the event.
*/
MouseEventType getMouseEventType() const { return _mouseEventType; }

/** Set mouse scroll data.
*
* @param scrollX The scroll data of x axis.
Expand Down
31 changes: 31 additions & 0 deletions core/ui/UIScrollView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ ScrollView::ScrollView()
, _scrollTime(DEFAULT_TIME_IN_SEC_FOR_SCROLL_TO_ITEM)
{
setTouchEnabled(true);
setMouseEnabled(true);
_propagateTouchEvents = false;
}

Expand Down Expand Up @@ -131,6 +132,7 @@ bool ScrollView::init()
{
initScrollBar();
}

return true;
}
return false;
Expand Down Expand Up @@ -1086,6 +1088,35 @@ void ScrollView::onTouchCancelled(Touch* touch, Event* unusedEvent)
_isInterceptTouch = false;
}

bool ScrollView::onMouseScroll(Event* event)
{
bool pass = Widget::onMouseScroll(event);

if(pass)
{
auto mouseEvent = static_cast<EventMouse*>(event);
float mouseFactor = 10.f;
Vec2 move;

if (_direction == Direction::HORIZONTAL)
{
move = Vec2(mouseEvent->getScrollY()*mouseFactor, 0.f);
}
else
{
move = Vec2(0.f, mouseEvent->getScrollY()*mouseFactor);
}

bool origBounce = _bounceEnabled;
_bounceEnabled = false;
scrollChildren(move);
_bounceEnabled = origBounce;
processScrollingEndedEvent();
}

return pass;
}

void ScrollView::update(float dt)
{
if (_autoScrolling)
Expand Down
1 change: 1 addition & 0 deletions core/ui/UIScrollView.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ class AX_GUI_DLL ScrollView : public Layout
void onTouchMoved(Touch* touch, Event* unusedEvent) override;
void onTouchEnded(Touch* touch, Event* unusedEvent) override;
void onTouchCancelled(Touch* touch, Event* unusedEvent) override;
bool onMouseScroll(Event* event) override;
void update(float dt) override;

/**
Expand Down
94 changes: 94 additions & 0 deletions core/ui/UIWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ Widget::Widget()
, _ccEventCallback(nullptr)
, _callbackType("")
, _callbackName("")
, _mouseEnabled(false)
, _mouseListener(nullptr)
, _mouseHitted(false)
{}

Widget::~Widget()
Expand Down Expand Up @@ -606,6 +609,36 @@ bool Widget::isTouchEnabled() const
return _touchEnabled;
}

void Widget::setMouseEnabled(bool enable)
{
if (enable == _mouseEnabled)
{
return;
}
_mouseEnabled = enable;
if (_mouseEnabled)
{
_mouseListener = EventListenerMouse::create();
AX_SAFE_RETAIN(_mouseListener);
_mouseListener->setSwallowMouse(true);
_mouseListener->onMouseUp = AX_CALLBACK_1(Widget::onMouseUp, this);
_mouseListener->onMouseDown = AX_CALLBACK_1(Widget::onMouseDown, this);
_mouseListener->onMouseMove = AX_CALLBACK_1(Widget::onMouseMove, this);
_mouseListener->onMouseScroll = AX_CALLBACK_1(Widget::onMouseScroll, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this);
}
else
{
_eventDispatcher->removeEventListener(_mouseListener);
AX_SAFE_RELEASE_NULL(_mouseListener);
}
}

bool Widget::isMouseEnabled() const
{
return _mouseEnabled;
}

bool Widget::isHighlighted() const
{
return _highlight;
Expand Down Expand Up @@ -919,6 +952,66 @@ void Widget::cancelUpEvent()
this->release();
}

void Widget::setSwallowMouse(bool swallow)
{
if (_mouseListener)
{
_mouseListener->setSwallowMouse(swallow);
}
}

bool Widget::isSwallowMouse() const
{
if (_mouseListener)
{
return _mouseListener->isSwallowMouse();
}
return false;
}

bool Widget::onMouseEvent(Event* event)
{
_mouseHitted = false;
if (isVisible() && isEnabled() && isAncestorsEnabled() && isAncestorsVisible(this))
{
auto scrollPosition = static_cast<EventMouse*>(event)->getLocation();
auto camera = Camera::getVisitingCamera();
if (hitTest(scrollPosition, camera, nullptr))
{
if (isClippingParentContainsPoint(scrollPosition))
{
_mouseHitted = true;
}
}
}
if (!_mouseHitted)
{
return false;
}

return true;
}

bool Widget::onMouseUp(Event* event)
{
return onMouseEvent(event);
}

bool Widget::onMouseDown(Event* event)
{
return onMouseEvent(event);
}

bool Widget::onMouseMove(Event* event)
{
return onMouseEvent(event);
}

bool Widget::onMouseScroll(Event* event)
{
return onMouseEvent(event);
}

void Widget::addTouchEventListener(const ccWidgetTouchCallback& callback)
{
this->_touchEventCallback = callback;
Expand Down Expand Up @@ -1207,6 +1300,7 @@ void Widget::copyProperties(Widget* widget)
setVisible(widget->isVisible());
setBright(widget->isBright());
setTouchEnabled(widget->isTouchEnabled());
setMouseEnabled(widget->isMouseEnabled());
setLocalZOrder(widget->getLocalZOrder());
setTag(widget->getTag());
setName(widget->getName());
Expand Down
Loading
Loading