2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* scene_tree_dock.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "scene_tree_dock.h"
2017-01-16 08:04:19 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2015-11-27 21:42:48 +01:00
# include "core/io/resource_saver.h"
2022-11-14 13:18:28 +01:00
# include "core/object/class_db.h"
2017-08-26 17:46:49 +02:00
# include "core/os/keyboard.h"
2020-02-07 02:52:05 +01:00
# include "editor/debugger/editor_debugger_node.h"
2019-12-24 08:17:23 +01:00
# include "editor/editor_feature_profile.h"
2017-08-26 17:46:49 +02:00
# include "editor/editor_node.h"
2022-07-29 02:36:26 +02:00
# include "editor/editor_paths.h"
2022-11-19 12:45:49 +01:00
# include "editor/editor_quick_open.h"
2017-08-26 17:46:49 +02:00
# include "editor/editor_settings.h"
2023-08-13 02:33:39 +02:00
# include "editor/editor_string_names.h"
2022-08-29 12:10:32 +02:00
# include "editor/editor_undo_redo_manager.h"
2023-11-14 12:55:36 +01:00
# include "editor/filesystem_dock.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2022-11-19 12:45:49 +01:00
# include "editor/inspector_dock.h"
2017-08-26 17:46:49 +02:00
# include "editor/multi_node_edit.h"
2022-05-12 17:36:37 +02:00
# include "editor/node_dock.h"
2017-03-05 14:21:25 +01:00
# include "editor/plugins/animation_player_editor_plugin.h"
# include "editor/plugins/canvas_item_editor_plugin.h"
2024-07-21 10:43:53 +02:00
# include "editor/plugins/editor_context_menu_plugin.h"
2020-03-27 08:44:44 +01:00
# include "editor/plugins/node_3d_editor_plugin.h"
2017-03-05 14:21:25 +01:00
# include "editor/plugins/script_editor_plugin.h"
2022-11-19 12:45:49 +01:00
# include "editor/reparent_dialog.h"
2021-06-04 11:24:08 +02:00
# include "editor/shader_create_dialog.h"
2024-01-15 13:14:55 +01:00
# include "editor/themes/editor_scale.h"
2023-11-01 05:11:10 +01:00
# include "scene/animation/animation_tree.h"
2024-05-16 04:13:46 +02:00
# include "scene/audio/audio_stream_player.h"
2022-02-27 03:15:01 +01:00
# include "scene/gui/check_box.h"
2021-09-14 13:05:54 +02:00
# include "scene/property_utils.h"
2014-02-10 02:10:30 +01:00
# include "scene/resources/packed_scene.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
2016-05-11 16:46:08 +02:00
2021-11-12 13:42:58 +01:00
# include "modules/modules_enabled.gen.h" // For regex.
2022-02-14 14:00:03 +01:00
# ifdef MODULE_REGEX_ENABLED
# include "editor/rename_dialog.h"
# endif // MODULE_REGEX_ENABLED
2021-11-12 13:42:58 +01:00
2016-08-03 16:28:20 +02:00
void SceneTreeDock : : _nodes_drag_begin ( ) {
2022-05-18 19:19:38 +02:00
pending_click_select = nullptr ;
2016-08-03 16:28:20 +02:00
}
2018-10-17 07:03:22 +02:00
void SceneTreeDock : : _quick_open ( ) {
2021-06-18 00:03:09 +02:00
instantiate_scenes ( quick_open - > get_selected_files ( ) , scene_tree - > get_selected ( ) ) ;
2018-10-17 07:03:22 +02:00
}
2024-04-07 23:04:36 +02:00
void SceneTreeDock : : _inspect_hovered_node ( ) {
2024-04-27 22:09:14 +02:00
select_node_hovered_at_end_of_drag = true ;
2024-04-07 23:04:36 +02:00
Tree * tree = scene_tree - > get_scene_tree ( ) ;
2024-04-27 22:09:14 +02:00
TreeItem * item = tree - > get_item_with_metadata ( node_hovered_now - > get_path ( ) ) ;
2024-04-07 23:04:36 +02:00
if ( item ) {
2024-06-24 23:05:39 +02:00
if ( tree_item_inspected ) {
tree_item_inspected - > clear_custom_color ( 0 ) ;
}
2024-04-27 22:09:14 +02:00
tree_item_inspected = item ;
tree_item_inspected - > set_custom_color ( 0 , get_theme_color ( SNAME ( " accent_color " ) , EditorStringName ( Editor ) ) ) ;
2024-04-07 23:04:36 +02:00
}
InspectorDock : : get_inspector_singleton ( ) - > edit ( node_hovered_now ) ;
InspectorDock : : get_inspector_singleton ( ) - > propagate_notification ( NOTIFICATION_DRAG_BEGIN ) ; // Enable inspector drag preview after it updated.
InspectorDock : : get_singleton ( ) - > update ( node_hovered_now ) ;
EditorNode : : get_singleton ( ) - > hide_unused_editors ( ) ;
}
void SceneTreeDock : : _handle_hover_to_inspect ( ) {
Tree * tree = scene_tree - > get_scene_tree ( ) ;
TreeItem * item = tree - > get_item_at_position ( tree - > get_local_mouse_position ( ) ) ;
if ( item ) {
const NodePath & np = item - > get_metadata ( 0 ) ;
node_hovered_now = get_node_or_null ( np ) ;
if ( node_hovered_previously ! = node_hovered_now ) {
inspect_hovered_node_delay - > start ( ) ;
}
node_hovered_previously = node_hovered_now ;
} else {
_reset_hovering_timer ( ) ;
}
}
void SceneTreeDock : : _reset_hovering_timer ( ) {
if ( ! inspect_hovered_node_delay - > is_stopped ( ) ) {
inspect_hovered_node_delay - > stop ( ) ;
}
node_hovered_previously = nullptr ;
}
2021-08-22 17:37:22 +02:00
void SceneTreeDock : : input ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > mb = p_event ;
2022-06-10 15:14:31 +02:00
if ( mb . is_valid ( ) & & ( mb - > get_button_index ( ) = = MouseButton : : LEFT | | mb - > get_button_index ( ) = = MouseButton : : RIGHT ) ) {
2022-07-21 23:57:52 +02:00
if ( mb - > is_pressed ( ) & & scene_tree - > get_rect ( ) . has_point ( scene_tree - > get_local_mouse_position ( ) ) ) {
2022-06-10 15:14:31 +02:00
tree_clicked = true ;
} else if ( ! mb - > is_pressed ( ) ) {
tree_clicked = false ;
}
if ( ! mb - > is_pressed ( ) & & pending_click_select ) {
_push_item ( pending_click_select ) ;
pending_click_select = nullptr ;
}
2024-04-07 23:04:36 +02:00
if ( mb - > is_released ( ) ) {
2024-06-24 23:05:39 +02:00
if ( tree_item_inspected ) {
2024-04-27 22:09:14 +02:00
tree_item_inspected - > clear_custom_color ( 0 ) ;
2024-06-24 23:05:39 +02:00
tree_item_inspected = nullptr ;
2024-04-07 23:04:36 +02:00
}
_reset_hovering_timer ( ) ;
}
}
if ( tree_clicked & & get_viewport ( ) - > gui_is_dragging ( ) ) {
_handle_hover_to_inspect ( ) ;
2016-08-03 16:28:20 +02:00
}
}
2016-05-11 16:46:08 +02:00
2022-01-11 14:59:52 +01:00
void SceneTreeDock : : shortcut_input ( const Ref < InputEvent > & p_event ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2024-06-14 16:44:06 +02:00
Control * focus_owner = get_viewport ( ) - > gui_get_focus_owner ( ) ;
if ( focus_owner & & focus_owner - > is_text_field ( ) ) {
2018-02-04 01:58:51 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-02-04 01:58:51 +01:00
2020-05-14 16:41:43 +02:00
if ( ! p_event - > is_pressed ( ) | | p_event - > is_echo ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-31 03:28:37 +02:00
if ( ED_IS_SHORTCUT ( " scene_tree/rename " , p_event ) ) {
2024-06-14 16:44:06 +02:00
// Prevent renaming if a button is focused
// to avoid conflict with Enter shortcut on macOS
if ( ! focus_owner | | ! Object : : cast_to < BaseButton > ( focus_owner ) ) {
_tool_selected ( TOOL_RENAME ) ;
}
2021-08-31 03:28:37 +02:00
# ifdef MODULE_REGEX_ENABLED
} else if ( ED_IS_SHORTCUT ( " scene_tree/batch_rename " , p_event ) ) {
_tool_selected ( TOOL_BATCH_RENAME ) ;
# endif // MODULE_REGEX_ENABLED
2018-01-21 07:12:25 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/add_child_node " , p_event ) ) {
2016-06-19 21:33:42 +02:00
_tool_selected ( TOOL_NEW ) ;
2022-11-16 00:13:39 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/instantiate_scene " , p_event ) ) {
2021-06-18 00:03:09 +02:00
_tool_selected ( TOOL_INSTANTIATE ) ;
2018-07-07 16:51:18 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/expand_collapse_all " , p_event ) ) {
_tool_selected ( TOOL_EXPAND_COLLAPSE ) ;
2020-01-07 17:43:21 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/cut_node " , p_event ) ) {
_tool_selected ( TOOL_CUT ) ;
} else if ( ED_IS_SHORTCUT ( " scene_tree/copy_node " , p_event ) ) {
_tool_selected ( TOOL_COPY ) ;
} else if ( ED_IS_SHORTCUT ( " scene_tree/paste_node " , p_event ) ) {
_tool_selected ( TOOL_PASTE ) ;
2023-07-14 17:34:35 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/paste_node_as_sibling " , p_event ) ) {
_tool_selected ( TOOL_PASTE_AS_SIBLING ) ;
2016-06-19 21:33:42 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/change_node_type " , p_event ) ) {
_tool_selected ( TOOL_REPLACE ) ;
} else if ( ED_IS_SHORTCUT ( " scene_tree/duplicate " , p_event ) ) {
_tool_selected ( TOOL_DUPLICATE ) ;
2016-11-09 17:29:15 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/attach_script " , p_event ) ) {
_tool_selected ( TOOL_ATTACH_SCRIPT ) ;
2020-05-09 18:59:19 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/detach_script " , p_event ) ) {
_tool_selected ( TOOL_DETACH_SCRIPT ) ;
2016-06-19 21:33:42 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/move_up " , p_event ) ) {
_tool_selected ( TOOL_MOVE_UP ) ;
} else if ( ED_IS_SHORTCUT ( " scene_tree/move_down " , p_event ) ) {
_tool_selected ( TOOL_MOVE_DOWN ) ;
} else if ( ED_IS_SHORTCUT ( " scene_tree/reparent " , p_event ) ) {
_tool_selected ( TOOL_REPARENT ) ;
2022-12-31 21:32:32 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/reparent_to_new_node " , p_event ) ) {
_tool_selected ( TOOL_REPARENT_TO_NEW_NODE ) ;
2016-06-19 21:33:42 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/save_branch_as_scene " , p_event ) ) {
_tool_selected ( TOOL_NEW_SCENE_FROM ) ;
2016-06-12 17:47:29 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/delete_no_confirm " , p_event ) ) {
_tool_selected ( TOOL_ERASE , true ) ;
2017-01-15 11:56:30 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/copy_node_path " , p_event ) ) {
_tool_selected ( TOOL_COPY_NODE_PATH ) ;
2023-11-14 12:55:36 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/show_in_file_system " , p_event ) ) {
_tool_selected ( TOOL_SHOW_IN_FILE_SYSTEM ) ;
2022-08-31 09:44:33 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/toggle_unique_name " , p_event ) ) {
_tool_selected ( TOOL_TOGGLE_SCENE_UNIQUE_NAME ) ;
2024-03-04 14:10:47 +01:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/toggle_editable_children " , p_event ) ) {
_tool_selected ( TOOL_SCENE_EDITABLE_CHILDREN ) ;
2016-06-12 17:47:29 +02:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/delete " , p_event ) ) {
_tool_selected ( TOOL_ERASE ) ;
2020-09-16 02:44:38 +02:00
} else {
2024-07-21 10:43:53 +02:00
int match_option = EditorNode : : get_editor_data ( ) . match_context_menu_shortcut ( EditorData : : CONTEXT_SLOT_SCENE_TREE , p_event ) ;
if ( match_option ) {
_tool_selected ( match_option ) ;
}
2020-09-16 02:44:38 +02:00
return ;
2014-02-10 02:10:30 +01:00
}
2020-09-16 02:44:38 +02:00
// Tool selection was successful, accept the event to stop propagation.
accept_event ( ) ;
2014-02-10 02:10:30 +01:00
}
2024-01-15 01:47:47 +01:00
void SceneTreeDock : : _scene_tree_gui_input ( Ref < InputEvent > p_event ) {
Ref < InputEventKey > key = p_event ;
if ( key . is_null ( ) | | ! key - > is_pressed ( ) | | key - > is_echo ( ) ) {
return ;
}
if ( ED_IS_SHORTCUT ( " editor/open_search " , p_event ) ) {
filter - > grab_focus ( ) ;
filter - > select_all ( ) ;
accept_event ( ) ;
}
}
2021-06-18 00:03:09 +02:00
void SceneTreeDock : : instantiate ( const String & p_file ) {
2016-05-12 01:57:52 +02:00
Vector < String > scenes ;
scenes . push_back ( p_file ) ;
2021-06-18 00:03:09 +02:00
instantiate_scenes ( scenes , scene_tree - > get_selected ( ) ) ;
2016-05-12 01:57:52 +02:00
}
2014-02-10 02:10:30 +01:00
2021-06-18 00:03:09 +02:00
void SceneTreeDock : : instantiate_scenes ( const Vector < String > & p_files , Node * p_parent ) {
2016-07-20 19:09:03 +02:00
Node * parent = p_parent ;
if ( ! parent ) {
parent = scene_tree - > get_selected ( ) ;
}
2021-04-04 05:20:18 +02:00
if ( ! parent ) {
parent = edited_scene ;
}
if ( ! parent ) {
2021-01-15 20:13:09 +01:00
if ( p_files . size ( ) = = 1 ) {
2021-06-18 00:03:09 +02:00
accept - > set_text ( TTR ( " No parent to instantiate a child at. " ) ) ;
2021-01-15 20:13:09 +01:00
} else {
2021-06-18 00:03:09 +02:00
accept - > set_text ( TTR ( " No parent to instantiate the scenes at. " ) ) ;
2021-01-15 20:13:09 +01:00
}
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-07-20 19:09:03 +02:00
return ;
} ;
2021-06-18 00:03:09 +02:00
_perform_instantiate_scenes ( p_files , parent , - 1 ) ;
2016-07-20 19:09:03 +02:00
}
2024-05-16 04:13:46 +02:00
void SceneTreeDock : : _perform_instantiate_scenes ( const Vector < String > & p_files , Node * p_parent , int p_pos ) {
ERR_FAIL_NULL ( p_parent ) ;
2015-01-20 15:05:22 +01:00
2016-05-12 01:57:52 +02:00
Vector < Node * > instances ;
bool error = false ;
for ( int i = 0 ; i < p_files . size ( ) ; i + + ) {
Ref < PackedScene > sdata = ResourceLoader : : load ( p_files [ i ] ) ;
if ( ! sdata . is_valid ( ) ) {
current_option = - 1 ;
2016-05-19 00:08:12 +02:00
accept - > set_text ( vformat ( TTR ( " Error loading scene from %s " ) , p_files [ i ] ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-05-12 01:57:52 +02:00
error = true ;
break ;
}
2021-06-18 00:03:09 +02:00
Node * instantiated_scene = sdata - > instantiate ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
if ( ! instantiated_scene ) {
2016-05-12 01:57:52 +02:00
current_option = - 1 ;
2022-11-16 00:13:39 +01:00
accept - > set_text ( vformat ( TTR ( " Error instantiating scene from %s " ) , p_files [ i ] ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-05-12 01:57:52 +02:00
error = true ;
break ;
}
2021-12-09 10:42:46 +01:00
if ( ! edited_scene - > get_scene_file_path ( ) . is_empty ( ) ) {
2021-09-30 16:30:55 +02:00
if ( _cyclical_dependency_exists ( edited_scene - > get_scene_file_path ( ) , instantiated_scene ) ) {
2022-11-16 00:13:39 +01:00
accept - > set_text ( vformat ( TTR ( " Cannot instantiate the scene '%s' because the current scene exists within one of its nodes. " ) , p_files [ i ] ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-05-12 01:57:52 +02:00
error = true ;
break ;
}
2015-01-20 15:05:22 +01:00
}
2016-05-12 01:57:52 +02:00
2021-09-30 16:30:55 +02:00
instantiated_scene - > set_scene_file_path ( ProjectSettings : : get_singleton ( ) - > localize_path ( p_files [ i ] ) ) ;
2016-05-12 01:57:52 +02:00
2021-06-18 00:03:09 +02:00
instances . push_back ( instantiated_scene ) ;
2014-02-10 02:10:30 +01:00
}
2016-05-12 01:57:52 +02:00
if ( error ) {
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
memdelete ( instances [ i ] ) ;
}
return ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2024-05-16 04:13:46 +02:00
undo_redo - > create_action_for_history ( TTRN ( " Instantiate Scene " , " Instantiate Scenes " , instances . size ( ) ) , editor_data - > get_current_edited_scene_history_id ( ) ) ;
undo_redo - > add_do_method ( editor_selection , " clear " ) ;
2015-08-02 17:29:37 +02:00
2016-05-12 01:57:52 +02:00
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
2021-06-18 00:03:09 +02:00
Node * instantiated_scene = instances [ i ] ;
2015-08-02 17:29:37 +02:00
2024-05-16 04:13:46 +02:00
undo_redo - > add_do_method ( p_parent , " add_child " , instantiated_scene , true ) ;
2016-05-12 01:57:52 +02:00
if ( p_pos > = 0 ) {
2024-05-16 04:13:46 +02:00
undo_redo - > add_do_method ( p_parent , " move_child " , instantiated_scene , p_pos + i ) ;
2016-05-12 01:57:52 +02:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( instantiated_scene , " set_owner " , edited_scene ) ;
undo_redo - > add_do_method ( editor_selection , " add_node " , instantiated_scene ) ;
undo_redo - > add_do_reference ( instantiated_scene ) ;
2024-05-16 04:13:46 +02:00
undo_redo - > add_undo_method ( p_parent , " remove_child " , instantiated_scene ) ;
2014-02-10 02:10:30 +01:00
2024-05-16 04:13:46 +02:00
String new_name = p_parent - > validate_child_name ( instantiated_scene ) ;
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2024-05-16 04:13:46 +02:00
undo_redo - > add_do_method ( ed , " live_debug_instantiate_node " , edited_scene - > get_path_to ( p_parent ) , p_files [ i ] , new_name ) ;
undo_redo - > add_undo_method ( ed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( p_parent ) ) . path_join ( new_name ) ) ) ;
2016-05-12 01:57:52 +02:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2021-12-09 18:50:57 +01:00
_push_item ( instances [ instances . size ( ) - 1 ] ) ;
2020-08-25 01:32:58 +02:00
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " node_created " ) , instances [ i ] ) ;
2020-08-25 01:32:58 +02:00
}
2014-02-10 02:10:30 +01:00
}
2024-05-16 04:13:46 +02:00
void SceneTreeDock : : _perform_create_audio_stream_players ( const Vector < String > & p_files , Node * p_parent , int p_pos ) {
ERR_FAIL_NULL ( p_parent ) ;
StringName node_type = " AudioStreamPlayer " ;
if ( Input : : get_singleton ( ) - > is_key_pressed ( Key : : SHIFT ) ) {
if ( Object : : cast_to < Node2D > ( p_parent ) ) {
node_type = " AudioStreamPlayer2D " ;
} else if ( Object : : cast_to < Node3D > ( p_parent ) ) {
node_type = " AudioStreamPlayer3D " ;
}
}
Vector < Node * > nodes ;
bool error = false ;
for ( const String & path : p_files ) {
Ref < AudioStream > stream = ResourceLoader : : load ( path ) ;
if ( stream . is_null ( ) ) {
current_option = - 1 ;
accept - > set_text ( vformat ( TTR ( " Error loading audio stream from %s " ) , path ) ) ;
accept - > popup_centered ( ) ;
error = true ;
break ;
}
Node * player = Object : : cast_to < Node > ( ClassDB : : instantiate ( node_type ) ) ;
player - > set ( " stream " , stream ) ;
// 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 ( path . get_file ( ) . get_basename ( ) ) ;
if ( ! node_name . is_empty ( ) ) {
player - > set_name ( node_name ) ;
}
nodes . push_back ( player ) ;
}
if ( error ) {
for ( Node * node : nodes ) {
memdelete ( node ) ;
}
return ;
}
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action_for_history ( TTRN ( " Create AudioStreamPlayer " , " Create AudioStreamPlayers " , nodes . size ( ) ) , editor_data - > get_current_edited_scene_history_id ( ) ) ;
undo_redo - > add_do_method ( editor_selection , " clear " ) ;
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
Node * node = nodes [ i ] ;
undo_redo - > add_do_method ( p_parent , " add_child " , node , true ) ;
if ( p_pos > = 0 ) {
undo_redo - > add_do_method ( p_parent , " move_child " , node , p_pos + i ) ;
}
undo_redo - > add_do_method ( node , " set_owner " , edited_scene ) ;
undo_redo - > add_do_method ( editor_selection , " add_node " , node ) ;
undo_redo - > add_do_reference ( node ) ;
undo_redo - > add_undo_method ( p_parent , " remove_child " , node ) ;
String new_name = p_parent - > validate_child_name ( node ) ;
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
undo_redo - > add_do_method ( ed , " live_debug_create_node " , edited_scene - > get_path_to ( p_parent ) , node - > get_class ( ) , new_name ) ;
undo_redo - > add_undo_method ( ed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( p_parent ) ) . path_join ( new_name ) ) ) ;
}
undo_redo - > commit_action ( ) ;
}
2016-10-11 16:54:46 +02:00
void SceneTreeDock : : _replace_with_branch_scene ( const String & p_file , Node * base ) {
2023-06-29 00:46:11 +02:00
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG ( base - > get_internal_mode ( ) ! = INTERNAL_MODE_DISABLED , " Trying to replace internal node, this is not supported. " ) ;
2016-10-11 16:54:46 +02:00
Ref < PackedScene > sdata = ResourceLoader : : load ( p_file ) ;
if ( ! sdata . is_valid ( ) ) {
accept - > set_text ( vformat ( TTR ( " Error loading scene from %s " ) , p_file ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-10-11 16:54:46 +02:00
return ;
}
2021-06-18 00:03:09 +02:00
Node * instantiated_scene = sdata - > instantiate ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
if ( ! instantiated_scene ) {
2022-11-16 00:13:39 +01:00
accept - > set_text ( vformat ( TTR ( " Error instantiating scene from %s " ) , p_file ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2016-10-11 16:54:46 +02:00
return ;
}
2023-04-30 13:33:43 +02:00
instantiated_scene - > set_unique_name_in_owner ( base - > is_unique_name_in_owner ( ) ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > create_action ( TTR ( " Replace with Branch Scene " ) ) ;
2016-10-11 16:54:46 +02:00
Node * parent = base - > get_parent ( ) ;
2023-06-29 00:46:11 +02:00
int pos = base - > get_index ( false ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_do_method ( parent , " remove_child " , base ) ;
2021-06-18 00:03:09 +02:00
undo_redo - > add_undo_method ( parent , " remove_child " , instantiated_scene ) ;
2021-11-09 22:16:25 +01:00
undo_redo - > add_do_method ( parent , " add_child " , instantiated_scene , true ) ;
undo_redo - > add_undo_method ( parent , " add_child " , base , true ) ;
2021-06-18 00:03:09 +02:00
undo_redo - > add_do_method ( parent , " move_child " , instantiated_scene , pos ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_undo_method ( parent , " move_child " , base , pos ) ;
List < Node * > owned ;
base - > get_owned_by ( base - > get_owner ( ) , & owned ) ;
Array owners ;
2021-07-16 05:45:57 +02:00
for ( Node * F : owned ) {
owners . push_back ( F ) ;
2019-09-25 09:06:05 +02:00
}
2021-06-18 00:03:09 +02:00
undo_redo - > add_do_method ( instantiated_scene , " set_owner " , edited_scene ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_undo_method ( this , " _set_owners " , edited_scene , owners ) ;
undo_redo - > add_do_method ( editor_selection , " clear " ) ;
undo_redo - > add_undo_method ( editor_selection , " clear " ) ;
2021-06-18 00:03:09 +02:00
undo_redo - > add_do_method ( editor_selection , " add_node " , instantiated_scene ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_undo_method ( editor_selection , " add_node " , base ) ;
2021-06-18 00:03:09 +02:00
undo_redo - > add_do_property ( scene_tree , " set_selected " , instantiated_scene ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_undo_property ( scene_tree , " set_selected " , base ) ;
2021-06-18 00:03:09 +02:00
undo_redo - > add_do_reference ( instantiated_scene ) ;
2019-09-25 09:06:05 +02:00
undo_redo - > add_undo_reference ( base ) ;
undo_redo - > commit_action ( ) ;
2016-10-11 16:54:46 +02:00
}
2015-01-19 21:47:50 +01:00
bool SceneTreeDock : : _cyclical_dependency_exists ( const String & p_target_scene_path , Node * p_desired_node ) {
int childCount = p_desired_node - > get_child_count ( ) ;
2019-03-14 06:04:16 +01:00
if ( _track_inherit ( p_target_scene_path , p_desired_node ) ) {
2015-01-19 21:47:50 +01:00
return true ;
}
for ( int i = 0 ; i < childCount ; i + + ) {
Node * child = p_desired_node - > get_child ( i ) ;
if ( _cyclical_dependency_exists ( p_target_scene_path , child ) ) {
return true ;
}
}
return false ;
}
2019-03-14 06:04:16 +01:00
bool SceneTreeDock : : _track_inherit ( const String & p_target_scene_path , Node * p_desired_node ) {
Node * p = p_desired_node ;
bool result = false ;
Vector < Node * > instances ;
while ( true ) {
2021-09-30 16:30:55 +02:00
if ( p - > get_scene_file_path ( ) = = p_target_scene_path ) {
2019-03-14 06:04:16 +01:00
result = true ;
break ;
}
Ref < SceneState > ss = p - > get_scene_inherited_state ( ) ;
if ( ss . is_valid ( ) ) {
String path = ss - > get_path ( ) ;
2022-09-29 11:53:28 +02:00
Ref < PackedScene > pack_data = ResourceLoader : : load ( path ) ;
if ( pack_data . is_valid ( ) ) {
p = pack_data - > instantiate ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
2020-05-14 16:41:43 +02:00
if ( ! p ) {
2019-07-23 09:14:31 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2019-03-14 06:04:16 +01:00
instances . push_back ( p ) ;
2020-05-14 16:41:43 +02:00
} else {
2019-03-14 06:04:16 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
} else {
2019-03-14 06:04:16 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2019-03-14 06:04:16 +01:00
}
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
memdelete ( instances [ i ] ) ;
}
return result ;
}
2014-05-09 12:50:48 +02:00
void SceneTreeDock : : _tool_selected ( int p_tool , bool p_confirm_override ) {
2014-02-10 02:10:30 +01:00
current_option = p_tool ;
switch ( p_tool ) {
2021-08-31 03:28:37 +02:00
# ifdef MODULE_REGEX_ENABLED
2018-01-21 07:12:25 +01:00
case TOOL_BATCH_RENAME : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2019-11-01 13:03:57 +01:00
if ( editor_selection - > get_selected_node_list ( ) . size ( ) > 1 ) {
2023-10-26 22:43:08 +02:00
if ( ! _validate_no_foreign ( ) ) {
break ;
}
2018-01-21 07:12:25 +01:00
rename_dialog - > popup_centered ( ) ;
}
} break ;
2021-08-31 03:28:37 +02:00
# endif // MODULE_REGEX_ENABLED
2018-05-11 07:48:14 +02:00
case TOOL_RENAME : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2018-05-11 07:48:14 +02:00
Tree * tree = scene_tree - > get_scene_tree ( ) ;
if ( tree - > is_anything_selected ( ) ) {
2023-10-26 22:43:08 +02:00
if ( ! _validate_no_foreign ( ) ) {
break ;
}
2018-05-11 07:48:14 +02:00
tree - > grab_focus ( ) ;
tree - > edit_selected ( ) ;
}
} break ;
2022-01-17 17:37:17 +01:00
case TOOL_REPARENT_TO_NEW_NODE :
if ( ! _validate_no_foreign ( ) ) {
break ;
}
[[fallthrough]] ;
case TOOL_NEW : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2017-09-29 20:57:31 +02:00
2021-07-08 00:52:49 +02:00
if ( reset_create_dialog & & ! p_confirm_override ) {
2020-08-25 01:32:58 +02:00
create_dialog - > set_base_type ( " Node " ) ;
reset_create_dialog = false ;
}
2020-06-29 18:23:49 +02:00
// Prefer nodes that inherit from the current scene root.
Node * current_edited_scene_root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
2017-09-29 20:57:31 +02:00
if ( current_edited_scene_root ) {
2020-07-01 22:57:08 +02:00
String root_class = current_edited_scene_root - > get_class_name ( ) ;
static Vector < String > preferred_types ;
2020-12-15 13:04:21 +01:00
if ( preferred_types . is_empty ( ) ) {
2020-07-01 22:57:08 +02:00
preferred_types . push_back ( " Control " ) ;
preferred_types . push_back ( " Node2D " ) ;
preferred_types . push_back ( " Node3D " ) ;
}
2020-06-29 18:23:49 +02:00
2020-07-01 22:57:08 +02:00
for ( int i = 0 ; i < preferred_types . size ( ) ; i + + ) {
2020-06-29 18:23:49 +02:00
if ( ClassDB : : is_parent_class ( root_class , preferred_types [ i ] ) ) {
create_dialog - > set_preferred_search_result_type ( preferred_types [ i ] ) ;
break ;
}
2020-05-14 16:41:43 +02:00
}
2017-09-29 20:57:31 +02:00
}
2020-06-29 18:23:49 +02:00
2017-03-16 21:58:45 +01:00
create_dialog - > popup_create ( true ) ;
2020-08-25 01:32:58 +02:00
if ( ! p_confirm_override ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " add_node_used " ) ) ;
2020-08-25 01:32:58 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
2021-06-18 00:03:09 +02:00
case TOOL_INSTANTIATE : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 02:10:30 +01:00
Node * scene = edited_scene ;
if ( ! scene ) {
2016-05-16 17:23:40 +02:00
EditorNode : : get_singleton ( ) - > new_inherited_scene ( ) ;
2017-11-25 06:03:43 +01:00
break ;
2014-02-10 02:10:30 +01:00
}
2018-10-17 07:03:22 +02:00
quick_open - > popup_dialog ( " PackedScene " , true ) ;
2021-06-18 00:03:09 +02:00
quick_open - > set_title ( TTR ( " Instantiate Child Scene " ) ) ;
2020-08-25 01:32:58 +02:00
if ( ! p_confirm_override ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " add_node_used " ) ) ;
2020-08-25 01:32:58 +02:00
}
2018-07-07 16:51:18 +02:00
} break ;
case TOOL_EXPAND_COLLAPSE : {
Tree * tree = scene_tree - > get_scene_tree ( ) ;
TreeItem * selected_item = tree - > get_selected ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! selected_item ) {
2018-07-07 16:51:18 +02:00
selected_item = tree - > get_root ( ) ;
2021-12-01 20:18:20 +01:00
if ( ! selected_item ) {
break ;
}
2020-05-14 16:41:43 +02:00
}
2018-07-07 16:51:18 +02:00
2022-07-01 15:43:39 +02:00
bool collapsed = selected_item - > is_any_collapsed ( ) ;
selected_item - > set_collapsed_recursive ( ! collapsed ) ;
2018-07-07 16:51:18 +02:00
tree - > ensure_cursor_is_visible ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2020-01-07 17:43:21 +01:00
case TOOL_CUT :
case TOOL_COPY : {
2021-12-13 13:33:06 +01:00
if ( ! edited_scene | | ( p_tool = = TOOL_CUT & & ! _validate_no_foreign ( ) ) ) {
2020-01-07 17:43:21 +01:00
break ;
}
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . size ( ) = = 0 ) {
break ;
}
2022-01-18 16:28:44 +01:00
bool was_empty = false ;
2020-01-07 17:43:21 +01:00
if ( ! node_clipboard . is_empty ( ) ) {
_clear_clipboard ( ) ;
2022-01-18 16:28:44 +01:00
} else {
was_empty = true ;
2020-01-07 17:43:21 +01:00
}
2022-01-27 10:36:51 +01:00
clipboard_source_scene = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > get_scene_file_path ( ) ;
2020-01-07 17:43:21 +01:00
selection . sort_custom < Node : : Comparator > ( ) ;
2021-07-16 05:45:57 +02:00
for ( Node * node : selection ) {
2022-05-13 15:04:37 +02:00
HashMap < const Node * , Node * > duplimap ;
2020-01-07 17:43:21 +01:00
Node * dup = node - > duplicate_from_editor ( duplimap ) ;
ERR_CONTINUE ( ! dup ) ;
2022-07-18 00:16:43 +02:00
// Preserve ownership relations ready for pasting.
List < Node * > owned ;
2023-10-18 17:48:15 +02:00
Node * owner = node ;
while ( owner ) {
List < Node * > cur_owned ;
node - > get_owned_by ( owner , & cur_owned ) ;
owner = owner - > get_owner ( ) ;
for ( Node * F : cur_owned ) {
owned . push_back ( F ) ;
}
}
2022-07-18 00:16:43 +02:00
for ( Node * F : owned ) {
if ( ! duplimap . has ( F ) | | F = = node ) {
continue ;
}
Node * d = duplimap [ F ] ;
2023-10-18 17:48:15 +02:00
// Only use nullptr as a marker that ownership may need to be assigned when pasting.
// The ownership is subsequently tracked in the node_clipboard_edited_scene_owned list.
d - > set_owner ( nullptr ) ;
node_clipboard_edited_scene_owned . insert ( d ) ;
2022-07-18 00:16:43 +02:00
}
2020-01-07 17:43:21 +01:00
node_clipboard . push_back ( dup ) ;
}
if ( p_tool = = TOOL_CUT ) {
_delete_confirm ( true ) ;
}
2022-01-18 16:28:44 +01:00
if ( was_empty ) {
_update_create_root_dialog ( ) ;
2020-01-07 17:43:21 +01:00
}
2022-01-18 16:28:44 +01:00
} break ;
case TOOL_PASTE : {
2023-07-14 17:34:35 +02:00
paste_nodes ( false ) ;
} break ;
case TOOL_PASTE_AS_SIBLING : {
paste_nodes ( true ) ;
2020-01-07 17:43:21 +01:00
} break ;
2014-02-10 02:10:30 +01:00
case TOOL_REPLACE : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2019-07-14 16:47:24 +02:00
2021-02-22 20:18:14 +01:00
if ( ! _validate_no_foreign ( ) ) {
break ;
}
if ( ! _validate_no_instance ( ) ) {
break ;
}
2021-07-20 16:47:57 +02:00
if ( reset_create_dialog ) {
create_dialog - > set_base_type ( " Node " ) ;
reset_create_dialog = false ;
}
2019-07-14 16:47:24 +02:00
Node * selected = scene_tree - > get_selected ( ) ;
2020-12-15 13:04:21 +01:00
if ( ! selected & & ! editor_selection - > get_selected_node_list ( ) . is_empty ( ) ) {
2019-08-09 16:31:31 +02:00
selected = editor_selection - > get_selected_node_list ( ) . front ( ) - > get ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-08-09 16:31:31 +02:00
2020-05-14 16:41:43 +02:00
if ( selected ) {
2022-08-16 19:27:28 +02:00
create_dialog - > popup_create ( false , true , selected - > get_class ( ) , selected - > get_name ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
2019-10-21 06:57:10 +02:00
case TOOL_EXTEND_SCRIPT : {
attach_script_to_selected ( true ) ;
} break ;
2016-11-09 17:29:15 +01:00
case TOOL_ATTACH_SCRIPT : {
2019-10-21 06:57:10 +02:00
attach_script_to_selected ( false ) ;
2016-10-31 15:45:20 +01:00
} break ;
2020-05-09 18:59:19 +02:00
case TOOL_DETACH_SCRIPT : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_script_editing ) {
break ;
}
2019-03-06 07:11:02 +01:00
Array selection = editor_selection - > get_selected_nodes ( ) ;
2018-03-07 20:08:13 +01:00
2020-12-15 13:04:21 +01:00
if ( selection . is_empty ( ) ) {
2018-03-07 20:08:13 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-03-07 20:08:13 +01:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Detach Script " ) , UndoRedo : : MERGE_DISABLE , EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) ;
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) , " push_item " , ( Script * ) nullptr ) ;
2018-03-07 20:08:13 +01:00
2019-03-06 07:11:02 +01:00
for ( int i = 0 ; i < selection . size ( ) ; i + + ) {
Node * n = Object : : cast_to < Node > ( selection [ i ] ) ;
Ref < Script > existing = n - > get_script ( ) ;
2019-07-19 21:21:30 +02:00
Ref < Script > empty = EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( n ) ;
if ( existing ! = empty ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( n , " set_script " , empty ) ;
undo_redo - > add_undo_method ( n , " set_script " , existing ) ;
2018-03-07 20:08:13 +01:00
}
2016-10-31 15:45:20 +01:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( this , " _update_script_button " ) ;
undo_redo - > add_undo_method ( this , " _update_script_button " ) ;
2018-03-07 20:08:13 +01:00
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case TOOL_MOVE_UP :
case TOOL_MOVE_DOWN : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2020-05-14 16:41:43 +02:00
if ( ! scene_tree - > get_selected ( ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( scene_tree - > get_selected ( ) = = edited_scene ) {
current_option = - 1 ;
2016-05-21 01:18:35 +02:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2014-02-10 02:10:30 +01:00
break ;
}
2020-05-14 16:41:43 +02:00
if ( ! _validate_no_foreign ( ) ) {
2014-09-03 04:13:40 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-09-03 04:13:40 +02:00
2014-12-18 03:38:24 +01:00
bool MOVING_DOWN = ( p_tool = = TOOL_MOVE_DOWN ) ;
bool MOVING_UP = ! MOVING_DOWN ;
2014-12-18 05:46:03 +01:00
Node * common_parent = scene_tree - > get_selected ( ) - > get_parent ( ) ;
2014-12-18 03:38:24 +01:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
selection . sort_custom < Node : : Comparator > ( ) ; // sort by index
2020-05-14 16:41:43 +02:00
if ( MOVING_DOWN ) {
2021-03-14 08:21:32 +01:00
selection . reverse ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-12-18 03:38:24 +01:00
2023-06-29 00:46:11 +02:00
int lowest_id = common_parent - > get_child_count ( false ) - 1 ;
2014-12-18 05:46:03 +01:00
int highest_id = 0 ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
2023-06-29 00:46:11 +02:00
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG ( E - > get_internal_mode ( ) ! = INTERNAL_MODE_DISABLED , " Trying to move internal node, this is not supported. " ) ;
int index = E - > get_index ( false ) ;
2014-12-18 03:38:24 +01:00
2020-05-14 16:41:43 +02:00
if ( index > highest_id ) {
2014-12-18 05:46:03 +01:00
highest_id = index ;
2020-05-14 16:41:43 +02:00
}
if ( index < lowest_id ) {
2014-12-18 05:46:03 +01:00
lowest_id = index ;
2020-05-14 16:41:43 +02:00
}
2014-12-18 05:46:03 +01:00
2021-07-16 05:45:57 +02:00
if ( E - > get_parent ( ) ! = common_parent ) {
2020-04-02 01:20:12 +02:00
common_parent = nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-12-18 03:38:24 +01:00
}
2023-06-29 00:46:11 +02:00
if ( ! common_parent | | ( MOVING_DOWN & & highest_id > = common_parent - > get_child_count ( false ) - MOVING_DOWN ) | | ( MOVING_UP & & lowest_id = = 0 ) ) {
2014-12-18 05:46:03 +01:00
break ; // one or more nodes can not be moved
2020-05-14 16:41:43 +02:00
}
2014-12-18 03:38:24 +01:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2020-05-14 16:41:43 +02:00
if ( selection . size ( ) = = 1 ) {
2024-01-20 20:05:28 +01:00
undo_redo - > create_action ( TTR ( " Move Node in Parent " ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( selection . size ( ) > 1 ) {
2024-01-20 20:05:28 +01:00
undo_redo - > create_action ( TTR ( " Move Nodes in Parent " ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-12-18 05:52:27 +01:00
2024-04-15 15:18:34 +02:00
for ( List < Node * > : : Element * top_E = selection . front ( ) , * bottom_E = selection . back ( ) ; top_E & & bottom_E ; top_E = top_E - > next ( ) , bottom_E = bottom_E - > prev ( ) ) {
Node * top_node = top_E - > get ( ) ;
Node * bottom_node = bottom_E - > get ( ) ;
2016-01-18 00:03:57 +01:00
2023-09-28 11:40:18 +02:00
ERR_FAIL_NULL ( top_node - > get_parent ( ) ) ;
ERR_FAIL_NULL ( bottom_node - > get_parent ( ) ) ;
2014-12-18 03:38:24 +01:00
2023-06-29 00:46:11 +02:00
int bottom_node_pos = bottom_node - > get_index ( false ) ;
int top_node_pos_next = top_node - > get_index ( false ) + ( MOVING_DOWN ? 1 : - 1 ) ;
2014-12-18 03:38:24 +01:00
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( top_node - > get_parent ( ) , " move_child " , top_node , top_node_pos_next ) ;
undo_redo - > add_undo_method ( bottom_node - > get_parent ( ) , " move_child " , bottom_node , bottom_node_pos ) ;
2014-12-18 03:38:24 +01:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case TOOL_DUPLICATE : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2020-05-14 16:41:43 +02:00
if ( ! edited_scene ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( editor_selection - > is_selected ( edited_scene ) ) {
current_option = - 1 ;
2016-05-21 01:18:35 +02:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2014-02-10 02:10:30 +01:00
break ;
}
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2020-05-14 16:41:43 +02:00
if ( selection . size ( ) = = 0 ) {
2016-11-04 16:52:53 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Duplicate Node(s) " ) , UndoRedo : : MERGE_DISABLE , selection . front ( ) - > get ( ) ) ;
undo_redo - > add_do_method ( editor_selection , " clear " ) ;
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
Node * dupsingle = nullptr ;
2014-02-10 02:10:30 +01:00
2019-07-06 14:51:24 +02:00
selection . sort_custom < Node : : Comparator > ( ) ;
2023-12-15 20:34:32 +01:00
HashMap < const Node * , Node * > add_below_map ;
for ( List < Node * > : : Element * E = selection . back ( ) ; E ; E = E - > prev ( ) ) {
Node * node = E - > get ( ) ;
if ( ! add_below_map . has ( node - > get_parent ( ) ) ) {
add_below_map . insert ( node - > get_parent ( ) , node ) ;
}
}
2020-05-01 10:45:55 +02:00
2021-07-16 05:45:57 +02:00
for ( Node * node : selection ) {
2014-02-10 02:10:30 +01:00
Node * parent = node - > get_parent ( ) ;
List < Node * > owned ;
2023-10-18 17:52:30 +02:00
Node * owner = node ;
while ( owner ) {
List < Node * > cur_owned ;
node - > get_owned_by ( owner , & cur_owned ) ;
owner = owner - > get_owner ( ) ;
for ( Node * F : cur_owned ) {
owned . push_back ( F ) ;
}
}
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
HashMap < const Node * , Node * > duplimap ;
2017-11-19 14:32:10 +01:00
Node * dup = node - > duplicate_from_editor ( duplimap ) ;
2014-02-10 02:10:30 +01:00
ERR_CONTINUE ( ! dup ) ;
2020-05-14 16:41:43 +02:00
if ( selection . size ( ) = = 1 ) {
2014-02-10 02:10:30 +01:00
dupsingle = dup ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-07 20:25:29 +02:00
dup - > set_name ( parent - > validate_child_name ( dup ) ) ;
2014-02-10 02:10:30 +01:00
2023-12-15 20:34:32 +01:00
undo_redo - > add_do_method ( add_below_map [ parent ] , " add_sibling " , dup , true ) ;
2020-05-12 08:12:08 +02:00
2021-07-16 05:45:57 +02:00
for ( Node * F : owned ) {
if ( ! duplimap . has ( F ) ) {
2014-02-10 02:10:30 +01:00
continue ;
}
2021-07-16 05:45:57 +02:00
Node * d = duplimap [ F ] ;
2023-10-18 17:52:30 +02:00
undo_redo - > add_do_method ( d , " set_owner " , edited_scene ) ;
2014-02-10 02:10:30 +01:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( editor_selection , " add_node " , dup ) ;
2023-10-18 17:52:30 +02:00
undo_redo - > add_do_method ( dup , " set_owner " , edited_scene ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( parent , " remove_child " , dup ) ;
undo_redo - > add_do_reference ( dup ) ;
2014-02-10 02:10:30 +01:00
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2015-08-02 17:29:37 +02:00
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( ed , " live_debug_duplicate_node " , edited_scene - > get_path_to ( node ) , dup - > get_name ( ) ) ;
undo_redo - > add_undo_method ( ed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( parent ) ) . path_join ( dup - > get_name ( ) ) ) ) ;
2020-05-01 10:45:55 +02:00
2023-12-15 20:34:32 +01:00
add_below_map [ parent ] = dup ;
2014-02-10 02:10:30 +01:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( dupsingle ) {
2021-12-09 18:50:57 +01:00
_push_item ( dupsingle ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
case TOOL_REPARENT : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2020-05-14 16:41:43 +02:00
if ( ! scene_tree - > get_selected ( ) ) {
2014-02-10 02:10:30 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( editor_selection - > is_selected ( edited_scene ) ) {
current_option = - 1 ;
2016-05-21 01:18:35 +02:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2014-02-10 02:10:30 +01:00
break ;
}
2020-05-14 16:41:43 +02:00
if ( ! _validate_no_foreign ( ) ) {
2014-09-03 04:13:40 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-09-03 04:13:40 +02:00
2014-02-10 02:10:30 +01:00
List < Node * > nodes = editor_selection - > get_selected_node_list ( ) ;
2022-05-19 17:00:06 +02:00
HashSet < Node * > nodeset ;
2021-07-16 05:45:57 +02:00
for ( Node * E : nodes ) {
nodeset . insert ( E ) ;
2014-02-10 02:10:30 +01:00
}
reparent_dialog - > set_current ( nodeset ) ;
2020-07-11 18:45:19 +02:00
reparent_dialog - > popup_centered_clamped ( Size2 ( 350 , 700 ) * EDSCALE ) ;
2015-08-25 05:08:45 +02:00
} break ;
2018-07-16 04:52:57 +02:00
case TOOL_MAKE_ROOT : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2018-07-16 04:52:57 +02:00
List < Node * > nodes = editor_selection - > get_selected_node_list ( ) ;
ERR_FAIL_COND ( nodes . size ( ) ! = 1 ) ;
Node * node = nodes . front ( ) - > get ( ) ;
Node * root = get_tree ( ) - > get_edited_scene_root ( ) ;
2020-05-14 16:41:43 +02:00
if ( node = = root ) {
2018-07-16 04:52:57 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-07-16 04:52:57 +02:00
2023-06-29 00:46:11 +02:00
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG ( node - > get_internal_mode ( ) ! = INTERNAL_MODE_DISABLED , " Trying to set internal node as scene root, this is not supported. " ) ;
2019-01-17 19:20:48 +01:00
//check that from node to root, all owners are right
2019-01-22 17:49:03 +01:00
if ( root - > get_scene_inherited_state ( ) . is_valid ( ) ) {
accept - > set_text ( TTR ( " Can't reparent nodes in inherited scenes, order of nodes can't change. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2019-01-22 17:49:03 +01:00
return ;
}
2019-01-17 19:20:48 +01:00
if ( node - > get_owner ( ) ! = root ) {
accept - > set_text ( TTR ( " Node must belong to the edited scene to become root. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2019-01-17 19:20:48 +01:00
return ;
}
2021-12-09 10:42:46 +01:00
if ( ! node - > get_scene_file_path ( ) . is_empty ( ) ) {
2019-01-17 19:20:48 +01:00
accept - > set_text ( TTR ( " Instantiated scenes can't become root " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2019-01-17 19:20:48 +01:00
return ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Make node as Root " ) ) ;
undo_redo - > add_do_method ( node - > get_parent ( ) , " remove_child " , node ) ;
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , node ) ;
undo_redo - > add_do_method ( node , " add_child " , root , true ) ;
undo_redo - > add_do_method ( node , " set_scene_file_path " , root - > get_scene_file_path ( ) ) ;
undo_redo - > add_do_method ( root , " set_scene_file_path " , String ( ) ) ;
undo_redo - > add_do_method ( node , " set_owner " , ( Object * ) nullptr ) ;
undo_redo - > add_do_method ( root , " set_owner " , node ) ;
2024-07-18 01:17:22 +02:00
undo_redo - > add_do_method ( node , " set_unique_name_in_owner " , false ) ;
2018-09-30 00:04:18 +02:00
_node_replace_owner ( root , root , node , MODE_DO ) ;
2018-07-16 04:52:57 +02:00
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( root , " set_scene_file_path " , root - > get_scene_file_path ( ) ) ;
undo_redo - > add_undo_method ( node , " set_scene_file_path " , String ( ) ) ;
undo_redo - > add_undo_method ( node , " remove_child " , root ) ;
undo_redo - > add_undo_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , root ) ;
undo_redo - > add_undo_method ( node - > get_parent ( ) , " add_child " , node , true ) ;
2023-06-29 00:46:11 +02:00
undo_redo - > add_undo_method ( node - > get_parent ( ) , " move_child " , node , node - > get_index ( false ) ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( root , " set_owner " , ( Object * ) nullptr ) ;
undo_redo - > add_undo_method ( node , " set_owner " , root ) ;
2024-07-18 01:17:22 +02:00
undo_redo - > add_undo_method ( node , " set_unique_name_in_owner " , node - > is_unique_name_in_owner ( ) ) ;
2018-09-30 00:04:18 +02:00
_node_replace_owner ( root , root , root , MODE_UNDO ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_undo_method ( scene_tree , " update_tree " ) ;
undo_redo - > commit_action ( ) ;
2018-07-16 04:52:57 +02:00
} break ;
2015-08-25 05:08:45 +02:00
case TOOL_MULTI_EDIT : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2015-08-25 05:08:45 +02:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! root ) {
2015-08-25 05:08:45 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2015-08-25 05:08:45 +02:00
Ref < MultiNodeEdit > mne = memnew ( MultiNodeEdit ) ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < Node * , Object * > & E : editor_selection - > get_selection ( ) ) {
mne - > add_node ( root - > get_path_to ( E . key ) ) ;
2015-08-25 05:08:45 +02:00
}
2021-12-09 18:50:57 +01:00
_push_item ( mne . ptr ( ) ) ;
2015-08-25 05:08:45 +02:00
2014-02-10 02:10:30 +01:00
} break ;
2016-06-12 04:00:06 +02:00
2014-02-10 02:10:30 +01:00
case TOOL_ERASE : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 02:10:30 +01:00
List < Node * > remove_list = editor_selection - > get_selected_node_list ( ) ;
2020-12-15 13:04:21 +01:00
if ( remove_list . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( ! _validate_no_foreign ( ) ) {
2014-09-03 04:13:40 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-09-03 04:13:40 +02:00
2022-02-27 03:15:01 +01:00
bool allow_ask_delete_tracks = EDITOR_GET ( " docks/scene_tree/ask_before_deleting_related_animation_tracks " ) . operator bool ( ) ;
bool has_tracks_to_delete = allow_ask_delete_tracks & & _has_tracks_to_delete ( edited_scene , remove_list ) ;
if ( p_confirm_override & & ! has_tracks_to_delete ) {
2014-05-09 12:50:48 +02:00
_delete_confirm ( ) ;
} else {
2020-06-29 17:11:04 +02:00
String msg ;
if ( remove_list . size ( ) > 1 ) {
bool any_children = false ;
2024-04-15 15:18:34 +02:00
for ( List < Node * > : : ConstIterator itr = remove_list . begin ( ) ; ! any_children & & itr ! = remove_list . end ( ) ; + + itr ) {
any_children = ( * itr ) - > get_child_count ( ) > 0 ;
2020-06-29 17:11:04 +02:00
}
msg = vformat ( any_children ? TTR ( " Delete %d nodes and any children? " ) : TTR ( " Delete %d nodes? " ) , remove_list . size ( ) ) ;
2019-09-03 23:14:59 +02:00
} else {
2022-02-27 03:15:01 +01:00
if ( ! p_confirm_override ) {
2024-04-15 15:18:34 +02:00
Node * node = remove_list . front ( ) - > get ( ) ;
2022-02-27 03:15:01 +01:00
if ( node = = editor_data - > get_edited_scene_root ( ) ) {
msg = vformat ( TTR ( " Delete the root node \" %s \" ? " ) , node - > get_name ( ) ) ;
} else if ( node - > get_scene_file_path ( ) . is_empty ( ) & & node - > get_child_count ( ) > 0 ) {
// Display this message only for non-instantiated scenes
msg = vformat ( TTR ( " Delete node \" %s \" and its children? " ) , node - > get_name ( ) ) ;
} else {
msg = vformat ( TTR ( " Delete node \" %s \" ? " ) , node - > get_name ( ) ) ;
}
}
if ( has_tracks_to_delete ) {
if ( ! msg . is_empty ( ) ) {
msg + = " \n " ;
}
msg + = TTR ( " Some nodes are referenced by animation tracks. " ) ;
delete_tracks_checkbox - > show ( ) ;
2020-06-29 17:11:04 +02:00
} else {
2022-02-27 03:15:01 +01:00
delete_tracks_checkbox - > hide ( ) ;
2020-06-29 17:11:04 +02:00
}
2019-09-03 23:14:59 +02:00
}
2022-02-27 03:15:01 +01:00
delete_dialog_label - > set_text ( msg ) ;
2020-06-29 17:11:04 +02:00
2019-09-03 23:14:59 +02:00
// Resize the dialog to its minimum size.
// This prevents the dialog from being too wide after displaying
// a deletion confirmation for a node with a long name.
2021-11-20 09:04:57 +01:00
delete_dialog - > reset_size ( ) ;
2020-03-06 18:00:16 +01:00
delete_dialog - > popup_centered ( ) ;
2014-05-09 12:50:48 +02:00
}
2014-02-10 02:10:30 +01:00
2015-11-27 21:42:48 +01:00
} break ;
case TOOL_NEW_SCENE_FROM : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2015-11-27 21:42:48 +01:00
Node * scene = editor_data - > get_edited_scene_root ( ) ;
2014-02-10 02:10:30 +01:00
2015-11-27 21:42:48 +01:00
if ( ! scene ) {
2021-03-09 15:30:56 +01:00
accept - > set_text ( TTR ( " Saving the branch as a scene requires having a scene open in the editor. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
break ;
}
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . size ( ) ! = 1 ) {
2021-03-09 15:30:56 +01:00
accept - > set_text ( vformat ( TTR ( " Saving the branch as a scene requires selecting only one node, but you have selected %d nodes. " ) , selection . size ( ) ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
break ;
}
Node * tocopy = selection . front ( ) - > get ( ) ;
2014-02-10 02:10:30 +01:00
2017-01-29 20:27:14 +01:00
if ( tocopy = = scene ) {
2021-06-18 00:03:09 +02:00
accept - > set_text ( TTR ( " Can't save the root node branch as an instantiated scene. \n To create an editable copy of the current scene, duplicate it using the FileSystem dock context menu \n or create an inherited scene using Scene > New Inherited Scene... instead. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2017-01-29 20:27:14 +01:00
break ;
}
2021-12-09 10:42:46 +01:00
if ( tocopy ! = editor_data - > get_edited_scene_root ( ) & & ! tocopy - > get_scene_file_path ( ) . is_empty ( ) ) {
2021-06-18 00:03:09 +02:00
accept - > set_text ( TTR ( " Can't save the branch of an already instantiated scene. \n To create a variation of a scene, you can make an inherited scene based on the instantiated scene using Scene > New Inherited Scene... instead. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
break ;
}
2022-01-02 08:32:53 +01:00
if ( tocopy - > get_owner ( ) ! = scene ) {
accept - > set_text ( TTR ( " Can't save a branch which is a child of an already instantiated scene. \n To save this branch into its own scene, open the original scene, right click on this branch, and select \" Save Branch as Scene \" . " ) ) ;
accept - > popup_centered ( ) ;
break ;
}
if ( scene - > get_scene_inherited_state ( ) . is_valid ( ) & & scene - > get_scene_inherited_state ( ) - > find_node_by_path ( scene - > get_path_to ( tocopy ) ) > = 0 ) {
accept - > set_text ( TTR ( " Can't save a branch which is part of an inherited scene. \n To save this branch into its own scene, open the original scene, right click on this branch, and select \" Save Branch as Scene \" . " ) ) ;
accept - > popup_centered ( ) ;
break ;
}
2020-03-06 18:00:16 +01:00
new_scene_from_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2015-11-27 21:42:48 +01:00
List < String > extensions ;
Ref < PackedScene > sd = memnew ( PackedScene ) ;
ResourceSaver : : get_recognized_extensions ( sd , & extensions ) ;
new_scene_from_dialog - > clear_filters ( ) ;
2024-04-15 15:18:34 +02:00
for ( const String & extension : extensions ) {
new_scene_from_dialog - > add_filter ( " *. " + extension , extension . to_upper ( ) ) ;
2015-11-27 21:42:48 +01:00
}
String existing ;
if ( extensions . size ( ) ) {
2016-05-23 15:27:58 +02:00
String root_name ( tocopy - > get_name ( ) ) ;
2022-09-09 02:29:59 +02:00
root_name = EditorNode : : adjust_scene_name_casing ( root_name ) ;
2016-05-23 15:27:58 +02:00
existing = root_name + " . " + extensions . front ( ) - > get ( ) . to_lower ( ) ;
2015-11-27 21:42:48 +01:00
}
new_scene_from_dialog - > set_current_path ( existing ) ;
2018-04-22 19:36:01 +02:00
new_scene_from_dialog - > set_title ( TTR ( " Save New Scene As... " ) ) ;
2020-07-11 18:45:19 +02:00
new_scene_from_dialog - > popup_file_dialog ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-01-15 11:56:30 +01:00
case TOOL_COPY_NODE_PATH : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-01-15 11:56:30 +01:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
NodePath path = root - > get_path ( ) . rel_path_to ( node - > get_path ( ) ) ;
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > clipboard_set ( path ) ;
2017-01-15 11:56:30 +01:00
}
}
} break ;
2023-11-14 12:55:36 +01:00
case TOOL_SHOW_IN_FILE_SYSTEM : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
const Node * node = e - > get ( ) ;
if ( node ) {
FileSystemDock : : get_singleton ( ) - > navigate_to_path ( node - > get_scene_file_path ( ) ) ;
}
}
} break ;
2018-10-03 11:25:18 +02:00
case TOOL_OPEN_DOCUMENTATION : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-04-15 15:18:34 +02:00
for ( const Node * node : selection ) {
2024-08-27 05:42:18 +02:00
String class_name ;
Ref < Script > script_base = node - > get_script ( ) ;
if ( script_base . is_valid ( ) ) {
class_name = script_base - > get_global_name ( ) ;
}
if ( class_name . is_empty ( ) ) {
class_name = node - > get_class ( ) ;
}
ScriptEditor : : get_singleton ( ) - > goto_help ( " class_name: " + class_name ) ;
2018-10-03 11:25:18 +02:00
}
EditorNode : : get_singleton ( ) - > set_visible_editor ( EditorNode : : EDITOR_SCRIPT ) ;
} break ;
2021-08-09 19:14:06 +02:00
case TOOL_AUTO_EXPAND : {
2022-10-18 16:43:37 +02:00
scene_tree - > set_auto_expand_selected ( ! EDITOR_GET ( " docks/scene_tree/auto_expand_to_selected " ) , true ) ;
2021-08-09 19:14:06 +02:00
} break ;
2023-11-17 02:58:23 +01:00
case TOOL_CENTER_PARENT : {
EditorSettings : : get_singleton ( ) - > set ( " docks/scene_tree/center_node_on_reparent " , ! EDITOR_GET ( " docks/scene_tree/center_node_on_reparent " ) ) ;
} break ;
2017-06-30 18:17:33 +02:00
case TOOL_SCENE_EDITABLE_CHILDREN : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 18:17:33 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-03-04 14:10:47 +01:00
if ( selection . size ( ) ! = 1 ) {
break ;
}
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2024-03-04 14:10:47 +01:00
bool is_external = ( ! node - > get_scene_file_path ( ) . is_empty ( ) ) ;
bool is_top_level = node - > get_owner ( ) = = nullptr ;
if ( ! is_external | | is_top_level ) {
break ;
}
2017-06-30 18:17:33 +02:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( node ) ;
if ( editable ) {
2018-09-13 00:49:12 +02:00
editable_instance_remove_dialog - > set_text ( TTR ( " Disabling \" editable_instance \" will cause all properties of the node to be reverted to their default. " ) ) ;
2020-03-06 18:00:16 +01:00
editable_instance_remove_dialog - > popup_centered ( ) ;
2018-09-13 00:49:12 +02:00
break ;
2017-06-30 18:17:33 +02:00
}
2019-05-14 02:11:06 +02:00
_toggle_editable_children ( node ) ;
2017-06-30 18:17:33 +02:00
}
}
} break ;
case TOOL_SCENE_USE_PLACEHOLDER : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 18:17:33 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2019-09-04 21:02:26 +02:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( node ) ;
2017-06-30 18:17:33 +02:00
bool placeholder = node - > get_scene_instance_load_placeholder ( ) ;
2019-09-04 21:02:26 +02:00
// Fire confirmation dialog when children are editable.
if ( editable & & ! placeholder ) {
2023-10-23 05:03:52 +02:00
placeholder_editable_instance_remove_dialog - > set_text ( TTR ( " Enabling \" Load as Placeholder \" will disable \" Editable Children \" and cause all properties of the node to be reverted to their default. " ) ) ;
2020-03-06 18:00:16 +01:00
placeholder_editable_instance_remove_dialog - > popup_centered ( ) ;
2019-09-04 21:02:26 +02:00
break ;
}
2017-06-30 18:17:33 +02:00
placeholder = ! placeholder ;
2019-09-04 21:02:26 +02:00
2020-05-14 16:41:43 +02:00
if ( placeholder ) {
2017-06-30 18:17:33 +02:00
EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > set_editable_instance ( node , false ) ;
2020-05-14 16:41:43 +02:00
}
2017-06-30 18:17:33 +02:00
node - > set_scene_instance_load_placeholder ( placeholder ) ;
scene_tree - > update_tree ( ) ;
}
}
} break ;
2018-06-23 13:03:05 +02:00
case TOOL_SCENE_MAKE_LOCAL : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2023-10-15 14:35:19 +02:00
if ( ! _validate_no_foreign ( ) ) {
break ;
}
2017-06-30 18:17:33 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 18:17:33 +02:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! root ) {
2017-06-30 18:17:33 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-06-30 18:17:33 +02:00
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( node - > get_scene_file_path ( ) . is_empty ( ) ) ;
2018-06-23 13:03:05 +02:00
undo_redo - > create_action ( TTR ( " Make Local " ) ) ;
2021-09-30 16:30:55 +02:00
undo_redo - > add_do_method ( node , " set_scene_file_path " , " " ) ;
undo_redo - > add_undo_method ( node , " set_scene_file_path " , node - > get_scene_file_path ( ) ) ;
2017-06-30 18:17:33 +02:00
_node_replace_owner ( node , node , root ) ;
2023-09-16 15:37:56 +02:00
_node_strip_signal_inheritance ( node ) ;
NodeDock : : get_singleton ( ) - > set_node ( node ) ; // Refresh.
2017-06-30 18:17:33 +02:00
undo_redo - > add_do_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_undo_method ( scene_tree , " update_tree " ) ;
undo_redo - > commit_action ( ) ;
}
}
} break ;
case TOOL_SCENE_OPEN : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2021-09-30 16:30:55 +02:00
scene_tree - > emit_signal ( SNAME ( " open " ) , node - > get_scene_file_path ( ) ) ;
2017-06-30 18:17:33 +02:00
}
}
} break ;
case TOOL_SCENE_CLEAR_INHERITANCE : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2020-03-06 18:00:16 +01:00
clear_inherit_confirm - > popup_centered ( ) ;
2017-06-30 18:17:33 +02:00
} break ;
case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM : {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 18:17:33 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 18:17:33 +02:00
node - > set_scene_inherited_state ( Ref < SceneState > ( ) ) ;
scene_tree - > update_tree ( ) ;
2021-11-17 21:08:55 +01:00
InspectorDock : : get_inspector_singleton ( ) - > update_tree ( ) ;
2017-06-30 18:17:33 +02:00
}
}
} break ;
case TOOL_SCENE_OPEN_INHERITED : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 23:50:18 +02:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
2019-04-08 11:03:37 +02:00
if ( node & & node - > get_scene_inherited_state ( ) . is_valid ( ) ) {
2021-07-17 23:22:52 +02:00
scene_tree - > emit_signal ( SNAME ( " open " ) , node - > get_scene_inherited_state ( ) - > get_path ( ) ) ;
2017-06-30 18:17:33 +02:00
}
}
} break ;
2022-04-16 12:23:32 +02:00
case TOOL_TOGGLE_SCENE_UNIQUE_NAME : {
2022-08-16 14:34:09 +02:00
// Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked.
List < Node * > : : Element * first_selected = editor_selection - > get_selected_node_list ( ) . front ( ) ;
if ( first_selected = = nullptr ) {
return ;
}
2022-08-31 09:44:33 +02:00
if ( first_selected - > get ( ) = = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
// Exclude Root Node. It should never be unique name in its own scene!
editor_selection - > remove_node ( first_selected - > get ( ) ) ;
first_selected = editor_selection - > get_selected_node_list ( ) . front ( ) ;
if ( first_selected = = nullptr ) {
return ;
}
}
2022-08-16 14:34:09 +02:00
List < Node * > full_selection = editor_selection - > get_full_selected_node_list ( ) ;
2023-10-15 06:58:19 +02:00
// Check if all the nodes for this operation are invalid, and if they are, pop up a dialog and end here.
bool all_nodes_owner_invalid = true ;
for ( Node * node : full_selection ) {
if ( node - > get_owner ( ) = = get_tree ( ) - > get_edited_scene_root ( ) ) {
all_nodes_owner_invalid = false ;
break ;
}
}
if ( all_nodes_owner_invalid ) {
accept - > set_text ( TTR ( " Can't toggle unique name for nodes in subscene! " ) ) ;
accept - > popup_centered ( ) ;
return ;
}
bool enabling = ! first_selected - > get ( ) - > is_unique_name_in_owner ( ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-08-16 14:34:09 +02:00
if ( enabling ) {
Vector < Node * > new_unique_nodes ;
Vector < StringName > new_unique_names ;
Vector < StringName > cant_be_set_unique_names ;
for ( Node * node : full_selection ) {
if ( node - > is_unique_name_in_owner ( ) ) {
continue ;
}
2023-10-15 06:58:19 +02:00
if ( node - > get_owner ( ) ! = get_tree ( ) - > get_edited_scene_root ( ) ) {
continue ;
}
2022-08-16 14:34:09 +02:00
StringName name = node - > get_name ( ) ;
2024-05-06 16:20:20 +02:00
if ( new_unique_names . has ( name ) | | get_tree ( ) - > get_edited_scene_root ( ) - > get_node_or_null ( UNIQUE_NODE_PREFIX + String ( name ) ) ! = nullptr ) {
2022-08-16 14:34:09 +02:00
cant_be_set_unique_names . push_back ( name ) ;
} else {
new_unique_nodes . push_back ( node ) ;
new_unique_names . push_back ( name ) ;
}
}
if ( new_unique_nodes . size ( ) ) {
undo_redo - > create_action ( TTR ( " Enable Scene Unique Name(s) " ) ) ;
for ( Node * node : new_unique_nodes ) {
undo_redo - > add_do_method ( node , " set_unique_name_in_owner " , true ) ;
undo_redo - > add_undo_method ( node , " set_unique_name_in_owner " , false ) ;
}
undo_redo - > commit_action ( ) ;
}
if ( cant_be_set_unique_names . size ( ) ) {
String popup_text = TTR ( " Unique names already used by another node in the scene: " ) ;
popup_text + = " \n " ;
2021-08-01 21:47:20 +02:00
for ( const StringName & name : cant_be_set_unique_names ) {
2022-08-16 14:34:09 +02:00
popup_text + = " \n " + String ( name ) ;
}
accept - > set_text ( popup_text ) ;
2022-04-16 12:23:32 +02:00
accept - > popup_centered ( ) ;
}
2022-08-16 14:34:09 +02:00
} else { // Disabling.
undo_redo - > create_action ( TTR ( " Disable Scene Unique Name(s) " ) ) ;
for ( Node * node : full_selection ) {
if ( ! node - > is_unique_name_in_owner ( ) ) {
continue ;
}
2023-10-15 06:58:19 +02:00
if ( node - > get_owner ( ) ! = get_tree ( ) - > get_edited_scene_root ( ) ) {
continue ;
}
2022-08-16 14:34:09 +02:00
undo_redo - > add_do_method ( node , " set_unique_name_in_owner " , false ) ;
undo_redo - > add_undo_method ( node , " set_unique_name_in_owner " , true ) ;
2022-04-16 12:23:32 +02:00
}
undo_redo - > commit_action ( ) ;
}
} break ;
2018-07-16 04:11:29 +02:00
case TOOL_CREATE_2D_SCENE :
case TOOL_CREATE_3D_SCENE :
2018-07-25 05:48:24 +02:00
case TOOL_CREATE_USER_INTERFACE :
case TOOL_CREATE_FAVORITE : {
2020-04-02 01:20:12 +02:00
Node * new_node = nullptr ;
2018-07-29 20:09:42 +02:00
2018-07-25 05:48:24 +02:00
if ( TOOL_CREATE_FAVORITE = = p_tool ) {
String name = selected_favorite_root . get_slicec ( ' ' , 0 ) ;
if ( ScriptServer : : is_global_class ( name ) ) {
2022-09-29 11:53:28 +02:00
Ref < Script > scr = ResourceLoader : : load ( ScriptServer : : get_global_class_path ( name ) , " Script " ) ;
2022-11-25 11:21:15 +01:00
if ( scr . is_valid ( ) ) {
new_node = Object : : cast_to < Node > ( ClassDB : : instantiate ( scr - > get_instance_base_type ( ) ) ) ;
if ( new_node ) {
new_node - > set_script ( scr ) ;
new_node - > set_name ( name ) ;
}
2018-07-25 05:48:24 +02:00
}
} else {
2021-06-18 00:03:09 +02:00
new_node = Object : : cast_to < Node > ( ClassDB : : instantiate ( selected_favorite_root ) ) ;
2018-07-25 05:48:24 +02:00
}
2019-08-15 04:57:49 +02:00
2018-07-25 05:48:24 +02:00
if ( ! new_node ) {
new_node = memnew ( Node ) ;
2019-11-06 17:03:04 +01:00
ERR_PRINT ( " Creating root from favorite ' " + selected_favorite_root + " ' failed. Creating 'Node' instead. " ) ;
2018-07-25 05:48:24 +02:00
}
} else {
switch ( p_tool ) {
2020-05-10 13:00:47 +02:00
case TOOL_CREATE_2D_SCENE :
new_node = memnew ( Node2D ) ;
break ;
case TOOL_CREATE_3D_SCENE :
new_node = memnew ( Node3D ) ;
break ;
2018-07-25 05:48:24 +02:00
case TOOL_CREATE_USER_INTERFACE : {
Control * node = memnew ( Control ) ;
2023-01-03 17:21:26 +01:00
// Making the root control full rect by default is more useful for resizable UIs.
node - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
node - > set_grow_direction_preset ( PRESET_FULL_RECT ) ;
2018-07-25 05:48:24 +02:00
new_node = node ;
} break ;
}
2018-07-16 04:11:29 +02:00
}
2021-07-07 01:59:46 +02:00
add_root_node ( new_node ) ;
2018-07-16 04:11:29 +02:00
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > edit_node ( new_node ) ;
2018-10-04 02:36:58 +02:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( new_node ) ;
2018-09-20 10:44:58 +02:00
2021-06-11 20:37:32 +02:00
scene_tree - > get_scene_tree ( ) - > grab_focus ( ) ;
2018-07-16 04:11:29 +02:00
} break ;
2017-06-05 05:12:19 +02:00
default : {
2024-07-21 10:43:53 +02:00
// Editor context plugin.
if ( p_tool > = EditorData : : CONTEXT_MENU_ITEM_ID_BASE ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
EditorNode : : get_editor_data ( ) . scene_tree_options_pressed ( EditorData : : CONTEXT_SLOT_SCENE_TREE , p_tool , selection ) ;
break ;
}
2022-09-16 15:10:28 +02:00
_filter_option_selected ( p_tool ) ;
2017-06-05 05:12:19 +02:00
if ( p_tool > = EDIT_SUBRESOURCE_BASE ) {
int idx = p_tool - EDIT_SUBRESOURCE_BASE ;
ERR_FAIL_INDEX ( idx , subresources . size ( ) ) ;
Object * obj = ObjectDB : : get_instance ( subresources [ idx ] ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( obj ) ;
2017-06-05 05:12:19 +02:00
2021-12-09 18:50:57 +01:00
_push_item ( obj ) ;
2017-06-05 05:12:19 +02:00
}
}
2014-02-10 02:10:30 +01:00
}
}
2021-07-16 16:27:59 +02:00
void SceneTreeDock : : _property_selected ( int p_idx ) {
ERR_FAIL_NULL ( property_drop_node ) ;
_perform_property_drop ( property_drop_node , menu_properties - > get_item_metadata ( p_idx ) , ResourceLoader : : load ( resource_drop_path ) ) ;
property_drop_node = nullptr ;
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : _perform_property_drop ( Node * p_node , const String & p_property , Ref < Resource > p_res ) {
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( vformat ( TTR ( " Set %s " ) , p_property ) ) ;
undo_redo - > add_do_property ( p_node , p_property , p_res ) ;
undo_redo - > add_undo_property ( p_node , p_property , p_node - > get ( p_property ) ) ;
undo_redo - > commit_action ( ) ;
2021-07-16 16:27:59 +02:00
}
2021-07-07 01:59:46 +02:00
void SceneTreeDock : : add_root_node ( Node * p_node ) {
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action_for_history ( TTR ( " New Scene Root " ) , editor_data - > get_current_edited_scene_history_id ( ) ) ;
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , p_node ) ;
undo_redo - > add_do_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_do_reference ( p_node ) ;
undo_redo - > add_undo_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , ( Object * ) nullptr ) ;
undo_redo - > commit_action ( ) ;
2021-07-07 01:59:46 +02:00
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _notification ( int p_what ) {
switch ( p_what ) {
2015-06-14 07:13:47 +02:00
case NOTIFICATION_READY : {
2020-05-14 16:41:43 +02:00
if ( ! first_enter ) {
2015-06-14 07:13:47 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2015-06-14 07:13:47 +02:00
first_enter = false ;
2014-02-10 02:10:30 +01:00
2020-02-21 18:28:45 +01:00
EditorFeatureProfileManager : : get_singleton ( ) - > connect ( " current_feature_profile_changed " , callable_mp ( this , & SceneTreeDock : : _feature_profile_changed ) ) ;
2019-04-09 00:18:03 +02:00
2023-08-11 15:55:47 +02:00
CanvasItemEditorPlugin * canvas_item_plugin = Object : : cast_to < CanvasItemEditorPlugin > ( editor_data - > get_editor_by_name ( " 2D " ) ) ;
2015-06-14 07:13:47 +02:00
if ( canvas_item_plugin ) {
2022-10-18 04:40:30 +02:00
canvas_item_plugin - > get_canvas_item_editor ( ) - > connect ( " item_lock_status_changed " , callable_mp ( scene_tree , & SceneTreeEditor : : _update_tree ) . bind ( false ) ) ;
canvas_item_plugin - > get_canvas_item_editor ( ) - > connect ( " item_group_status_changed " , callable_mp ( scene_tree , & SceneTreeEditor : : _update_tree ) . bind ( false ) ) ;
2022-08-13 23:21:24 +02:00
scene_tree - > connect ( " node_changed " , callable_mp ( ( CanvasItem * ) canvas_item_plugin - > get_canvas_item_editor ( ) - > get_viewport_control ( ) , & CanvasItem : : queue_redraw ) ) ;
2015-06-14 07:13:47 +02:00
}
2017-10-23 21:21:15 +02:00
2023-08-11 15:55:47 +02:00
Node3DEditorPlugin * spatial_editor_plugin = Object : : cast_to < Node3DEditorPlugin > ( editor_data - > get_editor_by_name ( " 3D " ) ) ;
2022-10-18 04:40:30 +02:00
spatial_editor_plugin - > get_spatial_editor ( ) - > connect ( " item_lock_status_changed " , callable_mp ( scene_tree , & SceneTreeEditor : : _update_tree ) . bind ( false ) ) ;
spatial_editor_plugin - > get_spatial_editor ( ) - > connect ( " item_group_status_changed " , callable_mp ( scene_tree , & SceneTreeEditor : : _update_tree ) . bind ( false ) ) ;
2017-10-23 21:21:15 +02:00
2018-07-26 13:45:38 +02:00
filter - > set_clear_button_enabled ( true ) ;
2017-01-23 05:40:43 +01:00
2018-07-25 05:48:24 +02:00
// create_root_dialog
HBoxContainer * top_row = memnew ( HBoxContainer ) ;
top_row - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2021-07-08 15:29:15 +02:00
Label * l = memnew ( Label ( TTR ( " Create Root Node: " ) ) ) ;
l - > set_theme_type_variation ( " HeaderSmall " ) ;
top_row - > add_child ( l ) ;
2018-07-25 05:48:24 +02:00
top_row - > add_spacer ( ) ;
2018-07-16 04:11:29 +02:00
2022-09-03 23:10:07 +02:00
node_shortcuts_toggle = memnew ( Button ) ;
2020-06-19 20:49:04 +02:00
node_shortcuts_toggle - > set_flat ( true ) ;
2023-08-13 02:33:39 +02:00
node_shortcuts_toggle - > set_icon ( get_editor_theme_icon ( SNAME ( " Favorites " ) ) ) ;
2018-07-25 05:48:24 +02:00
node_shortcuts_toggle - > set_toggle_mode ( true ) ;
2023-11-08 15:22:55 +01:00
node_shortcuts_toggle - > set_tooltip_text ( TTR ( " Toggle the display of favorite nodes. " ) ) ;
2018-07-25 05:48:24 +02:00
node_shortcuts_toggle - > set_pressed ( EDITOR_GET ( " _use_favorites_root_selection " ) ) ;
2020-12-22 17:24:29 +01:00
node_shortcuts_toggle - > set_anchors_and_offsets_preset ( Control : : PRESET_CENTER_RIGHT ) ;
2024-08-05 21:14:24 +02:00
node_shortcuts_toggle - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _update_create_root_dialog ) . bind ( false ) ) ;
2018-07-25 05:48:24 +02:00
top_row - > add_child ( node_shortcuts_toggle ) ;
create_root_dialog - > add_child ( top_row ) ;
2022-01-19 00:05:43 +01:00
ScrollContainer * scroll_container = memnew ( ScrollContainer ) ;
create_root_dialog - > add_child ( scroll_container ) ;
scroll_container - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
scroll_container - > set_horizontal_scroll_mode ( ScrollContainer : : SCROLL_MODE_DISABLED ) ;
2018-07-25 05:48:24 +02:00
VBoxContainer * node_shortcuts = memnew ( VBoxContainer ) ;
2022-01-19 00:05:43 +01:00
scroll_container - > add_child ( node_shortcuts ) ;
node_shortcuts - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2018-07-16 04:11:29 +02:00
2022-09-03 23:10:07 +02:00
beginner_node_shortcuts = memnew ( VBoxContainer ) ;
2018-07-25 05:48:24 +02:00
node_shortcuts - > add_child ( beginner_node_shortcuts ) ;
2020-09-17 04:33:19 +02:00
button_2d = memnew ( Button ) ;
2018-07-25 05:48:24 +02:00
beginner_node_shortcuts - > add_child ( button_2d ) ;
2018-07-16 04:11:29 +02:00
button_2d - > set_text ( TTR ( " 2D Scene " ) ) ;
2023-08-13 02:33:39 +02:00
button_2d - > set_icon ( get_editor_theme_icon ( SNAME ( " Node2D " ) ) ) ;
2024-05-14 09:40:21 +02:00
button_2d - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_CREATE_2D_SCENE , false ) ) ;
2020-03-12 13:37:40 +01:00
2019-11-10 16:58:56 +01:00
button_3d = memnew ( Button ) ;
2018-07-25 05:48:24 +02:00
beginner_node_shortcuts - > add_child ( button_3d ) ;
2018-07-16 04:11:29 +02:00
button_3d - > set_text ( TTR ( " 3D Scene " ) ) ;
2023-08-13 02:33:39 +02:00
button_3d - > set_icon ( get_editor_theme_icon ( SNAME ( " Node3D " ) ) ) ;
2024-05-14 09:40:21 +02:00
button_3d - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_CREATE_3D_SCENE , false ) ) ;
2018-07-16 04:11:29 +02:00
2020-09-17 04:33:19 +02:00
button_ui = memnew ( Button ) ;
2018-07-25 05:48:24 +02:00
beginner_node_shortcuts - > add_child ( button_ui ) ;
2018-07-16 04:11:29 +02:00
button_ui - > set_text ( TTR ( " User Interface " ) ) ;
2023-08-13 02:33:39 +02:00
button_ui - > set_icon ( get_editor_theme_icon ( SNAME ( " Control " ) ) ) ;
2024-05-14 09:40:21 +02:00
button_ui - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_CREATE_USER_INTERFACE , false ) ) ;
2018-07-16 04:11:29 +02:00
2022-09-03 23:10:07 +02:00
favorite_node_shortcuts = memnew ( VBoxContainer ) ;
2018-07-25 05:48:24 +02:00
node_shortcuts - > add_child ( favorite_node_shortcuts ) ;
2020-09-17 04:33:19 +02:00
button_custom = memnew ( Button ) ;
2018-07-25 05:48:24 +02:00
node_shortcuts - > add_child ( button_custom ) ;
2019-03-12 16:12:14 +01:00
button_custom - > set_text ( TTR ( " Other Node " ) ) ;
2023-08-13 02:33:39 +02:00
button_custom - > set_icon ( get_editor_theme_icon ( SNAME ( " Add " ) ) ) ;
2024-05-14 09:40:21 +02:00
button_custom - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_NEW , false ) ) ;
2018-07-16 04:11:29 +02:00
2022-01-18 16:28:44 +01:00
button_clipboard = memnew ( Button ) ;
node_shortcuts - > add_child ( button_clipboard ) ;
button_clipboard - > set_text ( TTR ( " Paste From Clipboard " ) ) ;
2023-08-13 02:33:39 +02:00
button_clipboard - > set_icon ( get_editor_theme_icon ( SNAME ( " ActionPaste " ) ) ) ;
2024-05-14 09:40:21 +02:00
button_clipboard - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_PASTE , false ) ) ;
2022-01-18 16:28:44 +01:00
2024-08-05 21:14:24 +02:00
_update_create_root_dialog ( true ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-06-30 18:17:33 +02:00
case NOTIFICATION_ENTER_TREE : {
2024-05-14 14:28:18 +02:00
clear_inherit_confirm - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM , false ) ) ;
2022-10-18 16:43:37 +02:00
scene_tree - > set_auto_expand_selected ( EDITOR_GET ( " docks/scene_tree/auto_expand_to_selected " ) , false ) ;
2017-06-30 18:17:33 +02:00
} break ;
case NOTIFICATION_EXIT_TREE : {
2024-05-14 14:28:18 +02:00
clear_inherit_confirm - > disconnect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) ) ;
2017-06-30 18:17:33 +02:00
} break ;
2022-02-16 15:17:55 +01:00
2017-08-30 01:03:13 +02:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
2022-11-23 00:14:08 +01:00
if ( EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " docks/scene_tree " ) ) {
scene_tree - > set_auto_expand_selected ( EDITOR_GET ( " docks/scene_tree/auto_expand_to_selected " ) , false ) ;
}
2023-03-31 21:17:59 +02:00
} break ;
case NOTIFICATION_THEME_CHANGED : {
2023-08-13 02:33:39 +02:00
button_add - > set_icon ( get_editor_theme_icon ( SNAME ( " Add " ) ) ) ;
button_instance - > set_icon ( get_editor_theme_icon ( SNAME ( " Instance " ) ) ) ;
button_create_script - > set_icon ( get_editor_theme_icon ( SNAME ( " ScriptCreate " ) ) ) ;
button_detach_script - > set_icon ( get_editor_theme_icon ( SNAME ( " ScriptRemove " ) ) ) ;
button_tree_menu - > set_icon ( get_editor_theme_icon ( SNAME ( " GuiTabMenuHl " ) ) ) ;
2021-07-17 23:22:52 +02:00
2023-08-13 02:33:39 +02:00
filter - > set_right_icon ( get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
2023-03-31 21:17:59 +02:00
2023-07-23 06:14:28 +02:00
PopupMenu * filter_menu = filter - > get_menu ( ) ;
2023-08-13 02:33:39 +02:00
filter_menu - > set_item_icon ( filter_menu - > get_item_idx_from_text ( TTR ( " Filters " ) ) , get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
filter_menu - > set_item_icon ( filter_menu - > get_item_index ( FILTER_BY_TYPE ) , get_editor_theme_icon ( SNAME ( " Node " ) ) ) ;
filter_menu - > set_item_icon ( filter_menu - > get_item_index ( FILTER_BY_GROUP ) , get_editor_theme_icon ( SNAME ( " Groups " ) ) ) ;
2023-07-23 06:14:28 +02:00
2023-03-31 21:17:59 +02:00
// These buttons are created on READY, because reasons...
if ( button_2d ) {
2023-08-13 02:33:39 +02:00
button_2d - > set_icon ( get_editor_theme_icon ( SNAME ( " Node2D " ) ) ) ;
2023-03-31 21:17:59 +02:00
}
if ( button_3d ) {
2023-08-13 02:33:39 +02:00
button_3d - > set_icon ( get_editor_theme_icon ( SNAME ( " Node3D " ) ) ) ;
2023-03-31 21:17:59 +02:00
}
if ( button_ui ) {
2023-08-13 02:33:39 +02:00
button_ui - > set_icon ( get_editor_theme_icon ( SNAME ( " Control " ) ) ) ;
2023-03-31 21:17:59 +02:00
}
if ( button_custom ) {
2023-08-13 02:33:39 +02:00
button_custom - > set_icon ( get_editor_theme_icon ( SNAME ( " Add " ) ) ) ;
2023-03-31 21:17:59 +02:00
}
if ( button_clipboard ) {
2023-08-13 02:33:39 +02:00
button_clipboard - > set_icon ( get_editor_theme_icon ( SNAME ( " ActionPaste " ) ) ) ;
2023-03-31 21:17:59 +02:00
}
2023-08-13 02:33:39 +02:00
menu_subresources - > add_theme_constant_override ( " icon_max_width " , get_theme_constant ( SNAME ( " class_icon_size " ) , EditorStringName ( Editor ) ) ) ;
2017-08-30 01:03:13 +02:00
} break ;
2022-02-16 15:17:55 +01:00
2018-07-16 04:11:29 +02:00
case NOTIFICATION_PROCESS : {
2020-04-02 01:20:12 +02:00
bool show_create_root = bool ( EDITOR_GET ( " interface/editors/show_scene_tree_root_selection " ) ) & & get_tree ( ) - > get_edited_scene_root ( ) = = nullptr ;
2018-07-16 04:11:29 +02:00
2019-05-30 02:20:59 +02:00
if ( show_create_root ! = create_root_dialog - > is_visible_in_tree ( ) & & ! remote_tree - > is_visible ( ) ) {
2018-07-16 04:11:29 +02:00
if ( show_create_root ) {
create_root_dialog - > show ( ) ;
scene_tree - > hide ( ) ;
} else {
create_root_dialog - > hide ( ) ;
scene_tree - > show ( ) ;
}
}
} break ;
2024-04-07 23:04:36 +02:00
case NOTIFICATION_DRAG_END : {
_reset_hovering_timer ( ) ;
2024-04-27 22:09:14 +02:00
if ( select_node_hovered_at_end_of_drag & & ! hovered_but_reparenting ) {
Node * node_inspected = Object : : cast_to < Node > ( InspectorDock : : get_inspector_singleton ( ) - > get_edited_object ( ) ) ;
if ( node_inspected ) {
editor_selection - > clear ( ) ;
editor_selection - > add_node ( node_inspected ) ;
scene_tree - > set_selected ( node_inspected ) ;
select_node_hovered_at_end_of_drag = false ;
}
}
hovered_but_reparenting = false ;
2024-04-07 23:04:36 +02:00
} break ;
2017-06-30 18:17:33 +02:00
}
}
2018-07-16 04:52:57 +02:00
void SceneTreeDock : : _node_replace_owner ( Node * p_base , Node * p_node , Node * p_root , ReplaceOwnerMode p_mode ) {
2018-10-11 00:45:44 +02:00
if ( p_node - > get_owner ( ) = = p_base & & p_node ! = p_root ) {
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2018-09-30 00:04:18 +02:00
switch ( p_mode ) {
case MODE_BIDI : {
2022-07-26 13:55:07 +02:00
bool disable_unique = p_node - > is_unique_name_in_owner ( ) & & p_root - > get_node_or_null ( UNIQUE_NODE_PREFIX + String ( p_node - > get_name ( ) ) ) ! = nullptr ;
if ( disable_unique ) {
2022-04-16 12:23:32 +02:00
// Will create a unique name conflict. Disable before setting owner.
undo_redo - > add_do_method ( p_node , " set_unique_name_in_owner " , false ) ;
}
2018-09-30 00:04:18 +02:00
undo_redo - > add_do_method ( p_node , " set_owner " , p_root ) ;
undo_redo - > add_undo_method ( p_node , " set_owner " , p_base ) ;
2022-07-26 13:55:07 +02:00
if ( disable_unique ) {
2022-04-16 12:23:32 +02:00
// Will create a unique name conflict. Enable after setting owner.
undo_redo - > add_undo_method ( p_node , " set_unique_name_in_owner " , true ) ;
}
2018-07-16 04:52:57 +02:00
2018-09-30 00:04:18 +02:00
} break ;
case MODE_DO : {
undo_redo - > add_do_method ( p_node , " set_owner " , p_root ) ;
2018-07-16 04:52:57 +02:00
2018-09-30 00:04:18 +02:00
} break ;
case MODE_UNDO : {
undo_redo - > add_undo_method ( p_node , " set_owner " , p_root ) ;
2018-07-16 04:52:57 +02:00
2018-09-30 00:04:18 +02:00
} break ;
2017-06-30 18:17:33 +02:00
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2018-07-16 04:52:57 +02:00
_node_replace_owner ( p_base , p_node - > get_child ( i ) , p_root , p_mode ) ;
2014-02-10 02:10:30 +01:00
}
}
2023-09-16 15:37:56 +02:00
void SceneTreeDock : : _node_strip_signal_inheritance ( Node * p_node ) {
List < Object : : Connection > conns ;
p_node - > get_all_signal_connections ( & conns ) ;
for ( Object : : Connection conn : conns ) {
conn . signal . disconnect ( conn . callable ) ;
conn . signal . connect ( conn . callable , conn . flags & ~ CONNECT_INHERITED ) ;
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_node_strip_signal_inheritance ( p_node - > get_child ( i ) ) ;
}
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _load_request ( const String & p_path ) {
2022-01-27 10:36:51 +01:00
EditorNode : : get_singleton ( ) - > open_request ( p_path ) ;
2022-08-31 00:52:05 +02:00
_local_tree_selected ( ) ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeDock : : _script_open_request ( const Ref < Script > & p_script ) {
2024-02-13 16:54:33 +01:00
EditorNode : : get_singleton ( ) - > push_item_no_inspector ( p_script . ptr ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2021-12-09 18:50:57 +01:00
void SceneTreeDock : : _push_item ( Object * p_object ) {
2023-02-01 00:50:34 +01:00
Node * node = Object : : cast_to < Node > ( p_object ) ;
if ( node | | ! p_object ) {
// Assume that null object is a Node.
EditorNode : : get_singleton ( ) - > push_node_item ( node ) ;
} else {
EditorNode : : get_singleton ( ) - > push_item ( p_object ) ;
}
2023-01-21 22:49:06 +01:00
if ( p_object = = nullptr ) {
EditorNode : : get_singleton ( ) - > hide_unused_editors ( this ) ;
}
2022-05-18 19:19:38 +02:00
}
void SceneTreeDock : : _handle_select ( Node * p_node ) {
2022-06-10 15:14:31 +02:00
if ( tree_clicked ) {
2022-05-18 19:19:38 +02:00
pending_click_select = p_node ;
} else {
2022-06-10 15:14:31 +02:00
_push_item ( p_node ) ;
2021-12-09 18:50:57 +01:00
}
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _node_selected ( ) {
Node * node = scene_tree - > get_selected ( ) ;
if ( ! node ) {
return ;
}
2022-05-18 19:19:38 +02:00
_handle_select ( node ) ;
2014-02-10 02:10:30 +01:00
}
2014-09-21 17:56:19 +02:00
void SceneTreeDock : : _node_renamed ( ) {
_node_selected ( ) ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _set_owners ( Node * p_owner , const Array & p_nodes ) {
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
2017-08-24 22:58:51 +02:00
Node * n = Object : : cast_to < Node > ( p_nodes [ i ] ) ;
2020-05-14 16:41:43 +02:00
if ( ! n ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
n - > set_owner ( p_owner ) ;
}
}
2022-05-13 15:04:37 +02:00
void SceneTreeDock : : _fill_path_renames ( Vector < StringName > base_path , Vector < StringName > new_base_path , Node * p_node , HashMap < Node * , NodePath > * p_renames ) {
2014-02-10 02:10:30 +01:00
base_path . push_back ( p_node - > get_name ( ) ) ;
2021-07-09 20:21:27 +02:00
NodePath new_path ;
2022-02-27 03:15:01 +01:00
if ( ! new_base_path . is_empty ( ) ) {
new_base_path . push_back ( p_node - > get_name ( ) ) ;
2021-07-09 20:21:27 +02:00
new_path = NodePath ( new_base_path , true ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-07-09 20:21:27 +02:00
p_renames - > insert ( p_node , new_path ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_fill_path_renames ( base_path , new_base_path , p_node - > get_child ( i ) , p_renames ) ;
}
}
2022-02-27 03:15:01 +01:00
bool SceneTreeDock : : _has_tracks_to_delete ( Node * p_node , List < Node * > & p_to_delete ) const {
2023-09-28 16:35:35 +02:00
// Skip if this node will be deleted.
for ( const Node * F : p_to_delete ) {
if ( F = = p_node | | F - > is_ancestor_of ( p_node ) ) {
return false ;
}
}
// This is an AnimationPlayer that survives the deletion.
2022-02-27 03:15:01 +01:00
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_node ) ;
if ( ap ) {
2023-07-20 17:34:06 +02:00
Node * root = ap - > get_node ( ap - > get_root_node ( ) ) ;
2022-02-27 03:15:01 +01:00
if ( root & & ! p_to_delete . find ( root ) ) {
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
for ( const StringName & E : anims ) {
Ref < Animation > anim = ap - > get_animation ( E ) ;
if ( anim . is_null ( ) ) {
continue ;
}
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
NodePath track_np = anim - > track_get_path ( i ) ;
Node * n = root - > get_node_or_null ( track_np ) ;
if ( n ) {
for ( const Node * F : p_to_delete ) {
if ( F = = n | | F - > is_ancestor_of ( n ) ) {
return true ;
}
}
}
}
}
}
}
2023-09-28 16:35:35 +02:00
// Recursively check child nodes.
2022-02-27 03:15:01 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
if ( _has_tracks_to_delete ( p_node - > get_child ( i ) , p_to_delete ) ) {
return true ;
}
}
2023-09-28 16:35:35 +02:00
2022-02-27 03:15:01 +01:00
return false ;
}
2022-05-13 15:04:37 +02:00
void SceneTreeDock : : fill_path_renames ( Node * p_node , Node * p_new_parent , HashMap < Node * , NodePath > * p_renames ) {
2014-02-10 02:10:30 +01:00
Vector < StringName > base_path ;
Node * n = p_node - > get_parent ( ) ;
while ( n ) {
base_path . push_back ( n - > get_name ( ) ) ;
n = n - > get_parent ( ) ;
}
2021-03-14 08:21:32 +01:00
base_path . reverse ( ) ;
2014-02-10 02:10:30 +01:00
Vector < StringName > new_base_path ;
if ( p_new_parent ) {
n = p_new_parent ;
while ( n ) {
new_base_path . push_back ( n - > get_name ( ) ) ;
n = n - > get_parent ( ) ;
}
2021-03-14 08:21:32 +01:00
new_base_path . reverse ( ) ;
2014-02-10 02:10:30 +01:00
}
_fill_path_renames ( base_path , new_base_path , p_node , p_renames ) ;
}
2022-05-13 15:04:37 +02:00
bool SceneTreeDock : : _update_node_path ( Node * p_root_node , NodePath & r_node_path , HashMap < Node * , NodePath > * p_renames ) const {
2021-07-09 20:21:27 +02:00
Node * target_node = p_root_node - > get_node_or_null ( r_node_path ) ;
ERR_FAIL_NULL_V_MSG ( target_node , false , " Found invalid node path ' " + String ( r_node_path ) + " ' on node ' " + String ( scene_root - > get_path_to ( p_root_node ) ) + " ' " ) ;
2021-06-21 21:09:00 +02:00
2021-07-09 20:21:27 +02:00
// Try to find the target node in modified node paths.
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > : : Iterator found_node_path = p_renames - > find ( target_node ) ;
2021-07-09 20:21:27 +02:00
if ( found_node_path ) {
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > : : Iterator found_root_path = p_renames - > find ( p_root_node ) ;
NodePath root_path_new = found_root_path ? found_root_path - > value : p_root_node - > get_path ( ) ;
r_node_path = root_path_new . rel_path_to ( found_node_path - > value ) ;
2021-06-21 21:09:00 +02:00
2021-07-09 20:21:27 +02:00
return true ;
}
2021-06-21 21:09:00 +02:00
2021-07-09 20:21:27 +02:00
// Update the path if the base node has changed and has not been deleted.
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > : : Iterator found_root_path = p_renames - > find ( p_root_node ) ;
2021-07-09 20:21:27 +02:00
if ( found_root_path ) {
2022-05-13 15:04:37 +02:00
NodePath root_path_new = found_root_path - > value ;
2021-07-09 20:21:27 +02:00
if ( ! root_path_new . is_empty ( ) ) {
2022-08-30 02:34:01 +02:00
NodePath old_abs_path = NodePath ( String ( p_root_node - > get_path ( ) ) . path_join ( r_node_path ) ) ;
2021-07-09 20:21:27 +02:00
old_abs_path . simplify ( ) ;
r_node_path = root_path_new . rel_path_to ( old_abs_path ) ;
2021-06-21 21:09:00 +02:00
}
2021-07-09 20:21:27 +02:00
return true ;
2021-06-21 21:09:00 +02:00
}
return false ;
}
2023-10-13 13:29:47 +02:00
bool SceneTreeDock : : _check_node_path_recursive ( Node * p_root_node , Variant & r_variant , HashMap < Node * , NodePath > * p_renames , bool p_inside_resource ) const {
2021-06-30 20:50:40 +02:00
switch ( r_variant . get_type ( ) ) {
2021-06-21 21:09:00 +02:00
case Variant : : NODE_PATH : {
2021-06-30 20:50:40 +02:00
NodePath node_path = r_variant ;
2023-10-13 13:29:47 +02:00
if ( p_inside_resource & & ! p_root_node - > has_node ( node_path ) ) {
// Resources may have NodePaths to nodes that aren't on the scene, so skip them.
return false ;
}
2021-07-09 20:21:27 +02:00
if ( ! node_path . is_empty ( ) & & _update_node_path ( p_root_node , node_path , p_renames ) ) {
2021-06-30 20:50:40 +02:00
r_variant = node_path ;
2021-06-21 21:09:00 +02:00
return true ;
}
} break ;
case Variant : : ARRAY : {
2021-06-30 20:50:40 +02:00
Array a = r_variant ;
2021-06-21 21:09:00 +02:00
bool updated = false ;
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
Variant value = a [ i ] ;
2023-10-13 13:29:47 +02:00
if ( _check_node_path_recursive ( p_root_node , value , p_renames , p_inside_resource ) ) {
2021-06-21 21:09:00 +02:00
if ( ! updated ) {
a = a . duplicate ( ) ; // Need to duplicate for undo-redo to work.
updated = true ;
}
a [ i ] = value ;
}
}
if ( updated ) {
2021-06-30 20:50:40 +02:00
r_variant = a ;
2021-06-21 21:09:00 +02:00
return true ;
}
} break ;
case Variant : : DICTIONARY : {
2021-06-30 20:50:40 +02:00
Dictionary d = r_variant ;
2021-06-21 21:09:00 +02:00
bool updated = false ;
for ( int i = 0 ; i < d . size ( ) ; i + + ) {
Variant value = d . get_value_at_index ( i ) ;
2023-10-13 13:29:47 +02:00
if ( _check_node_path_recursive ( p_root_node , value , p_renames , p_inside_resource ) ) {
2021-06-21 21:09:00 +02:00
if ( ! updated ) {
d = d . duplicate ( ) ; // Need to duplicate for undo-redo to work.
updated = true ;
}
d [ d . get_key_at_index ( i ) ] = value ;
}
}
if ( updated ) {
2021-06-30 20:50:40 +02:00
r_variant = d ;
2021-06-21 21:09:00 +02:00
return true ;
}
} break ;
2023-06-30 17:41:10 +02:00
case Variant : : OBJECT : {
Resource * resource = Object : : cast_to < Resource > ( r_variant ) ;
if ( ! resource ) {
break ;
}
2023-10-25 12:21:01 +02:00
if ( Object : : cast_to < Animation > ( resource ) ) {
// Animation resources are handled by animation editor.
break ;
}
2023-11-29 12:31:48 +01:00
if ( ! resource - > is_built_in ( ) ) {
// For performance reasons, assume that scene paths are no concern for external resources.
break ;
}
2023-06-30 17:41:10 +02:00
List < PropertyInfo > properties ;
resource - > get_property_list ( & properties ) ;
for ( const PropertyInfo & E : properties ) {
if ( ! ( E . usage & ( PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR ) ) ) {
continue ;
}
String propertyname = E . name ;
Variant old_variant = resource - > get ( propertyname ) ;
Variant updated_variant = old_variant ;
2023-10-13 13:29:47 +02:00
if ( _check_node_path_recursive ( p_root_node , updated_variant , p_renames , true ) ) {
2023-06-30 17:41:10 +02:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > add_do_property ( resource , propertyname , updated_variant ) ;
undo_redo - > add_undo_property ( resource , propertyname , old_variant ) ;
}
}
2023-11-29 12:31:48 +01:00
} break ;
2023-06-30 17:41:10 +02:00
2021-06-21 21:09:00 +02:00
default : {
}
}
return false ;
}
2022-05-19 17:00:06 +02:00
void SceneTreeDock : : perform_node_renames ( Node * p_base , HashMap < Node * , NodePath > * p_renames , HashMap < Ref < Animation > , HashSet < int > > * r_rem_anims ) {
HashMap < Ref < Animation > , HashSet < int > > rem_anims ;
2020-05-14 16:41:43 +02:00
if ( ! r_rem_anims ) {
2014-02-10 02:10:30 +01:00
r_rem_anims = & rem_anims ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( ! p_base ) {
p_base = edited_scene ;
}
2020-05-14 16:41:43 +02:00
if ( ! p_base ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-07-09 20:21:27 +02:00
// No renaming if base node is deleted.
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > : : Iterator found_base_path = p_renames - > find ( p_base ) ;
if ( found_base_path & & found_base_path - > value . is_empty ( ) ) {
2021-07-09 20:21:27 +02:00
return ;
}
2022-03-06 21:39:19 +01:00
bool autorename_animation_tracks = bool ( EDITOR_GET ( " editors/animation/autorename_animation_tracks " ) ) ;
2018-03-23 10:44:39 +01:00
2023-11-01 05:11:10 +01:00
AnimationMixer * mixer = Object : : cast_to < AnimationMixer > ( p_base ) ;
if ( autorename_animation_tracks & & mixer ) {
// Don't rename if we're an AnimationTree pointing to an AnimationPlayer
bool points_to_other_animation_player = false ;
AnimationTree * at = Object : : cast_to < AnimationTree > ( mixer ) ;
if ( at ) {
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( at - > get_node_or_null ( at - > get_animation_player ( ) ) ) ;
if ( ap ) {
points_to_other_animation_player = true ;
}
}
2014-02-10 02:10:30 +01:00
2023-11-01 05:11:10 +01:00
if ( ! points_to_other_animation_player ) {
List < StringName > anims ;
mixer - > get_animation_list ( & anims ) ;
Node * root = mixer - > get_node ( mixer - > get_root_node ( ) ) ;
if ( root ) {
HashMap < Node * , NodePath > : : Iterator found_root_path = p_renames - > find ( root ) ;
NodePath new_root_path = found_root_path ? found_root_path - > value : root - > get_path ( ) ;
if ( ! new_root_path . is_empty ( ) ) { // No renaming if root node is deleted.
for ( const StringName & E : anims ) {
Ref < Animation > anim = mixer - > get_animation ( E ) ;
if ( ! r_rem_anims - > has ( anim ) ) {
r_rem_anims - > insert ( anim , HashSet < int > ( ) ) ;
HashSet < int > & ran = r_rem_anims - > find ( anim ) - > value ;
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
ran . insert ( i ) ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-11-01 05:11:10 +01:00
HashSet < int > & ran = r_rem_anims - > find ( anim ) - > value ;
2023-09-14 15:48:04 +02:00
2023-11-01 05:11:10 +01:00
if ( anim . is_null ( ) | | EditorNode : : get_singleton ( ) - > is_resource_read_only ( anim ) ) {
2014-02-10 02:10:30 +01:00
continue ;
}
2023-11-01 05:11:10 +01:00
int tracks_removed = 0 ;
2014-02-10 02:10:30 +01:00
2023-11-01 05:11:10 +01:00
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
if ( anim - > track_is_imported ( i ) ) {
continue ;
}
2021-07-09 20:21:27 +02:00
2023-11-01 05:11:10 +01:00
NodePath track_np = anim - > track_get_path ( i ) ;
2021-07-09 20:21:27 +02:00
2023-11-01 05:11:10 +01:00
Node * n = root - > get_node_or_null ( track_np ) ;
if ( ! n ) {
continue ;
}
2021-07-09 20:21:27 +02:00
2023-11-01 05:11:10 +01:00
if ( ! ran . has ( i ) ) {
continue ; //channel was removed
}
HashMap < Node * , NodePath > : : Iterator found_path = p_renames - > find ( n ) ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
if ( found_path ) {
if ( found_path - > value . is_empty ( ) ) {
//will be erased
int idx = i - tracks_removed ;
tracks_removed + + ;
undo_redo - > add_do_method ( anim . ptr ( ) , " remove_track " , idx ) ;
undo_redo - > add_undo_method ( anim . ptr ( ) , " add_track " , anim - > track_get_type ( i ) , idx ) ;
undo_redo - > add_undo_method ( anim . ptr ( ) , " track_set_path " , idx , track_np ) ;
undo_redo - > add_undo_method ( anim . ptr ( ) , " track_set_interpolation_type " , idx , anim - > track_get_interpolation_type ( i ) ) ;
for ( int j = 0 ; j < anim - > track_get_key_count ( i ) ; j + + ) {
undo_redo - > add_undo_method ( anim . ptr ( ) , " track_insert_key " , idx , anim - > track_get_key_time ( i , j ) , anim - > track_get_key_value ( i , j ) , anim - > track_get_key_transition ( i , j ) ) ;
}
ran . erase ( i ) ; //byebye channel
} else {
//will be renamed
NodePath rel_path = new_root_path . rel_path_to ( found_path - > value ) ;
NodePath new_path = NodePath ( rel_path . get_names ( ) , track_np . get_subnames ( ) , false ) ;
if ( new_path = = track_np ) {
continue ; //bleh
}
undo_redo - > add_do_method ( anim . ptr ( ) , " track_set_path " , i , new_path ) ;
undo_redo - > add_undo_method ( anim . ptr ( ) , " track_set_path " , i , track_np ) ;
2014-02-10 02:10:30 +01:00
}
}
}
}
}
}
}
}
2023-11-01 05:11:10 +01:00
// Renaming node paths used in node properties.
List < PropertyInfo > properties ;
p_base - > get_property_list ( & properties ) ;
for ( const PropertyInfo & E : properties ) {
if ( ! ( E . usage & ( PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR ) ) ) {
continue ;
}
String propertyname = E . name ;
Variant old_variant = p_base - > get ( propertyname ) ;
Variant updated_variant = old_variant ;
if ( _check_node_path_recursive ( p_base , updated_variant , p_renames ) ) {
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > add_do_property ( p_base , propertyname , updated_variant ) ;
undo_redo - > add_undo_property ( p_base , propertyname , old_variant ) ;
}
}
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < p_base - > get_child_count ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
perform_node_renames ( p_base - > get_child ( i ) , p_renames , r_rem_anims ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
void SceneTreeDock : : _node_prerenamed ( Node * p_node , const String & p_new_name ) {
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > path_renames ;
2014-02-10 02:10:30 +01:00
Vector < StringName > base_path ;
Node * n = p_node - > get_parent ( ) ;
while ( n ) {
base_path . push_back ( n - > get_name ( ) ) ;
n = n - > get_parent ( ) ;
}
2021-03-14 08:21:32 +01:00
base_path . reverse ( ) ;
2014-02-10 02:10:30 +01:00
Vector < StringName > new_base_path = base_path ;
base_path . push_back ( p_node - > get_name ( ) ) ;
new_base_path . push_back ( p_new_name ) ;
2021-07-09 20:21:27 +02:00
NodePath new_path ( new_base_path , true ) ;
path_renames [ p_node ] = new_path ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
_fill_path_renames ( base_path , new_base_path , p_node - > get_child ( i ) , & path_renames ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-04-02 01:20:12 +02:00
perform_node_renames ( nullptr , & path_renames ) ;
2014-02-10 02:10:30 +01:00
}
2014-09-03 04:13:40 +02:00
bool SceneTreeDock : : _validate_no_foreign ( ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
if ( E ! = edited_scene & & E - > get_owner ( ) ! = edited_scene ) {
2016-05-04 03:25:37 +02:00
accept - > set_text ( TTR ( " Can't operate on nodes from a foreign scene! " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2014-09-03 04:13:40 +02:00
return false ;
}
2015-10-10 14:09:09 +02:00
2024-04-11 16:29:18 +02:00
if ( edited_scene - > get_scene_inherited_state ( ) . is_valid ( ) ) {
// When edited_scene inherits from another one the root Node will be the parent Scene,
// we don't want to consider that Node a foreign one otherwise we would not be able to
// delete it.
if ( edited_scene = = E & & current_option ! = TOOL_REPLACE ) {
continue ;
}
2018-10-23 21:55:25 +02:00
2024-04-11 16:29:18 +02:00
if ( edited_scene = = E | | edited_scene - > get_scene_inherited_state ( ) - > find_node_by_path ( edited_scene - > get_path_to ( E ) ) > = 0 ) {
accept - > set_text ( TTR ( " Can't operate on nodes the current scene inherits from! " ) ) ;
accept - > popup_centered ( ) ;
return false ;
}
2015-10-10 14:09:09 +02:00
}
2014-09-03 04:13:40 +02:00
}
return true ;
}
2021-02-22 20:18:14 +01:00
bool SceneTreeDock : : _validate_no_instance ( ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
2021-12-09 10:42:46 +01:00
if ( E ! = edited_scene & & ! E - > get_scene_file_path ( ) . is_empty ( ) ) {
2021-06-18 00:03:09 +02:00
accept - > set_text ( TTR ( " This operation can't be done on instantiated scenes. " ) ) ;
2021-02-22 20:18:14 +01:00
accept - > popup_centered ( ) ;
return false ;
}
}
return true ;
}
2016-01-02 15:57:47 +01:00
void SceneTreeDock : : _node_reparent ( NodePath p_path , bool p_keep_global_xform ) {
2014-02-10 02:10:30 +01:00
Node * new_parent = scene_root - > get_node ( p_path ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( new_parent ) ;
2014-02-10 02:10:30 +01:00
2016-05-11 16:46:08 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-04-27 22:09:14 +02:00
List < Node * > full_selection = editor_selection - > get_full_selected_node_list ( ) ;
2016-05-11 16:46:08 +02:00
2020-12-15 13:04:21 +01:00
if ( selection . is_empty ( ) ) {
2019-09-15 02:07:55 +02:00
return ; // Nothing to reparent.
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
Vector < Node * > nodes ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
nodes . push_back ( E ) ;
2016-05-11 16:46:08 +02:00
}
_do_reparent ( new_parent , - 1 , nodes , p_keep_global_xform ) ;
2024-04-27 22:09:14 +02:00
for ( Node * E : full_selection ) {
editor_selection - > add_node ( E ) ;
}
2016-05-11 16:46:08 +02:00
}
void SceneTreeDock : : _do_reparent ( Node * p_new_parent , int p_position_in_parent , Vector < Node * > p_nodes , bool p_keep_global_xform ) {
2024-08-30 22:56:53 +02:00
ERR_FAIL_NULL ( p_new_parent ) ;
2016-05-11 16:46:08 +02:00
2020-05-14 16:41:43 +02:00
if ( p_nodes . size ( ) = = 0 ) {
2019-09-15 02:07:55 +02:00
return ; // Nothing to reparent.
2020-05-14 16:41:43 +02:00
}
2019-09-15 02:07:55 +02:00
2019-09-22 12:44:59 +02:00
p_nodes . sort_custom < Node : : Comparator > ( ) ; //Makes result reliable.
2023-08-26 16:00:36 +02:00
const int first_idx = p_position_in_parent = = - 1 ? p_new_parent - > get_child_count ( false ) : p_position_in_parent ;
int nodes_before = first_idx ;
2019-09-22 12:44:59 +02:00
bool no_change = true ;
2019-09-15 02:07:55 +02:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
2020-05-14 16:41:43 +02:00
if ( p_nodes [ ni ] = = p_new_parent ) {
2019-09-15 02:07:55 +02:00
return ; // Attempt to reparent to itself.
2020-05-14 16:41:43 +02:00
}
2023-06-29 00:46:11 +02:00
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG ( p_nodes [ ni ] - > get_internal_mode ( ) ! = INTERNAL_MODE_DISABLED , " Trying to move internal node, this is not supported. " ) ;
2019-09-15 02:07:55 +02:00
2023-08-26 16:00:36 +02:00
if ( p_nodes [ ni ] - > get_index ( false ) < first_idx ) {
nodes_before - - ;
}
if ( p_nodes [ ni ] - > get_parent ( ) ! = p_new_parent ) {
no_change = false ;
}
}
for ( int ni = 0 ; ni < p_nodes . size ( ) & & no_change ; ni + + ) {
if ( p_nodes [ ni ] - > get_index ( false ) ! = nodes_before + ni ) {
2019-09-22 12:44:59 +02:00
no_change = false ;
2020-05-14 16:41:43 +02:00
}
2019-09-15 02:07:55 +02:00
}
2020-05-14 16:41:43 +02:00
if ( no_change ) {
2019-09-22 12:44:59 +02:00
return ; // Position and parent didn't change.
2020-05-14 16:41:43 +02:00
}
2019-09-15 02:07:55 +02:00
2024-04-27 22:09:14 +02:00
// Prevent selecting the hovered node and keep the reparented node(s) selected instead.
hovered_but_reparenting = true ;
2024-08-30 22:56:53 +02:00
Node * validate = p_new_parent ;
2014-02-10 02:10:30 +01:00
while ( validate ) {
2022-02-01 19:19:13 +01:00
ERR_FAIL_COND_MSG ( p_nodes . has ( validate ) , " Selection changed at some point. Can't reparent. " ) ;
2014-02-10 02:10:30 +01:00
validate = validate - > get_parent ( ) ;
}
2019-09-15 02:07:55 +02:00
// Sort by tree order, so re-adding is easy.
2016-05-11 16:46:08 +02:00
p_nodes . sort_custom < Node : : Comparator > ( ) ;
2014-02-10 02:10:30 +01:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Reparent Node " ) , UndoRedo : : MERGE_DISABLE , p_nodes [ 0 ] ) ;
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > path_renames ;
2016-10-08 20:37:05 +02:00
Vector < StringName > former_names ;
2014-02-10 02:10:30 +01:00
2016-07-01 04:19:44 +02:00
int inc = 0 ;
2024-07-08 23:52:16 +02:00
bool need_edit = false ;
2016-07-01 04:19:44 +02:00
2016-05-11 16:46:08 +02:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
2019-09-15 02:07:55 +02:00
// No undo implemented for this yet.
2016-05-11 16:46:08 +02:00
Node * node = p_nodes [ ni ] ;
2014-02-10 02:10:30 +01:00
2024-08-30 22:56:53 +02:00
fill_path_renames ( node , p_new_parent , & path_renames ) ;
2016-10-08 20:37:05 +02:00
former_names . push_back ( node - > get_name ( ) ) ;
2014-02-10 02:10:30 +01:00
List < Node * > owned ;
node - > get_owned_by ( node - > get_owner ( ) , & owned ) ;
Array owners ;
2021-07-16 05:45:57 +02:00
for ( Node * E : owned ) {
owners . push_back ( E ) ;
2014-02-10 02:10:30 +01:00
}
2024-08-30 22:56:53 +02:00
bool same_parent = p_new_parent = = node - > get_parent ( ) ;
2023-06-29 00:46:11 +02:00
if ( same_parent & & node - > get_index ( false ) < p_position_in_parent + ni ) {
2019-09-15 02:07:55 +02:00
inc - - ; // If the child will generate a gap when moved, adjust.
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-07-08 23:52:16 +02:00
if ( same_parent ) {
// When node is reparented to the same parent, EditorSelection does not change.
// After hovering another node, the inspector has to be manually updated in this case.
need_edit = select_node_hovered_at_end_of_drag ;
} else {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( node - > get_parent ( ) , " remove_child " , node ) ;
2024-08-30 22:56:53 +02:00
undo_redo - > add_do_method ( p_new_parent , " add_child " , node , true ) ;
2022-11-06 20:19:00 +01:00
}
2015-08-02 17:29:37 +02:00
2023-06-19 08:14:54 +02:00
int new_position_in_parent = p_position_in_parent = = - 1 ? - 1 : p_position_in_parent + inc ;
if ( new_position_in_parent > = 0 | | same_parent ) {
2024-08-30 22:56:53 +02:00
undo_redo - > add_do_method ( p_new_parent , " move_child " , node , new_position_in_parent ) ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2018-03-23 10:44:39 +01:00
String old_name = former_names [ ni ] ;
2024-08-30 22:56:53 +02:00
String new_name = p_new_parent - > validate_child_name ( node ) ;
2018-03-23 10:44:39 +01:00
2019-09-15 02:07:55 +02:00
// Name was modified, fix the path renames.
2018-03-23 10:44:39 +01:00
if ( old_name . casecmp_to ( new_name ) ! = 0 ) {
2019-09-15 02:07:55 +02:00
// Fix the to name to have the new name.
2022-05-13 15:04:37 +02:00
HashMap < Node * , NodePath > : : Iterator found_path = path_renames . find ( node ) ;
2021-07-09 20:21:27 +02:00
if ( found_path ) {
2022-05-13 15:04:37 +02:00
NodePath old_new_name = found_path - > value ;
2018-03-23 10:44:39 +01:00
2021-07-09 20:21:27 +02:00
Vector < StringName > unfixed_new_names = old_new_name . get_names ( ) ;
Vector < StringName > fixed_new_names ;
2018-03-23 10:44:39 +01:00
2021-07-09 20:21:27 +02:00
// Get last name and replace with fixed new name.
for ( int a = 0 ; a < ( unfixed_new_names . size ( ) - 1 ) ; a + + ) {
fixed_new_names . push_back ( unfixed_new_names [ a ] ) ;
}
fixed_new_names . push_back ( new_name ) ;
2018-03-23 10:44:39 +01:00
2021-07-09 20:21:27 +02:00
NodePath fixed_node_path = NodePath ( fixed_new_names , true ) ;
path_renames [ node ] = fixed_node_path ;
} else {
ERR_PRINT ( " Internal error. Can't find renamed path for node ' " + node - > get_path ( ) + " ' " ) ;
}
2018-03-23 10:44:39 +01:00
}
2024-08-30 22:56:53 +02:00
// FIXME: Live editing for "Reparent to New Node" option is broken.
// We must get the path to `p_new_parent` *after* it was added to the scene.
if ( p_new_parent - > is_inside_tree ( ) ) {
undo_redo - > add_do_method ( ed , " live_debug_reparent_node " , edited_scene - > get_path_to ( node ) , edited_scene - > get_path_to ( p_new_parent ) , new_name , new_position_in_parent ) ;
undo_redo - > add_undo_method ( ed , " live_debug_reparent_node " , NodePath ( String ( edited_scene - > get_path_to ( p_new_parent ) ) . path_join ( new_name ) ) , edited_scene - > get_path_to ( node - > get_parent ( ) ) , node - > get_name ( ) , node - > get_index ( false ) ) ;
}
2015-08-02 17:29:37 +02:00
2016-01-02 15:57:47 +01:00
if ( p_keep_global_xform ) {
2020-05-14 16:41:43 +02:00
if ( Object : : cast_to < Node2D > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( node , " set_global_transform " , Object : : cast_to < Node2D > ( node ) - > get_global_transform ( ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( Object : : cast_to < Node3D > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( node , " set_global_transform " , Object : : cast_to < Node3D > ( node ) - > get_global_transform ( ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( Object : : cast_to < Control > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( node , " set_global_position " , Object : : cast_to < Control > ( node ) - > get_global_position ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2016-01-02 15:57:47 +01:00
}
2015-08-02 17:29:37 +02:00
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( this , " _set_owners " , edited_scene , owners ) ;
2014-02-10 02:10:30 +01:00
2021-02-04 09:20:26 +01:00
if ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) - > get_root ( ) = = node ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) , " set_root " , node ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-08-30 22:56:53 +02:00
undo_redo - > add_undo_method ( p_new_parent , " remove_child " , node ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( node , " set_name " , former_names [ ni ] ) ;
2014-02-10 02:10:30 +01:00
2016-07-01 04:19:44 +02:00
inc + + ;
2014-02-10 02:10:30 +01:00
}
2019-09-15 02:07:55 +02:00
// Add and move in a second step (so old order is preserved).
2016-05-11 16:46:08 +02:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
Node * node = p_nodes [ ni ] ;
2014-02-10 02:10:30 +01:00
List < Node * > owned ;
node - > get_owned_by ( node - > get_owner ( ) , & owned ) ;
Array owners ;
2021-07-16 05:45:57 +02:00
for ( Node * E : owned ) {
owners . push_back ( E ) ;
2014-02-10 02:10:30 +01:00
}
2023-06-29 00:46:11 +02:00
int child_pos = node - > get_index ( false ) ;
2024-08-30 22:56:53 +02:00
bool reparented_to_container = Object : : cast_to < Container > ( p_new_parent ) & & Object : : cast_to < Control > ( node ) ;
2014-02-10 02:10:30 +01:00
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( node - > get_parent ( ) , " add_child " , node , true ) ;
undo_redo - > add_undo_method ( node - > get_parent ( ) , " move_child " , node , child_pos ) ;
undo_redo - > add_undo_method ( this , " _set_owners " , edited_scene , owners ) ;
2021-02-04 09:20:26 +01:00
if ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) - > get_root ( ) = = node ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) , " set_root " , node ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2016-01-02 15:57:47 +01:00
if ( p_keep_global_xform ) {
2020-05-14 16:41:43 +02:00
if ( Object : : cast_to < Node2D > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( node , " set_transform " , Object : : cast_to < Node2D > ( node ) - > get_transform ( ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( Object : : cast_to < Node3D > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( node , " set_transform " , Object : : cast_to < Node3D > ( node ) - > get_transform ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2023-11-21 16:54:26 +01:00
if ( ! reparented_to_container & & Object : : cast_to < Control > ( node ) ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( node , " set_position " , Object : : cast_to < Control > ( node ) - > get_position ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2016-01-02 15:57:47 +01:00
}
2023-11-21 16:54:26 +01:00
if ( reparented_to_container ) {
undo_redo - > add_undo_method ( node , " _edit_set_state " , Object : : cast_to < Control > ( node ) - > _edit_get_state ( ) ) ;
}
2014-02-10 02:10:30 +01:00
}
2020-04-02 01:20:12 +02:00
perform_node_renames ( nullptr , & path_renames ) ;
2014-02-10 02:10:30 +01:00
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2024-07-08 23:52:16 +02:00
if ( need_edit ) {
EditorNode : : get_singleton ( ) - > edit_current ( ) ;
2024-07-23 09:54:15 +02:00
editor_selection - > clear ( ) ;
2024-07-08 23:52:16 +02:00
}
2014-02-10 02:10:30 +01:00
}
void SceneTreeDock : : _script_created ( Ref < Script > p_script ) {
2018-03-07 20:08:13 +01:00
List < Node * > selected = editor_selection - > get_selected_node_list ( ) ;
2020-12-15 13:04:21 +01:00
if ( selected . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-03-07 20:08:13 +01:00
2023-07-26 14:52:45 +02:00
if ( p_script - > is_built_in ( ) ) {
p_script - > set_path ( edited_scene - > get_scene_file_path ( ) + " :: " ) ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-12-17 23:04:03 +01:00
undo_redo - > create_action ( TTR ( " Attach Script " ) , UndoRedo : : MERGE_DISABLE , selected . front ( ) - > get ( ) ) ;
for ( Node * E : selected ) {
Ref < Script > existing = E - > get_script ( ) ;
undo_redo - > add_do_method ( InspectorDock : : get_singleton ( ) , " store_script_properties " , E ) ;
undo_redo - > add_undo_method ( InspectorDock : : get_singleton ( ) , " store_script_properties " , E ) ;
undo_redo - > add_do_method ( E , " set_script " , p_script ) ;
undo_redo - > add_undo_method ( E , " set_script " , existing ) ;
undo_redo - > add_do_method ( InspectorDock : : get_singleton ( ) , " apply_script_properties " , E ) ;
undo_redo - > add_undo_method ( InspectorDock : : get_singleton ( ) , " apply_script_properties " , E ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( this , " _update_script_button " ) ;
undo_redo - > add_undo_method ( this , " _update_script_button " ) ;
2018-03-07 20:08:13 +01:00
}
2022-12-17 23:04:03 +01:00
undo_redo - > commit_action ( ) ;
2018-03-07 20:08:13 +01:00
2023-09-10 11:16:09 +02:00
// Avoid changing the currently edited object.
Object * edited_object = InspectorDock : : get_inspector_singleton ( ) - > get_edited_object ( ) ;
2022-12-17 23:04:03 +01:00
_push_item ( p_script . ptr ( ) ) ;
2018-10-25 20:33:16 +02:00
_update_script_button ( ) ;
2023-09-10 11:16:09 +02:00
InspectorDock : : get_inspector_singleton ( ) - > edit ( edited_object ) ;
2014-02-10 02:10:30 +01:00
}
2021-06-04 11:24:08 +02:00
void SceneTreeDock : : _shader_created ( Ref < Shader > p_shader ) {
if ( selected_shader_material . is_null ( ) ) {
return ;
}
Ref < Shader > existing = selected_shader_material - > get_shader ( ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Set Shader " ) ) ;
undo_redo - > add_do_method ( selected_shader_material . ptr ( ) , " set_shader " , p_shader ) ;
undo_redo - > add_undo_method ( selected_shader_material . ptr ( ) , " set_shader " , existing ) ;
undo_redo - > commit_action ( ) ;
2021-06-04 11:24:08 +02:00
}
2019-06-30 05:19:45 +02:00
void SceneTreeDock : : _script_creation_closed ( ) {
2020-02-21 18:28:45 +01:00
script_create_dialog - > disconnect ( " script_created " , callable_mp ( this , & SceneTreeDock : : _script_created ) ) ;
2024-05-14 14:28:18 +02:00
script_create_dialog - > disconnect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _script_creation_closed ) ) ;
2023-01-21 12:25:29 +01:00
script_create_dialog - > disconnect ( " canceled " , callable_mp ( this , & SceneTreeDock : : _script_creation_closed ) ) ;
2019-06-30 05:19:45 +02:00
}
2021-06-04 11:24:08 +02:00
void SceneTreeDock : : _shader_creation_closed ( ) {
shader_create_dialog - > disconnect ( " shader_created " , callable_mp ( this , & SceneTreeDock : : _shader_created ) ) ;
2024-05-14 14:28:18 +02:00
shader_create_dialog - > disconnect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _shader_creation_closed ) ) ;
2023-01-21 12:25:29 +01:00
shader_create_dialog - > disconnect ( " canceled " , callable_mp ( this , & SceneTreeDock : : _shader_creation_closed ) ) ;
2021-06-04 11:24:08 +02:00
}
2019-05-14 02:11:06 +02:00
void SceneTreeDock : : _toggle_editable_children_from_selection ( ) {
2018-09-13 00:49:12 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
List < Node * > : : Element * e = selection . front ( ) ;
2019-05-14 02:11:06 +02:00
if ( e ) {
_toggle_editable_children ( e - > get ( ) ) ;
}
}
2018-09-13 00:49:12 +02:00
2019-09-04 21:02:26 +02:00
void SceneTreeDock : : _toggle_placeholder_from_selection ( ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
_toggle_editable_children ( node ) ;
bool placeholder = node - > get_scene_instance_load_placeholder ( ) ;
placeholder = ! placeholder ;
node - > set_scene_instance_load_placeholder ( placeholder ) ;
scene_tree - > update_tree ( ) ;
}
}
}
2022-05-12 17:36:37 +02:00
void SceneTreeDock : : _reparent_nodes_to_root ( Node * p_root , const Array & p_nodes , Node * p_owner ) {
List < Node * > nodes ;
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
Node * node = Object : : cast_to < Node > ( p_nodes [ i ] ) ;
ERR_FAIL_NULL ( node ) ;
nodes . push_back ( node ) ;
}
for ( Node * node : nodes ) {
node - > set_owner ( p_owner ) ;
List < Node * > owned ;
node - > get_owned_by ( p_owner , & owned ) ;
String original_name = node - > get_name ( ) ;
node - > reparent ( p_root ) ;
node - > set_name ( original_name ) ;
for ( Node * F : owned ) {
F - > set_owner ( p_owner ) ;
}
}
}
void SceneTreeDock : : _reparent_nodes_to_paths_with_transform_and_name ( Node * p_root , const Array & p_nodes , const Array & p_paths , const Array & p_transforms , const Array & p_names , Node * p_owner ) {
ERR_FAIL_COND ( p_nodes . size ( ) ! = p_paths . size ( ) ) ;
ERR_FAIL_COND ( p_nodes . size ( ) ! = p_transforms . size ( ) ) ;
ERR_FAIL_COND ( p_nodes . size ( ) ! = p_names . size ( ) ) ;
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
Node * node = Object : : cast_to < Node > ( p_nodes [ i ] ) ;
ERR_FAIL_NULL ( node ) ;
const NodePath & np = p_paths [ i ] ;
Node * parent_node = p_root - > get_node_or_null ( np ) ;
ERR_FAIL_NULL ( parent_node ) ;
List < Node * > owned ;
node - > get_owned_by ( p_owner , & owned ) ;
node - > reparent ( parent_node ) ;
node - > set_name ( p_names [ i ] ) ;
Node3D * node_3d = Object : : cast_to < Node3D > ( node ) ;
if ( node_3d ) {
node_3d - > set_transform ( p_transforms [ i ] ) ;
} else {
Node2D * node_2d = Object : : cast_to < Node2D > ( node ) ;
if ( node_2d ) {
node_2d - > set_transform ( p_transforms [ i ] ) ;
}
2020-05-14 16:41:43 +02:00
}
2018-09-13 00:49:12 +02:00
2022-05-12 17:36:37 +02:00
for ( Node * F : owned ) {
F - > set_owner ( p_owner ) ;
}
}
}
void SceneTreeDock : : _toggle_editable_children ( Node * p_node ) {
if ( ! p_node ) {
return ;
}
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Toggle Editable Children " ) ) ;
bool editable = ! EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( p_node ) ;
undo_redo - > add_undo_method ( EditorNode : : get_singleton ( ) - > get_edited_scene ( ) , " set_editable_instance " , p_node , ! editable ) ;
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) - > get_edited_scene ( ) , " set_editable_instance " , p_node , editable ) ;
if ( editable ) {
bool original_scene_instance_load_placeholder = p_node - > get_scene_instance_load_placeholder ( ) ;
undo_redo - > add_undo_method ( p_node , " set_scene_instance_load_placeholder " , original_scene_instance_load_placeholder ) ;
undo_redo - > add_do_method ( p_node , " set_scene_instance_load_placeholder " , false ) ;
} else {
List < Node * > owned ;
p_node - > get_owned_by ( edited_scene , & owned ) ;
// Get the original paths, transforms, and names for undo.
Array owned_nodes_array ;
Array paths_array ;
Array transform_array ;
Array name_array ;
for ( Node * owned_node : owned ) {
if ( owned_node ! = p_node & & owned_node ! = edited_scene & & owned_node - > get_owner ( ) = = edited_scene & & owned_node - > get_parent ( ) - > get_owner ( ) ! = edited_scene ) {
owned_nodes_array . push_back ( owned_node ) ;
paths_array . push_back ( p_node - > get_path_to ( owned_node - > get_parent ( ) ) ) ;
name_array . push_back ( owned_node - > get_name ( ) ) ;
Node3D * node_3d = Object : : cast_to < Node3D > ( owned_node ) ;
if ( node_3d ) {
transform_array . push_back ( node_3d - > get_transform ( ) ) ;
} else {
Node2D * node_2d = Object : : cast_to < Node2D > ( owned_node ) ;
if ( node_2d ) {
transform_array . push_back ( node_2d - > get_transform ( ) ) ;
} else {
transform_array . push_back ( Variant ( ) ) ;
}
}
}
}
2018-09-13 00:49:12 +02:00
2022-05-12 17:36:37 +02:00
if ( ! owned_nodes_array . is_empty ( ) ) {
undo_redo - > add_undo_method ( this , " _reparent_nodes_to_paths_with_transform_and_name " , p_node , owned_nodes_array , paths_array , transform_array , name_array , edited_scene ) ;
undo_redo - > add_do_method ( this , " _reparent_nodes_to_root " , p_node , owned_nodes_array , edited_scene ) ;
}
2018-09-13 00:49:12 +02:00
}
2022-05-12 17:36:37 +02:00
undo_redo - > add_undo_method ( Node3DEditor : : get_singleton ( ) , " update_all_gizmos " , p_node ) ;
undo_redo - > add_do_method ( Node3DEditor : : get_singleton ( ) , " update_all_gizmos " , p_node ) ;
undo_redo - > add_undo_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_do_method ( scene_tree , " update_tree " ) ;
undo_redo - > commit_action ( ) ;
2018-09-13 00:49:12 +02:00
}
2020-01-07 17:43:21 +01:00
void SceneTreeDock : : _delete_confirm ( bool p_cut ) {
2014-02-10 02:10:30 +01:00
List < Node * > remove_list = editor_selection - > get_selected_node_list ( ) ;
2020-12-15 13:04:21 +01:00
if ( remove_list . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
bool entire_scene = false ;
2022-04-05 12:40:26 +02:00
for ( const Node * E : remove_list ) {
2021-07-16 05:45:57 +02:00
if ( E = = edited_scene ) {
2014-02-10 02:10:30 +01:00
entire_scene = true ;
2022-09-08 22:57:54 +02:00
break ;
2014-02-10 02:10:30 +01:00
}
}
2024-08-28 19:06:31 +02:00
if ( ! entire_scene ) {
for ( const Node * E : remove_list ) {
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG ( E - > get_internal_mode ( ) ! = INTERNAL_MODE_DISABLED , " Trying to remove internal node, this is not supported. " ) ;
}
}
2022-02-27 03:15:01 +01:00
EditorNode : : get_singleton ( ) - > hide_unused_editors ( this ) ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( p_cut ? TTR ( " Cut Node(s) " ) : TTR ( " Remove Node(s) " ) , UndoRedo : : MERGE_DISABLE , remove_list . front ( ) - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
if ( entire_scene ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , ( Object * ) nullptr ) ;
undo_redo - > add_undo_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , edited_scene ) ;
undo_redo - > add_undo_method ( edited_scene , " set_owner " , edited_scene - > get_owner ( ) ) ;
undo_redo - > add_undo_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_undo_reference ( edited_scene ) ;
2014-02-10 02:10:30 +01:00
} else {
2022-02-27 03:15:01 +01:00
if ( delete_tracks_checkbox - > is_pressed ( ) | | p_cut ) {
remove_list . sort_custom < Node : : Comparator > ( ) ; // Sort nodes to keep positions.
HashMap < Node * , NodePath > path_renames ;
2014-02-10 02:10:30 +01:00
2022-02-27 03:15:01 +01:00
//delete from animation
for ( Node * n : remove_list ) {
if ( ! n - > is_inside_tree ( ) | | ! n - > get_parent ( ) ) {
continue ;
}
fill_path_renames ( n , nullptr , & path_renames ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-02-27 03:15:01 +01:00
perform_node_renames ( nullptr , & path_renames ) ;
2014-02-10 02:10:30 +01:00
}
//delete for read
2021-07-16 05:45:57 +02:00
for ( Node * n : remove_list ) {
2020-05-14 16:41:43 +02:00
if ( ! n - > is_inside_tree ( ) | | ! n - > get_parent ( ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
List < Node * > owned ;
n - > get_owned_by ( n - > get_owner ( ) , & owned ) ;
Array owners ;
2021-07-16 05:45:57 +02:00
for ( Node * F : owned ) {
owners . push_back ( F ) ;
2014-02-10 02:10:30 +01:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( n - > get_parent ( ) , " remove_child " , n ) ;
undo_redo - > add_undo_method ( n - > get_parent ( ) , " add_child " , n , true ) ;
2023-06-29 00:46:11 +02:00
undo_redo - > add_undo_method ( n - > get_parent ( ) , " move_child " , n , n - > get_index ( false ) ) ;
2021-02-04 09:20:26 +01:00
if ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) - > get_root ( ) = = n ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( AnimationPlayerEditor : : get_singleton ( ) - > get_track_editor ( ) , " set_root " , n ) ;
2020-05-14 16:41:43 +02:00
}
2022-11-24 18:28:49 +01:00
undo_redo - > add_undo_method ( this , " _set_owners " , edited_scene , owners ) ;
undo_redo - > add_undo_reference ( n ) ;
2015-08-02 17:29:37 +02:00
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( ed , " live_debug_remove_and_keep_node " , edited_scene - > get_path_to ( n ) , n - > get_instance_id ( ) ) ;
2023-06-29 00:46:11 +02:00
undo_redo - > add_undo_method ( ed , " live_debug_restore_node " , n - > get_instance_id ( ) , edited_scene - > get_path_to ( n - > get_parent ( ) ) , n - > get_index ( false ) ) ;
2014-02-10 02:10:30 +01:00
}
}
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2017-11-08 03:10:31 +01:00
// hack, force 2d editor viewport to refresh after deletion
2020-05-14 16:41:43 +02:00
if ( CanvasItemEditor * editor = CanvasItemEditor : : get_singleton ( ) ) {
2022-08-13 23:21:24 +02:00
editor - > get_viewport_control ( ) - > queue_redraw ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-08 03:10:31 +01:00
2021-12-09 18:50:57 +01:00
_push_item ( nullptr ) ;
2018-01-08 06:50:51 +01:00
2022-03-30 20:12:26 +02:00
// Fixes the EditorSelectionHistory from still offering deleted notes
EditorSelectionHistory * editor_history = EditorNode : : get_singleton ( ) - > get_editor_selection_history ( ) ;
2018-01-08 06:50:51 +01:00
editor_history - > cleanup_history ( ) ;
2021-11-17 21:08:55 +01:00
InspectorDock : : get_singleton ( ) - > call ( " _prepare_history " ) ;
2024-06-09 09:51:41 +02:00
InspectorDock : : get_singleton ( ) - > update ( nullptr ) ;
2024-06-13 02:51:51 +02:00
NodeDock : : get_singleton ( ) - > set_node ( nullptr ) ;
2016-05-17 23:27:15 +02:00
}
2015-08-25 05:08:45 +02:00
2018-01-11 21:58:17 +01:00
void SceneTreeDock : : _update_script_button ( ) {
2019-04-09 00:18:03 +02:00
if ( ! profile_allow_script_editing ) {
button_create_script - > hide ( ) ;
2020-05-09 18:59:19 +02:00
button_detach_script - > hide ( ) ;
2021-08-28 01:55:06 +02:00
} else if ( editor_selection - > get_selection ( ) . size ( ) = = 0 ) {
2019-01-02 11:40:23 +01:00
button_create_script - > hide ( ) ;
2020-05-09 18:59:19 +02:00
button_detach_script - > hide ( ) ;
2021-08-28 01:55:06 +02:00
} else if ( editor_selection - > get_selection ( ) . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
Node * n = editor_selection - > get_selected_node_list ( ) . front ( ) - > get ( ) ;
2018-10-19 16:04:07 +02:00
if ( n - > get_script ( ) . is_null ( ) ) {
2018-10-25 20:33:16 +02:00
button_create_script - > show ( ) ;
2020-05-09 18:59:19 +02:00
button_detach_script - > hide ( ) ;
2018-10-19 16:04:07 +02:00
} else {
2018-10-25 20:33:16 +02:00
button_create_script - > hide ( ) ;
2020-05-09 18:59:19 +02:00
button_detach_script - > show ( ) ;
2018-10-19 16:04:07 +02:00
}
2016-08-08 00:22:33 +02:00
} else {
2019-03-06 05:19:34 +01:00
button_create_script - > hide ( ) ;
2019-03-06 07:11:02 +01:00
Array selection = editor_selection - > get_selected_nodes ( ) ;
for ( int i = 0 ; i < selection . size ( ) ; i + + ) {
Node * n = Object : : cast_to < Node > ( selection [ i ] ) ;
2019-01-02 11:40:23 +01:00
if ( ! n - > get_script ( ) . is_null ( ) ) {
2020-05-09 18:59:19 +02:00
button_detach_script - > show ( ) ;
2019-01-02 11:40:23 +01:00
return ;
}
}
2020-05-09 18:59:19 +02:00
button_detach_script - > hide ( ) ;
2016-08-08 00:22:33 +02:00
}
2015-08-25 05:08:45 +02:00
}
2018-01-11 21:58:17 +01:00
void SceneTreeDock : : _selection_changed ( ) {
2021-08-28 01:55:06 +02:00
int selection_size = editor_selection - > get_selection ( ) . size ( ) ;
2018-01-11 21:58:17 +01:00
if ( selection_size > 1 ) {
//automatically turn on multi-edit
_tool_selected ( TOOL_MULTI_EDIT ) ;
2021-08-28 01:55:06 +02:00
} else if ( selection_size = = 1 ) {
2022-05-18 19:19:38 +02:00
_handle_select ( editor_selection - > get_selection ( ) . begin ( ) - > key ) ;
2019-10-18 20:00:09 +02:00
} else if ( selection_size = = 0 ) {
2021-12-09 18:50:57 +01:00
_push_item ( nullptr ) ;
2018-01-11 21:58:17 +01:00
}
2019-10-18 20:00:09 +02:00
2018-01-11 21:58:17 +01:00
_update_script_button ( ) ;
}
2024-08-30 22:56:53 +02:00
Node * SceneTreeDock : : _do_create ( Node * p_parent ) {
2022-11-16 00:13:39 +01:00
Variant c = create_dialog - > instantiate_selected ( ) ;
2018-09-12 20:47:12 +02:00
Node * child = Object : : cast_to < Node > ( c ) ;
2024-08-30 22:56:53 +02:00
ERR_FAIL_NULL_V ( child , nullptr ) ;
2018-09-12 20:47:12 +02:00
2022-10-10 22:30:34 +02:00
String new_name = p_parent - > validate_child_name ( child ) ;
2023-01-12 09:41:13 +01:00
if ( GLOBAL_GET ( " editor/naming/node_name_casing " ) . operator int ( ) ! = NAME_CASING_PASCAL_CASE ) {
2022-10-10 22:30:34 +02:00
new_name = adjust_name_casing ( new_name ) ;
}
child - > set_name ( new_name ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action_for_history ( TTR ( " Create Node " ) , editor_data - > get_current_edited_scene_history_id ( ) ) ;
2018-09-12 20:47:12 +02:00
if ( edited_scene ) {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( p_parent , " add_child " , child , true ) ;
undo_redo - > add_do_method ( child , " set_owner " , edited_scene ) ;
undo_redo - > add_do_reference ( child ) ;
undo_redo - > add_undo_method ( p_parent , " remove_child " , child ) ;
2018-09-12 20:47:12 +02:00
2020-02-07 02:52:05 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( ed , " live_debug_create_node " , edited_scene - > get_path_to ( p_parent ) , child - > get_class ( ) , new_name ) ;
undo_redo - > add_undo_method ( ed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( p_parent ) ) . path_join ( new_name ) ) ) ;
2018-09-12 20:47:12 +02:00
} else {
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , child ) ;
undo_redo - > add_do_method ( scene_tree , " update_tree " ) ;
undo_redo - > add_do_reference ( child ) ;
undo_redo - > add_undo_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , ( Object * ) nullptr ) ;
2018-09-12 20:47:12 +02:00
}
2024-08-30 22:56:53 +02:00
undo_redo - > add_do_method ( this , " _post_do_create " , child ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > commit_action ( ) ;
2024-08-30 22:56:53 +02:00
return child ;
}
void SceneTreeDock : : _post_do_create ( Node * p_child ) {
2018-09-12 20:47:12 +02:00
editor_selection - > clear ( ) ;
2024-08-30 22:56:53 +02:00
editor_selection - > add_node ( p_child ) ;
_push_item ( p_child ) ;
2018-09-12 20:47:12 +02:00
2024-08-30 22:56:53 +02:00
// Make editor more comfortable, so some controls don't appear super shrunk.
Control * control = Object : : cast_to < Control > ( p_child ) ;
if ( control ) {
Size2 ms = control - > get_minimum_size ( ) ;
2020-05-14 16:41:43 +02:00
if ( ms . width < 4 ) {
2018-09-12 20:47:12 +02:00
ms . width = 40 ;
2020-05-14 16:41:43 +02:00
}
if ( ms . height < 4 ) {
2018-09-12 20:47:12 +02:00
ms . height = 40 ;
2020-05-14 16:41:43 +02:00
}
2024-08-30 22:56:53 +02:00
if ( control - > is_layout_rtl ( ) ) {
control - > set_position ( control - > get_position ( ) - Vector2 ( ms . x , 0 ) ) ;
2020-09-03 13:22:16 +02:00
}
2024-08-30 22:56:53 +02:00
control - > set_size ( ms ) ;
2018-09-12 20:47:12 +02:00
}
2020-08-25 01:32:58 +02:00
2024-08-30 22:56:53 +02:00
emit_signal ( SNAME ( " node_created " ) , p_child ) ;
2018-09-12 20:47:12 +02:00
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _create ( ) {
if ( current_option = = TOOL_NEW ) {
2020-04-02 01:20:12 +02:00
Node * parent = nullptr ;
2014-02-10 02:10:30 +01:00
if ( edited_scene ) {
2015-03-31 20:26:38 +02:00
// If root exists in edited scene
2014-02-10 02:10:30 +01:00
parent = scene_tree - > get_selected ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! parent ) {
2015-03-31 20:26:38 +02:00
parent = edited_scene ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2015-03-31 20:26:38 +02:00
} else {
// If no root exist in edited scene
2014-02-10 02:10:30 +01:00
parent = scene_root ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( parent ) ;
2014-02-10 02:10:30 +01:00
}
2018-09-12 20:47:12 +02:00
_do_create ( parent ) ;
2014-02-10 02:10:30 +01:00
} else if ( current_option = = TOOL_REPLACE ) {
2017-12-15 04:01:25 +01:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND ( selection . is_empty ( ) ) ;
2019-08-09 16:31:31 +02:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * ur = EditorUndoRedoManager : : get_singleton ( ) ;
2022-03-25 18:06:46 +01:00
ur - > create_action ( TTR ( " Change type of node(s) " ) , UndoRedo : : MERGE_DISABLE , selection . front ( ) - > get ( ) ) ;
2019-08-09 16:31:31 +02:00
2021-07-16 05:45:57 +02:00
for ( Node * n : selection ) {
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( n ) ;
2014-02-10 02:10:30 +01:00
2022-11-16 00:13:39 +01:00
Variant c = create_dialog - > instantiate_selected ( ) ;
2014-02-10 02:10:30 +01:00
2017-12-15 04:01:25 +01:00
ERR_FAIL_COND ( ! c ) ;
2023-06-16 02:33:33 +02:00
Node * new_node = Object : : cast_to < Node > ( c ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( new_node ) ;
2023-06-16 02:33:33 +02:00
replace_node ( n , new_node ) ;
2018-02-21 13:38:21 +01:00
}
2019-08-09 16:31:31 +02:00
2023-06-16 02:33:33 +02:00
ur - > commit_action ( false ) ;
2018-09-12 20:47:12 +02:00
} else if ( current_option = = TOOL_REPARENT_TO_NEW_NODE ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-01-19 13:21:39 +01:00
ERR_FAIL_COND ( selection . is_empty ( ) ) ;
2018-09-12 20:47:12 +02:00
// Find top level node in selection
bool only_one_top_node = true ;
Node * first = selection . front ( ) - > get ( ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( first ) ;
2018-09-12 20:47:12 +02:00
int smaller_path_to_top = first - > get_path_to ( scene_root ) . get_name_count ( ) ;
Node * top_node = first ;
2023-11-17 02:58:23 +01:00
bool center_parent = EDITOR_GET ( " docks/scene_tree/center_node_on_reparent " ) ;
Vector < Node * > top_level_nodes ;
2018-09-12 20:47:12 +02:00
for ( List < Node * > : : Element * E = selection . front ( ) - > next ( ) ; E ; E = E - > next ( ) ) {
Node * n = E - > get ( ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( n ) ;
2018-09-12 20:47:12 +02:00
int path_length = n - > get_path_to ( scene_root ) . get_name_count ( ) ;
if ( top_node ! = n ) {
if ( smaller_path_to_top > path_length ) {
top_node = n ;
smaller_path_to_top = path_length ;
only_one_top_node = true ;
2023-11-17 02:58:23 +01:00
if ( center_parent ) {
top_level_nodes . clear ( ) ;
top_level_nodes . append ( n ) ;
}
2018-09-12 20:47:12 +02:00
} else if ( smaller_path_to_top = = path_length ) {
2020-05-14 16:41:43 +02:00
if ( only_one_top_node & & top_node - > get_parent ( ) ! = n - > get_parent ( ) ) {
2018-09-12 20:47:12 +02:00
only_one_top_node = false ;
2020-05-14 16:41:43 +02:00
}
2023-11-17 02:58:23 +01:00
if ( center_parent ) {
top_level_nodes . append ( n ) ;
}
2018-09-12 20:47:12 +02:00
}
}
}
2020-04-02 01:20:12 +02:00
Node * parent = nullptr ;
2024-08-30 22:56:53 +02:00
int original_position = - 1 ;
2020-05-14 16:41:43 +02:00
if ( only_one_top_node ) {
2018-09-12 20:47:12 +02:00
parent = top_node - > get_parent ( ) ;
2024-09-06 13:13:40 +02:00
original_position = top_node - > get_index ( false ) ;
2020-05-14 16:41:43 +02:00
} else {
2018-09-12 20:47:12 +02:00
parent = top_node - > get_parent ( ) - > get_parent ( ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-12 20:47:12 +02:00
2024-08-30 22:56:53 +02:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action_for_history ( TTR ( " Reparent to New Node " ) , editor_data - > get_current_edited_scene_history_id ( ) ) ;
Node * last_created = _do_create ( parent ) ;
2018-09-12 20:47:12 +02:00
Vector < Node * > nodes ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
nodes . push_back ( E ) ;
2018-09-12 20:47:12 +02:00
}
2023-11-17 02:58:23 +01:00
if ( center_parent ) {
// Find parent type and only average positions of relevant nodes.
Node3D * parent_node_3d = Object : : cast_to < Node3D > ( last_created ) ;
if ( parent_node_3d ) {
Vector3 position ;
uint32_t node_count = 0 ;
for ( const Node * node : nodes ) {
const Node3D * node_3d = Object : : cast_to < Node3D > ( node ) ;
if ( node_3d ) {
position + = node_3d - > get_global_position ( ) ;
node_count + + ;
}
}
if ( node_count > 0 ) {
parent_node_3d - > set_global_position ( position / node_count ) ;
}
}
Node2D * parent_node_2d = Object : : cast_to < Node2D > ( last_created ) ;
if ( parent_node_2d ) {
Vector2 position ;
uint32_t node_count = 0 ;
for ( const Node * node : nodes ) {
const Node2D * node_2d = Object : : cast_to < Node2D > ( node ) ;
if ( node_2d ) {
position + = node_2d - > get_global_position ( ) ;
node_count + + ;
}
}
if ( node_count > 0 ) {
parent_node_2d - > set_global_position ( position / ( real_t ) node_count ) ;
}
}
}
2018-09-12 20:47:12 +02:00
_do_reparent ( last_created , - 1 , nodes , true ) ;
2024-08-30 22:56:53 +02:00
if ( only_one_top_node ) {
undo_redo - > add_do_method ( parent , " move_child " , last_created , original_position ) ;
}
undo_redo - > commit_action ( ) ;
2018-02-21 13:38:21 +01:00
}
2019-04-10 17:01:42 +02:00
2021-06-11 20:37:32 +02:00
scene_tree - > get_scene_tree ( ) - > grab_focus ( ) ;
2018-02-21 13:38:21 +01:00
}
2014-02-10 02:10:30 +01:00
2023-06-16 02:33:33 +02:00
void SceneTreeDock : : replace_node ( Node * p_node , Node * p_by_node ) {
EditorUndoRedoManager * ur = EditorUndoRedoManager : : get_singleton ( ) ;
ur - > create_action ( TTR ( " Change type of node(s) " ) , UndoRedo : : MERGE_DISABLE , p_node ) ;
ur - > add_do_method ( this , " replace_node " , p_node , p_by_node , true , false ) ;
ur - > add_do_reference ( p_by_node ) ;
_replace_node ( p_node , p_by_node , true , false ) ;
ur - > add_undo_method ( this , " replace_node " , p_by_node , p_node , false , false ) ;
ur - > add_undo_reference ( p_node ) ;
perform_node_replace ( nullptr , p_node , p_by_node ) ;
ur - > commit_action ( false ) ;
}
void SceneTreeDock : : _replace_node ( Node * p_node , Node * p_by_node , bool p_keep_properties , bool p_remove_old ) {
ERR_FAIL_COND_MSG ( ! p_node - > is_inside_tree ( ) , " _replace_node() can't be called on a node outside of tree. You might have called it twice. " ) ;
2024-05-09 14:19:16 +02:00
Node * oldnode = p_node ;
2018-02-21 13:38:21 +01:00
Node * newnode = p_by_node ;
2014-02-10 02:10:30 +01:00
2019-01-14 17:41:54 +01:00
if ( p_keep_properties ) {
2024-05-09 14:19:16 +02:00
Node * default_oldnode = Object : : cast_to < Node > ( ClassDB : : instantiate ( oldnode - > get_class ( ) ) ) ;
2019-01-14 17:41:54 +01:00
List < PropertyInfo > pinfo ;
2024-05-09 14:19:16 +02:00
oldnode - > get_property_list ( & pinfo ) ;
2019-01-14 17:41:54 +01:00
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : pinfo ) {
2021-07-16 05:45:57 +02:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2019-01-14 17:41:54 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2020-05-18 16:38:48 +02:00
2024-05-09 14:19:16 +02:00
bool valid ;
const Variant & default_val = default_oldnode - > get ( E . name , & valid ) ;
if ( ! valid | | default_val ! = oldnode - > get ( E . name ) ) {
newnode - > set ( E . name , oldnode - > get ( E . name ) ) ;
2019-01-14 17:41:54 +01:00
}
2018-03-09 19:05:04 +01:00
}
2019-01-14 17:41:54 +01:00
memdelete ( default_oldnode ) ;
2018-02-21 13:38:21 +01:00
}
2014-02-10 02:10:30 +01:00
2021-12-09 18:50:57 +01:00
_push_item ( nullptr ) ;
2014-02-10 02:10:30 +01:00
2018-02-21 13:38:21 +01:00
//reconnect signals
List < MethodInfo > sl ;
2014-02-10 02:10:30 +01:00
2024-05-09 14:19:16 +02:00
oldnode - > get_signal_list ( & sl ) ;
2021-07-24 15:46:25 +02:00
for ( const MethodInfo & E : sl ) {
2018-02-21 13:38:21 +01:00
List < Object : : Connection > cl ;
2024-05-09 14:19:16 +02:00
oldnode - > get_signal_connection_list ( E . name , & cl ) ;
2016-06-21 03:57:07 +02:00
2021-07-24 15:46:25 +02:00
for ( const Object : : Connection & c : cl ) {
2020-05-14 16:41:43 +02:00
if ( ! ( c . flags & Object : : CONNECT_PERSIST ) ) {
2018-02-21 13:38:21 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-07-28 22:56:41 +02:00
newnode - > connect ( c . signal . get_name ( ) , c . callable , Object : : CONNECT_PERSIST ) ;
2018-02-21 13:38:21 +01:00
}
}
2014-02-10 02:10:30 +01:00
2024-05-10 18:50:17 +02:00
// HACK: Remember size of anchored control.
Control * old_control = Object : : cast_to < Control > ( oldnode ) ;
Size2 size ;
if ( old_control ) {
size = old_control - > get_size ( ) ;
}
2024-05-09 14:19:16 +02:00
String newname = oldnode - > get_name ( ) ;
2015-09-07 15:13:29 +02:00
2018-02-21 13:38:21 +01:00
List < Node * > to_erase ;
2024-05-09 14:19:16 +02:00
for ( int i = 0 ; i < oldnode - > get_child_count ( ) ; i + + ) {
if ( oldnode - > get_child ( i ) - > get_owner ( ) = = nullptr & & oldnode - > is_owned_by_parent ( ) ) {
to_erase . push_back ( oldnode - > get_child ( i ) ) ;
2018-02-21 13:38:21 +01:00
}
}
2024-06-04 16:03:11 +02:00
if ( oldnode = = edited_scene ) {
EditorNode : : get_singleton ( ) - > set_edited_scene_root ( newnode , false ) ;
}
2024-05-09 14:19:16 +02:00
oldnode - > replace_by ( newnode , true ) ;
2014-02-10 02:10:30 +01:00
2024-05-10 18:50:17 +02:00
// Re-apply size of anchored control.
Control * new_control = Object : : cast_to < Control > ( newnode ) ;
if ( old_control & & new_control ) {
new_control - > set_size ( size ) ;
}
2018-02-21 13:38:21 +01:00
//small hack to make collisionshapes and other kind of nodes to work
for ( int i = 0 ; i < newnode - > get_child_count ( ) ; i + + ) {
Node * c = newnode - > get_child ( i ) ;
c - > call ( " set_transform " , c - > call ( " get_transform " ) ) ;
}
2019-04-23 21:10:44 +02:00
//p_remove_old was added to support undo
2020-05-14 16:41:43 +02:00
if ( p_remove_old ) {
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager : : get_singleton ( ) - > clear_history ( ) ;
2020-05-14 16:41:43 +02:00
}
2018-02-21 13:38:21 +01:00
newnode - > set_name ( newname ) ;
2021-12-09 18:50:57 +01:00
_push_item ( newnode ) ;
2018-02-21 13:38:21 +01:00
2019-04-23 21:10:44 +02:00
if ( p_remove_old ) {
2024-05-09 14:19:16 +02:00
memdelete ( oldnode ) ;
2018-02-21 13:38:21 +01:00
2019-04-23 21:10:44 +02:00
while ( to_erase . front ( ) ) {
memdelete ( to_erase . front ( ) - > get ( ) ) ;
to_erase . pop_front ( ) ;
}
2014-02-10 02:10:30 +01:00
}
}
2023-06-16 02:33:33 +02:00
void SceneTreeDock : : perform_node_replace ( Node * p_base , Node * p_node , Node * p_by_node ) {
if ( ! p_base ) {
p_base = edited_scene ;
}
if ( ! p_base ) {
return ;
}
// Renaming node used in node properties.
List < PropertyInfo > properties ;
p_base - > get_property_list ( & properties ) ;
for ( const PropertyInfo & E : properties ) {
if ( ! ( E . usage & ( PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR ) ) ) {
continue ;
}
String propertyname = E . name ;
Variant old_variant = p_base - > get ( propertyname ) ;
Variant updated_variant = old_variant ;
String warn_message ;
if ( _check_node_recursive ( updated_variant , p_node , p_by_node , E . hint_string , warn_message ) ) {
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > add_do_property ( p_base , propertyname , updated_variant ) ;
undo_redo - > add_undo_property ( p_base , propertyname , old_variant ) ;
if ( ! warn_message . is_empty ( ) ) {
String node_path = ( String ( edited_scene - > get_name ( ) ) + " / " + String ( edited_scene - > get_path_to ( p_base ) ) ) . trim_suffix ( " /. " ) ;
2023-11-11 22:59:05 +01:00
WARN_PRINT ( warn_message + vformat ( " Removing the node from variable \" %s \" on node \" %s \" . " , propertyname , node_path ) ) ;
2023-06-16 02:33:33 +02:00
}
}
}
for ( int i = 0 ; i < p_base - > get_child_count ( ) ; i + + ) {
perform_node_replace ( p_base - > get_child ( i ) , p_node , p_by_node ) ;
}
}
bool SceneTreeDock : : _check_node_recursive ( Variant & r_variant , Node * p_node , Node * p_by_node , const String type_hint , String & r_warn_message ) {
switch ( r_variant . get_type ( ) ) {
case Variant : : OBJECT : {
if ( p_node = = r_variant ) {
if ( p_by_node - > is_class ( type_hint ) | | EditorNode : : get_singleton ( ) - > is_object_of_custom_type ( p_by_node , type_hint ) ) {
r_variant = p_by_node ;
} else {
r_variant = memnew ( Object ) ;
2023-11-11 22:59:05 +01:00
r_warn_message = vformat ( " The node's new type is incompatible with an exported variable (expected %s, but type is %s). " , type_hint , p_by_node - > get_class ( ) ) ;
2023-06-16 02:33:33 +02:00
}
return true ;
}
} break ;
case Variant : : ARRAY : {
Array a = r_variant ;
bool updated = false ;
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
Variant value = a [ i ] ;
if ( _check_node_recursive ( value , p_node , p_by_node , type_hint . get_slice ( " : " , 1 ) , r_warn_message ) ) {
if ( ! updated ) {
a = a . duplicate ( ) ; // Need to duplicate for undo-redo to work.
updated = true ;
}
a [ i ] = value ;
}
}
if ( updated ) {
r_variant = a ;
return true ;
}
} break ;
default : {
}
}
return false ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : set_edited_scene ( Node * p_scene ) {
edited_scene = p_scene ;
}
2024-05-23 11:09:19 +02:00
static bool _is_same_selection ( const Vector < Node * > & p_first , const List < Node * > & p_second ) {
if ( p_first . size ( ) ! = p_second . size ( ) ) {
return false ;
}
for ( Node * node : p_second ) {
if ( ! p_first . has ( node ) ) {
return false ;
}
}
return true ;
}
2024-04-14 12:56:49 +02:00
void SceneTreeDock : : set_selection ( const Vector < Node * > & p_nodes ) {
2024-05-23 11:09:19 +02:00
// If the nodes selected are the same independently of order then return early.
if ( _is_same_selection ( p_nodes , editor_selection - > get_full_selected_node_list ( ) ) ) {
return ;
}
2024-04-14 12:56:49 +02:00
editor_selection - > clear ( ) ;
for ( Node * node : p_nodes ) {
editor_selection - > add_node ( node ) ;
}
}
2014-07-02 09:34:46 +02:00
void SceneTreeDock : : set_selected ( Node * p_node , bool p_emit_selected ) {
scene_tree - > set_selected ( p_node , p_emit_selected ) ;
2014-02-10 02:10:30 +01:00
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : _new_scene_from ( const String & p_file ) {
2015-11-27 21:42:48 +01:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . size ( ) ! = 1 ) {
2016-05-04 03:25:37 +02:00
accept - > set_text ( TTR ( " This operation requires a single selected node. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
return ;
}
2018-09-07 15:54:26 +02:00
if ( EditorNode : : get_singleton ( ) - > is_scene_open ( p_file ) ) {
accept - > set_text ( TTR ( " Can't overwrite scene that is still open! " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2018-09-07 15:54:26 +02:00
return ;
}
2015-11-27 21:42:48 +01:00
Node * base = selection . front ( ) - > get ( ) ;
2022-05-13 15:04:37 +02:00
HashMap < const Node * , Node * > duplimap ;
2023-10-04 19:18:22 +02:00
HashMap < const Node * , Node * > inverse_duplimap ;
2021-02-28 17:19:01 +01:00
Node * copy = base - > duplicate_from_editor ( duplimap ) ;
2023-10-04 19:18:22 +02:00
for ( const KeyValue < const Node * , Node * > & item : duplimap ) {
inverse_duplimap [ item . value ] = const_cast < Node * > ( item . key ) ;
}
2015-11-27 21:42:48 +01:00
if ( copy ) {
2022-09-02 07:26:46 +02:00
// Handle Unique Nodes.
2022-06-12 07:57:42 +02:00
for ( int i = 0 ; i < copy - > get_child_count ( false ) ; i + + ) {
2023-10-04 19:18:22 +02:00
_set_node_owner_recursive ( copy - > get_child ( i , false ) , copy , inverse_duplimap ) ;
2021-02-28 17:19:01 +01:00
}
2022-09-02 07:26:46 +02:00
// Root node cannot ever be unique name in its own Scene!
copy - > set_unique_name_in_owner ( false ) ;
2021-02-28 17:19:01 +01:00
2015-11-27 21:42:48 +01:00
Ref < PackedScene > sdata = memnew ( PackedScene ) ;
Error err = sdata - > pack ( copy ) ;
memdelete ( copy ) ;
if ( err ! = OK ) {
2016-05-04 03:25:37 +02:00
accept - > set_text ( TTR ( " Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
return ;
}
int flg = 0 ;
2022-10-18 16:43:37 +02:00
if ( EDITOR_GET ( " filesystem/on_save/compress_binary_resources " ) ) {
2015-11-27 21:42:48 +01:00
flg | = ResourceSaver : : FLAG_COMPRESS ;
2020-05-14 16:41:43 +02:00
}
2015-11-27 21:42:48 +01:00
2022-06-03 01:33:42 +02:00
err = ResourceSaver : : save ( sdata , p_file , flg ) ;
2015-11-27 21:42:48 +01:00
if ( err ! = OK ) {
2016-05-04 03:25:37 +02:00
accept - > set_text ( TTR ( " Error saving scene. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
return ;
}
2016-10-11 16:54:46 +02:00
_replace_with_branch_scene ( p_file , base ) ;
2015-11-27 21:42:48 +01:00
} else {
2016-05-04 03:25:37 +02:00
accept - > set_text ( TTR ( " Error duplicating scene to save it. " ) ) ;
2020-03-06 18:00:16 +01:00
accept - > popup_centered ( ) ;
2015-11-27 21:42:48 +01:00
return ;
}
}
2023-10-04 19:18:22 +02:00
void SceneTreeDock : : _set_node_owner_recursive ( Node * p_node , Node * p_owner , const HashMap < const Node * , Node * > & p_inverse_duplimap ) {
HashMap < const Node * , Node * > : : ConstIterator E = p_inverse_duplimap . find ( p_node ) ;
if ( E ) {
const Node * original = E - > value ;
if ( original - > get_owner ( ) ) {
p_node - > set_owner ( p_owner ) ;
}
2021-02-28 17:19:01 +01:00
}
2022-06-12 07:57:42 +02:00
for ( int i = 0 ; i < p_node - > get_child_count ( false ) ; i + + ) {
2023-10-04 19:18:22 +02:00
_set_node_owner_recursive ( p_node - > get_child ( i , false ) , p_owner , p_inverse_duplimap ) ;
2021-02-28 17:19:01 +01:00
}
}
2016-05-11 16:46:08 +02:00
static bool _is_node_visible ( Node * p_node ) {
2020-05-14 16:41:43 +02:00
if ( ! p_node - > get_owner ( ) ) {
2016-05-11 16:46:08 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
if ( p_node - > get_owner ( ) ! = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) & & ! EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( p_node - > get_owner ( ) ) ) {
2016-05-11 16:46:08 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
return true ;
}
static bool _has_visible_children ( Node * p_node ) {
2016-11-02 16:23:03 +01:00
bool collapsed = p_node - > is_displayed_folded ( ) ;
2020-05-14 16:41:43 +02:00
if ( collapsed ) {
2016-05-11 16:46:08 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
Node * child = p_node - > get_child ( i ) ;
2020-05-14 16:41:43 +02:00
if ( ! _is_node_visible ( child ) ) {
2016-05-11 16:46:08 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-05-11 16:46:08 +02:00
return true ;
}
return false ;
}
2016-07-01 04:19:44 +02:00
void SceneTreeDock : : _normalize_drop ( Node * & to_node , int & to_pos , int p_type ) {
2016-05-12 01:57:52 +02:00
to_pos = - 1 ;
2016-05-11 16:46:08 +02:00
2016-07-18 20:00:14 +02:00
if ( p_type = = - 1 ) {
2016-05-11 16:46:08 +02:00
//drop at above selected node
2016-05-12 01:57:52 +02:00
if ( to_node = = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
2020-04-02 01:20:12 +02:00
to_node = nullptr ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Cannot perform drop above the root node! " ) ;
2016-05-12 01:57:52 +02:00
}
2016-05-11 16:46:08 +02:00
2023-06-29 00:46:11 +02:00
to_pos = to_node - > get_index ( false ) ;
2016-11-02 16:23:03 +01:00
to_node = to_node - > get_parent ( ) ;
2016-06-18 20:30:44 +02:00
2016-05-11 16:46:08 +02:00
} else if ( p_type = = 1 ) {
//drop at below selected node
2016-05-12 01:57:52 +02:00
if ( to_node = = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
2016-07-18 20:00:14 +02:00
//if at lower sibling of root node
2017-03-24 21:45:31 +01:00
to_pos = 0 ; //just insert at beginning of root node
2017-03-05 16:44:50 +01:00
return ;
}
2016-06-18 20:30:44 +02:00
2020-04-02 01:20:12 +02:00
Node * lower_sibling = nullptr ;
2016-06-18 20:30:44 +02:00
if ( _has_visible_children ( to_node ) ) {
2017-03-05 16:44:50 +01:00
to_pos = 0 ;
} else {
2023-06-29 00:46:11 +02:00
for ( int i = to_node - > get_index ( false ) + 1 ; i < to_node - > get_parent ( ) - > get_child_count ( false ) ; i + + ) {
Node * c = to_node - > get_parent ( ) - > get_child ( i , false ) ;
2016-06-18 20:30:44 +02:00
if ( _is_node_visible ( c ) ) {
lower_sibling = c ;
break ;
}
}
if ( lower_sibling ) {
2023-06-29 00:46:11 +02:00
to_pos = lower_sibling - > get_index ( false ) ;
2017-03-05 16:44:50 +01:00
}
2014-12-18 03:38:24 +01:00
to_node = to_node - > get_parent ( ) ;
2017-03-05 16:44:50 +01:00
}
2016-05-11 16:46:08 +02:00
}
2016-05-12 01:57:52 +02:00
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : _files_dropped ( const Vector < String > & p_files , NodePath p_to , int p_type ) {
2016-05-12 01:57:52 +02:00
Node * node = get_node ( p_to ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( node ) ;
2024-05-16 04:13:46 +02:00
ERR_FAIL_COND ( p_files . is_empty ( ) ) ;
2016-05-12 01:57:52 +02:00
2024-05-16 04:13:46 +02:00
const String & res_path = p_files [ 0 ] ;
const StringName res_type = EditorFileSystem : : get_singleton ( ) - > get_file_type ( res_path ) ;
2024-08-03 08:43:24 +02:00
const bool is_dropping_scene = ClassDB : : is_parent_class ( res_type , " PackedScene " ) ;
2024-05-16 04:13:46 +02:00
2024-08-03 08:43:24 +02:00
// Dropping as property.
if ( p_type = = 0 & & p_files . size ( ) = = 1 & & ! is_dropping_scene ) {
2021-07-16 16:27:59 +02:00
List < String > valid_properties ;
List < PropertyInfo > pinfo ;
node - > get_property_list ( & pinfo ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & p : pinfo ) {
2021-07-16 16:27:59 +02:00
if ( ! ( p . usage & PROPERTY_USAGE_EDITOR ) | | ! ( p . usage & PROPERTY_USAGE_STORAGE ) | | p . hint ! = PROPERTY_HINT_RESOURCE_TYPE ) {
continue ;
}
Vector < String > valid_types = p . hint_string . split ( " , " ) ;
2021-07-24 15:46:25 +02:00
for ( const String & prop_type : valid_types ) {
2021-07-16 16:27:59 +02:00
if ( res_type = = prop_type | | ClassDB : : is_parent_class ( res_type , prop_type ) | | EditorNode : : get_editor_data ( ) . script_class_is_parent ( res_type , prop_type ) ) {
valid_properties . push_back ( p . name ) ;
break ;
}
}
}
if ( valid_properties . size ( ) > 1 ) {
property_drop_node = node ;
resource_drop_path = res_path ;
2022-03-23 02:46:59 +01:00
const EditorPropertyNameProcessor : : Style style = InspectorDock : : get_singleton ( ) - > get_property_name_style ( ) ;
2021-07-16 16:27:59 +02:00
menu_properties - > clear ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & p : valid_properties ) {
2023-10-05 15:12:10 +02:00
menu_properties - > add_item ( EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( p , style , p , node - > get_class_name ( ) ) ) ;
2022-03-12 01:06:45 +01:00
menu_properties - > set_item_metadata ( - 1 , p ) ;
2021-07-16 16:27:59 +02:00
}
2021-11-20 09:04:57 +01:00
menu_properties - > reset_size ( ) ;
2021-07-16 16:27:59 +02:00
menu_properties - > set_position ( get_screen_position ( ) + get_local_mouse_position ( ) ) ;
menu_properties - > popup ( ) ;
2024-05-16 04:13:46 +02:00
return ;
}
if ( ! valid_properties . is_empty ( ) ) {
2024-04-15 15:18:34 +02:00
_perform_property_drop ( node , valid_properties . front ( ) - > get ( ) , ResourceLoader : : load ( res_path ) ) ;
2024-05-16 04:13:46 +02:00
return ;
2021-07-16 16:27:59 +02:00
}
}
2024-05-16 04:13:46 +02:00
// Either instantiate scenes or create AudioStreamPlayers.
int to_pos = - 1 ;
_normalize_drop ( node , to_pos , p_type ) ;
2024-08-03 08:43:24 +02:00
if ( is_dropping_scene ) {
2024-05-16 04:13:46 +02:00
_perform_instantiate_scenes ( p_files , node , to_pos ) ;
2024-05-28 12:57:04 +02:00
} else if ( ClassDB : : is_parent_class ( res_type , " AudioStream " ) ) {
2024-05-16 04:13:46 +02:00
_perform_create_audio_stream_players ( p_files , node , to_pos ) ;
}
2016-05-12 01:57:52 +02:00
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : _script_dropped ( const String & p_file , NodePath p_to ) {
2016-10-27 16:32:41 +02:00
Ref < Script > scr = ResourceLoader : : load ( p_file ) ;
ERR_FAIL_COND ( ! scr . is_valid ( ) ) ;
2022-11-14 13:18:28 +01:00
Node * n = get_node ( p_to ) ;
if ( ! n ) {
return ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2023-06-08 23:24:00 +02:00
if ( Input : : get_singleton ( ) - > is_key_pressed ( Key : : CMD_OR_CTRL ) ) {
2022-11-14 13:18:28 +01:00
Object * obj = ClassDB : : instantiate ( scr - > get_instance_base_type ( ) ) ;
ERR_FAIL_NULL ( obj ) ;
Node * new_node = Object : : cast_to < Node > ( obj ) ;
if ( ! new_node ) {
if ( ! obj - > is_ref_counted ( ) ) {
memdelete ( obj ) ;
}
ERR_FAIL_MSG ( " Script does not extend Node-derived type. " ) ;
}
new_node - > set_name ( Node : : adjust_name_casing ( p_file . get_file ( ) . get_basename ( ) ) ) ;
new_node - > set_script ( scr ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Instantiate Script " ) ) ;
undo_redo - > add_do_method ( n , " add_child " , new_node , true ) ;
undo_redo - > add_do_method ( new_node , " set_owner " , edited_scene ) ;
undo_redo - > add_do_method ( editor_selection , " clear " ) ;
undo_redo - > add_do_method ( editor_selection , " add_node " , new_node ) ;
undo_redo - > add_do_reference ( new_node ) ;
undo_redo - > add_undo_method ( n , " remove_child " , new_node ) ;
2022-11-14 13:18:28 +01:00
EditorDebuggerNode * ed = EditorDebuggerNode : : get_singleton ( ) ;
2022-11-24 18:28:49 +01:00
undo_redo - > add_do_method ( ed , " live_debug_create_node " , edited_scene - > get_path_to ( n ) , new_node - > get_class ( ) , new_node - > get_name ( ) ) ;
undo_redo - > add_undo_method ( ed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( n ) ) . path_join ( new_node - > get_name ( ) ) ) ) ;
undo_redo - > commit_action ( ) ;
2022-11-14 13:18:28 +01:00
} else {
2022-11-24 18:28:49 +01:00
undo_redo - > create_action ( TTR ( " Attach Script " ) , UndoRedo : : MERGE_DISABLE , n ) ;
undo_redo - > add_do_method ( InspectorDock : : get_singleton ( ) , " store_script_properties " , n ) ;
undo_redo - > add_undo_method ( InspectorDock : : get_singleton ( ) , " store_script_properties " , n ) ;
undo_redo - > add_do_method ( n , " set_script " , scr ) ;
undo_redo - > add_undo_method ( n , " set_script " , n - > get_script ( ) ) ;
undo_redo - > add_do_method ( InspectorDock : : get_singleton ( ) , " apply_script_properties " , n ) ;
undo_redo - > add_undo_method ( InspectorDock : : get_singleton ( ) , " apply_script_properties " , n ) ;
undo_redo - > add_do_method ( this , " _update_script_button " ) ;
undo_redo - > add_undo_method ( this , " _update_script_button " ) ;
undo_redo - > commit_action ( ) ;
2016-10-27 16:32:41 +02:00
}
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : _nodes_dragged ( const Array & p_nodes , NodePath p_to , int p_type ) {
2022-01-17 17:37:17 +01:00
if ( ! _validate_no_foreign ( ) ) {
return ;
}
2019-07-04 15:41:21 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2024-04-27 22:09:14 +02:00
List < Node * > full_selection = editor_selection - > get_full_selected_node_list ( ) ;
2016-05-12 01:57:52 +02:00
2020-12-15 13:04:21 +01:00
if ( selection . is_empty ( ) ) {
2019-07-04 15:41:21 +02:00
return ; //nothing to reparent
2020-05-14 16:41:43 +02:00
}
2016-05-12 01:57:52 +02:00
2019-07-04 15:41:21 +02:00
Node * to_node = get_node ( p_to ) ;
2020-05-14 16:41:43 +02:00
if ( ! to_node ) {
2016-05-12 01:57:52 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-12 01:57:52 +02:00
2019-07-04 15:41:21 +02:00
Vector < Node * > nodes ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
nodes . push_back ( E ) ;
2019-07-04 15:41:21 +02:00
}
2016-05-12 01:57:52 +02:00
int to_pos = - 1 ;
2016-05-11 16:46:08 +02:00
2016-07-01 04:19:44 +02:00
_normalize_drop ( to_node , to_pos , p_type ) ;
2021-08-13 23:31:57 +02:00
_do_reparent ( to_node , to_pos , nodes , ! Input : : get_singleton ( ) - > is_key_pressed ( Key : : SHIFT ) ) ;
2024-04-27 22:09:14 +02:00
for ( Node * E : full_selection ) {
2023-10-29 09:29:06 +01:00
editor_selection - > add_node ( E ) ;
}
2016-05-11 16:46:08 +02:00
}
2017-06-05 05:12:19 +02:00
void SceneTreeDock : : _add_children_to_popup ( Object * p_obj , int p_depth ) {
2020-05-14 16:41:43 +02:00
if ( p_depth > 8 ) {
2017-06-05 05:12:19 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-06-05 05:12:19 +02:00
List < PropertyInfo > pinfo ;
p_obj - > get_property_list ( & pinfo ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : pinfo ) {
2021-07-16 05:45:57 +02:00
if ( ! ( E . usage & PROPERTY_USAGE_EDITOR ) ) {
2017-06-05 05:12:19 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2021-07-16 05:45:57 +02:00
if ( E . hint ! = PROPERTY_HINT_RESOURCE_TYPE ) {
2017-06-05 05:12:19 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-06-05 05:12:19 +02:00
2021-07-16 05:45:57 +02:00
Variant value = p_obj - > get ( E . name ) ;
2020-05-14 16:41:43 +02:00
if ( value . get_type ( ) ! = Variant : : OBJECT ) {
2017-06-05 05:12:19 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-06-05 05:12:19 +02:00
Object * obj = value ;
2020-05-14 16:41:43 +02:00
if ( ! obj ) {
2017-06-05 05:12:19 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-06-05 05:12:19 +02:00
2019-06-11 20:43:37 +02:00
Ref < Texture2D > icon = EditorNode : : get_singleton ( ) - > get_object_icon ( obj ) ;
2017-06-05 05:12:19 +02:00
if ( menu - > get_item_count ( ) = = 0 ) {
2023-11-28 17:33:04 +01:00
menu - > add_submenu_node_item ( TTR ( " Sub-Resources " ) , menu_subresources ) ;
2017-06-05 05:12:19 +02:00
}
2021-07-16 05:45:57 +02:00
menu_subresources - > add_icon_item ( icon , E . name . capitalize ( ) , EDIT_SUBRESOURCE_BASE + subresources . size ( ) ) ;
2023-04-04 15:59:50 +02:00
menu_subresources - > set_item_indent ( - 1 , p_depth ) ;
2017-08-07 12:17:31 +02:00
subresources . push_back ( obj - > get_instance_id ( ) ) ;
2017-06-05 05:12:19 +02:00
_add_children_to_popup ( obj , p_depth + 1 ) ;
}
}
2016-05-16 04:41:48 +02:00
void SceneTreeDock : : _tree_rmb ( const Vector2 & p_menu_pos ) {
2016-05-16 17:23:40 +02:00
if ( ! EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
2023-09-26 15:21:54 +02:00
menu - > clear ( false ) ;
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Add " ) ) , ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) , TOOL_NEW ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Instance " ) ) , ED_GET_SHORTCUT ( " scene_tree/instantiate_scene " ) , TOOL_INSTANTIATE ) ;
2019-04-09 00:18:03 +02:00
}
2016-05-16 17:23:40 +02:00
2021-11-20 09:04:57 +01:00
menu - > reset_size ( ) ;
2020-07-01 19:44:19 +02:00
menu - > set_position ( get_screen_position ( ) + p_menu_pos ) ;
2016-05-16 17:23:40 +02:00
menu - > popup ( ) ;
return ;
}
2016-05-16 04:41:48 +02:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2019-11-04 16:45:16 +01:00
List < Node * > full_selection = editor_selection - > get_full_selected_node_list ( ) ; // Above method only returns nodes with common parent.
2016-05-16 04:41:48 +02:00
2020-05-14 16:41:43 +02:00
if ( selection . size ( ) = = 0 ) {
2016-05-16 04:41:48 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-05-16 17:23:40 +02:00
2023-09-26 15:21:54 +02:00
menu - > clear ( false ) ;
2016-05-16 04:41:48 +02:00
2018-10-03 11:25:18 +02:00
Ref < Script > existing_script ;
2020-02-17 15:10:45 +01:00
bool existing_script_removable = true ;
2016-05-16 04:41:48 +02:00
if ( selection . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
Node * selected = selection . front ( ) - > get ( ) ;
2018-01-02 08:10:49 +01:00
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
subresources . clear ( ) ;
menu_subresources - > clear ( ) ;
2021-11-20 09:04:57 +01:00
menu_subresources - > reset_size ( ) ;
2024-04-15 15:18:34 +02:00
_add_children_to_popup ( selected , 0 ) ;
2020-05-14 16:41:43 +02:00
if ( menu - > get_item_count ( ) > 0 ) {
2019-04-09 00:18:03 +02:00
menu - > add_separator ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-06-05 05:12:19 +02:00
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Add " ) ) , ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) , TOOL_NEW ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Instance " ) ) , ED_GET_SHORTCUT ( " scene_tree/instantiate_scene " ) , TOOL_INSTANTIATE ) ;
2019-04-09 00:18:03 +02:00
}
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Collapse " ) ) , ED_GET_SHORTCUT ( " scene_tree/expand_collapse_all " ) , TOOL_EXPAND_COLLAPSE ) ;
2018-07-07 16:51:18 +02:00
menu - > add_separator ( ) ;
2018-10-03 11:25:18 +02:00
existing_script = selected - > get_script ( ) ;
2019-07-19 21:21:30 +02:00
if ( EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( selected ) = = existing_script ) {
2020-02-17 15:10:45 +01:00
existing_script_removable = false ;
2019-07-19 21:21:30 +02:00
}
2018-10-03 11:25:18 +02:00
}
2018-01-02 08:10:49 +01:00
2021-05-06 22:01:36 +02:00
if ( profile_allow_editing ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ActionCut " ) ) , ED_GET_SHORTCUT ( " scene_tree/cut_node " ) , TOOL_CUT ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ActionCopy " ) ) , ED_GET_SHORTCUT ( " scene_tree/copy_node " ) , TOOL_COPY ) ;
2020-01-07 17:43:21 +01:00
if ( selection . size ( ) = = 1 & & ! node_clipboard . is_empty ( ) ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ActionPaste " ) ) , ED_GET_SHORTCUT ( " scene_tree/paste_node " ) , TOOL_PASTE ) ;
2023-09-15 01:15:42 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ActionPaste " ) ) , ED_GET_SHORTCUT ( " scene_tree/paste_node_as_sibling " ) , TOOL_PASTE_AS_SIBLING ) ;
if ( selection . front ( ) - > get ( ) = = edited_scene ) {
menu - > set_item_disabled ( - 1 , true ) ;
}
2020-01-07 17:43:21 +01:00
}
menu - > add_separator ( ) ;
2021-05-06 22:01:36 +02:00
}
2020-01-07 17:43:21 +01:00
2021-05-06 22:01:36 +02:00
if ( profile_allow_script_editing ) {
2019-11-04 16:45:16 +01:00
bool add_separator = false ;
2018-10-03 11:25:18 +02:00
2019-11-04 16:45:16 +01:00
if ( full_selection . size ( ) = = 1 ) {
add_separator = true ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ScriptCreate " ) ) , ED_GET_SHORTCUT ( " scene_tree/attach_script " ) , TOOL_ATTACH_SCRIPT ) ;
2019-10-21 06:57:10 +02:00
if ( existing_script . is_valid ( ) ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ScriptExtend " ) ) , ED_GET_SHORTCUT ( " scene_tree/extend_script " ) , TOOL_EXTEND_SCRIPT ) ;
2019-04-14 14:04:04 +02:00
}
2019-04-09 00:18:03 +02:00
}
2020-02-17 15:10:45 +01:00
if ( existing_script . is_valid ( ) & & existing_script_removable ) {
2019-11-04 16:45:16 +01:00
add_separator = true ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ScriptRemove " ) ) , ED_GET_SHORTCUT ( " scene_tree/detach_script " ) , TOOL_DETACH_SCRIPT ) ;
2019-11-04 16:45:16 +01:00
} else if ( full_selection . size ( ) > 1 ) {
bool script_exists = false ;
2021-07-16 05:45:57 +02:00
for ( Node * E : full_selection ) {
if ( ! E - > get_script ( ) . is_null ( ) ) {
2019-11-04 16:45:16 +01:00
script_exists = true ;
break ;
}
}
if ( script_exists ) {
add_separator = true ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ScriptRemove " ) ) , ED_GET_SHORTCUT ( " scene_tree/detach_script " ) , TOOL_DETACH_SCRIPT ) ;
2019-11-04 16:45:16 +01:00
}
}
2021-05-06 23:37:12 +02:00
if ( add_separator & & profile_allow_editing ) {
2019-11-04 16:45:16 +01:00
menu - > add_separator ( ) ;
2019-04-09 00:18:03 +02:00
}
2016-05-16 04:41:48 +02:00
}
2018-10-03 11:25:18 +02:00
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
2023-06-15 13:20:49 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Rename " ) ) , ED_GET_SHORTCUT ( " scene_tree/rename " ) , TOOL_RENAME ) ;
2021-02-22 20:18:14 +01:00
bool can_replace = true ;
2021-07-16 05:45:57 +02:00
for ( Node * E : selection ) {
2021-12-09 10:42:46 +01:00
if ( E ! = edited_scene & & ( E - > get_owner ( ) ! = edited_scene | | ! E - > get_scene_file_path ( ) . is_empty ( ) ) ) {
2021-02-22 20:18:14 +01:00
can_replace = false ;
break ;
}
2024-04-11 16:29:18 +02:00
if ( edited_scene - > get_scene_inherited_state ( ) . is_valid ( ) ) {
if ( E = = edited_scene | | edited_scene - > get_scene_inherited_state ( ) - > find_node_by_path ( edited_scene - > get_path_to ( E ) ) > = 0 ) {
can_replace = false ;
break ;
}
}
2021-02-22 20:18:14 +01:00
}
if ( can_replace ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Reload " ) ) , ED_GET_SHORTCUT ( " scene_tree/change_node_type " ) , TOOL_REPLACE ) ;
2021-02-22 20:18:14 +01:00
}
2019-04-09 00:18:03 +02:00
if ( scene_tree - > get_selected ( ) ! = edited_scene ) {
2023-06-15 13:20:49 +02:00
menu - > add_separator ( ) ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " MoveUp " ) ) , ED_GET_SHORTCUT ( " scene_tree/move_up " ) , TOOL_MOVE_UP ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " MoveDown " ) ) , ED_GET_SHORTCUT ( " scene_tree/move_down " ) , TOOL_MOVE_DOWN ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Duplicate " ) ) , ED_GET_SHORTCUT ( " scene_tree/duplicate " ) , TOOL_DUPLICATE ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Reparent " ) ) , ED_GET_SHORTCUT ( " scene_tree/reparent " ) , TOOL_REPARENT ) ;
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ReparentToNewNode " ) ) , ED_GET_SHORTCUT ( " scene_tree/reparent_to_new_node " ) , TOOL_REPARENT_TO_NEW_NODE ) ;
2019-11-04 16:45:16 +01:00
if ( selection . size ( ) = = 1 ) {
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " NewRoot " ) ) , ED_GET_SHORTCUT ( " scene_tree/make_root " ) , TOOL_MAKE_ROOT ) ;
2019-11-04 16:45:16 +01:00
}
2019-04-09 00:18:03 +02:00
}
2018-01-02 08:10:49 +01:00
}
2016-05-16 04:41:48 +02:00
if ( selection . size ( ) = = 1 ) {
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
menu - > add_separator ( ) ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " CreateNewSceneFrom " ) ) , ED_GET_SHORTCUT ( " scene_tree/save_branch_as_scene " ) , TOOL_NEW_SCENE_FROM ) ;
2019-11-04 16:45:16 +01:00
}
2022-04-16 12:23:32 +02:00
2019-11-04 16:45:16 +01:00
if ( full_selection . size ( ) = = 1 ) {
2019-04-09 00:18:03 +02:00
menu - > add_separator ( ) ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " CopyNodePath " ) ) , ED_GET_SHORTCUT ( " scene_tree/copy_node_path " ) , TOOL_COPY_NODE_PATH ) ;
2019-04-09 00:18:03 +02:00
}
2022-08-16 14:34:09 +02:00
}
2019-04-09 00:18:03 +02:00
2022-08-16 14:34:09 +02:00
if ( profile_allow_editing ) {
// Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root.
bool all_owned = true ;
for ( Node * node : full_selection ) {
if ( node - > get_owner ( ) ! = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
all_owned = false ;
break ;
}
}
if ( all_owned ) {
2022-08-31 09:44:33 +02:00
// Group "toggle_unique_name" with "copy_node_path", if it is available.
if ( menu - > get_item_index ( TOOL_COPY_NODE_PATH ) = = - 1 ) {
menu - > add_separator ( ) ;
}
2024-04-15 15:18:34 +02:00
Node * node = full_selection . front ( ) - > get ( ) ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " SceneUniqueName " ) ) , ED_GET_SHORTCUT ( " scene_tree/toggle_unique_name " ) , TOOL_TOGGLE_SCENE_UNIQUE_NAME ) ;
2022-08-31 09:44:33 +02:00
menu - > set_item_text ( menu - > get_item_index ( TOOL_TOGGLE_SCENE_UNIQUE_NAME ) , node - > is_unique_name_in_owner ( ) ? TTR ( " Revoke Unique Name " ) : TTR ( " Access as Unique Name " ) ) ;
2022-04-16 12:23:32 +02:00
}
2022-08-16 14:34:09 +02:00
}
2022-04-16 12:23:32 +02:00
2022-08-16 14:34:09 +02:00
if ( selection . size ( ) = = 1 ) {
2024-04-15 15:18:34 +02:00
bool is_external = ( ! selection . front ( ) - > get ( ) - > get_scene_file_path ( ) . is_empty ( ) ) ;
2017-06-30 18:17:33 +02:00
if ( is_external ) {
2024-07-26 11:52:26 +02:00
bool is_inherited = selection . front ( ) - > get ( ) - > get_scene_inherited_state ( ) . is_valid ( ) ;
2024-04-15 15:18:34 +02:00
bool is_top_level = selection . front ( ) - > get ( ) - > get_owner ( ) = = nullptr ;
2017-07-28 10:32:49 +02:00
if ( is_inherited & & is_top_level ) {
2017-07-04 12:50:20 +02:00
menu - > add_separator ( ) ;
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
menu - > add_item ( TTR ( " Clear Inheritance " ) , TOOL_SCENE_CLEAR_INHERITANCE ) ;
}
2023-08-13 02:33:39 +02:00
menu - > add_icon_item ( get_editor_theme_icon ( SNAME ( " Load " ) ) , TTR ( " Open in Editor " ) , TOOL_SCENE_OPEN_INHERITED ) ;
2017-07-04 12:50:20 +02:00
} else if ( ! is_top_level ) {
menu - > add_separator ( ) ;
2024-04-15 15:18:34 +02:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( selection . front ( ) - > get ( ) ) ;
bool placeholder = selection . front ( ) - > get ( ) - > get_scene_instance_load_placeholder ( ) ;
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
menu - > add_check_item ( TTR ( " Editable Children " ) , TOOL_SCENE_EDITABLE_CHILDREN ) ;
2024-03-04 14:10:47 +01:00
menu - > set_item_shortcut ( - 1 , ED_GET_SHORTCUT ( " scene_tree/toggle_editable_children " ) ) ;
2023-10-23 05:03:52 +02:00
menu - > add_check_item ( TTR ( " Load as Placeholder " ) , TOOL_SCENE_USE_PLACEHOLDER ) ;
2019-04-09 00:18:03 +02:00
menu - > add_item ( TTR ( " Make Local " ) , TOOL_SCENE_MAKE_LOCAL ) ;
}
2023-08-13 02:33:39 +02:00
menu - > add_icon_item ( get_editor_theme_icon ( SNAME ( " Load " ) ) , TTR ( " Open in Editor " ) , TOOL_SCENE_OPEN ) ;
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
menu - > set_item_checked ( menu - > get_item_idx_from_text ( TTR ( " Editable Children " ) ) , editable ) ;
2023-10-23 05:03:52 +02:00
menu - > set_item_checked ( menu - > get_item_idx_from_text ( TTR ( " Load as Placeholder " ) ) , placeholder ) ;
2019-04-09 00:18:03 +02:00
}
2017-06-30 18:17:33 +02:00
}
}
2016-05-16 04:41:48 +02:00
}
2018-05-17 23:02:16 +02:00
2021-08-31 03:28:37 +02:00
# ifdef MODULE_REGEX_ENABLED
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing & & selection . size ( ) > 1 ) {
2018-05-17 23:02:16 +02:00
//this is not a commonly used action, it makes no sense for it to be where it was nor always present.
menu - > add_separator ( ) ;
2023-08-13 02:33:39 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Rename " ) ) , ED_GET_SHORTCUT ( " scene_tree/batch_rename " ) , TOOL_BATCH_RENAME ) ;
2018-05-17 23:02:16 +02:00
}
2021-08-31 03:28:37 +02:00
# endif // MODULE_REGEX_ENABLED
2018-10-03 11:25:18 +02:00
menu - > add_separator ( ) ;
2023-11-14 12:55:36 +01:00
2024-04-15 15:18:34 +02:00
if ( full_selection . size ( ) = = 1 & & ! selection . front ( ) - > get ( ) - > get_scene_file_path ( ) . is_empty ( ) ) {
2023-11-14 12:55:36 +01:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " ShowInFileSystem " ) ) , ED_GET_SHORTCUT ( " scene_tree/show_in_file_system " ) , TOOL_SHOW_IN_FILE_SYSTEM ) ;
}
2023-08-13 02:33:39 +02:00
menu - > add_icon_item ( get_editor_theme_icon ( SNAME ( " Help " ) ) , TTR ( " Open Documentation " ) , TOOL_OPEN_DOCUMENTATION ) ;
2018-10-03 11:25:18 +02:00
2019-04-09 00:18:03 +02:00
if ( profile_allow_editing ) {
menu - > add_separator ( ) ;
2024-05-21 22:11:50 +02:00
menu - > add_icon_shortcut ( get_editor_theme_icon ( SNAME ( " Remove " ) ) , ED_GET_SHORTCUT ( " scene_tree/delete " ) , TOOL_ERASE ) ;
2019-04-09 00:18:03 +02:00
}
2024-07-21 10:43:53 +02:00
Vector < String > p_paths ;
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
String node_path = root - > get_path ( ) . rel_path_to ( E - > get ( ) - > get_path ( ) ) ;
p_paths . push_back ( node_path ) ;
}
EditorNode : : get_editor_data ( ) . add_options_from_plugins ( menu , EditorData : : CONTEXT_SLOT_SCENE_TREE , p_paths ) ;
2021-11-20 09:04:57 +01:00
menu - > reset_size ( ) ;
2017-03-29 17:29:38 +02:00
menu - > set_position ( p_menu_pos ) ;
2016-05-16 04:41:48 +02:00
menu - > popup ( ) ;
}
2022-01-20 12:54:36 +01:00
void SceneTreeDock : : _update_tree_menu ( ) {
PopupMenu * tree_menu = button_tree_menu - > get_popup ( ) ;
2022-09-16 15:10:28 +02:00
tree_menu - > clear ( ) ;
_append_filter_options_to ( tree_menu ) ;
tree_menu - > add_separator ( ) ;
tree_menu - > add_check_item ( TTR ( " Auto Expand to Selected " ) , TOOL_AUTO_EXPAND ) ;
2022-10-18 16:43:37 +02:00
tree_menu - > set_item_checked ( tree_menu - > get_item_index ( TOOL_AUTO_EXPAND ) , EDITOR_GET ( " docks/scene_tree/auto_expand_to_selected " ) ) ;
2023-04-04 15:59:50 +02:00
2023-11-17 02:58:23 +01:00
tree_menu - > add_check_item ( TTR ( " Center Node on Reparent " ) , TOOL_CENTER_PARENT ) ;
tree_menu - > set_item_checked ( tree_menu - > get_item_index ( TOOL_CENTER_PARENT ) , EDITOR_GET ( " docks/scene_tree/center_node_on_reparent " ) ) ;
tree_menu - > set_item_tooltip ( tree_menu - > get_item_index ( TOOL_CENTER_PARENT ) , TTR ( " If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible. " ) ) ;
2023-04-04 15:59:50 +02:00
PopupMenu * resource_list = memnew ( PopupMenu ) ;
2024-03-26 17:47:30 +01:00
resource_list - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2023-04-04 15:59:50 +02:00
resource_list - > connect ( " about_to_popup " , callable_mp ( this , & SceneTreeDock : : _list_all_subresources ) . bind ( resource_list ) ) ;
resource_list - > connect ( " index_pressed " , callable_mp ( this , & SceneTreeDock : : _edit_subresource ) . bind ( resource_list ) ) ;
2023-11-28 17:33:04 +01:00
tree_menu - > add_submenu_node_item ( TTR ( " All Scene Sub-Resources " ) , resource_list ) ;
2022-09-16 15:10:28 +02:00
}
2016-05-16 17:23:40 +02:00
void SceneTreeDock : : _filter_changed ( const String & p_filter ) {
scene_tree - > set_filter ( p_filter ) ;
2022-09-16 15:10:28 +02:00
String warning = scene_tree - > get_filter_term_warning ( ) ;
if ( ! warning . is_empty ( ) ) {
2023-08-13 02:33:39 +02:00
filter - > add_theme_icon_override ( SNAME ( " clear " ) , get_editor_theme_icon ( SNAME ( " NodeWarning " ) ) ) ;
2022-09-16 15:10:28 +02:00
filter - > set_tooltip_text ( warning ) ;
} else {
filter - > remove_theme_icon_override ( SNAME ( " clear " ) ) ;
2023-12-18 00:07:46 +01:00
filter - > set_tooltip_text ( TTR ( " Filter nodes by entering a part of their name, type (if prefixed with \" type: \" or \" t: \" ) \n or group (if prefixed with \" group: \" or \" g: \" ). Filtering is case-insensitive. " ) ) ;
2022-09-16 15:10:28 +02:00
}
}
void SceneTreeDock : : _filter_gui_input ( const Ref < InputEvent > & p_event ) {
Ref < InputEventMouseButton > mb = p_event ;
if ( mb . is_null ( ) ) {
return ;
}
if ( mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : MIDDLE ) {
filter_quick_menu - > clear ( ) ;
_append_filter_options_to ( filter_quick_menu , false ) ;
filter_quick_menu - > set_position ( get_screen_position ( ) + get_local_mouse_position ( ) ) ;
filter_quick_menu - > reset_size ( ) ;
filter_quick_menu - > popup ( ) ;
filter_quick_menu - > grab_focus ( ) ;
accept_event ( ) ;
}
}
void SceneTreeDock : : _filter_option_selected ( int p_option ) {
String filter_parameter ;
switch ( p_option ) {
case FILTER_BY_TYPE : {
filter_parameter = " type " ;
} break ;
case FILTER_BY_GROUP : {
filter_parameter = " group " ;
} break ;
}
if ( ! filter_parameter . is_empty ( ) ) {
set_filter ( ( get_filter ( ) + " " + filter_parameter + " : " ) . strip_edges ( ) ) ;
filter - > set_caret_column ( filter - > get_text ( ) . length ( ) ) ;
filter - > grab_focus ( ) ;
}
}
void SceneTreeDock : : _append_filter_options_to ( PopupMenu * p_menu , bool p_include_separator ) {
if ( p_include_separator ) {
2024-04-19 07:31:40 +02:00
p_menu - > add_separator ( TTR ( " Filters " ) ) ;
2022-09-16 15:10:28 +02:00
}
p_menu - > add_item ( TTR ( " Filter by Type " ) , FILTER_BY_TYPE ) ;
p_menu - > add_item ( TTR ( " Filter by Group " ) , FILTER_BY_GROUP ) ;
p_menu - > set_item_tooltip ( p_menu - > get_item_index ( FILTER_BY_TYPE ) , TTR ( " Selects all Nodes of the given type. " ) ) ;
p_menu - > set_item_tooltip ( p_menu - > get_item_index ( FILTER_BY_GROUP ) , TTR ( " Selects all Nodes belonging to the given group. \n If empty, selects any Node belonging to any group. " ) ) ;
2016-05-16 17:23:40 +02:00
}
String SceneTreeDock : : get_filter ( ) {
return filter - > get_text ( ) ;
}
void SceneTreeDock : : set_filter ( const String & p_filter ) {
filter - > set_text ( p_filter ) ;
scene_tree - > set_filter ( p_filter ) ;
}
2024-02-15 17:25:58 +01:00
void SceneTreeDock : : save_branch_to_file ( const String & p_directory ) {
2021-09-09 00:43:14 +02:00
new_scene_from_dialog - > set_current_dir ( p_directory ) ;
_tool_selected ( TOOL_NEW_SCENE_FROM ) ;
}
2016-07-28 21:37:52 +02:00
void SceneTreeDock : : _focus_node ( ) {
Node * node = scene_tree - > get_selected ( ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( node ) ;
2016-07-28 21:37:52 +02:00
2017-01-03 03:03:46 +01:00
if ( node - > is_class ( " CanvasItem " ) ) {
2023-08-11 15:55:47 +02:00
CanvasItemEditorPlugin * editor = Object : : cast_to < CanvasItemEditorPlugin > ( editor_data - > get_editor_by_name ( " 2D " ) ) ;
2016-07-28 21:37:52 +02:00
editor - > get_canvas_item_editor ( ) - > focus_selection ( ) ;
} else {
2023-08-11 15:55:47 +02:00
Node3DEditorPlugin * editor = Object : : cast_to < Node3DEditorPlugin > ( editor_data - > get_editor_by_name ( " 3D " ) ) ;
2016-07-28 21:37:52 +02:00
editor - > get_spatial_editor ( ) - > get_editor_viewport ( 0 ) - > focus_selection ( ) ;
}
}
2019-10-21 06:57:10 +02:00
void SceneTreeDock : : attach_script_to_selected ( bool p_extend ) {
2020-05-31 19:31:45 +02:00
if ( ScriptServer : : get_language_count ( ) = = 0 ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Cannot attach a script: there are no languages registered. \n This is probably because this editor was built with all language modules disabled. " ) ) ;
return ;
}
2019-10-21 06:57:10 +02:00
if ( ! profile_allow_script_editing ) {
return ;
}
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2020-12-15 13:04:21 +01:00
if ( selection . is_empty ( ) ) {
2019-10-21 06:57:10 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-10-21 06:57:10 +02:00
Node * selected = scene_tree - > get_selected ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! selected ) {
2019-10-21 06:57:10 +02:00
selected = selection . front ( ) - > get ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-10-21 06:57:10 +02:00
Ref < Script > existing = selected - > get_script ( ) ;
2021-09-30 16:30:55 +02:00
String path = selected - > get_scene_file_path ( ) ;
2021-12-09 10:42:46 +01:00
if ( path . is_empty ( ) ) {
2021-09-30 16:30:55 +02:00
String root_path = editor_data - > get_edited_scene_root ( ) - > get_scene_file_path ( ) ;
2021-12-09 10:42:46 +01:00
if ( root_path . is_empty ( ) ) {
2022-08-30 02:34:01 +02:00
path = String ( " res:// " ) . path_join ( selected - > get_name ( ) ) ;
2019-10-21 06:57:10 +02:00
} else {
2022-08-30 02:34:01 +02:00
path = root_path . get_base_dir ( ) . path_join ( selected - > get_name ( ) ) ;
2019-10-21 06:57:10 +02:00
}
}
String inherits = selected - > get_class ( ) ;
if ( p_extend & & existing . is_valid ( ) ) {
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
ScriptLanguage * l = ScriptServer : : get_language ( i ) ;
if ( l - > get_type ( ) = = existing - > get_class ( ) ) {
String name = l - > get_global_class_name ( existing - > get_path ( ) ) ;
if ( ScriptServer : : is_global_class ( name ) & & EDITOR_GET ( " interface/editors/derive_script_globals_by_name " ) . operator bool ( ) ) {
inherits = name ;
} else if ( l - > can_inherit_from_file ( ) ) {
inherits = " \" " + existing - > get_path ( ) + " \" " ;
}
break ;
}
}
}
2020-02-21 18:28:45 +01:00
script_create_dialog - > connect ( " script_created " , callable_mp ( this , & SceneTreeDock : : _script_created ) ) ;
2024-05-14 14:28:18 +02:00
script_create_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _script_creation_closed ) ) ;
2023-01-21 12:25:29 +01:00
script_create_dialog - > connect ( " canceled " , callable_mp ( this , & SceneTreeDock : : _script_creation_closed ) ) ;
2019-10-21 06:57:10 +02:00
script_create_dialog - > set_inheritance_base_type ( " Node " ) ;
script_create_dialog - > config ( inherits , path ) ;
script_create_dialog - > popup_centered ( ) ;
}
void SceneTreeDock : : open_script_dialog ( Node * p_for_node , bool p_extend ) {
2016-09-13 00:31:07 +02:00
scene_tree - > set_selected ( p_for_node , false ) ;
2019-10-21 06:57:10 +02:00
if ( p_extend ) {
_tool_selected ( TOOL_EXTEND_SCRIPT ) ;
} else {
_tool_selected ( TOOL_ATTACH_SCRIPT ) ;
}
2016-09-13 00:31:07 +02:00
}
2021-09-17 16:35:24 +02:00
void SceneTreeDock : : attach_shader_to_selected ( int p_preferred_mode ) {
2021-06-04 11:24:08 +02:00
if ( selected_shader_material . is_null ( ) ) {
return ;
}
String path = selected_shader_material - > get_path ( ) ;
2021-12-09 10:42:46 +01:00
if ( path . is_empty ( ) ) {
2021-06-04 11:24:08 +02:00
String root_path ;
if ( editor_data - > get_edited_scene_root ( ) ) {
2021-09-30 16:30:55 +02:00
root_path = editor_data - > get_edited_scene_root ( ) - > get_scene_file_path ( ) ;
2021-06-04 11:24:08 +02:00
}
String shader_name ;
if ( selected_shader_material - > get_name ( ) . is_empty ( ) ) {
shader_name = root_path . get_file ( ) ;
} else {
shader_name = selected_shader_material - > get_name ( ) ;
}
2021-12-09 10:42:46 +01:00
if ( root_path . is_empty ( ) ) {
2022-08-30 02:34:01 +02:00
path = String ( " res:// " ) . path_join ( shader_name ) ;
2021-06-04 11:24:08 +02:00
} else {
2022-08-30 02:34:01 +02:00
path = root_path . get_base_dir ( ) . path_join ( shader_name ) ;
2021-06-04 11:24:08 +02:00
}
}
shader_create_dialog - > connect ( " shader_created " , callable_mp ( this , & SceneTreeDock : : _shader_created ) ) ;
2024-05-14 14:28:18 +02:00
shader_create_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _shader_creation_closed ) ) ;
2023-01-21 12:25:29 +01:00
shader_create_dialog - > connect ( " canceled " , callable_mp ( this , & SceneTreeDock : : _shader_creation_closed ) ) ;
2021-12-03 15:45:32 +01:00
shader_create_dialog - > config ( path , true , true , - 1 , p_preferred_mode ) ;
2021-06-04 11:24:08 +02:00
shader_create_dialog - > popup_centered ( ) ;
}
2022-04-07 12:23:40 +02:00
void SceneTreeDock : : open_shader_dialog ( const Ref < ShaderMaterial > & p_for_material , int p_preferred_mode ) {
2021-06-04 11:24:08 +02:00
selected_shader_material = p_for_material ;
2021-09-17 16:35:24 +02:00
attach_shader_to_selected ( p_preferred_mode ) ;
2021-06-04 11:24:08 +02:00
}
2020-08-25 01:32:58 +02:00
void SceneTreeDock : : open_add_child_dialog ( ) {
create_dialog - > set_base_type ( " CanvasItem " ) ;
_tool_selected ( TOOL_NEW , true ) ;
reset_create_dialog = true ;
}
void SceneTreeDock : : open_instance_child_dialog ( ) {
2021-06-18 00:03:09 +02:00
_tool_selected ( TOOL_INSTANTIATE , true ) ;
2020-08-25 01:32:58 +02:00
}
2023-07-14 17:34:35 +02:00
List < Node * > SceneTreeDock : : paste_nodes ( bool p_paste_as_sibling ) {
2022-01-18 16:28:44 +01:00
List < Node * > pasted_nodes ;
if ( node_clipboard . is_empty ( ) ) {
return pasted_nodes ;
}
bool has_cycle = false ;
if ( edited_scene & & ! edited_scene - > get_scene_file_path ( ) . is_empty ( ) ) {
for ( Node * E : node_clipboard ) {
if ( edited_scene - > get_scene_file_path ( ) = = E - > get_scene_file_path ( ) ) {
has_cycle = true ;
break ;
}
}
}
if ( has_cycle ) {
current_option = - 1 ;
accept - > set_text ( TTR ( " Can't paste root node into the same scene. " ) ) ;
accept - > popup_centered ( ) ;
return pasted_nodes ;
}
Node * paste_parent = edited_scene ;
2023-09-15 01:15:42 +02:00
Node * paste_sibling = nullptr ;
2022-01-18 16:28:44 +01:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . size ( ) > 0 ) {
paste_parent = selection . back ( ) - > get ( ) ;
}
2023-07-14 17:34:35 +02:00
if ( p_paste_as_sibling ) {
2023-09-15 01:15:42 +02:00
if ( paste_parent = = edited_scene ) {
return pasted_nodes ; // Don't paste as sibling of scene root.
}
paste_sibling = paste_parent ;
2023-07-14 17:34:35 +02:00
paste_parent = paste_parent - > get_parent ( ) ;
}
2022-01-18 16:28:44 +01:00
Node * owner = nullptr ;
if ( paste_parent ) {
owner = paste_parent - > get_owner ( ) ;
}
if ( ! owner ) {
owner = paste_parent ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * ur = EditorUndoRedoManager : : get_singleton ( ) ;
2023-09-07 14:34:18 +02:00
if ( paste_parent ) {
2023-09-15 01:15:42 +02:00
ur - > create_action ( vformat ( p_paste_as_sibling ? TTR ( " Paste Node(s) as Sibling of %s " ) : TTR ( " Paste Node(s) as Child of %s " ) , paste_sibling ? paste_sibling - > get_name ( ) : paste_parent - > get_name ( ) ) , UndoRedo : : MERGE_DISABLE , edited_scene ) ;
2023-09-07 14:34:18 +02:00
} else {
ur - > create_action ( TTR ( " Paste Node(s) as Root " ) , UndoRedo : : MERGE_DISABLE , edited_scene ) ;
}
2022-03-25 18:06:46 +01:00
ur - > add_do_method ( editor_selection , " clear " ) ;
2022-01-18 16:28:44 +01:00
2022-05-13 15:04:37 +02:00
HashMap < Ref < Resource > , Ref < Resource > > resource_remap ;
2022-01-18 16:28:44 +01:00
String target_scene ;
if ( edited_scene ) {
target_scene = edited_scene - > get_scene_file_path ( ) ;
}
if ( target_scene ! = clipboard_source_scene ) {
if ( ! clipboard_resource_remap . has ( target_scene ) ) {
2022-05-13 15:04:37 +02:00
HashMap < Ref < Resource > , Ref < Resource > > remap ;
2022-01-18 16:28:44 +01:00
for ( Node * E : node_clipboard ) {
_create_remap_for_node ( E , remap ) ;
}
clipboard_resource_remap [ target_scene ] = remap ;
}
resource_remap = clipboard_resource_remap [ target_scene ] ;
}
for ( Node * node : node_clipboard ) {
2022-05-13 15:04:37 +02:00
HashMap < const Node * , Node * > duplimap ;
2022-01-18 16:28:44 +01:00
Node * dup = node - > duplicate_from_editor ( duplimap , resource_remap ) ;
ERR_CONTINUE ( ! dup ) ;
pasted_nodes . push_back ( dup ) ;
if ( ! paste_parent ) {
paste_parent = dup ;
owner = dup ;
2022-12-27 08:26:43 +01:00
dup - > set_scene_file_path ( String ( ) ) ; // Make sure the scene path is empty, to avoid accidental references.
2022-03-25 18:06:46 +01:00
ur - > add_do_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , dup ) ;
2022-01-18 16:28:44 +01:00
} else {
2022-03-25 18:06:46 +01:00
ur - > add_do_method ( paste_parent , " add_child " , dup , true ) ;
2022-01-18 16:28:44 +01:00
}
for ( KeyValue < const Node * , Node * > & E2 : duplimap ) {
Node * d = E2 . value ;
2023-10-18 17:48:15 +02:00
// When copying, all nodes that should have an owner assigned here were given nullptr as an owner
// and added to the node_clipboard_edited_scene_owned list.
if ( d ! = dup & & E2 . key - > get_owner ( ) = = nullptr ) {
if ( node_clipboard_edited_scene_owned . find ( const_cast < Node * > ( E2 . key ) ) ) {
ur - > add_do_method ( d , " set_owner " , edited_scene ) ;
}
2022-01-18 16:28:44 +01:00
}
}
if ( dup ! = owner ) {
2023-10-18 17:48:15 +02:00
ur - > add_do_method ( dup , " set_owner " , edited_scene ) ;
2022-01-18 16:28:44 +01:00
}
2022-03-25 18:06:46 +01:00
ur - > add_do_method ( editor_selection , " add_node " , dup ) ;
2022-01-18 16:28:44 +01:00
if ( dup = = paste_parent ) {
2022-03-25 18:06:46 +01:00
ur - > add_undo_method ( EditorNode : : get_singleton ( ) , " set_edited_scene " , ( Object * ) nullptr ) ;
2022-01-18 16:28:44 +01:00
} else {
2022-03-25 18:06:46 +01:00
ur - > add_undo_method ( paste_parent , " remove_child " , dup ) ;
2022-01-18 16:28:44 +01:00
}
2022-03-25 18:06:46 +01:00
ur - > add_do_reference ( dup ) ;
2022-01-18 16:28:44 +01:00
if ( node_clipboard . size ( ) = = 1 ) {
2022-03-25 18:06:46 +01:00
ur - > add_do_method ( EditorNode : : get_singleton ( ) , " push_item " , dup ) ;
2022-01-18 16:28:44 +01:00
}
}
2022-03-25 18:06:46 +01:00
ur - > commit_action ( ) ;
2022-01-18 16:28:44 +01:00
return pasted_nodes ;
}
2022-01-18 16:35:12 +01:00
List < Node * > SceneTreeDock : : get_node_clipboard ( ) const {
return node_clipboard ;
}
2017-11-16 02:21:29 +01:00
void SceneTreeDock : : add_remote_tree_editor ( Control * p_remote ) {
2020-04-02 01:20:12 +02:00
ERR_FAIL_COND ( remote_tree ! = nullptr ) ;
2017-11-16 02:21:29 +01:00
add_child ( p_remote ) ;
remote_tree = p_remote ;
remote_tree - > hide ( ) ;
2022-08-31 00:52:05 +02:00
remote_tree - > connect ( " open " , callable_mp ( this , & SceneTreeDock : : _load_request ) ) ;
2017-11-16 02:21:29 +01:00
}
void SceneTreeDock : : show_remote_tree ( ) {
_remote_tree_selected ( ) ;
}
void SceneTreeDock : : hide_remote_tree ( ) {
_local_tree_selected ( ) ;
}
2017-11-22 14:50:54 +01:00
void SceneTreeDock : : show_tab_buttons ( ) {
button_hb - > show ( ) ;
}
void SceneTreeDock : : hide_tab_buttons ( ) {
button_hb - > hide ( ) ;
}
2017-11-16 02:21:29 +01:00
void SceneTreeDock : : _remote_tree_selected ( ) {
scene_tree - > hide ( ) ;
2019-05-30 02:20:59 +02:00
create_root_dialog - > hide ( ) ;
2020-05-14 16:41:43 +02:00
if ( remote_tree ) {
2017-11-16 02:21:29 +01:00
remote_tree - > show ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-16 02:21:29 +01:00
edit_remote - > set_pressed ( true ) ;
edit_local - > set_pressed ( false ) ;
2017-11-23 08:23:24 +01:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " remote_tree_selected " ) ) ;
2017-11-16 02:21:29 +01:00
}
void SceneTreeDock : : _local_tree_selected ( ) {
2020-06-10 00:06:15 +02:00
if ( ! bool ( EDITOR_GET ( " interface/editors/show_scene_tree_root_selection " ) ) | | get_tree ( ) - > get_edited_scene_root ( ) ! = nullptr ) {
scene_tree - > show ( ) ;
}
2020-05-14 16:41:43 +02:00
if ( remote_tree ) {
2017-11-16 02:21:29 +01:00
remote_tree - > hide ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-16 02:21:29 +01:00
edit_remote - > set_pressed ( false ) ;
edit_local - > set_pressed ( true ) ;
}
2024-08-05 21:14:24 +02:00
void SceneTreeDock : : _update_create_root_dialog ( bool p_initializing ) {
if ( ! p_initializing ) {
EditorSettings : : get_singleton ( ) - > set_setting ( " _use_favorites_root_selection " , node_shortcuts_toggle - > is_pressed ( ) ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
}
2022-09-03 23:10:07 +02:00
if ( node_shortcuts_toggle - > is_pressed ( ) ) {
for ( int i = 0 ; i < favorite_node_shortcuts - > get_child_count ( ) ; i + + ) {
2022-10-24 23:07:02 +02:00
favorite_node_shortcuts - > get_child ( i ) - > queue_free ( ) ;
2018-07-25 05:48:24 +02:00
}
2022-08-30 02:34:01 +02:00
Ref < FileAccess > f = FileAccess : : open ( EditorPaths : : get_singleton ( ) - > get_project_settings_dir ( ) . path_join ( " favorites.Node " ) , FileAccess : : READ ) ;
2022-03-23 10:08:58 +01:00
if ( f . is_valid ( ) ) {
2018-07-25 05:48:24 +02:00
while ( ! f - > eof_reached ( ) ) {
String l = f - > get_line ( ) . strip_edges ( ) ;
2021-12-09 10:42:46 +01:00
if ( ! l . is_empty ( ) ) {
2018-07-25 05:48:24 +02:00
Button * button = memnew ( Button ) ;
2022-09-03 23:10:07 +02:00
favorite_node_shortcuts - > add_child ( button ) ;
2020-07-24 15:14:56 +02:00
button - > set_text ( l ) ;
2022-01-19 00:05:43 +01:00
button - > set_clip_text ( true ) ;
2018-07-25 05:48:24 +02:00
String name = l . get_slicec ( ' ' , 0 ) ;
2020-05-14 16:41:43 +02:00
if ( ScriptServer : : is_global_class ( name ) ) {
2019-03-09 04:47:27 +01:00
name = ScriptServer : : get_global_class_native_base ( name ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-02 23:40:51 +02:00
button - > set_icon ( EditorNode : : get_singleton ( ) - > get_class_icon ( name ) ) ;
2024-05-14 09:40:21 +02:00
button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _favorite_root_selected ) . bind ( l ) ) ;
2018-07-25 05:48:24 +02:00
}
}
}
2022-09-03 23:10:07 +02:00
if ( ! favorite_node_shortcuts - > is_visible_in_tree ( ) ) {
favorite_node_shortcuts - > show ( ) ;
beginner_node_shortcuts - > hide ( ) ;
2018-07-25 05:48:24 +02:00
}
} else {
2022-09-03 23:10:07 +02:00
if ( ! beginner_node_shortcuts - > is_visible_in_tree ( ) ) {
beginner_node_shortcuts - > show ( ) ;
favorite_node_shortcuts - > hide ( ) ;
2018-07-25 05:48:24 +02:00
}
2022-01-18 16:28:44 +01:00
button_clipboard - > set_visible ( ! node_clipboard . is_empty ( ) ) ;
2018-07-25 05:48:24 +02:00
}
}
void SceneTreeDock : : _favorite_root_selected ( const String & p_class ) {
selected_favorite_root = p_class ;
2020-03-03 10:46:03 +01:00
_tool_selected ( TOOL_CREATE_FAVORITE ) ;
2018-07-25 05:48:24 +02:00
}
2019-04-09 00:18:03 +02:00
void SceneTreeDock : : _feature_profile_changed ( ) {
Ref < EditorFeatureProfile > profile = EditorFeatureProfileManager : : get_singleton ( ) - > get_current_profile ( ) ;
if ( profile . is_valid ( ) ) {
profile_allow_editing = ! profile - > is_feature_disabled ( EditorFeatureProfile : : FEATURE_SCENE_TREE ) ;
profile_allow_script_editing = ! profile - > is_feature_disabled ( EditorFeatureProfile : : FEATURE_SCRIPT ) ;
2019-11-10 16:58:56 +01:00
bool profile_allow_3d = ! profile - > is_feature_disabled ( EditorFeatureProfile : : FEATURE_3D ) ;
2019-04-09 00:18:03 +02:00
2019-11-10 16:58:56 +01:00
button_3d - > set_visible ( profile_allow_3d ) ;
2019-04-09 00:18:03 +02:00
button_add - > set_visible ( profile_allow_editing ) ;
button_instance - > set_visible ( profile_allow_editing ) ;
scene_tree - > set_can_rename ( profile_allow_editing ) ;
} else {
2019-11-10 16:58:56 +01:00
button_3d - > set_visible ( true ) ;
2019-04-09 00:18:03 +02:00
button_add - > set_visible ( true ) ;
button_instance - > set_visible ( true ) ;
scene_tree - > set_can_rename ( true ) ;
profile_allow_editing = true ;
profile_allow_script_editing = true ;
}
_update_script_button ( ) ;
}
2020-01-07 17:43:21 +01:00
void SceneTreeDock : : _clear_clipboard ( ) {
2021-07-16 05:45:57 +02:00
for ( Node * E : node_clipboard ) {
memdelete ( E ) ;
2020-01-07 17:43:21 +01:00
}
node_clipboard . clear ( ) ;
2023-10-18 17:48:15 +02:00
node_clipboard_edited_scene_owned . clear ( ) ;
2021-02-12 17:36:37 +01:00
clipboard_resource_remap . clear ( ) ;
}
2022-05-13 15:04:37 +02:00
void SceneTreeDock : : _create_remap_for_node ( Node * p_node , HashMap < Ref < Resource > , Ref < Resource > > & r_remap ) {
2021-02-12 17:36:37 +01:00
List < PropertyInfo > props ;
p_node - > get_property_list ( & props ) ;
2021-09-14 13:05:54 +02:00
Vector < SceneState : : PackState > states_stack ;
bool states_stack_ready = false ;
2021-02-12 17:36:37 +01:00
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : props ) {
2021-07-16 05:45:57 +02:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 17:36:37 +01:00
continue ;
}
2021-07-16 05:45:57 +02:00
Variant v = p_node - > get ( E . name ) ;
2021-08-26 21:37:17 +02:00
if ( v . is_ref_counted ( ) ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = v ;
2021-02-12 17:36:37 +01:00
if ( res . is_valid ( ) ) {
2021-09-14 13:05:54 +02:00
if ( ! states_stack_ready ) {
states_stack = PropertyUtils : : get_node_states_stack ( p_node ) ;
states_stack_ready = true ;
}
2021-12-11 14:03:48 +01:00
bool is_valid_default = false ;
Variant orig = PropertyUtils : : get_property_default_value ( p_node , E . name , & is_valid_default , & states_stack ) ;
2024-05-19 00:17:34 +02:00
if ( is_valid_default & & ! PropertyUtils : : is_property_value_different ( p_node , v , orig ) ) {
2021-09-14 13:05:54 +02:00
continue ;
2021-06-07 12:52:05 +02:00
}
2021-07-10 21:17:41 +02:00
if ( res - > is_built_in ( ) & & ! r_remap . has ( res ) ) {
2021-02-12 17:36:37 +01:00
_create_remap_for_resource ( res , r_remap ) ;
}
}
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_create_remap_for_node ( p_node - > get_child ( i ) , r_remap ) ;
}
}
2022-05-13 15:04:37 +02:00
void SceneTreeDock : : _create_remap_for_resource ( Ref < Resource > p_resource , HashMap < Ref < Resource > , Ref < Resource > > & r_remap ) {
2021-02-12 17:36:37 +01:00
r_remap [ p_resource ] = p_resource - > duplicate ( ) ;
List < PropertyInfo > props ;
p_resource - > get_property_list ( & props ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : props ) {
2021-07-16 05:45:57 +02:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 17:36:37 +01:00
continue ;
}
2021-07-16 05:45:57 +02:00
Variant v = p_resource - > get ( E . name ) ;
2021-08-26 21:37:17 +02:00
if ( v . is_ref_counted ( ) ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = v ;
2021-02-12 17:36:37 +01:00
if ( res . is_valid ( ) ) {
2021-07-10 21:17:41 +02:00
if ( res - > is_built_in ( ) & & ! r_remap . has ( res ) ) {
2021-02-12 17:36:37 +01:00
_create_remap_for_resource ( res , r_remap ) ;
}
}
}
}
2020-01-07 17:43:21 +01:00
}
2023-04-04 15:59:50 +02:00
void SceneTreeDock : : _list_all_subresources ( PopupMenu * p_menu ) {
p_menu - > clear ( ) ;
List < Pair < Ref < Resource > , Node * > > all_resources ;
if ( edited_scene ) {
_gather_resources ( edited_scene , all_resources ) ;
}
HashMap < String , List < Pair < Ref < Resource > , Node * > > > resources_by_type ;
HashMap < Ref < Resource > , int > unique_resources ;
for ( const Pair < Ref < Resource > , Node * > & pair : all_resources ) {
if ( ! unique_resources . has ( pair . first ) ) {
resources_by_type [ pair . first - > get_class ( ) ] . push_back ( pair ) ;
}
unique_resources [ pair . first ] + + ;
}
for ( KeyValue < String , List < Pair < Ref < Resource > , Node * > > > kv : resources_by_type ) {
p_menu - > add_icon_item ( EditorNode : : get_singleton ( ) - > get_class_icon ( kv . key ) , kv . key ) ;
p_menu - > set_item_as_separator ( - 1 , true ) ;
for ( const Pair < Ref < Resource > , Node * > & pair : kv . value ) {
String display_text ;
if ( pair . first - > get_name ( ) . is_empty ( ) ) {
display_text = vformat ( TTR ( " <Unnamed> at %s " ) , pair . second - > get_name ( ) ) ;
} else {
display_text = pair . first - > get_name ( ) ;
}
if ( unique_resources [ pair . first ] > 1 ) {
display_text + = " " + vformat ( TTR ( " (used %d times) " ) , unique_resources [ pair . first ] ) ;
}
p_menu - > add_item ( display_text ) ;
2024-01-16 23:51:57 +01:00
p_menu - > set_item_tooltip ( - 1 , pair . first - > get_path ( ) ) ;
2023-04-04 15:59:50 +02:00
p_menu - > set_item_metadata ( - 1 , pair . first - > get_instance_id ( ) ) ;
}
}
2023-05-26 14:18:44 +02:00
if ( resources_by_type . is_empty ( ) ) {
p_menu - > add_item ( TTR ( " None " ) ) ;
p_menu - > set_item_disabled ( - 1 , true ) ;
}
p_menu - > reset_size ( ) ;
2023-04-04 15:59:50 +02:00
}
void SceneTreeDock : : _gather_resources ( Node * p_node , List < Pair < Ref < Resource > , Node * > > & r_resources ) {
if ( p_node ! = edited_scene & & p_node - > get_owner ( ) ! = edited_scene ) {
return ;
}
List < PropertyInfo > pinfo ;
p_node - > get_property_list ( & pinfo ) ;
for ( const PropertyInfo & E : pinfo ) {
if ( ! ( E . usage & PROPERTY_USAGE_EDITOR ) ) {
continue ;
}
if ( E . hint ! = PROPERTY_HINT_RESOURCE_TYPE ) {
continue ;
}
Variant value = p_node - > get ( E . name ) ;
if ( value . get_type ( ) ! = Variant : : OBJECT ) {
continue ;
}
Ref < Resource > res = value ;
if ( res . is_null ( ) ) {
continue ;
}
2023-05-18 01:15:27 +02:00
if ( ! res - > is_built_in ( ) | | res - > get_path ( ) . get_slice ( " :: " , 0 ) ! = edited_scene - > get_scene_file_path ( ) ) {
// Ignore external and foreign resources.
continue ;
}
2023-04-04 15:59:50 +02:00
const Pair < Ref < Resource > , Node * > pair ( res , p_node ) ;
r_resources . push_back ( pair ) ;
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_gather_resources ( p_node - > get_child ( i ) , r_resources ) ;
}
}
void SceneTreeDock : : _edit_subresource ( int p_idx , const PopupMenu * p_from_menu ) {
const ObjectID & id = p_from_menu - > get_item_metadata ( p_idx ) ;
Object * obj = ObjectDB : : get_instance ( id ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( obj ) ;
2023-04-04 15:59:50 +02:00
_push_item ( obj ) ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeDock : : _bind_methods ( ) {
2024-08-30 22:56:53 +02:00
ClassDB : : bind_method ( D_METHOD ( " _post_do_create " ) , & SceneTreeDock : : _post_do_create ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " _set_owners " ) , & SceneTreeDock : : _set_owners ) ;
2022-05-12 17:36:37 +02:00
ClassDB : : bind_method ( D_METHOD ( " _reparent_nodes_to_root " ) , & SceneTreeDock : : _reparent_nodes_to_root ) ;
ClassDB : : bind_method ( D_METHOD ( " _reparent_nodes_to_paths_with_transform_and_name " ) , & SceneTreeDock : : _reparent_nodes_to_paths_with_transform_and_name ) ;
2021-08-22 17:37:22 +02:00
2018-03-07 20:08:13 +01:00
ClassDB : : bind_method ( D_METHOD ( " _update_script_button " ) , & SceneTreeDock : : _update_script_button ) ;
2017-03-05 16:44:50 +01:00
2021-06-18 00:03:09 +02:00
ClassDB : : bind_method ( D_METHOD ( " instantiate " ) , & SceneTreeDock : : instantiate ) ;
2019-08-20 18:06:21 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_tree_editor " ) , & SceneTreeDock : : get_tree_editor ) ;
2023-06-16 02:33:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " replace_node " ) , & SceneTreeDock : : _replace_node ) ;
2017-11-23 08:23:24 +01:00
ADD_SIGNAL ( MethodInfo ( " remote_tree_selected " ) ) ;
2020-08-25 01:32:58 +02:00
ADD_SIGNAL ( MethodInfo ( " add_node_used " ) ) ;
ADD_SIGNAL ( MethodInfo ( " node_created " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2014-02-10 02:10:30 +01:00
}
2021-04-27 17:43:49 +02:00
SceneTreeDock * SceneTreeDock : : singleton = nullptr ;
void SceneTreeDock : : _update_configuration_warning ( ) {
if ( singleton ) {
2023-12-18 15:46:56 +01:00
callable_mp ( singleton - > scene_tree , & SceneTreeEditor : : update_warning ) . call_deferred ( ) ;
2021-04-27 17:43:49 +02:00
}
}
2022-01-27 10:36:51 +01:00
SceneTreeDock : : SceneTreeDock ( Node * p_scene_root , EditorSelection * p_editor_selection , EditorData & p_editor_data ) {
2021-04-27 17:43:49 +02:00
singleton = this ;
2017-11-26 02:59:31 +01:00
set_name ( " Scene " ) ;
2020-04-02 01:20:12 +02:00
edited_scene = nullptr ;
2014-02-10 02:10:30 +01:00
editor_data = & p_editor_data ;
editor_selection = p_editor_selection ;
scene_root = p_scene_root ;
VBoxContainer * vbc = this ;
2016-05-17 23:27:15 +02:00
HBoxContainer * filter_hbc = memnew ( HBoxContainer ) ;
2022-02-08 10:14:58 +01:00
filter_hbc - > add_theme_constant_override ( " separate " , 0 ) ;
2014-02-10 02:10:30 +01:00
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " scene_tree/rename " , TTR ( " Rename " ) , Key : : F2 ) ;
ED_SHORTCUT_OVERRIDE ( " scene_tree/rename " , " macos " , Key : : ENTER ) ;
2021-11-12 19:54:12 +01:00
2024-02-17 14:14:53 +01:00
ED_SHORTCUT ( " scene_tree/batch_rename " , TTR ( " Batch Rename... " ) , KeyModifierMask : : SHIFT | Key : : F2 ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT_OVERRIDE ( " scene_tree/batch_rename " , " macos " , KeyModifierMask : : SHIFT | Key : : ENTER ) ;
2021-11-12 19:54:12 +01:00
2023-08-09 15:25:03 +02:00
ED_SHORTCUT ( " scene_tree/add_child_node " , TTR ( " Add Child Node... " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : A ) ;
ED_SHORTCUT ( " scene_tree/instantiate_scene " , TTR ( " Instantiate Child Scene... " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : A ) ;
2021-12-23 22:19:50 +01:00
ED_SHORTCUT ( " scene_tree/expand_collapse_all " , TTR ( " Expand/Collapse Branch " ) ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " scene_tree/cut_node " , TTR ( " Cut " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : X ) ;
ED_SHORTCUT ( " scene_tree/copy_node " , TTR ( " Copy " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : C ) ;
ED_SHORTCUT ( " scene_tree/paste_node " , TTR ( " Paste " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : V ) ;
2023-07-14 17:34:35 +02:00
ED_SHORTCUT ( " scene_tree/paste_node_as_sibling " , TTR ( " Paste as Sibling " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : V ) ;
2023-08-09 15:25:03 +02:00
ED_SHORTCUT ( " scene_tree/change_node_type " , TTR ( " Change Type... " ) ) ;
ED_SHORTCUT ( " scene_tree/attach_script " , TTR ( " Attach Script... " ) ) ;
ED_SHORTCUT ( " scene_tree/extend_script " , TTR ( " Extend Script... " ) ) ;
2020-05-09 18:59:19 +02:00
ED_SHORTCUT ( " scene_tree/detach_script " , TTR ( " Detach Script " ) ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " scene_tree/move_up " , TTR ( " Move Up " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : UP ) ;
ED_SHORTCUT ( " scene_tree/move_down " , TTR ( " Move Down " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : DOWN ) ;
ED_SHORTCUT ( " scene_tree/duplicate " , TTR ( " Duplicate " ) , KeyModifierMask : : CMD_OR_CTRL | Key : : D ) ;
2024-02-17 14:14:53 +01:00
ED_SHORTCUT ( " scene_tree/reparent " , TTR ( " Reparent... " ) ) ;
ED_SHORTCUT ( " scene_tree/reparent_to_new_node " , TTR ( " Reparent to New Node... " ) ) ;
2018-07-16 04:52:57 +02:00
ED_SHORTCUT ( " scene_tree/make_root " , TTR ( " Make Scene Root " ) ) ;
2024-02-17 14:14:53 +01:00
ED_SHORTCUT ( " scene_tree/save_branch_as_scene " , TTR ( " Save Branch as Scene... " ) ) ;
2022-09-02 11:37:48 +02:00
ED_SHORTCUT ( " scene_tree/copy_node_path " , TTR ( " Copy Node Path " ) , KeyModifierMask : : CMD_OR_CTRL | KeyModifierMask : : SHIFT | Key : : C ) ;
2024-01-20 20:05:28 +01:00
ED_SHORTCUT ( " scene_tree/show_in_file_system " , TTR ( " Show in FileSystem " ) ) ;
2022-08-31 09:44:33 +02:00
ED_SHORTCUT ( " scene_tree/toggle_unique_name " , TTR ( " Toggle Access as Unique Name " ) ) ;
2024-03-04 14:10:47 +01:00
ED_SHORTCUT ( " scene_tree/toggle_editable_children " , TTR ( " Toggle Editable Children " ) ) ;
2021-08-13 23:31:57 +02:00
ED_SHORTCUT ( " scene_tree/delete_no_confirm " , TTR ( " Delete (No Confirm) " ) , KeyModifierMask : : SHIFT | Key : : KEY_DELETE ) ;
ED_SHORTCUT ( " scene_tree/delete " , TTR ( " Delete " ) , Key : : KEY_DELETE ) ;
2016-06-19 21:33:42 +02:00
2020-06-19 20:49:04 +02:00
button_add = memnew ( Button ) ;
2023-12-21 01:52:20 +01:00
button_add - > set_theme_type_variation ( " FlatMenuButton " ) ;
2024-05-14 09:40:21 +02:00
button_add - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_NEW , false ) ) ;
2022-08-25 12:42:17 +02:00
button_add - > set_tooltip_text ( TTR ( " Add/Create a New Node. " ) ) ;
2019-03-06 05:19:34 +01:00
button_add - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) ) ;
filter_hbc - > add_child ( button_add ) ;
2014-02-10 02:10:30 +01:00
2020-06-19 20:49:04 +02:00
button_instance = memnew ( Button ) ;
2023-12-21 01:52:20 +01:00
button_instance - > set_theme_type_variation ( " FlatMenuButton " ) ;
2024-05-14 09:40:21 +02:00
button_instance - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_INSTANTIATE , false ) ) ;
2022-08-25 12:42:17 +02:00
button_instance - > set_tooltip_text ( TTR ( " Instantiate a scene file as a Node. Creates an inherited scene if no root node exists. " ) ) ;
2022-11-16 00:13:39 +01:00
button_instance - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/instantiate_scene " ) ) ;
2019-03-06 05:19:34 +01:00
filter_hbc - > add_child ( button_instance ) ;
2016-05-16 17:23:40 +02:00
vbc - > add_child ( filter_hbc ) ;
2022-09-16 15:10:28 +02:00
// The "Filter Nodes" text input above the Scene Tree Editor.
2016-05-16 17:23:40 +02:00
filter = memnew ( LineEdit ) ;
filter - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2023-09-15 02:20:57 +02:00
filter - > set_placeholder ( TTR ( " Filter: name, t:type, g:group " ) ) ;
filter - > set_tooltip_text ( TTR ( " Filter nodes by entering a part of their name, type (if prefixed with \" type: \" or \" t: \" ) \n or group (if prefixed with \" group: \" or \" g: \" ). Filtering is case-insensitive. " ) ) ;
2016-05-16 17:23:40 +02:00
filter_hbc - > add_child ( filter ) ;
2022-02-08 10:14:58 +01:00
filter - > add_theme_constant_override ( " minimum_character_width " , 0 ) ;
2024-05-14 11:42:00 +02:00
filter - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & SceneTreeDock : : _filter_changed ) ) ;
2024-05-13 16:56:03 +02:00
filter - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & SceneTreeDock : : _filter_gui_input ) ) ;
2024-05-14 14:13:31 +02:00
filter - > get_menu ( ) - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _filter_option_selected ) ) ;
2023-07-23 06:14:28 +02:00
_append_filter_options_to ( filter - > get_menu ( ) ) ;
2022-09-16 15:10:28 +02:00
filter_quick_menu = memnew ( PopupMenu ) ;
2023-12-21 01:52:20 +01:00
filter_quick_menu - > set_theme_type_variation ( " FlatMenuButton " ) ;
2024-05-14 14:13:31 +02:00
filter_quick_menu - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _filter_option_selected ) ) ;
2022-09-16 15:10:28 +02:00
filter - > add_child ( filter_quick_menu ) ;
2016-05-16 17:23:40 +02:00
2020-06-19 20:49:04 +02:00
button_create_script = memnew ( Button ) ;
2023-12-21 01:52:20 +01:00
button_create_script - > set_theme_type_variation ( " FlatMenuButton " ) ;
2024-05-14 09:40:21 +02:00
button_create_script - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_ATTACH_SCRIPT , false ) ) ;
2022-08-25 12:42:17 +02:00
button_create_script - > set_tooltip_text ( TTR ( " Attach a new or existing script to the selected node. " ) ) ;
2019-03-06 05:19:34 +01:00
button_create_script - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/attach_script " ) ) ;
filter_hbc - > add_child ( button_create_script ) ;
button_create_script - > hide ( ) ;
2020-06-19 20:49:04 +02:00
button_detach_script = memnew ( Button ) ;
2023-12-21 01:52:20 +01:00
button_detach_script - > set_theme_type_variation ( " FlatMenuButton " ) ;
2024-05-14 09:40:21 +02:00
button_detach_script - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( TOOL_DETACH_SCRIPT , false ) ) ;
2022-08-25 12:42:17 +02:00
button_detach_script - > set_tooltip_text ( TTR ( " Detach the script from the selected node. " ) ) ;
2020-05-09 18:59:19 +02:00
button_detach_script - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/detach_script " ) ) ;
filter_hbc - > add_child ( button_detach_script ) ;
button_detach_script - > hide ( ) ;
2016-10-31 15:45:20 +01:00
2022-01-20 12:54:36 +01:00
button_tree_menu = memnew ( MenuButton ) ;
2023-12-21 01:52:20 +01:00
button_tree_menu - > set_flat ( false ) ;
button_tree_menu - > set_theme_type_variation ( " FlatMenuButton " ) ;
2022-07-29 02:30:20 +02:00
button_tree_menu - > set_tooltip_text ( TTR ( " Extra scene options. " ) ) ;
2022-01-20 12:54:36 +01:00
button_tree_menu - > connect ( " about_to_popup " , callable_mp ( this , & SceneTreeDock : : _update_tree_menu ) ) ;
2021-08-12 01:34:52 +02:00
filter_hbc - > add_child ( button_tree_menu ) ;
2022-01-20 12:54:36 +01:00
PopupMenu * tree_menu = button_tree_menu - > get_popup ( ) ;
2024-05-14 14:13:31 +02:00
tree_menu - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( false ) ) ;
2022-01-20 12:54:36 +01:00
2017-11-16 02:21:29 +01:00
button_hb = memnew ( HBoxContainer ) ;
vbc - > add_child ( button_hb ) ;
2020-06-19 20:49:04 +02:00
edit_remote = memnew ( Button ) ;
2023-11-22 19:36:03 +01:00
edit_remote - > set_theme_type_variation ( " FlatButton " ) ;
2017-11-16 02:21:29 +01:00
edit_remote - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
edit_remote - > set_text ( TTR ( " Remote " ) ) ;
edit_remote - > set_toggle_mode ( true ) ;
2022-08-25 12:42:17 +02:00
edit_remote - > set_tooltip_text ( TTR ( " If selected, the Remote scene tree dock will cause the project to stutter every time it updates. \n Switch back to the Local scene tree dock to improve performance. " ) ) ;
2023-11-22 19:36:03 +01:00
button_hb - > add_child ( edit_remote ) ;
2024-05-14 09:40:21 +02:00
edit_remote - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _remote_tree_selected ) ) ;
2017-11-16 02:21:29 +01:00
2020-06-19 20:49:04 +02:00
edit_local = memnew ( Button ) ;
2023-11-22 19:36:03 +01:00
edit_local - > set_theme_type_variation ( " FlatButton " ) ;
2017-11-16 02:21:29 +01:00
edit_local - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
edit_local - > set_text ( TTR ( " Local " ) ) ;
edit_local - > set_toggle_mode ( true ) ;
2020-04-21 20:03:42 +02:00
edit_local - > set_pressed ( true ) ;
2023-11-22 19:36:03 +01:00
button_hb - > add_child ( edit_local ) ;
2024-05-14 09:40:21 +02:00
edit_local - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & SceneTreeDock : : _local_tree_selected ) ) ;
2017-11-16 02:21:29 +01:00
2020-04-02 01:20:12 +02:00
remote_tree = nullptr ;
2017-11-16 02:21:29 +01:00
button_hb - > hide ( ) ;
2018-07-16 04:11:29 +02:00
create_root_dialog = memnew ( VBoxContainer ) ;
vbc - > add_child ( create_root_dialog ) ;
2022-01-19 00:05:43 +01:00
create_root_dialog - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2018-07-16 04:11:29 +02:00
create_root_dialog - > hide ( ) ;
2014-02-10 02:10:30 +01:00
scene_tree = memnew ( SceneTreeEditor ( false , true , true ) ) ;
2017-11-16 02:21:29 +01:00
2014-02-10 02:10:30 +01:00
vbc - > add_child ( scene_tree ) ;
scene_tree - > set_v_size_flags ( SIZE_EXPAND | SIZE_FILL ) ;
2020-02-21 18:28:45 +01:00
scene_tree - > connect ( " rmb_pressed " , callable_mp ( this , & SceneTreeDock : : _tree_rmb ) ) ;
2017-03-05 16:44:50 +01:00
2024-06-24 12:17:45 +02:00
scene_tree - > connect ( " node_selected " , callable_mp ( this , & SceneTreeDock : : _node_selected ) , CONNECT_DEFERRED ) ;
2022-07-28 22:56:41 +02:00
scene_tree - > connect ( " node_renamed " , callable_mp ( this , & SceneTreeDock : : _node_renamed ) , CONNECT_DEFERRED ) ;
2020-02-21 18:28:45 +01:00
scene_tree - > connect ( " node_prerename " , callable_mp ( this , & SceneTreeDock : : _node_prerenamed ) ) ;
scene_tree - > connect ( " open " , callable_mp ( this , & SceneTreeDock : : _load_request ) ) ;
scene_tree - > connect ( " open_script " , callable_mp ( this , & SceneTreeDock : : _script_open_request ) ) ;
scene_tree - > connect ( " nodes_rearranged " , callable_mp ( this , & SceneTreeDock : : _nodes_dragged ) ) ;
scene_tree - > connect ( " files_dropped " , callable_mp ( this , & SceneTreeDock : : _files_dropped ) ) ;
scene_tree - > connect ( " script_dropped " , callable_mp ( this , & SceneTreeDock : : _script_dropped ) ) ;
scene_tree - > connect ( " nodes_dragged " , callable_mp ( this , & SceneTreeDock : : _nodes_drag_begin ) ) ;
2024-05-13 16:56:03 +02:00
scene_tree - > connect ( SceneStringName ( mouse_exited ) , callable_mp ( this , & SceneTreeDock : : _reset_hovering_timer ) ) ;
2016-05-11 16:46:08 +02:00
2024-05-13 16:56:03 +02:00
scene_tree - > get_scene_tree ( ) - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & SceneTreeDock : : _scene_tree_gui_input ) ) ;
2022-12-21 16:58:59 +01:00
scene_tree - > get_scene_tree ( ) - > connect ( " item_icon_double_clicked " , callable_mp ( this , & SceneTreeDock : : _focus_node ) ) ;
2021-06-19 04:25:24 +02:00
editor_selection - > connect ( " selection_changed " , callable_mp ( this , & SceneTreeDock : : _selection_changed ) ) ;
2016-07-28 21:37:52 +02:00
2022-08-29 12:10:32 +02:00
scene_tree - > set_as_scene_tree_dock ( ) ;
2014-02-10 02:10:30 +01:00
scene_tree - > set_editor_selection ( editor_selection ) ;
2024-04-07 23:04:36 +02:00
inspect_hovered_node_delay = memnew ( Timer ) ;
inspect_hovered_node_delay - > connect ( " timeout " , callable_mp ( this , & SceneTreeDock : : _inspect_hovered_node ) ) ;
inspect_hovered_node_delay - > set_one_shot ( true ) ;
add_child ( inspect_hovered_node_delay ) ;
2014-02-10 02:10:30 +01:00
create_dialog = memnew ( CreateDialog ) ;
create_dialog - > set_base_type ( " Node " ) ;
add_child ( create_dialog ) ;
2020-02-21 18:28:45 +01:00
create_dialog - > connect ( " create " , callable_mp ( this , & SceneTreeDock : : _create ) ) ;
2024-08-05 21:14:24 +02:00
create_dialog - > connect ( " favorites_updated " , callable_mp ( this , & SceneTreeDock : : _update_create_root_dialog ) . bind ( false ) ) ;
2014-02-10 02:10:30 +01:00
2021-08-31 03:28:37 +02:00
# ifdef MODULE_REGEX_ENABLED
2022-11-24 18:28:49 +01:00
rename_dialog = memnew ( RenameDialog ( scene_tree ) ) ;
2018-01-21 07:12:25 +01:00
add_child ( rename_dialog ) ;
2021-08-31 03:28:37 +02:00
# endif // MODULE_REGEX_ENABLED
2018-01-21 07:12:25 +01:00
2014-02-10 02:10:30 +01:00
script_create_dialog = memnew ( ScriptCreateDialog ) ;
2019-02-18 16:45:26 +01:00
script_create_dialog - > set_inheritance_base_type ( " Node " ) ;
2014-02-10 02:10:30 +01:00
add_child ( script_create_dialog ) ;
2015-11-27 21:42:48 +01:00
2021-06-04 11:24:08 +02:00
shader_create_dialog = memnew ( ShaderCreateDialog ) ;
add_child ( shader_create_dialog ) ;
2014-02-10 02:10:30 +01:00
reparent_dialog = memnew ( ReparentDialog ) ;
add_child ( reparent_dialog ) ;
2020-02-21 18:28:45 +01:00
reparent_dialog - > connect ( " reparent " , callable_mp ( this , & SceneTreeDock : : _node_reparent ) ) ;
2014-02-10 02:10:30 +01:00
accept = memnew ( AcceptDialog ) ;
add_child ( accept ) ;
2018-10-17 07:03:22 +02:00
quick_open = memnew ( EditorQuickOpen ) ;
add_child ( quick_open ) ;
2020-02-21 18:28:45 +01:00
quick_open - > connect ( " quick_open " , callable_mp ( this , & SceneTreeDock : : _quick_open ) ) ;
2020-09-17 03:40:00 +02:00
2022-01-11 14:59:52 +01:00
set_process_shortcut_input ( true ) ;
2014-02-10 02:10:30 +01:00
delete_dialog = memnew ( ConfirmationDialog ) ;
add_child ( delete_dialog ) ;
2024-05-14 14:28:18 +02:00
delete_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _delete_confirm ) . bind ( false ) ) ;
2015-11-27 21:42:48 +01:00
2022-02-27 03:15:01 +01:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
delete_dialog - > add_child ( vb ) ;
delete_dialog_label = memnew ( Label ) ;
vb - > add_child ( delete_dialog_label ) ;
delete_tracks_checkbox = memnew ( CheckBox ( TTR ( " Delete Related Animation Tracks " ) ) ) ;
delete_tracks_checkbox - > set_pressed ( true ) ;
vb - > add_child ( delete_tracks_checkbox ) ;
2018-09-13 00:49:12 +02:00
editable_instance_remove_dialog = memnew ( ConfirmationDialog ) ;
add_child ( editable_instance_remove_dialog ) ;
2024-05-14 14:28:18 +02:00
editable_instance_remove_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _toggle_editable_children_from_selection ) ) ;
2018-09-13 00:49:12 +02:00
2019-09-04 21:02:26 +02:00
placeholder_editable_instance_remove_dialog = memnew ( ConfirmationDialog ) ;
add_child ( placeholder_editable_instance_remove_dialog ) ;
2024-05-14 14:28:18 +02:00
placeholder_editable_instance_remove_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & SceneTreeDock : : _toggle_placeholder_from_selection ) ) ;
2019-09-04 21:02:26 +02:00
2015-11-27 21:42:48 +01:00
new_scene_from_dialog = memnew ( EditorFileDialog ) ;
2020-03-06 18:00:16 +01:00
new_scene_from_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2015-11-27 21:42:48 +01:00
add_child ( new_scene_from_dialog ) ;
2020-02-21 18:28:45 +01:00
new_scene_from_dialog - > connect ( " file_selected " , callable_mp ( this , & SceneTreeDock : : _new_scene_from ) ) ;
2016-05-11 16:46:08 +02:00
2016-05-16 04:41:48 +02:00
menu = memnew ( PopupMenu ) ;
add_child ( menu ) ;
2024-05-14 14:13:31 +02:00
menu - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( false ) ) ;
2020-03-12 13:37:40 +01:00
2017-12-17 15:55:24 +01:00
menu_subresources = memnew ( PopupMenu ) ;
2024-05-14 14:13:31 +02:00
menu_subresources - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _tool_selected ) . bind ( false ) ) ;
2017-12-17 15:55:24 +01:00
menu - > add_child ( menu_subresources ) ;
2014-02-10 02:10:30 +01:00
2021-07-16 16:27:59 +02:00
menu_properties = memnew ( PopupMenu ) ;
add_child ( menu_properties ) ;
2024-05-14 14:13:31 +02:00
menu_properties - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & SceneTreeDock : : _property_selected ) ) ;
2021-07-16 16:27:59 +02:00
2017-06-30 18:17:33 +02:00
clear_inherit_confirm = memnew ( ConfirmationDialog ) ;
clear_inherit_confirm - > set_text ( TTR ( " Clear Inheritance? (No Undo!) " ) ) ;
2022-07-08 02:31:19 +02:00
clear_inherit_confirm - > set_ok_button_text ( TTR ( " Clear " ) ) ;
2017-06-30 18:17:33 +02:00
add_child ( clear_inherit_confirm ) ;
2016-08-03 16:28:20 +02:00
set_process_input ( true ) ;
2018-07-16 04:11:29 +02:00
set_process ( true ) ;
EDITOR_DEF ( " interface/editors/show_scene_tree_root_selection " , true ) ;
2019-09-03 12:42:34 +02:00
EDITOR_DEF ( " interface/editors/derive_script_globals_by_name " , true ) ;
2022-02-27 03:15:01 +01:00
EDITOR_DEF ( " docks/scene_tree/ask_before_deleting_related_animation_tracks " , true ) ;
2024-08-09 22:43:37 +02:00
EDITOR_DEF ( " docks/scene_tree/ask_before_revoking_unique_name " , true ) ;
2018-07-25 05:48:24 +02:00
EDITOR_DEF ( " _use_favorites_root_selection " , false ) ;
2021-04-27 17:43:49 +02:00
Resource : : _update_configuration_warning = _update_configuration_warning ;
2014-02-10 02:10:30 +01:00
}
2020-01-07 17:43:21 +01:00
SceneTreeDock : : ~ SceneTreeDock ( ) {
2021-04-27 17:43:49 +02:00
singleton = nullptr ;
2020-01-07 17:43:21 +01:00
if ( ! node_clipboard . is_empty ( ) ) {
_clear_clipboard ( ) ;
}
}