2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* scene_tree_editor.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
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 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_editor.h"
2017-01-16 07:04:19 +00:00
2020-11-07 22:33:38 +00:00
# include "core/object/message_queue.h"
# include "core/string/print_string.h"
2019-12-24 07:17:23 +00:00
# include "editor/editor_node.h"
2020-07-11 16:45:19 +00:00
# include "editor/editor_scale.h"
2019-12-24 07:17:23 +00:00
# include "editor/node_dock.h"
2018-06-07 15:46:14 +00:00
# include "editor/plugins/animation_player_editor_plugin.h"
2017-03-05 15:44:50 +00:00
# include "editor/plugins/canvas_item_editor_plugin.h"
# include "scene/gui/label.h"
2020-03-04 01:51:12 +00:00
# include "scene/main/window.h"
2015-10-10 12:09:09 +00:00
# include "scene/resources/packed_scene.h"
2014-02-10 01:10:30 +00:00
Node * SceneTreeEditor : : get_scene_node ( ) {
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , nullptr ) ;
2014-02-10 01:10:30 +00:00
2016-01-17 01:41:10 +00:00
return get_tree ( ) - > get_edited_scene_root ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _cell_button_pressed ( Object * p_item , int p_column , int p_id ) {
2019-04-12 02:21:48 +00:00
if ( connect_to_script_mode ) {
2019-05-19 10:34:40 +00:00
return ; //don't do anything in this mode
2019-04-12 02:21:48 +00:00
}
2019-06-06 02:13:57 +00:00
2017-08-24 20:58:51 +00:00
TreeItem * item = Object : : cast_to < TreeItem > ( p_item ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! n ) ;
2017-03-05 15:44:50 +00:00
if ( p_id = = BUTTON_SUBSCENE ) {
if ( n = = get_scene_node ( ) ) {
2017-06-30 16:17:33 +00:00
if ( n & & n - > get_scene_inherited_state ( ) . is_valid ( ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " open " ) , n - > get_scene_inherited_state ( ) - > get_path ( ) ) ;
2015-10-16 22:11:23 +00:00
}
2017-06-30 16:17:33 +00:00
} else {
2021-09-30 14:30:55 +00:00
emit_signal ( SNAME ( " open " ) , n - > get_scene_file_path ( ) ) ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_SCRIPT ) {
2020-02-13 19:03:10 +00:00
Ref < Script > script_typed = n - > get_script ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! script_typed . is_null ( ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " open_script " ) , script_typed ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_VISIBILITY ) {
2018-01-01 08:05:00 +00:00
undo_redo - > create_action ( TTR ( " Toggle Visible " ) ) ;
2018-05-15 14:13:48 +00:00
_toggle_visible ( n ) ;
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2020-04-01 23:20:12 +00:00
if ( selection . size ( ) > 1 & & selection . find ( n ) ! = nullptr ) {
2021-07-16 03:45:57 +00:00
for ( Node * nv : selection ) {
2018-05-15 14:13:48 +00:00
ERR_FAIL_COND ( ! nv ) ;
if ( nv = = n ) {
continue ;
}
_toggle_visible ( nv ) ;
}
}
2018-01-01 08:05:00 +00:00
undo_redo - > commit_action ( ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_LOCK ) {
2019-04-26 17:23:50 +00:00
undo_redo - > create_action ( TTR ( " Unlock Node " ) ) ;
2014-05-08 05:43:19 +00:00
2020-03-26 21:49:16 +00:00
if ( n - > is_class ( " CanvasItem " ) | | n - > is_class ( " Node3D " ) ) {
2019-04-26 17:23:50 +00:00
undo_redo - > add_do_method ( n , " remove_meta " , " _edit_lock_ " ) ;
undo_redo - > add_undo_method ( n , " set_meta " , " _edit_lock_ " , true ) ;
undo_redo - > add_do_method ( this , " _update_tree " , Variant ( ) ) ;
undo_redo - > add_undo_method ( this , " _update_tree " , Variant ( ) ) ;
undo_redo - > add_do_method ( this , " emit_signal " , " node_changed " ) ;
undo_redo - > add_undo_method ( this , " emit_signal " , " node_changed " ) ;
2014-05-08 05:43:19 +00:00
}
2019-04-26 17:23:50 +00:00
undo_redo - > commit_action ( ) ;
2018-06-07 15:46:14 +00:00
} else if ( p_id = = BUTTON_PIN ) {
if ( n - > is_class ( " AnimationPlayer " ) ) {
2021-02-04 08:20:26 +00:00
AnimationPlayerEditor : : get_singleton ( ) - > unpin ( ) ;
2018-06-07 15:46:14 +00:00
_update_tree ( ) ;
}
2014-05-08 05:43:19 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_GROUP ) {
2019-04-26 17:23:50 +00:00
undo_redo - > create_action ( TTR ( " Button Group " ) ) ;
2020-03-26 21:49:16 +00:00
if ( n - > is_class ( " CanvasItem " ) | | n - > is_class ( " Node3D " ) ) {
2019-04-26 17:23:50 +00:00
undo_redo - > add_do_method ( n , " remove_meta " , " _edit_group_ " ) ;
undo_redo - > add_undo_method ( n , " set_meta " , " _edit_group_ " , true ) ;
undo_redo - > add_do_method ( this , " _update_tree " , Variant ( ) ) ;
undo_redo - > add_undo_method ( this , " _update_tree " , Variant ( ) ) ;
undo_redo - > add_do_method ( this , " emit_signal " , " node_changed " ) ;
undo_redo - > add_undo_method ( this , " emit_signal " , " node_changed " ) ;
2014-05-08 05:43:19 +00:00
}
2019-04-26 17:23:50 +00:00
undo_redo - > commit_action ( ) ;
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_WARNING ) {
2020-10-29 10:01:28 +00:00
String config_err = n - > get_configuration_warnings_as_string ( ) ;
2021-12-09 09:42:46 +00:00
if ( config_err . is_empty ( ) ) {
2016-05-17 21:27:15 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
config_err = config_err . word_wrap ( 80 ) ;
2016-05-17 21:27:15 +00:00
warning - > set_text ( config_err ) ;
2020-03-06 17:00:16 +00:00
warning - > popup_centered ( ) ;
2016-05-17 21:27:15 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_SIGNALS ) {
2016-07-16 21:22:44 +00:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( n ) ;
set_selected ( n ) ;
2021-11-17 20:08:55 +00:00
NodeDock : : get_singleton ( ) - > get_parent ( ) - > call ( " set_current_tab " , NodeDock : : get_singleton ( ) - > get_index ( ) ) ;
NodeDock : : get_singleton ( ) - > show_connections ( ) ;
2016-06-04 16:17:56 +00:00
2017-03-05 15:44:50 +00:00
} else if ( p_id = = BUTTON_GROUPS ) {
2016-07-16 21:22:44 +00:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( n ) ;
set_selected ( n ) ;
2021-11-17 20:08:55 +00:00
NodeDock : : get_singleton ( ) - > get_parent ( ) - > call ( " set_current_tab " , NodeDock : : get_singleton ( ) - > get_index ( ) ) ;
NodeDock : : get_singleton ( ) - > show_groups ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2020-05-14 12:29:06 +00:00
2018-01-01 08:05:00 +00:00
void SceneTreeEditor : : _toggle_visible ( Node * p_node ) {
2018-05-15 14:13:48 +00:00
if ( p_node - > has_method ( " is_visible " ) & & p_node - > has_method ( " set_visible " ) ) {
2018-01-01 08:05:00 +00:00
bool v = bool ( p_node - > call ( " is_visible " ) ) ;
2018-05-15 14:13:48 +00:00
undo_redo - > add_do_method ( p_node , " set_visible " , ! v ) ;
undo_redo - > add_undo_method ( p_node , " set_visible " , v ) ;
2018-01-01 08:05:00 +00:00
}
}
2014-02-10 01:10:30 +00:00
2021-02-08 00:19:46 +00:00
bool SceneTreeEditor : : _add_nodes ( Node * p_node , TreeItem * p_parent , bool p_scroll_to_selected ) {
2020-05-14 14:41:43 +00:00
if ( ! p_node ) {
2016-05-16 15:23:40 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
// only owned nodes are editable, since nodes can create their own (manually owned) child nodes,
// which the editor needs not to know about.
2014-09-03 02:13:40 +00:00
2017-03-05 15:44:50 +00:00
bool part_of_subscene = false ;
2014-09-03 02:13:40 +00:00
2017-03-05 15:44:50 +00:00
if ( ! display_foreign & & p_node - > get_owner ( ) ! = get_scene_node ( ) & & p_node ! = get_scene_node ( ) ) {
2015-10-10 12:09:09 +00:00
if ( ( show_enabled_subscene | | can_open_instance ) & & p_node - > get_owner ( ) & & ( get_scene_node ( ) - > is_editable_instance ( p_node - > get_owner ( ) ) ) ) {
2017-03-05 15:44:50 +00:00
part_of_subscene = true ;
2014-09-03 02:13:40 +00:00
//allow
} else {
2016-05-16 15:23:40 +00:00
return false ;
2014-09-03 02:13:40 +00:00
}
2015-10-10 12:09:09 +00:00
} else {
2017-03-05 15:44:50 +00:00
part_of_subscene = p_node ! = get_scene_node ( ) & & get_scene_node ( ) - > get_scene_inherited_state ( ) . is_valid ( ) & & get_scene_node ( ) - > get_scene_inherited_state ( ) - > find_node_by_path ( get_scene_node ( ) - > get_path_to ( p_node ) ) > = 0 ;
2014-09-03 02:13:40 +00:00
}
2014-02-10 01:10:30 +00:00
TreeItem * item = tree - > create_item ( p_parent ) ;
2018-06-27 23:50:25 +00:00
2017-03-05 15:44:50 +00:00
item - > set_text ( 0 , p_node - > get_name ( ) ) ;
2020-05-14 14:41:43 +00:00
if ( can_rename & & ! part_of_subscene ) {
2014-02-10 01:10:30 +00:00
item - > set_editable ( 0 , true ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
item - > set_selectable ( 0 , true ) ;
2014-02-10 01:10:30 +00:00
if ( can_rename ) {
2016-06-28 16:10:15 +00:00
bool collapsed = p_node - > is_displayed_folded ( ) ;
2020-05-14 14:41:43 +00:00
if ( collapsed ) {
2014-02-10 01:10:30 +00:00
item - > set_collapsed ( true ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2019-06-11 18:43:37 +00:00
Ref < Texture2D > icon = EditorNode : : get_singleton ( ) - > get_object_icon ( p_node , " Node " ) ;
2017-03-05 15:44:50 +00:00
item - > set_icon ( 0 , icon ) ;
item - > set_metadata ( 0 , p_node - > get_path ( ) ) ;
2015-10-10 12:09:09 +00:00
2019-04-12 02:21:48 +00:00
if ( connect_to_script_mode ) {
2021-07-17 21:22:52 +00:00
Color accent = get_theme_color ( SNAME ( " accent_color " ) , SNAME ( " Editor " ) ) ;
2019-04-12 02:21:48 +00:00
2019-07-12 15:53:07 +00:00
Ref < Script > script = p_node - > get_script ( ) ;
2019-07-19 19:21:30 +00:00
if ( ! script . is_null ( ) & & EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( p_node ) ! = script ) {
2019-04-12 02:21:48 +00:00
//has script
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , BUTTON_SCRIPT ) ;
2019-04-12 02:21:48 +00:00
} else {
2019-07-19 19:21:30 +00:00
//has no script (or script is a custom type)
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " disabled_font_color " ) , SNAME ( " Editor " ) ) ) ;
2019-04-12 02:21:48 +00:00
item - > set_selectable ( 0 , false ) ;
2019-07-19 19:21:30 +00:00
if ( ! script . is_null ( ) ) { // make sure to mark the script if a custom type
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , BUTTON_SCRIPT ) ;
2019-07-19 19:21:30 +00:00
item - > set_button_disabled ( 0 , item - > get_button_count ( 0 ) - 1 , true ) ;
}
2019-04-12 02:21:48 +00:00
accent . a * = 0.7 ;
}
if ( marked . has ( p_node ) ) {
2019-06-06 02:13:57 +00:00
String node_name = p_node - > get_name ( ) ;
if ( connecting_signal ) {
node_name + = " " + TTR ( " (Connecting From) " ) ;
}
item - > set_text ( 0 , node_name ) ;
2019-04-12 02:21:48 +00:00
item - > set_custom_color ( 0 , accent ) ;
}
} else if ( part_of_subscene ) {
2018-06-27 23:50:25 +00:00
if ( valid_types . size ( ) = = 0 ) {
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " disabled_font_color " ) , SNAME ( " Editor " ) ) ) ;
2018-06-27 23:50:25 +00:00
}
2014-09-03 02:13:40 +00:00
} else if ( marked . has ( p_node ) ) {
2019-06-06 02:13:57 +00:00
String node_name = p_node - > get_name ( ) ;
if ( connecting_signal ) {
node_name + = " " + TTR ( " (Connecting From) " ) ;
2019-04-12 02:21:48 +00:00
}
2019-06-06 02:13:57 +00:00
item - > set_text ( 0 , node_name ) ;
item - > set_selectable ( 0 , marked_selectable ) ;
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " accent_color " ) , SNAME ( " Editor " ) ) ) ;
2021-02-18 18:52:29 +00:00
} else if ( ! p_node - > can_process ( ) ) {
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " disabled_font_color " ) , SNAME ( " Editor " ) ) ) ;
2014-02-10 01:10:30 +00:00
} else if ( ! marked_selectable & & ! marked_children_selectable ) {
2017-03-05 15:44:50 +00:00
Node * node = p_node ;
while ( node ) {
2014-02-10 01:10:30 +00:00
if ( marked . has ( node ) ) {
2017-03-05 15:44:50 +00:00
item - > set_selectable ( 0 , false ) ;
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " error_color " ) , SNAME ( " Editor " ) ) ) ;
2014-02-10 01:10:30 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
node = node - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2016-06-04 16:17:56 +00:00
if ( can_rename ) { //should be can edit..
2020-10-29 10:01:28 +00:00
String warning = p_node - > get_configuration_warnings_as_string ( ) ;
2020-12-15 12:04:21 +00:00
if ( ! warning . is_empty ( ) ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " NodeWarning " ) , SNAME ( " EditorIcons " ) ) , BUTTON_WARNING , false , TTR ( " Node configuration warning: " ) + " \n " + warning ) ;
2016-06-04 16:17:56 +00:00
}
2019-08-16 20:30:31 +00:00
int num_connections = p_node - > get_persistent_signal_connection_count ( ) ;
int num_groups = p_node - > get_persistent_group_count ( ) ;
2020-07-16 08:52:06 +00:00
String msg_temp ;
if ( num_connections > = 1 ) {
Array arr ;
arr . push_back ( num_connections ) ;
msg_temp + = TTRN ( " Node has one connection. " , " Node has {num} connections. " , num_connections ) . format ( arr , " {num} " ) ;
msg_temp + = " " ;
}
if ( num_groups > = 1 ) {
Array arr ;
arr . push_back ( num_groups ) ;
msg_temp + = TTRN ( " Node is in one group. " , " Node is in {num} groups. " , num_groups ) . format ( arr , " {num} " ) ;
}
if ( num_connections > = 1 | | num_groups > = 1 ) {
2020-08-07 11:17:12 +00:00
msg_temp + = " \n " + TTR ( " Click to show signals dock. " ) ;
2020-07-16 08:52:06 +00:00
}
Ref < Texture2D > icon_temp ;
2021-04-25 14:40:58 +00:00
SceneTreeEditorButton signal_temp = BUTTON_SIGNALS ;
2019-08-16 20:30:31 +00:00
if ( num_connections > = 1 & & num_groups > = 1 ) {
2021-07-17 21:22:52 +00:00
icon_temp = get_theme_icon ( SNAME ( " SignalsAndGroups " ) , SNAME ( " EditorIcons " ) ) ;
2019-08-16 20:30:31 +00:00
} else if ( num_connections > = 1 ) {
2021-07-17 21:22:52 +00:00
icon_temp = get_theme_icon ( SNAME ( " Signals " ) , SNAME ( " EditorIcons " ) ) ;
2019-08-16 20:30:31 +00:00
} else if ( num_groups > = 1 ) {
2021-07-17 21:22:52 +00:00
icon_temp = get_theme_icon ( SNAME ( " Groups " ) , SNAME ( " EditorIcons " ) ) ;
2020-07-16 08:52:06 +00:00
signal_temp = BUTTON_GROUPS ;
}
if ( num_connections > = 1 | | num_groups > = 1 ) {
item - > add_button ( 0 , icon_temp , signal_temp , false , msg_temp ) ;
2016-06-04 16:17:56 +00:00
}
2016-05-17 21:27:15 +00:00
}
2021-09-01 13:02:42 +00:00
// Display the node name in all tooltips so that long node names can be previewed
// without having to rename them.
2017-03-05 15:44:50 +00:00
if ( p_node = = get_scene_node ( ) & & p_node - > get_scene_inherited_state ( ) . is_valid ( ) ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " InstanceOptions " ) , SNAME ( " EditorIcons " ) ) , BUTTON_SUBSCENE , false , TTR ( " Open in Editor " ) ) ;
2014-02-10 01:10:30 +00:00
2021-09-01 13:02:42 +00:00
String tooltip = String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Inherits: " ) + " " + p_node - > get_scene_inherited_state ( ) - > get_path ( ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ;
2021-12-09 09:42:46 +00:00
if ( ! p_node - > get_editor_description ( ) . is_empty ( ) ) {
2019-08-15 12:50:26 +00:00
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
2021-12-09 09:42:46 +00:00
} else if ( p_node ! = get_scene_node ( ) & & ! p_node - > get_scene_file_path ( ) . is_empty ( ) & & can_open_instance ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " InstanceOptions " ) , SNAME ( " EditorIcons " ) ) , BUTTON_SUBSCENE , false , TTR ( " Open in Editor " ) ) ;
2019-08-15 12:50:26 +00:00
2021-09-30 14:30:55 +00:00
String tooltip = String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Instance: " ) + " " + p_node - > get_scene_file_path ( ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ;
2021-12-09 09:42:46 +00:00
if ( ! p_node - > get_editor_description ( ) . is_empty ( ) ) {
2019-08-15 12:50:26 +00:00
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
2014-09-21 04:43:42 +00:00
} else {
2019-07-19 19:21:30 +00:00
StringName type = EditorNode : : get_singleton ( ) - > get_object_custom_type_name ( p_node ) ;
2019-08-15 12:50:26 +00:00
if ( type = = StringName ( ) ) {
2019-07-19 19:21:30 +00:00
type = p_node - > get_class ( ) ;
2019-08-15 12:50:26 +00:00
}
2021-09-01 13:02:42 +00:00
String tooltip = String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Type: " ) + " " + type ;
2021-12-09 09:42:46 +00:00
if ( ! p_node - > get_editor_description ( ) . is_empty ( ) ) {
2019-08-15 12:50:26 +00:00
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
2014-02-10 01:10:30 +00:00
}
2019-03-13 10:19:51 +00:00
if ( can_open_instance & & undo_redo ) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! p_node - > is_connected ( " script_changed " , callable_mp ( this , & SceneTreeEditor : : _node_script_changed ) ) ) {
2020-02-21 17:28:45 +00:00
p_node - > connect ( " script_changed " , callable_mp ( this , & SceneTreeEditor : : _node_script_changed ) , varray ( p_node ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2019-07-12 15:53:07 +00:00
Ref < Script > script = p_node - > get_script ( ) ;
if ( ! script . is_null ( ) ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Script " ) , SNAME ( " EditorIcons " ) ) , BUTTON_SCRIPT , false , TTR ( " Open Script: " ) + " " + script - > get_path ( ) ) ;
2019-07-19 19:21:30 +00:00
if ( EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( p_node ) = = script ) {
item - > set_button_color ( 0 , item - > get_button_count ( 0 ) - 1 , Color ( 1 , 1 , 1 , 0.5 ) ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-01-03 02:03:46 +00:00
if ( p_node - > is_class ( " CanvasItem " ) ) {
2017-03-05 15:44:50 +00:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ; //_edit_group_
2020-05-14 14:41:43 +00:00
if ( is_locked ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Lock " ) , SNAME ( " EditorIcons " ) ) , BUTTON_LOCK , false , TTR ( " Node is locked. \n Click to unlock it. " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-05-08 05:43:19 +00:00
bool is_grouped = p_node - > has_meta ( " _edit_group_ " ) ;
2020-05-14 14:41:43 +00:00
if ( is_grouped ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Group " ) , SNAME ( " EditorIcons " ) ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make selectable. " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-05-08 05:43:19 +00:00
2017-01-18 20:49:30 +00:00
bool v = p_node - > call ( " is_visible " ) ;
2020-05-14 14:41:43 +00:00
if ( v ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " GuiVisibilityVisible " ) , SNAME ( " EditorIcons " ) ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " GuiVisibilityHidden " ) , SNAME ( " EditorIcons " ) ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-05-08 05:43:19 +00:00
2020-05-14 14:41:43 +00:00
if ( ! p_node - > is_connected ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) ) ) {
2020-02-21 17:28:45 +00:00
p_node - > connect ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) , varray ( p_node ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-05-08 05:43:19 +00:00
2016-12-28 13:12:08 +00:00
_update_visibility_color ( p_node , item ) ;
2021-04-18 18:49:21 +00:00
} else if ( p_node - > is_class ( " CanvasLayer " ) ) {
bool v = p_node - > call ( " is_visible " ) ;
if ( v ) {
item - > add_button ( 0 , get_theme_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
} else {
item - > add_button ( 0 , get_theme_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
}
if ( ! p_node - > is_connected ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) ) ) {
p_node - > connect ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) , varray ( p_node ) ) ;
}
2020-03-26 21:49:16 +00:00
} else if ( p_node - > is_class ( " Node3D " ) ) {
2017-10-23 19:21:15 +00:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ;
2020-05-14 14:41:43 +00:00
if ( is_locked ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Lock " ) , SNAME ( " EditorIcons " ) ) , BUTTON_LOCK , false , TTR ( " Node is locked. \n Click to unlock it. " ) ) ;
2020-05-14 14:41:43 +00:00
}
2017-10-23 19:21:15 +00:00
2019-04-17 16:24:28 +00:00
bool is_grouped = p_node - > has_meta ( " _edit_group_ " ) ;
2020-05-14 14:41:43 +00:00
if ( is_grouped ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Group " ) , SNAME ( " EditorIcons " ) ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make selectable. " ) ) ;
2020-05-14 14:41:43 +00:00
}
2019-04-17 16:24:28 +00:00
2017-01-18 20:49:30 +00:00
bool v = p_node - > call ( " is_visible " ) ;
2020-05-14 14:41:43 +00:00
if ( v ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " GuiVisibilityVisible " ) , SNAME ( " EditorIcons " ) ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " GuiVisibilityHidden " ) , SNAME ( " EditorIcons " ) ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! p_node - > is_connected ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) ) ) {
2020-02-21 17:28:45 +00:00
p_node - > connect ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) , varray ( p_node ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2016-12-28 13:12:08 +00:00
_update_visibility_color ( p_node , item ) ;
2018-06-07 15:46:14 +00:00
} else if ( p_node - > is_class ( " AnimationPlayer " ) ) {
2021-02-04 08:20:26 +00:00
bool is_pinned = AnimationPlayerEditor : : get_singleton ( ) - > get_player ( ) = = p_node & & AnimationPlayerEditor : : get_singleton ( ) - > is_pinned ( ) ;
2018-06-07 15:46:14 +00:00
if ( is_pinned ) {
2021-07-17 21:22:52 +00:00
item - > add_button ( 0 , get_theme_icon ( SNAME ( " Pin " ) , SNAME ( " EditorIcons " ) ) , BUTTON_PIN , false , TTR ( " AnimationPlayer is pinned. \n Click to unpin. " ) ) ;
2018-06-07 15:46:14 +00:00
}
2014-02-10 01:10:30 +00:00
}
}
2021-02-08 00:19:46 +00:00
bool scroll = false ;
2014-02-10 01:10:30 +00:00
if ( editor_selection ) {
if ( editor_selection - > is_selected ( p_node ) ) {
item - > select ( 0 ) ;
2021-02-08 00:19:46 +00:00
scroll = p_scroll_to_selected ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
if ( selected = = p_node ) {
2020-05-14 14:41:43 +00:00
if ( ! editor_selection ) {
2014-02-10 01:10:30 +00:00
item - > select ( 0 ) ;
2021-02-08 00:19:46 +00:00
scroll = p_scroll_to_selected ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
item - > set_as_cursor ( 0 ) ;
}
2016-03-08 23:00:52 +00:00
2022-01-26 23:03:56 +00:00
bool keep = ( filter . is_subsequence_ofn ( String ( p_node - > get_name ( ) ) ) ) ;
2016-05-16 15:23:40 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2021-02-08 00:19:46 +00:00
bool child_keep = _add_nodes ( p_node - > get_child ( i ) , item , p_scroll_to_selected ) ;
2016-05-16 15:23:40 +00:00
keep = keep | | child_keep ;
2014-02-10 01:10:30 +00:00
}
2016-05-16 15:23:40 +00:00
2018-06-27 23:50:25 +00:00
if ( valid_types . size ( ) ) {
bool valid = false ;
for ( int i = 0 ; i < valid_types . size ( ) ; i + + ) {
if ( p_node - > is_class ( valid_types [ i ] ) ) {
valid = true ;
break ;
}
}
if ( ! valid ) {
//item->set_selectable(0,marked_selectable);
2021-07-17 21:22:52 +00:00
item - > set_custom_color ( 0 , get_theme_color ( SNAME ( " disabled_font_color " ) , SNAME ( " Editor " ) ) ) ;
2018-06-27 23:50:25 +00:00
item - > set_selectable ( 0 , false ) ;
}
}
2016-05-16 15:23:40 +00:00
if ( ! keep ) {
2019-05-26 18:05:02 +00:00
if ( editor_selection ) {
Node * n = get_node ( item - > get_metadata ( 0 ) ) ;
if ( n ) {
editor_selection - > remove_node ( n ) ;
}
}
2016-05-16 15:23:40 +00:00
memdelete ( item ) ;
return false ;
} else {
2021-02-08 00:19:46 +00:00
if ( scroll ) {
tree - > scroll_to_item ( item ) ;
}
2016-05-16 15:23:40 +00:00
return true ;
}
2014-02-10 01:10:30 +00:00
}
void SceneTreeEditor : : _node_visibility_changed ( Node * p_node ) {
2019-06-03 19:52:50 +00:00
if ( ! p_node | | ( p_node ! = get_scene_node ( ) & & ! p_node - > get_owner ( ) ) ) {
2014-08-14 13:31:38 +00:00
return ;
}
2019-06-03 19:52:50 +00:00
TreeItem * item = _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) ;
if ( ! item ) {
2014-08-14 13:31:38 +00:00
return ;
}
2019-06-03 19:52:50 +00:00
2017-03-05 15:44:50 +00:00
int idx = item - > get_button_by_id ( 0 , BUTTON_VISIBILITY ) ;
ERR_FAIL_COND ( idx = = - 1 ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool visible = false ;
2014-02-10 01:10:30 +00:00
2017-01-19 16:10:47 +00:00
if ( p_node - > is_class ( " CanvasItem " ) ) {
visible = p_node - > call ( " is_visible " ) ;
CanvasItemEditor : : get_singleton ( ) - > get_viewport_control ( ) - > update ( ) ;
2021-04-18 18:49:21 +00:00
} else if ( p_node - > is_class ( " CanvasLayer " ) ) {
visible = p_node - > call ( " is_visible " ) ;
CanvasItemEditor : : get_singleton ( ) - > get_viewport_control ( ) - > update ( ) ;
2020-03-26 21:49:16 +00:00
} else if ( p_node - > is_class ( " Node3D " ) ) {
2017-01-18 20:49:30 +00:00
visible = p_node - > call ( " is_visible " ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( visible ) {
2021-07-17 21:22:52 +00:00
item - > set_button ( 0 , idx , get_theme_icon ( SNAME ( " GuiVisibilityVisible " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2021-07-17 21:22:52 +00:00
item - > set_button ( 0 , idx , get_theme_icon ( SNAME ( " GuiVisibilityHidden " ) , SNAME ( " EditorIcons " ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2016-12-28 13:12:08 +00:00
_update_visibility_color ( p_node , item ) ;
2014-02-10 01:10:30 +00:00
}
2016-12-28 13:12:08 +00:00
void SceneTreeEditor : : _update_visibility_color ( Node * p_node , TreeItem * p_item ) {
2020-03-26 21:49:16 +00:00
if ( p_node - > is_class ( " CanvasItem " ) | | p_node - > is_class ( " Node3D " ) ) {
2017-03-05 15:44:50 +00:00
Color color ( 1 , 1 , 1 , 1 ) ;
2017-07-02 15:27:27 +00:00
bool visible_on_screen = p_node - > call ( " is_visible_in_tree " ) ;
2016-12-28 13:12:08 +00:00
if ( ! visible_on_screen ) {
2017-09-26 02:43:20 +00:00
color . a = 0.6 ;
2016-12-28 13:12:08 +00:00
}
2017-03-05 15:44:50 +00:00
int idx = p_item - > get_button_by_id ( 0 , BUTTON_VISIBILITY ) ;
p_item - > set_button_color ( 0 , idx , color ) ;
2016-12-28 13:12:08 +00:00
}
}
2014-02-10 01:10:30 +00:00
void SceneTreeEditor : : _node_script_changed ( Node * p_node ) {
2020-05-14 14:41:43 +00:00
if ( tree_dirty ) {
2017-11-15 13:41:31 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-11-15 13:41:31 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
2014-02-10 01:10:30 +00:00
}
void SceneTreeEditor : : _node_removed ( Node * p_node ) {
2020-05-14 14:41:43 +00:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) ) {
2016-06-08 01:08:12 +00:00
return ; //speed up exit
2020-05-14 14:41:43 +00:00
}
2016-06-08 01:08:12 +00:00
2020-05-14 14:41:43 +00:00
if ( p_node - > is_connected ( " script_changed " , callable_mp ( this , & SceneTreeEditor : : _node_script_changed ) ) ) {
2020-02-21 17:28:45 +00:00
p_node - > disconnect ( " script_changed " , callable_mp ( this , & SceneTreeEditor : : _node_script_changed ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-04-18 18:49:21 +00:00
if ( p_node - > is_class ( " Node3D " ) | | p_node - > is_class ( " CanvasItem " ) | | p_node - > is_class ( " CanvasLayer " ) ) {
2020-05-14 14:41:43 +00:00
if ( p_node - > is_connected ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) ) ) {
2020-02-21 17:28:45 +00:00
p_node - > disconnect ( " visibility_changed " , callable_mp ( this , & SceneTreeEditor : : _node_visibility_changed ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
if ( p_node = = selected ) {
2020-04-01 23:20:12 +00:00
selected = nullptr ;
2021-08-20 12:48:34 +00:00
emit_signal ( SNAME ( " node_selected " ) ) ;
2014-02-10 01:10:30 +00:00
}
}
2019-05-24 13:27:22 +00:00
void SceneTreeEditor : : _node_renamed ( Node * p_node ) {
2021-09-23 07:19:21 +00:00
if ( p_node ! = get_scene_node ( ) & & ! get_scene_node ( ) - > is_ancestor_of ( p_node ) ) {
2021-04-12 11:26:56 +00:00
return ;
}
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " node_renamed " ) ) ;
2019-05-24 13:27:22 +00:00
if ( ! tree_dirty ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
}
}
2021-02-08 00:19:46 +00:00
void SceneTreeEditor : : _update_tree ( bool p_scroll_to_selected ) {
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) ) {
2017-03-05 15:44:50 +00:00
tree_dirty = false ;
2014-02-10 01:10:30 +00:00
return ;
}
2020-12-31 07:43:03 +00:00
if ( tree - > is_editing ( ) ) {
return ;
}
2017-03-05 15:44:50 +00:00
updating_tree = true ;
2014-02-10 01:10:30 +00:00
tree - > clear ( ) ;
if ( get_scene_node ( ) ) {
2021-02-08 00:19:46 +00:00
_add_nodes ( get_scene_node ( ) , nullptr , p_scroll_to_selected ) ;
2014-02-10 01:10:30 +00:00
last_hash = hash_djb2_one_64 ( 0 ) ;
2017-03-05 15:44:50 +00:00
_compute_hash ( get_scene_node ( ) , last_hash ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
updating_tree = false ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_dirty = false ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _compute_hash ( Node * p_node , uint64_t & hash ) {
2017-08-07 10:17:31 +00:00
hash = hash_djb2_one_64 ( p_node - > get_instance_id ( ) , hash ) ;
2020-05-14 14:41:43 +00:00
if ( p_node - > get_parent ( ) ) {
2017-08-07 10:17:31 +00:00
hash = hash_djb2_one_64 ( p_node - > get_parent ( ) - > get_instance_id ( ) , hash ) ; //so a reparent still produces a different hash
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_compute_hash ( p_node - > get_child ( i ) , hash ) ;
2014-02-10 01:10:30 +00:00
}
}
void SceneTreeEditor : : _test_update_tree ( ) {
2017-03-05 15:44:50 +00:00
pending_test_update = false ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( tree_dirty ) {
2014-02-10 01:10:30 +00:00
return ; // don't even bother
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
uint64_t hash = hash_djb2_one_64 ( 0 ) ;
2020-05-14 14:41:43 +00:00
if ( get_scene_node ( ) ) {
2017-03-05 15:44:50 +00:00
_compute_hash ( get_scene_node ( ) , hash ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
//test hash
2020-05-14 14:41:43 +00:00
if ( hash = = last_hash ) {
2014-02-10 01:10:30 +00:00
return ; // did not change
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
void SceneTreeEditor : : _tree_process_mode_changed ( ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeEditor : : _tree_changed ( ) {
2020-05-14 14:41:43 +00:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) ) {
2016-06-08 01:08:12 +00:00
return ; //speed up exit
2020-05-14 14:41:43 +00:00
}
if ( pending_test_update ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
if ( tree_dirty ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _test_update_tree " ) ;
pending_test_update = true ;
2014-02-10 01:10:30 +00:00
}
2021-07-23 08:34:21 +00:00
void SceneTreeEditor : : _selected_changed ( ) {
TreeItem * s = tree - > get_selected ( ) ;
ERR_FAIL_COND ( ! s ) ;
NodePath np = s - > get_metadata ( 0 ) ;
Node * n = get_node ( np ) ;
if ( n = = selected ) {
return ;
}
selected = get_node ( np ) ;
blocked + + ;
2021-08-20 12:48:34 +00:00
emit_signal ( SNAME ( " node_selected " ) ) ;
2021-07-23 08:34:21 +00:00
blocked - - ;
}
2017-11-26 11:49:21 +00:00
void SceneTreeEditor : : _deselect_items ( ) {
2021-03-12 16:58:25 +00:00
// Clear currently selected items in scene tree dock.
2018-08-23 12:15:54 +00:00
if ( editor_selection ) {
2017-12-10 21:33:44 +00:00
editor_selection - > clear ( ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " node_changed " ) ) ;
2018-08-23 12:15:54 +00:00
}
2017-11-26 11:49:21 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _cell_multi_selected ( Object * p_object , int p_cell , bool p_selected ) {
2017-08-24 20:58:51 +00:00
TreeItem * item = Object : : cast_to < TreeItem > ( p_object ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! n ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! editor_selection ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
if ( p_selected ) {
editor_selection - > add_node ( n ) ;
} else {
editor_selection - > remove_node ( n ) ;
}
2021-06-19 02:25:24 +00:00
2021-07-23 08:37:35 +00:00
// Emitted "selected" in _selected_changed() when select single node, so select multiple node emit "changed"
if ( editor_selection - > get_selected_nodes ( ) . size ( ) > 1 ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " node_changed " ) ) ;
2021-06-19 02:25:24 +00:00
}
2014-02-10 01:10:30 +00:00
}
void SceneTreeEditor : : _notification ( int p_what ) {
2019-03-06 17:33:26 +00:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2020-02-21 17:28:45 +00:00
get_tree ( ) - > connect ( " tree_changed " , callable_mp ( this , & SceneTreeEditor : : _tree_changed ) ) ;
2021-02-18 18:52:29 +00:00
get_tree ( ) - > connect ( " tree_process_mode_changed " , callable_mp ( this , & SceneTreeEditor : : _tree_process_mode_changed ) ) ;
2020-02-21 17:28:45 +00:00
get_tree ( ) - > connect ( " node_removed " , callable_mp ( this , & SceneTreeEditor : : _node_removed ) ) ;
get_tree ( ) - > connect ( " node_renamed " , callable_mp ( this , & SceneTreeEditor : : _node_renamed ) ) ;
2021-04-27 15:43:49 +00:00
get_tree ( ) - > connect ( " node_configuration_warning_changed " , callable_mp ( this , & SceneTreeEditor : : _warning_changed ) , varray ( ) , CONNECT_DEFERRED ) ;
2015-10-10 12:09:09 +00:00
2020-02-21 17:28:45 +00:00
tree - > connect ( " item_collapsed " , callable_mp ( this , & SceneTreeEditor : : _cell_collapsed ) ) ;
2016-06-15 17:10:19 +00:00
2019-03-06 17:33:26 +00:00
_update_tree ( ) ;
} break ;
case NOTIFICATION_EXIT_TREE : {
2020-02-21 17:28:45 +00:00
get_tree ( ) - > disconnect ( " tree_changed " , callable_mp ( this , & SceneTreeEditor : : _tree_changed ) ) ;
2021-02-18 18:52:29 +00:00
get_tree ( ) - > disconnect ( " tree_process_mode_changed " , callable_mp ( this , & SceneTreeEditor : : _tree_process_mode_changed ) ) ;
2020-02-21 17:28:45 +00:00
get_tree ( ) - > disconnect ( " node_removed " , callable_mp ( this , & SceneTreeEditor : : _node_removed ) ) ;
get_tree ( ) - > disconnect ( " node_renamed " , callable_mp ( this , & SceneTreeEditor : : _node_renamed ) ) ;
tree - > disconnect ( " item_collapsed " , callable_mp ( this , & SceneTreeEditor : : _cell_collapsed ) ) ;
get_tree ( ) - > disconnect ( " node_configuration_warning_changed " , callable_mp ( this , & SceneTreeEditor : : _warning_changed ) ) ;
2019-03-06 17:33:26 +00:00
} break ;
case NOTIFICATION_THEME_CHANGED : {
_update_tree ( ) ;
} break ;
2018-02-25 16:04:16 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
TreeItem * SceneTreeEditor : : _find ( TreeItem * p_node , const NodePath & p_path ) {
2020-05-14 14:41:43 +00:00
if ( ! p_node ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
NodePath np = p_node - > get_metadata ( 0 ) ;
2020-05-14 14:41:43 +00:00
if ( np = = p_path ) {
2014-02-10 01:10:30 +00:00
return p_node ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2021-03-07 20:07:30 +00:00
TreeItem * children = p_node - > get_first_child ( ) ;
2017-03-05 15:44:50 +00:00
while ( children ) {
TreeItem * n = _find ( children , p_path ) ;
2020-05-14 14:41:43 +00:00
if ( n ) {
2014-02-10 01:10:30 +00:00
return n ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
children = children - > get_next ( ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : set_selected ( Node * p_node , bool p_emit_selected ) {
ERR_FAIL_COND ( blocked > 0 ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( pending_test_update ) {
2014-02-10 01:10:30 +00:00
_test_update_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
if ( tree_dirty ) {
2014-02-10 01:10:30 +00:00
_update_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( selected = = p_node ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
TreeItem * item = p_node ? _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) : nullptr ;
2014-02-10 01:10:30 +00:00
if ( item ) {
2021-08-09 17:14:06 +00:00
if ( auto_expand_selected ) {
// Make visible when it's collapsed.
TreeItem * node = item - > get_parent ( ) ;
while ( node & & node ! = tree - > get_root ( ) ) {
node - > set_collapsed ( false ) ;
node = node - > get_parent ( ) ;
}
item - > select ( 0 ) ;
item - > set_as_cursor ( 0 ) ;
selected = p_node ;
tree - > ensure_cursor_is_visible ( ) ;
2016-12-02 02:27:17 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2020-05-14 14:41:43 +00:00
if ( ! p_node ) {
2020-04-01 23:20:12 +00:00
selected = nullptr ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
_update_tree ( ) ;
2017-03-05 15:44:50 +00:00
selected = p_node ;
2017-08-19 22:13:10 +00:00
}
if ( p_emit_selected ) {
2021-08-20 12:48:34 +00:00
emit_signal ( SNAME ( " node_selected " ) ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _rename_node ( ObjectID p_node , const String & p_name ) {
2014-02-10 01:10:30 +00:00
Object * o = ObjectDB : : get_instance ( p_node ) ;
ERR_FAIL_COND ( ! o ) ;
2017-08-24 20:58:51 +00:00
Node * n = Object : : cast_to < Node > ( o ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! n ) ;
2017-03-05 15:44:50 +00:00
TreeItem * item = _find ( tree - > get_root ( ) , n - > get_path ( ) ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! item ) ;
2017-03-05 15:44:50 +00:00
n - > set_name ( p_name ) ;
item - > set_metadata ( 0 , n - > get_path ( ) ) ;
item - > set_text ( 0 , p_name ) ;
2014-02-10 01:10:30 +00:00
}
void SceneTreeEditor : : _renamed ( ) {
2017-03-05 15:44:50 +00:00
TreeItem * which = tree - > get_edited ( ) ;
2014-06-11 06:45:26 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! which ) ;
NodePath np = which - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! n ) ;
2018-10-29 13:47:53 +00:00
// Empty node names are not allowed, so resets it to previous text and show warning
2020-12-15 12:04:21 +00:00
if ( which - > get_text ( 0 ) . strip_edges ( ) . is_empty ( ) ) {
2018-10-29 13:47:53 +00:00
which - > set_text ( 0 , n - > get_name ( ) ) ;
2018-12-17 23:03:25 +00:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " No name provided. " ) ) ;
2018-10-29 13:47:53 +00:00
return ;
}
2021-01-28 20:48:12 +00:00
String raw_new_name = which - > get_text ( 0 ) ;
String new_name = raw_new_name . validate_node_name ( ) ;
if ( new_name ! = raw_new_name ) {
error - > set_text ( TTR ( " Invalid node name, the following characters are not allowed: " ) + " \n " + String : : invalid_node_name_characters ) ;
2020-03-06 17:00:16 +00:00
error - > popup_centered ( ) ;
2018-04-26 16:42:15 +00:00
2020-12-15 12:04:21 +00:00
if ( new_name . is_empty ( ) ) {
2019-01-29 16:51:50 +00:00
which - > set_text ( 0 , n - > get_name ( ) ) ;
return ;
}
2018-04-26 16:42:15 +00:00
which - > set_text ( 0 , new_name ) ;
2014-06-11 06:45:26 +00:00
}
2020-05-14 14:41:43 +00:00
if ( new_name = = n - > get_name ( ) ) {
2016-01-26 16:25:04 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-01-26 16:25:04 +00:00
2020-09-12 21:59:46 +00:00
// Trim leading/trailing whitespace to prevent node names from containing accidental whitespace, which would make it more difficult to get the node via `get_node()`.
new_name = new_name . strip_edges ( ) ;
2014-02-10 01:10:30 +00:00
if ( ! undo_redo ) {
2017-03-05 15:44:50 +00:00
n - > set_name ( new_name ) ;
which - > set_metadata ( 0 , n - > get_path ( ) ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " node_renamed " ) ) ;
2014-02-10 01:10:30 +00:00
} else {
2016-05-04 01:25:37 +00:00
undo_redo - > create_action ( TTR ( " Rename Node " ) ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " node_prerename " ) , n , new_name ) ;
2017-08-07 10:17:31 +00:00
undo_redo - > add_do_method ( this , " _rename_node " , n - > get_instance_id ( ) , new_name ) ;
undo_redo - > add_undo_method ( this , " _rename_node " , n - > get_instance_id ( ) , n - > get_name ( ) ) ;
2014-02-10 01:10:30 +00:00
undo_redo - > commit_action ( ) ;
}
}
Node * SceneTreeEditor : : get_selected ( ) {
return selected ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : set_marked ( const Set < Node * > & p_marked , bool p_selectable , bool p_children_selectable ) {
2020-05-14 14:41:43 +00:00
if ( tree_dirty ) {
2014-02-10 01:10:30 +00:00
_update_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
marked = p_marked ;
marked_selectable = p_selectable ;
marked_children_selectable = p_children_selectable ;
2014-02-10 01:10:30 +00:00
_update_tree ( ) ;
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : set_marked ( Node * p_marked , bool p_selectable , bool p_children_selectable ) {
Set < Node * > s ;
2020-05-14 14:41:43 +00:00
if ( p_marked ) {
2014-02-10 01:10:30 +00:00
s . insert ( p_marked ) ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
set_marked ( s , p_selectable , p_children_selectable ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : set_filter ( const String & p_filter ) {
filter = p_filter ;
2021-02-08 00:19:46 +00:00
_update_tree ( true ) ;
2016-05-16 15:23:40 +00:00
}
String SceneTreeEditor : : get_filter ( ) const {
return filter ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeEditor : : set_display_foreign_nodes ( bool p_display ) {
2017-03-05 15:44:50 +00:00
display_foreign = p_display ;
2014-02-10 01:10:30 +00:00
_update_tree ( ) ;
}
2020-05-14 12:29:06 +00:00
2018-06-27 23:50:25 +00:00
void SceneTreeEditor : : set_valid_types ( const Vector < StringName > & p_valid ) {
valid_types = p_valid ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeEditor : : set_editor_selection ( EditorSelection * p_selection ) {
2017-03-05 15:44:50 +00:00
editor_selection = p_selection ;
2014-02-10 01:10:30 +00:00
tree - > set_select_mode ( Tree : : SELECT_MULTI ) ;
tree - > set_cursor_can_exit_tree ( false ) ;
2020-02-21 17:28:45 +00:00
editor_selection - > connect ( " selection_changed " , callable_mp ( this , & SceneTreeEditor : : _selection_changed ) ) ;
2014-02-10 01:10:30 +00:00
}
void SceneTreeEditor : : _update_selection ( TreeItem * item ) {
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2020-05-14 14:41:43 +00:00
if ( ! has_node ( np ) ) {
2016-01-23 22:51:51 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-01-23 22:51:51 +00:00
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! n ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( editor_selection - > is_selected ( n ) ) {
2014-02-10 01:10:30 +00:00
item - > select ( 0 ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
item - > deselect ( 0 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-03-07 20:07:30 +00:00
TreeItem * c = item - > get_first_child ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
while ( c ) {
2014-02-10 01:10:30 +00:00
_update_selection ( c ) ;
2017-03-05 15:44:50 +00:00
c = c - > get_next ( ) ;
2014-02-10 01:10:30 +00:00
}
}
void SceneTreeEditor : : _selection_changed ( ) {
2020-05-14 14:41:43 +00:00
if ( ! editor_selection ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
TreeItem * root = tree - > get_root ( ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! root ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
_update_selection ( root ) ;
}
void SceneTreeEditor : : _cell_collapsed ( Object * p_obj ) {
2020-05-14 14:41:43 +00:00
if ( updating_tree ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
if ( ! can_rename ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-08-24 20:58:51 +00:00
TreeItem * ti = Object : : cast_to < TreeItem > ( p_obj ) ;
2020-05-14 14:41:43 +00:00
if ( ! ti ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool collapsed = ti - > is_collapsed ( ) ;
2014-02-10 01:10:30 +00:00
NodePath np = ti - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! n ) ;
2016-06-28 16:10:15 +00:00
n - > set_display_folded ( collapsed ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant SceneTreeEditor : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
2020-05-14 14:41:43 +00:00
if ( ! can_rename ) {
2016-05-11 14:46:08 +00:00
return Variant ( ) ; //not editable tree
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
2019-12-13 05:13:47 +00:00
if ( tree - > get_button_id_at_position ( p_point ) ! = - 1 ) {
return Variant ( ) ; //dragging from button
}
2017-03-05 15:44:50 +00:00
Vector < Node * > selected ;
2020-03-17 06:33:00 +00:00
Vector < Ref < Texture2D > > icons ;
2020-04-01 23:20:12 +00:00
TreeItem * next = tree - > get_next_selected ( nullptr ) ;
2016-05-11 14:46:08 +00:00
while ( next ) {
NodePath np = next - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2016-05-11 14:46:08 +00:00
if ( n ) {
2021-06-17 22:03:09 +00:00
// Only allow selection if not part of an instantiated scene.
2021-12-09 09:42:46 +00:00
if ( ! n - > get_owner ( ) | | n - > get_owner ( ) = = get_scene_node ( ) | | n - > get_owner ( ) - > get_scene_file_path ( ) . is_empty ( ) ) {
2017-12-14 16:49:02 +00:00
selected . push_back ( n ) ;
icons . push_back ( next - > get_icon ( 0 ) ) ;
}
2016-05-11 14:46:08 +00:00
}
2017-03-05 15:44:50 +00:00
next = tree - > get_next_selected ( next ) ;
2016-05-11 14:46:08 +00:00
}
2020-12-15 12:04:21 +00:00
if ( selected . is_empty ( ) ) {
2016-05-11 14:46:08 +00:00
return Variant ( ) ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2016-05-11 14:46:08 +00:00
Array objs ;
2016-05-17 14:27:35 +00:00
int list_max = 10 ;
float opacity_step = 1.0f / list_max ;
float opacity_item = 1.0f ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < selected . size ( ) ; i + + ) {
if ( i < list_max ) {
HBoxContainer * hb = memnew ( HBoxContainer ) ;
2017-01-12 21:27:27 +00:00
TextureRect * tf = memnew ( TextureRect ) ;
2016-05-17 14:27:35 +00:00
tf - > set_texture ( icons [ i ] ) ;
2019-09-30 16:36:49 +00:00
tf - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_CENTERED ) ;
2016-05-17 14:27:35 +00:00
hb - > add_child ( tf ) ;
2017-03-05 15:44:50 +00:00
Label * label = memnew ( Label ( selected [ i ] - > get_name ( ) ) ) ;
2016-05-17 14:27:35 +00:00
hb - > add_child ( label ) ;
vb - > add_child ( hb ) ;
2017-03-05 15:44:50 +00:00
hb - > set_modulate ( Color ( 1 , 1 , 1 , opacity_item ) ) ;
2016-05-17 14:27:35 +00:00
opacity_item - = opacity_step ;
}
2016-05-11 14:46:08 +00:00
NodePath p = selected [ i ] - > get_path ( ) ;
objs . push_back ( p ) ;
}
set_drag_preview ( vb ) ;
Dictionary drag_data ;
2017-03-05 15:44:50 +00:00
drag_data [ " type " ] = " nodes " ;
drag_data [ " nodes " ] = objs ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN | Tree : : DROP_MODE_ON_ITEM ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " nodes_dragged " ) ) ;
2016-05-11 14:46:08 +00:00
return drag_data ;
}
2016-10-27 14:32:41 +00:00
bool SceneTreeEditor : : _is_script_type ( const StringName & p_type ) const {
return ( script_types - > find ( p_type ) ) ;
}
2017-03-05 15:44:50 +00:00
bool SceneTreeEditor : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2020-05-14 14:41:43 +00:00
if ( ! can_rename ) {
2016-05-11 14:46:08 +00:00
return false ; //not editable tree
2020-05-14 14:41:43 +00:00
}
2016-05-16 15:23:40 +00:00
2017-03-05 15:44:50 +00:00
Dictionary d = p_data ;
2020-05-14 14:41:43 +00:00
if ( ! d . has ( " type " ) ) {
2016-05-11 14:46:08 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
2017-09-10 13:37:49 +00:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2020-05-14 14:41:43 +00:00
if ( ! item ) {
2016-07-18 18:00:14 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-07-18 18:00:14 +00:00
2017-09-10 13:37:49 +00:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2020-05-14 14:41:43 +00:00
if ( section < - 1 | | ( section = = - 1 & & ! item - > get_parent ( ) ) ) {
2016-07-18 18:00:14 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2016-07-18 18:00:14 +00:00
2017-03-05 15:44:50 +00:00
if ( String ( d [ " type " ] ) = = " files " ) {
2016-05-11 23:57:52 +00:00
Vector < String > files = d [ " files " ] ;
2020-05-14 14:41:43 +00:00
if ( files . size ( ) = = 0 ) {
2016-05-11 23:57:52 +00:00
return false ; //weird
2020-05-14 14:41:43 +00:00
}
2016-05-11 23:57:52 +00:00
2016-10-27 14:32:41 +00:00
if ( _is_script_type ( EditorFileSystem : : get_singleton ( ) - > get_file_type ( files [ 0 ] ) ) ) {
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_ON_ITEM ) ;
return true ;
}
2016-05-11 23:57:52 +00:00
2021-07-16 14:27:59 +00:00
bool scene_drop = true ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2016-10-27 14:32:41 +00:00
String file = files [ i ] ;
2016-05-11 23:57:52 +00:00
String ftype = EditorFileSystem : : get_singleton ( ) - > get_file_type ( file ) ;
2020-05-14 14:41:43 +00:00
if ( ftype ! = " PackedScene " ) {
2021-07-16 14:27:59 +00:00
scene_drop = false ;
break ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 23:57:52 +00:00
}
2021-07-16 14:27:59 +00:00
if ( scene_drop ) {
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN | Tree : : DROP_MODE_ON_ITEM ) ;
} else {
if ( files . size ( ) > 1 ) {
return false ;
}
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_ON_ITEM ) ;
}
2016-05-11 23:57:52 +00:00
return true ;
}
2019-08-16 19:05:01 +00:00
if ( String ( d [ " type " ] ) = = " script_list_element " ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( d [ " script_list_element " ] ) ;
if ( se ) {
String sp = se - > get_edited_resource ( ) - > get_path ( ) ;
if ( _is_script_type ( EditorFileSystem : : get_singleton ( ) - > get_file_type ( sp ) ) ) {
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_ON_ITEM ) ;
return true ;
}
}
}
2021-12-09 09:42:46 +00:00
return String ( d [ " type " ] ) = = " nodes " & & filter . is_empty ( ) ;
2016-05-11 14:46:08 +00:00
}
2020-05-14 12:29:06 +00:00
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2020-05-14 14:41:43 +00:00
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) ) {
2016-05-11 14:46:08 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
2017-09-10 13:37:49 +00:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2020-05-14 14:41:43 +00:00
if ( ! item ) {
2016-05-11 14:46:08 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-09-10 13:37:49 +00:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2020-05-14 14:41:43 +00:00
if ( section < - 1 ) {
2016-05-11 14:46:08 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 15:44:50 +00:00
Node * n = get_node ( np ) ;
2020-05-14 14:41:43 +00:00
if ( ! n ) {
2016-05-11 14:46:08 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
Dictionary d = p_data ;
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
if ( String ( d [ " type " ] ) = = " nodes " ) {
Array nodes = d [ " nodes " ] ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " nodes_rearranged " ) , nodes , np , section ) ;
2016-05-11 23:57:52 +00:00
}
2016-05-11 14:46:08 +00:00
2017-03-05 15:44:50 +00:00
if ( String ( d [ " type " ] ) = = " files " ) {
2016-10-27 14:32:41 +00:00
Vector < String > files = d [ " files " ] ;
String ftype = EditorFileSystem : : get_singleton ( ) - > get_file_type ( files [ 0 ] ) ;
if ( _is_script_type ( ftype ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " script_dropped " ) , files [ 0 ] , np ) ;
2016-10-27 14:32:41 +00:00
} else {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " files_dropped " ) , files , np , section ) ;
2016-10-27 14:32:41 +00:00
}
2016-05-11 23:57:52 +00:00
}
2019-08-16 19:05:01 +00:00
if ( String ( d [ " type " ] ) = = " script_list_element " ) {
ScriptEditorBase * se = Object : : cast_to < ScriptEditorBase > ( d [ " script_list_element " ] ) ;
if ( se ) {
String sp = se - > get_edited_resource ( ) - > get_path ( ) ;
if ( _is_script_type ( EditorFileSystem : : get_singleton ( ) - > get_file_type ( sp ) ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " script_dropped " ) , sp , np ) ;
2019-08-16 19:05:01 +00:00
}
}
}
2016-05-11 14:46:08 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _rmb_select ( const Vector2 & p_pos ) {
2021-08-31 15:43:35 +00:00
emit_signal ( SNAME ( " rmb_pressed " ) , tree - > get_screen_position ( ) + p_pos ) ;
2016-05-16 02:41:48 +00:00
}
2014-09-03 02:13:40 +00:00
2021-04-27 15:43:49 +00:00
void SceneTreeEditor : : update_warning ( ) {
_warning_changed ( nullptr ) ;
}
2021-08-09 17:14:06 +00:00
2017-03-05 15:44:50 +00:00
void SceneTreeEditor : : _warning_changed ( Node * p_for_node ) {
2016-05-17 21:27:15 +00:00
//should use a timer
update_timer - > start ( ) ;
}
2016-05-16 15:23:40 +00:00
2021-08-09 17:14:06 +00:00
void SceneTreeEditor : : set_auto_expand_selected ( bool p_auto , bool p_update_settings ) {
if ( p_update_settings ) {
EditorSettings : : get_singleton ( ) - > set ( " docks/scene_tree/auto_expand_to_selected " , p_auto ) ;
}
auto_expand_selected = p_auto ;
}
2019-04-12 02:21:48 +00:00
void SceneTreeEditor : : set_connect_to_script_mode ( bool p_enable ) {
connect_to_script_mode = p_enable ;
update_tree ( ) ;
}
2019-06-06 02:13:57 +00:00
void SceneTreeEditor : : set_connecting_signal ( bool p_enable ) {
connecting_signal = p_enable ;
update_tree ( ) ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeEditor : : _bind_methods ( ) {
2021-02-14 21:32:42 +00:00
ClassDB : : bind_method ( D_METHOD ( " _update_tree " , " scroll_to_selected " ) , & SceneTreeEditor : : _update_tree , DEFVAL ( false ) ) ; // Still used by some connect_compat.
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _rename_node " , & SceneTreeEditor : : _rename_node ) ;
ClassDB : : bind_method ( " _test_update_tree " , & SceneTreeEditor : : _test_update_tree ) ;
2014-02-10 01:10:30 +00:00
2021-05-15 21:48:59 +00:00
ClassDB : : bind_method ( D_METHOD ( " _get_drag_data_fw " ) , & SceneTreeEditor : : get_drag_data_fw ) ;
ClassDB : : bind_method ( D_METHOD ( " _can_drop_data_fw " ) , & SceneTreeEditor : : can_drop_data_fw ) ;
ClassDB : : bind_method ( D_METHOD ( " _drop_data_fw " ) , & SceneTreeEditor : : drop_data_fw ) ;
2016-05-11 14:46:08 +00:00
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_tree " ) , & SceneTreeEditor : : update_tree ) ;
2016-05-17 21:27:15 +00:00
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " node_selected " ) ) ;
ADD_SIGNAL ( MethodInfo ( " node_renamed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " node_prerename " ) ) ;
ADD_SIGNAL ( MethodInfo ( " node_changed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " nodes_dragged " ) ) ;
ADD_SIGNAL ( MethodInfo ( " nodes_rearranged " , PropertyInfo ( Variant : : ARRAY , " paths " ) , PropertyInfo ( Variant : : NODE_PATH , " to_path " ) , PropertyInfo ( Variant : : INT , " type " ) ) ) ;
2020-02-17 21:06:54 +00:00
ADD_SIGNAL ( MethodInfo ( " files_dropped " , PropertyInfo ( Variant : : PACKED_STRING_ARRAY , " files " ) , PropertyInfo ( Variant : : NODE_PATH , " to_path " ) , PropertyInfo ( Variant : : INT , " type " ) ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " script_dropped " , PropertyInfo ( Variant : : STRING , " file " ) , PropertyInfo ( Variant : : NODE_PATH , " to_path " ) ) ) ;
2017-09-10 13:37:49 +00:00
ADD_SIGNAL ( MethodInfo ( " rmb_pressed " , PropertyInfo ( Variant : : VECTOR2 , " position " ) ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " open " ) ) ;
ADD_SIGNAL ( MethodInfo ( " open_script " ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
SceneTreeEditor : : SceneTreeEditor ( bool p_label , bool p_can_rename , bool p_can_open_instance ) {
2019-04-12 02:21:48 +00:00
connect_to_script_mode = false ;
2019-06-06 02:13:57 +00:00
connecting_signal = false ;
2020-04-01 23:20:12 +00:00
undo_redo = nullptr ;
2017-03-05 15:44:50 +00:00
tree_dirty = true ;
2020-04-01 23:20:12 +00:00
selected = nullptr ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
marked_selectable = false ;
marked_children_selectable = false ;
can_rename = p_can_rename ;
can_open_instance = p_can_open_instance ;
display_foreign = false ;
2020-04-01 23:20:12 +00:00
editor_selection = nullptr ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( p_label ) {
2017-03-05 15:44:50 +00:00
Label * label = memnew ( Label ) ;
2021-07-08 13:29:15 +00:00
label - > set_theme_type_variation ( " HeaderSmall " ) ;
2017-03-29 15:29:38 +00:00
label - > set_position ( Point2 ( 10 , 0 ) ) ;
2016-05-04 01:25:37 +00:00
label - > set_text ( TTR ( " Scene Tree (Nodes): " ) ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
add_child ( label ) ;
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
tree = memnew ( Tree ) ;
2020-12-22 16:24:29 +00:00
tree - > set_anchor ( SIDE_RIGHT , ANCHOR_END ) ;
tree - > set_anchor ( SIDE_BOTTOM , ANCHOR_END ) ;
2017-03-05 15:44:50 +00:00
tree - > set_begin ( Point2 ( 0 , p_label ? 18 : 0 ) ) ;
tree - > set_end ( Point2 ( 0 , 0 ) ) ;
2021-03-12 16:58:25 +00:00
tree - > set_allow_reselect ( true ) ;
2020-03-12 12:37:40 +00:00
tree - > add_theme_constant_override ( " button_margin " , 0 ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
add_child ( tree ) ;
2016-03-08 23:00:52 +00:00
2016-05-11 14:46:08 +00:00
tree - > set_drag_forwarding ( this ) ;
2016-05-16 15:23:40 +00:00
if ( p_can_rename ) {
2016-05-16 02:41:48 +00:00
tree - > set_allow_rmb_select ( true ) ;
2020-02-21 17:28:45 +00:00
tree - > connect ( " item_rmb_selected " , callable_mp ( this , & SceneTreeEditor : : _rmb_select ) ) ;
tree - > connect ( " empty_tree_rmb_selected " , callable_mp ( this , & SceneTreeEditor : : _rmb_select ) ) ;
2016-05-16 15:23:40 +00:00
}
2016-05-11 14:46:08 +00:00
2021-07-23 08:34:21 +00:00
tree - > connect ( " cell_selected " , callable_mp ( this , & SceneTreeEditor : : _selected_changed ) ) ;
2021-08-16 21:10:57 +00:00
tree - > connect ( " item_edited " , callable_mp ( this , & SceneTreeEditor : : _renamed ) ) ;
2020-02-21 17:28:45 +00:00
tree - > connect ( " multi_selected " , callable_mp ( this , & SceneTreeEditor : : _cell_multi_selected ) ) ;
tree - > connect ( " button_pressed " , callable_mp ( this , & SceneTreeEditor : : _cell_button_pressed ) ) ;
tree - > connect ( " nothing_selected " , callable_mp ( this , & SceneTreeEditor : : _deselect_items ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
error = memnew ( AcceptDialog ) ;
2014-03-14 01:57:24 +00:00
add_child ( error ) ;
2017-03-05 15:44:50 +00:00
warning = memnew ( AcceptDialog ) ;
2016-05-17 21:27:15 +00:00
add_child ( warning ) ;
2017-08-23 20:25:14 +00:00
warning - > set_title ( TTR ( " Node Configuration Warning! " ) ) ;
2016-05-17 21:27:15 +00:00
2017-03-05 15:44:50 +00:00
show_enabled_subscene = false ;
2016-05-17 21:27:15 +00:00
2017-03-05 15:44:50 +00:00
last_hash = 0 ;
pending_test_update = false ;
updating_tree = false ;
blocked = 0 ;
2014-09-03 02:13:40 +00:00
2016-05-17 21:27:15 +00:00
update_timer = memnew ( Timer ) ;
2021-02-19 11:42:47 +00:00
update_timer - > connect ( " timeout " , callable_mp ( this , & SceneTreeEditor : : _update_tree ) , varray ( false ) ) ;
2016-05-17 21:27:15 +00:00
update_timer - > set_one_shot ( true ) ;
update_timer - > set_wait_time ( 0.5 ) ;
add_child ( update_timer ) ;
2015-10-10 12:09:09 +00:00
2016-10-27 14:32:41 +00:00
script_types = memnew ( List < StringName > ) ;
2017-01-03 02:03:46 +00:00
ClassDB : : get_inheriters_from_class ( " Script " , script_types ) ;
2014-02-10 01:10:30 +00:00
}
SceneTreeEditor : : ~ SceneTreeEditor ( ) {
2016-10-27 14:32:41 +00:00
memdelete ( script_types ) ;
2014-02-10 01:10:30 +00:00
}
/******** DIALOG *********/
2020-07-11 16:45:19 +00:00
void SceneTreeDialog : : popup_scenetree_dialog ( ) {
popup_centered_clamped ( Size2 ( 350 , 700 ) * EDSCALE ) ;
}
2022-01-16 07:59:02 +00:00
void SceneTreeDialog : : _update_theme ( ) {
filter - > set_right_icon ( tree - > get_theme_icon ( SNAME ( " Search " ) , SNAME ( " EditorIcons " ) ) ) ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeDialog : : _notification ( int p_what ) {
2019-04-15 23:21:51 +00:00
switch ( p_what ) {
2020-03-06 17:00:16 +00:00
case NOTIFICATION_VISIBILITY_CHANGED : {
2020-05-14 14:41:43 +00:00
if ( is_visible ( ) ) {
2020-03-06 17:00:16 +00:00
tree - > update_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
2020-03-06 17:00:16 +00:00
} break ;
2019-04-15 23:21:51 +00:00
case NOTIFICATION_ENTER_TREE : {
2020-02-21 17:28:45 +00:00
connect ( " confirmed " , callable_mp ( this , & SceneTreeDialog : : _select ) ) ;
2022-01-16 07:59:02 +00:00
_update_theme ( ) ;
} break ;
case NOTIFICATION_THEME_CHANGED : {
_update_theme ( ) ;
2019-04-15 23:21:51 +00:00
} break ;
case NOTIFICATION_EXIT_TREE : {
2020-02-21 17:28:45 +00:00
disconnect ( " confirmed " , callable_mp ( this , & SceneTreeDialog : : _select ) ) ;
2019-04-15 23:21:51 +00:00
} break ;
2014-02-10 01:10:30 +00:00
}
}
void SceneTreeDialog : : _cancel ( ) {
hide ( ) ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
void SceneTreeDialog : : _select ( ) {
if ( tree - > get_selected ( ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " selected " ) , tree - > get_selected ( ) - > get_path ( ) ) ;
2014-02-10 01:10:30 +00:00
hide ( ) ;
}
}
2019-07-06 17:09:34 +00:00
void SceneTreeDialog : : _filter_changed ( const String & p_filter ) {
tree - > set_filter ( p_filter ) ;
}
2014-02-10 01:10:30 +00:00
void SceneTreeDialog : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _cancel " , & SceneTreeDialog : : _cancel ) ;
2019-07-06 17:09:34 +00:00
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " selected " , PropertyInfo ( Variant : : NODE_PATH , " path " ) ) ) ;
2014-02-10 01:10:30 +00:00
}
SceneTreeDialog : : SceneTreeDialog ( ) {
2016-05-04 01:25:37 +00:00
set_title ( TTR ( " Select a Node " ) ) ;
2019-07-06 17:09:34 +00:00
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
add_child ( vbc ) ;
filter = memnew ( LineEdit ) ;
2020-03-06 17:00:16 +00:00
filter - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2019-07-06 17:09:34 +00:00
filter - > set_placeholder ( TTR ( " Filter nodes " ) ) ;
2022-01-16 07:59:02 +00:00
filter - > set_clear_button_enabled ( true ) ;
2021-02-12 14:05:10 +00:00
filter - > add_theme_constant_override ( " minimum_character_width " , 0 ) ;
2020-02-21 17:28:45 +00:00
filter - > connect ( " text_changed " , callable_mp ( this , & SceneTreeDialog : : _filter_changed ) ) ;
2019-07-06 17:09:34 +00:00
vbc - > add_child ( filter ) ;
2014-02-10 01:10:30 +00:00
2018-11-02 18:05:38 +00:00
tree = memnew ( SceneTreeEditor ( false , false , true ) ) ;
2020-03-06 17:00:16 +00:00
tree - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2020-02-21 17:28:45 +00:00
tree - > get_scene_tree ( ) - > connect ( " item_activated " , callable_mp ( this , & SceneTreeDialog : : _select ) ) ;
2019-07-06 17:09:34 +00:00
vbc - > add_child ( tree ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
SceneTreeDialog : : ~ SceneTreeDialog ( ) {
2014-02-10 01:10:30 +00:00
}