2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* scene_tree_dock.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* 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-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "scene_tree_dock.h"
2017-01-16 07:04:19 +00:00
2017-03-05 15:44:50 +00:00
# include "core/io/resource_saver.h"
2019-04-24 12:49:00 +00:00
# include "core/os/input.h"
2017-08-26 15:46:49 +00:00
# include "core/os/keyboard.h"
# include "core/project_settings.h"
2018-06-07 15:46:14 +00:00
2019-12-24 07:17:23 +00:00
# include "editor/editor_feature_profile.h"
2017-08-26 15:46:49 +00:00
# include "editor/editor_node.h"
2019-12-24 07:17:23 +00:00
# include "editor/editor_scale.h"
2017-08-26 15:46:49 +00:00
# include "editor/editor_settings.h"
# include "editor/multi_node_edit.h"
2017-03-05 15:44:50 +00:00
# include "editor/plugins/animation_player_editor_plugin.h"
# include "editor/plugins/canvas_item_editor_plugin.h"
# include "editor/plugins/script_editor_plugin.h"
# include "editor/plugins/spatial_editor_plugin.h"
2017-08-26 15:46:49 +00:00
# include "editor/script_editor_debugger.h"
2017-03-05 15:44:50 +00:00
# include "scene/main/viewport.h"
2014-02-10 01:10:30 +00:00
# include "scene/resources/packed_scene.h"
2016-05-11 14:46:08 +00:00
2016-08-03 14:28:20 +00:00
void SceneTreeDock : : _nodes_drag_begin ( ) {
if ( restore_script_editor_on_drag ) {
EditorNode : : get_singleton ( ) - > set_visible_editor ( EditorNode : : EDITOR_SCRIPT ) ;
2017-03-05 15:44:50 +00:00
restore_script_editor_on_drag = false ;
2016-08-03 14:28:20 +00:00
}
}
2018-10-17 05:03:22 +00:00
void SceneTreeDock : : _quick_open ( ) {
Vector < String > files = quick_open - > get_selected_files ( ) ;
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
instance ( files [ i ] ) ;
}
}
2017-05-20 15:38:03 +00:00
void SceneTreeDock : : _input ( Ref < InputEvent > p_event ) {
2016-08-03 14:28:20 +00:00
2017-05-20 15:38:03 +00:00
Ref < InputEventMouseButton > mb = p_event ;
if ( mb . is_valid ( ) & & ! mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = BUTTON_LEFT ) {
2017-03-05 15:44:50 +00:00
restore_script_editor_on_drag = false ; //lost chance
2016-08-03 14:28:20 +00:00
}
}
2016-05-11 14:46:08 +00:00
2017-05-20 15:38:03 +00:00
void SceneTreeDock : : _unhandled_key_input ( Ref < InputEvent > p_event ) {
2014-02-10 01:10:30 +00:00
2016-06-27 23:14:59 +00:00
if ( get_viewport ( ) - > get_modal_stack_top ( ) )
return ; //ignore because of modal window
2018-02-04 00:58:51 +00:00
if ( get_focus_owner ( ) & & get_focus_owner ( ) - > is_text_field ( ) )
return ;
2017-05-20 15:38:03 +00:00
if ( ! p_event - > is_pressed ( ) | | p_event - > is_echo ( ) )
2014-02-10 01:10:30 +00:00
return ;
2018-01-21 06:12:25 +00:00
if ( ED_IS_SHORTCUT ( " scene_tree/batch_rename " , p_event ) ) {
_tool_selected ( TOOL_BATCH_RENAME ) ;
2018-05-11 05:48:14 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/rename " , p_event ) ) {
_tool_selected ( TOOL_RENAME ) ;
2018-01-21 06:12:25 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/add_child_node " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_NEW ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/instance_scene " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_INSTANCE ) ;
2018-07-07 14:51:18 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/expand_collapse_all " , p_event ) ) {
_tool_selected ( TOOL_EXPAND_COLLAPSE ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/change_node_type " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_REPLACE ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/duplicate " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_DUPLICATE ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/attach_script " , p_event ) ) {
2016-11-09 16:29:15 +00:00
_tool_selected ( TOOL_ATTACH_SCRIPT ) ;
2020-05-09 16:59:19 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/detach_script " , p_event ) ) {
_tool_selected ( TOOL_DETACH_SCRIPT ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/move_up " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_MOVE_UP ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/move_down " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_MOVE_DOWN ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/reparent " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_REPARENT ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/merge_from_scene " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_MERGE_FROM_SCENE ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/save_branch_as_scene " , p_event ) ) {
2016-06-19 19:33:42 +00:00
_tool_selected ( TOOL_NEW_SCENE_FROM ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/delete_no_confirm " , p_event ) ) {
2016-06-12 15:47:29 +00:00
_tool_selected ( TOOL_ERASE , true ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/copy_node_path " , p_event ) ) {
2017-01-15 10:56:30 +00:00
_tool_selected ( TOOL_COPY_NODE_PATH ) ;
2017-03-05 15:44:50 +00:00
} else if ( ED_IS_SHORTCUT ( " scene_tree/delete " , p_event ) ) {
2016-06-12 15:47:29 +00:00
_tool_selected ( TOOL_ERASE ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : instance ( const String & p_file ) {
2014-02-10 01:10:30 +00:00
Node * parent = scene_tree - > get_selected ( ) ;
2018-05-03 10:53:57 +00:00
if ( ! parent ) {
2018-05-26 14:09:07 +00:00
parent = edited_scene ;
2018-05-03 10:53:57 +00:00
} ;
if ( ! edited_scene ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " No parent to instance a child at. " ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2016-05-11 23:57:52 +00:00
return ;
2014-02-10 01:10:30 +00:00
} ;
2016-05-11 23:57:52 +00:00
ERR_FAIL_COND ( ! parent ) ;
2014-02-10 01:10:30 +00:00
2016-05-11 23:57:52 +00:00
Vector < String > scenes ;
scenes . push_back ( p_file ) ;
2017-03-05 15:44:50 +00:00
_perform_instance_scenes ( scenes , parent , - 1 ) ;
2016-05-11 23:57:52 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : instance_scenes ( const Vector < String > & p_files , Node * p_parent ) {
2016-07-20 17:09:03 +00:00
Node * parent = p_parent ;
if ( ! parent ) {
parent = scene_tree - > get_selected ( ) ;
}
if ( ! parent | | ! edited_scene ) {
accept - > set_text ( TTR ( " No parent to instance the scenes at. " ) ) ;
accept - > popup_centered_minsize ( ) ;
return ;
} ;
_perform_instance_scenes ( p_files , parent , - 1 ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _perform_instance_scenes ( const Vector < String > & p_files , Node * parent , int p_pos ) {
2015-01-19 20:47:50 +00:00
2016-05-11 23:57:52 +00:00
ERR_FAIL_COND ( ! parent ) ;
2015-01-20 14:05:22 +00:00
2017-03-05 15:44:50 +00:00
Vector < Node * > instances ;
2016-05-11 23:57:52 +00:00
2017-03-05 15:44:50 +00:00
bool error = false ;
2016-05-11 23:57:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_files . size ( ) ; i + + ) {
2016-05-11 23:57:52 +00:00
Ref < PackedScene > sdata = ResourceLoader : : load ( p_files [ i ] ) ;
if ( ! sdata . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
accept - > set_text ( vformat ( TTR ( " Error loading scene from %s " ) , p_files [ i ] ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2017-03-05 15:44:50 +00:00
error = true ;
2016-05-11 23:57:52 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
Node * instanced_scene = sdata - > instance ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
2016-05-11 23:57:52 +00:00
if ( ! instanced_scene ) {
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
accept - > set_text ( vformat ( TTR ( " Error instancing scene from %s " ) , p_files [ i ] ) ) ;
2016-05-11 23:57:52 +00:00
accept - > popup_centered_minsize ( ) ;
2017-03-05 15:44:50 +00:00
error = true ;
2016-05-11 23:57:52 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
if ( edited_scene - > get_filename ( ) ! = " " ) {
2016-05-11 23:57:52 +00:00
if ( _cyclical_dependency_exists ( edited_scene - > get_filename ( ) , instanced_scene ) ) {
2017-03-05 15:44:50 +00:00
accept - > set_text ( vformat ( TTR ( " Cannot instance the scene '%s' because the current scene exists within one of its nodes. " ) , p_files [ i ] ) ) ;
2016-05-11 23:57:52 +00:00
accept - > popup_centered_minsize ( ) ;
2017-03-05 15:44:50 +00:00
error = true ;
2016-05-11 23:57:52 +00:00
break ;
}
2015-01-20 14:05:22 +00:00
}
2016-05-11 23:57:52 +00:00
2017-07-19 20:00:46 +00:00
instanced_scene - > set_filename ( ProjectSettings : : get_singleton ( ) - > localize_path ( p_files [ i ] ) ) ;
2016-05-11 23:57:52 +00:00
instances . push_back ( instanced_scene ) ;
2014-02-10 01:10:30 +00:00
}
2016-05-11 23:57:52 +00:00
if ( error ) {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
2016-05-11 23:57:52 +00:00
memdelete ( instances [ i ] ) ;
}
return ;
}
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Instance Scene(s) " ) ) ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
Node * instanced_scene = instances [ i ] ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( parent , " add_child " , instanced_scene ) ;
if ( p_pos > = 0 ) {
editor_data - > get_undo_redo ( ) . add_do_method ( parent , " move_child " , instanced_scene , p_pos + i ) ;
2016-05-11 23:57:52 +00:00
}
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( instanced_scene , " set_owner " , edited_scene ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " clear " ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " add_node " , instanced_scene ) ;
2016-05-11 23:57:52 +00:00
editor_data - > get_undo_redo ( ) . add_do_reference ( instanced_scene ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( parent , " remove_child " , instanced_scene ) ;
2014-02-10 01:10:30 +00:00
2016-10-07 18:25:29 +00:00
String new_name = parent - > validate_child_name ( instanced_scene ) ;
2016-05-11 23:57:52 +00:00
ScriptEditorDebugger * sed = ScriptEditor : : get_singleton ( ) - > get_debugger ( ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( sed , " live_debug_instance_node " , edited_scene - > get_path_to ( parent ) , p_files [ i ] , new_name ) ;
2018-09-12 10:29:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( sed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( parent ) ) . plus_file ( new_name ) ) ) ;
2016-05-11 23:57:52 +00:00
}
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _replace_with_branch_scene ( const String & p_file , Node * base ) {
2016-10-11 14:54:46 +00:00
Ref < PackedScene > sdata = ResourceLoader : : load ( p_file ) ;
if ( ! sdata . is_valid ( ) ) {
2017-03-05 15:44:50 +00:00
accept - > set_text ( vformat ( TTR ( " Error loading scene from %s " ) , p_file ) ) ;
2016-10-11 14:54:46 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
2017-03-05 15:44:50 +00:00
Node * instanced_scene = sdata - > instance ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
2016-10-11 14:54:46 +00:00
if ( ! instanced_scene ) {
2017-03-05 15:44:50 +00:00
accept - > set_text ( vformat ( TTR ( " Error instancing scene from %s " ) , p_file ) ) ;
2016-10-11 14:54:46 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
2019-09-25 07:06:05 +00:00
UndoRedo * undo_redo = editor - > get_undo_redo ( ) ;
undo_redo - > create_action ( TTR ( " Replace with Branch Scene " ) ) ;
2016-10-11 14:54:46 +00:00
Node * parent = base - > get_parent ( ) ;
int pos = base - > get_index ( ) ;
2019-09-25 07:06:05 +00:00
undo_redo - > add_do_method ( parent , " remove_child " , base ) ;
undo_redo - > add_undo_method ( parent , " remove_child " , instanced_scene ) ;
undo_redo - > add_do_method ( parent , " add_child " , instanced_scene ) ;
undo_redo - > add_undo_method ( parent , " add_child " , base ) ;
undo_redo - > add_do_method ( parent , " move_child " , instanced_scene , pos ) ;
undo_redo - > add_undo_method ( parent , " move_child " , base , pos ) ;
List < Node * > owned ;
base - > get_owned_by ( base - > get_owner ( ) , & owned ) ;
Array owners ;
for ( List < Node * > : : Element * F = owned . front ( ) ; F ; F = F - > next ( ) ) {
owners . push_back ( F - > get ( ) ) ;
}
undo_redo - > add_do_method ( instanced_scene , " set_owner " , edited_scene ) ;
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 " ) ;
undo_redo - > add_do_method ( editor_selection , " add_node " , instanced_scene ) ;
undo_redo - > add_undo_method ( editor_selection , " add_node " , base ) ;
undo_redo - > add_do_property ( scene_tree , " set_selected " , instanced_scene ) ;
undo_redo - > add_undo_property ( scene_tree , " set_selected " , base ) ;
undo_redo - > add_do_reference ( instanced_scene ) ;
undo_redo - > add_undo_reference ( base ) ;
undo_redo - > commit_action ( ) ;
2016-10-11 14:54:46 +00:00
}
2017-03-05 15:44:50 +00:00
bool SceneTreeDock : : _cyclical_dependency_exists ( const String & p_target_scene_path , Node * p_desired_node ) {
2015-01-19 20:47:50 +00:00
int childCount = p_desired_node - > get_child_count ( ) ;
2019-03-14 05:04:16 +00:00
if ( _track_inherit ( p_target_scene_path , p_desired_node ) ) {
2015-01-19 20:47:50 +00:00
return true ;
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < childCount ; i + + ) {
Node * child = p_desired_node - > get_child ( i ) ;
2015-01-19 20:47:50 +00:00
2017-03-05 15:44:50 +00:00
if ( _cyclical_dependency_exists ( p_target_scene_path , child ) ) {
2015-01-19 20:47:50 +00:00
return true ;
}
}
return false ;
}
2019-03-14 05:04:16 +00: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 ) {
if ( p - > get_filename ( ) = = p_target_scene_path ) {
result = true ;
break ;
}
Ref < SceneState > ss = p - > get_scene_inherited_state ( ) ;
if ( ss . is_valid ( ) ) {
String path = ss - > get_path ( ) ;
Ref < PackedScene > data = ResourceLoader : : load ( path ) ;
if ( data . is_valid ( ) ) {
p = data - > instance ( PackedScene : : GEN_EDIT_STATE_INSTANCE ) ;
2019-07-23 07:14:31 +00:00
if ( ! p )
continue ;
2019-03-14 05:04:16 +00:00
instances . push_back ( p ) ;
} else
break ;
} else
break ;
}
for ( int i = 0 ; i < instances . size ( ) ; i + + ) {
memdelete ( instances [ i ] ) ;
}
return result ;
}
2014-05-09 10:50:48 +00:00
void SceneTreeDock : : _tool_selected ( int p_tool , bool p_confirm_override ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
current_option = p_tool ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
switch ( p_tool ) {
2014-02-10 01:10:30 +00:00
2018-01-21 06:12:25 +00:00
case TOOL_BATCH_RENAME : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2019-11-01 12:03:57 +00:00
if ( editor_selection - > get_selected_node_list ( ) . size ( ) > 1 ) {
2018-01-21 06:12:25 +00:00
rename_dialog - > popup_centered ( ) ;
}
} break ;
2018-05-11 05:48:14 +00:00
case TOOL_RENAME : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2018-05-11 05:48:14 +00:00
Tree * tree = scene_tree - > get_scene_tree ( ) ;
if ( tree - > is_anything_selected ( ) ) {
tree - > grab_focus ( ) ;
tree - > edit_selected ( ) ;
}
} break ;
2018-09-12 18:47:12 +00:00
case TOOL_NEW :
case TOOL_REPARENT_TO_NEW_NODE : {
2017-09-29 18:57:31 +00:00
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-09-29 18:57:31 +00:00
2020-06-29 16:23:49 +00:00
// Prefer nodes that inherit from the current scene root.
Node * current_edited_scene_root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
2017-09-29 18:57:31 +00:00
if ( current_edited_scene_root ) {
2020-06-29 16:23:49 +00:00
String root_class = current_edited_scene_root - > get_class_name ( ) ;
static Vector < String > preferred_types ;
if ( preferred_types . empty ( ) ) {
preferred_types . push_back ( " Control " ) ;
preferred_types . push_back ( " Node2D " ) ;
preferred_types . push_back ( " Node3D " ) ;
}
for ( int i = 0 ; i < preferred_types . size ( ) ; i + + ) {
if ( ClassDB : : is_parent_class ( root_class , preferred_types [ i ] ) ) {
create_dialog - > set_preferred_search_result_type ( preferred_types [ i ] ) ;
break ;
}
}
2017-09-29 18:57:31 +00:00
}
2020-06-29 16:23:49 +00:00
2017-03-16 20:58:45 +00:00
create_dialog - > popup_create ( true ) ;
2014-02-10 01:10:30 +00:00
} break ;
case TOOL_INSTANCE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 01:10:30 +00:00
Node * scene = edited_scene ;
if ( ! scene ) {
2016-05-16 15:23:40 +00:00
EditorNode : : get_singleton ( ) - > new_inherited_scene ( ) ;
2017-11-25 05:03:43 +00:00
break ;
2014-02-10 01:10:30 +00:00
}
2018-10-17 05:03:22 +00:00
quick_open - > popup_dialog ( " PackedScene " , true ) ;
quick_open - > set_title ( TTR ( " Instance Child Scene " ) ) ;
2014-02-10 01:10:30 +00:00
2018-07-07 14:51:18 +00:00
} break ;
case TOOL_EXPAND_COLLAPSE : {
if ( ! scene_tree - > get_selected ( ) )
break ;
Tree * tree = scene_tree - > get_scene_tree ( ) ;
TreeItem * selected_item = tree - > get_selected ( ) ;
if ( ! selected_item )
selected_item = tree - > get_root ( ) ;
bool collapsed = _is_collapsed_recursive ( selected_item ) ;
_set_collapsed_recursive ( selected_item , ! collapsed ) ;
tree - > ensure_cursor_is_visible ( ) ;
2014-02-10 01:10:30 +00:00
} break ;
case TOOL_REPLACE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2019-07-14 14:47:24 +00:00
Node * selected = scene_tree - > get_selected ( ) ;
2019-08-09 14:31:31 +00:00
if ( ! selected & & ! editor_selection - > get_selected_node_list ( ) . empty ( ) )
selected = editor_selection - > get_selected_node_list ( ) . front ( ) - > get ( ) ;
2019-07-14 14:47:24 +00:00
if ( selected )
create_dialog - > popup_create ( false , true , selected - > get_class ( ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
2019-10-21 04:57:10 +00:00
case TOOL_EXTEND_SCRIPT : {
attach_script_to_selected ( true ) ;
} break ;
2016-11-09 16:29:15 +00:00
case TOOL_ATTACH_SCRIPT : {
2019-10-21 04:57:10 +00:00
attach_script_to_selected ( false ) ;
2016-10-31 14:45:20 +00:00
} break ;
2020-05-09 16:59:19 +00:00
case TOOL_DETACH_SCRIPT : {
2016-10-31 14:45:20 +00:00
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_script_editing ) {
break ;
}
2019-03-06 06:11:02 +00:00
Array selection = editor_selection - > get_selected_nodes ( ) ;
2018-03-07 19:08:13 +00:00
if ( selection . empty ( ) )
return ;
2020-05-09 16:59:19 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Detach Script " ) ) ;
2018-03-07 19:08:13 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( editor , " push_item " , ( Script * ) NULL ) ;
2019-03-06 06:11:02 +00:00
for ( int i = 0 ; i < selection . size ( ) ; i + + ) {
2018-03-07 19:08:13 +00:00
2019-03-06 06:11:02 +00:00
Node * n = Object : : cast_to < Node > ( selection [ i ] ) ;
Ref < Script > existing = n - > get_script ( ) ;
2019-07-19 19:21:30 +00:00
Ref < Script > empty = EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( n ) ;
if ( existing ! = empty ) {
2019-03-06 06:11:02 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( n , " set_script " , empty ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( n , " set_script " , existing ) ;
2018-03-07 19:08:13 +00:00
}
2016-10-31 14:45:20 +00:00
}
2018-03-07 19:08:13 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( this , " _update_script_button " ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( this , " _update_script_button " ) ;
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2014-02-10 01:10:30 +00:00
} break ;
case TOOL_MOVE_UP :
case TOOL_MOVE_DOWN : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 01:10:30 +00:00
if ( ! scene_tree - > get_selected ( ) )
break ;
2017-03-05 15:44:50 +00:00
if ( scene_tree - > get_selected ( ) = = edited_scene ) {
2014-09-03 02:13:40 +00:00
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
2016-05-20 23:18:35 +00:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2014-02-10 01:10:30 +00:00
break ;
}
2014-09-03 02:13:40 +00:00
if ( ! _validate_no_foreign ( ) )
break ;
2014-12-18 02:38:24 +00:00
bool MOVING_DOWN = ( p_tool = = TOOL_MOVE_DOWN ) ;
bool MOVING_UP = ! MOVING_DOWN ;
2014-12-18 04:46:03 +00:00
Node * common_parent = scene_tree - > get_selected ( ) - > get_parent ( ) ;
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
selection . sort_custom < Node : : Comparator > ( ) ; // sort by index
2014-12-18 02:38:24 +00:00
if ( MOVING_DOWN )
selection . invert ( ) ;
2014-12-18 04:46:03 +00:00
int lowest_id = common_parent - > get_child_count ( ) - 1 ;
int highest_id = 0 ;
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
2014-12-18 02:38:24 +00:00
int index = E - > get ( ) - > get_index ( ) ;
2014-12-18 04:46:03 +00:00
if ( index > highest_id ) highest_id = index ;
if ( index < lowest_id ) lowest_id = index ;
if ( E - > get ( ) - > get_parent ( ) ! = common_parent )
common_parent = NULL ;
2014-12-18 02:38:24 +00:00
}
2014-12-18 04:46:03 +00:00
if ( ! common_parent | | ( MOVING_DOWN & & highest_id > = common_parent - > get_child_count ( ) - MOVING_DOWN ) | | ( MOVING_UP & & lowest_id = = 0 ) )
break ; // one or more nodes can not be moved
2014-12-18 02:38:24 +00:00
2016-05-04 01:25:37 +00:00
if ( selection . size ( ) = = 1 ) editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Move Node In Parent " ) ) ;
if ( selection . size ( ) > 1 ) editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Move Nodes In Parent " ) ) ;
2014-12-18 04:52:27 +00:00
2014-12-18 02:38:24 +00:00
for ( int i = 0 ; i < selection . size ( ) ; i + + ) {
Node * top_node = selection [ i ] ;
Node * bottom_node = selection [ selection . size ( ) - 1 - i ] ;
2016-01-17 23:03:57 +00:00
2014-12-18 02:38:24 +00:00
ERR_FAIL_COND ( ! top_node - > get_parent ( ) ) ;
ERR_FAIL_COND ( ! bottom_node - > get_parent ( ) ) ;
int bottom_node_pos = bottom_node - > get_index ( ) ;
2016-07-06 17:04:21 +00:00
int top_node_pos_next = top_node - > get_index ( ) + ( MOVING_DOWN ? 1 : - 1 ) ;
2014-12-18 02:38:24 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( top_node - > get_parent ( ) , " move_child " , top_node , top_node_pos_next ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( bottom_node - > get_parent ( ) , " move_child " , bottom_node , bottom_node_pos ) ;
}
2014-12-18 04:52:27 +00:00
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2014-02-10 01:10:30 +00:00
} break ;
case TOOL_DUPLICATE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 01:10:30 +00:00
if ( ! edited_scene )
break ;
if ( editor_selection - > is_selected ( edited_scene ) ) {
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
2016-05-20 23:18:35 +00:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2014-02-10 01:10:30 +00:00
break ;
}
2014-09-03 02:13:40 +00:00
if ( ! _validate_no_foreign ( ) )
break ;
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . size ( ) = = 0 )
2016-11-04 15:52:53 +00:00
break ;
2014-02-10 01:10:30 +00:00
2016-05-04 01:25:37 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Duplicate Node(s) " ) ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " clear " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * dupsingle = NULL ;
2019-05-14 00:11:06 +00:00
List < Node * > editable_children ;
2014-02-10 01:10:30 +00:00
2019-07-06 12:51:24 +00:00
selection . sort_custom < Node : : Comparator > ( ) ;
2020-05-01 08:45:55 +00:00
Node * add_below_node = selection . back ( ) - > get ( ) ;
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
Node * node = E - > get ( ) ;
Node * parent = node - > get_parent ( ) ;
2017-03-05 15:44:50 +00:00
List < Node * > owned ;
node - > get_owned_by ( node - > get_owner ( ) , & owned ) ;
2014-02-10 01:10:30 +00:00
2017-11-19 13:32:10 +00:00
Map < const Node * , Node * > duplimap ;
Node * dup = node - > duplicate_from_editor ( duplimap ) ;
2014-02-10 01:10:30 +00:00
2019-05-14 00:11:06 +00:00
if ( EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( node ) )
editable_children . push_back ( dup ) ;
2014-02-10 01:10:30 +00:00
ERR_CONTINUE ( ! dup ) ;
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) = = 1 )
dupsingle = dup ;
2014-02-10 01:10:30 +00:00
2016-10-07 18:25:29 +00:00
dup - > set_name ( parent - > validate_child_name ( dup ) ) ;
2014-02-10 01:10:30 +00:00
2020-05-01 08:45:55 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( parent , " add_child_below_node " , add_below_node , dup ) ;
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * F = owned . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 01:10:30 +00:00
if ( ! duplimap . has ( F - > get ( ) ) ) {
continue ;
}
2017-03-05 15:44:50 +00:00
Node * d = duplimap [ F - > get ( ) ] ;
2020-05-01 08:45:55 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( d , " set_owner " , node - > get_owner ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " add_node " , dup ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( parent , " remove_child " , dup ) ;
2014-02-10 01:10:30 +00:00
editor_data - > get_undo_redo ( ) . add_do_reference ( dup ) ;
2015-08-02 15:29:37 +00:00
ScriptEditorDebugger * sed = ScriptEditor : : get_singleton ( ) - > get_debugger ( ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( sed , " live_debug_duplicate_node " , edited_scene - > get_path_to ( node ) , dup - > get_name ( ) ) ;
2018-09-12 10:29:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( sed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( parent ) ) . plus_file ( dup - > get_name ( ) ) ) ) ;
2020-05-01 08:45:55 +00:00
add_below_node = dup ;
2014-02-10 01:10:30 +00:00
}
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
if ( dupsingle )
editor - > push_item ( dupsingle ) ;
2020-05-01 08:45:55 +00:00
for ( List < Node * > : : Element * E = editable_children . back ( ) ; E ; E = E - > prev ( ) )
2019-05-14 00:11:06 +00:00
_toggle_editable_children ( E - > get ( ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
case TOOL_REPARENT : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2014-02-10 01:10:30 +00:00
if ( ! scene_tree - > get_selected ( ) )
break ;
if ( editor_selection - > is_selected ( edited_scene ) ) {
2017-03-05 15:44:50 +00:00
current_option = - 1 ;
2016-05-20 23:18:35 +00:00
accept - > set_text ( TTR ( " This operation can't be done on the tree root. " ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2014-02-10 01:10:30 +00:00
break ;
}
2014-09-03 02:13:40 +00:00
if ( ! _validate_no_foreign ( ) )
break ;
2017-03-05 15:44:50 +00:00
List < Node * > nodes = editor_selection - > get_selected_node_list ( ) ;
Set < Node * > nodeset ;
for ( List < Node * > : : Element * E = nodes . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
nodeset . insert ( E - > get ( ) ) ;
}
reparent_dialog - > popup_centered_ratio ( ) ;
2017-03-05 15:44:50 +00:00
reparent_dialog - > set_current ( nodeset ) ;
2014-02-10 01:10:30 +00:00
2015-08-25 03:08:45 +00:00
} break ;
2018-07-16 02:52:57 +00:00
case TOOL_MAKE_ROOT : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2018-07-16 02:52:57 +00: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 ( ) ;
if ( node = = root )
return ;
2019-01-17 18:20:48 +00:00
//check that from node to root, all owners are right
2019-01-22 16:49:03 +00: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. " ) ) ;
accept - > popup_centered_minsize ( ) ;
return ;
}
2019-01-17 18:20:48 +00:00
if ( node - > get_owner ( ) ! = root ) {
accept - > set_text ( TTR ( " Node must belong to the edited scene to become root. " ) ) ;
accept - > popup_centered_minsize ( ) ;
return ;
}
if ( node - > get_filename ( ) ! = String ( ) ) {
accept - > set_text ( TTR ( " Instantiated scenes can't become root " ) ) ;
accept - > popup_centered_minsize ( ) ;
return ;
}
2019-02-21 19:41:01 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Make node as Root " ) ) ;
2018-07-16 02:52:57 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( node - > get_parent ( ) , " remove_child " , node ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( editor , " set_edited_scene " , node ) ;
2019-09-28 12:17:07 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( node , " add_child " , root ) ;
2018-07-16 02:52:57 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( node , " set_filename " , root - > get_filename ( ) ) ;
2018-09-29 22:04:18 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( root , " set_filename " , String ( ) ) ;
2018-10-10 22:45:44 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( node , " set_owner " , ( Object * ) NULL ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( root , " set_owner " , node ) ;
2018-09-29 22:04:18 +00:00
_node_replace_owner ( root , root , node , MODE_DO ) ;
2018-07-16 02:52:57 +00:00
2018-09-29 22:04:18 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( root , " set_filename " , root - > get_filename ( ) ) ;
2018-07-16 02:52:57 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_filename " , String ( ) ) ;
2018-09-29 22:04:18 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " remove_child " , root ) ;
2018-07-16 02:52:57 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( editor , " set_edited_scene " , root ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( node - > get_parent ( ) , " add_child " , node ) ;
2019-09-28 12:17:07 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( node - > get_parent ( ) , " move_child " , node , node - > get_index ( ) ) ;
2018-10-10 22:45:44 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( root , " set_owner " , ( Object * ) NULL ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_owner " , root ) ;
2018-09-29 22:04:18 +00:00
_node_replace_owner ( root , root , root , MODE_UNDO ) ;
2018-07-16 02:52:57 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( scene_tree , " update_tree " ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( scene_tree , " update_tree " ) ;
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
} break ;
2015-08-25 03:08:45 +00:00
case TOOL_MULTI_EDIT : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-03-05 15:44:50 +00:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
2015-08-25 03:08:45 +00:00
if ( ! root )
break ;
2017-03-05 15:44:50 +00:00
Ref < MultiNodeEdit > mne = memnew ( MultiNodeEdit ) ;
for ( const Map < Node * , Object * > : : Element * E = EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selection ( ) . front ( ) ; E ; E = E - > next ( ) ) {
2015-08-25 03:08:45 +00:00
mne - > add_node ( root - > get_path_to ( E - > key ( ) ) ) ;
}
EditorNode : : get_singleton ( ) - > push_item ( mne . ptr ( ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
2016-06-12 02:00:06 +00:00
2014-02-10 01:10:30 +00:00
case TOOL_ERASE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-03-05 15:44:50 +00:00
List < Node * > remove_list = editor_selection - > get_selected_node_list ( ) ;
2014-02-10 01:10:30 +00:00
if ( remove_list . empty ( ) )
return ;
2014-09-03 02:13:40 +00:00
if ( ! _validate_no_foreign ( ) )
break ;
2014-05-09 10:50:48 +00:00
if ( p_confirm_override ) {
_delete_confirm ( ) ;
} else {
2020-06-29 15:11:04 +00:00
String msg ;
if ( remove_list . size ( ) > 1 ) {
bool any_children = false ;
for ( int i = 0 ; ! any_children & & i < remove_list . size ( ) ; i + + ) {
any_children = remove_list [ i ] - > get_child_count ( ) > 0 ;
}
msg = vformat ( any_children ? TTR ( " Delete %d nodes and any children? " ) : TTR ( " Delete %d nodes? " ) , remove_list . size ( ) ) ;
2019-09-03 21:14:59 +00:00
} else {
2020-06-29 15:11:04 +00:00
Node * node = remove_list [ 0 ] ;
if ( node = = editor_data - > get_edited_scene_root ( ) ) {
msg = vformat ( TTR ( " Delete the root node \" %s \" ? " ) , node - > get_name ( ) ) ;
} else if ( node - > get_filename ( ) = = " " & & node - > get_child_count ( ) > 0 ) {
// Display this message only for non-instanced scenes
msg = vformat ( TTR ( " Delete node \" %s \" and its children? " ) , node - > get_name ( ) ) ;
} else {
msg = vformat ( TTR ( " Delete node \" %s \" ? " ) , node - > get_name ( ) ) ;
}
2019-09-03 21:14:59 +00:00
}
2020-06-29 15:11:04 +00:00
delete_dialog - > set_text ( msg ) ;
2019-09-03 21:14:59 +00: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.
delete_dialog - > set_size ( Size2 ( ) ) ;
2015-04-08 17:02:13 +00:00
delete_dialog - > popup_centered_minsize ( ) ;
2014-05-09 10:50:48 +00:00
}
2014-02-10 01:10:30 +00:00
2015-11-27 20:42:48 +00:00
} break ;
2016-05-27 17:18:40 +00:00
case TOOL_MERGE_FROM_SCENE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2016-05-27 17:18:40 +00:00
EditorNode : : get_singleton ( ) - > merge_from_scene ( ) ;
} break ;
2015-11-27 20:42:48 +00:00
case TOOL_NEW_SCENE_FROM : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2015-11-27 20:42:48 +00:00
Node * scene = editor_data - > get_edited_scene_root ( ) ;
2014-02-10 01:10:30 +00:00
2015-11-27 20:42:48 +00:00
if ( ! scene ) {
2016-05-20 23:18:35 +00:00
accept - > set_text ( TTR ( " This operation can't be done without a scene. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
break ;
}
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2015-11-27 20:42:48 +00:00
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) ! = 1 ) {
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " This operation requires a single selected node. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
break ;
}
Node * tocopy = selection . front ( ) - > get ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( tocopy = = scene ) {
2017-01-29 19:27:14 +00:00
accept - > set_text ( TTR ( " Can not perform with the root node. " ) ) ;
accept - > popup_centered_minsize ( ) ;
break ;
}
2017-03-05 15:44:50 +00:00
if ( tocopy ! = editor_data - > get_edited_scene_root ( ) & & tocopy - > get_filename ( ) ! = " " ) {
2016-05-20 23:18:35 +00:00
accept - > set_text ( TTR ( " This operation can't be done on instanced scenes. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
break ;
}
new_scene_from_dialog - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
List < String > extensions ;
2017-03-05 15:44:50 +00:00
Ref < PackedScene > sd = memnew ( PackedScene ) ;
ResourceSaver : : get_recognized_extensions ( sd , & extensions ) ;
2015-11-27 20:42:48 +00:00
new_scene_from_dialog - > clear_filters ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < extensions . size ( ) ; i + + ) {
new_scene_from_dialog - > add_filter ( " *. " + extensions [ i ] + " ; " + extensions [ i ] . to_upper ( ) ) ;
2015-11-27 20:42:48 +00:00
}
String existing ;
if ( extensions . size ( ) ) {
2016-05-23 13:27:58 +00:00
String root_name ( tocopy - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
existing = root_name + " . " + extensions . front ( ) - > get ( ) . to_lower ( ) ;
2015-11-27 20:42:48 +00:00
}
new_scene_from_dialog - > set_current_path ( existing ) ;
new_scene_from_dialog - > popup_centered_ratio ( ) ;
2018-04-22 17:36:01 +00:00
new_scene_from_dialog - > set_title ( TTR ( " Save New Scene As... " ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
2017-03-05 15:44:50 +00:00
case TOOL_COPY_NODE_PATH : {
2019-04-08 22:18:03 +00:00
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-01-15 10:56:30 +00:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
NodePath path = root - > get_path ( ) . rel_path_to ( node - > get_path ( ) ) ;
OS : : get_singleton ( ) - > set_clipboard ( path ) ;
}
}
} break ;
2018-10-03 09:25:18 +00:00
case TOOL_OPEN_DOCUMENTATION : {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
for ( int i = 0 ; i < selection . size ( ) ; i + + ) {
ScriptEditor : : get_singleton ( ) - > goto_help ( " class_name: " + selection [ i ] - > get_class ( ) ) ;
}
EditorNode : : get_singleton ( ) - > set_visible_editor ( EditorNode : : EDITOR_SCRIPT ) ;
} break ;
2017-06-30 16:17:33 +00:00
case TOOL_SCENE_EDITABLE_CHILDREN : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 16:17:33 +00:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( node ) ;
if ( editable ) {
2018-09-12 22:49:12 +00:00
editable_instance_remove_dialog - > set_text ( TTR ( " Disabling \" editable_instance \" will cause all properties of the node to be reverted to their default. " ) ) ;
editable_instance_remove_dialog - > popup_centered_minsize ( ) ;
break ;
2017-06-30 16:17:33 +00:00
}
2019-05-14 00:11:06 +00:00
_toggle_editable_children ( node ) ;
2017-06-30 16:17:33 +00:00
}
}
} break ;
case TOOL_SCENE_USE_PLACEHOLDER : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2019-09-04 19:02:26 +00:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( node ) ;
2017-06-30 16:17:33 +00:00
bool placeholder = node - > get_scene_instance_load_placeholder ( ) ;
2019-09-04 19:02:26 +00:00
// Fire confirmation dialog when children are editable.
if ( editable & & ! placeholder ) {
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. " ) ) ;
placeholder_editable_instance_remove_dialog - > popup_centered_minsize ( ) ;
break ;
}
2017-06-30 16:17:33 +00:00
placeholder = ! placeholder ;
2019-09-04 19:02:26 +00:00
2017-06-30 16:17:33 +00:00
if ( placeholder )
EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > set_editable_instance ( node , false ) ;
node - > set_scene_instance_load_placeholder ( placeholder ) ;
scene_tree - > update_tree ( ) ;
}
}
} break ;
2018-06-23 11:03:05 +00:00
case TOOL_SCENE_MAKE_LOCAL : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 16:17:33 +00:00
Node * root = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ;
UndoRedo * undo_redo = & editor_data - > get_undo_redo ( ) ;
if ( ! root )
break ;
ERR_FAIL_COND ( node - > get_filename ( ) = = String ( ) ) ;
2018-06-23 11:03:05 +00:00
undo_redo - > create_action ( TTR ( " Make Local " ) ) ;
2017-06-30 16:17:33 +00:00
undo_redo - > add_do_method ( node , " set_filename " , " " ) ;
undo_redo - > add_undo_method ( node , " set_filename " , node - > get_filename ( ) ) ;
_node_replace_owner ( node , node , root ) ;
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 : {
2019-04-08 22:18:03 +00:00
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 16:17:33 +00:00
scene_tree - > emit_signal ( " open " , node - > get_filename ( ) ) ;
}
}
} break ;
case TOOL_SCENE_CLEAR_INHERITANCE : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 16:17:33 +00:00
clear_inherit_confirm - > popup_centered_minsize ( ) ;
} break ;
case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM : {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_editing ) {
break ;
}
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
if ( node ) {
2017-06-30 16:17:33 +00:00
node - > set_scene_inherited_state ( Ref < SceneState > ( ) ) ;
scene_tree - > update_tree ( ) ;
2018-05-15 20:12:35 +00:00
EditorNode : : get_singleton ( ) - > get_inspector ( ) - > update_tree ( ) ;
2017-06-30 16:17:33 +00:00
}
}
} break ;
case TOOL_SCENE_OPEN_INHERITED : {
2019-04-08 22:18:03 +00:00
2017-06-30 16:17:33 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2017-09-06 21:50:18 +00:00
List < Node * > : : Element * e = selection . front ( ) ;
if ( e ) {
Node * node = e - > get ( ) ;
2019-04-08 09:03:37 +00:00
if ( node & & node - > get_scene_inherited_state ( ) . is_valid ( ) ) {
scene_tree - > emit_signal ( " open " , node - > get_scene_inherited_state ( ) - > get_path ( ) ) ;
2017-06-30 16:17:33 +00:00
}
}
} break ;
2018-07-16 02:11:29 +00:00
case TOOL_CREATE_2D_SCENE :
case TOOL_CREATE_3D_SCENE :
2018-07-25 03:48:24 +00:00
case TOOL_CREATE_USER_INTERFACE :
case TOOL_CREATE_FAVORITE : {
2018-07-16 02:11:29 +00:00
2018-10-04 16:54:20 +00:00
Node * new_node = NULL ;
2018-07-29 18:09:42 +00:00
2018-07-25 03:48:24 +00:00
if ( TOOL_CREATE_FAVORITE = = p_tool ) {
String name = selected_favorite_root . get_slicec ( ' ' , 0 ) ;
if ( ScriptServer : : is_global_class ( name ) ) {
2019-03-09 03:47:27 +00:00
new_node = Object : : cast_to < Node > ( ClassDB : : instance ( ScriptServer : : get_global_class_native_base ( name ) ) ) ;
2018-07-25 03:48:24 +00:00
Ref < Script > script = ResourceLoader : : load ( ScriptServer : : get_global_class_path ( name ) , " Script " ) ;
if ( new_node & & script . is_valid ( ) ) {
new_node - > set_script ( script . get_ref_ptr ( ) ) ;
new_node - > set_name ( name ) ;
}
} else {
new_node = Object : : cast_to < Node > ( ClassDB : : instance ( selected_favorite_root ) ) ;
}
2019-08-15 02:57:49 +00:00
2018-07-25 03:48:24 +00:00
if ( ! new_node ) {
new_node = memnew ( Node ) ;
2019-08-15 02:57:49 +00:00
ERR_PRINTS ( " Creating root from favorite ' " + selected_favorite_root + " ' failed. Creating 'Node' instead. " ) ;
2018-07-25 03:48:24 +00:00
}
} else {
switch ( p_tool ) {
case TOOL_CREATE_2D_SCENE : new_node = memnew ( Node2D ) ; break ;
case TOOL_CREATE_3D_SCENE : new_node = memnew ( Spatial ) ; break ;
case TOOL_CREATE_USER_INTERFACE : {
Control * node = memnew ( Control ) ;
node - > set_anchors_and_margins_preset ( PRESET_WIDE ) ; //more useful for resizable UIs.
new_node = node ;
} break ;
}
2018-07-16 02:11:29 +00:00
}
2019-02-21 19:41:01 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " New Scene Root " ) ) ;
2018-07-16 02:11:29 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( editor , " set_edited_scene " , new_node ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( scene_tree , " update_tree " ) ;
editor_data - > get_undo_redo ( ) . add_do_reference ( new_node ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( editor , " set_edited_scene " , ( Object * ) NULL ) ;
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2018-09-20 08:44:58 +00:00
editor - > edit_node ( new_node ) ;
2018-10-04 00:36:58 +00:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( new_node ) ;
2018-09-20 08:44:58 +00:00
2018-07-16 02:11:29 +00:00
} break ;
2017-06-05 03:12:19 +00:00
default : {
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 ] ) ;
ERR_FAIL_COND ( ! obj ) ;
editor - > push_item ( obj ) ;
}
}
2014-02-10 01:10:30 +00:00
}
}
2018-07-07 14:51:18 +00:00
void SceneTreeDock : : _node_collapsed ( Object * p_obj ) {
TreeItem * ti = Object : : cast_to < TreeItem > ( p_obj ) ;
if ( ! ti )
return ;
if ( Input : : get_singleton ( ) - > is_key_pressed ( KEY_SHIFT ) ) {
_set_collapsed_recursive ( ti , ti - > is_collapsed ( ) ) ;
}
}
2014-02-10 01:10:30 +00:00
void SceneTreeDock : : _notification ( int p_what ) {
2017-03-05 15:44:50 +00:00
switch ( p_what ) {
2015-06-14 05:13:47 +00:00
case NOTIFICATION_READY : {
if ( ! first_enter )
break ;
2017-03-05 15:44:50 +00:00
first_enter = false ;
2014-02-10 01:10:30 +00:00
2019-04-08 22:18:03 +00:00
EditorFeatureProfileManager : : get_singleton ( ) - > connect ( " current_feature_profile_changed " , this , " _feature_profile_changed " ) ;
2017-08-24 20:58:51 +00:00
CanvasItemEditorPlugin * canvas_item_plugin = Object : : cast_to < CanvasItemEditorPlugin > ( editor_data - > get_editor ( " 2D " ) ) ;
2015-06-14 05:13:47 +00:00
if ( canvas_item_plugin ) {
canvas_item_plugin - > get_canvas_item_editor ( ) - > connect ( " item_lock_status_changed " , scene_tree , " _update_tree " ) ;
canvas_item_plugin - > get_canvas_item_editor ( ) - > connect ( " item_group_status_changed " , scene_tree , " _update_tree " ) ;
scene_tree - > connect ( " node_changed " , canvas_item_plugin - > get_canvas_item_editor ( ) - > get_viewport_control ( ) , " update " ) ;
}
2017-10-23 19:21:15 +00:00
SpatialEditorPlugin * spatial_editor_plugin = Object : : cast_to < SpatialEditorPlugin > ( editor_data - > get_editor ( " 3D " ) ) ;
spatial_editor_plugin - > get_spatial_editor ( ) - > connect ( " item_lock_status_changed " , scene_tree , " _update_tree " ) ;
2019-04-17 16:24:28 +00:00
spatial_editor_plugin - > get_spatial_editor ( ) - > connect ( " item_group_status_changed " , scene_tree , " _update_tree " ) ;
2017-10-23 19:21:15 +00:00
2017-03-05 15:44:50 +00:00
button_add - > set_icon ( get_icon ( " Add " , " EditorIcons " ) ) ;
button_instance - > set_icon ( get_icon ( " Instance " , " EditorIcons " ) ) ;
button_create_script - > set_icon ( get_icon ( " ScriptCreate " , " EditorIcons " ) ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > set_icon ( get_icon ( " ScriptRemove " , " EditorIcons " ) ) ;
2016-08-07 22:22:33 +00:00
2018-08-11 10:04:19 +00:00
filter - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
2018-07-26 11:45:38 +00:00
filter - > set_clear_button_enabled ( true ) ;
2017-01-23 04:40:43 +00:00
2017-03-05 15:44:50 +00:00
EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > connect ( " selection_changed " , this , " _selection_changed " ) ;
2018-07-07 14:51:18 +00:00
scene_tree - > get_scene_tree ( ) - > connect ( " item_collapsed " , this , " _node_collapsed " ) ;
2015-08-25 03:08:45 +00:00
2018-07-25 03:48:24 +00:00
// create_root_dialog
HBoxContainer * top_row = memnew ( HBoxContainer ) ;
top_row - > set_name ( " NodeShortcutsTopRow " ) ;
top_row - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
top_row - > add_child ( memnew ( Label ( TTR ( " Create Root Node: " ) ) ) ) ;
top_row - > add_spacer ( ) ;
2018-07-16 02:11:29 +00:00
2018-07-25 03:48:24 +00:00
ToolButton * node_shortcuts_toggle = memnew ( ToolButton ) ;
node_shortcuts_toggle - > set_name ( " NodeShortcutsToggle " ) ;
node_shortcuts_toggle - > set_icon ( get_icon ( " Favorites " , " EditorIcons " ) ) ;
node_shortcuts_toggle - > set_toggle_mode ( true ) ;
node_shortcuts_toggle - > set_pressed ( EDITOR_GET ( " _use_favorites_root_selection " ) ) ;
node_shortcuts_toggle - > set_anchors_and_margins_preset ( Control : : PRESET_CENTER_RIGHT ) ;
node_shortcuts_toggle - > connect ( " pressed " , this , " _update_create_root_dialog " ) ;
top_row - > add_child ( node_shortcuts_toggle ) ;
create_root_dialog - > add_child ( top_row ) ;
VBoxContainer * node_shortcuts = memnew ( VBoxContainer ) ;
node_shortcuts - > set_name ( " NodeShortcuts " ) ;
2018-07-16 02:11:29 +00:00
2018-07-25 03:48:24 +00:00
VBoxContainer * beginner_node_shortcuts = memnew ( VBoxContainer ) ;
beginner_node_shortcuts - > set_name ( " BeginnerNodeShortcuts " ) ;
node_shortcuts - > add_child ( beginner_node_shortcuts ) ;
2020-09-17 02:33:19 +00:00
button_2d = memnew ( Button ) ;
2018-07-25 03:48:24 +00:00
beginner_node_shortcuts - > add_child ( button_2d ) ;
2018-07-16 02:11:29 +00:00
button_2d - > set_text ( TTR ( " 2D Scene " ) ) ;
button_2d - > set_icon ( get_icon ( " Node2D " , " EditorIcons " ) ) ;
button_2d - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_CREATE_2D_SCENE , false ) ) ;
2019-11-10 15:58:56 +00:00
button_3d = memnew ( Button ) ;
2018-07-25 03:48:24 +00:00
beginner_node_shortcuts - > add_child ( button_3d ) ;
2018-07-16 02:11:29 +00:00
button_3d - > set_text ( TTR ( " 3D Scene " ) ) ;
button_3d - > set_icon ( get_icon ( " Spatial " , " EditorIcons " ) ) ;
button_3d - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_CREATE_3D_SCENE , false ) ) ;
2020-09-17 02:33:19 +00:00
button_ui = memnew ( Button ) ;
2018-07-25 03:48:24 +00:00
beginner_node_shortcuts - > add_child ( button_ui ) ;
2018-07-16 02:11:29 +00:00
button_ui - > set_text ( TTR ( " User Interface " ) ) ;
button_ui - > set_icon ( get_icon ( " Control " , " EditorIcons " ) ) ;
button_ui - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_CREATE_USER_INTERFACE , false ) ) ;
2018-07-25 03:48:24 +00:00
VBoxContainer * favorite_node_shortcuts = memnew ( VBoxContainer ) ;
favorite_node_shortcuts - > set_name ( " FavoriteNodeShortcuts " ) ;
node_shortcuts - > add_child ( favorite_node_shortcuts ) ;
2020-09-17 02:33:19 +00:00
button_custom = memnew ( Button ) ;
2018-07-25 03:48:24 +00:00
node_shortcuts - > add_child ( button_custom ) ;
2019-03-12 15:12:14 +00:00
button_custom - > set_text ( TTR ( " Other Node " ) ) ;
2018-07-16 02:11:29 +00:00
button_custom - > set_icon ( get_icon ( " Add " , " EditorIcons " ) ) ;
button_custom - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_NEW , false ) ) ;
2018-07-25 03:48:24 +00:00
node_shortcuts - > add_spacer ( ) ;
create_root_dialog - > add_child ( node_shortcuts ) ;
_update_create_root_dialog ( ) ;
2014-02-10 01:10:30 +00:00
} break ;
2017-06-30 16:17:33 +00:00
case NOTIFICATION_ENTER_TREE : {
clear_inherit_confirm - > connect ( " confirmed " , this , " _tool_selected " , varray ( TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM ) ) ;
} break ;
case NOTIFICATION_EXIT_TREE : {
clear_inherit_confirm - > disconnect ( " confirmed " , this , " _tool_selected " ) ;
} break ;
2017-08-29 23:03:13 +00:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
button_add - > set_icon ( get_icon ( " Add " , " EditorIcons " ) ) ;
button_instance - > set_icon ( get_icon ( " Instance " , " EditorIcons " ) ) ;
button_create_script - > set_icon ( get_icon ( " ScriptCreate " , " EditorIcons " ) ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > set_icon ( get_icon ( " ScriptRemove " , " EditorIcons " ) ) ;
2020-09-17 02:33:19 +00:00
button_2d - > set_icon ( get_icon ( " Node2D " , " EditorIcons " ) ) ;
button_3d - > set_icon ( get_icon ( " Node3D " , " EditorIcons " ) ) ;
button_ui - > set_icon ( get_icon ( " Control " , " EditorIcons " ) ) ;
button_custom - > set_icon ( get_icon ( " Add " , " EditorIcons " ) ) ;
2017-08-29 23:03:13 +00:00
2018-08-11 10:04:19 +00:00
filter - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
2018-07-26 11:45:38 +00:00
filter - > set_clear_button_enabled ( true ) ;
2017-08-29 23:03:13 +00:00
} break ;
2018-07-16 02:11:29 +00:00
case NOTIFICATION_PROCESS : {
bool show_create_root = bool ( EDITOR_GET ( " interface/editors/show_scene_tree_root_selection " ) ) & & get_tree ( ) - > get_edited_scene_root ( ) = = NULL ;
2019-05-30 00:20:59 +00:00
if ( show_create_root ! = create_root_dialog - > is_visible_in_tree ( ) & & ! remote_tree - > is_visible ( ) ) {
2018-07-16 02:11:29 +00:00
if ( show_create_root ) {
create_root_dialog - > show ( ) ;
scene_tree - > hide ( ) ;
} else {
create_root_dialog - > hide ( ) ;
scene_tree - > show ( ) ;
}
}
} break ;
2017-06-30 16:17:33 +00:00
}
}
2018-07-16 02:52:57 +00:00
void SceneTreeDock : : _node_replace_owner ( Node * p_base , Node * p_node , Node * p_root , ReplaceOwnerMode p_mode ) {
2017-06-30 16:17:33 +00:00
2018-10-10 22:45:44 +00:00
if ( p_node - > get_owner ( ) = = p_base & & p_node ! = p_root ) {
2018-09-29 22:04:18 +00:00
UndoRedo * undo_redo = & editor_data - > get_undo_redo ( ) ;
switch ( p_mode ) {
case MODE_BIDI : {
undo_redo - > add_do_method ( p_node , " set_owner " , p_root ) ;
undo_redo - > add_undo_method ( p_node , " set_owner " , p_base ) ;
2018-07-16 02:52:57 +00:00
2018-09-29 22:04:18 +00:00
} break ;
case MODE_DO : {
undo_redo - > add_do_method ( p_node , " set_owner " , p_root ) ;
2018-07-16 02:52:57 +00:00
2018-09-29 22:04:18 +00:00
} break ;
case MODE_UNDO : {
undo_redo - > add_undo_method ( p_node , " set_owner " , p_root ) ;
2018-07-16 02:52:57 +00:00
2018-09-29 22:04:18 +00:00
} break ;
2017-06-30 16:17:33 +00:00
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2018-07-16 02:52:57 +00:00
_node_replace_owner ( p_base , p_node - > get_child ( i ) , p_root , p_mode ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _load_request ( const String & p_path ) {
2014-02-10 01:10:30 +00:00
editor - > open_request ( p_path ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _script_open_request ( const Ref < Script > & p_script ) {
2014-02-10 01:10:30 +00:00
editor - > edit_resource ( p_script ) ;
}
void SceneTreeDock : : _node_selected ( ) {
2017-03-05 15:44:50 +00:00
Node * node = scene_tree - > get_selected ( ) ;
2014-02-10 01:10:30 +00:00
if ( ! node ) {
editor - > push_item ( NULL ) ;
return ;
}
2017-01-13 13:45:50 +00:00
if ( ScriptEditor : : get_singleton ( ) - > is_visible_in_tree ( ) ) {
2017-03-05 15:44:50 +00:00
restore_script_editor_on_drag = true ;
2016-08-03 14:28:20 +00:00
}
2014-02-10 01:10:30 +00:00
editor - > push_item ( node ) ;
}
2014-09-21 15:56:19 +00:00
void SceneTreeDock : : _node_renamed ( ) {
_node_selected ( ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _set_owners ( Node * p_owner , const Array & p_nodes ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
Node * n = Object : : cast_to < Node > ( p_nodes [ i ] ) ;
2014-02-10 01:10:30 +00:00
if ( ! n )
continue ;
n - > set_owner ( p_owner ) ;
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _fill_path_renames ( Vector < StringName > base_path , Vector < StringName > new_base_path , Node * p_node , List < Pair < NodePath , NodePath > > * p_renames ) {
2014-02-10 01:10:30 +00:00
base_path . push_back ( p_node - > get_name ( ) ) ;
if ( new_base_path . size ( ) )
new_base_path . push_back ( p_node - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
NodePath from ( base_path , true ) ;
2014-02-10 01:10:30 +00:00
NodePath to ;
if ( new_base_path . size ( ) )
2017-03-05 15:44:50 +00:00
to = NodePath ( new_base_path , true ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Pair < NodePath , NodePath > npp ;
npp . first = from ;
npp . second = to ;
2014-02-10 01:10:30 +00:00
p_renames - > push_back ( npp ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
_fill_path_renames ( base_path , new_base_path , p_node - > get_child ( i ) , p_renames ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : fill_path_renames ( Node * p_node , Node * p_new_parent , List < Pair < NodePath , NodePath > > * p_renames ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( ! bool ( EDITOR_DEF ( " editors/animation/autorename_animation_tracks " , true ) ) )
2014-02-10 01:10:30 +00:00
return ;
Vector < StringName > base_path ;
Node * n = p_node - > get_parent ( ) ;
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
base_path . push_back ( n - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
n = n - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
base_path . invert ( ) ;
Vector < StringName > new_base_path ;
if ( p_new_parent ) {
n = p_new_parent ;
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
new_base_path . push_back ( n - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
n = n - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
new_base_path . invert ( ) ;
}
2017-03-05 15:44:50 +00:00
_fill_path_renames ( base_path , new_base_path , p_node , p_renames ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : perform_node_renames ( Node * p_base , List < Pair < NodePath , NodePath > > * p_renames , Map < Ref < Animation > , Set < int > > * r_rem_anims ) {
2014-02-10 01:10:30 +00:00
Map < Ref < Animation > , Set < int > > rem_anims ;
if ( ! r_rem_anims )
2017-03-05 15:44:50 +00:00
r_rem_anims = & rem_anims ;
2014-02-10 01:10:30 +00:00
if ( ! p_base ) {
2017-03-05 15:44:50 +00:00
p_base = edited_scene ;
2014-02-10 01:10:30 +00:00
}
if ( ! p_base )
return ;
2018-03-23 09:44:39 +00:00
// Renaming node paths used in script instances
if ( p_base - > get_script_instance ( ) ) {
ScriptInstance * si = p_base - > get_script_instance ( ) ;
if ( si ) {
List < PropertyInfo > properties ;
si - > get_property_list ( & properties ) ;
for ( List < PropertyInfo > : : Element * E = properties . front ( ) ; E ; E = E - > next ( ) ) {
String propertyname = E - > get ( ) . name ;
Variant p = p_base - > get ( propertyname ) ;
if ( p . get_type ( ) = = Variant : : NODE_PATH ) {
// Goes through all paths to check if its matching
2019-02-12 20:10:08 +00:00
for ( List < Pair < NodePath , NodePath > > : : Element * F = p_renames - > front ( ) ; F ; F = F - > next ( ) ) {
2018-03-23 09:44:39 +00:00
NodePath root_path = p_base - > get_path ( ) ;
2019-02-12 20:10:08 +00:00
NodePath rel_path_old = root_path . rel_path_to ( F - > get ( ) . first ) ;
2018-03-30 12:49:21 +00:00
2019-02-12 20:10:08 +00:00
NodePath rel_path_new = F - > get ( ) . second ;
2018-03-30 12:49:21 +00:00
// if not empty, get new relative path
2019-02-12 20:10:08 +00:00
if ( F - > get ( ) . second ! = NodePath ( ) ) {
rel_path_new = root_path . rel_path_to ( F - > get ( ) . second ) ;
2018-03-30 12:49:21 +00:00
}
2018-03-23 09:44:39 +00:00
// if old path detected, then it needs to be replaced with the new one
if ( p = = rel_path_old ) {
editor_data - > get_undo_redo ( ) . add_do_property ( p_base , propertyname , rel_path_new ) ;
editor_data - > get_undo_redo ( ) . add_undo_property ( p_base , propertyname , rel_path_old ) ;
p_base - > set ( propertyname , rel_path_new ) ;
break ;
}
}
}
}
}
}
bool autorename_animation_tracks = bool ( EDITOR_DEF ( " editors/animation/autorename_animation_tracks " , true ) ) ;
if ( autorename_animation_tracks & & Object : : cast_to < AnimationPlayer > ( p_base ) ) {
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
AnimationPlayer * ap = Object : : cast_to < AnimationPlayer > ( p_base ) ;
2014-02-10 01:10:30 +00:00
List < StringName > anims ;
ap - > get_animation_list ( & anims ) ;
Node * root = ap - > get_node ( ap - > get_root ( ) ) ;
if ( root ) {
2017-03-05 15:44:50 +00:00
NodePath root_path = root - > get_path ( ) ;
NodePath new_root_path = root_path ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( List < Pair < NodePath , NodePath > > : : Element * E = p_renames - > front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . first = = root_path ) {
new_root_path = E - > get ( ) . second ;
2014-02-10 01:10:30 +00:00
break ;
}
}
2017-03-05 15:44:50 +00:00
if ( new_root_path ! = NodePath ( ) ) {
2014-02-10 01:10:30 +00:00
//will not be erased
2017-03-05 15:44:50 +00:00
for ( List < StringName > : : Element * E = anims . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Ref < Animation > anim = ap - > get_animation ( E - > get ( ) ) ;
2014-02-10 01:10:30 +00:00
if ( ! r_rem_anims - > has ( anim ) ) {
2017-03-05 15:44:50 +00:00
r_rem_anims - > insert ( anim , Set < int > ( ) ) ;
2014-02-10 01:10:30 +00:00
Set < int > & ran = r_rem_anims - > find ( anim ) - > get ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + )
2014-02-10 01:10:30 +00:00
ran . insert ( i ) ;
}
Set < int > & ran = r_rem_anims - > find ( anim ) - > get ( ) ;
if ( anim . is_null ( ) )
continue ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
NodePath track_np = anim - > track_get_path ( i ) ;
2014-02-10 01:10:30 +00:00
Node * n = root - > get_node ( track_np ) ;
if ( ! n ) {
continue ;
}
NodePath old_np = n - > get_path ( ) ;
if ( ! ran . has ( i ) )
continue ; //channel was removed
2019-02-12 20:10:08 +00:00
for ( List < Pair < NodePath , NodePath > > : : Element * F = p_renames - > front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2019-02-12 20:10:08 +00:00
if ( F - > get ( ) . first = = old_np ) {
2014-02-10 01:10:30 +00:00
2019-02-12 20:10:08 +00:00
if ( F - > get ( ) . second = = NodePath ( ) ) {
2014-02-10 01:10:30 +00:00
//will be erased
2017-03-05 15:44:50 +00:00
int idx = 0 ;
Set < int > : : Element * EI = ran . front ( ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! EI ) ; //bug
2017-03-05 15:44:50 +00:00
while ( EI - > get ( ) ! = i ) {
2014-02-10 01:10:30 +00:00
idx + + ;
2017-03-05 15:44:50 +00:00
EI = EI - > next ( ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! EI ) ; //another bug
}
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( anim . ptr ( ) , " remove_track " , idx ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( anim . ptr ( ) , " add_track " , anim - > track_get_type ( i ) , idx ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( anim . ptr ( ) , " track_set_path " , idx , track_np ) ;
editor_data - > get_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 + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
editor_data - > get_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 ) ) ;
2014-02-10 01:10:30 +00:00
}
ran . erase ( i ) ; //byebye channel
} else {
//will be renamed
2019-02-12 20:10:08 +00:00
NodePath rel_path = new_root_path . rel_path_to ( F - > get ( ) . second ) ;
2014-02-10 01:10:30 +00:00
2017-05-30 20:20:15 +00:00
NodePath new_path = NodePath ( rel_path . get_names ( ) , track_np . get_subnames ( ) , false ) ;
2017-03-05 15:44:50 +00:00
if ( new_path = = track_np )
2014-02-10 01:10:30 +00:00
continue ; //bleh
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( anim . ptr ( ) , " track_set_path " , i , new_path ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( anim . ptr ( ) , " track_set_path " , i , track_np ) ;
2014-02-10 01:10:30 +00:00
}
}
}
}
}
}
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_base - > get_child_count ( ) ; i + + )
perform_node_renames ( p_base - > get_child ( i ) , p_renames , r_rem_anims ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _node_prerenamed ( Node * p_node , const String & p_new_name ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
List < Pair < NodePath , NodePath > > path_renames ;
2014-02-10 01:10:30 +00:00
Vector < StringName > base_path ;
Node * n = p_node - > get_parent ( ) ;
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
base_path . push_back ( n - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
n = n - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
base_path . invert ( ) ;
2017-03-05 15:44:50 +00:00
Vector < StringName > new_base_path = base_path ;
2014-02-10 01:10:30 +00:00
base_path . push_back ( p_node - > get_name ( ) ) ;
new_base_path . push_back ( p_new_name ) ;
2017-03-05 15:44:50 +00:00
Pair < NodePath , NodePath > npp ;
npp . first = NodePath ( base_path , true ) ;
npp . second = NodePath ( new_base_path , true ) ;
2014-02-10 01:10:30 +00:00
path_renames . push_back ( npp ) ;
2017-03-05 15:44:50 +00: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 ) , & path_renames ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
perform_node_renames ( NULL , & path_renames ) ;
2014-02-10 01:10:30 +00:00
}
2014-09-03 02:13:40 +00:00
bool SceneTreeDock : : _validate_no_foreign ( ) {
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2014-09-03 02:13:40 +00:00
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
2014-09-03 02:13:40 +00:00
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) ! = edited_scene & & E - > get ( ) - > get_owner ( ) ! = edited_scene ) {
2014-09-03 02:13:40 +00:00
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " Can't operate on nodes from a foreign scene! " ) ) ;
2015-04-08 17:02:13 +00:00
accept - > popup_centered_minsize ( ) ;
2014-09-03 02:13:40 +00:00
return false ;
}
2015-10-10 12:09:09 +00:00
2018-10-23 19:55:25 +00:00
// 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
2019-09-15 00:07:55 +00:00
// delete it.
2018-10-23 19:55:25 +00:00
if ( edited_scene - > get_scene_inherited_state ( ) . is_valid ( ) & & edited_scene = = E - > get ( ) ) {
continue ;
}
2017-03-05 15:44:50 +00:00
if ( edited_scene - > get_scene_inherited_state ( ) . is_valid ( ) & & edited_scene - > get_scene_inherited_state ( ) - > find_node_by_path ( edited_scene - > get_path_to ( E - > get ( ) ) ) > = 0 ) {
2015-10-10 12:09:09 +00:00
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " Can't operate on nodes the current scene inherits from! " ) ) ;
2015-10-10 12:09:09 +00:00
accept - > popup_centered_minsize ( ) ;
return false ;
}
2014-09-03 02:13:40 +00:00
}
return true ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _node_reparent ( NodePath p_path , bool p_keep_global_xform ) {
2014-02-10 01:10:30 +00:00
Node * new_parent = scene_root - > get_node ( p_path ) ;
ERR_FAIL_COND ( ! new_parent ) ;
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2016-05-11 14:46:08 +00:00
if ( selection . empty ( ) )
2019-09-15 00:07:55 +00:00
return ; // Nothing to reparent.
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
Vector < Node * > nodes ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
2016-05-11 14:46:08 +00:00
nodes . push_back ( E - > get ( ) ) ;
}
2017-03-05 15:44:50 +00:00
_do_reparent ( new_parent , - 1 , nodes , p_keep_global_xform ) ;
2016-05-11 14:46:08 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _do_reparent ( Node * p_new_parent , int p_position_in_parent , Vector < Node * > p_nodes , bool p_keep_global_xform ) {
2016-05-11 14:46:08 +00:00
Node * new_parent = p_new_parent ;
ERR_FAIL_COND ( ! new_parent ) ;
2019-09-15 00:07:55 +00:00
if ( p_nodes . size ( ) = = 0 )
return ; // Nothing to reparent.
2019-09-22 10:44:59 +00:00
p_nodes . sort_custom < Node : : Comparator > ( ) ; //Makes result reliable.
bool no_change = true ;
2019-09-15 00:07:55 +00:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
if ( p_nodes [ ni ] = = p_new_parent )
return ; // Attempt to reparent to itself.
2019-09-22 10:44:59 +00:00
if ( p_nodes [ ni ] - > get_parent ( ) ! = p_new_parent | | p_position_in_parent + ni ! = p_nodes [ ni ] - > get_position_in_parent ( ) )
no_change = false ;
2019-09-15 00:07:55 +00:00
}
2019-09-22 10:44:59 +00:00
if ( no_change )
return ; // Position and parent didn't change.
2019-09-15 00:07:55 +00:00
2017-03-05 15:44:50 +00:00
Node * validate = new_parent ;
while ( validate ) {
2014-02-10 01:10:30 +00:00
2019-09-15 00:07:55 +00:00
ERR_FAIL_COND_MSG ( p_nodes . find ( validate ) ! = - 1 , " Selection changed at some point. Can't reparent. " ) ;
2017-03-05 15:44:50 +00:00
validate = validate - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
2019-09-15 00:07:55 +00:00
// Sort by tree order, so re-adding is easy.
2016-05-11 14:46:08 +00:00
p_nodes . sort_custom < Node : : Comparator > ( ) ;
2014-02-10 01:10:30 +00:00
2016-05-04 01:25:37 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Reparent Node " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
List < Pair < NodePath , NodePath > > path_renames ;
2016-10-08 18:37:05 +00:00
Vector < StringName > former_names ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
int inc = 0 ;
2016-07-01 02:19:44 +00:00
2017-03-05 15:44:50 +00:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
2014-02-10 01:10:30 +00:00
2019-09-15 00:07:55 +00:00
// No undo implemented for this yet.
2016-05-11 14:46:08 +00:00
Node * node = p_nodes [ ni ] ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
fill_path_renames ( node , new_parent , & path_renames ) ;
2016-10-08 18:37:05 +00:00
former_names . push_back ( node - > get_name ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
List < Node * > owned ;
node - > get_owned_by ( node - > get_owner ( ) , & owned ) ;
2014-02-10 01:10:30 +00:00
Array owners ;
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = owned . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
owners . push_back ( E - > get ( ) ) ;
}
2019-09-15 00:07:55 +00:00
if ( new_parent = = node - > get_parent ( ) & & node - > get_index ( ) < p_position_in_parent + ni )
inc - - ; // If the child will generate a gap when moved, adjust.
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( node - > get_parent ( ) , " remove_child " , node ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( new_parent , " add_child " , node ) ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
if ( p_position_in_parent > = 0 )
editor_data - > get_undo_redo ( ) . add_do_method ( new_parent , " move_child " , node , p_position_in_parent + inc ) ;
2016-05-11 14:46:08 +00:00
2015-08-02 15:29:37 +00:00
ScriptEditorDebugger * sed = ScriptEditor : : get_singleton ( ) - > get_debugger ( ) ;
2018-03-23 09:44:39 +00:00
String old_name = former_names [ ni ] ;
2016-10-07 18:25:29 +00:00
String new_name = new_parent - > validate_child_name ( node ) ;
2018-03-23 09:44:39 +00:00
2019-09-15 00:07:55 +00:00
// Name was modified, fix the path renames.
2018-03-23 09:44:39 +00:00
if ( old_name . casecmp_to ( new_name ) ! = 0 ) {
2019-09-15 00:07:55 +00:00
// Fix the to name to have the new name.
2018-03-23 09:44:39 +00:00
NodePath old_new_name = path_renames [ ni ] . second ;
NodePath new_path ;
Vector < StringName > unfixed_new_names = old_new_name . get_names ( ) ;
Vector < StringName > fixed_new_names ;
2019-09-15 00:07:55 +00:00
// Get last name and replace with fixed new name.
2018-03-23 09:44:39 +00:00
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 ) ;
NodePath fixed_node_path = NodePath ( fixed_new_names , true ) ;
path_renames [ ni ] . second = fixed_node_path ;
}
2018-06-07 22:40:43 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( sed , " live_debug_reparent_node " , edited_scene - > get_path_to ( node ) , edited_scene - > get_path_to ( new_parent ) , new_name , p_position_in_parent + inc ) ;
2018-09-12 10:29:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( sed , " live_debug_reparent_node " , NodePath ( String ( edited_scene - > get_path_to ( new_parent ) ) . plus_file ( new_name ) ) , edited_scene - > get_path_to ( node - > get_parent ( ) ) , node - > get_name ( ) , node - > get_index ( ) ) ;
2015-08-02 15:29:37 +00:00
2016-01-02 14:57:47 +00:00
if ( p_keep_global_xform ) {
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < Node2D > ( node ) )
editor_data - > get_undo_redo ( ) . add_do_method ( node , " set_global_transform " , Object : : cast_to < Node2D > ( node ) - > get_global_transform ( ) ) ;
if ( Object : : cast_to < Spatial > ( node ) )
editor_data - > get_undo_redo ( ) . add_do_method ( node , " set_global_transform " , Object : : cast_to < Spatial > ( node ) - > get_global_transform ( ) ) ;
if ( Object : : cast_to < Control > ( node ) )
editor_data - > get_undo_redo ( ) . add_do_method ( node , " set_global_position " , Object : : cast_to < Control > ( node ) - > get_global_position ( ) ) ;
2016-01-02 14:57:47 +00:00
}
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( this , " _set_owners " , edited_scene , owners ) ;
2014-02-10 01:10:30 +00:00
2018-06-07 15:46:14 +00:00
if ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) - > get_root ( ) = = node )
editor_data - > get_undo_redo ( ) . add_do_method ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) , " set_root " , node ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( new_parent , " remove_child " , node ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_name " , former_names [ ni ] ) ;
2014-02-10 01:10:30 +00:00
2016-07-01 02:19:44 +00:00
inc + + ;
2014-02-10 01:10:30 +00:00
}
2019-09-15 00:07:55 +00:00
// Add and move in a second step (so old order is preserved).
2017-03-05 15:44:50 +00:00
for ( int ni = 0 ; ni < p_nodes . size ( ) ; ni + + ) {
2014-02-10 01:10:30 +00:00
2016-05-11 14:46:08 +00:00
Node * node = p_nodes [ ni ] ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
List < Node * > owned ;
node - > get_owned_by ( node - > get_owner ( ) , & owned ) ;
2014-02-10 01:10:30 +00:00
Array owners ;
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = owned . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
owners . push_back ( E - > get ( ) ) ;
}
int child_pos = node - > get_position_in_parent ( ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( node - > get_parent ( ) , " add_child " , node ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( node - > get_parent ( ) , " move_child " , node , child_pos ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( this , " _set_owners " , edited_scene , owners ) ;
2018-06-07 15:46:14 +00:00
if ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) - > get_root ( ) = = node )
editor_data - > get_undo_redo ( ) . add_undo_method ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) , " set_root " , node ) ;
2014-02-10 01:10:30 +00:00
2016-01-02 14:57:47 +00:00
if ( p_keep_global_xform ) {
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < Node2D > ( node ) )
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_transform " , Object : : cast_to < Node2D > ( node ) - > get_transform ( ) ) ;
if ( Object : : cast_to < Spatial > ( node ) )
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_transform " , Object : : cast_to < Spatial > ( node ) - > get_transform ( ) ) ;
if ( Object : : cast_to < Control > ( node ) )
editor_data - > get_undo_redo ( ) . add_undo_method ( node , " set_position " , Object : : cast_to < Control > ( node ) - > get_position ( ) ) ;
2016-01-02 14:57:47 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
perform_node_renames ( NULL , & path_renames ) ;
2014-02-10 01:10:30 +00:00
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
}
2018-07-07 14:51:18 +00:00
bool SceneTreeDock : : _is_collapsed_recursive ( TreeItem * p_item ) const {
bool is_branch_collapsed = false ;
List < TreeItem * > needs_check ;
needs_check . push_back ( p_item ) ;
while ( ! needs_check . empty ( ) ) {
TreeItem * item = needs_check . back ( ) - > get ( ) ;
needs_check . pop_back ( ) ;
TreeItem * child = item - > get_children ( ) ;
is_branch_collapsed = item - > is_collapsed ( ) & & child ;
if ( is_branch_collapsed ) {
break ;
}
while ( child ) {
needs_check . push_back ( child ) ;
child = child - > get_next ( ) ;
}
}
return is_branch_collapsed ;
}
void SceneTreeDock : : _set_collapsed_recursive ( TreeItem * p_item , bool p_collapsed ) {
List < TreeItem * > to_collapse ;
to_collapse . push_back ( p_item ) ;
while ( ! to_collapse . empty ( ) ) {
TreeItem * item = to_collapse . back ( ) - > get ( ) ;
to_collapse . pop_back ( ) ;
item - > set_collapsed ( p_collapsed ) ;
TreeItem * child = item - > get_children ( ) ;
while ( child ) {
to_collapse . push_back ( child ) ;
child = child - > get_next ( ) ;
}
}
}
2014-02-10 01:10:30 +00:00
void SceneTreeDock : : _script_created ( Ref < Script > p_script ) {
2018-03-07 19:08:13 +00:00
List < Node * > selected = editor_selection - > get_selected_node_list ( ) ;
if ( selected . empty ( ) )
2014-02-10 01:10:30 +00:00
return ;
2018-03-07 19:08:13 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Attach Script " ) ) ;
for ( List < Node * > : : Element * E = selected . front ( ) ; E ; E = E - > next ( ) ) {
Ref < Script > existing = E - > get ( ) - > get_script ( ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( E - > get ( ) , " set_script " , p_script . get_ref_ptr ( ) ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( E - > get ( ) , " set_script " , existing ) ;
2019-05-14 01:58:41 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( this , " _update_script_button " ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( this , " _update_script_button " ) ;
2018-03-07 19:08:13 +00:00
}
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2018-07-25 19:43:17 +00:00
editor - > push_item ( p_script . operator - > ( ) ) ;
2018-10-25 18:33:16 +00:00
_update_script_button ( ) ;
2014-02-10 01:10:30 +00:00
}
2019-06-30 03:19:45 +00:00
void SceneTreeDock : : _script_creation_closed ( ) {
script_create_dialog - > disconnect ( " script_created " , this , " _script_created " ) ;
}
2019-05-14 00:11:06 +00:00
void SceneTreeDock : : _toggle_editable_children_from_selection ( ) {
2018-09-12 22:49:12 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
List < Node * > : : Element * e = selection . front ( ) ;
2019-05-14 00:11:06 +00:00
if ( e ) {
_toggle_editable_children ( e - > get ( ) ) ;
}
}
2018-09-12 22:49:12 +00:00
2019-09-04 19:02:26 +00: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 ( ) ;
}
}
}
2019-05-14 00:11:06 +00:00
void SceneTreeDock : : _toggle_editable_children ( Node * p_node ) {
2018-09-12 22:49:12 +00:00
2019-05-14 00:11:06 +00:00
if ( p_node ) {
bool editable = ! EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( p_node ) ;
EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > set_editable_instance ( p_node , editable ) ;
if ( editable )
p_node - > set_scene_instance_load_placeholder ( false ) ;
2018-09-12 22:49:12 +00:00
2019-05-14 00:11:06 +00:00
SpatialEditor : : get_singleton ( ) - > update_all_gizmos ( p_node ) ;
2018-09-12 22:49:12 +00:00
2019-05-14 00:11:06 +00:00
scene_tree - > update_tree ( ) ;
2018-09-12 22:49:12 +00:00
}
}
2014-02-10 01:10:30 +00:00
void SceneTreeDock : : _delete_confirm ( ) {
2017-03-05 15:44:50 +00:00
List < Node * > remove_list = editor_selection - > get_selected_node_list ( ) ;
2014-02-10 01:10:30 +00:00
if ( remove_list . empty ( ) )
return ;
2016-03-29 23:02:53 +00:00
editor - > get_editor_plugins_over ( ) - > make_visible ( false ) ;
2014-02-10 01:10:30 +00:00
2016-05-04 01:25:37 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Remove Node(s) " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool entire_scene = false ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = remove_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) = = edited_scene ) {
entire_scene = true ;
2014-02-10 01:10:30 +00:00
}
}
if ( entire_scene ) {
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( editor , " set_edited_scene " , ( Object * ) NULL ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( editor , " set_edited_scene " , edited_scene ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( edited_scene , " set_owner " , edited_scene - > get_owner ( ) ) ;
2017-11-12 16:12:53 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( scene_tree , " update_tree " ) ;
2014-02-10 01:10:30 +00:00
editor_data - > get_undo_redo ( ) . add_undo_reference ( edited_scene ) ;
} else {
remove_list . sort_custom < Node : : Comparator > ( ) ; //sort nodes to keep positions
2017-03-05 15:44:50 +00:00
List < Pair < NodePath , NodePath > > path_renames ;
2014-02-10 01:10:30 +00:00
//delete from animation
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = remove_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
Node * n = E - > get ( ) ;
2014-11-06 00:20:42 +00:00
if ( ! n - > is_inside_tree ( ) | | ! n - > get_parent ( ) )
2014-02-10 01:10:30 +00:00
continue ;
2017-03-05 15:44:50 +00:00
fill_path_renames ( n , NULL , & path_renames ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
perform_node_renames ( NULL , & path_renames ) ;
2014-02-10 01:10:30 +00:00
//delete for read
2017-03-05 15:44:50 +00:00
for ( List < Node * > : : Element * E = remove_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
Node * n = E - > get ( ) ;
2014-11-06 00:20:42 +00:00
if ( ! n - > is_inside_tree ( ) | | ! n - > get_parent ( ) )
2014-02-10 01:10:30 +00:00
continue ;
2017-03-05 15:44:50 +00:00
List < Node * > owned ;
n - > get_owned_by ( n - > get_owner ( ) , & owned ) ;
2014-02-10 01:10:30 +00:00
Array owners ;
2019-02-12 20:10:08 +00:00
for ( List < Node * > : : Element * F = owned . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2019-02-12 20:10:08 +00:00
owners . push_back ( F - > get ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( n - > get_parent ( ) , " remove_child " , n ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( n - > get_parent ( ) , " add_child " , n ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( n - > get_parent ( ) , " move_child " , n , n - > get_index ( ) ) ;
2018-06-07 15:46:14 +00:00
if ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) - > get_root ( ) = = n )
editor_data - > get_undo_redo ( ) . add_undo_method ( AnimationPlayerEditor : : singleton - > get_track_editor ( ) , " set_root " , n ) ;
2017-03-05 15:44:50 +00:00
editor_data - > get_undo_redo ( ) . add_undo_method ( this , " _set_owners " , edited_scene , owners ) ;
2014-02-10 01:10:30 +00:00
editor_data - > get_undo_redo ( ) . add_undo_reference ( n ) ;
2015-08-02 15:29:37 +00:00
ScriptEditorDebugger * sed = ScriptEditor : : get_singleton ( ) - > get_debugger ( ) ;
2017-08-07 10:17:31 +00:00
editor_data - > get_undo_redo ( ) . add_do_method ( sed , " live_debug_remove_and_keep_node " , edited_scene - > get_path_to ( n ) , n - > get_instance_id ( ) ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( sed , " live_debug_restore_node " , n - > get_instance_id ( ) , edited_scene - > get_path_to ( n - > get_parent ( ) ) , n - > get_index ( ) ) ;
2014-02-10 01:10:30 +00:00
}
}
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2017-11-08 02:10:31 +00:00
// hack, force 2d editor viewport to refresh after deletion
if ( CanvasItemEditor * editor = CanvasItemEditor : : get_singleton ( ) )
editor - > get_viewport_control ( ) - > update ( ) ;
editor - > push_item ( NULL ) ;
2018-01-08 05:50:51 +00:00
// Fixes the EditorHistory from still offering deleted notes
EditorHistory * editor_history = EditorNode : : get_singleton ( ) - > get_editor_history ( ) ;
editor_history - > cleanup_history ( ) ;
2018-10-01 10:15:22 +00:00
EditorNode : : get_singleton ( ) - > get_inspector_dock ( ) - > call ( " _prepare_history " ) ;
2016-05-17 21:27:15 +00:00
}
2015-08-25 03:08:45 +00:00
2018-01-11 20:58:17 +00:00
void SceneTreeDock : : _update_script_button ( ) {
2019-04-08 22:18:03 +00:00
if ( ! profile_allow_script_editing ) {
button_create_script - > hide ( ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > hide ( ) ;
2019-04-08 22:18:03 +00:00
} else if ( EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selection ( ) . size ( ) = = 0 ) {
2019-01-02 10:40:23 +00:00
button_create_script - > hide ( ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > hide ( ) ;
2019-01-02 10:40:23 +00:00
} else if ( EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selection ( ) . size ( ) = = 1 ) {
2018-10-19 14:04:07 +00:00
Node * n = EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selected_node_list ( ) [ 0 ] ;
if ( n - > get_script ( ) . is_null ( ) ) {
2018-10-25 18:33:16 +00:00
button_create_script - > show ( ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > hide ( ) ;
2018-10-19 14:04:07 +00:00
} else {
2018-10-25 18:33:16 +00:00
button_create_script - > hide ( ) ;
2020-05-09 16:59:19 +00:00
button_detach_script - > show ( ) ;
2018-10-19 14:04:07 +00:00
}
2016-08-07 22:22:33 +00:00
} else {
2019-03-06 04:19:34 +00:00
button_create_script - > hide ( ) ;
2019-03-06 06:11:02 +00: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 10:40:23 +00:00
if ( ! n - > get_script ( ) . is_null ( ) ) {
2020-05-09 16:59:19 +00:00
button_detach_script - > show ( ) ;
2019-01-02 10:40:23 +00:00
return ;
}
}
2020-05-09 16:59:19 +00:00
button_detach_script - > hide ( ) ;
2016-08-07 22:22:33 +00:00
}
2015-08-25 03:08:45 +00:00
}
2018-01-11 20:58:17 +00:00
void SceneTreeDock : : _selection_changed ( ) {
int selection_size = EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selection ( ) . size ( ) ;
if ( selection_size > 1 ) {
//automatically turn on multi-edit
_tool_selected ( TOOL_MULTI_EDIT ) ;
2018-10-01 00:00:07 +00:00
} else if ( selection_size = = 1 ) {
editor - > push_item ( EditorNode : : get_singleton ( ) - > get_editor_selection ( ) - > get_selected_node_list ( ) [ 0 ] ) ;
} else {
editor - > push_item ( NULL ) ;
2018-01-11 20:58:17 +00:00
}
_update_script_button ( ) ;
}
2019-05-01 15:14:18 +00:00
Node * SceneTreeDock : : _get_selection_group_tail ( Node * p_node , List < Node * > p_list ) {
Node * tail = p_node ;
Node * parent = tail - > get_parent ( ) ;
for ( int i = p_node - > get_position_in_parent ( ) ; i < parent - > get_child_count ( ) ; i + + ) {
Node * sibling = parent - > get_child ( i ) ;
if ( p_list . find ( sibling ) )
tail = sibling ;
else
break ;
}
return tail ;
}
2018-09-12 18:47:12 +00:00
void SceneTreeDock : : _do_create ( Node * p_parent ) {
Object * c = create_dialog - > instance_selected ( ) ;
ERR_FAIL_COND ( ! c ) ;
Node * child = Object : : cast_to < Node > ( c ) ;
ERR_FAIL_COND ( ! child ) ;
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Create Node " ) ) ;
if ( edited_scene ) {
editor_data - > get_undo_redo ( ) . add_do_method ( p_parent , " add_child " , child ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( child , " set_owner " , edited_scene ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " clear " ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( editor_selection , " add_node " , child ) ;
editor_data - > get_undo_redo ( ) . add_do_reference ( child ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( p_parent , " remove_child " , child ) ;
String new_name = p_parent - > validate_child_name ( child ) ;
ScriptEditorDebugger * sed = ScriptEditor : : get_singleton ( ) - > get_debugger ( ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( sed , " live_debug_create_node " , edited_scene - > get_path_to ( p_parent ) , child - > get_class ( ) , new_name ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( sed , " live_debug_remove_node " , NodePath ( String ( edited_scene - > get_path_to ( p_parent ) ) . plus_file ( new_name ) ) ) ;
} else {
editor_data - > get_undo_redo ( ) . add_do_method ( editor , " set_edited_scene " , child ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( scene_tree , " update_tree " ) ;
editor_data - > get_undo_redo ( ) . add_do_reference ( child ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( editor , " set_edited_scene " , ( Object * ) NULL ) ;
}
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
editor - > push_item ( c ) ;
editor_selection - > clear ( ) ;
editor_selection - > add_node ( child ) ;
if ( Object : : cast_to < Control > ( c ) ) {
//make editor more comfortable, so some controls don't appear super shrunk
Control * ct = Object : : cast_to < Control > ( c ) ;
Size2 ms = ct - > get_minimum_size ( ) ;
if ( ms . width < 4 )
ms . width = 40 ;
if ( ms . height < 4 )
ms . height = 40 ;
ct - > set_size ( ms ) ;
}
}
2014-02-10 01:10:30 +00:00
void SceneTreeDock : : _create ( ) {
2017-03-05 15:44:50 +00:00
if ( current_option = = TOOL_NEW ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * parent = NULL ;
2014-02-10 01:10:30 +00:00
if ( edited_scene ) {
2015-03-31 18:26:38 +00:00
// If root exists in edited scene
2014-02-10 01:10:30 +00:00
parent = scene_tree - > get_selected ( ) ;
2017-03-05 15:44:50 +00:00
if ( ! parent )
2015-03-31 18:26:38 +00:00
parent = edited_scene ;
2014-02-10 01:10:30 +00:00
2015-03-31 18:26:38 +00:00
} else {
// If no root exist in edited scene
2014-02-10 01:10:30 +00:00
parent = scene_root ;
ERR_FAIL_COND ( ! parent ) ;
}
2018-09-12 18:47:12 +00:00
_do_create ( parent ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
} else if ( current_option = = TOOL_REPLACE ) {
2017-12-15 03:01:25 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
ERR_FAIL_COND ( selection . size ( ) < = 0 ) ;
2019-08-09 14:31:31 +00:00
UndoRedo * ur = EditorNode : : get_singleton ( ) - > get_undo_redo ( ) ;
ur - > create_action ( TTR ( " Change type of node(s) " ) ) ;
2017-12-15 03:01:25 +00:00
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
Node * n = E - > get ( ) ;
ERR_FAIL_COND ( ! n ) ;
2014-02-10 01:10:30 +00:00
2017-12-15 03:01:25 +00:00
Object * c = create_dialog - > instance_selected ( ) ;
2014-02-10 01:10:30 +00:00
2017-12-15 03:01:25 +00:00
ERR_FAIL_COND ( ! c ) ;
Node * newnode = Object : : cast_to < Node > ( c ) ;
ERR_FAIL_COND ( ! newnode ) ;
2014-02-10 01:10:30 +00:00
2019-08-09 14:31:31 +00:00
ur - > add_do_method ( this , " replace_node " , n , newnode , true , false ) ;
ur - > add_do_reference ( newnode ) ;
ur - > add_undo_method ( this , " replace_node " , newnode , n , false , false ) ;
ur - > add_undo_reference ( n ) ;
2018-02-21 12:38:21 +00:00
}
2019-08-09 14:31:31 +00:00
ur - > commit_action ( ) ;
2018-09-12 18:47:12 +00:00
} else if ( current_option = = TOOL_REPARENT_TO_NEW_NODE ) {
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
ERR_FAIL_COND ( selection . size ( ) < = 0 ) ;
// Find top level node in selection
bool only_one_top_node = true ;
Node * first = selection . front ( ) - > get ( ) ;
ERR_FAIL_COND ( ! first ) ;
int smaller_path_to_top = first - > get_path_to ( scene_root ) . get_name_count ( ) ;
Node * top_node = first ;
for ( List < Node * > : : Element * E = selection . front ( ) - > next ( ) ; E ; E = E - > next ( ) ) {
Node * n = E - > get ( ) ;
ERR_FAIL_COND ( ! n ) ;
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 ;
} else if ( smaller_path_to_top = = path_length ) {
if ( only_one_top_node & & top_node - > get_parent ( ) ! = n - > get_parent ( ) )
only_one_top_node = false ;
}
}
}
Node * parent = NULL ;
if ( only_one_top_node )
parent = top_node - > get_parent ( ) ;
else
parent = top_node - > get_parent ( ) - > get_parent ( ) ;
_do_create ( parent ) ;
Vector < Node * > nodes ;
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
nodes . push_back ( E - > get ( ) ) ;
}
// This works because editor_selection was cleared and populated with last created node in _do_create()
Node * last_created = editor_selection - > get_selected_node_list ( ) . front ( ) - > get ( ) ;
_do_reparent ( last_created , - 1 , nodes , true ) ;
2018-02-21 12:38:21 +00:00
}
2019-04-10 15:01:42 +00:00
scene_tree - > get_scene_tree ( ) - > call_deferred ( " grab_focus " ) ;
2018-02-21 12:38:21 +00:00
}
2014-02-10 01:10:30 +00:00
2019-04-23 19:10:44 +00:00
void SceneTreeDock : : replace_node ( Node * p_node , Node * p_by_node , bool p_keep_properties , bool p_remove_old ) {
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
Node * n = p_node ;
Node * newnode = p_by_node ;
2014-02-10 01:10:30 +00:00
2019-01-14 16:41:54 +00:00
if ( p_keep_properties ) {
Node * default_oldnode = Object : : cast_to < Node > ( ClassDB : : instance ( n - > get_class ( ) ) ) ;
List < PropertyInfo > pinfo ;
n - > get_property_list ( & pinfo ) ;
for ( List < PropertyInfo > : : Element * E = pinfo . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
continue ;
2020-05-18 14:38:48 +00:00
if ( E - > get ( ) . name = = " __meta__ " ) {
if ( Object : : cast_to < CanvasItem > ( newnode ) ) {
Dictionary metadata = n - > get ( E - > get ( ) . name ) ;
if ( metadata . has ( " _edit_group_ " ) & & metadata [ " _edit_group_ " ] ) {
newnode - > set_meta ( " _edit_group_ " , true ) ;
}
if ( metadata . has ( " _edit_lock_ " ) & & metadata [ " _edit_lock_ " ] ) {
newnode - > set_meta ( " _edit_lock_ " , true ) ;
}
}
2019-01-14 16:41:54 +00:00
continue ;
2020-05-18 14:38:48 +00:00
}
2019-01-14 16:41:54 +00:00
if ( default_oldnode - > get ( E - > get ( ) . name ) ! = n - > get ( E - > get ( ) . name ) ) {
newnode - > set ( E - > get ( ) . name , n - > get ( E - > get ( ) . name ) ) ;
}
2018-03-09 18:05:04 +00:00
}
2019-01-14 16:41:54 +00:00
memdelete ( default_oldnode ) ;
2018-02-21 12:38:21 +00:00
}
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
editor - > push_item ( NULL ) ;
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
//reconnect signals
List < MethodInfo > sl ;
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
n - > get_signal_list ( & sl ) ;
for ( List < MethodInfo > : : Element * E = sl . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
List < Object : : Connection > cl ;
n - > get_signal_connection_list ( E - > get ( ) . name , & cl ) ;
2016-06-21 01:57:07 +00:00
2018-02-21 12:38:21 +00:00
for ( List < Object : : Connection > : : Element * F = cl . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
Object : : Connection & c = F - > get ( ) ;
if ( ! ( c . flags & Object : : CONNECT_PERSIST ) )
continue ;
2019-03-19 09:21:52 +00:00
newnode - > connect ( c . signal , c . target , c . method , c . binds , Object : : CONNECT_PERSIST ) ;
2018-02-21 12:38:21 +00:00
}
}
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
String newname = n - > get_name ( ) ;
2015-09-07 13:13:29 +00:00
2018-02-21 12:38:21 +00:00
List < Node * > to_erase ;
for ( int i = 0 ; i < n - > get_child_count ( ) ; i + + ) {
if ( n - > get_child ( i ) - > get_owner ( ) = = NULL & & n - > is_owned_by_parent ( ) ) {
to_erase . push_back ( n - > get_child ( i ) ) ;
}
}
n - > replace_by ( newnode , true ) ;
2014-02-10 01:10:30 +00:00
2018-02-21 12:38:21 +00:00
if ( n = = edited_scene ) {
edited_scene = newnode ;
editor - > set_edited_scene ( newnode ) ;
newnode - > set_editable_instances ( n - > get_editable_instances ( ) ) ;
}
2016-01-17 23:03:57 +00:00
2018-02-21 12:38:21 +00: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 19:10:44 +00:00
//p_remove_old was added to support undo
if ( p_remove_old )
editor_data - > get_undo_redo ( ) . clear_history ( ) ;
2018-02-21 12:38:21 +00:00
newnode - > set_name ( newname ) ;
editor - > push_item ( newnode ) ;
2019-04-23 19:10:44 +00:00
if ( p_remove_old ) {
memdelete ( n ) ;
2018-02-21 12:38:21 +00:00
2019-04-23 19:10:44 +00:00
while ( to_erase . front ( ) ) {
memdelete ( to_erase . front ( ) - > get ( ) ) ;
to_erase . pop_front ( ) ;
}
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : set_edited_scene ( Node * p_scene ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
edited_scene = p_scene ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : set_selected ( Node * p_node , bool p_emit_selected ) {
2016-05-17 21:27:15 +00:00
2017-03-05 15:44:50 +00:00
scene_tree - > set_selected ( p_node , p_emit_selected ) ;
2014-02-10 01:10:30 +00:00
}
void SceneTreeDock : : import_subscene ( ) {
2019-04-26 19:36:44 +00:00
import_subscene_dialog - > popup_centered_clamped ( Size2 ( 500 , 800 ) * EDSCALE , 0.8 ) ;
2014-02-10 01:10:30 +00:00
}
void SceneTreeDock : : _import_subscene ( ) {
2017-03-05 15:44:50 +00:00
Node * parent = scene_tree - > get_selected ( ) ;
2015-11-23 19:06:37 +00:00
if ( ! parent ) {
parent = editor_data - > get_edited_scene_root ( ) ;
ERR_FAIL_COND ( ! parent ) ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
import_subscene_dialog - > move ( parent , edited_scene ) ;
2014-02-10 01:10:30 +00:00
editor_data - > get_undo_redo ( ) . clear_history ( ) ; //no undo for now..
}
2015-11-27 20:42:48 +00:00
void SceneTreeDock : : _new_scene_from ( String p_file ) {
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2015-11-27 20:42:48 +00:00
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) ! = 1 ) {
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " This operation requires a single selected node. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
2018-09-07 13:54:26 +00:00
if ( EditorNode : : get_singleton ( ) - > is_scene_open ( p_file ) ) {
accept - > set_text ( TTR ( " Can't overwrite scene that is still open! " ) ) ;
accept - > popup_centered_minsize ( ) ;
return ;
}
2015-11-27 20:42:48 +00:00
Node * base = selection . front ( ) - > get ( ) ;
2017-03-05 15:44:50 +00:00
Map < Node * , Node * > reown ;
reown [ editor_data - > get_edited_scene_root ( ) ] = base ;
2015-11-27 20:42:48 +00:00
Node * copy = base - > duplicate_and_reown ( reown ) ;
if ( copy ) {
2017-03-05 15:44:50 +00:00
Ref < PackedScene > sdata = memnew ( PackedScene ) ;
2015-11-27 20:42:48 +00:00
Error err = sdata - > pack ( copy ) ;
memdelete ( copy ) ;
2017-03-05 15:44:50 +00:00
if ( err ! = OK ) {
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
2017-03-05 15:44:50 +00:00
int flg = 0 ;
2017-01-05 22:41:36 +00:00
if ( EditorSettings : : get_singleton ( ) - > get ( " filesystem/on_save/compress_binary_resources " ) )
2017-03-05 15:44:50 +00:00
flg | = ResourceSaver : : FLAG_COMPRESS ;
2015-11-27 20:42:48 +00:00
2017-03-05 15:44:50 +00:00
err = ResourceSaver : : save ( p_file , sdata , flg ) ;
if ( err ! = OK ) {
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " Error saving scene. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
2016-10-11 14:54:46 +00:00
_replace_with_branch_scene ( p_file , base ) ;
2015-11-27 20:42:48 +00:00
} else {
2016-05-04 01:25:37 +00:00
accept - > set_text ( TTR ( " Error duplicating scene to save it. " ) ) ;
2015-11-27 20:42:48 +00:00
accept - > popup_centered_minsize ( ) ;
return ;
}
}
2017-03-05 15:44:50 +00:00
static bool _is_node_visible ( Node * p_node ) {
2016-05-11 14:46:08 +00:00
if ( ! p_node - > get_owner ( ) )
return false ;
2017-03-05 15:44:50 +00: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 14:46:08 +00:00
return false ;
return true ;
}
2017-03-05 15:44:50 +00:00
static bool _has_visible_children ( Node * p_node ) {
2016-05-11 14:46:08 +00:00
2016-11-02 15:23:03 +00:00
bool collapsed = p_node - > is_displayed_folded ( ) ;
2016-05-11 14:46:08 +00:00
if ( collapsed )
return false ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
Node * child = p_node - > get_child ( i ) ;
2016-07-07 06:37:38 +00:00
if ( ! _is_node_visible ( child ) )
2016-05-11 14:46:08 +00:00
continue ;
return true ;
}
return false ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _normalize_drop ( Node * & to_node , int & to_pos , int p_type ) {
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
to_pos = - 1 ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
if ( p_type = = - 1 ) {
2016-05-11 14:46:08 +00:00
//drop at above selected node
2017-03-05 15:44:50 +00:00
if ( to_node = = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
to_node = NULL ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_MSG ( " Cannot perform drop above the root node! " ) ;
2016-05-11 23:57:52 +00:00
}
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
to_pos = to_node - > get_index ( ) ;
to_node = to_node - > get_parent ( ) ;
2016-06-18 18:30:44 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_type = = 1 ) {
//drop at below selected node
if ( to_node = = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
//if at lower sibling of root node
2017-03-24 20:45:31 +00:00
to_pos = 0 ; //just insert at beginning of root node
2017-03-05 15:44:50 +00:00
return ;
}
2016-06-18 18:30:44 +00:00
2017-03-05 15:44:50 +00:00
Node * lower_sibling = NULL ;
2016-06-18 18:30:44 +00:00
2017-03-05 15:44:50 +00:00
if ( _has_visible_children ( to_node ) ) {
to_pos = 0 ;
} else {
for ( int i = to_node - > get_index ( ) + 1 ; i < to_node - > get_parent ( ) - > get_child_count ( ) ; i + + ) {
Node * c = to_node - > get_parent ( ) - > get_child ( i ) ;
if ( _is_node_visible ( c ) ) {
lower_sibling = c ;
break ;
2016-06-18 18:30:44 +00:00
}
}
2017-03-05 15:44:50 +00:00
if ( lower_sibling ) {
to_pos = lower_sibling - > get_index ( ) ;
}
to_node = to_node - > get_parent ( ) ;
}
2016-05-11 14:46:08 +00:00
}
2016-05-11 23:57:52 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _files_dropped ( Vector < String > p_files , NodePath p_to , int p_type ) {
2016-05-11 23:57:52 +00:00
Node * node = get_node ( p_to ) ;
ERR_FAIL_COND ( ! node ) ;
2017-03-05 15:44:50 +00:00
int to_pos = - 1 ;
_normalize_drop ( node , to_pos , p_type ) ;
_perform_instance_scenes ( p_files , node , to_pos ) ;
2016-05-11 23:57:52 +00:00
}
2016-10-27 14:32:41 +00:00
void SceneTreeDock : : _script_dropped ( String p_file , NodePath p_to ) {
Ref < Script > scr = ResourceLoader : : load ( p_file ) ;
ERR_FAIL_COND ( ! scr . is_valid ( ) ) ;
Node * n = get_node ( p_to ) ;
if ( n ) {
2018-03-07 19:08:13 +00:00
editor_data - > get_undo_redo ( ) . create_action ( TTR ( " Attach Script " ) ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( n , " set_script " , scr ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( n , " set_script " , n - > get_script ( ) ) ;
editor_data - > get_undo_redo ( ) . add_do_method ( this , " _update_script_button " ) ;
editor_data - > get_undo_redo ( ) . add_undo_method ( this , " _update_script_button " ) ;
editor_data - > get_undo_redo ( ) . commit_action ( ) ;
2016-10-27 14:32:41 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _nodes_dragged ( Array p_nodes , NodePath p_to , int p_type ) {
2016-05-11 23:57:52 +00:00
2019-07-04 13:41:21 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2016-05-11 23:57:52 +00:00
2019-07-04 13:41:21 +00:00
if ( selection . empty ( ) )
return ; //nothing to reparent
2016-05-11 23:57:52 +00:00
2019-07-04 13:41:21 +00:00
Node * to_node = get_node ( p_to ) ;
2016-05-11 23:57:52 +00:00
if ( ! to_node )
return ;
2019-07-04 13:41:21 +00:00
Vector < Node * > nodes ;
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
nodes . push_back ( E - > get ( ) ) ;
}
2017-03-05 15:44:50 +00:00
int to_pos = - 1 ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
_normalize_drop ( to_node , to_pos , p_type ) ;
2019-04-24 12:49:00 +00:00
_do_reparent ( to_node , to_pos , nodes , ! Input : : get_singleton ( ) - > is_key_pressed ( KEY_SHIFT ) ) ;
2016-05-11 14:46:08 +00:00
}
2017-06-05 03:12:19 +00:00
void SceneTreeDock : : _add_children_to_popup ( Object * p_obj , int p_depth ) {
if ( p_depth > 8 )
return ;
List < PropertyInfo > pinfo ;
p_obj - > get_property_list ( & pinfo ) ;
for ( List < PropertyInfo > : : Element * E = pinfo . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_EDITOR ) )
continue ;
if ( E - > get ( ) . hint ! = PROPERTY_HINT_RESOURCE_TYPE )
continue ;
Variant value = p_obj - > get ( E - > get ( ) . name ) ;
if ( value . get_type ( ) ! = Variant : : OBJECT )
continue ;
Object * obj = value ;
if ( ! obj )
continue ;
2018-09-02 21:40:51 +00:00
Ref < Texture > icon = EditorNode : : get_singleton ( ) - > get_object_icon ( obj ) ;
2017-06-05 03:12:19 +00:00
if ( menu - > get_item_count ( ) = = 0 ) {
2017-12-19 15:07:50 +00:00
menu - > add_submenu_item ( TTR ( " Sub-Resources " ) , " Sub-Resources " ) ;
2017-06-05 03:12:19 +00:00
}
2017-12-17 14:55:24 +00:00
int index = menu_subresources - > get_item_count ( ) ;
menu_subresources - > add_icon_item ( icon , E - > get ( ) . name . capitalize ( ) , EDIT_SUBRESOURCE_BASE + subresources . size ( ) ) ;
menu_subresources - > set_item_h_offset ( index , p_depth * 10 * EDSCALE ) ;
2017-08-07 10:17:31 +00:00
subresources . push_back ( obj - > get_instance_id ( ) ) ;
2017-06-05 03:12:19 +00:00
_add_children_to_popup ( obj , p_depth + 1 ) ;
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _tree_rmb ( const Vector2 & p_menu_pos ) {
2019-04-08 22:18:03 +00:00
2016-05-16 15:23:40 +00:00
if ( ! EditorNode : : get_singleton ( ) - > get_edited_scene ( ) ) {
menu - > clear ( ) ;
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > add_icon_shortcut ( get_icon ( " Add " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) , TOOL_NEW ) ;
menu - > add_icon_shortcut ( get_icon ( " Instance " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/instance_scene " ) , TOOL_INSTANCE ) ;
}
2016-05-16 15:23:40 +00:00
2017-03-05 15:44:50 +00:00
menu - > set_size ( Size2 ( 1 , 1 ) ) ;
2017-03-29 15:29:38 +00:00
menu - > set_position ( p_menu_pos ) ;
2016-05-16 15:23:40 +00:00
menu - > popup ( ) ;
return ;
}
2017-03-05 15:44:50 +00:00
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2019-11-04 15:45:16 +00:00
List < Node * > full_selection = editor_selection - > get_full_selected_node_list ( ) ; // Above method only returns nodes with common parent.
2016-05-16 02:41:48 +00:00
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) = = 0 )
2016-05-16 02:41:48 +00:00
return ;
2016-05-16 15:23:40 +00:00
2016-05-16 02:41:48 +00:00
menu - > clear ( ) ;
2018-10-03 09:25:18 +00:00
Ref < Script > existing_script ;
2019-07-19 19:21:30 +00:00
bool exisiting_script_removable = true ;
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) = = 1 ) {
2017-06-05 03:12:19 +00:00
2018-01-02 07:10:49 +00:00
Node * selected = selection [ 0 ] ;
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
subresources . clear ( ) ;
menu_subresources - > clear ( ) ;
menu_subresources - > set_size ( Size2 ( 1 , 1 ) ) ;
_add_children_to_popup ( selection . front ( ) - > get ( ) , 0 ) ;
if ( menu - > get_item_count ( ) > 0 )
menu - > add_separator ( ) ;
2017-06-05 03:12:19 +00:00
2019-04-08 22:18:03 +00:00
menu - > add_icon_shortcut ( get_icon ( " Add " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) , TOOL_NEW ) ;
menu - > add_icon_shortcut ( get_icon ( " Instance " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/instance_scene " ) , TOOL_INSTANCE ) ;
}
2018-07-07 14:51:18 +00:00
menu - > add_icon_shortcut ( get_icon ( " Collapse " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/expand_collapse_all " ) , TOOL_EXPAND_COLLAPSE ) ;
menu - > add_separator ( ) ;
2018-10-03 09:25:18 +00:00
existing_script = selected - > get_script ( ) ;
2019-07-19 19:21:30 +00:00
if ( EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( selected ) = = existing_script ) {
exisiting_script_removable = false ;
}
2018-10-03 09:25:18 +00:00
}
2018-01-02 07:10:49 +00:00
2019-04-08 22:18:03 +00:00
if ( profile_allow_script_editing ) {
2019-11-04 15:45:16 +00:00
bool add_separator = false ;
2018-10-03 09:25:18 +00:00
2019-11-04 15:45:16 +00:00
if ( full_selection . size ( ) = = 1 ) {
add_separator = true ;
2019-10-21 04:57:10 +00:00
menu - > add_icon_shortcut ( get_icon ( " ScriptCreate " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/attach_script " ) , TOOL_ATTACH_SCRIPT ) ;
if ( existing_script . is_valid ( ) ) {
menu - > add_icon_shortcut ( get_icon ( " ScriptExtend " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/extend_script " ) , TOOL_EXTEND_SCRIPT ) ;
2019-04-14 12:04:04 +00:00
}
2019-04-08 22:18:03 +00:00
}
2019-11-04 15:45:16 +00:00
if ( existing_script . is_valid ( ) & & exisiting_script_removable ) {
add_separator = true ;
2020-05-09 16:59:19 +00:00
menu - > add_icon_shortcut ( get_icon ( " ScriptRemove " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/detach_script " ) , TOOL_DETACH_SCRIPT ) ;
2019-11-04 15:45:16 +00:00
} else if ( full_selection . size ( ) > 1 ) {
bool script_exists = false ;
for ( List < Node * > : : Element * E = full_selection . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! E - > get ( ) - > get_script ( ) . is_null ( ) ) {
script_exists = true ;
break ;
}
}
if ( script_exists ) {
add_separator = true ;
2020-05-09 16:59:19 +00:00
menu - > add_icon_shortcut ( get_icon ( " ScriptRemove " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/detach_script " ) , TOOL_DETACH_SCRIPT ) ;
2019-11-04 15:45:16 +00:00
}
}
if ( add_separator ) {
menu - > add_separator ( ) ;
2019-04-08 22:18:03 +00:00
}
2016-05-16 02:41:48 +00:00
}
2018-10-03 09:25:18 +00:00
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
2019-11-04 15:45:16 +00:00
if ( full_selection . size ( ) = = 1 ) {
2019-04-08 22:18:03 +00:00
menu - > add_icon_shortcut ( get_icon ( " Rename " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/rename " ) , TOOL_RENAME ) ;
}
menu - > add_icon_shortcut ( get_icon ( " Reload " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/change_node_type " ) , TOOL_REPLACE ) ;
if ( scene_tree - > get_selected ( ) ! = edited_scene ) {
menu - > add_separator ( ) ;
menu - > add_icon_shortcut ( get_icon ( " MoveUp " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/move_up " ) , TOOL_MOVE_UP ) ;
menu - > add_icon_shortcut ( get_icon ( " MoveDown " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/move_down " ) , TOOL_MOVE_DOWN ) ;
menu - > add_icon_shortcut ( get_icon ( " Duplicate " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/duplicate " ) , TOOL_DUPLICATE ) ;
menu - > add_icon_shortcut ( get_icon ( " Reparent " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/reparent " ) , TOOL_REPARENT ) ;
2018-09-12 18:47:12 +00:00
menu - > add_icon_shortcut ( get_icon ( " ReparentToNewNode " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/reparent_to_new_node " ) , TOOL_REPARENT_TO_NEW_NODE ) ;
2019-11-04 15:45:16 +00:00
if ( selection . size ( ) = = 1 ) {
menu - > add_icon_shortcut ( get_icon ( " NewRoot " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/make_root " ) , TOOL_MAKE_ROOT ) ;
}
2019-04-08 22:18:03 +00:00
}
2018-01-02 07:10:49 +00:00
}
2017-03-05 15:44:50 +00:00
if ( selection . size ( ) = = 1 ) {
2018-07-16 02:52:57 +00:00
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > add_separator ( ) ;
menu - > add_icon_shortcut ( get_icon ( " Blend " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/merge_from_scene " ) , TOOL_MERGE_FROM_SCENE ) ;
menu - > add_icon_shortcut ( get_icon ( " CreateNewSceneFrom " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/save_branch_as_scene " ) , TOOL_NEW_SCENE_FROM ) ;
2019-11-04 15:45:16 +00:00
}
if ( full_selection . size ( ) = = 1 ) {
2019-04-08 22:18:03 +00:00
menu - > add_separator ( ) ;
2019-11-04 15:45:16 +00:00
menu - > add_icon_shortcut ( get_icon ( " CopyNodePath " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/copy_node_path " ) , TOOL_COPY_NODE_PATH ) ;
2019-04-08 22:18:03 +00:00
}
2017-07-04 10:50:20 +00:00
bool is_external = ( selection [ 0 ] - > get_filename ( ) ! = " " ) ;
2017-06-30 16:17:33 +00:00
if ( is_external ) {
bool is_inherited = selection [ 0 ] - > get_scene_inherited_state ( ) ! = NULL ;
2017-07-04 10:50:20 +00:00
bool is_top_level = selection [ 0 ] - > get_owner ( ) = = NULL ;
2017-07-28 08:32:49 +00:00
if ( is_inherited & & is_top_level ) {
2017-07-04 10:50:20 +00:00
menu - > add_separator ( ) ;
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > add_item ( TTR ( " Clear Inheritance " ) , TOOL_SCENE_CLEAR_INHERITANCE ) ;
}
2017-06-30 16:17:33 +00:00
menu - > add_icon_item ( get_icon ( " Load " , " EditorIcons " ) , TTR ( " Open in Editor " ) , TOOL_SCENE_OPEN_INHERITED ) ;
2017-07-04 10:50:20 +00:00
} else if ( ! is_top_level ) {
menu - > add_separator ( ) ;
2017-06-30 16:17:33 +00:00
bool editable = EditorNode : : get_singleton ( ) - > get_edited_scene ( ) - > is_editable_instance ( selection [ 0 ] ) ;
bool placeholder = selection [ 0 ] - > get_scene_instance_load_placeholder ( ) ;
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > add_check_item ( TTR ( " Editable Children " ) , TOOL_SCENE_EDITABLE_CHILDREN ) ;
menu - > add_check_item ( TTR ( " Load As Placeholder " ) , TOOL_SCENE_USE_PLACEHOLDER ) ;
menu - > add_item ( TTR ( " Make Local " ) , TOOL_SCENE_MAKE_LOCAL ) ;
}
2017-06-30 16:17:33 +00:00
menu - > add_icon_item ( get_icon ( " Load " , " EditorIcons " ) , TTR ( " Open in Editor " ) , TOOL_SCENE_OPEN ) ;
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > set_item_checked ( menu - > get_item_idx_from_text ( TTR ( " Editable Children " ) ) , editable ) ;
menu - > set_item_checked ( menu - > get_item_idx_from_text ( TTR ( " Load As Placeholder " ) ) , placeholder ) ;
}
2017-06-30 16:17:33 +00:00
}
}
2016-05-16 02:41:48 +00:00
}
2018-05-17 21:02:16 +00:00
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing & & selection . size ( ) > 1 ) {
2018-05-17 21:02:16 +00: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 ( ) ;
menu - > add_icon_shortcut ( get_icon ( " Rename " , " EditorIcons " ) , ED_GET_SHORTCUT ( " scene_tree/batch_rename " ) , TOOL_BATCH_RENAME ) ;
}
2018-10-03 09:25:18 +00:00
menu - > add_separator ( ) ;
2019-03-06 04:19:34 +00:00
menu - > add_icon_item ( get_icon ( " Help " , " EditorIcons " ) , TTR ( " Open Documentation " ) , TOOL_OPEN_DOCUMENTATION ) ;
2018-10-03 09:25:18 +00:00
2019-04-08 22:18:03 +00:00
if ( profile_allow_editing ) {
menu - > add_separator ( ) ;
menu - > add_icon_shortcut ( get_icon ( " Remove " , " EditorIcons " ) , ED_SHORTCUT ( " scene_tree/delete " , TTR ( " Delete Node(s) " ) , KEY_DELETE ) , TOOL_ERASE ) ;
}
2017-03-05 15:44:50 +00:00
menu - > set_size ( Size2 ( 1 , 1 ) ) ;
2017-03-29 15:29:38 +00:00
menu - > set_position ( p_menu_pos ) ;
2016-05-16 02:41:48 +00:00
menu - > popup ( ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : _filter_changed ( const String & p_filter ) {
2016-05-16 15:23:40 +00:00
scene_tree - > set_filter ( p_filter ) ;
}
String SceneTreeDock : : get_filter ( ) {
return filter - > get_text ( ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeDock : : set_filter ( const String & p_filter ) {
2016-05-16 15:23:40 +00:00
filter - > set_text ( p_filter ) ;
scene_tree - > set_filter ( p_filter ) ;
}
2016-07-28 19:37:52 +00:00
void SceneTreeDock : : _focus_node ( ) {
Node * node = scene_tree - > get_selected ( ) ;
ERR_FAIL_COND ( ! node ) ;
2017-01-03 02:03:46 +00:00
if ( node - > is_class ( " CanvasItem " ) ) {
2017-08-24 20:58:51 +00:00
CanvasItemEditorPlugin * editor = Object : : cast_to < CanvasItemEditorPlugin > ( editor_data - > get_editor ( " 2D " ) ) ;
2016-07-28 19:37:52 +00:00
editor - > get_canvas_item_editor ( ) - > focus_selection ( ) ;
} else {
2017-08-24 20:58:51 +00:00
SpatialEditorPlugin * editor = Object : : cast_to < SpatialEditorPlugin > ( editor_data - > get_editor ( " 3D " ) ) ;
2016-07-28 19:37:52 +00:00
editor - > get_spatial_editor ( ) - > get_editor_viewport ( 0 ) - > focus_selection ( ) ;
}
}
2019-10-21 04:57:10 +00:00
void SceneTreeDock : : attach_script_to_selected ( bool p_extend ) {
2020-05-31 17:31:45 +00: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 04:57:10 +00:00
if ( ! profile_allow_script_editing ) {
return ;
}
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
if ( selection . empty ( ) )
return ;
Node * selected = scene_tree - > get_selected ( ) ;
if ( ! selected )
selected = selection . front ( ) - > get ( ) ;
Ref < Script > existing = selected - > get_script ( ) ;
String path = selected - > get_filename ( ) ;
if ( path = = " " ) {
String root_path = editor_data - > get_edited_scene_root ( ) - > get_filename ( ) ;
if ( root_path = = " " ) {
path = String ( " res:// " ) . plus_file ( selected - > get_name ( ) ) ;
} else {
path = root_path . get_base_dir ( ) . plus_file ( selected - > get_name ( ) ) ;
}
}
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 ;
}
}
}
script_create_dialog - > connect ( " script_created " , this , " _script_created " ) ;
2019-12-20 06:58:24 +00:00
script_create_dialog - > connect ( " popup_hide " , this , " _script_creation_closed " , varray ( ) , CONNECT_ONESHOT ) ;
2019-10-21 04:57:10 +00: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-12 22:31:07 +00:00
2017-03-05 15:44:50 +00:00
scene_tree - > set_selected ( p_for_node , false ) ;
2019-10-21 04:57:10 +00:00
if ( p_extend ) {
_tool_selected ( TOOL_EXTEND_SCRIPT ) ;
} else {
_tool_selected ( TOOL_ATTACH_SCRIPT ) ;
}
2016-09-12 22:31:07 +00:00
}
2017-11-16 01:21:29 +00:00
void SceneTreeDock : : add_remote_tree_editor ( Control * p_remote ) {
ERR_FAIL_COND ( remote_tree ! = NULL ) ;
add_child ( p_remote ) ;
remote_tree = p_remote ;
remote_tree - > hide ( ) ;
}
void SceneTreeDock : : show_remote_tree ( ) {
_remote_tree_selected ( ) ;
}
void SceneTreeDock : : hide_remote_tree ( ) {
_local_tree_selected ( ) ;
}
2017-11-22 13:50:54 +00:00
void SceneTreeDock : : show_tab_buttons ( ) {
button_hb - > show ( ) ;
}
void SceneTreeDock : : hide_tab_buttons ( ) {
button_hb - > hide ( ) ;
}
2017-11-16 01:21:29 +00:00
void SceneTreeDock : : _remote_tree_selected ( ) {
scene_tree - > hide ( ) ;
2019-05-30 00:20:59 +00:00
create_root_dialog - > hide ( ) ;
2017-11-16 01:21:29 +00:00
if ( remote_tree )
remote_tree - > show ( ) ;
edit_remote - > set_pressed ( true ) ;
edit_local - > set_pressed ( false ) ;
2017-11-23 07:23:24 +00:00
emit_signal ( " remote_tree_selected " ) ;
2017-11-16 01:21:29 +00:00
}
void SceneTreeDock : : _local_tree_selected ( ) {
2020-06-09 22:06:15 +00:00
if ( ! bool ( EDITOR_GET ( " interface/editors/show_scene_tree_root_selection " ) ) | | get_tree ( ) - > get_edited_scene_root ( ) ! = nullptr ) {
scene_tree - > show ( ) ;
}
2017-11-16 01:21:29 +00:00
if ( remote_tree )
remote_tree - > hide ( ) ;
edit_remote - > set_pressed ( false ) ;
edit_local - > set_pressed ( true ) ;
}
2018-07-25 03:48:24 +00:00
void SceneTreeDock : : _update_create_root_dialog ( ) {
BaseButton * toggle = Object : : cast_to < BaseButton > ( create_root_dialog - > get_node ( String ( " NodeShortcutsTopRow/NodeShortcutsToggle " ) ) ) ;
Node * node_shortcuts = create_root_dialog - > get_node ( String ( " NodeShortcuts " ) ) ;
if ( ! toggle | | ! node_shortcuts )
return ;
Control * beginner_nodes = Object : : cast_to < Control > ( node_shortcuts - > get_node ( String ( " BeginnerNodeShortcuts " ) ) ) ;
Control * favorite_nodes = Object : : cast_to < Control > ( node_shortcuts - > get_node ( String ( " FavoriteNodeShortcuts " ) ) ) ;
if ( ! beginner_nodes | | ! favorite_nodes )
return ;
EditorSettings : : get_singleton ( ) - > set_setting ( " _use_favorites_root_selection " , toggle - > is_pressed ( ) ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
if ( toggle - > is_pressed ( ) ) {
for ( int i = 0 ; i < favorite_nodes - > get_child_count ( ) ; i + + ) {
favorite_nodes - > get_child ( i ) - > queue_delete ( ) ;
}
FileAccess * f = FileAccess : : open ( EditorSettings : : get_singleton ( ) - > get_project_settings_dir ( ) . plus_file ( " favorites.Node " ) , FileAccess : : READ ) ;
if ( f ) {
while ( ! f - > eof_reached ( ) ) {
String l = f - > get_line ( ) . strip_edges ( ) ;
if ( l ! = String ( ) ) {
Button * button = memnew ( Button ) ;
favorite_nodes - > add_child ( button ) ;
button - > set_text ( TTR ( l ) ) ;
String name = l . get_slicec ( ' ' , 0 ) ;
if ( ScriptServer : : is_global_class ( name ) )
2019-03-09 03:47:27 +00:00
name = ScriptServer : : get_global_class_native_base ( name ) ;
2018-09-02 21:40:51 +00:00
button - > set_icon ( EditorNode : : get_singleton ( ) - > get_class_icon ( name ) ) ;
2018-07-25 03:48:24 +00:00
button - > connect ( " pressed " , this , " _favorite_root_selected " , make_binds ( l ) ) ;
}
}
memdelete ( f ) ;
}
if ( ! favorite_nodes - > is_visible_in_tree ( ) ) {
favorite_nodes - > show ( ) ;
beginner_nodes - > hide ( ) ;
}
} else {
if ( ! beginner_nodes - > is_visible_in_tree ( ) ) {
beginner_nodes - > show ( ) ;
favorite_nodes - > hide ( ) ;
}
}
}
void SceneTreeDock : : _favorite_root_selected ( const String & p_class ) {
selected_favorite_root = p_class ;
_tool_selected ( TOOL_CREATE_FAVORITE , false ) ;
}
2019-04-08 22:18:03 +00: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 15:58:56 +00:00
bool profile_allow_3d = ! profile - > is_feature_disabled ( EditorFeatureProfile : : FEATURE_3D ) ;
2019-04-08 22:18:03 +00:00
2019-11-10 15:58:56 +00:00
button_3d - > set_visible ( profile_allow_3d ) ;
2019-04-08 22:18:03 +00: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 15:58:56 +00:00
button_3d - > set_visible ( true ) ;
2019-04-08 22:18:03 +00: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 ( ) ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeDock : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _tool_selected " ) , & SceneTreeDock : : _tool_selected , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _create " ) , & SceneTreeDock : : _create ) ;
ClassDB : : bind_method ( D_METHOD ( " _node_reparent " ) , & SceneTreeDock : : _node_reparent ) ;
ClassDB : : bind_method ( D_METHOD ( " _set_owners " ) , & SceneTreeDock : : _set_owners ) ;
ClassDB : : bind_method ( D_METHOD ( " _node_selected " ) , & SceneTreeDock : : _node_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " _node_renamed " ) , & SceneTreeDock : : _node_renamed ) ;
ClassDB : : bind_method ( D_METHOD ( " _script_created " ) , & SceneTreeDock : : _script_created ) ;
2019-06-30 03:19:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " _script_creation_closed " ) , & SceneTreeDock : : _script_creation_closed ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _load_request " ) , & SceneTreeDock : : _load_request ) ;
ClassDB : : bind_method ( D_METHOD ( " _script_open_request " ) , & SceneTreeDock : : _script_open_request ) ;
ClassDB : : bind_method ( D_METHOD ( " _unhandled_key_input " ) , & SceneTreeDock : : _unhandled_key_input ) ;
ClassDB : : bind_method ( D_METHOD ( " _input " ) , & SceneTreeDock : : _input ) ;
ClassDB : : bind_method ( D_METHOD ( " _nodes_drag_begin " ) , & SceneTreeDock : : _nodes_drag_begin ) ;
ClassDB : : bind_method ( D_METHOD ( " _delete_confirm " ) , & SceneTreeDock : : _delete_confirm ) ;
2019-05-14 00:11:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " _toggle_editable_children_from_selection " ) , & SceneTreeDock : : _toggle_editable_children_from_selection ) ;
2019-09-04 19:02:26 +00:00
ClassDB : : bind_method ( D_METHOD ( " _toggle_placeholder_from_selection " ) , & SceneTreeDock : : _toggle_placeholder_from_selection ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _node_prerenamed " ) , & SceneTreeDock : : _node_prerenamed ) ;
ClassDB : : bind_method ( D_METHOD ( " _import_subscene " ) , & SceneTreeDock : : _import_subscene ) ;
ClassDB : : bind_method ( D_METHOD ( " _selection_changed " ) , & SceneTreeDock : : _selection_changed ) ;
2018-07-07 14:51:18 +00:00
ClassDB : : bind_method ( D_METHOD ( " _node_collapsed " ) , & SceneTreeDock : : _node_collapsed ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _new_scene_from " ) , & SceneTreeDock : : _new_scene_from ) ;
ClassDB : : bind_method ( D_METHOD ( " _nodes_dragged " ) , & SceneTreeDock : : _nodes_dragged ) ;
ClassDB : : bind_method ( D_METHOD ( " _files_dropped " ) , & SceneTreeDock : : _files_dropped ) ;
2018-10-17 05:03:22 +00:00
ClassDB : : bind_method ( D_METHOD ( " _quick_open " ) , & SceneTreeDock : : _quick_open ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _script_dropped " ) , & SceneTreeDock : : _script_dropped ) ;
ClassDB : : bind_method ( D_METHOD ( " _tree_rmb " ) , & SceneTreeDock : : _tree_rmb ) ;
ClassDB : : bind_method ( D_METHOD ( " _filter_changed " ) , & SceneTreeDock : : _filter_changed ) ;
ClassDB : : bind_method ( D_METHOD ( " _focus_node " ) , & SceneTreeDock : : _focus_node ) ;
2017-11-16 01:21:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " _remote_tree_selected " ) , & SceneTreeDock : : _remote_tree_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " _local_tree_selected " ) , & SceneTreeDock : : _local_tree_selected ) ;
2018-03-07 19:08:13 +00:00
ClassDB : : bind_method ( D_METHOD ( " _update_script_button " ) , & SceneTreeDock : : _update_script_button ) ;
2018-07-25 03:48:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " _favorite_root_selected " ) , & SceneTreeDock : : _favorite_root_selected ) ;
ClassDB : : bind_method ( D_METHOD ( " _update_create_root_dialog " ) , & SceneTreeDock : : _update_create_root_dialog ) ;
2019-04-08 22:18:03 +00:00
ClassDB : : bind_method ( D_METHOD ( " _feature_profile_changed " ) , & SceneTreeDock : : _feature_profile_changed ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " instance " ) , & SceneTreeDock : : instance ) ;
2019-08-20 16:06:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_tree_editor " ) , & SceneTreeDock : : get_tree_editor ) ;
2019-04-23 19:10:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " replace_node " ) , & SceneTreeDock : : replace_node ) ;
2017-11-23 07:23:24 +00:00
ADD_SIGNAL ( MethodInfo ( " remote_tree_selected " ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
SceneTreeDock : : SceneTreeDock ( EditorNode * p_editor , Node * p_scene_root , EditorSelection * p_editor_selection , EditorData & p_editor_data ) {
2014-02-10 01:10:30 +00:00
2017-11-26 01:59:31 +00:00
set_name ( " Scene " ) ;
2017-03-05 15:44:50 +00:00
editor = p_editor ;
edited_scene = NULL ;
editor_data = & p_editor_data ;
editor_selection = p_editor_selection ;
scene_root = p_scene_root ;
2014-02-10 01:10:30 +00:00
VBoxContainer * vbc = this ;
2017-03-05 15:44:50 +00:00
HBoxContainer * filter_hbc = memnew ( HBoxContainer ) ;
2017-04-28 02:01:17 +00:00
filter_hbc - > add_constant_override ( " separate " , 0 ) ;
2014-02-10 01:10:30 +00:00
2018-05-11 05:48:14 +00:00
ED_SHORTCUT ( " scene_tree/rename " , TTR ( " Rename " ) ) ;
2018-01-21 06:12:25 +00:00
ED_SHORTCUT ( " scene_tree/batch_rename " , TTR ( " Batch Rename " ) , KEY_MASK_CMD | KEY_F2 ) ;
2017-03-05 15:44:50 +00:00
ED_SHORTCUT ( " scene_tree/add_child_node " , TTR ( " Add Child Node " ) , KEY_MASK_CMD | KEY_A ) ;
ED_SHORTCUT ( " scene_tree/instance_scene " , TTR ( " Instance Child Scene " ) ) ;
2018-07-07 14:51:18 +00:00
ED_SHORTCUT ( " scene_tree/expand_collapse_all " , TTR ( " Expand/Collapse All " ) ) ;
2016-06-19 19:33:42 +00:00
ED_SHORTCUT ( " scene_tree/change_node_type " , TTR ( " Change Type " ) ) ;
2016-11-09 16:29:15 +00:00
ED_SHORTCUT ( " scene_tree/attach_script " , TTR ( " Attach Script " ) ) ;
2018-10-25 18:33:16 +00:00
ED_SHORTCUT ( " scene_tree/extend_script " , TTR ( " Extend Script " ) ) ;
2020-05-09 16:59:19 +00:00
ED_SHORTCUT ( " scene_tree/detach_script " , TTR ( " Detach Script " ) ) ;
2016-06-19 19:33:42 +00:00
ED_SHORTCUT ( " scene_tree/move_up " , TTR ( " Move Up " ) , KEY_MASK_CMD | KEY_UP ) ;
ED_SHORTCUT ( " scene_tree/move_down " , TTR ( " Move Down " ) , KEY_MASK_CMD | KEY_DOWN ) ;
2017-03-05 15:44:50 +00:00
ED_SHORTCUT ( " scene_tree/duplicate " , TTR ( " Duplicate " ) , KEY_MASK_CMD | KEY_D ) ;
2016-06-19 19:33:42 +00:00
ED_SHORTCUT ( " scene_tree/reparent " , TTR ( " Reparent " ) ) ;
2018-09-12 18:47:12 +00:00
ED_SHORTCUT ( " scene_tree/reparent_to_new_node " , TTR ( " Reparent to New Node " ) ) ;
2018-07-16 02:52:57 +00:00
ED_SHORTCUT ( " scene_tree/make_root " , TTR ( " Make Scene Root " ) ) ;
2016-06-19 19:33:42 +00:00
ED_SHORTCUT ( " scene_tree/merge_from_scene " , TTR ( " Merge From Scene " ) ) ;
ED_SHORTCUT ( " scene_tree/save_branch_as_scene " , TTR ( " Save Branch as Scene " ) ) ;
2017-03-05 15:44:50 +00:00
ED_SHORTCUT ( " scene_tree/copy_node_path " , TTR ( " Copy Node Path " ) , KEY_MASK_CMD | KEY_C ) ;
ED_SHORTCUT ( " scene_tree/delete_no_confirm " , TTR ( " Delete (No Confirm) " ) , KEY_MASK_SHIFT | KEY_DELETE ) ;
2016-06-12 15:47:29 +00:00
ED_SHORTCUT ( " scene_tree/delete " , TTR ( " Delete " ) , KEY_DELETE ) ;
2016-06-19 19:33:42 +00:00
2019-03-06 04:19:34 +00:00
button_add = memnew ( ToolButton ) ;
button_add - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_NEW , false ) ) ;
2018-07-07 14:51:18 +00:00
button_add - > set_tooltip ( TTR ( " Add/Create a New Node. " ) ) ;
2019-03-06 04:19:34 +00:00
button_add - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/add_child_node " ) ) ;
filter_hbc - > add_child ( button_add ) ;
2014-02-10 01:10:30 +00:00
2019-03-06 04:19:34 +00:00
button_instance = memnew ( ToolButton ) ;
button_instance - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_INSTANCE , false ) ) ;
button_instance - > set_tooltip ( TTR ( " Instance a scene file as a Node. Creates an inherited scene if no root node exists. " ) ) ;
button_instance - > set_shortcut ( ED_GET_SHORTCUT ( " scene_tree/instance_scene " ) ) ;
filter_hbc - > add_child ( button_instance ) ;
2014-02-10 01:10:30 +00:00
2016-05-16 15:23:40 +00:00
vbc - > add_child ( filter_hbc ) ;
2017-03-05 15:44:50 +00:00
filter = memnew ( LineEdit ) ;
2016-05-16 15:23:40 +00:00
filter - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2017-07-18 19:35:37 +00:00
filter - > set_placeholder ( TTR ( " Filter nodes " ) ) ;
2016-05-16 15:23:40 +00:00
filter_hbc - > add_child ( filter ) ;
2018-10-26 10:44:49 +00:00
filter - > add_constant_override ( " minimum_spaces " , 0 ) ;
2017-03-05 15:44:50 +00:00
filter - > connect ( " text_changed " , this , " _filter_changed " ) ;
2016-05-16 15:23:40 +00:00
2019-03-06 04:19:34 +00:00
button_create_script = memnew ( ToolButton ) ;
button_create_script - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_ATTACH_SCRIPT , false ) ) ;
2020-05-09 16:59:19 +00:00
button_create_script - > set_tooltip ( TTR ( " Attach a new or existing script to the selected node. " ) ) ;
2019-03-06 04:19:34 +00: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-05-09 16:59:19 +00:00
button_detach_script = memnew ( ToolButton ) ;
button_detach_script - > connect ( " pressed " , this , " _tool_selected " , make_binds ( TOOL_DETACH_SCRIPT , false ) ) ;
button_detach_script - > set_tooltip ( TTR ( " Detach the script from the selected node. " ) ) ;
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 14:45:20 +00:00
2017-11-16 01:21:29 +00:00
button_hb = memnew ( HBoxContainer ) ;
vbc - > add_child ( button_hb ) ;
edit_remote = memnew ( ToolButton ) ;
button_hb - > add_child ( edit_remote ) ;
edit_remote - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
edit_remote - > set_text ( TTR ( " Remote " ) ) ;
edit_remote - > set_toggle_mode ( true ) ;
edit_remote - > connect ( " pressed " , this , " _remote_tree_selected " ) ;
edit_local = memnew ( ToolButton ) ;
button_hb - > add_child ( edit_local ) ;
edit_local - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
edit_local - > set_text ( TTR ( " Local " ) ) ;
edit_local - > set_toggle_mode ( true ) ;
edit_local - > connect ( " pressed " , this , " _local_tree_selected " ) ;
remote_tree = NULL ;
button_hb - > hide ( ) ;
2018-07-16 02:11:29 +00:00
create_root_dialog = memnew ( VBoxContainer ) ;
vbc - > add_child ( create_root_dialog ) ;
create_root_dialog - > hide ( ) ;
2017-03-05 15:44:50 +00:00
scene_tree = memnew ( SceneTreeEditor ( false , true , true ) ) ;
2017-11-16 01:21:29 +00:00
2014-02-10 01:10:30 +00:00
vbc - > add_child ( scene_tree ) ;
2017-03-05 15:44:50 +00:00
scene_tree - > set_v_size_flags ( SIZE_EXPAND | SIZE_FILL ) ;
scene_tree - > connect ( " rmb_pressed " , this , " _tree_rmb " ) ;
scene_tree - > connect ( " node_selected " , this , " _node_selected " , varray ( ) , CONNECT_DEFERRED ) ;
scene_tree - > connect ( " node_renamed " , this , " _node_renamed " , varray ( ) , CONNECT_DEFERRED ) ;
scene_tree - > connect ( " node_prerename " , this , " _node_prerenamed " ) ;
scene_tree - > connect ( " open " , this , " _load_request " ) ;
scene_tree - > connect ( " open_script " , this , " _script_open_request " ) ;
scene_tree - > connect ( " nodes_rearranged " , this , " _nodes_dragged " ) ;
scene_tree - > connect ( " files_dropped " , this , " _files_dropped " ) ;
scene_tree - > connect ( " script_dropped " , this , " _script_dropped " ) ;
scene_tree - > connect ( " nodes_dragged " , this , " _nodes_drag_begin " ) ;
2016-05-11 14:46:08 +00:00
2016-07-28 19:37:52 +00:00
scene_tree - > get_scene_tree ( ) - > connect ( " item_double_clicked " , this , " _focus_node " ) ;
2014-02-10 01:10:30 +00:00
scene_tree - > set_undo_redo ( & editor_data - > get_undo_redo ( ) ) ;
scene_tree - > set_editor_selection ( editor_selection ) ;
2017-03-05 15:44:50 +00:00
create_dialog = memnew ( CreateDialog ) ;
2014-02-10 01:10:30 +00:00
create_dialog - > set_base_type ( " Node " ) ;
add_child ( create_dialog ) ;
2017-03-05 15:44:50 +00:00
create_dialog - > connect ( " create " , this , " _create " ) ;
2018-07-25 03:48:24 +00:00
create_dialog - > connect ( " favorites_updated " , this , " _update_create_root_dialog " ) ;
2014-02-10 01:10:30 +00:00
2018-01-21 06:12:25 +00:00
rename_dialog = memnew ( RenameDialog ( scene_tree , & editor_data - > get_undo_redo ( ) ) ) ;
add_child ( rename_dialog ) ;
2017-03-05 15:44:50 +00:00
script_create_dialog = memnew ( ScriptCreateDialog ) ;
2019-02-18 15:45:26 +00:00
script_create_dialog - > set_inheritance_base_type ( " Node " ) ;
2014-02-10 01:10:30 +00:00
add_child ( script_create_dialog ) ;
2015-11-27 20:42:48 +00:00
2017-03-05 15:44:50 +00:00
reparent_dialog = memnew ( ReparentDialog ) ;
2014-02-10 01:10:30 +00:00
add_child ( reparent_dialog ) ;
2017-03-05 15:44:50 +00:00
reparent_dialog - > connect ( " reparent " , this , " _node_reparent " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
accept = memnew ( AcceptDialog ) ;
2014-02-10 01:10:30 +00:00
add_child ( accept ) ;
2018-10-17 05:03:22 +00:00
quick_open = memnew ( EditorQuickOpen ) ;
add_child ( quick_open ) ;
quick_open - > connect ( " quick_open " , this , " _quick_open " ) ;
2014-04-10 03:18:27 +00:00
set_process_unhandled_key_input ( true ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
delete_dialog = memnew ( ConfirmationDialog ) ;
2014-02-10 01:10:30 +00:00
add_child ( delete_dialog ) ;
2017-03-05 15:44:50 +00:00
delete_dialog - > connect ( " confirmed " , this , " _delete_confirm " ) ;
2015-11-27 20:42:48 +00:00
2018-09-12 22:49:12 +00:00
editable_instance_remove_dialog = memnew ( ConfirmationDialog ) ;
add_child ( editable_instance_remove_dialog ) ;
2019-05-14 00:11:06 +00:00
editable_instance_remove_dialog - > connect ( " confirmed " , this , " _toggle_editable_children_from_selection " ) ;
2018-09-12 22:49:12 +00:00
2019-09-04 19:02:26 +00:00
placeholder_editable_instance_remove_dialog = memnew ( ConfirmationDialog ) ;
add_child ( placeholder_editable_instance_remove_dialog ) ;
placeholder_editable_instance_remove_dialog - > connect ( " confirmed " , this , " _toggle_placeholder_from_selection " ) ;
2017-03-05 15:44:50 +00:00
import_subscene_dialog = memnew ( EditorSubScene ) ;
2014-02-10 01:10:30 +00:00
add_child ( import_subscene_dialog ) ;
2017-03-05 15:44:50 +00:00
import_subscene_dialog - > connect ( " subscene_selected " , this , " _import_subscene " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
new_scene_from_dialog = memnew ( EditorFileDialog ) ;
2015-11-27 20:42:48 +00:00
new_scene_from_dialog - > set_mode ( EditorFileDialog : : MODE_SAVE_FILE ) ;
add_child ( new_scene_from_dialog ) ;
2017-03-05 15:44:50 +00:00
new_scene_from_dialog - > connect ( " file_selected " , this , " _new_scene_from " ) ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
menu = memnew ( PopupMenu ) ;
2016-05-16 02:41:48 +00:00
add_child ( menu ) ;
2017-03-05 15:44:50 +00:00
menu - > connect ( " id_pressed " , this , " _tool_selected " ) ;
2018-01-02 07:10:49 +00:00
menu - > set_hide_on_window_lose_focus ( true ) ;
2017-12-17 14:55:24 +00:00
menu_subresources = memnew ( PopupMenu ) ;
menu_subresources - > set_name ( " Sub-Resources " ) ;
2018-01-13 08:05:50 +00:00
menu_subresources - > connect ( " id_pressed " , this , " _tool_selected " ) ;
2017-12-17 14:55:24 +00:00
menu - > add_child ( menu_subresources ) ;
2017-03-05 15:44:50 +00:00
first_enter = true ;
restore_script_editor_on_drag = false ;
2014-02-10 01:10:30 +00:00
2017-06-30 16:17:33 +00:00
clear_inherit_confirm = memnew ( ConfirmationDialog ) ;
clear_inherit_confirm - > set_text ( TTR ( " Clear Inheritance? (No Undo!) " ) ) ;
2018-08-09 09:22:11 +00:00
clear_inherit_confirm - > get_ok ( ) - > set_text ( TTR ( " Clear " ) ) ;
2017-06-30 16:17:33 +00:00
add_child ( clear_inherit_confirm ) ;
2016-08-03 14:28:20 +00:00
set_process_input ( true ) ;
2018-07-16 02:11:29 +00:00
set_process ( true ) ;
2019-04-08 22:18:03 +00:00
profile_allow_editing = true ;
profile_allow_script_editing = true ;
2018-07-16 02:11:29 +00:00
EDITOR_DEF ( " interface/editors/show_scene_tree_root_selection " , true ) ;
2019-09-03 10:42:34 +00:00
EDITOR_DEF ( " interface/editors/derive_script_globals_by_name " , true ) ;
2018-07-25 03:48:24 +00:00
EDITOR_DEF ( " _use_favorites_root_selection " , false ) ;
2014-02-10 01:10:30 +00:00
}