diff options
Diffstat (limited to 'editor/plugins/node_3d_editor_plugin.cpp')
-rw-r--r-- | editor/plugins/node_3d_editor_plugin.cpp | 396 |
1 files changed, 250 insertions, 146 deletions
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index be14132185..69b66cd7b2 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -78,12 +78,14 @@ #include "editor/plugins/gizmos/voxel_gi_gizmo_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/scene_tree_dock.h" +#include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/decal.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/physics/collision_shape_3d.h" #include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/sprite_3d.h" #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" @@ -124,11 +126,11 @@ constexpr real_t MAX_FOV = 179; void ViewportNavigationControl::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - if (!is_connected("mouse_exited", callable_mp(this, &ViewportNavigationControl::_on_mouse_exited))) { - connect("mouse_exited", callable_mp(this, &ViewportNavigationControl::_on_mouse_exited)); + if (!is_connected(SceneStringName(mouse_exited), callable_mp(this, &ViewportNavigationControl::_on_mouse_exited))) { + connect(SceneStringName(mouse_exited), callable_mp(this, &ViewportNavigationControl::_on_mouse_exited)); } - if (!is_connected("mouse_entered", callable_mp(this, &ViewportNavigationControl::_on_mouse_entered))) { - connect("mouse_entered", callable_mp(this, &ViewportNavigationControl::_on_mouse_entered)); + if (!is_connected(SceneStringName(mouse_entered), callable_mp(this, &ViewportNavigationControl::_on_mouse_entered))) { + connect(SceneStringName(mouse_entered), callable_mp(this, &ViewportNavigationControl::_on_mouse_entered)); } } break; @@ -309,8 +311,8 @@ void ViewportRotationControl::_notification(int p_what) { axis_colors.push_back(get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor))); queue_redraw(); - if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) { - connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited)); + if (!is_connected(SceneStringName(mouse_exited), callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) { + connect(SceneStringName(mouse_exited), callable_mp(this, &ViewportRotationControl::_on_mouse_exited)); } } break; @@ -737,9 +739,21 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { return; } + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + // Prevent selection of nodes not owned by the edited scene. + while (node && node != edited_scene->get_parent()) { + Node *node_owner = node->get_owner(); + if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + break; + } + node = node->get_parent(); + selected = Object::cast_to<Node3D>(node); + } + if (!p_allow_locked) { // Replace the node by the group if grouped - while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { + while (node && node != edited_scene->get_parent()) { Node3D *selected_tmp = Object::cast_to<Node3D>(node); if (selected_tmp && node->has_meta("_edit_group_")) { selected = selected_tmp; @@ -764,7 +778,7 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { } if (editor_selection->get_selected_node_list().size() == 1) { - EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list()[0]); + EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list().front()->get()); } } } @@ -1042,25 +1056,34 @@ void Node3DEditorViewport::_select_region() { found_nodes.insert(sp); - Node *item = Object::cast_to<Node>(sp); - if (item != edited_scene) { - item = edited_scene->get_deepest_editable_node(item); + Node *node = Object::cast_to<Node>(sp); + if (node != edited_scene) { + node = edited_scene->get_deepest_editable_node(node); + } + + // Prevent selection of nodes not owned by the edited scene. + while (node && node != edited_scene->get_parent()) { + Node *node_owner = node->get_owner(); + if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + break; + } + node = node->get_parent(); } // Replace the node by the group if grouped - if (item->is_class("Node3D")) { - Node3D *sel = Object::cast_to<Node3D>(item); - while (item && item != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { - Node3D *selected_tmp = Object::cast_to<Node3D>(item); - if (selected_tmp && item->has_meta("_edit_group_")) { + if (node->is_class("Node3D")) { + Node3D *sel = Object::cast_to<Node3D>(node); + while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) { + Node3D *selected_tmp = Object::cast_to<Node3D>(node); + if (selected_tmp && node->has_meta("_edit_group_")) { sel = selected_tmp; } - item = item->get_parent(); + node = node->get_parent(); } - item = sel; + node = sel; } - if (_is_node_locked(item)) { + if (_is_node_locked(node)) { continue; } @@ -1072,7 +1095,7 @@ void Node3DEditorViewport::_select_region() { } if (seg->intersect_frustum(camera, frustum)) { - selected.push_back(item); + selected.push_back(node); } } } @@ -1084,7 +1107,7 @@ void Node3DEditorViewport::_select_region() { } if (editor_selection->get_selected_node_list().size() == 1) { - EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list()[0]); + EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list().front()->get()); } } @@ -1448,7 +1471,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const switch (p_mode) { case TRANSFORM_SCALE: { if (_edit.snap || spatial_editor->is_snap_enabled()) { - p_motion.snap(Vector3(p_extra, p_extra, p_extra)); + p_motion.snapf(p_extra); } Transform3D s; if (p_local) { @@ -1469,7 +1492,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const } case TRANSFORM_TRANSLATE: { if (_edit.snap || spatial_editor->is_snap_enabled()) { - p_motion.snap(Vector3(p_extra, p_extra, p_extra)); + p_motion.snapf(p_extra); } if (p_local) { @@ -1529,23 +1552,35 @@ bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) { } void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { - _find_items_at_pos(b->get_position(), selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); + Vector<_RayResult> potential_selection_results; + _find_items_at_pos(b->get_position(), potential_selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); - Node *scene = EditorNode::get_singleton()->get_edited_scene(); + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - for (int i = 0; i < selection_results.size(); i++) { - Node3D *item = selection_results[i].item; - if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) { - //invalid result - selection_results.remove_at(i); - i--; + // Filter to a list of nodes which include either the edited scene or nodes directly owned by the edited scene. + // If a node has an invalid owner, recursively check their parents until a valid node is found. + for (int i = 0; i < potential_selection_results.size(); i++) { + Node3D *node = potential_selection_results[i].item; + while (true) { + if (node == nullptr || node == edited_scene->get_parent()) { + break; + } else { + Node *node_owner = node->get_owner(); + if (node == edited_scene || node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { + if (selection_results.has(node)) { + selection_results.append(node); + } + break; + } + } + node = Object::cast_to<Node3D>(node->get_parent()); } } clicked_wants_append = b->is_shift_pressed(); if (selection_results.size() == 1) { - clicked = selection_results[0].item->get_instance_id(); + clicked = selection_results[0]->get_instance_id(); selection_results.clear(); if (clicked.is_valid()) { @@ -1556,7 +1591,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { StringName root_name = root_path.get_name(root_path.get_name_count() - 1); for (int i = 0; i < selection_results.size(); i++) { - Node3D *spat = selection_results[i].item; + Node3D *spat = selection_results[i]; Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node"); @@ -2593,8 +2628,8 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) { surface->queue_redraw(); } -Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { - Point2i relative; +Point2 Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { + Point2 relative; if (bool(EDITOR_GET("editors/3d/navigation/warped_mouse_panning"))) { relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect()); } else { @@ -2783,10 +2818,10 @@ void Node3DEditorViewport::_notification(int p_what) { if (cam != nullptr && cam != previewing) { //then switch the viewport's camera to the scene's viewport camera if (previewing != nullptr) { - previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->disconnect(SceneStringName(tree_exited), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); } previewing = cam; - previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->connect(SceneStringName(tree_exited), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera()); surface->queue_redraw(); } @@ -2899,10 +2934,8 @@ void Node3DEditorViewport::_notification(int p_what) { // FPS Counter. bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); - if (show_fps != fps_label->is_visible()) { - cpu_time_label->set_visible(show_fps); - gpu_time_label->set_visible(show_fps); - fps_label->set_visible(show_fps); + if (show_fps != frame_time_panel->is_visible()) { + frame_time_panel->set_visible(show_fps); RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps); for (int i = 0; i < FRAME_TIME_HISTORY; i++) { // Initialize to 120 FPS, so that the initial estimation until we get enough data is always reasonable. @@ -2991,12 +3024,12 @@ void Node3DEditorViewport::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw)); - surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput)); - surface->connect("mouse_entered", callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter)); - surface->connect("mouse_exited", callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit)); - surface->connect("focus_entered", callable_mp(this, &Node3DEditorViewport::_surface_focus_enter)); - surface->connect("focus_exited", callable_mp(this, &Node3DEditorViewport::_surface_focus_exit)); + surface->connect(SceneStringName(draw), callable_mp(this, &Node3DEditorViewport::_draw)); + surface->connect(SceneStringName(gui_input), callable_mp(this, &Node3DEditorViewport::_sinput)); + surface->connect(SceneStringName(mouse_entered), callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter)); + surface->connect(SceneStringName(mouse_exited), callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit)); + surface->connect(SceneStringName(focus_entered), callable_mp(this, &Node3DEditorViewport::_surface_focus_enter)); + surface->connect(SceneStringName(focus_exited), callable_mp(this, &Node3DEditorViewport::_surface_focus_exit)); _init_gizmo_instance(index); } break; @@ -3013,7 +3046,7 @@ void Node3DEditorViewport::_notification(int p_what) { view_menu->begin_bulk_theme_override(); view_menu->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - view_menu->add_theme_style_override("pressed", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + view_menu->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); view_menu->end_bulk_theme_override(); @@ -3021,7 +3054,7 @@ void Node3DEditorViewport::_notification(int p_what) { preview_camera->begin_bulk_theme_override(); preview_camera->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - preview_camera->add_theme_style_override("pressed", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + preview_camera->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); preview_camera->end_bulk_theme_override(); @@ -3031,9 +3064,15 @@ void Node3DEditorViewport::_notification(int p_what) { frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), EditorStringName(Editor))); info_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - cpu_time_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - gpu_time_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); - fps_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + + frame_time_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); + // Set a minimum width to prevent the width from changing all the time + // when numbers vary rapidly. This minimum width is set based on a + // GPU time of 999.99 ms in the current editor language. + const float min_width = get_theme_font(SNAME("main"), EditorStringName(EditorFonts))->get_string_size(vformat(TTR("GPU Time: %s ms"), 999.99)).x; + frame_time_panel->set_custom_minimum_size(Size2(min_width, 0) * EDSCALE); + frame_time_vbox->add_theme_constant_override("separation", Math::round(-1 * EDSCALE)); + cinema_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); locked_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles))); } break; @@ -3705,7 +3744,7 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { _update_navigation_controls_visibility(); if (!p_activate) { - previewing->disconnect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->disconnect(SceneStringName(tree_exiting), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); previewing = nullptr; RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore if (!preview) { @@ -3715,7 +3754,7 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { } else { previewing = preview; - previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->connect(SceneStringName(tree_exiting), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace surface->queue_redraw(); } @@ -3727,7 +3766,7 @@ void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) { if (!previewing_cinema) { if (previewing != nullptr) { - previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->disconnect(SceneStringName(tree_exited), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); } previewing = nullptr; @@ -3748,7 +3787,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) { return; } - clicked = selection_results_menu[p_result].item->get_instance_id(); + clicked = selection_results_menu[p_result]->get_instance_id(); if (clicked.is_valid()) { _select_clicked(spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); @@ -3972,7 +4011,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]); if (Object::cast_to<Camera3D>(pv)) { previewing = Object::cast_to<Camera3D>(pv); - previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing->connect(SceneStringName(tree_exiting), callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace surface->queue_redraw(); preview_camera->set_pressed(true); @@ -4192,27 +4231,37 @@ Node *Node3DEditorViewport::_sanitize_preview_node(Node *p_node) const { void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) const { bool add_preview = false; - for (int i = 0; i < files.size(); i++) { - Ref<Resource> res = ResourceLoader::load(files[i]); + for (const String &path : files) { + Ref<Resource> res = ResourceLoader::load(path); ERR_CONTINUE(res.is_null()); - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != nullptr || scene != nullptr) { - if (mesh != nullptr) { - MeshInstance3D *mesh_instance = memnew(MeshInstance3D); - mesh_instance->set_mesh(mesh); - preview_node->add_child(mesh_instance); - } else { - if (scene.is_valid()) { - Node *instance = scene->instantiate(); - if (instance) { - instance = _sanitize_preview_node(instance); - preview_node->add_child(instance); - } - } + + Ref<PackedScene> scene = res; + if (scene.is_valid()) { + Node *instance = scene->instantiate(); + if (instance) { + instance = _sanitize_preview_node(instance); + preview_node->add_child(instance); } add_preview = true; } + + Ref<Mesh> mesh = res; + if (mesh.is_valid()) { + MeshInstance3D *mesh_instance = memnew(MeshInstance3D); + mesh_instance->set_mesh(mesh); + preview_node->add_child(mesh_instance); + add_preview = true; + } + + Ref<AudioStream> audio = res; + if (audio.is_valid()) { + Sprite3D *sprite = memnew(Sprite3D); + sprite->set_texture(get_editor_theme_icon(SNAME("Gizmo3DSamplePlayer"))); + sprite->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED); + sprite->set_pixel_size(0.005); + preview_node->add_child(sprite); + add_preview = true; + } } if (add_preview) { EditorNode::get_singleton()->get_scene_root()->add_child(preview_node); @@ -4346,12 +4395,12 @@ bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_sc return false; } -bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { - Ref<Resource> res = ResourceLoader::load(path); +bool Node3DEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) { + Ref<Resource> res = ResourceLoader::load(p_path); ERR_FAIL_COND_V(res.is_null(), false); - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); + Ref<PackedScene> scene = res; + Ref<Mesh> mesh = res; Node *instantiated_scene = nullptr; @@ -4361,8 +4410,10 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po mesh_instance->set_mesh(mesh); // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. - String name = path.get_file().get_basename(); - mesh_instance->set_name(Node::adjust_name_casing(name)); + const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename()); + if (!node_name.is_empty()) { + mesh_instance->set_name(node_name); + } instantiated_scene = mesh_instance; } else { @@ -4386,25 +4437,25 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po } if (scene != nullptr) { - instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); + instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_path)); } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->add_do_method(parent, "add_child", instantiated_scene, true); + undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true); undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); undo_redo->add_do_reference(instantiated_scene); - undo_redo->add_undo_method(parent, "remove_child", instantiated_scene); + undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene); undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene); - String new_name = parent->validate_child_name(instantiated_scene); + String new_name = p_parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); - undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_path, new_name); + undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name)); Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene); if (node3d) { Transform3D parent_tf; - Node3D *parent_node3d = Object::cast_to<Node3D>(parent); + Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent); if (parent_node3d) { parent_tf = parent_node3d->get_global_gizmo_transform(); } @@ -4419,6 +4470,46 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po return true; } +bool Node3DEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) { + Ref<AudioStream> audio = ResourceLoader::load(p_path); + ERR_FAIL_COND_V(audio.is_null(), false); + + AudioStreamPlayer3D *audio_player = memnew(AudioStreamPlayer3D); + audio_player->set_stream(audio); + + // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. + const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename()); + if (!node_name.is_empty()) { + audio_player->set_name(node_name); + } + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->add_do_method(p_parent, "add_child", audio_player, true); + undo_redo->add_do_method(audio_player, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + undo_redo->add_do_reference(audio_player); + undo_redo->add_undo_method(p_parent, "remove_child", audio_player); + undo_redo->add_do_method(editor_selection, "add_node", audio_player); + + const String new_name = p_parent->validate_child_name(audio_player); + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), audio_player->get_class(), new_name); + undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name)); + + Transform3D parent_tf; + Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent); + if (parent_node3d) { + parent_tf = parent_node3d->get_global_gizmo_transform(); + } + + Transform3D new_tf = audio_player->get_transform(); + new_tf.origin = parent_tf.affine_inverse().xform(preview_node_pos + audio_player->get_position()); + new_tf.basis = parent_tf.affine_inverse().basis * new_tf.basis; + + undo_redo->add_do_method(audio_player, "set_transform", new_tf); + + return true; +} + void Node3DEditorViewport::_perform_drop_data() { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); if (spatial_editor->get_preview_material_target().is_valid()) { @@ -4453,11 +4544,18 @@ void Node3DEditorViewport::_perform_drop_data() { if (res.is_null()) { continue; } - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != nullptr || scene != nullptr) { - bool success = _create_instance(target_node, path, drop_pos); - if (!success) { + + Ref<PackedScene> scene = res; + Ref<Mesh> mesh = res; + if (mesh.is_valid() || scene.is_valid()) { + if (!_create_instance(target_node, path, drop_pos)) { + error_files.push_back(path.get_file()); + } + } + + Ref<AudioStream> audio = res; + if (audio.is_valid()) { + if (!_create_audio_node(target_node, path, drop_pos)) { error_files.push_back(path.get_file()); } } @@ -4488,12 +4586,14 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant bool is_other_valid = false; // Check if at least one of the dragged files is a mesh, material, texture or scene. for (int i = 0; i < files.size(); i++) { - bool is_scene = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "PackedScene"); - bool is_mesh = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Mesh"); - bool is_material = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Material"); - bool is_texture = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Texture"); - - if (is_mesh || is_scene || is_material || is_texture) { + const String &res_type = ResourceLoader::get_resource_type(files[i]); + bool is_scene = ClassDB::is_parent_class(res_type, "PackedScene"); + bool is_mesh = ClassDB::is_parent_class(res_type, "Mesh"); + bool is_material = ClassDB::is_parent_class(res_type, "Material"); + bool is_texture = ClassDB::is_parent_class(res_type, "Texture"); + bool is_audio = ClassDB::is_parent_class(res_type, "AudioStream"); + + if (is_mesh || is_scene || is_material || is_texture || is_audio) { Ref<Resource> res = ResourceLoader::load(files[i]); if (res.is_null()) { continue; @@ -4502,6 +4602,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant Ref<Mesh> mesh = res; Ref<Material> mat = res; Ref<Texture2D> tex = res; + Ref<AudioStream> audio = res; if (scn.is_valid()) { Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instantiated_scene) { @@ -4537,6 +4638,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant spatial_editor->set_preview_material(new_mat); is_other_valid = true; continue; + } else if (!is_other_valid && audio.is_valid()) { + is_other_valid = true; } else { continue; } @@ -4592,12 +4695,13 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list(); Node *root_node = EditorNode::get_singleton()->get_edited_scene(); if (selected_nodes.size() > 0) { - Node *selected_node = selected_nodes[0]; - target_node = selected_node; + Node *selected_node = selected_nodes.front()->get(); if (is_alt) { target_node = root_node; - } else if (is_shift && selected_node != root_node) { - target_node = selected_node->get_parent(); + } else if (is_shift) { + target_node = selected_node; + } else { // Default behavior. + target_node = (selected_node != root_node) ? selected_node->get_parent() : root_node; } } else { if (root_node) { @@ -4786,7 +4890,7 @@ void Node3DEditorViewport::update_transform(bool p_shift) { snap = spatial_editor->get_scale_snap() / 100; } Vector3 motion_snapped = motion; - motion_snapped.snap(Vector3(snap, snap, snap)); + motion_snapped.snapf(snap); // This might not be necessary anymore after issue #288 is solved (in 4.0?). // TRANSLATORS: Refers to changing the scale of a node in the 3D editor. set_message(TTR("Scaling:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " + @@ -4858,7 +4962,7 @@ void Node3DEditorViewport::update_transform(bool p_shift) { snap = spatial_editor->get_translate_snap(); } Vector3 motion_snapped = motion; - motion_snapped.snap(Vector3(snap, snap, snap)); + motion_snapped.snapf(snap); // TRANSLATORS: Refers to changing the position of a node in the 3D editor. set_message(TTR("Translating:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " + String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); @@ -5312,10 +5416,6 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p top_right_vbox = memnew(VBoxContainer); top_right_vbox->set_anchors_and_offsets_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 10.0 * EDSCALE); top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN); - // Make sure frame time labels don't touch the viewport's edge. - top_right_vbox->set_custom_minimum_size(Size2(100, 0) * EDSCALE); - // Prevent visible spacing between frame time labels. - top_right_vbox->add_theme_constant_override("separation", 0); const int navigation_control_size = 150; @@ -5347,18 +5447,22 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p rotation_control->set_viewport(this); top_right_vbox->add_child(rotation_control); + frame_time_panel = memnew(PanelContainer); + top_right_vbox->add_child(frame_time_panel); + frame_time_panel->hide(); + + frame_time_vbox = memnew(VBoxContainer); + frame_time_panel->add_child(frame_time_vbox); + // Individual Labels are used to allow coloring each label with its own color. cpu_time_label = memnew(Label); - top_right_vbox->add_child(cpu_time_label); - cpu_time_label->hide(); + frame_time_vbox->add_child(cpu_time_label); gpu_time_label = memnew(Label); - top_right_vbox->add_child(gpu_time_label); - gpu_time_label->hide(); + frame_time_vbox->add_child(gpu_time_label); fps_label = memnew(Label); - top_right_vbox->add_child(fps_label); - fps_label->hide(); + frame_time_vbox->add_child(fps_label); surface->add_child(top_right_vbox); @@ -6069,9 +6173,9 @@ void Node3DEditor::set_state(const Dictionary &p_state) { continue; } int state = EditorNode3DGizmoPlugin::VISIBLE; - for (int i = 0; i < keys.size(); i++) { - if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(keys[i])) { - state = gizmos_status[keys[i]]; + for (const Variant &key : keys) { + if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(key)) { + state = gizmos_status[key]; break; } } @@ -7817,7 +7921,7 @@ void Node3DEditor::add_control_to_menu_panel(Control *p_control) { context_toolbar_hbox->add_child(p_control); context_toolbar_separators[p_control] = sep; - p_control->connect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar)); + p_control->connect(SceneStringName(visibility_changed), callable_mp(this, &Node3DEditor::_update_context_toolbar)); _update_context_toolbar(); } @@ -7826,7 +7930,7 @@ void Node3DEditor::remove_control_from_menu_panel(Control *p_control) { ERR_FAIL_NULL(p_control); ERR_FAIL_COND(p_control->get_parent() != context_toolbar_hbox); - p_control->disconnect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar)); + p_control->disconnect(SceneStringName(visibility_changed), callable_mp(this, &Node3DEditor::_update_context_toolbar)); VSeparator *sep = context_toolbar_separators[p_control]; context_toolbar_hbox->remove_child(sep); @@ -8360,7 +8464,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_SELECT]->set_theme_type_variation("FlatButton"); tool_button[TOOL_MODE_SELECT]->set_pressed(true); - tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT)); + tool_button[TOOL_MODE_SELECT]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT)); tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q)); tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this); tool_button[TOOL_MODE_SELECT]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); @@ -8371,7 +8475,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true); tool_button[TOOL_MODE_MOVE]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_MOVE)); + tool_button[TOOL_MODE_MOVE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_MOVE)); tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), Key::W)); tool_button[TOOL_MODE_MOVE]->set_shortcut_context(this); tool_button[TOOL_MODE_MOVE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); @@ -8380,7 +8484,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_MODE_ROTATE]); tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true); tool_button[TOOL_MODE_ROTATE]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_ROTATE)); + tool_button[TOOL_MODE_ROTATE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_ROTATE)); tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), Key::E)); tool_button[TOOL_MODE_ROTATE]->set_shortcut_context(this); tool_button[TOOL_MODE_ROTATE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); @@ -8389,7 +8493,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_MODE_SCALE]); tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true); tool_button[TOOL_MODE_SCALE]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_SCALE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SCALE)); + tool_button[TOOL_MODE_SCALE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SCALE)); tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), Key::R)); tool_button[TOOL_MODE_SCALE]->set_shortcut_context(this); tool_button[TOOL_MODE_SCALE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); @@ -8400,40 +8504,40 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_MODE_LIST_SELECT]); tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_LIST_SELECT]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT)); + tool_button[TOOL_MODE_LIST_SELECT]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT)); tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked.")); tool_button[TOOL_LOCK_SELECTED] = memnew(Button); main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]); tool_button[TOOL_LOCK_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED)); + tool_button[TOOL_LOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED)); tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(TTR("Lock selected node, preventing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L)); + tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/lock_selected_nodes")); tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button); main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]); tool_button[TOOL_UNLOCK_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED)); + tool_button[TOOL_UNLOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED)); tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L)); + tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/unlock_selected_nodes")); tool_button[TOOL_GROUP_SELECTED] = memnew(Button); main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]); tool_button[TOOL_GROUP_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); + tool_button[TOOL_GROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Groups the selected node with its children. This selects the parent when any child node is clicked in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G)); + tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/group_selected_nodes")); tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button); main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]); tool_button[TOOL_UNGROUP_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); + tool_button[TOOL_UNGROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G)); + tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes")); main_menu_hbox->add_child(memnew(VSeparator)); @@ -8468,7 +8572,7 @@ Node3DEditor::Node3DEditor() { sun_button->set_tooltip_text(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled.")); sun_button->set_toggle_mode(true); sun_button->set_theme_type_variation("FlatButton"); - sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); + sun_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); // Preview is enabled by default - ensure this applies on editor startup when there is no state yet. sun_button->set_pressed(true); @@ -8478,7 +8582,7 @@ Node3DEditor::Node3DEditor() { environ_button->set_tooltip_text(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled.")); environ_button->set_toggle_mode(true); environ_button->set_theme_type_variation("FlatButton"); - environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); + environ_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); // Preview is enabled by default - ensure this applies on editor startup when there is no state yet. environ_button->set_pressed(true); @@ -8487,7 +8591,7 @@ Node3DEditor::Node3DEditor() { sun_environ_settings = memnew(Button); sun_environ_settings->set_tooltip_text(TTR("Edit Sun and Environment settings.")); sun_environ_settings->set_theme_type_variation("FlatButton"); - sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed)); + sun_environ_settings->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed)); main_menu_hbox->add_child(sun_environ_settings); @@ -8616,7 +8720,7 @@ Node3DEditor::Node3DEditor() { snap_dialog->set_title(TTR("Snap Settings")); add_child(snap_dialog); snap_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_snap_changed)); - snap_dialog->get_cancel_button()->connect("pressed", callable_mp(this, &Node3DEditor::_snap_update)); + snap_dialog->get_cancel_button()->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_snap_update)); VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer); snap_dialog->add_child(snap_dialog_vbc); @@ -8737,7 +8841,7 @@ Node3DEditor::Node3DEditor() { selected = nullptr; set_process_shortcut_input(true); - add_to_group("_spatial_editor_group"); + add_to_group(SceneStringName(_spatial_editor_group)); EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,160,1")); @@ -8774,8 +8878,8 @@ Node3DEditor::Node3DEditor() { sun_direction->set_custom_minimum_size(Size2(128, 128) * EDSCALE); sun_direction_center->add_child(sun_direction); sun_vb->add_margin_child(TTR("Sun Direction"), sun_direction_center); - sun_direction->connect("gui_input", callable_mp(this, &Node3DEditor::_sun_direction_input)); - sun_direction->connect("draw", callable_mp(this, &Node3DEditor::_sun_direction_draw)); + sun_direction->connect(SceneStringName(gui_input), callable_mp(this, &Node3DEditor::_sun_direction_input)); + sun_direction->connect(SceneStringName(draw), callable_mp(this, &Node3DEditor::_sun_direction_draw)); sun_direction->set_default_cursor_shape(CURSOR_MOVE); sun_direction_shader.instantiate(); @@ -8852,7 +8956,7 @@ void fragment() { sun_add_to_scene = memnew(Button); sun_add_to_scene->set_text(TTR("Add Sun to Scene")); sun_add_to_scene->set_tooltip_text(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene.")); - sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene).bind(false)); + sun_add_to_scene->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_add_sun_to_scene).bind(false)); sun_vb->add_spacer(); sun_vb->add_child(sun_add_to_scene); @@ -8901,29 +9005,29 @@ void fragment() { environ_ao_button = memnew(Button); environ_ao_button->set_text(TTR("AO")); environ_ao_button->set_toggle_mode(true); - environ_ao_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); + environ_ao_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); fx_vb->add_child(environ_ao_button); environ_glow_button = memnew(Button); environ_glow_button->set_text(TTR("Glow")); environ_glow_button->set_toggle_mode(true); - environ_glow_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); + environ_glow_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); fx_vb->add_child(environ_glow_button); environ_tonemap_button = memnew(Button); environ_tonemap_button->set_text(TTR("Tonemap")); environ_tonemap_button->set_toggle_mode(true); - environ_tonemap_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); + environ_tonemap_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); fx_vb->add_child(environ_tonemap_button); environ_gi_button = memnew(Button); environ_gi_button->set_text(TTR("GI")); environ_gi_button->set_toggle_mode(true); - environ_gi_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); + environ_gi_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED); fx_vb->add_child(environ_gi_button); environ_vb->add_margin_child(TTR("Post Process"), fx_vb); environ_add_to_scene = memnew(Button); environ_add_to_scene->set_text(TTR("Add Environment to Scene")); environ_add_to_scene->set_tooltip_text(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene.")); - environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene).bind(false)); + environ_add_to_scene->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_add_environment_to_scene).bind(false)); environ_vb->add_spacer(); environ_vb->add_child(environ_add_to_scene); @@ -8997,7 +9101,7 @@ void Node3DEditorPlugin::set_state(const Dictionary &p_state) { Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const { if (is_snap_enabled()) { real_t snap = get_translate_snap(); - p_target.snap(Vector3(snap, snap, snap)); + p_target.snapf(snap); } return p_target; } |