| 1745 | } |
| 1746 | |
| 1747 | void Node::remove_child(Node *p_child) { |
| 1748 | ERR_FAIL_COND_MSG(data.tree && !Thread::is_main_thread(), "Removing children from a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"remove_child\",node)."); |
| 1749 | ERR_FAIL_NULL(p_child); |
| 1750 | ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead."); |
| 1751 | ERR_FAIL_COND(p_child->data.parent != this); |
| 1752 | |
| 1753 | /** |
| 1754 | * Do not change the data.internal_children*cache counters here. |
| 1755 | * Because if nodes are re-added, the indices can remain |
| 1756 | * greater-than-everything indices and children added remain |
| 1757 | * properly ordered. |
| 1758 | * |
| 1759 | * All children indices and counters will be updated next time the |
| 1760 | * cache is re-generated. |
| 1761 | */ |
| 1762 | |
| 1763 | data.blocked++; |
| 1764 | p_child->_set_tree(nullptr); |
| 1765 | |
| 1766 | remove_child_notify(p_child); |
| 1767 | p_child->notification(NOTIFICATION_UNPARENTED); |
| 1768 | |
| 1769 | data.blocked--; |
| 1770 | |
| 1771 | data.children_cache_dirty = true; |
| 1772 | bool success = data.children.erase(p_child->data.name); |
| 1773 | ERR_FAIL_COND_MSG(!success, "Children name does not match parent name in hashtable, this is a bug."); |
| 1774 | |
| 1775 | p_child->data.parent = nullptr; |
| 1776 | p_child->data.index = -1; |
| 1777 | |
| 1778 | notification(NOTIFICATION_CHILD_ORDER_CHANGED); |
| 1779 | emit_signal(SNAME("child_order_changed")); |
| 1780 | |
| 1781 | if (data.tree) { |
| 1782 | p_child->_propagate_after_exit_tree(); |
| 1783 | } |
| 1784 | } |
| 1785 | |
| 1786 | void Node::_update_children_cache_impl() const { |
| 1787 | // Assign children |
no test coverage detected