mirror of
https://github.com/godotengine/godot.git
synced 2025-11-01 22:21:18 +00:00
Implement properties that recursively disables children's focus & mouse filter.
Co-authored-by: Tomasz Chabora <kobewi4e@gmail.com> Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
This commit is contained in:
parent
f2cc3f1275
commit
a49ca33a7f
8 changed files with 212 additions and 18 deletions
|
|
@ -394,6 +394,12 @@
|
||||||
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">
|
||||||
|
<return type="int" enum="Control.FocusMode" />
|
||||||
|
<description>
|
||||||
|
Similar to the getter of [member focus_mode], but takes parent's [member focus_recursive_behavior] into account.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_focus_neighbor" qualifiers="const">
|
<method name="get_focus_neighbor" qualifiers="const">
|
||||||
<return type="NodePath" />
|
<return type="NodePath" />
|
||||||
<param index="0" name="side" type="int" enum="Side" />
|
<param index="0" name="side" type="int" enum="Side" />
|
||||||
|
|
@ -416,6 +422,12 @@
|
||||||
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">
|
||||||
|
<return type="int" enum="Control.MouseFilter" />
|
||||||
|
<description>
|
||||||
|
Similar to the getter of [member mouse_filter], but takes parent's [member mouse_recursive_behavior] into account.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_offset" qualifiers="const">
|
<method name="get_offset" qualifiers="const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<param index="0" name="offset" type="int" enum="Side" />
|
<param index="0" name="offset" type="int" enum="Side" />
|
||||||
|
|
@ -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.
|
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>
|
||||||
|
|
@ -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.
|
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.
|
||||||
|
|
@ -1156,6 +1174,15 @@
|
||||||
<constant name="FOCUS_ALL" value="2" enum="FocusMode">
|
<constant name="FOCUS_ALL" value="2" enum="FocusMode">
|
||||||
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].
|
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].
|
||||||
</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>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
<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.
|
||||||
</constant>
|
</constant>
|
||||||
|
|
|
||||||
|
|
@ -2768,7 +2768,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() != Control::FOCUS_NONE) {
|
if (control && control->get_focus_mode_with_recursive() != 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++) {
|
||||||
|
|
|
||||||
|
|
@ -1866,6 +1866,42 @@ Control::MouseFilter Control::get_mouse_filter() const {
|
||||||
return data.mouse_filter;
|
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(RecursiveBehavior p_recursive_mouse_behavior) {
|
||||||
|
ERR_MAIN_THREAD_GUARD;
|
||||||
|
ERR_FAIL_INDEX((int)p_recursive_mouse_behavior, 4);
|
||||||
|
if (data.mouse_recursive_behavior == p_recursive_mouse_behavior) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.mouse_recursive_behavior = p_recursive_mouse_behavior;
|
||||||
|
if (p_recursive_mouse_behavior == RECURSIVE_BEHAVIOR_INHERITED) {
|
||||||
|
Control *parent = get_parent_control();
|
||||||
|
if (parent) {
|
||||||
|
_apply_mouse_behavior_recursively(parent->data.parent_mouse_recursive_behavior, false);
|
||||||
|
} else {
|
||||||
|
_apply_mouse_behavior_recursively(RECURSIVE_BEHAVIOR_ENABLED, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_apply_mouse_behavior_recursively(p_recursive_mouse_behavior, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
void Control::set_force_pass_scroll_events(bool p_force_pass_scroll_events) {
|
||||||
ERR_MAIN_THREAD_GUARD;
|
ERR_MAIN_THREAD_GUARD;
|
||||||
data.force_pass_scroll_events = p_force_pass_scroll_events;
|
data.force_pass_scroll_events = p_force_pass_scroll_events;
|
||||||
|
|
@ -2014,6 +2050,38 @@ Control::FocusMode Control::get_focus_mode() const {
|
||||||
return data.focus_mode;
|
return data.focus_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Control::FocusMode Control::get_focus_mode_with_recursive() const {
|
||||||
|
ERR_READ_THREAD_GUARD_V(FOCUS_NONE);
|
||||||
|
if (_is_focus_disabled_recursively()) {
|
||||||
|
return FOCUS_NONE;
|
||||||
|
}
|
||||||
|
return data.focus_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Control::set_focus_recursive_behavior(RecursiveBehavior p_recursive_focus_behavior) {
|
||||||
|
ERR_MAIN_THREAD_GUARD;
|
||||||
|
ERR_FAIL_INDEX((int)p_recursive_focus_behavior, 4);
|
||||||
|
if (data.focus_recursive_behavior == p_recursive_focus_behavior) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.focus_recursive_behavior = p_recursive_focus_behavior;
|
||||||
|
if (p_recursive_focus_behavior == RECURSIVE_BEHAVIOR_INHERITED) {
|
||||||
|
Control *parent = get_parent_control();
|
||||||
|
if (parent) {
|
||||||
|
_apply_focus_behavior_recursively(parent->data.parent_focus_recursive_behavior, false);
|
||||||
|
} else {
|
||||||
|
_apply_focus_behavior_recursively(RECURSIVE_BEHAVIOR_ENABLED, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_apply_focus_behavior_recursively(p_recursive_focus_behavior, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
bool Control::has_focus() const {
|
||||||
ERR_READ_THREAD_GUARD_V(false);
|
ERR_READ_THREAD_GUARD_V(false);
|
||||||
return is_inside_tree() && get_viewport()->_gui_control_has_focus(this);
|
return is_inside_tree() && get_viewport()->_gui_control_has_focus(this);
|
||||||
|
|
@ -2084,7 +2152,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->data.focus_mode != FOCUS_NONE) {
|
if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2128,7 +2196,7 @@ Control *Control::find_next_valid_focus() const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_child->data.focus_mode == FOCUS_ALL) {
|
if (next_child->get_focus_mode_with_recursive() == FOCUS_ALL) {
|
||||||
return next_child;
|
return next_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2165,7 +2233,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->data.focus_mode != FOCUS_NONE) {
|
if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2201,7 +2269,7 @@ Control *Control::find_prev_valid_focus() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev_child->data.focus_mode == FOCUS_ALL) {
|
if (prev_child->get_focus_mode_with_recursive() == FOCUS_ALL) {
|
||||||
return prev_child;
|
return prev_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2260,7 +2328,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->data.focus_mode != FOCUS_NONE) {
|
if (c->is_visible_in_tree() && c->get_focus_mode_with_recursive() != FOCUS_NONE) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2369,6 +2437,64 @@ 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::_apply_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->_apply_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::_apply_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->_apply_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);
|
||||||
}
|
}
|
||||||
|
|
@ -2382,7 +2508,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() == FOCUS_ALL && !in_container && p_clamp.intersects(c->get_global_rect())) {
|
if (c && c != this && c->get_focus_mode_with_recursive() == FOCUS_ALL && !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());
|
||||||
|
|
@ -3285,6 +3411,9 @@ void Control::_notification(int p_notification) {
|
||||||
data.theme_owner->assign_theme_on_parented(this);
|
data.theme_owner->assign_theme_on_parented(this);
|
||||||
|
|
||||||
_update_layout_mode();
|
_update_layout_mode();
|
||||||
|
|
||||||
|
set_focus_recursive_behavior(data.focus_recursive_behavior);
|
||||||
|
set_mouse_recursive_behavior(data.mouse_recursive_behavior);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_UNPARENTED: {
|
case NOTIFICATION_UNPARENTED: {
|
||||||
|
|
@ -3505,6 +3634,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("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);
|
||||||
|
|
@ -3600,6 +3732,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("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("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);
|
||||||
|
|
@ -3696,9 +3832,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"), "set_focus_mode", "get_focus_mode");
|
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_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::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");
|
||||||
|
|
||||||
|
|
@ -3713,6 +3851,10 @@ void Control::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(FOCUS_CLICK);
|
BIND_ENUM_CONSTANT(FOCUS_CLICK);
|
||||||
BIND_ENUM_CONSTANT(FOCUS_ALL);
|
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_RESIZED);
|
||||||
BIND_CONSTANT(NOTIFICATION_MOUSE_ENTER);
|
BIND_CONSTANT(NOTIFICATION_MOUSE_ENTER);
|
||||||
BIND_CONSTANT(NOTIFICATION_MOUSE_EXIT);
|
BIND_CONSTANT(NOTIFICATION_MOUSE_EXIT);
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,12 @@ public:
|
||||||
FOCUS_ALL
|
FOCUS_ALL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RecursiveBehavior {
|
||||||
|
RECURSIVE_BEHAVIOR_INHERITED,
|
||||||
|
RECURSIVE_BEHAVIOR_DISABLED,
|
||||||
|
RECURSIVE_BEHAVIOR_ENABLED,
|
||||||
|
};
|
||||||
|
|
||||||
enum SizeFlags {
|
enum SizeFlags {
|
||||||
SIZE_SHRINK_BEGIN = 0,
|
SIZE_SHRINK_BEGIN = 0,
|
||||||
SIZE_FILL = 1,
|
SIZE_FILL = 1,
|
||||||
|
|
@ -191,6 +197,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;
|
||||||
GrowDirection h_grow = GROW_DIRECTION_END;
|
GrowDirection h_grow = GROW_DIRECTION_END;
|
||||||
GrowDirection v_grow = GROW_DIRECTION_END;
|
GrowDirection v_grow = GROW_DIRECTION_END;
|
||||||
|
|
||||||
|
|
@ -219,6 +227,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;
|
||||||
bool force_pass_scroll_events = true;
|
bool force_pass_scroll_events = true;
|
||||||
|
|
||||||
bool clip_contents = false;
|
bool clip_contents = false;
|
||||||
|
|
@ -312,10 +322,17 @@ private:
|
||||||
|
|
||||||
void _call_gui_input(const Ref<InputEvent> &p_event);
|
void _call_gui_input(const Ref<InputEvent> &p_event);
|
||||||
|
|
||||||
|
// Mouse Filter.
|
||||||
|
|
||||||
|
bool _is_parent_mouse_disabled() const;
|
||||||
|
|
||||||
// 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 _apply_focus_behavior_recursively(RecursiveBehavior p_focus_recursive_behavior, bool p_force);
|
||||||
|
void _apply_mouse_behavior_recursively(RecursiveBehavior p_focus_recursive_behavior, bool p_force);
|
||||||
|
|
||||||
// Theming.
|
// Theming.
|
||||||
|
|
||||||
|
|
@ -516,6 +533,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;
|
||||||
|
|
||||||
|
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);
|
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;
|
||||||
|
|
@ -540,6 +561,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;
|
||||||
bool has_focus() const;
|
bool has_focus() const;
|
||||||
void grab_focus();
|
void grab_focus();
|
||||||
void grab_click_focus();
|
void grab_click_focus();
|
||||||
|
|
@ -657,6 +681,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(Control::FocusMode);
|
VARIANT_ENUM_CAST(Control::FocusMode);
|
||||||
|
VARIANT_ENUM_CAST(Control::RecursiveBehavior);
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -1198,7 +1198,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() == MOUSE_FILTER_IGNORE) {
|
if (!control_rect.has_point(mpos) || p_control->get_mouse_filter_with_recursive() == 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));
|
||||||
|
|
|
||||||
|
|
@ -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() != FOCUS_NONE) {
|
if (get_focus_mode_with_recursive() != 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() != FOCUS_NONE) {
|
if (get_focus_mode_with_recursive() != FOCUS_NONE) {
|
||||||
grab_focus();
|
grab_focus();
|
||||||
}
|
}
|
||||||
set_value(get_value() - get_step());
|
set_value(get_value() - get_step());
|
||||||
|
|
|
||||||
|
|
@ -725,7 +725,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();
|
return tab_bar->get_focus_mode_with_recursive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabContainer::set_clip_tabs(bool p_clip_tabs) {
|
void TabContainer::set_clip_tabs(bool p_clip_tabs) {
|
||||||
|
|
|
||||||
|
|
@ -722,7 +722,7 @@ void Viewport::_process_picking() {
|
||||||
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
|
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
|
||||||
|
|
||||||
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() == 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;
|
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.
|
||||||
|
|
@ -1832,7 +1832,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() != Control::FOCUS_NONE) {
|
if (control->get_focus_mode_with_recursive() != 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)) {
|
||||||
|
|
@ -2410,7 +2410,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() == Control::MOUSE_FILTER_IGNORE) {
|
if (removing || ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE) {
|
||||||
needs_exit.push_back(found);
|
needs_exit.push_back(found);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2421,14 +2421,14 @@ void Viewport::_gui_update_mouse_over() {
|
||||||
}
|
}
|
||||||
reached_top = true;
|
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);
|
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() == Control::MOUSE_FILTER_STOP) {
|
if (ancestor_control->get_mouse_filter_with_recursive() == 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;
|
||||||
|
|
@ -3087,7 +3087,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() != 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);
|
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];
|
||||||
|
|
@ -3095,7 +3095,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() == Control::MOUSE_FILTER_STOP) {
|
if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) {
|
||||||
// MOUSE_FILTER_STOP breaks the propagation chain.
|
// MOUSE_FILTER_STOP breaks the propagation chain.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue