How to check if UI Widget is obscured by a non-ancestor Widget?

How to check if UI Widget is obscured by a non-ancestor Widget?

I’m looking to bind mouseover events to a given widget, which works, but when you add a sibling ui::Widget that visually overlaps, I can’t figure out how to check to make sure that when you mouseover it, that there isn’t another widget in the way.

Say a scene is:

Node @root_node
  \-> ui::Button @close_btn
  \-> ui::Layout @fullscreen_layout

Where both close_btn and fullscreen_layout are added to root_node, and fullscreen_layout blocks the entire view (for the sake of example, its not fullscreen in every case. purely to explain that the close button is not visible whatsoever).

If you attach a EventMouseListener, there doesn’t seem to be a way to check that when you’re mousing over close_btn, to determine that fullscreen_layout isn’t blocking it.

ui::Widget::hitTest() checks that the camera can see the object’s rect, not so much that it’s blocked by anything else. ui::Widget::isClippingParentContainsPoint works for ancestors up the tree, but not non-ancestors.


How do you attach EventMouseListener?


Here’s my helper, I do things the standard way (I think). VoidFunc is std::function<void()>.

void bind_mouseover_to_widget(cocos2d::ui::Widget* hovered_widget, VoidFunc on_hover_func, VoidFunc on_lose_hover_func)

    auto event_mouse_listener = cocos2d::EventListenerMouse::create();
    bool was_touched = false;

    event_mouse_listener->onMouseMove = [hovered_widget, was_touched, on_hover_func, on_lose_hover_func](cocos2d::EventMouse* evt) mutable {
        // TODO: figure out a way to check if the mouse is being blocked by something, things get weird
        auto is_touching = mouse_evt_touches_widget(evt, hovered_widget);

        bool widget_is_usable = hovered_widget->isEnabled() && hovered_widget->isTouchEnabled() && hovered_widget->isVisible();

        if (is_touching && was_touched == false && widget_is_usable) {
            was_touched = true;
        } else if (is_touching == false && was_touched) {
            was_touched = false;

        if (widget_is_usable) {
            try_set_highlighted(hovered_widget, is_touching);
            if (is_touching) {

                //stop propagation so any widgets behind this one can't receive mouse hover too
                // EDIT: except this broke hovers in the location buttons (and stops multiple things being bound to the same widget)
    hovered_widget->getEventDispatcher()->addEventListenerWithSceneGraphPriority(event_mouse_listener, hovered_widget);