diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 451f399d2c49..77b53f1d70ff 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -394,6 +394,12 @@ Returns [member offset_right] and [member offset_bottom]. + + + + Similar to the getter of [member focus_mode], but takes parent's [member focus_recursive_behavior] into account. + + @@ -416,6 +422,12 @@ Returns the minimum size for this control. See [member custom_minimum_size]. + + + + Similar to to the getter of [member mouse_filter], but takes parent's [member mouse_recursive_behavior] into account. + + @@ -973,6 +985,9 @@ Tells Godot which node it should give focus to if the user presses [kbd]Shift + Tab[/kbd] on a keyboard by default. You can change the key by editing the [member ProjectSettings.input/ui_focus_prev] input action. If this property is not set, Godot will select a "best guess" based on surrounding nodes in the scene tree. + + Controls whether the recursive child nodes should have their [member focus_mode] overridden to [constant FOCUS_NONE] when evaluating input. + The node's global position, relative to the world (usually to the [CanvasLayer]). @@ -1001,6 +1016,9 @@ You should disable it on the root of your UI if you do not want scroll events to go to the [method Node._unhandled_input] processing. [b]Note:[/b] Because this property defaults to [code]true[/code], this allows nested scrollable containers to work out of the box. + + Controls whether the recursive child nodes should have their [member mouse_filter] overridden to [constant MOUSE_FILTER_IGNORE] when evaluating input. + Distance between the node's bottom edge and its parent control, based on [member anchor_bottom]. Offsets are often controlled by one or multiple parent [Container] nodes, so you should not modify them manually if your node is a direct child of a [Container]. Offsets update automatically when you move or resize the node. @@ -1156,6 +1174,15 @@ The node can grab focus on mouse click, using the arrows and the Tab keys on the keyboard, or using the D-pad buttons on a gamepad. Use with [member focus_mode]. + + Inherits the associated behavior from the control's parent. This is the default for any newly created control. + + + The current control and all its recursive child controls have their associated behavior disabled, regardless of the parent control's configuration. + + + The current control and all its recursive child controls have their associated behavior enabled, regardless of the parent control's configuration. + Sent when the node changes size. Use [member size] to get the new size. diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 78e386d9e0cf..ce5a39674b19 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2758,7 +2758,7 @@ TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() { void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) { Control *control = Object::cast_to(p_node); - if (control && control->get_focus_mode() != Control::FOCUS_NONE) { + if (control && control->get_focus_mode_with_recursive() != Control::FOCUS_NONE) { add_focusable(control); } for (int i = 0; i < p_node->get_child_count(); i++) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 515c33a45477..12ece608ebec 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1866,6 +1866,29 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } +Control::MouseFilter Control::get_mouse_filter_with_recursive() const { + ERR_READ_THREAD_GUARD_V(MOUSE_FILTER_IGNORE); + if (_is_parent_mouse_disabled()) { + return MOUSE_FILTER_IGNORE; + } + return data.mouse_filter; +} + +void Control::set_mouse_recursive_behavior(const RecursiveBehavior p_recursive_mouse_behavior) { + ERR_MAIN_THREAD_GUARD; + ERR_FAIL_INDEX((int)p_recursive_mouse_behavior, 4); + data.mouse_recursive_behavior = p_recursive_mouse_behavior; + + if (get_viewport()) { + get_viewport()->_gui_update_mouse_over(); + } +} + +Control::RecursiveBehavior Control::get_mouse_recursive_behavior() const { + ERR_READ_THREAD_GUARD_V(RECURSIVE_BEHAVIOR_INHERITED); + return data.mouse_recursive_behavior; +} + void Control::set_force_pass_scroll_events(bool p_force_pass_scroll_events) { ERR_MAIN_THREAD_GUARD; data.force_pass_scroll_events = p_force_pass_scroll_events; @@ -2014,6 +2037,30 @@ Control::FocusMode Control::get_focus_mode() const { return data.focus_mode; } +Control::FocusMode Control::get_focus_mode_with_recursive() const { + ERR_READ_THREAD_GUARD_V(FOCUS_NONE); + if (_get_parent_focus_recursive_behavior() == RECURSIVE_BEHAVIOR_DISABLED) { + return FOCUS_NONE; + } + return data.focus_mode; +} + +void Control::set_focus_recursive_behavior(RecursiveBehavior p_recursive_mouse_behavior) { + ERR_MAIN_THREAD_GUARD; + ERR_FAIL_INDEX((int)p_recursive_mouse_behavior, 4); + data.focus_recursive_behavior = p_recursive_mouse_behavior; + if (p_recursive_mouse_behavior == RECURSIVE_BEHAVIOR_INHERITED) { + _update_focus_mode_recursive(_get_parent_focus_recursive_behavior()); + } else { + _update_focus_mode_recursive(p_recursive_mouse_behavior); + } +} + +Control::RecursiveBehavior Control::get_focus_recursive_behavior() const { + ERR_READ_THREAD_GUARD_V(RECURSIVE_BEHAVIOR_INHERITED); + return data.focus_recursive_behavior; +} + bool Control::has_focus() const { ERR_READ_THREAD_GUARD_V(false); return is_inside_tree() && get_viewport()->_gui_control_has_focus(this); @@ -2087,7 +2134,7 @@ Control *Control::find_next_valid_focus() const { ERR_FAIL_NULL_V_MSG(n, nullptr, "Next focus node path is invalid: '" + data.focus_next + "'."); Control *c = Object::cast_to(n); ERR_FAIL_NULL_V_MSG(c, nullptr, "Next focus node is not a control: '" + n->get_name() + "'."); - if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE) { + if (c->is_visible() && c->get_focus_mode_with_recursive() != FOCUS_NONE) { return c; } } @@ -2127,10 +2174,10 @@ Control *Control::find_next_valid_focus() const { } if (next_child == from || next_child == this) { // No next control. - return (get_focus_mode() == FOCUS_ALL) ? next_child : nullptr; + return (get_focus_mode_with_recursive() == FOCUS_ALL) ? next_child : nullptr; } if (next_child) { - if (next_child->get_focus_mode() == FOCUS_ALL) { + if (next_child->get_focus_mode_with_recursive() == FOCUS_ALL) { return next_child; } from = next_child; @@ -2174,7 +2221,7 @@ Control *Control::find_prev_valid_focus() const { ERR_FAIL_NULL_V_MSG(n, nullptr, "Previous focus node path is invalid: '" + data.focus_prev + "'."); Control *c = Object::cast_to(n); ERR_FAIL_NULL_V_MSG(c, nullptr, "Previous focus node is not a control: '" + n->get_name() + "'."); - if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE) { + if (c->is_visible() && c->get_focus_mode_with_recursive() != FOCUS_NONE) { return c; } } @@ -2208,10 +2255,10 @@ Control *Control::find_prev_valid_focus() const { } if (prev_child == from || prev_child == this) { // No prev control. - return (get_focus_mode() == FOCUS_ALL) ? prev_child : nullptr; + return (get_focus_mode_with_recursive() == FOCUS_ALL) ? prev_child : nullptr; } - if (prev_child->get_focus_mode() == FOCUS_ALL) { + if (prev_child->get_focus_mode_with_recursive() == FOCUS_ALL) { return prev_child; } @@ -2270,7 +2317,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) { if (!c->is_visible()) { valid = false; } - if (c->get_focus_mode() == FOCUS_NONE) { + if (c->get_focus_mode_with_recursive() == FOCUS_NONE) { valid = false; } if (valid) { @@ -2332,6 +2379,54 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) { return result; } +Control::RecursiveBehavior Control::_get_parent_focus_recursive_behavior() const { + if (data.focus_recursive_behavior != RECURSIVE_BEHAVIOR_INHERITED) { + return data.focus_recursive_behavior; + } + + const Control *parent = get_parent_control(); + if (parent) { + return parent->_get_parent_focus_recursive_behavior(); + } + + return RECURSIVE_BEHAVIOR_INHERITED; +} + +void Control::_update_focus_mode_recursive(const RecursiveBehavior p_focus_recursive_behavior) { + if (is_inside_tree() && (data.focus_recursive_behavior == RECURSIVE_BEHAVIOR_DISABLED || (data.focus_recursive_behavior == RECURSIVE_BEHAVIOR_INHERITED && p_focus_recursive_behavior == RECURSIVE_BEHAVIOR_DISABLED)) && has_focus()) { + release_focus(); + return; + } + + for (int i = 0; i < get_child_count(); i++) { + Control *control = Object::cast_to(get_child(i)); + if (control) { + if (data.focus_recursive_behavior == RECURSIVE_BEHAVIOR_INHERITED) { + control->_update_focus_mode_recursive(p_focus_recursive_behavior); + } else { + control->_update_focus_mode_recursive(data.focus_recursive_behavior); + } + } + } +} + +bool Control::_is_parent_mouse_disabled() const { + if (data.mouse_recursive_behavior == RECURSIVE_BEHAVIOR_DISABLED) { + return true; + } + + if (data.mouse_recursive_behavior == RECURSIVE_BEHAVIOR_ENABLED) { + return false; + } + + const Control *parent = get_parent_control(); + if (parent) { + return parent->_is_parent_mouse_disabled(); + } + + return false; +} + Control *Control::find_valid_focus_neighbor(Side p_side) const { return const_cast(this)->_get_focus_neighbor(p_side); } @@ -2343,7 +2438,7 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons Control *c = Object::cast_to(p_at); - if (c && c != this && c->get_focus_mode() == FOCUS_ALL && c->is_visible_in_tree()) { + if (c && c != this && c->get_focus_mode_with_recursive() == FOCUS_ALL && c->is_visible_in_tree()) { Point2 points[4]; Transform2D xform = c->get_global_transform(); @@ -3453,6 +3548,9 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect); ClassDB::bind_method(D_METHOD("set_focus_mode", "mode"), &Control::set_focus_mode); ClassDB::bind_method(D_METHOD("get_focus_mode"), &Control::get_focus_mode); + ClassDB::bind_method(D_METHOD("get_focus_mode_with_recursive"), &Control::get_focus_mode_with_recursive); + ClassDB::bind_method(D_METHOD("set_focus_recursive_behavior", "focus_recursive_behavior"), &Control::set_focus_recursive_behavior); + ClassDB::bind_method(D_METHOD("get_focus_recursive_behavior"), &Control::get_focus_recursive_behavior); ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus); ClassDB::bind_method(D_METHOD("grab_focus"), &Control::grab_focus); ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus); @@ -3548,6 +3646,10 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mouse_filter", "filter"), &Control::set_mouse_filter); ClassDB::bind_method(D_METHOD("get_mouse_filter"), &Control::get_mouse_filter); + ClassDB::bind_method(D_METHOD("get_mouse_filter_with_recursive"), &Control::get_mouse_filter_with_recursive); + + ClassDB::bind_method(D_METHOD("set_mouse_recursive_behavior", "mouse_recursive_behavior"), &Control::set_mouse_recursive_behavior); + ClassDB::bind_method(D_METHOD("get_mouse_recursive_behavior"), &Control::get_mouse_recursive_behavior); ClassDB::bind_method(D_METHOD("set_force_pass_scroll_events", "force_pass_scroll_events"), &Control::set_force_pass_scroll_events); ClassDB::bind_method(D_METHOD("is_force_pass_scroll_events"), &Control::is_force_pass_scroll_events); @@ -3644,9 +3746,11 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous"); ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_recursive_behavior", PROPERTY_HINT_ENUM, "Inherited,Disabled,Enabled"), "set_focus_recursive_behavior", "get_focus_recursive_behavior"); ADD_GROUP("Mouse", "mouse_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_filter", PROPERTY_HINT_ENUM, "Stop,Pass (Propagate Up),Ignore"), "set_mouse_filter", "get_mouse_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_recursive_behavior", PROPERTY_HINT_ENUM, "Inherited,Disabled,Enabled"), "set_mouse_recursive_behavior", "get_mouse_recursive_behavior"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape"); @@ -3661,6 +3765,10 @@ void Control::_bind_methods() { BIND_ENUM_CONSTANT(FOCUS_CLICK); BIND_ENUM_CONSTANT(FOCUS_ALL); + BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_INHERITED); + BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_DISABLED); + BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_ENABLED); + BIND_CONSTANT(NOTIFICATION_RESIZED); BIND_CONSTANT(NOTIFICATION_MOUSE_ENTER); BIND_CONSTANT(NOTIFICATION_MOUSE_EXIT); diff --git a/scene/gui/control.h b/scene/gui/control.h index 23190381f3f4..eb3f2265d02b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -68,6 +68,12 @@ class Control : public CanvasItem { FOCUS_ALL }; + enum RecursiveBehavior { + RECURSIVE_BEHAVIOR_INHERITED, + RECURSIVE_BEHAVIOR_DISABLED, + RECURSIVE_BEHAVIOR_ENABLED, + }; + enum SizeFlags { SIZE_SHRINK_BEGIN = 0, SIZE_FILL = 1, @@ -191,6 +197,7 @@ class Control : public CanvasItem { real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 }; real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN }; FocusMode focus_mode = FOCUS_NONE; + RecursiveBehavior focus_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED; GrowDirection h_grow = GROW_DIRECTION_END; GrowDirection v_grow = GROW_DIRECTION_END; @@ -219,6 +226,7 @@ class Control : public CanvasItem { // Input events and rendering. MouseFilter mouse_filter = MOUSE_FILTER_STOP; + RecursiveBehavior mouse_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED; bool force_pass_scroll_events = true; bool clip_contents = false; @@ -312,10 +320,16 @@ class Control : public CanvasItem { void _call_gui_input(const Ref &p_event); + // Mouse Filter. + + bool _is_parent_mouse_disabled() const; + // Focus. void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest); Control *_get_focus_neighbor(Side p_side, int p_count = 0); + RecursiveBehavior _get_parent_focus_recursive_behavior() const; + void _update_focus_mode_recursive(RecursiveBehavior p_focus_recursive_behavior); // Theming. @@ -516,6 +530,10 @@ class Control : public CanvasItem { void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; + MouseFilter get_mouse_filter_with_recursive() const; + + void set_mouse_recursive_behavior(RecursiveBehavior p_recursive_mouse_behavior); + RecursiveBehavior get_mouse_recursive_behavior() const; void set_force_pass_scroll_events(bool p_force_pass_scroll_events); bool is_force_pass_scroll_events() const; @@ -540,6 +558,9 @@ class Control : public CanvasItem { void set_focus_mode(FocusMode p_focus_mode); FocusMode get_focus_mode() const; + FocusMode get_focus_mode_with_recursive() const; + void set_focus_recursive_behavior(RecursiveBehavior p_recursive_mouse_behavior); + RecursiveBehavior get_focus_recursive_behavior() const; bool has_focus() const; void grab_focus(); void grab_click_focus(); @@ -657,6 +678,7 @@ class Control : public CanvasItem { }; VARIANT_ENUM_CAST(Control::FocusMode); +VARIANT_ENUM_CAST(Control::RecursiveBehavior); VARIANT_BITFIELD_CAST(Control::SizeFlags); VARIANT_ENUM_CAST(Control::CursorShape); VARIANT_ENUM_CAST(Control::LayoutPreset); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 2b393dacafbe..a2259d69270c 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1198,7 +1198,7 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos control_rect.size *= zoom; control_rect.position += p_offset; - if (!control_rect.has_point(mpos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { + if (!control_rect.has_point(mpos) || p_control->get_mouse_filter_with_recursive() == MOUSE_FILTER_IGNORE) { // Test children. for (int i = 0; i < p_control->get_child_count(); i++) { Control *child_rect = Object::cast_to(p_control->get_child(i)); diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 7099b1892b93..d0b453ed235f 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -90,12 +90,12 @@ void Slider::gui_input(const Ref &p_event) { } } else if (scrollable) { if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) { - if (get_focus_mode() != FOCUS_NONE) { + if (get_focus_mode_with_recursive() != FOCUS_NONE) { grab_focus(); } set_value(get_value() + get_step()); } else if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) { - if (get_focus_mode() != FOCUS_NONE) { + if (get_focus_mode_with_recursive() != FOCUS_NONE) { grab_focus(); } set_value(get_value() - get_step()); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 33e72428cfb0..dbd453727457 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -725,7 +725,7 @@ void TabContainer::set_tab_focus_mode(Control::FocusMode p_focus_mode) { } Control::FocusMode TabContainer::get_tab_focus_mode() const { - return tab_bar->get_focus_mode(); + return tab_bar->get_focus_mode_with_recursive(); } void TabContainer::set_clip_tabs(bool p_clip_tabs) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d29ea240b29f..04111811a643 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -719,7 +719,7 @@ void Viewport::_process_picking() { PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); SubViewportContainer *parent_svc = Object::cast_to(get_parent()); - bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter() == Control::MOUSE_FILTER_IGNORE); + bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE); bool create_passive_hover_event = true; if (gui.mouse_over || parent_ignore_mouse) { // When the mouse is over a Control node, passive hovering would cause input events for Colliders, that are behind Control nodes. @@ -1835,7 +1835,7 @@ void Viewport::_gui_input_event(Ref p_event) { while (ci) { Control *control = Object::cast_to(ci); if (control) { - if (control->get_focus_mode() != Control::FOCUS_NONE) { + if (control->get_focus_mode_with_recursive() != Control::FOCUS_NONE) { // Grabbing unhovered focus can cause issues when mouse is dragged // with another button held down. if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) { @@ -2413,7 +2413,7 @@ void Viewport::_gui_update_mouse_over() { int found = gui.mouse_over_hierarchy.find(ancestor_control); if (found >= 0) { // Remove the node if the propagation chain has been broken or it is now MOUSE_FILTER_IGNORE. - if (removing || ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_IGNORE) { + if (removing || ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE) { needs_exit.push_back(found); } } @@ -2424,14 +2424,14 @@ void Viewport::_gui_update_mouse_over() { } reached_top = true; } - if (!removing && ancestor_control->get_mouse_filter() != Control::MOUSE_FILTER_IGNORE) { + if (!removing && ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) { new_mouse_over_hierarchy.push_back(ancestor_control); // Add the node if it was not found and it is now not MOUSE_FILTER_IGNORE. if (found < 0) { needs_enter.push_back(ancestor_control); } } - if (ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_STOP) { + if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) { // MOUSE_FILTER_STOP breaks the propagation chain. if (reached_top) { break; @@ -3049,7 +3049,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { while (ancestor) { Control *ancestor_control = Object::cast_to(ancestor); if (ancestor_control) { - if (ancestor_control->get_mouse_filter() != Control::MOUSE_FILTER_IGNORE) { + if (ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) { int found = gui.mouse_over_hierarchy.find(ancestor_control); if (found >= 0) { common_ancestor = gui.mouse_over_hierarchy[found]; @@ -3057,7 +3057,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { } over_ancestors.push_back(ancestor_control); } - if (ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_STOP) { + if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) { // MOUSE_FILTER_STOP breaks the propagation chain. break; }