2023-01-10 15:26:54 +01:00
/**************************************************************************/
/* scene_tree_editor.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "scene_tree_editor.h"
2017-01-16 08:04:19 +01:00
2018-09-11 18:13:45 +02:00
# include "core/message_queue.h"
# include "core/print_string.h"
2019-12-24 08:17:23 +01:00
# include "editor/editor_node.h"
# include "editor/node_dock.h"
2018-06-07 17:46:14 +02:00
# include "editor/plugins/animation_player_editor_plugin.h"
2017-03-05 16:44:50 +01:00
# include "editor/plugins/canvas_item_editor_plugin.h"
2023-11-27 08:07:01 +01:00
# include "scene/3d/lod_manager.h"
2017-03-05 16:44:50 +01:00
# include "scene/gui/label.h"
2014-02-10 02:10:30 +01:00
# include "scene/main/viewport.h"
2015-10-10 14:09:09 +02:00
# include "scene/resources/packed_scene.h"
2023-12-06 09:26:37 +01:00
Node * SceneTreeEditor : : get_scene_node ( ) const {
2021-05-04 16:00:45 +02:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , nullptr ) ;
2014-02-10 02:10:30 +01:00
2016-01-17 02:41:10 +01:00
return get_tree ( ) - > get_edited_scene_root ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _cell_button_pressed ( Object * p_item , int p_column , int p_id ) {
2019-04-12 04:21:48 +02:00
if ( connect_to_script_mode ) {
2019-05-19 12:34:40 +02:00
return ; //don't do anything in this mode
2019-04-12 04:21:48 +02:00
}
2019-06-06 04:13:57 +02:00
2017-08-24 22:58:51 +02:00
TreeItem * item = Object : : cast_to < TreeItem > ( p_item ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! n ) ;
2017-03-05 16:44:50 +01:00
if ( p_id = = BUTTON_SUBSCENE ) {
if ( n = = get_scene_node ( ) ) {
2017-06-30 18:17:33 +02:00
if ( n & & n - > get_scene_inherited_state ( ) . is_valid ( ) ) {
emit_signal ( " open " , n - > get_scene_inherited_state ( ) - > get_path ( ) ) ;
2015-10-17 00:11:23 +02:00
}
2017-06-30 18:17:33 +02:00
} else {
emit_signal ( " open " , n - > get_filename ( ) ) ;
2015-10-10 14:09:09 +02:00
}
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_SCRIPT ) {
RefPtr script = n - > get_script ( ) ;
2019-07-12 17:53:07 +02:00
Ref < Script > script_typed = script ;
2021-05-05 12:44:11 +02:00
if ( ! script_typed . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
emit_signal ( " open_script " , script ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_VISIBILITY ) {
2018-01-01 09:05:00 +01:00
undo_redo - > create_action ( TTR ( " Toggle Visible " ) ) ;
2018-05-15 16:13:48 +02:00
_toggle_visible ( n ) ;
List < Node * > selection = editor_selection - > get_selected_node_list ( ) ;
2021-05-04 16:00:45 +02:00
if ( selection . size ( ) > 1 & & selection . find ( n ) ! = nullptr ) {
2018-05-15 16:13:48 +02:00
for ( List < Node * > : : Element * E = selection . front ( ) ; E ; E = E - > next ( ) ) {
Node * nv = E - > get ( ) ;
ERR_FAIL_COND ( ! nv ) ;
if ( nv = = n ) {
continue ;
}
_toggle_visible ( nv ) ;
}
}
2018-01-01 09:05:00 +01:00
undo_redo - > commit_action ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_LOCK ) {
2019-04-26 19:23:50 +02:00
undo_redo - > create_action ( TTR ( " Unlock Node " ) ) ;
2014-05-08 07:43:19 +02:00
2017-10-23 21:21:15 +02:00
if ( n - > is_class ( " CanvasItem " ) | | n - > is_class ( " Spatial " ) ) {
2019-04-26 19:23:50 +02: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 07:43:19 +02:00
}
2019-04-26 19:23:50 +02:00
undo_redo - > commit_action ( ) ;
2018-06-07 17:46:14 +02:00
} else if ( p_id = = BUTTON_PIN ) {
if ( n - > is_class ( " AnimationPlayer " ) ) {
AnimationPlayerEditor : : singleton - > unpin ( ) ;
_update_tree ( ) ;
}
2014-05-08 07:43:19 +02:00
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_GROUP ) {
2019-04-26 19:23:50 +02:00
undo_redo - > create_action ( TTR ( " Button Group " ) ) ;
2019-04-17 18:24:28 +02:00
if ( n - > is_class ( " CanvasItem " ) | | n - > is_class ( " Spatial " ) ) {
2019-04-26 19:23:50 +02: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 07:43:19 +02:00
}
2019-04-26 19:23:50 +02:00
undo_redo - > commit_action ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_WARNING ) {
2016-05-17 23:27:15 +02:00
String config_err = n - > get_configuration_warning ( ) ;
2021-05-05 12:44:11 +02:00
if ( config_err = = String ( ) ) {
2016-05-17 23:27:15 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
config_err = config_err . word_wrap ( 80 ) ;
2016-05-17 23:27:15 +02:00
warning - > set_text ( config_err ) ;
warning - > popup_centered_minsize ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_SIGNALS ) {
2016-07-16 23:22:44 +02:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( n ) ;
set_selected ( n ) ;
2017-03-05 16:44:50 +01:00
NodeDock : : singleton - > get_parent ( ) - > call ( " set_current_tab " , NodeDock : : singleton - > get_index ( ) ) ;
2016-06-04 18:17:56 +02:00
NodeDock : : singleton - > show_connections ( ) ;
2017-03-05 16:44:50 +01:00
} else if ( p_id = = BUTTON_GROUPS ) {
2016-07-16 23:22:44 +02:00
editor_selection - > clear ( ) ;
editor_selection - > add_node ( n ) ;
set_selected ( n ) ;
2017-03-05 16:44:50 +01:00
NodeDock : : singleton - > get_parent ( ) - > call ( " set_current_tab " , NodeDock : : singleton - > get_index ( ) ) ;
2016-06-04 18:17:56 +02:00
NodeDock : : singleton - > show_groups ( ) ;
2022-04-26 13:37:20 +02:00
} else if ( p_id = = BUTTON_UNIQUE ) {
undo_redo - > create_action ( TTR ( " Disable Scene Unique Name " ) ) ;
undo_redo - > add_do_method ( n , " set_unique_name_in_owner " , false ) ;
undo_redo - > add_undo_method ( n , " set_unique_name_in_owner " , true ) ;
undo_redo - > add_do_method ( this , " _update_tree " ) ;
undo_redo - > add_undo_method ( this , " _update_tree " ) ;
undo_redo - > commit_action ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2018-01-01 09:05:00 +01:00
void SceneTreeEditor : : _toggle_visible ( Node * p_node ) {
2018-05-15 16:13:48 +02:00
if ( p_node - > has_method ( " is_visible " ) & & p_node - > has_method ( " set_visible " ) ) {
2018-01-01 09:05:00 +01:00
bool v = bool ( p_node - > call ( " is_visible " ) ) ;
2018-05-15 16:13:48 +02:00
undo_redo - > add_do_method ( p_node , " set_visible " , ! v ) ;
undo_redo - > add_undo_method ( p_node , " set_visible " , v ) ;
2018-01-01 09:05:00 +01:00
}
}
2014-02-10 02:10:30 +01:00
2023-11-27 08:07:01 +01:00
void SceneTreeEditor : : _add_nodes ( Node * p_node , TreeItem * p_parent , bool p_disable_visibility ) {
2021-05-05 12:44:11 +02:00
if ( ! p_node ) {
2022-10-12 19:43:56 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01: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 04:13:40 +02:00
2017-03-05 16:44:50 +01:00
bool part_of_subscene = false ;
2014-09-03 04:13:40 +02:00
2017-03-05 16:44:50 +01:00
if ( ! display_foreign & & p_node - > get_owner ( ) ! = get_scene_node ( ) & & p_node ! = get_scene_node ( ) ) {
2015-10-10 14:09:09 +02: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 16:44:50 +01:00
part_of_subscene = true ;
2014-09-03 04:13:40 +02:00
//allow
} else {
2022-10-12 19:43:56 +02:00
return ;
2014-09-03 04:13:40 +02:00
}
2015-10-10 14:09:09 +02:00
} else {
2017-03-05 16:44:50 +01: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 04:13:40 +02:00
}
2014-02-10 02:10:30 +01:00
TreeItem * item = tree - > create_item ( p_parent ) ;
2018-06-28 01:50:25 +02:00
2017-03-05 16:44:50 +01:00
item - > set_text ( 0 , p_node - > get_name ( ) ) ;
2021-05-05 12:44:11 +02:00
if ( can_rename & & ! part_of_subscene /*(p_node->get_owner() == get_scene_node() || p_node==get_scene_node())*/ ) {
2014-02-10 02:10:30 +01:00
item - > set_editable ( 0 , true ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
item - > set_selectable ( 0 , true ) ;
2014-02-10 02:10:30 +01:00
if ( can_rename ) {
2017-07-15 06:23:10 +02:00
# ifndef DISABLE_DEPRECATED
2016-06-28 18:10:15 +02:00
if ( p_node - > has_meta ( " _editor_collapsed " ) ) {
//remove previous way of storing folding, which did not get along with scene inheritance and instancing
2021-05-05 12:44:11 +02:00
if ( ( bool ) p_node - > get_meta ( " _editor_collapsed " ) ) {
2016-06-28 18:10:15 +02:00
p_node - > set_display_folded ( true ) ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
p_node - > set_meta ( " _editor_collapsed " , Variant ( ) ) ;
2016-06-28 18:10:15 +02:00
}
# endif
bool collapsed = p_node - > is_displayed_folded ( ) ;
2021-05-05 12:44:11 +02:00
if ( collapsed ) {
2014-02-10 02:10:30 +01:00
item - > set_collapsed ( true ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
}
2018-09-02 23:40:51 +02:00
Ref < Texture > icon = EditorNode : : get_singleton ( ) - > get_object_icon ( p_node , " Node " ) ;
2017-03-05 16:44:50 +01:00
item - > set_icon ( 0 , icon ) ;
item - > set_metadata ( 0 , p_node - > get_path ( ) ) ;
2015-10-10 14:09:09 +02:00
2019-04-12 04:21:48 +02:00
if ( connect_to_script_mode ) {
Color accent = get_color ( " accent_color " , " Editor " ) ;
2019-07-12 17:53:07 +02:00
Ref < Script > script = p_node - > get_script ( ) ;
2019-07-19 21:21:30 +02:00
if ( ! script . is_null ( ) & & EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( p_node ) ! = script ) {
2019-04-12 04:21:48 +02:00
//has script
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , BUTTON_SCRIPT ) ;
} else {
2019-07-19 21:21:30 +02:00
//has no script (or script is a custom type)
2019-04-12 04:21:48 +02:00
item - > set_custom_color ( 0 , get_color ( " disabled_font_color " , " Editor " ) ) ;
item - > set_selectable ( 0 , false ) ;
2019-07-19 21:21:30 +02:00
if ( ! script . is_null ( ) ) { // make sure to mark the script if a custom type
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , BUTTON_SCRIPT ) ;
item - > set_button_disabled ( 0 , item - > get_button_count ( 0 ) - 1 , true ) ;
}
2019-04-12 04:21:48 +02:00
accent . a * = 0.7 ;
}
if ( marked . has ( p_node ) ) {
2019-06-06 04:13:57 +02: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 04:21:48 +02:00
item - > set_custom_color ( 0 , accent ) ;
}
} else if ( part_of_subscene ) {
2018-06-28 01:50:25 +02:00
if ( valid_types . size ( ) = = 0 ) {
2022-10-12 19:43:56 +02:00
item - > set_custom_color ( 0 , get_color ( " warning_color " , " Editor " ) ) ;
2018-06-28 01:50:25 +02:00
}
2014-09-03 04:13:40 +02:00
} else if ( marked . has ( p_node ) ) {
2019-06-06 04:13:57 +02:00
String node_name = p_node - > get_name ( ) ;
if ( connecting_signal ) {
node_name + = " " + TTR ( " (Connecting From) " ) ;
2019-04-12 04:21:48 +02:00
}
2019-06-06 04:13:57 +02:00
item - > set_text ( 0 , node_name ) ;
item - > set_selectable ( 0 , marked_selectable ) ;
item - > set_custom_color ( 0 , get_color ( " accent_color " , " Editor " ) ) ;
2014-02-10 02:10:30 +01:00
} else if ( ! marked_selectable & & ! marked_children_selectable ) {
2017-03-05 16:44:50 +01:00
Node * node = p_node ;
while ( node ) {
2014-02-10 02:10:30 +01:00
if ( marked . has ( node ) ) {
2017-03-05 16:44:50 +01:00
item - > set_selectable ( 0 , false ) ;
2017-08-08 04:55:24 +02:00
item - > set_custom_color ( 0 , get_color ( " error_color " , " Editor " ) ) ;
2014-02-10 02:10:30 +01:00
break ;
}
2017-03-05 16:44:50 +01:00
node = node - > get_parent ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2016-06-04 18:17:56 +02:00
if ( can_rename ) { //should be can edit..
String warning = p_node - > get_configuration_warning ( ) ;
2017-03-05 16:44:50 +01:00
if ( warning ! = String ( ) ) {
2017-04-24 21:41:17 +02:00
item - > add_button ( 0 , get_icon ( " NodeWarning " , " EditorIcons " ) , BUTTON_WARNING , false , TTR ( " Node configuration warning: " ) + " \n " + p_node - > get_configuration_warning ( ) ) ;
2016-06-04 18:17:56 +02:00
}
2022-04-26 13:37:20 +02:00
if ( p_node - > is_unique_name_in_owner ( ) ) {
item - > add_button ( 0 , get_icon ( " SceneUniqueName " , " EditorIcons " ) , BUTTON_UNIQUE , false , vformat ( TTR ( " This node can be accessed from within anywhere in the scene by preceding it with the '%s' prefix in a node path. \n Click to disable this. " ) , UNIQUE_NODE_PREFIX ) ) ;
}
2019-08-16 22:30:31 +02:00
int num_connections = p_node - > get_persistent_signal_connection_count ( ) ;
int num_groups = p_node - > get_persistent_group_count ( ) ;
if ( num_connections > = 1 & & num_groups > = 1 ) {
item - > add_button (
0 ,
get_icon ( " SignalsAndGroups " , " EditorIcons " ) ,
BUTTON_SIGNALS ,
false ,
vformat ( TTR ( " Node has %s connection(s) and %s group(s). \n Click to show signals dock. " ) , num_connections , num_groups ) ) ;
} else if ( num_connections > = 1 ) {
item - > add_button (
0 ,
get_icon ( " Signals " , " EditorIcons " ) ,
BUTTON_SIGNALS ,
false ,
vformat ( TTR ( " Node has %s connection(s). \n Click to show signals dock. " ) , num_connections ) ) ;
} else if ( num_groups > = 1 ) {
item - > add_button (
0 ,
get_icon ( " Groups " , " EditorIcons " ) ,
BUTTON_GROUPS ,
false ,
vformat ( TTR ( " Node is in %s group(s). \n Click to show groups dock. " ) , num_groups ) ) ;
2016-06-04 18:17:56 +02:00
}
2016-05-17 23:27:15 +02:00
}
2021-09-01 15:02:42 +02:00
// Display the node name in all tooltips so that long node names can be previewed
// without having to rename them.
2017-03-05 16:44:50 +01:00
if ( p_node = = get_scene_node ( ) & & p_node - > get_scene_inherited_state ( ) . is_valid ( ) ) {
2017-07-17 19:28:18 +02:00
item - > add_button ( 0 , get_icon ( " InstanceOptions " , " EditorIcons " ) , BUTTON_SUBSCENE , false , TTR ( " Open in Editor " ) ) ;
2014-02-10 02:10:30 +01:00
2021-09-01 15:02:42 +02: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 ( ) ;
2019-08-15 14:50:26 +02:00
if ( p_node - > get_editor_description ( ) ! = String ( ) ) {
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
} else if ( p_node ! = get_scene_node ( ) & & p_node - > get_filename ( ) ! = " " & & can_open_instance ) {
2017-07-17 19:28:18 +02:00
item - > add_button ( 0 , get_icon ( " InstanceOptions " , " EditorIcons " ) , BUTTON_SUBSCENE , false , TTR ( " Open in Editor " ) ) ;
2019-08-15 14:50:26 +02:00
2021-09-01 15:02:42 +02:00
String tooltip = String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Instance: " ) + " " + p_node - > get_filename ( ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ;
2019-08-15 14:50:26 +02:00
if ( p_node - > get_editor_description ( ) ! = String ( ) ) {
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
2014-09-21 06:43:42 +02:00
} else {
2019-07-19 21:21:30 +02:00
StringName type = EditorNode : : get_singleton ( ) - > get_object_custom_type_name ( p_node ) ;
2019-08-15 14:50:26 +02:00
if ( type = = StringName ( ) ) {
2019-07-19 21:21:30 +02:00
type = p_node - > get_class ( ) ;
2019-08-15 14:50:26 +02:00
}
2021-09-01 15:02:42 +02:00
String tooltip = String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Type: " ) + " " + type ;
2019-08-15 14:50:26 +02:00
if ( p_node - > get_editor_description ( ) ! = String ( ) ) {
tooltip + = " \n \n " + p_node - > get_editor_description ( ) ;
}
item - > set_tooltip ( 0 , tooltip ) ;
2014-02-10 02:10:30 +01:00
}
2019-03-13 11:19:51 +01:00
if ( can_open_instance & & undo_redo ) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! p_node - > is_connected ( " script_changed " , this , " _node_script_changed " ) ) {
2017-03-05 16:44:50 +01:00
p_node - > connect ( " script_changed " , this , " _node_script_changed " , varray ( p_node ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2019-07-12 17:53:07 +02:00
Ref < Script > script = p_node - > get_script ( ) ;
if ( ! script . is_null ( ) ) {
2022-08-30 16:44:57 +02:00
String additional_notes ;
2022-09-06 10:14:28 +02:00
Color button_color = Color ( 1 , 1 , 1 ) ;
2022-08-30 16:44:57 +02:00
// Can't set tooltip after adding button, need to do it before.
if ( script - > is_tool ( ) ) {
additional_notes + = " \n " + TTR ( " This script is currently running in the editor. " ) ;
2022-09-06 10:14:28 +02:00
button_color = get_color ( " accent_color " , " Editor " ) ;
2022-08-30 16:44:57 +02:00
}
2019-07-19 21:21:30 +02:00
if ( EditorNode : : get_singleton ( ) - > get_object_custom_type_base ( p_node ) = = script ) {
2022-09-06 10:14:28 +02:00
additional_notes + = " \n " + TTR ( " This script is a custom type. " ) ;
button_color . a = 0.5 ;
2022-08-30 16:44:57 +02:00
}
2022-09-06 10:14:28 +02:00
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , BUTTON_SCRIPT , false , TTR ( " Open Script: " ) + " " + script - > get_path ( ) + additional_notes ) ;
item - > set_button_color ( 0 , item - > get_button_count ( 0 ) - 1 , button_color ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-03 03:03:46 +01:00
if ( p_node - > is_class ( " CanvasItem " ) ) {
2017-03-05 16:44:50 +01:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ; //_edit_group_
2021-05-05 12:44:11 +02:00
if ( is_locked ) {
2018-05-28 17:54:07 +02:00
item - > add_button ( 0 , get_icon ( " Lock " , " EditorIcons " ) , BUTTON_LOCK , false , TTR ( " Node is locked. \n Click to unlock it. " ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-05-08 07:43:19 +02:00
bool is_grouped = p_node - > has_meta ( " _edit_group_ " ) ;
2021-05-05 12:44:11 +02:00
if ( is_grouped ) {
2021-07-19 18:18:35 +02:00
item - > add_button ( 0 , get_icon ( " Group " , " EditorIcons " ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make them selectable. " ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-05-08 07:43:19 +02:00
2017-01-18 21:49:30 +01:00
bool v = p_node - > call ( " is_visible " ) ;
2021-05-05 12:44:11 +02:00
if ( v ) {
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2021-05-05 12:44:11 +02:00
} else {
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-05-08 07:43:19 +02:00
2021-05-05 12:44:11 +02:00
if ( ! p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) ) {
2017-03-05 16:44:50 +01:00
p_node - > connect ( " visibility_changed " , this , " _node_visibility_changed " , varray ( p_node ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-05-08 07:43:19 +02:00
2016-12-28 14:12:08 +01:00
_update_visibility_color ( p_node , item ) ;
2022-02-10 09:50:27 +01:00
} else if ( p_node - > is_class ( " CanvasLayer " ) ) {
bool v = p_node - > call ( " is_visible " ) ;
if ( v ) {
item - > add_button ( 0 , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
} else {
item - > add_button ( 0 , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
}
if ( ! p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) ) {
p_node - > connect ( " visibility_changed " , this , " _node_visibility_changed " , varray ( p_node ) ) ;
}
2017-01-03 03:03:46 +01:00
} else if ( p_node - > is_class ( " Spatial " ) ) {
2017-10-23 21:21:15 +02:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ;
2021-05-05 12:44:11 +02:00
if ( is_locked ) {
2018-05-28 17:54:07 +02:00
item - > add_button ( 0 , get_icon ( " Lock " , " EditorIcons " ) , BUTTON_LOCK , false , TTR ( " Node is locked. \n Click to unlock it. " ) ) ;
2021-05-05 12:44:11 +02:00
}
2017-10-23 21:21:15 +02:00
2019-04-17 18:24:28 +02:00
bool is_grouped = p_node - > has_meta ( " _edit_group_ " ) ;
2021-05-05 12:44:11 +02:00
if ( is_grouped ) {
2021-07-19 18:18:35 +02:00
item - > add_button ( 0 , get_icon ( " Group " , " EditorIcons " ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make them selectable. " ) ) ;
2021-05-05 12:44:11 +02:00
}
2019-04-17 18:24:28 +02:00
2017-01-18 21:49:30 +01:00
bool v = p_node - > call ( " is_visible " ) ;
2021-05-05 12:44:11 +02:00
if ( v ) {
2023-11-27 08:07:01 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , p_disable_visibility , TTR ( " Toggle Visibility " ) ) ;
2021-05-05 12:44:11 +02:00
} else {
2023-11-27 08:07:01 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , p_disable_visibility , TTR ( " Toggle Visibility " ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) ) {
2017-03-05 16:44:50 +01:00
p_node - > connect ( " visibility_changed " , this , " _node_visibility_changed " , varray ( p_node ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2016-12-28 14:12:08 +01:00
_update_visibility_color ( p_node , item ) ;
2018-06-07 17:46:14 +02:00
} else if ( p_node - > is_class ( " AnimationPlayer " ) ) {
bool is_pinned = AnimationPlayerEditor : : singleton - > get_player ( ) = = p_node & & AnimationPlayerEditor : : singleton - > is_pinned ( ) ;
if ( is_pinned ) {
item - > add_button ( 0 , get_icon ( " Pin " , " EditorIcons " ) , BUTTON_PIN , false , TTR ( " AnimationPlayer is pinned. \n Click to unpin. " ) ) ;
}
2014-02-10 02:10:30 +01:00
}
}
if ( editor_selection ) {
if ( editor_selection - > is_selected ( p_node ) ) {
item - > select ( 0 ) ;
}
}
2017-03-05 16:44:50 +01:00
if ( selected = = p_node ) {
2021-02-08 01:31:43 +01:00
if ( ! editor_selection ) {
2014-02-10 02:10:30 +01:00
item - > select ( 0 ) ;
2021-02-08 01:31:43 +01:00
}
2014-02-10 02:10:30 +01:00
item - > set_as_cursor ( 0 ) ;
}
2016-03-09 00:00:52 +01:00
2023-11-27 08:07:01 +01:00
// In some cases we want to disable visibility control by the user
// for automatically visibility-controlled children.
bool disable_visibility = p_node - > is_class ( " LOD " ) & & LODManager : : is_enabled ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2023-11-27 08:07:01 +01:00
_add_nodes ( p_node - > get_child ( i ) , item , disable_visibility ) ;
2014-02-10 02:10:30 +01:00
}
2016-05-16 17:23:40 +02:00
2018-06-28 01:50:25 +02: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_custom_color ( 0 , get_color ( " disabled_font_color " , " Editor " ) ) ;
item - > set_selectable ( 0 , false ) ;
}
}
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _node_visibility_changed ( Node * p_node ) {
2019-06-03 21:52:50 +02:00
if ( ! p_node | | ( p_node ! = get_scene_node ( ) & & ! p_node - > get_owner ( ) ) ) {
2014-08-14 15:31:38 +02:00
return ;
}
2019-06-03 21:52:50 +02:00
TreeItem * item = _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) ;
if ( ! item ) {
2014-08-14 15:31:38 +02:00
return ;
}
2019-06-03 21:52:50 +02:00
2017-03-05 16:44:50 +01:00
int idx = item - > get_button_by_id ( 0 , BUTTON_VISIBILITY ) ;
ERR_FAIL_COND ( idx = = - 1 ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool visible = false ;
2014-02-10 02:10:30 +01:00
2017-01-19 17:10:47 +01:00
if ( p_node - > is_class ( " CanvasItem " ) ) {
visible = p_node - > call ( " is_visible " ) ;
CanvasItemEditor : : get_singleton ( ) - > get_viewport_control ( ) - > update ( ) ;
2022-02-10 09:50:27 +01:00
} else if ( p_node - > is_class ( " CanvasLayer " ) ) {
visible = p_node - > call ( " is_visible " ) ;
CanvasItemEditor : : get_singleton ( ) - > get_viewport_control ( ) - > update ( ) ;
2017-01-19 17:10:47 +01:00
} else if ( p_node - > is_class ( " Spatial " ) ) {
2017-01-18 21:49:30 +01:00
visible = p_node - > call ( " is_visible " ) ;
2014-02-10 02:10:30 +01:00
}
2021-05-05 12:44:11 +02:00
if ( visible ) {
2017-12-14 22:34:24 +01:00
item - > set_button ( 0 , idx , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) ) ;
2021-05-05 12:44:11 +02:00
} else {
2017-12-14 22:34:24 +01:00
item - > set_button ( 0 , idx , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2016-12-28 14:12:08 +01:00
_update_visibility_color ( p_node , item ) ;
2014-02-10 02:10:30 +01:00
}
2016-12-28 14:12:08 +01:00
void SceneTreeEditor : : _update_visibility_color ( Node * p_node , TreeItem * p_item ) {
2017-01-03 03:03:46 +01:00
if ( p_node - > is_class ( " CanvasItem " ) | | p_node - > is_class ( " Spatial " ) ) {
2017-03-05 16:44:50 +01:00
Color color ( 1 , 1 , 1 , 1 ) ;
2017-07-02 17:27:27 +02:00
bool visible_on_screen = p_node - > call ( " is_visible_in_tree " ) ;
2016-12-28 14:12:08 +01:00
if ( ! visible_on_screen ) {
2017-09-26 04:43:20 +02:00
color . a = 0.6 ;
2016-12-28 14:12:08 +01:00
}
2017-03-05 16:44:50 +01:00
int idx = p_item - > get_button_by_id ( 0 , BUTTON_VISIBILITY ) ;
p_item - > set_button_color ( 0 , idx , color ) ;
2016-12-28 14:12:08 +01:00
}
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : _node_script_changed ( Node * p_node ) {
2021-05-05 12:44:11 +02:00
if ( tree_dirty ) {
2017-11-15 14:41:31 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2017-11-15 14:41:31 +01:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
2014-02-10 02:10:30 +01:00
/*
changes the order : |
TreeItem * item = p_node ? _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) : NULL ;
if ( p_node - > get_script ( ) . is_null ( ) ) {
int idx = item - > get_button_by_id ( 0 , 2 ) ;
if ( idx > = 0 )
item - > erase_button ( 0 , idx ) ;
} else {
int idx = item - > get_button_by_id ( 0 , 2 ) ;
if ( idx < 0 )
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , 2 ) ;
} */
}
void SceneTreeEditor : : _node_removed ( Node * p_node ) {
2021-05-05 12:44:11 +02:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) ) {
2016-06-08 03:08:12 +02:00
return ; //speed up exit
2021-05-05 12:44:11 +02:00
}
2016-06-08 03:08:12 +02:00
2021-05-05 12:44:11 +02:00
if ( p_node - > is_connected ( " script_changed " , this , " _node_script_changed " ) ) {
2017-03-05 16:44:50 +01:00
p_node - > disconnect ( " script_changed " , this , " _node_script_changed " ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2022-02-10 09:50:27 +01:00
if ( p_node - > is_class ( " Spatial " ) | | p_node - > is_class ( " CanvasItem " ) | | p_node - > is_class ( " CanvasLayer " ) ) {
2021-05-05 12:44:11 +02:00
if ( p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) ) {
2017-03-05 16:44:50 +01:00
p_node - > disconnect ( " visibility_changed " , this , " _node_visibility_changed " ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( p_node = = selected ) {
2021-05-04 16:00:45 +02:00
selected = nullptr ;
2021-07-23 10:56:03 +02:00
emit_signal ( " node_selected " ) ;
2014-02-10 02:10:30 +01:00
}
}
2019-05-24 15:27:22 +02:00
void SceneTreeEditor : : _node_renamed ( Node * p_node ) {
2021-09-23 09:19:21 +02:00
if ( p_node ! = get_scene_node ( ) & & ! get_scene_node ( ) - > is_a_parent_of ( p_node ) ) {
2021-04-12 13:26:56 +02:00
return ;
}
2019-05-24 15:27:22 +02:00
emit_signal ( " node_renamed " ) ;
if ( ! tree_dirty ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
}
}
2021-02-08 01:31:43 +01:00
void SceneTreeEditor : : _update_tree ( bool p_scroll_to_selected ) {
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) ) {
2017-03-05 16:44:50 +01:00
tree_dirty = false ;
2014-02-10 02:10:30 +01:00
return ;
}
2017-03-05 16:44:50 +01:00
updating_tree = true ;
2014-02-10 02:10:30 +01:00
tree - > clear ( ) ;
if ( get_scene_node ( ) ) {
2022-10-12 19:43:56 +02:00
_add_nodes ( get_scene_node ( ) , nullptr ) ;
2014-02-10 02:10:30 +01:00
last_hash = hash_djb2_one_64 ( 0 ) ;
2017-03-05 16:44:50 +01:00
_compute_hash ( get_scene_node ( ) , last_hash ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
updating_tree = false ;
tree_dirty = false ;
2022-10-12 19:43:56 +02:00
if ( ! filter . strip_edges ( ) . empty ( ) ) {
_update_filter ( nullptr , p_scroll_to_selected ) ;
}
}
bool SceneTreeEditor : : _update_filter ( TreeItem * p_parent , bool p_scroll_to_selected ) {
if ( ! p_parent ) {
p_parent = tree - > get_root ( ) ;
filter_term_warning . clear ( ) ;
}
if ( ! p_parent ) {
// Tree is empty, nothing to do here.
return false ;
}
bool keep_for_children = false ;
2024-02-28 06:38:33 +01:00
// Get the list of children ahead of time, as the list may be invalidated by deleting one of them.
LocalVector < TreeItem * > children ;
2022-10-12 19:43:56 +02:00
for ( TreeItem * child = p_parent - > get_children ( ) ; child ; child = child - > get_next ( ) ) {
2024-02-28 06:38:33 +01:00
children . push_back ( child ) ;
}
for ( uint32_t n = 0 ; n < children . size ( ) ; n + + ) {
2022-10-12 19:43:56 +02:00
// Always keep if at least one of the children are kept.
2024-02-28 06:38:33 +01:00
keep_for_children = _update_filter ( children [ n ] , p_scroll_to_selected ) | | keep_for_children ;
2022-10-12 19:43:56 +02:00
}
// Now find other reasons to keep this Node, too.
Vector < String > terms = filter . to_lower ( ) . split_spaces ( ) ;
bool keep = _item_matches_all_terms ( p_parent , terms ) ;
if ( keep_for_children | | keep ) {
if ( keep_for_children ) {
if ( ! keep ) {
const Color original_color = p_parent - > get_custom_color ( 0 ) ;
const Color disabled_color = get_color ( " disabled_font_color " , " Editor " ) ;
if ( original_color = = Color ( ) ) {
p_parent - > set_custom_color ( 0 , disabled_color ) ;
} else {
p_parent - > set_custom_color ( 0 , original_color . linear_interpolate ( disabled_color , 0.5 ) ) ;
p_parent - > set_selectable ( 0 , false ) ;
p_parent - > deselect ( 0 ) ;
}
}
}
}
if ( editor_selection ) {
Node * n = get_node_or_null ( p_parent - > get_metadata ( 0 ) ) ;
if ( keep ) {
if ( p_scroll_to_selected & & n & & editor_selection - > is_selected ( n ) ) {
tree - > scroll_to_item ( p_parent ) ;
}
} else {
if ( n & & p_parent - > is_selected ( 0 ) ) {
editor_selection - > remove_node ( n ) ;
p_parent - > deselect ( 0 ) ;
}
}
}
2024-02-28 06:38:33 +01:00
if ( ! ( keep | | keep_for_children ) ) {
memdelete ( p_parent ) ;
}
2022-10-12 19:43:56 +02:00
return keep | | keep_for_children ;
}
bool SceneTreeEditor : : _item_matches_all_terms ( TreeItem * p_item , Vector < String > p_terms ) {
if ( p_terms . empty ( ) ) {
return true ;
}
for ( int i = 0 ; i < p_terms . size ( ) ; i + + ) {
String term = p_terms [ i ] ;
// Recognise special filter.
if ( term . find ( " : " ) > - 1 & & ! term . get_slicec ( ' : ' , 0 ) . empty ( ) ) {
String parameter = term . get_slicec ( ' : ' , 0 ) ;
String argument = term . get_slicec ( ' : ' , 1 ) ;
if ( parameter = = " type " | | parameter = = " t " ) {
// Filter by Type.
String type = get_node ( p_item - > get_metadata ( 0 ) ) - > get_class ( ) ;
bool term_in_inherited_class = false ;
// Every Node is is a Node, duh!
while ( type ! = " Node " ) {
if ( type . to_lower ( ) . find ( argument ) > - 1 ) {
term_in_inherited_class = true ;
break ;
}
type = ClassDB : : get_parent_class ( type ) ;
}
if ( ! term_in_inherited_class ) {
return false ;
}
} else if ( parameter = = " group " | | parameter = = " g " ) {
// Filter by Group.
Node * node = get_node ( p_item - > get_metadata ( 0 ) ) ;
if ( argument . empty ( ) ) {
// When argument is empty, match all Nodes belonging to any exposed group.
if ( node - > get_persistent_group_count ( ) = = 0 ) {
return false ;
}
} else {
List < Node : : GroupInfo > group_info_list ;
node - > get_groups ( & group_info_list ) ;
bool term_in_groups = false ;
for ( int j = 0 ; j < group_info_list . size ( ) ; j + + ) {
if ( ! group_info_list [ j ] . persistent ) {
continue ; // Ignore internal groups.
}
if ( String ( group_info_list [ j ] . name ) . to_lower ( ) . find ( argument ) > - 1 ) {
term_in_groups = true ;
break ;
}
}
if ( ! term_in_groups ) {
return false ;
}
}
} else if ( filter_term_warning . empty ( ) ) {
filter_term_warning = vformat ( TTR ( " \" %s \" is not a known filter. " ) , parameter ) ;
continue ;
}
} else {
// Default.
if ( p_item - > get_text ( 0 ) . to_lower ( ) . find ( term ) = = - 1 ) {
return false ;
}
}
}
return true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _compute_hash ( Node * p_node , uint64_t & hash ) {
2017-08-07 12:17:31 +02:00
hash = hash_djb2_one_64 ( p_node - > get_instance_id ( ) , hash ) ;
2021-05-05 12:44:11 +02:00
if ( p_node - > get_parent ( ) ) {
2017-08-07 12:17:31 +02:00
hash = hash_djb2_one_64 ( p_node - > get_parent ( ) - > get_instance_id ( ) , hash ) ; //so a reparent still produces a different hash
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_compute_hash ( p_node - > get_child ( i ) , hash ) ;
2014-02-10 02:10:30 +01:00
}
}
void SceneTreeEditor : : _test_update_tree ( ) {
2017-03-05 16:44:50 +01:00
pending_test_update = false ;
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! is_inside_tree ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( tree_dirty ) {
2014-02-10 02:10:30 +01:00
return ; // don't even bother
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
uint64_t hash = hash_djb2_one_64 ( 0 ) ;
2021-05-05 12:44:11 +02:00
if ( get_scene_node ( ) ) {
2017-03-05 16:44:50 +01:00
_compute_hash ( get_scene_node ( ) , hash ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
//test hash
2021-05-05 12:44:11 +02:00
if ( hash = = last_hash ) {
2014-02-10 02:10:30 +01:00
return ; // did not change
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _tree_changed ( ) {
2021-05-05 12:44:11 +02:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) ) {
2016-06-08 03:08:12 +02:00
return ; //speed up exit
2021-05-05 12:44:11 +02:00
}
if ( pending_test_update ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
if ( tree_dirty ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
MessageQueue : : get_singleton ( ) - > push_call ( this , " _test_update_tree " ) ;
pending_test_update = true ;
2014-02-10 02:10:30 +01:00
}
2021-07-23 10:56:03 +02: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 + + ;
emit_signal ( " node_selected " ) ;
blocked - - ;
}
2017-11-26 12:49:21 +01:00
void SceneTreeEditor : : _deselect_items ( ) {
2021-03-12 17:58:25 +01:00
// Clear currently selected items in scene tree dock.
2018-08-23 14:15:54 +02:00
if ( editor_selection ) {
2017-12-10 22:33:44 +01:00
editor_selection - > clear ( ) ;
2018-08-23 14:15:54 +02:00
emit_signal ( " node_changed " ) ;
}
2017-11-26 12:49:21 +01:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _cell_multi_selected ( Object * p_object , int p_cell , bool p_selected ) {
2017-08-24 22:58:51 +02:00
TreeItem * item = Object : : cast_to < TreeItem > ( p_object ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! n ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! editor_selection ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
if ( p_selected ) {
editor_selection - > add_node ( n ) ;
} else {
editor_selection - > remove_node ( n ) ;
}
2021-07-23 10:56:03 +02:00
emit_signal ( " node_changed " ) ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _notification ( int p_what ) {
2019-03-06 18:33:26 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
get_tree ( ) - > connect ( " tree_changed " , this , " _tree_changed " ) ;
get_tree ( ) - > connect ( " node_removed " , this , " _node_removed " ) ;
2019-05-24 15:27:22 +02:00
get_tree ( ) - > connect ( " node_renamed " , this , " _node_renamed " ) ;
2019-03-06 18:33:26 +01:00
get_tree ( ) - > connect ( " node_configuration_warning_changed " , this , " _warning_changed " ) ;
2015-10-10 14:09:09 +02:00
2019-03-06 18:33:26 +01:00
tree - > connect ( " item_collapsed " , this , " _cell_collapsed " ) ;
2016-06-15 19:10:19 +02:00
2019-03-06 18:33:26 +01:00
_update_tree ( ) ;
} break ;
case NOTIFICATION_EXIT_TREE : {
get_tree ( ) - > disconnect ( " tree_changed " , this , " _tree_changed " ) ;
get_tree ( ) - > disconnect ( " node_removed " , this , " _node_removed " ) ;
2019-05-24 15:27:22 +02:00
get_tree ( ) - > disconnect ( " node_renamed " , this , " _node_renamed " ) ;
2019-03-06 18:33:26 +01:00
tree - > disconnect ( " item_collapsed " , this , " _cell_collapsed " ) ;
get_tree ( ) - > disconnect ( " node_configuration_warning_changed " , this , " _warning_changed " ) ;
} break ;
case NOTIFICATION_THEME_CHANGED : {
_update_tree ( ) ;
} break ;
2018-02-25 17:04:16 +01:00
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
TreeItem * SceneTreeEditor : : _find ( TreeItem * p_node , const NodePath & p_path ) {
2021-05-05 12:44:11 +02:00
if ( ! p_node ) {
2021-05-04 16:00:45 +02:00
return nullptr ;
2021-05-05 12:44:11 +02:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
NodePath np = p_node - > get_metadata ( 0 ) ;
2021-05-05 12:44:11 +02:00
if ( np = = p_path ) {
2014-02-10 02:10:30 +01:00
return p_node ;
2021-05-05 12:44:11 +02:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * children = p_node - > get_children ( ) ;
while ( children ) {
TreeItem * n = _find ( children , p_path ) ;
2021-05-05 12:44:11 +02:00
if ( n ) {
2014-02-10 02:10:30 +01:00
return n ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
children = children - > get_next ( ) ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2021-05-04 16:00:45 +02:00
return nullptr ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : set_selected ( Node * p_node , bool p_emit_selected ) {
ERR_FAIL_COND ( blocked > 0 ) ;
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( pending_test_update ) {
2014-02-10 02:10:30 +01:00
_test_update_tree ( ) ;
2021-05-05 12:44:11 +02:00
}
if ( tree_dirty ) {
2014-02-10 02:10:30 +01:00
_update_tree ( ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( selected = = p_node ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-03-09 00:00:52 +01:00
2021-05-04 16:00:45 +02:00
TreeItem * item = p_node ? _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) : nullptr ;
2014-02-10 02:10:30 +01:00
if ( item ) {
2016-12-02 03:27:17 +01:00
// make visible when it's collapsed
2017-03-05 16:44:50 +01:00
TreeItem * node = item - > get_parent ( ) ;
while ( node & & node ! = tree - > get_root ( ) ) {
2016-12-02 03:27:17 +01:00
node - > set_collapsed ( false ) ;
2017-03-05 16:44:50 +01:00
node = node - > get_parent ( ) ;
2016-12-02 03:27:17 +01:00
}
2014-02-10 02:10:30 +01:00
item - > select ( 0 ) ;
item - > set_as_cursor ( 0 ) ;
2017-03-05 16:44:50 +01:00
selected = p_node ;
2014-02-10 02:10:30 +01:00
tree - > ensure_cursor_is_visible ( ) ;
2019-04-12 04:21:48 +02:00
2014-02-10 02:10:30 +01:00
} else {
2021-05-05 12:44:11 +02:00
if ( ! p_node ) {
2021-05-04 16:00:45 +02:00
selected = nullptr ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
_update_tree ( ) ;
2017-03-05 16:44:50 +01:00
selected = p_node ;
2017-08-20 00:13:10 +02:00
}
if ( p_emit_selected ) {
2021-07-23 10:56:03 +02:00
emit_signal ( " node_selected " ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _rename_node ( ObjectID p_node , const String & p_name ) {
2014-02-10 02:10:30 +01:00
Object * o = ObjectDB : : get_instance ( p_node ) ;
ERR_FAIL_COND ( ! o ) ;
2017-08-24 22:58:51 +02:00
Node * n = Object : : cast_to < Node > ( o ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! n ) ;
2017-03-05 16:44:50 +01:00
TreeItem * item = _find ( tree - > get_root ( ) , n - > get_path ( ) ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! item ) ;
2017-03-05 16:44:50 +01:00
n - > set_name ( p_name ) ;
item - > set_metadata ( 0 , n - > get_path ( ) ) ;
item - > set_text ( 0 , p_name ) ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _renamed ( ) {
2017-03-05 16:44:50 +01:00
TreeItem * which = tree - > get_edited ( ) ;
2014-06-11 08:45:26 +02:00
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! which ) ;
NodePath np = which - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! n ) ;
2018-10-29 14:47:53 +01:00
// Empty node names are not allowed, so resets it to previous text and show warning
if ( which - > get_text ( 0 ) . strip_edges ( ) . empty ( ) ) {
which - > set_text ( 0 , n - > get_name ( ) ) ;
2018-12-18 00:03:25 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " No name provided. " ) ) ;
2018-10-29 14:47:53 +01:00
return ;
}
2021-01-28 20:43:49 +01: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 ) ;
2014-06-11 08:45:26 +02:00
error - > popup_centered_minsize ( ) ;
2018-04-26 18:42:15 +02:00
2019-01-29 17:51:50 +01:00
if ( new_name . empty ( ) ) {
which - > set_text ( 0 , n - > get_name ( ) ) ;
return ;
}
2018-04-26 18:42:15 +02:00
which - > set_text ( 0 , new_name ) ;
2014-06-11 08:45:26 +02:00
}
2021-05-05 12:44:11 +02:00
if ( new_name = = n - > get_name ( ) ) {
2016-01-26 17:25:04 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-01-26 17:25:04 +01:00
2020-09-12 23:59:46 +02: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 ( ) ;
2022-04-26 13:37:20 +02:00
if ( n - > is_unique_name_in_owner ( ) & & get_tree ( ) - > get_edited_scene_root ( ) - > get_node_or_null ( " % " + new_name ) ! = nullptr ) {
error - > set_text ( TTR ( " Another node already uses this unique name in the scene. " ) ) ;
error - > popup_centered ( ) ;
which - > set_text ( 0 , n - > get_name ( ) ) ;
return ;
}
2014-02-10 02:10:30 +01:00
if ( ! undo_redo ) {
2017-03-05 16:44:50 +01:00
n - > set_name ( new_name ) ;
which - > set_metadata ( 0 , n - > get_path ( ) ) ;
2014-02-10 02:10:30 +01:00
emit_signal ( " node_renamed " ) ;
} else {
2016-05-04 03:25:37 +02:00
undo_redo - > create_action ( TTR ( " Rename Node " ) ) ;
2017-03-05 16:44:50 +01:00
emit_signal ( " node_prerename " , n , new_name ) ;
2017-08-07 12:17:31 +02: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 02:10:30 +01:00
undo_redo - > commit_action ( ) ;
}
}
Node * SceneTreeEditor : : get_selected ( ) {
return selected ;
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : set_marked ( const Set < Node * > & p_marked , bool p_selectable , bool p_children_selectable ) {
2021-05-05 12:44:11 +02:00
if ( tree_dirty ) {
2014-02-10 02:10:30 +01:00
_update_tree ( ) ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
marked = p_marked ;
marked_selectable = p_selectable ;
marked_children_selectable = p_children_selectable ;
2014-02-10 02:10:30 +01:00
_update_tree ( ) ;
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : set_marked ( Node * p_marked , bool p_selectable , bool p_children_selectable ) {
Set < Node * > s ;
2021-05-05 12:44:11 +02:00
if ( p_marked ) {
2014-02-10 02:10:30 +01:00
s . insert ( p_marked ) ;
2021-05-05 12:44:11 +02:00
}
2017-03-05 16:44:50 +01:00
set_marked ( s , p_selectable , p_children_selectable ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : set_filter ( const String & p_filter ) {
filter = p_filter ;
2021-02-08 01:31:43 +01:00
_update_tree ( true ) ;
2016-05-16 17:23:40 +02:00
}
String SceneTreeEditor : : get_filter ( ) const {
return filter ;
}
2022-10-12 19:43:56 +02:00
String SceneTreeEditor : : get_filter_term_warning ( ) const {
return filter_term_warning ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : set_display_foreign_nodes ( bool p_display ) {
2017-03-05 16:44:50 +01:00
display_foreign = p_display ;
2014-02-10 02:10:30 +01:00
_update_tree ( ) ;
}
bool SceneTreeEditor : : get_display_foreign_nodes ( ) const {
return display_foreign ;
}
2018-06-28 01:50:25 +02:00
void SceneTreeEditor : : set_valid_types ( const Vector < StringName > & p_valid ) {
valid_types = p_valid ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : set_editor_selection ( EditorSelection * p_selection ) {
2017-03-05 16:44:50 +01:00
editor_selection = p_selection ;
2014-02-10 02:10:30 +01:00
tree - > set_select_mode ( Tree : : SELECT_MULTI ) ;
tree - > set_cursor_can_exit_tree ( false ) ;
2017-03-05 16:44:50 +01:00
editor_selection - > connect ( " selection_changed " , this , " _selection_changed " ) ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _update_selection ( TreeItem * item ) {
ERR_FAIL_COND ( ! item ) ;
NodePath np = item - > get_metadata ( 0 ) ;
2021-05-05 12:44:11 +02:00
if ( ! has_node ( np ) ) {
2016-01-23 23:51:51 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-01-23 23:51:51 +01:00
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! n ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( editor_selection - > is_selected ( n ) ) {
2014-02-10 02:10:30 +01:00
item - > select ( 0 ) ;
2021-05-05 12:44:11 +02:00
} else {
2014-02-10 02:10:30 +01:00
item - > deselect ( 0 ) ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * c = item - > get_children ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( c ) {
2014-02-10 02:10:30 +01:00
_update_selection ( c ) ;
2017-03-05 16:44:50 +01:00
c = c - > get_next ( ) ;
2014-02-10 02:10:30 +01:00
}
}
void SceneTreeEditor : : _selection_changed ( ) {
2021-05-05 12:44:11 +02:00
if ( ! editor_selection ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * root = tree - > get_root ( ) ;
2014-02-10 02:10:30 +01:00
2021-05-05 12:44:11 +02:00
if ( ! root ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
_update_selection ( root ) ;
}
void SceneTreeEditor : : _cell_collapsed ( Object * p_obj ) {
2021-05-05 12:44:11 +02:00
if ( updating_tree ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
if ( ! can_rename ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
TreeItem * ti = Object : : cast_to < TreeItem > ( p_obj ) ;
2021-05-05 12:44:11 +02:00
if ( ! ti ) {
2014-02-10 02:10:30 +01:00
return ;
2021-05-05 12:44:11 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool collapsed = ti - > is_collapsed ( ) ;
2014-02-10 02:10:30 +01:00
NodePath np = ti - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! n ) ;
2016-06-28 18:10:15 +02:00
n - > set_display_folded ( collapsed ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
Variant SceneTreeEditor : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
2021-05-05 12:44:11 +02:00
if ( ! can_rename ) {
2016-05-11 16:46:08 +02:00
return Variant ( ) ; //not editable tree
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
2019-12-13 06:13:47 +01:00
if ( tree - > get_button_id_at_position ( p_point ) ! = - 1 ) {
return Variant ( ) ; //dragging from button
}
2017-03-05 16:44:50 +01:00
Vector < Node * > selected ;
2021-05-04 14:20:36 +02:00
Vector < Ref < Texture > > icons ;
2021-05-04 16:00:45 +02:00
TreeItem * next = tree - > get_next_selected ( nullptr ) ;
2016-05-11 16:46:08 +02:00
while ( next ) {
NodePath np = next - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2016-05-11 16:46:08 +02:00
if ( n ) {
2023-12-06 09:26:37 +01:00
selected . push_back ( n ) ;
icons . push_back ( next - > get_icon ( 0 ) ) ;
2016-05-11 16:46:08 +02:00
}
2017-03-05 16:44:50 +01:00
next = tree - > get_next_selected ( next ) ;
2016-05-11 16:46:08 +02:00
}
2021-05-05 12:44:11 +02:00
if ( selected . empty ( ) ) {
2016-05-11 16:46:08 +02:00
return Variant ( ) ;
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2016-05-11 16:46:08 +02:00
Array objs ;
2016-05-17 16:27:35 +02:00
int list_max = 10 ;
float opacity_step = 1.0f / list_max ;
float opacity_item = 1.0f ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < selected . size ( ) ; i + + ) {
if ( i < list_max ) {
HBoxContainer * hb = memnew ( HBoxContainer ) ;
2017-01-12 22:27:27 +01:00
TextureRect * tf = memnew ( TextureRect ) ;
2016-05-17 16:27:35 +02:00
tf - > set_texture ( icons [ i ] ) ;
2019-09-30 18:36:49 +02:00
tf - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_CENTERED ) ;
2016-05-17 16:27:35 +02:00
hb - > add_child ( tf ) ;
2017-03-05 16:44:50 +01:00
Label * label = memnew ( Label ( selected [ i ] - > get_name ( ) ) ) ;
2016-05-17 16:27:35 +02:00
hb - > add_child ( label ) ;
vb - > add_child ( hb ) ;
2017-03-05 16:44:50 +01:00
hb - > set_modulate ( Color ( 1 , 1 , 1 , opacity_item ) ) ;
2016-05-17 16:27:35 +02:00
opacity_item - = opacity_step ;
}
2016-05-11 16:46:08 +02:00
NodePath p = selected [ i ] - > get_path ( ) ;
objs . push_back ( p ) ;
}
set_drag_preview ( vb ) ;
Dictionary drag_data ;
2017-03-05 16:44:50 +01:00
drag_data [ " type " ] = " nodes " ;
drag_data [ " nodes " ] = objs ;
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN | Tree : : DROP_MODE_ON_ITEM ) ;
2016-08-03 16:28:20 +02:00
emit_signal ( " nodes_dragged " ) ;
2016-05-11 16:46:08 +02:00
return drag_data ;
}
2016-10-27 16:32:41 +02:00
bool SceneTreeEditor : : _is_script_type ( const StringName & p_type ) const {
return ( script_types - > find ( p_type ) ) ;
}
2017-03-05 16:44:50 +01:00
bool SceneTreeEditor : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2021-05-05 12:44:11 +02:00
if ( ! can_rename ) {
2016-05-11 16:46:08 +02:00
return false ; //not editable tree
2021-05-05 12:44:11 +02:00
}
2016-05-16 17:23:40 +02:00
2017-03-05 16:44:50 +01:00
Dictionary d = p_data ;
2021-05-05 12:44:11 +02:00
if ( ! d . has ( " type " ) ) {
2016-05-11 16:46:08 +02:00
return false ;
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
2017-09-10 15:37:49 +02:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2021-05-05 12:44:11 +02:00
if ( ! item ) {
2016-07-18 20:00:14 +02:00
return false ;
2021-05-05 12:44:11 +02:00
}
2016-07-18 20:00:14 +02:00
2017-09-10 15:37:49 +02:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2021-05-05 12:44:11 +02:00
if ( section < - 1 | | ( section = = - 1 & & ! item - > get_parent ( ) ) ) {
2016-07-18 20:00:14 +02:00
return false ;
2021-05-05 12:44:11 +02:00
}
2016-07-18 20:00:14 +02:00
2017-03-05 16:44:50 +01:00
if ( String ( d [ " type " ] ) = = " files " ) {
2016-05-12 01:57:52 +02:00
Vector < String > files = d [ " files " ] ;
2021-05-05 12:44:11 +02:00
if ( files . size ( ) = = 0 ) {
2016-05-12 01:57:52 +02:00
return false ; //weird
2021-05-05 12:44:11 +02:00
}
2016-05-12 01:57:52 +02:00
2016-10-27 16:32:41 +02: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-12 01:57:52 +02:00
2021-07-21 15:40:19 +02:00
bool scene_drop = true ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2016-10-27 16:32:41 +02:00
String file = files [ i ] ;
2016-05-12 01:57:52 +02:00
String ftype = EditorFileSystem : : get_singleton ( ) - > get_file_type ( file ) ;
2021-05-05 12:44:11 +02:00
if ( ftype ! = " PackedScene " ) {
2021-07-21 15:40:19 +02:00
scene_drop = false ;
break ;
2021-05-05 12:44:11 +02:00
}
2016-05-12 01:57:52 +02:00
}
2021-07-21 15:40:19 +02: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-12 01:57:52 +02:00
return true ;
}
2019-08-16 21:05:01 +02: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 ;
}
}
}
2023-12-06 09:26:37 +01:00
if ( filter . empty ( ) & & String ( d [ " type " ] ) = = " nodes " ) {
Array nodes = d [ " nodes " ] ;
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
Node * n = get_node ( nodes [ i ] ) ;
// Only allow selection if not part of an instanced scene.
if ( n & & n - > get_owner ( ) & & n - > get_owner ( ) ! = get_scene_node ( ) & & ! n - > get_owner ( ) - > get_filename ( ) . empty ( ) ) {
return false ;
}
}
return true ;
}
return false ;
2016-05-11 16:46:08 +02:00
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2021-05-05 12:44:11 +02:00
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) ) {
2016-05-11 16:46:08 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
2017-09-10 15:37:49 +02:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2021-05-05 12:44:11 +02:00
if ( ! item ) {
2016-05-11 16:46:08 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2017-09-10 15:37:49 +02:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2021-05-05 12:44:11 +02:00
if ( section < - 1 ) {
2016-05-11 16:46:08 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
NodePath np = item - > get_metadata ( 0 ) ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2021-05-05 12:44:11 +02:00
if ( ! n ) {
2016-05-11 16:46:08 +02:00
return ;
2021-05-05 12:44:11 +02:00
}
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
Dictionary d = p_data ;
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
if ( String ( d [ " type " ] ) = = " nodes " ) {
Array nodes = d [ " nodes " ] ;
emit_signal ( " nodes_rearranged " , nodes , np , section ) ;
2016-05-12 01:57:52 +02:00
}
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
if ( String ( d [ " type " ] ) = = " files " ) {
2016-10-27 16:32:41 +02:00
Vector < String > files = d [ " files " ] ;
String ftype = EditorFileSystem : : get_singleton ( ) - > get_file_type ( files [ 0 ] ) ;
if ( _is_script_type ( ftype ) ) {
2017-03-05 16:44:50 +01:00
emit_signal ( " script_dropped " , files [ 0 ] , np ) ;
2016-10-27 16:32:41 +02:00
} else {
2017-03-05 16:44:50 +01:00
emit_signal ( " files_dropped " , files , np , section ) ;
2016-10-27 16:32:41 +02:00
}
2016-05-12 01:57:52 +02:00
}
2019-08-16 21:05:01 +02: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 ) ) ) {
emit_signal ( " script_dropped " , sp , np ) ;
}
}
}
2016-05-11 16:46:08 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _rmb_select ( const Vector2 & p_pos ) {
emit_signal ( " rmb_pressed " , tree - > get_global_transform ( ) . xform ( p_pos ) ) ;
2016-05-16 04:41:48 +02:00
}
2014-09-03 04:13:40 +02:00
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : _warning_changed ( Node * p_for_node ) {
2016-05-17 23:27:15 +02:00
//should use a timer
update_timer - > start ( ) ;
}
2016-05-16 17:23:40 +02:00
2019-04-12 04:21:48 +02:00
void SceneTreeEditor : : set_connect_to_script_mode ( bool p_enable ) {
connect_to_script_mode = p_enable ;
update_tree ( ) ;
}
2019-06-06 04:13:57 +02:00
void SceneTreeEditor : : set_connecting_signal ( bool p_enable ) {
connecting_signal = p_enable ;
update_tree ( ) ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _tree_changed " , & SceneTreeEditor : : _tree_changed ) ;
2021-02-14 22:32:42 +01:00
ClassDB : : bind_method ( D_METHOD ( " _update_tree " , " scroll_to_selected " ) , & SceneTreeEditor : : _update_tree , DEFVAL ( false ) ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _node_removed " , & SceneTreeEditor : : _node_removed ) ;
2019-05-24 15:27:22 +02:00
ClassDB : : bind_method ( " _node_renamed " , & SceneTreeEditor : : _node_renamed ) ;
2021-07-23 10:56:03 +02:00
ClassDB : : bind_method ( " _selected_changed " , & SceneTreeEditor : : _selected_changed ) ;
2017-11-26 12:49:21 +01:00
ClassDB : : bind_method ( " _deselect_items " , & SceneTreeEditor : : _deselect_items ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _renamed " , & SceneTreeEditor : : _renamed ) ;
ClassDB : : bind_method ( " _rename_node " , & SceneTreeEditor : : _rename_node ) ;
ClassDB : : bind_method ( " _test_update_tree " , & SceneTreeEditor : : _test_update_tree ) ;
ClassDB : : bind_method ( " _cell_multi_selected " , & SceneTreeEditor : : _cell_multi_selected ) ;
ClassDB : : bind_method ( " _selection_changed " , & SceneTreeEditor : : _selection_changed ) ;
ClassDB : : bind_method ( " _cell_button_pressed " , & SceneTreeEditor : : _cell_button_pressed ) ;
ClassDB : : bind_method ( " _cell_collapsed " , & SceneTreeEditor : : _cell_collapsed ) ;
ClassDB : : bind_method ( " _rmb_select " , & SceneTreeEditor : : _rmb_select ) ;
ClassDB : : bind_method ( " _warning_changed " , & SceneTreeEditor : : _warning_changed ) ;
ClassDB : : bind_method ( " _node_script_changed " , & SceneTreeEditor : : _node_script_changed ) ;
ClassDB : : bind_method ( " _node_visibility_changed " , & SceneTreeEditor : : _node_visibility_changed ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01: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 16:46:08 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " update_tree " ) , & SceneTreeEditor : : update_tree ) ;
2016-05-17 23:27:15 +02:00
2017-03-05 16:44:50 +01: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 " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " files_dropped " , PropertyInfo ( Variant : : POOL_STRING_ARRAY , " files " ) , PropertyInfo ( Variant : : NODE_PATH , " to_path " ) , PropertyInfo ( Variant : : INT , " type " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " script_dropped " , PropertyInfo ( Variant : : STRING , " file " ) , PropertyInfo ( Variant : : NODE_PATH , " to_path " ) ) ) ;
2017-09-10 15:37:49 +02:00
ADD_SIGNAL ( MethodInfo ( " rmb_pressed " , PropertyInfo ( Variant : : VECTOR2 , " position " ) ) ) ;
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " open " ) ) ;
ADD_SIGNAL ( MethodInfo ( " open_script " ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
SceneTreeEditor : : SceneTreeEditor ( bool p_label , bool p_can_rename , bool p_can_open_instance ) {
2019-04-12 04:21:48 +02:00
connect_to_script_mode = false ;
2019-06-06 04:13:57 +02:00
connecting_signal = false ;
2021-05-04 16:00:45 +02:00
undo_redo = nullptr ;
2017-03-05 16:44:50 +01:00
tree_dirty = true ;
2021-05-04 16:00:45 +02:00
selected = nullptr ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
marked_selectable = false ;
marked_children_selectable = false ;
can_rename = p_can_rename ;
can_open_instance = p_can_open_instance ;
display_foreign = false ;
2021-05-04 16:00:45 +02:00
editor_selection = nullptr ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( p_label ) {
2017-03-05 16:44:50 +01:00
Label * label = memnew ( Label ) ;
2017-03-29 17:29:38 +02:00
label - > set_position ( Point2 ( 10 , 0 ) ) ;
2016-05-04 03:25:37 +02:00
label - > set_text ( TTR ( " Scene Tree (Nodes): " ) ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
add_child ( label ) ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
tree = memnew ( Tree ) ;
tree - > set_anchor ( MARGIN_RIGHT , ANCHOR_END ) ;
tree - > set_anchor ( MARGIN_BOTTOM , ANCHOR_END ) ;
tree - > set_begin ( Point2 ( 0 , p_label ? 18 : 0 ) ) ;
tree - > set_end ( Point2 ( 0 , 0 ) ) ;
2017-04-03 08:50:16 +02:00
tree - > add_constant_override ( " button_margin " , 0 ) ;
2021-03-12 17:58:25 +01:00
tree - > set_allow_reselect ( true ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
add_child ( tree ) ;
2016-03-09 00:00:52 +01:00
2016-05-11 16:46:08 +02:00
tree - > set_drag_forwarding ( this ) ;
2016-05-16 17:23:40 +02:00
if ( p_can_rename ) {
2016-05-16 04:41:48 +02:00
tree - > set_allow_rmb_select ( true ) ;
2017-03-05 16:44:50 +01:00
tree - > connect ( " item_rmb_selected " , this , " _rmb_select " ) ;
tree - > connect ( " empty_tree_rmb_selected " , this , " _rmb_select " ) ;
2016-05-16 17:23:40 +02:00
}
2016-05-11 16:46:08 +02:00
2021-07-23 10:56:03 +02:00
tree - > connect ( " cell_selected " , this , " _selected_changed " ) ;
2017-03-05 16:44:50 +01:00
tree - > connect ( " item_edited " , this , " _renamed " , varray ( ) , CONNECT_DEFERRED ) ;
tree - > connect ( " multi_selected " , this , " _cell_multi_selected " ) ;
tree - > connect ( " button_pressed " , this , " _cell_button_pressed " ) ;
2017-11-26 12:49:21 +01:00
tree - > connect ( " nothing_selected " , this , " _deselect_items " ) ;
2021-07-23 10:56:03 +02:00
//tree->connect("item_edited", this,"_renamed",Vector<Variant>(),true);
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
error = memnew ( AcceptDialog ) ;
2014-03-14 02:57:24 +01:00
add_child ( error ) ;
2017-03-05 16:44:50 +01:00
warning = memnew ( AcceptDialog ) ;
2016-05-17 23:27:15 +02:00
add_child ( warning ) ;
2017-08-23 22:25:14 +02:00
warning - > set_title ( TTR ( " Node Configuration Warning! " ) ) ;
2016-05-17 23:27:15 +02:00
2017-03-05 16:44:50 +01:00
show_enabled_subscene = false ;
2016-05-17 23:27:15 +02:00
2017-03-05 16:44:50 +01:00
last_hash = 0 ;
pending_test_update = false ;
updating_tree = false ;
blocked = 0 ;
2014-09-03 04:13:40 +02:00
2016-05-17 23:27:15 +02:00
update_timer = memnew ( Timer ) ;
2021-02-19 12:39:53 +01:00
update_timer - > connect ( " timeout " , this , " _update_tree " , varray ( false ) ) ;
2016-05-17 23:27:15 +02:00
update_timer - > set_one_shot ( true ) ;
update_timer - > set_wait_time ( 0.5 ) ;
add_child ( update_timer ) ;
2015-10-10 14:09:09 +02:00
2016-10-27 16:32:41 +02:00
script_types = memnew ( List < StringName > ) ;
2017-01-03 03:03:46 +01:00
ClassDB : : get_inheriters_from_class ( " Script " , script_types ) ;
2014-02-10 02:10:30 +01:00
}
SceneTreeEditor : : ~ SceneTreeEditor ( ) {
2016-10-27 16:32:41 +02:00
memdelete ( script_types ) ;
2014-02-10 02:10:30 +01:00
}
/******** DIALOG *********/
void SceneTreeDialog : : _notification ( int p_what ) {
2019-04-16 01:21:51 +02:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
connect ( " confirmed " , this , " _select " ) ;
2019-07-06 19:09:34 +02:00
filter - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
filter - > set_clear_button_enabled ( true ) ;
2019-04-16 01:21:51 +02:00
} break ;
case NOTIFICATION_EXIT_TREE : {
disconnect ( " confirmed " , this , " _select " ) ;
} break ;
case NOTIFICATION_VISIBILITY_CHANGED : {
2021-05-05 12:44:11 +02:00
if ( is_visible_in_tree ( ) ) {
2019-04-16 01:21:51 +02:00
tree - > update_tree ( ) ;
2021-05-05 12:44:11 +02:00
}
2019-04-16 01:21:51 +02:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
void SceneTreeDialog : : _cancel ( ) {
hide ( ) ;
}
void SceneTreeDialog : : _select ( ) {
if ( tree - > get_selected ( ) ) {
2017-03-05 16:44:50 +01:00
emit_signal ( " selected " , tree - > get_selected ( ) - > get_path ( ) ) ;
2014-02-10 02:10:30 +01:00
hide ( ) ;
}
}
2022-07-14 06:03:27 +02:00
void SceneTreeDialog : : _selected_changed ( ) {
get_ok ( ) - > set_disabled ( ! tree - > get_selected ( ) ) ;
}
2019-07-06 19:09:34 +02:00
void SceneTreeDialog : : _filter_changed ( const String & p_filter ) {
tree - > set_filter ( p_filter ) ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeDialog : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _select " , & SceneTreeDialog : : _select ) ;
ClassDB : : bind_method ( " _cancel " , & SceneTreeDialog : : _cancel ) ;
2022-07-14 06:03:27 +02:00
ClassDB : : bind_method ( D_METHOD ( " _selected_changed " ) , & SceneTreeDialog : : _selected_changed ) ;
2019-07-06 19:09:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " _filter_changed " ) , & SceneTreeDialog : : _filter_changed ) ;
2017-03-05 16:44:50 +01:00
ADD_SIGNAL ( MethodInfo ( " selected " , PropertyInfo ( Variant : : NODE_PATH , " path " ) ) ) ;
2014-02-10 02:10:30 +01:00
}
SceneTreeDialog : : SceneTreeDialog ( ) {
2016-05-04 03:25:37 +02:00
set_title ( TTR ( " Select a Node " ) ) ;
2019-07-06 19:09:34 +02:00
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
add_child ( vbc ) ;
filter = memnew ( LineEdit ) ;
filter - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
filter - > set_placeholder ( TTR ( " Filter nodes " ) ) ;
filter - > add_constant_override ( " minimum_spaces " , 0 ) ;
filter - > connect ( " text_changed " , this , " _filter_changed " ) ;
vbc - > add_child ( filter ) ;
2014-02-10 02:10:30 +01:00
2018-11-02 19:05:38 +01:00
tree = memnew ( SceneTreeEditor ( false , false , true ) ) ;
2019-07-06 19:09:34 +02:00
tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-05 16:44:50 +01:00
tree - > get_scene_tree ( ) - > connect ( " item_activated " , this , " _select " ) ;
2019-07-06 19:09:34 +02:00
vbc - > add_child ( tree ) ;
2022-07-14 06:03:27 +02:00
// Disable the OK button when no node is selected.
get_ok ( ) - > set_disabled ( ! tree - > get_selected ( ) ) ;
tree - > connect ( " node_selected " , this , " _selected_changed " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
SceneTreeDialog : : ~ SceneTreeDialog ( ) {
2014-02-10 02:10:30 +01:00
}