Repository: godotengine/godot (language: cpp)

Issue:
Control in invisible container acquire focus and loose it immediately with custom neightbors
### Tested versions

- Reproducible in v4.3.stable.official [77dcf97d8]

### System information

Godot v4.3.stable - Ubuntu 24.04 LTS 24.04 - Wayland - GLES3 (Compatibility)

### Issue description

By default (current and correct behavior), when a control is not visible, either because it's `visible` property is set to `false`, or because it's parent is not visible, then the control cannot acquire focus, and focus skips the control.


When a control's neighbors or `focus_next` or `focus_previous` are set explicitely, and wether the control's `visible` property is set to `true` or `false`, the behavior is the same (expected).

However, if the control 's `visible` property is set to `true`, but the control is effectively not visible due to a parent not being visible, then the control CAN acquire focus, and then looses it immediately, resulting in no control having focus. This makes focus navigation between controls impossible when mixing invisible containers and explicitly set neighbors.


https://github.com/user-attachments/assets/09a2d88b-2ecb-426d-8979-99d1a4570577



### Steps to reproduce

- Open the MRP
- Check / Uncheck the checkboxes, and naviguate focus between controls with TAB and SHIFT + TAB, to test the configurations I mentioned.

### Minimal reproduction project (MRP)

[mrp-invisible-control-focus.zip](https://github.com/user-attachments/files/16648076/mrp-invisible-control-focus.zip)



Discussion / hints:

Fix patch:
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 92b5f327775a..389c29a240b9 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2054,7 +2054,7 @@ static Control *_next_control(Control *p_from) {
 		return nullptr; // Can't go above.
 	}
 
-	Control *parent = Object::cast_to<Control>(p_from->get_parent());
+	Control *parent = p_from->get_parent_control();
 
 	if (!parent) {
 		return nullptr;
@@ -2077,21 +2077,21 @@ static Control *_next_control(Control *p_from) {
 
 Control *Control::find_next_valid_focus() const {
 	ERR_READ_THREAD_GUARD_V(nullptr);
-	Control *from = const_cast<Control *>(this);
 
-	while (true) {
-		// If the focus property is manually overwritten, attempt to use it.
-
-		if (!data.focus_next.is_empty()) {
-			Node *n = get_node_or_null(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);
-			ERR_FAIL_NULL_V_MSG(c, nullptr, "Next focus node is not a control: '" + n->get_name() + "'.");
-			if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE) {
-				return c;
-			}
+	// If the focus property is manually overwritten, attempt to use it.
+	if (!data.focus_next.is_empty()) {
+		Node *n = get_node_or_null(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);
+		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) {
+			return c;
 		}
+	}
+
+	Control *from = const_cast<Control *>(this);
 
+	while (true) {
 		// Find next child.
 
 		Control *next_child = nullptr;
@@ -2110,83 +2110,77 @@ Control *Control::find_next_valid_focus() const {
 			next_child = _next_control(from);
 			if (!next_child) { // Nothing else. Go up and find either window or subwindow.
 				next_child = const_cast<Control *>(this);
-				while (next_child && !next_child->is_set_as_top_level()) {
-					next_child = cast_to<Control>(next_child->get_parent());
-				}
 
-				if (!next_child) {
-					next_child = const_cast<Control *>(this);
-					while (next_child) {
-						if (next_child->data.RI) {
-							break;
-						}
-						next_child = next_child->get_parent_control();
+				while (next_child) {
+					if (next_child->is_set_as_top_level()) {
+						break;
+					}
+
+					if (next_child->data.RI) {
+						break;
 					}
+					next_child = next_child->data.parent_control;
 				}
 			}
 		}
 
-		if (next_child == from || next_child == this) { // No next control.
-			return (get_focus_mode() == FOCUS_ALL) ? next_child : nullptr;
-		}
-		if (next_child) {
-			if (next_child->get_focus_mode() == FOCUS_ALL) {
-				return next_child;
-			}
-			from = next_child;
-		} else {
+		if (!next_child) {
 			break;
 		}
+
+		if (next_child->data.focus_mode == FOCUS_ALL) {
+			return next_child;
+		}
+
+		if (next_child == from || next_child == this) {
+			return nullptr; // Stuck in a loop with no next control.
+		}
+
+		from = next_child; // Try to find the next control with focus mode FOCUS_ALL.
 	}
 
 	return nullptr;
 }
 
 static Control *_prev_control(Control *p_from) {
-	Control *child = nullptr;
 	for (int i = p_from->get_child_count() - 1; i >= 0; i--) {
 		Control *c = Object::cast_to<Control>(p_from->get_child(i));
 		if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) {
 			continue;
 		}
 
-		child = c;
-		break;
-	}
-
-	if (!child) {
-		return p_from;
+		// Find the last child as prev, try the same in the last child.
+		return _prev_control(c);
 	}
 
-	// No prev in parent, try the same in parent.
-	return _prev_control(child);
+	return p_from; // Not found in the children, return itself.
 }
 
 Control *Control::find_prev_valid_focus() const {
 	ERR_READ_THREAD_GUARD_V(nullptr);
-	Control *from = const_cast<Control *>(this);
 
-	while (true) {
-		// If the focus property is manually overwritten, attempt to use it.
-
-		if (!data.focus_prev.is_empty()) {
-			Node *n = get_node_or_null(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);
-			ERR_FAIL_NULL_V_MSG(c, nullptr, "Previous focus node is not a control: '" + n->get_name() + "'.");
-			if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE) {
-				return c;
-			}
+	// If the focus property is manually overwritten, attempt to use it.
+	if (!data.focus_prev.is_empty()) {
+		Node *n = get_node_or_null(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);
+		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) {
+			return c;
 		}
+	}
 
+	Control *from = const_cast<Control *>(this);
+
+	while (true) {
 		// Find prev child.
 
 		Control *prev_child = nullptr;
 
-		if (from->is_set_as_top_level() || !Object::cast_to<Control>(from->get_parent())) {
+		if (from->is_set_as_top_level() || !from->data.parent_control) {
 			// Find last of the children.
 
-			prev_child = _prev_control(from);
+			prev_child = _prev_control(from); // Wrap start here.
 
 		} else {
 			for (int i = (from->get_index() - 1); i >= 0; i--) {
@@ -2201,21 +2195,21 @@ Control *Control::find_prev_valid_focus() const {
 			}
 
 			if (!prev_child) {
-				prev_child = Object::cast_to<Control>(from->get_parent());
+				prev_child = from->data.parent_control;
 			} else {
 				prev_child = _prev_control(prev_child);
 			}
 		}
 
-		if (prev_child == from || prev_child == this) { // No prev control.
-			return (get_focus_mode() == FOCUS_ALL) ? prev_child : nullptr;
+		if (prev_child->data.focus_mode == FOCUS_ALL) {
+			return prev_child;
 		}
 
-		if (prev_child->get_focus_mode() == FOCUS_ALL) {
-			return prev_child;
+		if (prev_child == from || prev_child == this) {
+			return nullptr; // Stuck in a loop with no prev control.
 		}
 
-		from = prev_child;
+		from = prev_child; // Try to find the prev control with focus mode FOCUS_ALL.
 	}
 
 	return nullptr;
@@ -2266,14 +2260,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] + "'.");
 		Control *c = Object::cast_to<Control>(n);
 		ERR_FAIL_NULL_V_MSG(c, nullptr, "Neighbor focus node is not a control: '" + n->get_name() + "'.");
-		bool valid = true;
-		if (!c->is_visible()) {
-			valid = false;
-		}
-		if (c->get_focus_mode() == FOCUS_NONE) {
-			valid = false;
-		}
-		if (valid) {
+		if (c->is_visible_in_tree() && c->data.focus_mode != FOCUS_NONE) {
 			return c;
 		}
 


Test patch:
diff --git a/tests/scene/test_control.h b/tests/scene/test_control.h
index 557c5b232cf3..540a4f493137 100644
--- a/tests/scene/test_control.h
+++ b/tests/scene/test_control.h
@@ -31,6 +31,7 @@
 #ifndef TEST_CONTROL_H
 #define TEST_CONTROL_H
 
+#include "scene/2d/node_2d.h"
 #include "scene/gui/control.h"
 
 #include "tests/test_macros.h"
@@ -66,7 +67,7 @@ TEST_CASE("[SceneTree][Control] Focus") {
 	SceneTree::get_singleton()->get_root()->add_child(ctrl);
 
 	SUBCASE("[SceneTree][Control] Default focus") {
-		CHECK_FALSE(ctrl->has_focus());
+		CHECK_UNARY_FALSE(ctrl->has_focus());
 	}
 
 	SUBCASE("[SceneTree][Control] Can't grab focus with default focus mode") {
@@ -74,41 +75,828 @@ TEST_CASE("[SceneTree][Control] Focus") {
 		ctrl->grab_focus();
 		ERR_PRINT_ON
 
-		CHECK_FALSE(ctrl->has_focus());
+		CHECK_UNARY_FALSE(ctrl->has_focus());
 	}
 
 	SUBCASE("[SceneTree][Control] Can grab focus") {
 		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
 		ctrl->grab_focus();
 
-		CHECK(ctrl->has_focus());
+		CHECK_UNARY(ctrl->has_focus());
 	}
 
 	SUBCASE("[SceneTree][Control] Can release focus") {
 		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
 		ctrl->grab_focus();
-		CHECK(ctrl->has_focus());
+		CHECK_UNARY(ctrl->has_focus());
 
 		ctrl->release_focus();
-		CHECK_FALSE(ctrl->has_focus());
+		CHECK_UNARY_FALSE(ctrl->has_focus());
 	}
 
 	SUBCASE("[SceneTree][Control] Only one can grab focus at the same time") {
 		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
 		ctrl->grab_focus();
-		CHECK(ctrl->has_focus());
+		CHECK_UNARY(ctrl->has_focus());
 
 		Control *other_ctrl = memnew(Control);
 		SceneTree::get_singleton()->get_root()->add_child(other_ctrl);
 		other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
 		other_ctrl->grab_focus();
 
-		CHECK(other_ctrl->has_focus());
-		CHECK_FALSE(ctrl->has_focus());
+		CHECK_UNARY(other_ctrl->has_focus());
+		CHECK_UNARY_FALSE(ctrl->has_focus());
 
 		memdelete(other_ctrl);
 	}
 
+	SUBCASE("[SceneTree][Control] Hide control will cause the focus to be released") {
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		ctrl->grab_focus();
+		CHECK_UNARY(ctrl->has_focus());
+
+		ctrl->hide();
+		CHECK_UNARY_FALSE(ctrl->has_focus());
+
+		ctrl->show();
+		CHECK_UNARY_FALSE(ctrl->has_focus());
+	}
+
+	SUBCASE("[SceneTree][Control] The parent node is hidden causing the focus to be released") {
+		Control *child_ctrl = memnew(Control);
+		ctrl->add_child(child_ctrl);
+
+		child_ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		child_ctrl->grab_focus();
+		CHECK_UNARY(child_ctrl->has_focus());
+
+		ctrl->hide();
+		CHECK_UNARY_FALSE(child_ctrl->has_focus());
+
+		ctrl->show();
+		CHECK_UNARY_FALSE(child_ctrl->has_focus());
+
+		memdelete(child_ctrl);
+	}
+
+	memdelete(ctrl);
+}
+
+TEST_CASE("[SceneTree][Control] Find next/prev valid focus") {
+	Control *ctrl = memnew(Control);
+	SceneTree::get_singleton()->get_root()->add_child(ctrl);
+
+	SUBCASE("[SceneTree][Control] In FOCUS_CLICK mode") {
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_CLICK);
+		ctrl->grab_focus();
+		REQUIRE_UNARY(ctrl->has_focus());
+
+		SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+			SEND_GUI_ACTION("ui_focus_next");
+			CHECK_UNARY(ctrl->has_focus());
+		}
+
+		SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+			SEND_GUI_ACTION("ui_focus_prev");
+			CHECK_UNARY(ctrl->has_focus());
+		}
+
+		SUBCASE("[SceneTree][Control] Has a sibling control but the parent node is not a control") {
+			Control *other_ctrl = memnew(Control);
+			SceneTree::get_singleton()->get_root()->add_child(other_ctrl);
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_ALL") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_ALL);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus next is hidden") {
+						other_ctrl->hide();
+						REQUIRE_UNARY_FALSE(other_ctrl->is_visible());
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus next is hidden") {
+						other_ctrl->hide();
+						REQUIRE_UNARY_FALSE(other_ctrl->is_visible());
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_CLICK") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_CLICK);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_CLICK);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_NONE") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_NONE);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+			}
+
+			memdelete(other_ctrl);
+		}
+	}
+
+	SUBCASE("[SceneTree][Control] In FOCUS_ALL mode") {
+		ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+		REQUIRE_EQ(ctrl->get_focus_mode(), Control::FocusMode::FOCUS_ALL);
+
+		ctrl->grab_focus();
+		REQUIRE_UNARY(ctrl->has_focus());
+
+		SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+			SEND_GUI_ACTION("ui_focus_next");
+			CHECK_UNARY(ctrl->has_focus());
+		}
+
+		SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+			SEND_GUI_ACTION("ui_focus_prev");
+			CHECK_UNARY(ctrl->has_focus());
+		}
+
+		SUBCASE("[SceneTree][Control] Has a sibling control but the parent node is not a control") {
+			Control *other_ctrl = memnew(Control);
+			SceneTree::get_singleton()->get_root()->add_child(other_ctrl);
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_ALL") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_ALL);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus next is hidden") {
+						other_ctrl->hide();
+						REQUIRE_UNARY_FALSE(other_ctrl->is_visible());
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus next is hidden") {
+						other_ctrl->hide();
+						REQUIRE_UNARY_FALSE(other_ctrl->is_visible());
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl->has_focus());
+							CHECK_UNARY_FALSE(other_ctrl->has_focus());
+						}
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_CLICK") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_CLICK);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_CLICK);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY_FALSE(ctrl->has_focus());
+						CHECK_UNARY(other_ctrl->has_focus());
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Has a sibling control with FOCUS_NONE") {
+				other_ctrl->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+				REQUIRE_EQ(other_ctrl->get_focus_mode(), Control::FocusMode::FOCUS_NONE);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl->has_focus());
+					CHECK_UNARY_FALSE(other_ctrl->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus next") {
+					ctrl->set_focus_next(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Manually specify focus prev") {
+					ctrl->set_focus_previous(ctrl->get_path_to(other_ctrl));
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+						CHECK_UNARY_FALSE(other_ctrl->has_focus());
+					}
+				}
+			}
+
+			memdelete(other_ctrl);
+		}
+
+		SUBCASE("[SceneTree][Control] Simple control tree") {
+			Control *ctrl_0 = memnew(Control);
+			Control *ctrl_1 = memnew(Control);
+			Node2D *node_2d_2 = memnew(Node2D);
+
+			ctrl->add_child(ctrl_0);
+			ctrl->add_child(ctrl_1);
+			ctrl->add_child(node_2d_2);
+
+			ctrl_0->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+			ctrl_1->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+			REQUIRE_EQ(ctrl_0->get_focus_mode(), Control::FocusMode::FOCUS_ALL);
+			REQUIRE_EQ(ctrl_1->get_focus_mode(), Control::FocusMode::FOCUS_ALL);
+
+			SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+				SEND_GUI_ACTION("ui_focus_next");
+				CHECK_UNARY(ctrl_0->has_focus());
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl_1->has_focus());
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl->has_focus());
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+				SEND_GUI_ACTION("ui_focus_prev");
+				CHECK_UNARY(ctrl_1->has_focus());
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl_0->has_focus());
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+					}
+				}
+			}
+
+			SUBCASE("[SceneTree][Control] Skip next hidden control") {
+				ctrl_0->hide();
+				REQUIRE_UNARY_FALSE(ctrl_0->is_visible());
+				SEND_GUI_ACTION("ui_focus_next");
+				CHECK_UNARY_FALSE(ctrl_0->has_focus());
+				CHECK_UNARY(ctrl_1->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip next control with FOCUS_NONE") {
+				ctrl_0->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+				REQUIRE_EQ(ctrl_0->get_focus_mode(), Control::FocusMode::FOCUS_NONE);
+				SEND_GUI_ACTION("ui_focus_next");
+				CHECK_UNARY_FALSE(ctrl_0->has_focus());
+				CHECK_UNARY(ctrl_1->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip next control with FOCUS_CLICK") {
+				ctrl_0->set_focus_mode(Control::FocusMode::FOCUS_CLICK);
+				REQUIRE_EQ(ctrl_0->get_focus_mode(), Control::FocusMode::FOCUS_CLICK);
+				SEND_GUI_ACTION("ui_focus_next");
+				CHECK_UNARY_FALSE(ctrl_0->has_focus());
+				CHECK_UNARY(ctrl_1->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip next top level control") {
+				ctrl_0->set_as_top_level(true);
+				REQUIRE_UNARY(ctrl_0->is_set_as_top_level());
+				SEND_GUI_ACTION("ui_focus_next");
+				CHECK_UNARY_FALSE(ctrl_0->has_focus());
+				CHECK_UNARY(ctrl_1->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip prev hidden control") {
+				ctrl_1->hide();
+				REQUIRE_UNARY_FALSE(ctrl_1->is_visible());
+				SEND_GUI_ACTION("ui_focus_prev");
+				CHECK_UNARY_FALSE(ctrl_1->has_focus());
+				CHECK_UNARY(ctrl_0->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip prev control with FOCUS_NONE") {
+				ctrl_1->set_focus_mode(Control::FocusMode::FOCUS_NONE);
+				REQUIRE_EQ(ctrl_1->get_focus_mode(), Control::FocusMode::FOCUS_NONE);
+				SEND_GUI_ACTION("ui_focus_prev");
+				CHECK_UNARY_FALSE(ctrl_1->has_focus());
+				CHECK_UNARY(ctrl_0->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip prev control with FOCUS_CLICK") {
+				ctrl_1->set_focus_mode(Control::FocusMode::FOCUS_CLICK);
+				REQUIRE_EQ(ctrl_1->get_focus_mode(), Control::FocusMode::FOCUS_CLICK);
+				SEND_GUI_ACTION("ui_focus_prev");
+				CHECK_UNARY_FALSE(ctrl_1->has_focus());
+				CHECK_UNARY(ctrl_0->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Skip prev top level control") {
+				ctrl_1->set_as_top_level(true);
+				REQUIRE_UNARY(ctrl_1->is_set_as_top_level());
+				SEND_GUI_ACTION("ui_focus_prev");
+				CHECK_UNARY_FALSE(ctrl_1->has_focus());
+				CHECK_UNARY(ctrl_0->has_focus());
+			}
+
+			SUBCASE("[SceneTree][Control] Add more node controls") {
+				Control *ctrl_0_0 = memnew(Control);
+				Control *ctrl_0_1 = memnew(Control);
+				Control *ctrl_0_2 = memnew(Control);
+				ctrl_0->add_child(ctrl_0_0);
+				ctrl_0->add_child(ctrl_0_1);
+				ctrl_0->add_child(ctrl_0_2);
+				ctrl_0_0->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_0_1->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_0_2->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+
+				Control *ctrl_1_0 = memnew(Control);
+				Control *ctrl_1_1 = memnew(Control);
+				Control *ctrl_1_2 = memnew(Control);
+				ctrl_1->add_child(ctrl_1_0);
+				ctrl_1->add_child(ctrl_1_1);
+				ctrl_1->add_child(ctrl_1_2);
+				ctrl_1_0->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_1_1->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_1_2->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+
+				Control *ctrl_2_0 = memnew(Control);
+				Control *ctrl_2_1 = memnew(Control);
+				Control *ctrl_2_2 = memnew(Control);
+				node_2d_2->add_child(ctrl_2_0);
+				node_2d_2->add_child(ctrl_2_1);
+				node_2d_2->add_child(ctrl_2_2);
+				ctrl_2_0->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_2_1->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+				ctrl_2_2->set_focus_mode(Control::FocusMode::FOCUS_ALL);
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+					SEND_GUI_ACTION("ui_focus_next");
+					CHECK_UNARY(ctrl_0->has_focus());
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl_0_0->has_focus());
+					}
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+						SEND_GUI_ACTION("ui_focus_prev");
+						CHECK_UNARY(ctrl->has_focus());
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+					SEND_GUI_ACTION("ui_focus_prev");
+					CHECK_UNARY(ctrl_1_2->has_focus());
+				}
+
+				SUBCASE("[SceneTree][Control] Exist top level tree") {
+					ctrl_0->set_as_top_level(true);
+					REQUIRE_UNARY(ctrl_0->is_set_as_top_level());
+
+					SUBCASE("[SceneTree][Control] Outside top level tree") {
+						ctrl->grab_focus();
+						REQUIRE_UNARY(ctrl->has_focus());
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl_1->has_focus());
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+								SEND_GUI_ACTION("ui_focus_prev");
+								CHECK_UNARY(ctrl->has_focus());
+							}
+						}
+					}
+
+					SUBCASE("[SceneTree][Control] Inside top level tree") {
+						ctrl_0->grab_focus();
+						REQUIRE_UNARY(ctrl_0->has_focus());
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl_0_0->has_focus());
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+								SEND_GUI_ACTION("ui_focus_prev");
+								CHECK_UNARY(ctrl_0->has_focus());
+							}
+						}
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl_0_2->has_focus());
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+								SEND_GUI_ACTION("ui_focus_next");
+								CHECK_UNARY(ctrl_0->has_focus());
+							}
+						}
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus next") {
+						ctrl->set_focus_next(ctrl->get_path_to(ctrl_2_1));
+						ctrl_2_1->set_focus_next(ctrl_2_1->get_path_to(ctrl_1_0));
+						ctrl_1_0->set_focus_next(ctrl_1_0->get_path_to(ctrl_0));
+						ctrl_0->set_focus_next(ctrl_0->get_path_to(ctrl));
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+							SEND_GUI_ACTION("ui_focus_next");
+							CHECK_UNARY(ctrl_2_1->has_focus());
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+								SEND_GUI_ACTION("ui_focus_next");
+								CHECK_UNARY(ctrl_1_0->has_focus());
+
+								SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+									SEND_GUI_ACTION("ui_focus_next");
+									CHECK_UNARY(ctrl_0->has_focus());
+
+									SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+										SEND_GUI_ACTION("ui_focus_next");
+										CHECK_UNARY(ctrl->has_focus());
+									}
+
+									SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+										SEND_GUI_ACTION("ui_focus_prev");
+										CHECK_UNARY(ctrl_0_2->has_focus());
+									}
+								}
+
+								SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+									SEND_GUI_ACTION("ui_focus_prev");
+									CHECK_UNARY(ctrl_1->has_focus());
+								}
+							}
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+								SEND_GUI_ACTION("ui_focus_prev");
+								CHECK_UNARY(ctrl_2_1->has_focus());
+							}
+						}
+
+						SUBCASE("[SceneTree][Control] The parent node is not visible") {
+							node_2d_2->hide();
+							REQUIRE_UNARY(ctrl_2_1->is_visible());
+							REQUIRE_UNARY_FALSE(ctrl_2_1->is_visible_in_tree());
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+								SEND_GUI_ACTION("ui_focus_next");
+								CHECK_UNARY_FALSE(ctrl->has_focus());
+								CHECK_UNARY_FALSE(ctrl_2_1->has_focus());
+								CHECK_UNARY_FALSE(ctrl_0->has_focus());
+								CHECK_UNARY(ctrl_1->has_focus());
+							}
+						}
+					}
+
+					SUBCASE("[SceneTree][Control] Manually specified focus prev") {
+						ctrl->set_focus_previous(ctrl->get_path_to(ctrl_0_2));
+						ctrl_0_2->set_focus_previous(ctrl_0_2->get_path_to(ctrl_1_1));
+						ctrl_1_1->set_focus_previous(ctrl_1_1->get_path_to(ctrl_2_0));
+						ctrl_2_0->set_focus_previous(ctrl_2_0->get_path_to(ctrl));
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl_0_2->has_focus());
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+								SEND_GUI_ACTION("ui_focus_prev");
+								CHECK_UNARY(ctrl_1_1->has_focus());
+
+								SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+									SEND_GUI_ACTION("ui_focus_prev");
+									CHECK_UNARY(ctrl_2_0->has_focus());
+
+									SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+										SEND_GUI_ACTION("ui_focus_prev");
+										CHECK_UNARY(ctrl->has_focus());
+									}
+
+									SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+										SEND_GUI_ACTION("ui_focus_next");
+										CHECK_UNARY(ctrl_2_0->has_focus());
+									}
+								}
+
+								SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+									SEND_GUI_ACTION("ui_focus_next");
+									CHECK_UNARY(ctrl_1_2->has_focus());
+								}
+							}
+
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+								SEND_GUI_ACTION("ui_focus_next");
+								CHECK_UNARY(ctrl_0->has_focus());
+							}
+						}
+
+						SUBCASE("[SceneTree][Control] The parent node is not visible") {
+							ctrl_0->hide();
+							REQUIRE_UNARY(ctrl_0_2->is_visible());
+							REQUIRE_UNARY_FALSE(ctrl_0_2->is_visible_in_tree());
+							SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+								SEND_GUI_ACTION("ui_focus_prev");
+								CHECK_UNARY_FALSE(ctrl->has_focus());
+								CHECK_UNARY_FALSE(ctrl_0_2->has_focus());
+								CHECK_UNARY(ctrl_1_2->has_focus());
+							}
+						}
+					}
+				}
+
+				SUBCASE("[SceneTree][Control] Exist hidden control tree") {
+					ctrl_0->hide();
+					REQUIRE_UNARY_FALSE(ctrl_0->is_visible());
+
+					SUBCASE("[SceneTree][Control] Simulate ui_focus_next action") {
+						SEND_GUI_ACTION("ui_focus_next");
+						CHECK_UNARY(ctrl_1->has_focus());
+
+						SUBCASE("[SceneTree][Control] Simulate ui_focus_prev action") {
+							SEND_GUI_ACTION("ui_focus_prev");
+							CHECK_UNARY(ctrl->has_focus());
+						}
+					}
+				}
+
+				memdelete(ctrl_2_2);
+				memdelete(ctrl_2_1);
+				memdelete(ctrl_2_0);
+				memdelete(ctrl_1_2);
+				memdelete(ctrl_1_1);
+				memdelete(ctrl_1_0);
+				memdelete(ctrl_0_2);
+				memdelete(ctrl_0_1);
+				memdelete(ctrl_0_0);
+			}
+
+			memdelete(node_2d_2);
+			memdelete(ctrl_1);
+			memdelete(ctrl_0);
+		}
+	}
+
 	memdelete(ctrl);
 }