소스 검색

Merge pull request #105222 from kitbdev/fix-mouse-filter-recursive-and-rename

Fix and rename mouse filter recursive behavior and focus mode recursive behavior
Thaddeus Crews 3 달 전
부모
커밋
00bd421089

+ 27 - 18
doc/classes/Control.xml

@@ -415,10 +415,10 @@
 				Returns [member offset_right] and [member offset_bottom].
 				Returns [member offset_right] and [member offset_bottom].
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="get_focus_mode_with_recursive" qualifiers="const">
+		<method name="get_focus_mode_with_override" qualifiers="const">
 			<return type="int" enum="Control.FocusMode" />
 			<return type="int" enum="Control.FocusMode" />
 			<description>
 			<description>
-				Similar to the getter of [member focus_mode], but takes parent's [member focus_recursive_behavior] into account.
+				Returns the [member focus_mode], but takes the [member focus_behavior_recursive] into account. If [member focus_behavior_recursive] is set to [constant FOCUS_BEHAVIOR_DISABLED], or it is set to [constant FOCUS_BEHAVIOR_INHERITED] and its ancestor is set to [constant FOCUS_BEHAVIOR_DISABLED], then this returns [constant FOCUS_NONE].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_focus_neighbor" qualifiers="const">
 		<method name="get_focus_neighbor" qualifiers="const">
@@ -443,10 +443,10 @@
 				Returns the minimum size for this control. See [member custom_minimum_size].
 				Returns the minimum size for this control. See [member custom_minimum_size].
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="get_mouse_filter_with_recursive" qualifiers="const">
+		<method name="get_mouse_filter_with_override" qualifiers="const">
 			<return type="int" enum="Control.MouseFilter" />
 			<return type="int" enum="Control.MouseFilter" />
 			<description>
 			<description>
-				Similar to the getter of [member mouse_filter], but takes parent's [member mouse_recursive_behavior] into account.
+				Returns the [member mouse_filter], but takes the [member mouse_behavior_recursive] into account. If [member mouse_behavior_recursive] is set to [constant MOUSE_BEHAVIOR_DISABLED], or it is set to [constant MOUSE_BEHAVIOR_INHERITED] and its ancestor is set to [constant MOUSE_BEHAVIOR_DISABLED], then this returns [constant MOUSE_FILTER_IGNORE].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_offset" qualifiers="const">
 		<method name="get_offset" qualifiers="const">
@@ -983,8 +983,11 @@
 		<member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
 		<member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
 			The minimum size of the node's bounding rectangle. If you set it to a value greater than [code](0, 0)[/code], the node's bounding rectangle will always have at least this size. Note that [Control] nodes have their internal minimum size returned by [method get_minimum_size]. It depends on the control's contents, like text, textures, or style boxes. The actual minimum size is the maximum value of this property and the internal minimum size (see [method get_combined_minimum_size]).
 			The minimum size of the node's bounding rectangle. If you set it to a value greater than [code](0, 0)[/code], the node's bounding rectangle will always have at least this size. Note that [Control] nodes have their internal minimum size returned by [method get_minimum_size]. It depends on the control's contents, like text, textures, or style boxes. The actual minimum size is the maximum value of this property and the internal minimum size (see [method get_combined_minimum_size]).
 		</member>
 		</member>
+		<member name="focus_behavior_recursive" type="int" setter="set_focus_behavior_recursive" getter="get_focus_behavior_recursive" enum="Control.FocusBehaviorRecursive" default="0">
+			Determines which controls can be focused together with [member focus_mode]. See [method get_focus_mode_with_override]. Since the default behavior is [constant FOCUS_BEHAVIOR_INHERITED], this can be used to prevent all children controls from getting focused.
+		</member>
 		<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
 		<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
-			The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard, gamepad, and mouse signals.
+			Determines which controls can be focused. Only one control can be focused at a time, and the focused control will receive keyboard, gamepad, and mouse events in [method _gui_input]. Use [method get_focus_mode_with_override] to determine if a control can grab focus, since [member focus_behavior_recursive] also affects it. See also [method grab_focus].
 		</member>
 		</member>
 		<member name="focus_neighbor_bottom" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)" keywords="focus_neighbour_bottom">
 		<member name="focus_neighbor_bottom" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)" keywords="focus_neighbour_bottom">
 			Tells Godot which node it should give focus to if the user presses the down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_down] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
 			Tells Godot which node it should give focus to if the user presses the down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [member ProjectSettings.input/ui_down] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
@@ -1006,9 +1009,6 @@
 			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.
 			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.
 			If this property is not set, Godot will select a "best guess" based on surrounding nodes in the scene tree.
 		</member>
 		</member>
-		<member name="focus_recursive_behavior" type="int" setter="set_focus_recursive_behavior" getter="get_focus_recursive_behavior" enum="Control.RecursiveBehavior" default="0">
-			Controls whether the recursive child nodes should have their [member focus_mode] overridden to [constant FOCUS_NONE] when evaluating input.
-		</member>
 		<member name="global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
 		<member name="global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
 			The node's global position, relative to the world (usually to the [CanvasLayer]).
 			The node's global position, relative to the world (usually to the [CanvasLayer]).
 		</member>
 		</member>
@@ -1025,21 +1025,21 @@
 			If [code]true[/code], automatically converts code line numbers, list indices, [SpinBox] and [ProgressBar] values from the Western Arabic (0..9) to the numeral systems used in current locale.
 			If [code]true[/code], automatically converts code line numbers, list indices, [SpinBox] and [ProgressBar] values from the Western Arabic (0..9) to the numeral systems used in current locale.
 			[b]Note:[/b] Numbers within the text are not automatically converted, it can be done manually, using [method TextServer.format_number].
 			[b]Note:[/b] Numbers within the text are not automatically converted, it can be done manually, using [method TextServer.format_number].
 		</member>
 		</member>
+		<member name="mouse_behavior_recursive" type="int" setter="set_mouse_behavior_recursive" getter="get_mouse_behavior_recursive" enum="Control.MouseBehaviorRecursive" default="0">
+			Determines which controls can receive mouse input together with [member mouse_filter]. See [method get_mouse_filter_with_override]. Since the default behavior is [constant MOUSE_BEHAVIOR_INHERITED], this can be used to prevent all children controls from receiving mouse input.
+		</member>
 		<member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape" default="0">
 		<member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape" default="0">
 			The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors.
 			The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors.
 			[b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system.
 			[b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system.
 		</member>
 		</member>
 		<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" enum="Control.MouseFilter" default="0">
 		<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" enum="Control.MouseFilter" default="0">
-			Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does.
+			Determines which controls will be able to receive mouse button input events through [method _gui_input] and the [signal mouse_entered], and [signal mouse_exited] signals. Also determines how these events should be propagated. See the constants to learn what each does. Use [method get_mouse_filter_with_override] to determine if a control can receive mouse input, since [member mouse_behavior_recursive] also affects it.
 		</member>
 		</member>
 		<member name="mouse_force_pass_scroll_events" type="bool" setter="set_force_pass_scroll_events" getter="is_force_pass_scroll_events" default="true">
 		<member name="mouse_force_pass_scroll_events" type="bool" setter="set_force_pass_scroll_events" getter="is_force_pass_scroll_events" default="true">
 			When enabled, scroll wheel events processed by [method _gui_input] will be passed to the parent control even if [member mouse_filter] is set to [constant MOUSE_FILTER_STOP].
 			When enabled, scroll wheel events processed by [method _gui_input] will be passed to the parent control even if [member mouse_filter] is set to [constant MOUSE_FILTER_STOP].
 			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.
 			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.
 			[b]Note:[/b] Because this property defaults to [code]true[/code], this allows nested scrollable containers to work out of the box.
 		</member>
 		</member>
-		<member name="mouse_recursive_behavior" type="int" setter="set_mouse_recursive_behavior" getter="get_mouse_recursive_behavior" enum="Control.RecursiveBehavior" default="0">
-			Controls whether the recursive child nodes should have their [member mouse_filter] overridden to [constant MOUSE_FILTER_IGNORE] when evaluating input.
-		</member>
 		<member name="offset_bottom" type="float" setter="set_offset" getter="get_offset" default="0.0">
 		<member name="offset_bottom" type="float" setter="set_offset" getter="get_offset" default="0.0">
 			Distance between the node's bottom edge and its parent control, based on [member anchor_bottom].
 			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.
 			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.
@@ -1198,14 +1198,23 @@
 		<constant name="FOCUS_ACCESSIBILITY" value="3" enum="FocusMode">
 		<constant name="FOCUS_ACCESSIBILITY" value="3" enum="FocusMode">
 			The node can grab focus only when screen reader is active. Use with [member focus_mode].
 			The node can grab focus only when screen reader is active. Use with [member focus_mode].
 		</constant>
 		</constant>
-		<constant name="RECURSIVE_BEHAVIOR_INHERITED" value="0" enum="RecursiveBehavior">
-			Inherits the associated behavior from the control's parent. This is the default for any newly created control.
+		<constant name="FOCUS_BEHAVIOR_INHERITED" value="0" enum="FocusBehaviorRecursive">
+			Inherits the [member focus_behavior_recursive] from the parent control. If there is no parent control, this is the same as [constant FOCUS_BEHAVIOR_ENABLED].
+		</constant>
+		<constant name="FOCUS_BEHAVIOR_DISABLED" value="1" enum="FocusBehaviorRecursive">
+			Prevents the control from getting focused. [method get_focus_mode_with_override] will return [constant FOCUS_NONE].
+		</constant>
+		<constant name="FOCUS_BEHAVIOR_ENABLED" value="2" enum="FocusBehaviorRecursive">
+			Allows the control to be focused, depending on the [member focus_mode]. This can be used to ignore the parent's [member focus_behavior_recursive]. [method get_focus_mode_with_override] will return the [member focus_mode].
+		</constant>
+		<constant name="MOUSE_BEHAVIOR_INHERITED" value="0" enum="MouseBehaviorRecursive">
+			Inherits the [member mouse_behavior_recursive] from the parent control. If there is no parent control, this is the same as [constant MOUSE_BEHAVIOR_ENABLED].
 		</constant>
 		</constant>
-		<constant name="RECURSIVE_BEHAVIOR_DISABLED" value="1" enum="RecursiveBehavior">
-			The current control and all its recursive child controls have their associated behavior disabled, regardless of the parent control's configuration.
+		<constant name="MOUSE_BEHAVIOR_DISABLED" value="1" enum="MouseBehaviorRecursive">
+			Prevents the control from receiving mouse input. [method get_mouse_filter_with_override] will return [constant MOUSE_FILTER_IGNORE].
 		</constant>
 		</constant>
-		<constant name="RECURSIVE_BEHAVIOR_ENABLED" value="2" enum="RecursiveBehavior">
-			The current control and all its recursive child controls have their associated behavior enabled, regardless of the parent control's configuration.
+		<constant name="MOUSE_BEHAVIOR_ENABLED" value="2" enum="MouseBehaviorRecursive">
+			Allows the control to be receive mouse input, depending on the [member mouse_filter]. This can be used to ignore the parent's [member mouse_behavior_recursive]. [method get_mouse_filter_with_override] will return the [member mouse_filter].
 		</constant>
 		</constant>
 		<constant name="NOTIFICATION_RESIZED" value="40">
 		<constant name="NOTIFICATION_RESIZED" value="40">
 			Sent when the node changes size. Use [member size] to get the new size.
 			Sent when the node changes size. Use [member size] to get the new size.

+ 1 - 1
editor/plugins/tiles/tile_set_atlas_source_editor.cpp

@@ -2764,7 +2764,7 @@ TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
 
 
 void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
 void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
 	Control *control = Object::cast_to<Control>(p_node);
 	Control *control = Object::cast_to<Control>(p_node);
-	if (control && control->get_focus_mode_with_recursive() != Control::FOCUS_NONE) {
+	if (control && control->get_focus_mode_with_override() != Control::FOCUS_NONE) {
 		add_focusable(control);
 		add_focusable(control);
 	}
 	}
 	for (int i = 0; i < p_node->get_child_count(); i++) {
 	for (int i = 0; i < p_node->get_child_count(); i++) {

+ 110 - 112
scene/gui/control.cpp

@@ -1891,44 +1891,67 @@ Control::MouseFilter Control::get_mouse_filter() const {
 	return data.mouse_filter;
 	return data.mouse_filter;
 }
 }
 
 
-Control::MouseFilter Control::get_mouse_filter_with_recursive() const {
+Control::MouseFilter Control::get_mouse_filter_with_override() const {
 	ERR_READ_THREAD_GUARD_V(MOUSE_FILTER_IGNORE);
 	ERR_READ_THREAD_GUARD_V(MOUSE_FILTER_IGNORE);
-	if (_is_parent_mouse_disabled()) {
+	if (!_is_mouse_filter_enabled()) {
 		return MOUSE_FILTER_IGNORE;
 		return MOUSE_FILTER_IGNORE;
 	}
 	}
 	return data.mouse_filter;
 	return data.mouse_filter;
 }
 }
 
 
-void Control::set_mouse_recursive_behavior(RecursiveBehavior p_recursive_mouse_behavior) {
+void Control::set_mouse_behavior_recursive(MouseBehaviorRecursive p_mouse_behavior_recursive) {
 	ERR_MAIN_THREAD_GUARD;
 	ERR_MAIN_THREAD_GUARD;
-	ERR_FAIL_INDEX((int)p_recursive_mouse_behavior, 4);
-	if (data.mouse_recursive_behavior == p_recursive_mouse_behavior) {
+	ERR_FAIL_INDEX(p_mouse_behavior_recursive, 3);
+	if (data.mouse_behavior_recursive == p_mouse_behavior_recursive) {
 		return;
 		return;
 	}
 	}
-	_set_mouse_recursive_behavior_ignore_cache(p_recursive_mouse_behavior);
+	data.mouse_behavior_recursive = p_mouse_behavior_recursive;
+	_update_mouse_behavior_recursive();
 }
 }
 
 
-void Control::_set_mouse_recursive_behavior_ignore_cache(RecursiveBehavior p_recursive_mouse_behavior) {
-	data.mouse_recursive_behavior = p_recursive_mouse_behavior;
-	if (p_recursive_mouse_behavior == RECURSIVE_BEHAVIOR_INHERITED) {
-		Control *parent = get_parent_control();
-		if (parent) {
-			_propagate_mouse_behavior_recursively(parent->data.parent_mouse_recursive_behavior, false);
+Control::MouseBehaviorRecursive Control::get_mouse_behavior_recursive() const {
+	ERR_READ_THREAD_GUARD_V(MOUSE_BEHAVIOR_INHERITED);
+	return data.mouse_behavior_recursive;
+}
+
+bool Control::_is_mouse_filter_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
+	if (data.mouse_behavior_recursive == MOUSE_BEHAVIOR_INHERITED) {
+		if (data.parent_control) {
+			return data.parent_mouse_behavior_recursive_enabled;
+		}
+		return true;
+	}
+	return data.mouse_behavior_recursive == MOUSE_BEHAVIOR_ENABLED;
+}
+
+void Control::_update_mouse_behavior_recursive() {
+	if (data.mouse_behavior_recursive == MOUSE_BEHAVIOR_INHERITED) {
+		if (data.parent_control) {
+			_propagate_mouse_behavior_recursive_recursively(data.parent_control->_is_mouse_filter_enabled(), false);
 		} else {
 		} else {
-			_propagate_mouse_behavior_recursively(RECURSIVE_BEHAVIOR_ENABLED, false);
+			_propagate_mouse_behavior_recursive_recursively(true, false);
 		}
 		}
 	} else {
 	} else {
-		_propagate_mouse_behavior_recursively(p_recursive_mouse_behavior, false);
+		_propagate_mouse_behavior_recursive_recursively(data.mouse_behavior_recursive == MOUSE_BEHAVIOR_ENABLED, false);
 	}
 	}
-
 	if (get_viewport()) {
 	if (get_viewport()) {
 		get_viewport()->_gui_update_mouse_over();
 		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::_propagate_mouse_behavior_recursive_recursively(bool p_enabled, bool p_skip_non_inherited) {
+	if (p_skip_non_inherited && data.mouse_behavior_recursive != MOUSE_BEHAVIOR_INHERITED) {
+		return;
+	}
+
+	data.parent_mouse_behavior_recursive_enabled = p_enabled;
+	for (int i = 0; i < get_child_count(); i++) {
+		Control *control = Object::cast_to<Control>(get_child(i));
+		if (control) {
+			control->_propagate_mouse_behavior_recursive_recursively(p_enabled, true);
+		}
+	}
 }
 }
 
 
 void Control::set_force_pass_scroll_events(bool p_force_pass_scroll_events) {
 void Control::set_force_pass_scroll_events(bool p_force_pass_scroll_events) {
@@ -2112,40 +2135,69 @@ Control::FocusMode Control::get_focus_mode() const {
 	return data.focus_mode;
 	return data.focus_mode;
 }
 }
 
 
-Control::FocusMode Control::get_focus_mode_with_recursive() const {
+Control::FocusMode Control::get_focus_mode_with_override() const {
 	ERR_READ_THREAD_GUARD_V(FOCUS_NONE);
 	ERR_READ_THREAD_GUARD_V(FOCUS_NONE);
-	if (_is_focus_disabled_recursively()) {
+	if (!_is_focus_mode_enabled()) {
 		return FOCUS_NONE;
 		return FOCUS_NONE;
 	}
 	}
 	return data.focus_mode;
 	return data.focus_mode;
 }
 }
 
 
-void Control::set_focus_recursive_behavior(RecursiveBehavior p_recursive_focus_behavior) {
+void Control::set_focus_behavior_recursive(FocusBehaviorRecursive p_focus_behavior_recursive) {
 	ERR_MAIN_THREAD_GUARD;
 	ERR_MAIN_THREAD_GUARD;
-	ERR_FAIL_INDEX((int)p_recursive_focus_behavior, 4);
-	if (data.focus_recursive_behavior == p_recursive_focus_behavior) {
+	ERR_FAIL_INDEX((int)p_focus_behavior_recursive, 3);
+	if (data.focus_behavior_recursive == p_focus_behavior_recursive) {
 		return;
 		return;
 	}
 	}
-	_set_focus_recursive_behavior_ignore_cache(p_recursive_focus_behavior);
+	data.focus_behavior_recursive = p_focus_behavior_recursive;
+	_update_focus_behavior_recursive();
 }
 }
 
 
-void Control::_set_focus_recursive_behavior_ignore_cache(RecursiveBehavior p_recursive_focus_behavior) {
-	data.focus_recursive_behavior = p_recursive_focus_behavior;
-	if (p_recursive_focus_behavior == RECURSIVE_BEHAVIOR_INHERITED) {
+Control::FocusBehaviorRecursive Control::get_focus_behavior_recursive() const {
+	ERR_READ_THREAD_GUARD_V(FOCUS_BEHAVIOR_INHERITED);
+	return data.focus_behavior_recursive;
+}
+
+bool Control::_is_focus_mode_enabled() const {
+	if (data.focus_behavior_recursive == FOCUS_BEHAVIOR_INHERITED) {
+		if (data.parent_control) {
+			return data.parent_focus_behavior_recursive_enabled;
+		}
+		return true;
+	}
+	return data.focus_behavior_recursive == FOCUS_BEHAVIOR_ENABLED;
+}
+
+void Control::_update_focus_behavior_recursive() {
+	if (data.focus_behavior_recursive == FOCUS_BEHAVIOR_INHERITED) {
 		Control *parent = get_parent_control();
 		Control *parent = get_parent_control();
 		if (parent) {
 		if (parent) {
-			_propagate_focus_behavior_recursively(parent->data.parent_focus_recursive_behavior, false);
+			_propagate_focus_behavior_recursive_recursively(parent->_is_focus_mode_enabled(), false);
 		} else {
 		} else {
-			_propagate_focus_behavior_recursively(RECURSIVE_BEHAVIOR_ENABLED, false);
+			_propagate_focus_behavior_recursive_recursively(true, false);
 		}
 		}
 	} else {
 	} else {
-		_propagate_focus_behavior_recursively(p_recursive_focus_behavior, false);
+		_propagate_focus_behavior_recursive_recursively(data.focus_behavior_recursive == FOCUS_BEHAVIOR_ENABLED, false);
 	}
 	}
 }
 }
 
 
-Control::RecursiveBehavior Control::get_focus_recursive_behavior() const {
-	ERR_READ_THREAD_GUARD_V(RECURSIVE_BEHAVIOR_INHERITED);
-	return data.focus_recursive_behavior;
+void Control::_propagate_focus_behavior_recursive_recursively(bool p_enabled, bool p_skip_non_inherited) {
+	if (is_inside_tree() && (data.focus_behavior_recursive == FOCUS_BEHAVIOR_DISABLED || (data.focus_behavior_recursive == FOCUS_BEHAVIOR_INHERITED && !p_enabled)) && has_focus()) {
+		release_focus();
+	}
+
+	if (p_skip_non_inherited && data.focus_behavior_recursive != FOCUS_BEHAVIOR_INHERITED) {
+		return;
+	}
+
+	data.parent_focus_behavior_recursive_enabled = p_enabled;
+
+	for (int i = 0; i < get_child_count(); i++) {
+		Control *control = Object::cast_to<Control>(get_child(i));
+		if (control) {
+			control->_propagate_focus_behavior_recursive_recursively(p_enabled, true);
+		}
+	}
 }
 }
 
 
 bool Control::has_focus() const {
 bool Control::has_focus() const {
@@ -2157,8 +2209,8 @@ void Control::grab_focus() {
 	ERR_MAIN_THREAD_GUARD;
 	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 
 
-	if (data.focus_mode == FOCUS_NONE) {
-		WARN_PRINT("This control can't grab focus. Use set_focus_mode() to allow a control to get focus.");
+	if (get_focus_mode_with_override() == FOCUS_NONE) {
+		WARN_PRINT("This control can't grab focus. Use set_focus_mode() and set_focus_behavior_recursive() to allow a control to get focus.");
 		return;
 		return;
 	}
 	}
 
 
@@ -2218,7 +2270,7 @@ Control *Control::find_next_valid_focus() const {
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Next focus node path is invalid: '" + data.focus_next + "'.");
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Next focus node path is invalid: '" + data.focus_next + "'.");
 		Control *c = Object::cast_to<Control>(n);
 		Control *c = Object::cast_to<Control>(n);
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Next focus node is not a control: '" + n->get_name() + "'.");
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Next focus node is not a control: '" + n->get_name() + "'.");
-		if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
+		if (c->is_visible_in_tree() && c->get_focus_mode_with_override() != FOCUS_NONE) {
 			return c;
 			return c;
 		}
 		}
 	}
 	}
@@ -2285,7 +2337,7 @@ Control *Control::find_next_valid_focus() const {
 			break;
 			break;
 		}
 		}
 
 
-		if ((next_child->get_focus_mode_with_recursive() == FOCUS_ALL) || (ac_enabled && next_child->get_focus_mode_with_recursive() == FOCUS_ACCESSIBILITY)) {
+		if ((next_child->get_focus_mode_with_override() == FOCUS_ALL) || (ac_enabled && next_child->get_focus_mode_with_override() == FOCUS_ACCESSIBILITY)) {
 			return next_child;
 			return next_child;
 		}
 		}
 
 
@@ -2322,7 +2374,7 @@ Control *Control::find_prev_valid_focus() const {
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Previous focus node path is invalid: '" + data.focus_prev + "'.");
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Previous focus node path is invalid: '" + data.focus_prev + "'.");
 		Control *c = Object::cast_to<Control>(n);
 		Control *c = Object::cast_to<Control>(n);
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Previous focus node is not a control: '" + n->get_name() + "'.");
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Previous focus node is not a control: '" + n->get_name() + "'.");
-		if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
+		if (c->is_visible_in_tree() && c->get_focus_mode_with_override() != FOCUS_NONE) {
 			return c;
 			return c;
 		}
 		}
 	}
 	}
@@ -2383,7 +2435,7 @@ Control *Control::find_prev_valid_focus() const {
 			}
 			}
 		}
 		}
 
 
-		if ((prev_child->get_focus_mode_with_recursive() == FOCUS_ALL) || (ac_enabled && prev_child->get_focus_mode_with_recursive() == FOCUS_ACCESSIBILITY)) {
+		if ((prev_child->get_focus_mode_with_override() == FOCUS_ALL) || (ac_enabled && prev_child->get_focus_mode_with_override() == FOCUS_ACCESSIBILITY)) {
 			return prev_child;
 			return prev_child;
 		}
 		}
 
 
@@ -2442,7 +2494,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Neighbor focus node path is invalid: '" + data.focus_neighbor[p_side] + "'.");
 		ERR_FAIL_NULL_V_MSG(n, nullptr, "Neighbor focus node path is invalid: '" + data.focus_neighbor[p_side] + "'.");
 		Control *c = Object::cast_to<Control>(n);
 		Control *c = Object::cast_to<Control>(n);
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Neighbor focus node is not a control: '" + n->get_name() + "'.");
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Neighbor focus node is not a control: '" + n->get_name() + "'.");
-		if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
+		if (c->is_visible_in_tree() && c->get_focus_mode_with_override() != FOCUS_NONE) {
 			return c;
 			return c;
 		}
 		}
 
 
@@ -2551,64 +2603,6 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
 	return result;
 	return result;
 }
 }
 
 
-bool Control::_is_focus_disabled_recursively() const {
-	switch (data.focus_recursive_behavior) {
-		case RECURSIVE_BEHAVIOR_INHERITED:
-			return data.parent_focus_recursive_behavior == RECURSIVE_BEHAVIOR_DISABLED;
-		case RECURSIVE_BEHAVIOR_DISABLED:
-			return true;
-		case RECURSIVE_BEHAVIOR_ENABLED:
-			return false;
-	}
-	return false;
-}
-
-void Control::_propagate_focus_behavior_recursively(RecursiveBehavior p_focus_recursive_behavior, bool p_skip_non_inherited) {
-	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();
-	}
-
-	if (p_skip_non_inherited && data.focus_recursive_behavior != RECURSIVE_BEHAVIOR_INHERITED) {
-		return;
-	}
-
-	data.parent_focus_recursive_behavior = p_focus_recursive_behavior;
-
-	for (int i = 0; i < get_child_count(); i++) {
-		Control *control = Object::cast_to<Control>(get_child(i));
-		if (control) {
-			control->_propagate_focus_behavior_recursively(p_focus_recursive_behavior, true);
-		}
-	}
-}
-
-bool Control::_is_parent_mouse_disabled() const {
-	switch (data.mouse_recursive_behavior) {
-		case RECURSIVE_BEHAVIOR_INHERITED:
-			return data.parent_mouse_recursive_behavior == RECURSIVE_BEHAVIOR_DISABLED;
-		case RECURSIVE_BEHAVIOR_DISABLED:
-			return true;
-		case RECURSIVE_BEHAVIOR_ENABLED:
-			return false;
-	}
-	return false;
-}
-
-void Control::_propagate_mouse_behavior_recursively(RecursiveBehavior p_mouse_recursive_behavior, bool p_skip_non_inherited) {
-	if (p_skip_non_inherited && data.mouse_recursive_behavior != RECURSIVE_BEHAVIOR_INHERITED) {
-		return;
-	}
-
-	data.parent_mouse_recursive_behavior = p_mouse_recursive_behavior;
-
-	for (int i = 0; i < get_child_count(); i++) {
-		Control *control = Object::cast_to<Control>(get_child(i));
-		if (control) {
-			control->_propagate_mouse_behavior_recursively(p_mouse_recursive_behavior, true);
-		}
-	}
-}
-
 Control *Control::find_valid_focus_neighbor(Side p_side) const {
 Control *Control::find_valid_focus_neighbor(Side p_side) const {
 	return const_cast<Control *>(this)->_get_focus_neighbor(p_side);
 	return const_cast<Control *>(this)->_get_focus_neighbor(p_side);
 }
 }
@@ -2624,7 +2618,7 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
 	Container *container = Object::cast_to<Container>(p_at);
 	Container *container = Object::cast_to<Container>(p_at);
 	bool in_container = container ? container->is_ancestor_of(this) : false;
 	bool in_container = container ? container->is_ancestor_of(this) : false;
 
 
-	if (c && c != this && ((c->get_focus_mode_with_recursive() == FOCUS_ALL) || (ac_enabled && c->get_focus_mode_with_recursive() == FOCUS_ACCESSIBILITY)) && !in_container && p_clamp.intersects(c->get_global_rect())) {
+	if (c && c != this && ((c->get_focus_mode_with_override() == FOCUS_ALL) || (ac_enabled && c->get_focus_mode_with_override() == FOCUS_ACCESSIBILITY)) && !in_container && p_clamp.intersects(c->get_global_rect())) {
 		Rect2 r_c = c->get_global_rect();
 		Rect2 r_c = c->get_global_rect();
 		r_c = r_c.intersection(p_clamp);
 		r_c = r_c.intersection(p_clamp);
 		real_t begin_d = p_dir.dot(r_c.get_position());
 		real_t begin_d = p_dir.dot(r_c.get_position());
@@ -3627,8 +3621,8 @@ void Control::_notification(int p_notification) {
 
 
 			_update_layout_mode();
 			_update_layout_mode();
 
 
-			_set_focus_recursive_behavior_ignore_cache(data.focus_recursive_behavior);
-			_set_mouse_recursive_behavior_ignore_cache(data.mouse_recursive_behavior);
+			_update_focus_behavior_recursive();
+			_update_mouse_behavior_recursive();
 		} break;
 		} break;
 
 
 		case NOTIFICATION_UNPARENTED: {
 		case NOTIFICATION_UNPARENTED: {
@@ -3849,9 +3843,9 @@ void Control::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect);
 	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("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"), &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("get_focus_mode_with_override"), &Control::get_focus_mode_with_override);
+	ClassDB::bind_method(D_METHOD("set_focus_behavior_recursive", "focus_behavior_recursive"), &Control::set_focus_behavior_recursive);
+	ClassDB::bind_method(D_METHOD("get_focus_behavior_recursive"), &Control::get_focus_behavior_recursive);
 	ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus);
 	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("grab_focus"), &Control::grab_focus);
 	ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus);
 	ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus);
@@ -3950,10 +3944,10 @@ void Control::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("set_mouse_filter", "filter"), &Control::set_mouse_filter);
 	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"), &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("get_mouse_filter_with_override"), &Control::get_mouse_filter_with_override);
 
 
-	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_mouse_behavior_recursive", "mouse_behavior_recursive"), &Control::set_mouse_behavior_recursive);
+	ClassDB::bind_method(D_METHOD("get_mouse_behavior_recursive"), &Control::get_mouse_behavior_recursive);
 
 
 	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("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);
 	ClassDB::bind_method(D_METHOD("is_force_pass_scroll_events"), &Control::is_force_pass_scroll_events);
@@ -4050,11 +4044,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_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::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,Accessibility"), "set_focus_mode", "get_focus_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All,Accessibility"), "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_PROPERTY(PropertyInfo(Variant::INT, "focus_behavior_recursive", PROPERTY_HINT_ENUM, "Inherited,Disabled,Enabled"), "set_focus_behavior_recursive", "get_focus_behavior_recursive");
 
 
 	ADD_GROUP("Mouse", "mouse_");
 	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_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::INT, "mouse_behavior_recursive", PROPERTY_HINT_ENUM, "Inherited,Disabled,Enabled"), "set_mouse_behavior_recursive", "get_mouse_behavior_recursive");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events");
 	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");
 	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");
 
 
@@ -4070,9 +4064,13 @@ void Control::_bind_methods() {
 	BIND_ENUM_CONSTANT(FOCUS_ALL);
 	BIND_ENUM_CONSTANT(FOCUS_ALL);
 	BIND_ENUM_CONSTANT(FOCUS_ACCESSIBILITY);
 	BIND_ENUM_CONSTANT(FOCUS_ACCESSIBILITY);
 
 
-	BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_INHERITED);
-	BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_DISABLED);
-	BIND_ENUM_CONSTANT(RECURSIVE_BEHAVIOR_ENABLED);
+	BIND_ENUM_CONSTANT(FOCUS_BEHAVIOR_INHERITED);
+	BIND_ENUM_CONSTANT(FOCUS_BEHAVIOR_DISABLED);
+	BIND_ENUM_CONSTANT(FOCUS_BEHAVIOR_ENABLED);
+
+	BIND_ENUM_CONSTANT(MOUSE_BEHAVIOR_INHERITED);
+	BIND_ENUM_CONSTANT(MOUSE_BEHAVIOR_DISABLED);
+	BIND_ENUM_CONSTANT(MOUSE_BEHAVIOR_ENABLED);
 
 
 	BIND_CONSTANT(NOTIFICATION_RESIZED);
 	BIND_CONSTANT(NOTIFICATION_RESIZED);
 	BIND_CONSTANT(NOTIFICATION_MOUSE_ENTER);
 	BIND_CONSTANT(NOTIFICATION_MOUSE_ENTER);

+ 28 - 21
scene/gui/control.h

@@ -68,10 +68,10 @@ public:
 		FOCUS_ACCESSIBILITY,
 		FOCUS_ACCESSIBILITY,
 	};
 	};
 
 
-	enum RecursiveBehavior {
-		RECURSIVE_BEHAVIOR_INHERITED,
-		RECURSIVE_BEHAVIOR_DISABLED,
-		RECURSIVE_BEHAVIOR_ENABLED,
+	enum FocusBehaviorRecursive {
+		FOCUS_BEHAVIOR_INHERITED,
+		FOCUS_BEHAVIOR_DISABLED,
+		FOCUS_BEHAVIOR_ENABLED,
 	};
 	};
 
 
 	enum SizeFlags {
 	enum SizeFlags {
@@ -90,6 +90,12 @@ public:
 		MOUSE_FILTER_IGNORE
 		MOUSE_FILTER_IGNORE
 	};
 	};
 
 
+	enum MouseBehaviorRecursive {
+		MOUSE_BEHAVIOR_INHERITED,
+		MOUSE_BEHAVIOR_DISABLED,
+		MOUSE_BEHAVIOR_ENABLED,
+	};
+
 	enum CursorShape {
 	enum CursorShape {
 		CURSOR_ARROW,
 		CURSOR_ARROW,
 		CURSOR_IBEAM,
 		CURSOR_IBEAM,
@@ -197,8 +203,8 @@ private:
 		real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
 		real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
 		real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
 		real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
 		FocusMode focus_mode = FOCUS_NONE;
 		FocusMode focus_mode = FOCUS_NONE;
-		RecursiveBehavior parent_focus_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED;
-		RecursiveBehavior focus_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED;
+		FocusBehaviorRecursive focus_behavior_recursive = FOCUS_BEHAVIOR_INHERITED;
+		bool parent_focus_behavior_recursive_enabled = false;
 		GrowDirection h_grow = GROW_DIRECTION_END;
 		GrowDirection h_grow = GROW_DIRECTION_END;
 		GrowDirection v_grow = GROW_DIRECTION_END;
 		GrowDirection v_grow = GROW_DIRECTION_END;
 
 
@@ -227,8 +233,8 @@ private:
 		// Input events and rendering.
 		// Input events and rendering.
 
 
 		MouseFilter mouse_filter = MOUSE_FILTER_STOP;
 		MouseFilter mouse_filter = MOUSE_FILTER_STOP;
-		RecursiveBehavior parent_mouse_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED;
-		RecursiveBehavior mouse_recursive_behavior = RECURSIVE_BEHAVIOR_INHERITED;
+		MouseBehaviorRecursive mouse_behavior_recursive = MOUSE_BEHAVIOR_INHERITED;
+		bool parent_mouse_behavior_recursive_enabled = true;
 		bool force_pass_scroll_events = true;
 		bool force_pass_scroll_events = true;
 
 
 		bool clip_contents = false;
 		bool clip_contents = false;
@@ -325,17 +331,17 @@ private:
 
 
 	// Mouse Filter.
 	// Mouse Filter.
 
 
-	bool _is_parent_mouse_disabled() const;
+	bool _is_mouse_filter_enabled() const;
+	void _update_mouse_behavior_recursive();
+	void _propagate_mouse_behavior_recursive_recursively(bool p_enabled, bool p_skip_non_inherited);
 
 
 	// Focus.
 	// Focus.
 
 
 	void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Rect2 &p_rect, const Rect2 &p_clamp, real_t p_min, real_t &r_closest_dist_squared, Control **r_closest);
 	void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Rect2 &p_rect, const Rect2 &p_clamp, real_t p_min, real_t &r_closest_dist_squared, Control **r_closest);
 	Control *_get_focus_neighbor(Side p_side, int p_count = 0);
 	Control *_get_focus_neighbor(Side p_side, int p_count = 0);
-	bool _is_focus_disabled_recursively() const;
-	void _propagate_focus_behavior_recursively(RecursiveBehavior p_focus_recursive_behavior, bool p_force);
-	void _propagate_mouse_behavior_recursively(RecursiveBehavior p_focus_recursive_behavior, bool p_force);
-	void _set_mouse_recursive_behavior_ignore_cache(RecursiveBehavior p_recursive_mouse_behavior);
-	void _set_focus_recursive_behavior_ignore_cache(RecursiveBehavior p_recursive_mouse_behavior);
+	bool _is_focus_mode_enabled() const;
+	void _update_focus_behavior_recursive();
+	void _propagate_focus_behavior_recursive_recursively(bool p_enabled, bool p_skip_non_inherited);
 
 
 	// Theming.
 	// Theming.
 
 
@@ -541,10 +547,10 @@ public:
 
 
 	void set_mouse_filter(MouseFilter p_filter);
 	void set_mouse_filter(MouseFilter p_filter);
 	MouseFilter get_mouse_filter() const;
 	MouseFilter get_mouse_filter() const;
-	MouseFilter get_mouse_filter_with_recursive() const;
+	MouseFilter get_mouse_filter_with_override() const;
 
 
-	void set_mouse_recursive_behavior(RecursiveBehavior p_recursive_mouse_behavior);
-	RecursiveBehavior get_mouse_recursive_behavior() const;
+	void set_mouse_behavior_recursive(MouseBehaviorRecursive p_mouse_behavior_recursive);
+	MouseBehaviorRecursive get_mouse_behavior_recursive() const;
 
 
 	void set_force_pass_scroll_events(bool p_force_pass_scroll_events);
 	void set_force_pass_scroll_events(bool p_force_pass_scroll_events);
 	bool is_force_pass_scroll_events() const;
 	bool is_force_pass_scroll_events() const;
@@ -571,9 +577,9 @@ public:
 
 
 	void set_focus_mode(FocusMode p_focus_mode);
 	void set_focus_mode(FocusMode p_focus_mode);
 	FocusMode get_focus_mode() const;
 	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;
+	FocusMode get_focus_mode_with_override() const;
+	void set_focus_behavior_recursive(FocusBehaviorRecursive p_focus_behavior_recursive);
+	FocusBehaviorRecursive get_focus_behavior_recursive() const;
 	bool has_focus() const;
 	bool has_focus() const;
 	void grab_focus();
 	void grab_focus();
 	void grab_click_focus();
 	void grab_click_focus();
@@ -695,7 +701,8 @@ public:
 };
 };
 
 
 VARIANT_ENUM_CAST(Control::FocusMode);
 VARIANT_ENUM_CAST(Control::FocusMode);
-VARIANT_ENUM_CAST(Control::RecursiveBehavior);
+VARIANT_ENUM_CAST(Control::FocusBehaviorRecursive);
+VARIANT_ENUM_CAST(Control::MouseBehaviorRecursive);
 VARIANT_BITFIELD_CAST(Control::SizeFlags);
 VARIANT_BITFIELD_CAST(Control::SizeFlags);
 VARIANT_ENUM_CAST(Control::CursorShape);
 VARIANT_ENUM_CAST(Control::CursorShape);
 VARIANT_ENUM_CAST(Control::LayoutPreset);
 VARIANT_ENUM_CAST(Control::LayoutPreset);

+ 1 - 1
scene/gui/graph_edit.cpp

@@ -1421,7 +1421,7 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos
 	control_rect.size *= zoom;
 	control_rect.size *= zoom;
 	control_rect.position += p_offset;
 	control_rect.position += p_offset;
 
 
-	if (!control_rect.has_point(mpos) || p_control->get_mouse_filter_with_recursive() == MOUSE_FILTER_IGNORE) {
+	if (!control_rect.has_point(mpos) || p_control->get_mouse_filter_with_override() == MOUSE_FILTER_IGNORE) {
 		// Test children.
 		// Test children.
 		for (int i = 0; i < p_control->get_child_count(); i++) {
 		for (int i = 0; i < p_control->get_child_count(); i++) {
 			Control *child_rect = Object::cast_to<Control>(p_control->get_child(i));
 			Control *child_rect = Object::cast_to<Control>(p_control->get_child(i));

+ 2 - 2
scene/gui/slider.cpp

@@ -89,12 +89,12 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
 			}
 			}
 		} else if (scrollable) {
 		} else if (scrollable) {
 			if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
 			if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP) {
-				if (get_focus_mode_with_recursive() != FOCUS_NONE) {
+				if (get_focus_mode_with_override() != FOCUS_NONE) {
 					grab_focus();
 					grab_focus();
 				}
 				}
 				set_value(get_value() + get_step());
 				set_value(get_value() + get_step());
 			} else if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
 			} else if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN) {
-				if (get_focus_mode_with_recursive() != FOCUS_NONE) {
+				if (get_focus_mode_with_override() != FOCUS_NONE) {
 					grab_focus();
 					grab_focus();
 				}
 				}
 				set_value(get_value() - get_step());
 				set_value(get_value() - get_step());

+ 1 - 1
scene/gui/tab_container.cpp

@@ -773,7 +773,7 @@ void TabContainer::set_tab_focus_mode(Control::FocusMode p_focus_mode) {
 }
 }
 
 
 Control::FocusMode TabContainer::get_tab_focus_mode() const {
 Control::FocusMode TabContainer::get_tab_focus_mode() const {
-	return tab_bar->get_focus_mode_with_recursive();
+	return tab_bar->get_focus_mode();
 }
 }
 
 
 void TabContainer::set_clip_tabs(bool p_clip_tabs) {
 void TabContainer::set_clip_tabs(bool p_clip_tabs) {

+ 17 - 17
scene/main/viewport.cpp

@@ -750,7 +750,7 @@ void Viewport::_process_picking() {
 #endif // PHYSICS_2D_DISABLED
 #endif // PHYSICS_2D_DISABLED
 
 
 	SubViewportContainer *parent_svc = Object::cast_to<SubViewportContainer>(get_parent());
 	SubViewportContainer *parent_svc = Object::cast_to<SubViewportContainer>(get_parent());
-	bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE);
+	bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter_with_override() == Control::MOUSE_FILTER_IGNORE);
 	bool create_passive_hover_event = true;
 	bool create_passive_hover_event = true;
 	if (gui.mouse_over || parent_ignore_mouse) {
 	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.
 		// When the mouse is over a Control node, passive hovering would cause input events for Colliders, that are behind Control nodes.
@@ -1546,7 +1546,7 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
 
 
 		// Otherwise, we check parent controls unless some conditions prevent it.
 		// Otherwise, we check parent controls unless some conditions prevent it.
 
 
-		if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+		if (p_control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 			break;
 			break;
 		}
 		}
 		if (p_control->is_set_as_top_level()) {
 		if (p_control->is_set_as_top_level()) {
@@ -1717,14 +1717,14 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
 	while (ci) {
 	while (ci) {
 		Control *control = Object::cast_to<Control>(ci);
 		Control *control = Object::cast_to<Control>(ci);
 		if (control) {
 		if (control) {
-			if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
+			if (control->get_mouse_filter_with_override() != Control::MOUSE_FILTER_IGNORE) {
 				control->_call_gui_input(ev);
 				control->_call_gui_input(ev);
 			}
 			}
 
 
 			if (!control->is_inside_tree() || control->is_set_as_top_level()) {
 			if (!control->is_inside_tree() || control->is_set_as_top_level()) {
 				break;
 				break;
 			}
 			}
-			if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP && is_pointer_event && !(is_scroll_event && control->data.force_pass_scroll_events)) {
+			if (control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP && is_pointer_event && !(is_scroll_event && control->data.force_pass_scroll_events)) {
 				// Mouse, ScreenDrag and ScreenTouch events are stopped by default with MOUSE_FILTER_STOP, unless we have a scroll event and force_pass_scroll_events set to true
 				// Mouse, ScreenDrag and ScreenTouch events are stopped by default with MOUSE_FILTER_STOP, unless we have a scroll event and force_pass_scroll_events set to true
 				set_input_as_handled();
 				set_input_as_handled();
 				break;
 				break;
@@ -1750,7 +1750,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
 	while (ci) {
 	while (ci) {
 		Control *control = Object::cast_to<Control>(ci);
 		Control *control = Object::cast_to<Control>(ci);
 		if (control) {
 		if (control) {
-			if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
+			if (control->get_mouse_filter_with_override() != Control::MOUSE_FILTER_IGNORE) {
 				control->notification(p_what);
 				control->notification(p_what);
 			}
 			}
 
 
@@ -1761,7 +1761,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
 			if (!control->is_inside_tree() || control->is_set_as_top_level()) {
 			if (!control->is_inside_tree() || control->is_set_as_top_level()) {
 				break;
 				break;
 			}
 			}
-			if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+			if (control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -1831,7 +1831,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
 		}
 		}
 	}
 	}
 
 
-	if (!c || c->data.mouse_filter == Control::MOUSE_FILTER_IGNORE) {
+	if (!c || c->get_mouse_filter_with_override() == Control::MOUSE_FILTER_IGNORE) {
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
@@ -1863,7 +1863,7 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che
 				return true;
 				return true;
 			}
 			}
 
 
-			if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+			if (control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -1929,7 +1929,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 				while (ci) {
 				while (ci) {
 					Control *control = Object::cast_to<Control>(ci);
 					Control *control = Object::cast_to<Control>(ci);
 					if (control) {
 					if (control) {
-						if (control->get_focus_mode_with_recursive() != Control::FOCUS_NONE) {
+						if (control->get_focus_mode_with_override() != Control::FOCUS_NONE) {
 							// Grabbing unhovered focus can cause issues when mouse is dragged
 							// Grabbing unhovered focus can cause issues when mouse is dragged
 							// with another button held down.
 							// with another button held down.
 							if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) {
 							if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) {
@@ -1938,7 +1938,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 							break;
 							break;
 						}
 						}
 
 
-						if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+						if (control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 							break;
 							break;
 						}
 						}
 					}
 					}
@@ -2024,7 +2024,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 								section_root->gui.global_dragging = false;
 								section_root->gui.global_dragging = false;
 							}
 							}
 
 
-							if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+							if (control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 								break;
 								break;
 							}
 							}
 						}
 						}
@@ -2116,7 +2116,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 					if (cursor_shape != Control::CURSOR_ARROW) {
 					if (cursor_shape != Control::CURSOR_ARROW) {
 						break;
 						break;
 					}
 					}
-					if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
+					if (c->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 						break;
 						break;
 					}
 					}
 					if (c->is_set_as_top_level()) {
 					if (c->is_set_as_top_level()) {
@@ -2550,7 +2550,7 @@ void Viewport::_gui_update_mouse_over() {
 			int found = gui.mouse_over_hierarchy.find(ancestor_control);
 			int found = gui.mouse_over_hierarchy.find(ancestor_control);
 			if (found >= 0) {
 			if (found >= 0) {
 				// Remove the node if the propagation chain has been broken or it is now MOUSE_FILTER_IGNORE.
 				// Remove the node if the propagation chain has been broken or it is now MOUSE_FILTER_IGNORE.
-				if (removing || ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE) {
+				if (removing || ancestor_control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_IGNORE) {
 					needs_exit.push_back(found);
 					needs_exit.push_back(found);
 				}
 				}
 			}
 			}
@@ -2561,14 +2561,14 @@ void Viewport::_gui_update_mouse_over() {
 				}
 				}
 				reached_top = true;
 				reached_top = true;
 			}
 			}
-			if (!removing && ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) {
+			if (!removing && ancestor_control->get_mouse_filter_with_override() != Control::MOUSE_FILTER_IGNORE) {
 				new_mouse_over_hierarchy.push_back(ancestor_control);
 				new_mouse_over_hierarchy.push_back(ancestor_control);
 				// Add the node if it was not found and it is now not MOUSE_FILTER_IGNORE.
 				// Add the node if it was not found and it is now not MOUSE_FILTER_IGNORE.
 				if (found < 0) {
 				if (found < 0) {
 					needs_enter.push_back(ancestor_control);
 					needs_enter.push_back(ancestor_control);
 				}
 				}
 			}
 			}
-			if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) {
+			if (ancestor_control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 				// MOUSE_FILTER_STOP breaks the propagation chain.
 				// MOUSE_FILTER_STOP breaks the propagation chain.
 				if (reached_top) {
 				if (reached_top) {
 					break;
 					break;
@@ -3229,7 +3229,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
 			while (ancestor) {
 			while (ancestor) {
 				Control *ancestor_control = Object::cast_to<Control>(ancestor);
 				Control *ancestor_control = Object::cast_to<Control>(ancestor);
 				if (ancestor_control) {
 				if (ancestor_control) {
-					if (ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) {
+					if (ancestor_control->get_mouse_filter_with_override() != Control::MOUSE_FILTER_IGNORE) {
 						int found = gui.mouse_over_hierarchy.find(ancestor_control);
 						int found = gui.mouse_over_hierarchy.find(ancestor_control);
 						if (found >= 0) {
 						if (found >= 0) {
 							common_ancestor = gui.mouse_over_hierarchy[found];
 							common_ancestor = gui.mouse_over_hierarchy[found];
@@ -3237,7 +3237,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
 						}
 						}
 						over_ancestors.push_back(ancestor_control);
 						over_ancestors.push_back(ancestor_control);
 					}
 					}
-					if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) {
+					if (ancestor_control->get_mouse_filter_with_override() == Control::MOUSE_FILTER_STOP) {
 						// MOUSE_FILTER_STOP breaks the propagation chain.
 						// MOUSE_FILTER_STOP breaks the propagation chain.
 						break;
 						break;
 					}
 					}

+ 56 - 0
tests/scene/test_control.h

@@ -138,6 +138,62 @@ TEST_CASE("[SceneTree][Control] Focus") {
 		memdelete(child_ctrl);
 		memdelete(child_ctrl);
 	}
 	}
 
 
+	SUBCASE("[SceneTree][Control] Grab focus with focus behavior recursive") {
+		CHECK_UNARY_FALSE(ctrl->has_focus());
+
+		// Cannot grab focus if focus behavior is disabled.
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		ctrl->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_DISABLED);
+
+		ERR_PRINT_OFF
+		ctrl->grab_focus();
+		ERR_PRINT_ON
+		CHECK_UNARY_FALSE(ctrl->has_focus());
+
+		// Cannot grab focus if focus behavior is enabled but focus mode is none.
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+		ctrl->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_ENABLED);
+
+		ERR_PRINT_OFF
+		ctrl->grab_focus();
+		ERR_PRINT_ON
+		CHECK_UNARY_FALSE(ctrl->has_focus());
+
+		// Can grab focus if focus behavior is enabled and focus mode is all.
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		ctrl->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_ENABLED);
+
+		ctrl->grab_focus();
+		CHECK_UNARY(ctrl->has_focus());
+	}
+
+	SUBCASE("[SceneTree][Control] Children focus with focus behavior recursive") {
+		Control *child_control = memnew(Control);
+		ctrl->add_child(child_control);
+
+		// Can grab focus on child if parent focus behavior is inherit.
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		ctrl->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_INHERITED);
+		child_control->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		child_control->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_INHERITED);
+
+		child_control->grab_focus();
+		CHECK_UNARY(child_control->has_focus());
+
+		// Cannot grab focus on child if parent focus behavior is disabled.
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		ctrl->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_DISABLED);
+		child_control->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		child_control->set_focus_behavior_recursive(Control::FOCUS_BEHAVIOR_INHERITED);
+
+		ERR_PRINT_OFF
+		child_control->grab_focus();
+		ERR_PRINT_ON
+		CHECK_UNARY_FALSE(child_control->has_focus());
+
+		memdelete(child_control);
+	}
+
 	memdelete(ctrl);
 	memdelete(ctrl);
 }
 }
 
 

+ 39 - 0
tests/scene/test_viewport.h

@@ -512,6 +512,45 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
 			CHECK_FALSE(node_d->invalid_order);
 			CHECK_FALSE(node_d->invalid_order);
 		}
 		}
 
 
+		SUBCASE("[Viewport][GuiInputEvent] Mouse behavior recursive disables mouse motion events.") {
+			node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+
+			// Enabled when parent is set to inherit.
+			node_h->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_INHERITED);
+			node_i->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_INHERITED);
+			SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
+			CHECK(node_i->mouse_over);
+			CHECK(node_i->mouse_over_self);
+
+			// Enabled when parent is set to enabled.
+			node_h->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_ENABLED);
+			node_i->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_INHERITED);
+			SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
+			CHECK(node_i->mouse_over);
+			CHECK(node_i->mouse_over_self);
+
+			// Disabled when parent is set to disabled.
+			node_h->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_DISABLED);
+			node_i->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_INHERITED);
+			SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
+			CHECK_FALSE(node_i->mouse_over);
+			CHECK_FALSE(node_i->mouse_over_self);
+
+			// Enabled when set to enabled and parent is set to disabled.
+			node_h->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_DISABLED);
+			node_i->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_ENABLED);
+			SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
+			CHECK(node_i->mouse_over);
+			CHECK(node_i->mouse_over_self);
+
+			// Disabled when it is set to disabled.
+			node_h->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_ENABLED);
+			node_i->set_mouse_behavior_recursive(Control::MOUSE_BEHAVIOR_DISABLED);
+			SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
+			CHECK_FALSE(node_i->mouse_over);
+			CHECK_FALSE(node_i->mouse_over_self);
+		}
+
 		SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation.") {
 		SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation.") {
 			node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
 			node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
 			node_g->set_mouse_filter(Control::MOUSE_FILTER_PASS);
 			node_g->set_mouse_filter(Control::MOUSE_FILTER_PASS);