2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* scene_tree_editor.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01: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-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"
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"
2014-02-10 02:10:30 +01:00
# include "editor_node.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"
2014-02-10 02:10:30 +01:00
Node * SceneTreeEditor : : get_scene_node ( ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , NULL ) ;
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 ) {
2016-06-12 04:00:06 +02:00
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
}
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 ( ) ;
2014-02-10 02:10:30 +01:00
if ( ! script . is_null ( ) )
2017-03-05 16:44:50 +01:00
emit_signal ( " open_script " , script ) ;
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 ( ) ;
2018-10-14 19:33:34 +02:00
if ( selection . size ( ) > 1 & & selection . find ( n ) ! = NULL ) {
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 ( ) ;
2017-03-05 16:44:50 +01:00
if ( config_err = = String ( ) )
2016-05-17 23:27:15 +02:00
return ;
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-06-04 18:17:56 +02:00
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-06-04 18:17:56 +02:00
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 ( ) ;
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
2017-03-05 16:44:50 +01:00
bool SceneTreeEditor : : _add_nodes ( Node * p_node , TreeItem * p_parent ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! p_node )
2016-05-16 17:23:40 +02:00
return false ;
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 ( ) ) {
2014-09-03 04:13:40 +02:00
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 ( ) ) ) ) {
2014-09-03 04:13:40 +02:00
2017-03-05 16:44:50 +01:00
part_of_subscene = true ;
2014-09-03 04:13:40 +02:00
//allow
} else {
2016-05-16 17:23:40 +02:00
return false ;
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 ( ) ) ;
2015-10-17 23:43:52 +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 ) ;
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
if ( ( bool ) p_node - > get_meta ( " _editor_collapsed " ) )
p_node - > set_display_folded ( true ) ;
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 ( ) ;
2014-02-10 02:10:30 +01:00
if ( collapsed )
item - > set_collapsed ( true ) ;
}
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 " ) ;
if ( ! p_node - > get_script ( ) . is_null ( ) ) {
//has script
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , BUTTON_SCRIPT ) ;
} else {
//has no script
item - > set_custom_color ( 0 , get_color ( " disabled_font_color " , " Editor " ) ) ;
item - > set_selectable ( 0 , false ) ;
accent . a * = 0.7 ;
}
if ( marked . has ( p_node ) ) {
item - > set_text ( 0 , String ( p_node - > get_name ( ) ) + " " + TTR ( " (Connecting From) " ) ) ;
item - > set_custom_color ( 0 , accent ) ;
}
} else if ( part_of_subscene ) {
2014-09-03 04:13:40 +02:00
//item->set_selectable(0,marked_selectable);
2018-06-28 01:50:25 +02:00
if ( valid_types . size ( ) = = 0 ) {
item - > set_custom_color ( 0 , get_color ( " disabled_font_color " , " Editor " ) ) ;
}
2014-09-03 04:13:40 +02:00
} else if ( marked . has ( p_node ) ) {
2016-03-09 00:00:52 +01:00
2019-04-12 04:21:48 +02:00
if ( ! connect_to_script_mode ) {
item - > set_selectable ( 0 , marked_selectable ) ;
}
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
} 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
}
bool has_connections = p_node - > has_persistent_signal_connections ( ) ;
bool has_groups = p_node - > has_persistent_groups ( ) ;
if ( has_connections & & has_groups ) {
2018-05-28 17:54:07 +02:00
item - > add_button ( 0 , get_icon ( " SignalsAndGroups " , " EditorIcons " ) , BUTTON_SIGNALS , false , TTR ( " Node has connection(s) and group(s). \n Click to show signals dock. " ) ) ;
2016-06-04 18:17:56 +02:00
} else if ( has_connections ) {
2017-10-12 20:59:25 +02:00
item - > add_button ( 0 , get_icon ( " Signals " , " EditorIcons " ) , BUTTON_SIGNALS , false , TTR ( " Node has connections. \n Click to show signals dock. " ) ) ;
2016-06-04 18:17:56 +02:00
} else if ( has_groups ) {
2017-04-24 21:41:17 +02:00
item - > add_button ( 0 , get_icon ( " Groups " , " EditorIcons " ) , BUTTON_GROUPS , false , TTR ( " Node is in group(s). \n Click to show groups dock. " ) ) ;
2016-06-04 18:17:56 +02:00
}
2016-05-17 23:27:15 +02:00
}
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 " ) ) ;
2017-03-05 16:44:50 +01:00
item - > set_tooltip ( 0 , TTR ( " Inherits: " ) + " " + p_node - > get_scene_inherited_state ( ) - > get_path ( ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ) ;
} else if ( p_node ! = get_scene_node ( ) & & p_node - > get_filename ( ) ! = " " & & can_open_instance ) {
2014-02-10 02:10:30 +01:00
2017-07-17 19:28:18 +02:00
item - > add_button ( 0 , get_icon ( " InstanceOptions " , " EditorIcons " ) , BUTTON_SUBSCENE , false , TTR ( " Open in Editor " ) ) ;
2017-03-05 16:44:50 +01:00
item - > set_tooltip ( 0 , TTR ( " Instance: " ) + " " + p_node - > get_filename ( ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ) ;
2014-09-21 06:43:42 +02:00
} else {
2017-03-05 16:44:50 +01:00
item - > set_tooltip ( 0 , String ( p_node - > get_name ( ) ) + " \n " + TTR ( " Type: " ) + " " + p_node - > get_class ( ) ) ;
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
2017-03-05 16:44:50 +01:00
if ( ! p_node - > is_connected ( " script_changed " , this , " _node_script_changed " ) )
p_node - > connect ( " script_changed " , this , " _node_script_changed " , varray ( p_node ) ) ;
2014-02-10 02:10:30 +01:00
if ( ! p_node - > get_script ( ) . is_null ( ) ) {
2018-05-28 17:54:07 +02:00
item - > add_button ( 0 , get_icon ( " Script " , " EditorIcons " ) , BUTTON_SCRIPT , false , TTR ( " Open Script " ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-03 03:03:46 +01:00
if ( p_node - > is_class ( " CanvasItem " ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ; //_edit_group_
2014-05-08 07:43:19 +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. " ) ) ;
2014-05-08 07:43:19 +02:00
bool is_grouped = p_node - > has_meta ( " _edit_group_ " ) ;
if ( is_grouped )
2018-05-28 17:54:07 +02:00
item - > add_button ( 0 , get_icon ( " Group " , " EditorIcons " ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make selectable. " ) ) ;
2014-05-08 07:43:19 +02:00
2017-01-18 21:49:30 +01:00
bool v = p_node - > call ( " is_visible " ) ;
if ( v )
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2017-01-18 21:49:30 +01:00
else
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2014-05-08 07:43:19 +02:00
2017-03-05 16:44:50 +01:00
if ( ! p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) )
p_node - > connect ( " visibility_changed " , this , " _node_visibility_changed " , varray ( p_node ) ) ;
2014-05-08 07:43:19 +02:00
2016-12-28 14:12:08 +01:00
_update_visibility_color ( p_node , item ) ;
2017-01-03 03:03:46 +01:00
} else if ( p_node - > is_class ( " Spatial " ) ) {
2014-02-10 02:10:30 +01:00
2017-10-23 21:21:15 +02:00
bool is_locked = p_node - > has_meta ( " _edit_lock_ " ) ;
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. " ) ) ;
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_ " ) ;
if ( is_grouped )
item - > add_button ( 0 , get_icon ( " Group " , " EditorIcons " ) , BUTTON_GROUP , false , TTR ( " Children are not selectable. \n Click to make selectable. " ) ) ;
2017-01-18 21:49:30 +01:00
bool v = p_node - > call ( " is_visible " ) ;
if ( v )
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2017-01-18 21:49:30 +01:00
else
2017-12-14 22:34:24 +01:00
item - > add_button ( 0 , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) , BUTTON_VISIBILITY , false , TTR ( " Toggle Visibility " ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( ! p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) )
p_node - > connect ( " visibility_changed " , this , " _node_visibility_changed " , varray ( p_node ) ) ;
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 ) {
2014-02-10 02:10:30 +01:00
if ( ! editor_selection )
item - > select ( 0 ) ;
item - > set_as_cursor ( 0 ) ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
bool keep = ( filter . is_subsequence_ofi ( String ( p_node - > get_name ( ) ) ) ) ;
2016-05-16 17:23:40 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
bool child_keep = _add_nodes ( p_node - > get_child ( i ) , item ) ;
2016-05-16 17:23:40 +02:00
keep = keep | | child_keep ;
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_selectable(0,marked_selectable);
item - > set_custom_color ( 0 , get_color ( " disabled_font_color " , " Editor " ) ) ;
item - > set_selectable ( 0 , false ) ;
}
}
2016-05-16 17:23:40 +02:00
if ( ! keep ) {
memdelete ( item ) ;
return false ;
} else {
return true ;
}
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _node_visibility_changed ( Node * p_node ) {
2017-03-05 16:44:50 +01:00
if ( p_node ! = get_scene_node ( ) & & ! p_node - > get_owner ( ) ) {
2014-08-14 15:31:38 +02:00
return ;
}
2017-03-05 16:44:50 +01:00
TreeItem * item = p_node ? _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) : NULL ;
2014-08-14 15:31:38 +02:00
if ( ! item ) {
return ;
}
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 ( ) ;
} 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
}
2017-01-18 21:49:30 +01:00
if ( visible )
2017-12-14 22:34:24 +01:00
item - > set_button ( 0 , idx , get_icon ( " GuiVisibilityVisible " , " EditorIcons " ) ) ;
2017-01-18 21:49:30 +01:00
else
2017-12-14 22:34:24 +01:00
item - > set_button ( 0 , idx , get_icon ( " GuiVisibilityHidden " , " EditorIcons " ) ) ;
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 ) {
2017-11-15 14:41:31 +01:00
if ( tree_dirty )
return ;
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 ) {
2016-03-09 00:00:52 +01:00
2016-06-08 03:08:12 +02:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) )
return ; //speed up exit
2017-03-05 16:44:50 +01:00
if ( p_node - > is_connected ( " script_changed " , this , " _node_script_changed " ) )
p_node - > disconnect ( " script_changed " , this , " _node_script_changed " ) ;
2014-02-10 02:10:30 +01:00
2017-01-03 03:03:46 +01:00
if ( p_node - > is_class ( " Spatial " ) | | p_node - > is_class ( " CanvasItem " ) ) {
2017-03-05 16:44:50 +01:00
if ( p_node - > is_connected ( " visibility_changed " , this , " _node_visibility_changed " ) )
p_node - > disconnect ( " visibility_changed " , this , " _node_visibility_changed " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( p_node = = selected ) {
selected = NULL ;
2014-02-10 02:10:30 +01:00
emit_signal ( " node_selected " ) ;
}
}
2019-05-24 15:27:22 +02:00
void SceneTreeEditor : : _node_renamed ( Node * p_node ) {
emit_signal ( " node_renamed " ) ;
if ( ! tree_dirty ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _update_tree " ) ;
tree_dirty = true ;
}
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : _update_tree ( ) {
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 ( ) ) {
2017-03-05 16:44:50 +01:00
_add_nodes ( get_scene_node ( ) , NULL ) ;
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 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
tree_dirty = false ;
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 ) {
2014-02-10 02:10:30 +01:00
2017-08-07 12:17:31 +02:00
hash = hash_djb2_one_64 ( p_node - > get_instance_id ( ) , hash ) ;
2014-02-10 02:10:30 +01: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
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 + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
_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
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
if ( tree_dirty )
2014-02-10 02:10:30 +01:00
return ; // don't even bother
uint64_t hash = hash_djb2_one_64 ( 0 ) ;
if ( get_scene_node ( ) )
2017-03-05 16:44:50 +01:00
_compute_hash ( get_scene_node ( ) , hash ) ;
2014-02-10 02:10:30 +01:00
//test hash
2017-03-05 16:44:50 +01:00
if ( hash = = last_hash )
2014-02-10 02:10:30 +01:00
return ; // did not change
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 ( ) {
2016-06-08 03:08:12 +02:00
if ( EditorNode : : get_singleton ( ) - > is_exiting ( ) )
return ; //speed up exit
2014-02-10 02:10:30 +01:00
if ( pending_test_update )
return ;
if ( tree_dirty )
return ;
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
}
void SceneTreeEditor : : _selected_changed ( ) {
TreeItem * s = tree - > get_selected ( ) ;
ERR_FAIL_COND ( ! s ) ;
NodePath np = s - > get_metadata ( 0 ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( n = = selected )
2014-02-10 02:10:30 +01:00
return ;
selected = get_node ( np ) ;
blocked + + ;
emit_signal ( " node_selected " ) ;
blocked - - ;
}
2017-11-26 12:49:21 +01:00
void SceneTreeEditor : : _deselect_items ( ) {
// Clear currently elected 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 ) {
2014-02-10 02:10:30 +01:00
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
if ( ! n )
return ;
if ( ! editor_selection )
return ;
if ( p_selected ) {
editor_selection - > add_node ( n ) ;
} else {
editor_selection - > remove_node ( n ) ;
}
2018-08-23 14:15:54 +02:00
emit_signal ( " node_changed " ) ;
2014-02-10 02:10:30 +01:00
}
void SceneTreeEditor : : _notification ( int p_what ) {
2016-03-09 00:00:52 +01:00
2019-03-06 18:33:26 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2016-05-17 23:27:15 +02:00
2019-03-06 18:33:26 +01:00
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 : {
2017-03-05 16:44:50 +01:00
2019-03-06 18:33:26 +01:00
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 : {
2018-02-25 17:04:16 +01:00
2019-03-06 18:33:26 +01:00
_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 ) {
2014-02-10 02:10:30 +01:00
if ( ! p_node )
return NULL ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
NodePath np = p_node - > get_metadata ( 0 ) ;
if ( np = = p_path )
2014-02-10 02:10:30 +01:00
return p_node ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * children = p_node - > get_children ( ) ;
while ( children ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * n = _find ( children , p_path ) ;
2014-02-10 02:10:30 +01:00
if ( n )
return n ;
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
2014-02-10 02:10:30 +01:00
return NULL ;
}
2017-03-05 16:44:50 +01:00
void SceneTreeEditor : : set_selected ( Node * p_node , bool p_emit_selected ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( blocked > 0 ) ;
2014-02-10 02:10:30 +01:00
if ( pending_test_update )
_test_update_tree ( ) ;
if ( tree_dirty )
_update_tree ( ) ;
2017-03-05 16:44:50 +01:00
if ( selected = = p_node )
2014-02-10 02:10:30 +01:00
return ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
TreeItem * item = p_node ? _find ( tree - > get_root ( ) , p_node - > get_path ( ) ) : NULL ;
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 {
if ( ! p_node )
2017-03-05 16:44:50 +01:00
selected = NULL ;
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 ) {
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 ;
}
2017-03-05 16:44:50 +01:00
String new_name = which - > get_text ( 0 ) ;
2018-04-26 18:42:15 +02:00
if ( ! Node : : _validate_node_name ( new_name ) ) {
2014-06-11 08:45:26 +02:00
2018-04-26 18:42:15 +02:00
error - > set_text ( TTR ( " Invalid node name, the following characters are not allowed: " ) + " \n " + Node : : invalid_character ) ;
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
}
2017-03-05 16:44:50 +01:00
if ( new_name = = n - > get_name ( ) )
2016-01-26 17:25:04 +01:00
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 ) {
2014-02-10 02:10:30 +01:00
if ( tree_dirty )
_update_tree ( ) ;
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 ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Set < Node * > s ;
2014-02-10 02:10:30 +01:00
if ( p_marked )
s . insert ( p_marked ) ;
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 ) {
2016-05-16 17:23:40 +02:00
2017-03-05 16:44:50 +01:00
filter = p_filter ;
2016-05-16 17:23:40 +02:00
_update_tree ( ) ;
}
String SceneTreeEditor : : get_filter ( ) const {
return filter ;
}
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 ) ;
2016-01-23 23:51:51 +01:00
if ( ! has_node ( np ) )
return ;
2017-03-05 16:44:50 +01:00
Node * n = get_node ( np ) ;
2014-02-10 02:10:30 +01:00
if ( ! n )
return ;
if ( editor_selection - > is_selected ( n ) )
item - > select ( 0 ) ;
else
item - > deselect ( 0 ) ;
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 ( ) {
if ( ! editor_selection )
return ;
2017-03-05 16:44:50 +01:00
TreeItem * root = tree - > get_root ( ) ;
2014-02-10 02:10:30 +01:00
if ( ! root )
return ;
_update_selection ( root ) ;
}
void SceneTreeEditor : : _cell_collapsed ( Object * p_obj ) {
if ( updating_tree )
return ;
if ( ! can_rename )
return ;
2017-08-24 22:58:51 +02:00
TreeItem * ti = Object : : cast_to < TreeItem > ( p_obj ) ;
2014-02-10 02:10:30 +01:00
if ( ! ti )
return ;
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 ) {
2016-05-11 16:46:08 +02:00
if ( ! can_rename )
return Variant ( ) ; //not editable tree
2017-03-05 16:44:50 +01:00
Vector < Node * > selected ;
2016-05-11 16:46:08 +02:00
Vector < Ref < Texture > > icons ;
2017-03-05 16:44:50 +01:00
TreeItem * next = tree - > get_next_selected ( NULL ) ;
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 ) {
2017-12-14 17:49:02 +01:00
// Only allow selection if not part of an instanced scene.
if ( ! n - > get_owner ( ) | | n - > get_owner ( ) = = get_scene_node ( ) | | n - > get_owner ( ) - > get_filename ( ) = = String ( ) ) {
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
}
if ( selected . empty ( ) )
return Variant ( ) ;
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 + + ) {
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
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 ] ) ;
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 {
2016-05-11 16:46:08 +02:00
if ( ! can_rename )
return false ; //not editable tree
2017-03-05 16:44:50 +01:00
if ( filter ! = String ( ) )
2016-05-16 17:23:40 +02:00
return false ; //can't rearrange tree with filter turned on
2017-03-05 16:44:50 +01:00
Dictionary d = p_data ;
2016-05-12 01:57:52 +02:00
if ( ! d . has ( " type " ) )
2016-05-11 16:46:08 +02:00
return false ;
2017-09-10 15:37:49 +02:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2016-07-18 20:00:14 +02:00
if ( ! item )
return false ;
2017-09-10 15:37:49 +02:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2017-03-05 16:44:50 +01:00
if ( section < - 1 | | ( section = = - 1 & & ! item - > get_parent ( ) ) )
2016-07-18 20:00:14 +02:00
return false ;
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 " ] ;
2017-03-05 16:44:50 +01:00
if ( files . size ( ) = = 0 )
2016-05-12 01:57:52 +02:00
return false ; //weird
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
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 ) ;
2017-03-05 16:44:50 +01:00
if ( ftype ! = " PackedScene " )
2016-05-12 01:57:52 +02:00
return false ;
}
2017-03-05 16:44:50 +01:00
tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN | Tree : : DROP_MODE_ON_ITEM ) ; //so it works..
2016-05-12 01:57:52 +02:00
return true ;
}
2017-03-05 16:44:50 +01:00
if ( String ( d [ " type " ] ) = = " nodes " ) {
2016-05-12 01:57:52 +02:00
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 ) {
2016-05-11 16:46:08 +02:00
2017-03-05 16:44:50 +01:00
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) )
2016-05-11 16:46:08 +02:00
return ;
2017-09-10 15:37:49 +02:00
TreeItem * item = tree - > get_item_at_position ( p_point ) ;
2016-05-11 16:46:08 +02:00
if ( ! item )
return ;
2017-09-10 15:37:49 +02:00
int section = tree - > get_drop_section_at_position ( p_point ) ;
2017-03-05 16:44:50 +01:00
if ( section < - 1 )
2016-05-11 16:46:08 +02:00
return ;
NodePath np = item - > 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 )
return ;
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-05-12 01:57:52 +02:00
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
}
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 ) {
2016-05-16 04:41:48 +02:00
2017-03-05 16:44:50 +01:00
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 ( ) ;
}
2014-02-10 02:10:30 +01:00
void SceneTreeEditor : : _bind_methods ( ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _tree_changed " , & SceneTreeEditor : : _tree_changed ) ;
ClassDB : : bind_method ( " _update_tree " , & SceneTreeEditor : : _update_tree ) ;
ClassDB : : bind_method ( " _node_removed " , & SceneTreeEditor : : _node_removed ) ;
2019-05-24 15:27:22 +02:00
ClassDB : : bind_method ( " _node_renamed " , & SceneTreeEditor : : _node_renamed ) ;
2017-03-05 16:44:50 +01: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 ) {
2014-02-10 02:10:30 +01:00
2019-04-12 04:21:48 +02:00
connect_to_script_mode = false ;
2017-03-05 16:44:50 +01:00
undo_redo = NULL ;
tree_dirty = true ;
selected = NULL ;
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 ;
editor_selection = NULL ;
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 ) ;
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
2017-03-05 16:44:50 +01:00
tree - > connect ( " cell_selected " , this , " _selected_changed " ) ;
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 " ) ;
2017-01-14 12:26:56 +01: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 ) ;
2017-03-05 16:44:50 +01:00
update_timer - > connect ( " timeout " , this , " _update_tree " ) ;
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-03-09 00:00:52 +01:00
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 " ) ;
} break ;
case NOTIFICATION_EXIT_TREE : {
disconnect ( " confirmed " , this , " _select " ) ;
} break ;
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( is_visible_in_tree ( ) )
tree - > update_tree ( ) ;
} 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 ( ) ;
}
}
void SceneTreeDialog : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _select " , & SceneTreeDialog : : _select ) ;
ClassDB : : bind_method ( " _cancel " , & SceneTreeDialog : : _cancel ) ;
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 " ) ) ;
2014-02-10 02:10:30 +01:00
2018-11-02 19:05:38 +01:00
tree = memnew ( SceneTreeEditor ( false , false , true ) ) ;
2014-02-10 02:10:30 +01:00
add_child ( tree ) ;
2017-03-05 16:44:50 +01:00
tree - > get_scene_tree ( ) - > connect ( " item_activated " , this , " _select " ) ;
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
}