diff options
Diffstat (limited to 'scene/main')
-rw-r--r-- | scene/main/canvas_item.cpp | 18 | ||||
-rw-r--r-- | scene/main/node.cpp | 107 | ||||
-rw-r--r-- | scene/main/resource_preloader.cpp | 5 | ||||
-rw-r--r-- | scene/main/scene_tree.cpp | 19 | ||||
-rw-r--r-- | scene/main/scene_tree.h | 1 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 37 | ||||
-rw-r--r-- | scene/main/viewport.h | 2 | ||||
-rw-r--r-- | scene/main/window.cpp | 32 |
8 files changed, 159 insertions, 62 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index d2735b968b..4ee81e5cb0 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -891,18 +891,22 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { * notification anyway). */ - if (p_node->block_transform_notify || p_node->_is_global_invalid()) { + if (/*p_node->xform_change.in_list() &&*/ p_node->_is_global_invalid()) { return; //nothing to do } p_node->_set_global_invalid(true); - if (p_node->notify_transform && !p_node->xform_change.in_list() && p_node->is_inside_tree()) { - if (is_accessible_from_caller_thread()) { - get_tree()->xform_change_list.add(&p_node->xform_change); - } else { - // Should be rare, but still needs to be handled. - MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred)); + if (p_node->notify_transform && !p_node->xform_change.in_list()) { + if (!p_node->block_transform_notify) { + if (p_node->is_inside_tree()) { + if (is_accessible_from_caller_thread()) { + get_tree()->xform_change_list.add(&p_node->xform_change); + } else { + // Should be rare, but still needs to be handled. + MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred)); + } + } } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e730f47607..820cb7571f 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -202,6 +202,11 @@ void Node::_notification(int p_notification) { _clean_up_owner(); } + while (!data.owned.is_empty()) { + Node *n = data.owned.back()->get(); + n->_clean_up_owner(); // This will change data.owned. So it's impossible to loop over the list in the usual manner. + } + if (data.parent) { data.parent->remove_child(this); } @@ -1415,6 +1420,14 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead."); _validate_child_name(p_child, p_force_readable_name); + +#ifdef DEBUG_ENABLED + if (p_child->data.owner && !p_child->data.owner->is_ancestor_of(p_child)) { + // Owner of p_child should be ancestor of p_child. + WARN_PRINT(vformat("Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand.", p_child->get_name(), get_name(), p_child->data.owner->get_name())); + } +#endif // DEBUG_ENABLED + _add_child_nocheck(p_child, p_child->data.name, p_internal); } @@ -2515,44 +2528,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } - for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { - Node *current_node = node->get_node(get_path_to(N->get())); - ERR_CONTINUE(!current_node); - - if (p_flags & DUPLICATE_SCRIPTS) { - bool is_valid = false; - Variant scr = N->get()->get(script_property_name, &is_valid); - if (is_valid) { - current_node->set(script_property_name, scr); - } - } - - List<PropertyInfo> plist; - N->get()->get_property_list(&plist); - - for (const PropertyInfo &E : plist) { - if (!(E.usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - String name = E.name; - if (name == script_property_name) { - continue; - } - - Variant value = N->get()->get(name).duplicate(true); - - if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { - Resource *res = Object::cast_to<Resource>(value); - if (res) { // Duplicate only if it's a resource - current_node->set(name, res->duplicate()); - } - - } else { - current_node->set(name, value); - } - } - } - if (get_name() != String()) { node->set_name(get_name()); } @@ -2618,6 +2593,62 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } + for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { + Node *current_node = node->get_node(get_path_to(N->get())); + ERR_CONTINUE(!current_node); + + if (p_flags & DUPLICATE_SCRIPTS) { + bool is_valid = false; + Variant scr = N->get()->get(script_property_name, &is_valid); + if (is_valid) { + current_node->set(script_property_name, scr); + } + } + + List<PropertyInfo> plist; + N->get()->get_property_list(&plist); + + for (const PropertyInfo &E : plist) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + String name = E.name; + if (name == script_property_name) { + continue; + } + + Variant value = N->get()->get(name).duplicate(true); + + if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { + Resource *res = Object::cast_to<Resource>(value); + if (res) { // Duplicate only if it's a resource + current_node->set(name, res->duplicate()); + } + + } else { + // If property points to a node which is owned by a node we are duplicating, update its path. + if (value.get_type() == Variant::OBJECT) { + Node *property_node = Object::cast_to<Node>(value); + if (property_node && is_ancestor_of(property_node)) { + value = current_node->get_node_or_null(get_path_to(property_node)); + } + } else if (value.get_type() == Variant::ARRAY) { + Array arr = value; + if (arr.get_typed_builtin() == Variant::OBJECT) { + for (int i = 0; i < arr.size(); i++) { + Node *property_node = Object::cast_to<Node>(arr[i]); + if (property_node && is_ancestor_of(property_node)) { + arr[i] = current_node->get_node_or_null(get_path_to(property_node)); + } + } + value = arr; + } + } + current_node->set(name, value); + } + } + } + return node; } diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index de42b63548..fe0e82370a 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -40,12 +40,11 @@ void ResourcePreloader::_set_resources(const Array &p_data) { ERR_FAIL_COND(names.size() != resdata.size()); for (int i = 0; i < resdata.size(); i++) { - String name = names[i]; Ref<Resource> resource = resdata[i]; ERR_CONTINUE(!resource.is_valid()); - resources[name] = resource; + resources[names[i]] = resource; - //add_resource(name,resource); + //add_resource(names[i],resource); } } diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index d3347bc304..4417007b9d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -515,6 +515,10 @@ bool SceneTree::process(double p_time) { _flush_delete_queue(); + if (unlikely(pending_new_scene)) { + _flush_scene_change(); + } + process_timers(p_time, false); //go through timers process_tweens(p_time, false); @@ -550,10 +554,6 @@ bool SceneTree::process(double p_time) { #endif // _3D_DISABLED #endif // TOOLS_ENABLED - if (unlikely(pending_new_scene)) { - _flush_scene_change(); - } - return _quit; } @@ -1302,6 +1302,16 @@ bool SceneTree::has_group(const StringName &p_identifier) const { return group_map.has(p_identifier); } +int SceneTree::get_node_count_in_group(const StringName &p_group) const { + _THREAD_SAFE_METHOD_ + HashMap<StringName, Group>::ConstIterator E = group_map.find(p_group); + if (!E) { + return 0; + } + + return E->value.nodes.size(); +} + Node *SceneTree::get_first_node_in_group(const StringName &p_group) { _THREAD_SAFE_METHOD_ HashMap<StringName, Group>::Iterator E = group_map.find(p_group); @@ -1617,6 +1627,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group); ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group); + ClassDB::bind_method(D_METHOD("get_node_count_in_group", "group"), &SceneTree::get_node_count_in_group); ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene); ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index e1597d3890..618ac275ff 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -385,6 +385,7 @@ public: void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list); Node *get_first_node_in_group(const StringName &p_group); bool has_group(const StringName &p_identifier) const; + int get_node_count_in_group(const StringName &p_group) const; //void change_scene(const String& p_path); //Node *get_loaded_scene(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 43bdb1395b..89ec5636ab 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2451,6 +2451,14 @@ void Viewport::_gui_update_mouse_over() { return; } + if (gui.sending_mouse_enter_exit_notifications) { + // If notifications are already being sent, delay call to next frame. + if (get_tree() && !get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over))) { + get_tree()->connect(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over), CONNECT_ONE_SHOT); + } + return; + } + // Rebuild the mouse over hierarchy. LocalVector<Control *> new_mouse_over_hierarchy; LocalVector<Control *> needs_enter; @@ -2507,6 +2515,8 @@ void Viewport::_gui_update_mouse_over() { return; } + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Exit Self notification. if (gui.mouse_over && !needs_exit.is_empty() && needs_exit[0] == (int)gui.mouse_over_hierarchy.size() - 1) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); @@ -2528,6 +2538,8 @@ void Viewport::_gui_update_mouse_over() { for (int i = needs_enter.size() - 1; i >= 0; i--) { needs_enter[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } + + gui.sending_mouse_enter_exit_notifications = false; } Window *Viewport::get_base_window() const { @@ -3200,14 +3212,20 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { gui.mouse_over = over; gui.mouse_over_hierarchy.reserve(gui.mouse_over_hierarchy.size() + over_ancestors.size()); + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Enter notifications to parents first. for (int i = over_ancestors.size() - 1; i >= 0; i--) { - over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); gui.mouse_over_hierarchy.push_back(over_ancestors[i]); + over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } // Send Mouse Enter Self notification. - gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); + if (gui.mouse_over) { + gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); + } + + gui.sending_mouse_enter_exit_notifications = false; notify_embedded_viewports = true; } @@ -3250,6 +3268,12 @@ void Viewport::_mouse_leave_viewport() { } void Viewport::_drop_mouse_over(Control *p_until_control) { + if (gui.sending_mouse_enter_exit_notifications) { + // If notifications are already being sent, defer call. + callable_mp(this, &Viewport::_drop_mouse_over).call_deferred(p_until_control); + return; + } + _gui_cancel_tooltip(); SubViewportContainer *c = Object::cast_to<SubViewportContainer>(gui.mouse_over); if (c) { @@ -3261,6 +3285,8 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { v->_mouse_leave_viewport(); } } + + gui.sending_mouse_enter_exit_notifications = true; if (gui.mouse_over && gui.mouse_over->is_inside_tree()) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); } @@ -3274,6 +3300,7 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { } } gui.mouse_over_hierarchy.resize(notification_until); + gui.sending_mouse_enter_exit_notifications = false; } void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) { @@ -3491,6 +3518,11 @@ Control *Viewport::gui_get_focus_owner() const { return gui.key_focus; } +Control *Viewport::gui_get_hovered_control() const { + ERR_READ_THREAD_GUARD_V(nullptr); + return gui.mouse_over; +} + void Viewport::set_msaa_2d(MSAA p_msaa) { ERR_MAIN_THREAD_GUARD; ERR_FAIL_INDEX(p_msaa, MSAA_MAX); @@ -4530,6 +4562,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("gui_release_focus"), &Viewport::gui_release_focus); ClassDB::bind_method(D_METHOD("gui_get_focus_owner"), &Viewport::gui_get_focus_owner); + ClassDB::bind_method(D_METHOD("gui_get_hovered_control"), &Viewport::gui_get_hovered_control); ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 82a9bfc438..43a89c8a0b 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -362,6 +362,7 @@ private: Control *key_focus = nullptr; Control *mouse_over = nullptr; LocalVector<Control *> mouse_over_hierarchy; + bool sending_mouse_enter_exit_notifications = false; Window *subwindow_over = nullptr; // mouse_over and subwindow_over are mutually exclusive. At all times at least one of them is nullptr. Window *windowmanager_window_over = nullptr; // Only used in root Viewport. Control *drag_mouse_over = nullptr; @@ -609,6 +610,7 @@ public: void gui_release_focus(); Control *gui_get_focus_owner() const; + Control *gui_get_hovered_control() const; PackedStringArray get_configuration_warnings() const override; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 0d554de6f4..98b207bd3c 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -284,7 +284,13 @@ void Window::set_title(const String &p_title) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_title(tr_title, window_id); - _update_window_size(); + if (keep_title_visible) { + Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id); + Size2i size_limit = get_clamped_minimum_size(); + if (title_size.x > size_limit.x || title_size.y > size_limit.y) { + _update_window_size(); + } + } } } @@ -681,6 +687,9 @@ void Window::_propagate_window_notification(Node *p_node, int p_notification) { void Window::_event_callback(DisplayServer::WindowEvent p_event) { switch (p_event) { case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { + if (!is_inside_tree()) { + return; + } Window *root = get_tree()->get_root(); if (root->gui.windowmanager_window_over) { #ifdef DEV_ENABLED @@ -696,6 +705,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { } } break; case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { + if (!is_inside_tree()) { + return; + } Window *root = get_tree()->get_root(); if (!root->gui.windowmanager_window_over) { #ifdef DEV_ENABLED @@ -955,6 +967,10 @@ Size2i Window::_clamp_window_size(const Size2i &p_size) { void Window::_update_window_size() { Size2i size_limit = get_clamped_minimum_size(); + if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID && keep_title_visible) { + Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id); + size_limit = size_limit.max(title_size); + } size = size.max(size_limit); @@ -986,12 +1002,6 @@ void Window::_update_window_size() { } DisplayServer::get_singleton()->window_set_max_size(max_size_used, window_id); - - if (keep_title_visible) { - Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id); - size_limit = size_limit.max(title_size); - } - DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id); DisplayServer::get_singleton()->window_set_size(size, window_id); } @@ -1291,7 +1301,13 @@ void Window::_notification(int p_what) { if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { DisplayServer::get_singleton()->window_set_title(tr_title, window_id); - _update_window_size(); + if (keep_title_visible) { + Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id); + Size2i size_limit = get_clamped_minimum_size(); + if (title_size.x > size_limit.x || title_size.y > size_limit.y) { + _update_window_size(); + } + } } } break; |