2018-08-29 22:38:13 +02:00
/**************************************************************************/
/* animation_blend_tree_editor_plugin.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-06-19 03:10:48 +02:00
# include "animation_blend_tree_editor_plugin.h"
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2018-06-19 03:10:48 +02:00
# include "core/io/resource_loader.h"
2018-09-11 18:13:45 +02:00
# include "core/os/keyboard.h"
2018-08-20 18:38:18 +02:00
# include "editor/editor_inspector.h"
2022-02-12 02:46:22 +01:00
# include "editor/editor_node.h"
2024-08-31 08:57:34 +02:00
# include "editor/editor_properties.h"
2022-07-31 20:14:15 +02:00
# include "editor/editor_settings.h"
2023-08-13 02:33:39 +02:00
# include "editor/editor_string_names.h"
2022-03-25 18:06:46 +01:00
# include "editor/editor_undo_redo_manager.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2024-01-15 13:14:55 +01:00
# include "editor/themes/editor_scale.h"
2024-01-05 18:21:38 +01:00
# include "scene/3d/skeleton_3d.h"
2018-06-19 03:10:48 +02:00
# include "scene/animation/animation_player.h"
2022-11-19 12:45:49 +01:00
# include "scene/gui/check_box.h"
2018-06-19 03:10:48 +02:00
# include "scene/gui/menu_button.h"
2024-08-31 08:57:34 +02:00
# include "scene/gui/option_button.h"
2018-06-19 03:10:48 +02:00
# include "scene/gui/panel.h"
2019-12-24 08:17:23 +01:00
# include "scene/gui/progress_bar.h"
2022-11-19 12:45:49 +01:00
# include "scene/gui/separator.h"
2022-01-19 19:59:12 +01:00
# include "scene/gui/view_panner.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2023-07-14 22:35:39 +02:00
# include "scene/resources/style_box_flat.h"
2018-06-19 03:10:48 +02:00
void AnimationNodeBlendTreeEditor : : add_custom_type ( const String & p_name , const Ref < Script > & p_script ) {
for ( int i = 0 ; i < add_options . size ( ) ; i + + ) {
ERR_FAIL_COND ( add_options [ i ] . script = = p_script ) ;
}
AddOption ao ;
ao . name = p_name ;
ao . script = p_script ;
add_options . push_back ( ao ) ;
_update_options_menu ( ) ;
}
void AnimationNodeBlendTreeEditor : : remove_custom_type ( const Ref < Script > & p_script ) {
for ( int i = 0 ; i < add_options . size ( ) ; i + + ) {
if ( add_options [ i ] . script = = p_script ) {
2021-07-04 00:17:03 +02:00
add_options . remove_at ( i ) ;
2018-06-19 03:10:48 +02:00
return ;
}
}
_update_options_menu ( ) ;
}
2021-09-18 17:08:22 +02:00
void AnimationNodeBlendTreeEditor : : _update_options_menu ( bool p_has_input_ports ) {
2018-06-19 03:10:48 +02:00
add_node - > get_popup ( ) - > clear ( ) ;
2021-11-20 09:04:57 +01:00
add_node - > get_popup ( ) - > reset_size ( ) ;
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < add_options . size ( ) ; i + + ) {
2021-09-18 17:08:22 +02:00
if ( p_has_input_ports & & add_options [ i ] . input_port_count = = 0 ) {
continue ;
}
2018-08-20 18:38:18 +02:00
add_node - > get_popup ( ) - > add_item ( add_options [ i ] . name , i ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
Ref < AnimationNode > clipb = EditorSettings : : get_singleton ( ) - > get_resource_clipboard ( ) ;
if ( clipb . is_valid ( ) ) {
add_node - > get_popup ( ) - > add_separator ( ) ;
add_node - > get_popup ( ) - > add_item ( TTR ( " Paste " ) , MENU_PASTE ) ;
}
add_node - > get_popup ( ) - > add_separator ( ) ;
2019-01-07 16:57:52 +01:00
add_node - > get_popup ( ) - > add_item ( TTR ( " Load... " ) , MENU_LOAD_FILE ) ;
2021-08-31 17:43:35 +02:00
use_position_from_popup_menu = false ;
2018-06-19 03:10:48 +02:00
}
Size2 AnimationNodeBlendTreeEditor : : get_minimum_size ( ) const {
return Size2 ( 10 , 200 ) ;
}
2019-01-18 17:01:24 +01:00
void AnimationNodeBlendTreeEditor : : _property_changed ( const StringName & p_property , const Variant & p_value , const String & p_field , bool p_changing ) {
2022-11-20 15:53:17 +01:00
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
2022-12-12 19:00:11 +01:00
if ( ! tree ) {
return ;
}
2018-08-20 18:38:18 +02:00
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2023-09-12 12:15:44 +02:00
undo_redo - > create_action ( vformat ( TTR ( " Parameter Changed: %s " ) , p_property ) , UndoRedo : : MERGE_ENDS ) ;
2018-08-20 18:38:18 +02:00
undo_redo - > add_do_property ( tree , p_property , p_value ) ;
undo_redo - > add_undo_property ( tree , p_property , tree - > get ( p_property ) ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-08-20 18:38:18 +02:00
undo_redo - > commit_action ( ) ;
updating = false ;
}
2022-09-01 16:00:55 +02:00
void AnimationNodeBlendTreeEditor : : update_graph ( ) {
2022-01-17 07:35:09 +01:00
if ( updating | | blend_tree . is_null ( ) ) {
2018-06-19 03:10:48 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
2022-12-12 19:00:11 +01:00
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
return ;
}
2018-08-20 18:38:18 +02:00
visible_properties . clear ( ) ;
2023-07-10 17:26:02 +02:00
graph - > set_scroll_offset ( blend_tree - > get_graph_offset ( ) * EDSCALE ) ;
2018-06-19 03:10:48 +02:00
graph - > clear_connections ( ) ;
//erase all nodes
for ( int i = 0 ; i < graph - > get_child_count ( ) ; i + + ) {
if ( Object : : cast_to < GraphNode > ( graph - > get_child ( i ) ) ) {
memdelete ( graph - > get_child ( i ) ) ;
i - - ;
}
}
animations . clear ( ) ;
List < StringName > nodes ;
blend_tree - > get_node_list ( & nodes ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & E : nodes ) {
2018-06-19 03:10:48 +02:00
GraphNode * node = memnew ( GraphNode ) ;
graph - > add_child ( node ) ;
2022-05-04 07:31:53 +02:00
node - > set_draggable ( ! read_only ) ;
2021-07-16 05:45:57 +02:00
Ref < AnimationNode > agnode = blend_tree - > get_node ( E ) ;
2021-08-19 16:01:08 +02:00
ERR_CONTINUE ( ! agnode . is_valid ( ) ) ;
2018-06-19 03:10:48 +02:00
2021-07-16 05:45:57 +02:00
node - > set_position_offset ( blend_tree - > get_node_position ( E ) * EDSCALE ) ;
2018-06-19 03:10:48 +02:00
node - > set_title ( agnode - > get_caption ( ) ) ;
2021-07-16 05:45:57 +02:00
node - > set_name ( E ) ;
2018-06-19 03:10:48 +02:00
int base = 0 ;
2021-07-16 05:45:57 +02:00
if ( String ( E ) ! = " output " ) {
2018-06-19 03:10:48 +02:00
LineEdit * name = memnew ( LineEdit ) ;
2021-07-16 05:45:57 +02:00
name - > set_text ( E ) ;
2022-05-04 07:31:53 +02:00
name - > set_editable ( ! read_only ) ;
2021-03-28 20:31:25 +02:00
name - > set_expand_to_text_length_enabled ( true ) ;
2018-06-19 03:10:48 +02:00
node - > add_child ( name ) ;
2024-05-14 15:57:29 +02:00
node - > set_slot ( 0 , false , 0 , Color ( ) , true , read_only ? - 1 : 0 , get_theme_color ( SceneStringName ( font_color ) , SNAME ( " Label " ) ) ) ;
2022-07-28 22:56:41 +02:00
name - > connect ( " text_submitted " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_renamed ) . bind ( agnode ) , CONNECT_DEFERRED ) ;
2024-05-13 16:56:03 +02:00
name - > connect ( SceneStringName ( focus_exited ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_renamed_focus_out ) . bind ( agnode ) , CONNECT_DEFERRED ) ;
2024-05-14 11:42:00 +02:00
name - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_rename_lineedit_changed ) , CONNECT_DEFERRED ) ;
2018-06-19 03:10:48 +02:00
base = 1 ;
2024-02-07 02:37:26 +01:00
agnode - > set_deletable ( true ) ;
2023-10-17 17:04:19 +02:00
if ( ! read_only ) {
Button * delete_button = memnew ( Button ) ;
delete_button - > set_flat ( true ) ;
delete_button - > set_focus_mode ( FOCUS_NONE ) ;
delete_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Close " ) ) ) ;
2024-05-14 09:40:21 +02:00
delete_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _delete_node_request ) . bind ( E ) , CONNECT_DEFERRED ) ;
2023-10-17 17:04:19 +02:00
node - > get_titlebar_hbox ( ) - > add_child ( delete_button ) ;
}
2018-06-19 03:10:48 +02:00
}
for ( int i = 0 ; i < agnode - > get_input_count ( ) ; i + + ) {
Label * in_name = memnew ( Label ) ;
node - > add_child ( in_name ) ;
in_name - > set_text ( agnode - > get_input_name ( i ) ) ;
2024-05-14 15:57:29 +02:00
node - > set_slot ( base + i , true , read_only ? - 1 : 0 , get_theme_color ( SceneStringName ( font_color ) , SNAME ( " Label " ) ) , false , 0 , Color ( ) ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
List < PropertyInfo > pinfo ;
agnode - > get_parameter_list ( & pinfo ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & F : pinfo ) {
2021-07-16 05:45:57 +02:00
if ( ! ( F . usage & PROPERTY_USAGE_EDITOR ) ) {
2018-08-20 18:38:18 +02:00
continue ;
}
2021-07-16 05:45:57 +02:00
String base_path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + String ( E ) + " / " + F . name ;
2022-12-12 19:00:11 +01:00
EditorProperty * prop = EditorInspector : : instantiate_property_editor ( tree , F . type , base_path , F . hint , F . hint_string , F . usage ) ;
2018-08-20 18:38:18 +02:00
if ( prop ) {
2023-01-12 13:51:03 +01:00
prop - > set_read_only ( read_only | | ( F . usage & PROPERTY_USAGE_READ_ONLY ) ) ;
2022-12-12 19:00:11 +01:00
prop - > set_object_and_property ( tree , base_path ) ;
2018-08-20 18:38:18 +02:00
prop - > update_property ( ) ;
prop - > set_name_split_ratio ( 0 ) ;
2020-02-21 18:28:45 +01:00
prop - > connect ( " property_changed " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _property_changed ) ) ;
2018-08-20 18:38:18 +02:00
node - > add_child ( prop ) ;
visible_properties . push_back ( prop ) ;
}
}
2022-07-28 22:56:41 +02:00
node - > connect ( " dragged " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_dragged ) . bind ( E ) ) ;
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
if ( AnimationTreeEditor : : get_singleton ( ) - > can_edit ( agnode ) ) {
2018-06-19 03:10:48 +02:00
node - > add_child ( memnew ( HSeparator ) ) ;
Button * open_in_editor = memnew ( Button ) ;
open_in_editor - > set_text ( TTR ( " Open Editor " ) ) ;
2023-08-13 02:33:39 +02:00
open_in_editor - > set_icon ( get_editor_theme_icon ( SNAME ( " Edit " ) ) ) ;
2018-06-19 03:10:48 +02:00
node - > add_child ( open_in_editor ) ;
2024-05-14 09:40:21 +02:00
open_in_editor - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _open_in_editor ) . bind ( E ) , CONNECT_DEFERRED ) ;
2018-06-19 03:10:48 +02:00
open_in_editor - > set_h_size_flags ( SIZE_SHRINK_CENTER ) ;
}
if ( agnode - > has_filter ( ) ) {
node - > add_child ( memnew ( HSeparator ) ) ;
2022-05-04 07:31:53 +02:00
Button * inspect_filters = memnew ( Button ) ;
if ( read_only ) {
inspect_filters - > set_text ( TTR ( " Inspect Filters " ) ) ;
} else {
inspect_filters - > set_text ( TTR ( " Edit Filters " ) ) ;
}
2023-08-13 02:33:39 +02:00
inspect_filters - > set_icon ( get_editor_theme_icon ( SNAME ( " AnimationFilter " ) ) ) ;
2022-05-04 07:31:53 +02:00
node - > add_child ( inspect_filters ) ;
2024-05-14 09:40:21 +02:00
inspect_filters - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _inspect_filters ) . bind ( E ) , CONNECT_DEFERRED ) ;
2022-05-04 07:31:53 +02:00
inspect_filters - > set_h_size_flags ( SIZE_SHRINK_CENTER ) ;
2018-06-19 03:10:48 +02:00
}
Ref < AnimationNodeAnimation > anim = agnode ;
if ( anim . is_valid ( ) ) {
MenuButton * mb = memnew ( MenuButton ) ;
mb - > set_text ( anim - > get_animation ( ) ) ;
2023-08-13 02:33:39 +02:00
mb - > set_icon ( get_editor_theme_icon ( SNAME ( " Animation " ) ) ) ;
2024-01-23 22:29:45 +01:00
mb - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2022-05-04 07:31:53 +02:00
mb - > set_disabled ( read_only ) ;
2018-06-19 03:10:48 +02:00
Array options ;
node - > add_child ( memnew ( HSeparator ) ) ;
node - > add_child ( mb ) ;
ProgressBar * pb = memnew ( ProgressBar ) ;
2023-07-20 17:34:06 +02:00
List < StringName > anims ;
tree - > get_animation_list ( & anims ) ;
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
for ( const StringName & F : anims ) {
mb - > get_popup ( ) - > add_item ( F ) ;
options . push_back ( F ) ;
}
2022-08-29 15:20:48 +02:00
pb - > set_show_percentage ( false ) ;
2019-02-27 14:56:49 +01:00
pb - > set_custom_minimum_size ( Vector2 ( 0 , 14 ) * EDSCALE ) ;
2021-07-16 05:45:57 +02:00
animations [ E ] = pb ;
2018-06-19 03:10:48 +02:00
node - > add_child ( pb ) ;
2022-07-28 22:56:41 +02:00
mb - > get_popup ( ) - > connect ( " index_pressed " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _anim_selected ) . bind ( options , E ) , CONNECT_DEFERRED ) ;
2018-06-19 03:10:48 +02:00
}
2023-09-23 21:22:33 +02:00
// TODO: Avoid using strings, expose a method on GraphNode instead.
2024-05-14 15:50:53 +02:00
Ref < StyleBoxFlat > sb = node - > get_theme_stylebox ( SceneStringName ( panel ) ) ;
2019-03-23 01:57:28 +01:00
Color c = sb - > get_border_color ( ) ;
Color mono_color = ( ( c . r + c . g + c . b ) / 3 ) < 0.7 ? Color ( 1.0 , 1.0 , 1.0 ) : Color ( 0.0 , 0.0 , 0.0 ) ;
mono_color . a = 0.85 ;
c = mono_color ;
2022-02-08 10:14:58 +01:00
node - > add_theme_color_override ( " title_color " , c ) ;
2019-03-23 01:57:28 +01:00
c . a = 0.7 ;
2022-02-08 10:14:58 +01:00
node - > add_theme_color_override ( " close_color " , c ) ;
node - > add_theme_color_override ( " resizer_color " , c ) ;
2018-06-19 03:10:48 +02:00
}
2022-09-29 11:53:28 +02:00
List < AnimationNodeBlendTree : : NodeConnection > node_connections ;
blend_tree - > get_node_connections ( & node_connections ) ;
2018-06-19 03:10:48 +02:00
2022-09-29 11:53:28 +02:00
for ( const AnimationNodeBlendTree : : NodeConnection & E : node_connections ) {
2021-07-16 05:45:57 +02:00
StringName from = E . output_node ;
StringName to = E . input_node ;
int to_idx = E . input_index ;
2018-06-19 03:10:48 +02:00
graph - > connect_node ( from , 0 , to , to_idx ) ;
}
2021-01-25 15:37:05 +01:00
2022-10-18 16:43:37 +02:00
float graph_minimap_opacity = EDITOR_GET ( " editors/visual_editors/minimap_opacity " ) ;
2021-01-25 15:37:05 +01:00
graph - > set_minimap_opacity ( graph_minimap_opacity ) ;
2022-10-18 16:43:37 +02:00
float graph_lines_curvature = EDITOR_GET ( " editors/visual_editors/lines_curvature " ) ;
2022-05-30 15:38:13 +02:00
graph - > set_connection_lines_curvature ( graph_lines_curvature ) ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
void AnimationNodeBlendTreeEditor : : _file_opened ( const String & p_file ) {
file_loaded = ResourceLoader : : load ( p_file ) ;
if ( file_loaded . is_valid ( ) ) {
_add_node ( MENU_LOAD_FILE_CONFIRM ) ;
2020-10-07 04:44:09 +02:00
} else {
2022-08-07 23:32:59 +02:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " This type of node can't be used. Only animation nodes are allowed. " ) ) ;
2018-08-20 18:38:18 +02:00
}
}
void AnimationNodeBlendTreeEditor : : _add_node ( int p_idx ) {
2018-06-19 03:10:48 +02:00
Ref < AnimationNode > anode ;
2018-08-20 18:38:18 +02:00
String base_name ;
if ( p_idx = = MENU_LOAD_FILE ) {
open_file - > clear_filters ( ) ;
2022-09-29 11:53:28 +02:00
List < String > ext_filters ;
ResourceLoader : : get_recognized_extensions_for_type ( " AnimationNode " , & ext_filters ) ;
for ( const String & E : ext_filters ) {
2021-07-16 05:45:57 +02:00
open_file - > add_filter ( " *. " + E ) ;
2018-08-20 18:38:18 +02:00
}
2020-07-11 18:45:19 +02:00
open_file - > popup_file_dialog ( ) ;
2018-08-20 18:38:18 +02:00
return ;
} else if ( p_idx = = MENU_LOAD_FILE_CONFIRM ) {
anode = file_loaded ;
file_loaded . unref ( ) ;
base_name = anode - > get_class ( ) ;
} else if ( p_idx = = MENU_PASTE ) {
anode = EditorSettings : : get_singleton ( ) - > get_resource_clipboard ( ) ;
ERR_FAIL_COND ( ! anode . is_valid ( ) ) ;
base_name = anode - > get_class ( ) ;
2021-12-09 10:42:46 +01:00
} else if ( ! add_options [ p_idx ] . type . is_empty ( ) ) {
2021-06-18 00:03:09 +02:00
AnimationNode * an = Object : : cast_to < AnimationNode > ( ClassDB : : instantiate ( add_options [ p_idx ] . type ) ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( an ) ;
2018-06-19 03:10:48 +02:00
anode = Ref < AnimationNode > ( an ) ;
2018-08-20 18:38:18 +02:00
base_name = add_options [ p_idx ] . name ;
2018-06-19 03:10:48 +02:00
} else {
ERR_FAIL_COND ( add_options [ p_idx ] . script . is_null ( ) ) ;
2022-02-06 14:12:19 +01:00
StringName base_type = add_options [ p_idx ] . script - > get_instance_base_type ( ) ;
2021-06-18 00:03:09 +02:00
AnimationNode * an = Object : : cast_to < AnimationNode > ( ClassDB : : instantiate ( base_type ) ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( an ) ;
2018-06-19 03:10:48 +02:00
anode = Ref < AnimationNode > ( an ) ;
2020-02-13 20:03:10 +01:00
anode - > set_script ( add_options [ p_idx ] . script ) ;
2018-08-20 18:38:18 +02:00
base_name = add_options [ p_idx ] . name ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
Ref < AnimationNodeOutput > out = anode ;
if ( out . is_valid ( ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Output node can't be added to the blend tree. " ) ) ;
return ;
}
2019-04-08 04:11:53 +02:00
2021-09-18 17:08:22 +02:00
if ( ! from_node . is_empty ( ) & & anode - > get_input_count ( ) = = 0 ) {
from_node = " " ;
return ;
}
2023-07-10 17:26:02 +02:00
Point2 instance_pos = graph - > get_scroll_offset ( ) ;
2021-08-31 17:43:35 +02:00
if ( use_position_from_popup_menu ) {
instance_pos + = position_from_popup_menu ;
2019-04-08 04:11:53 +02:00
} else {
instance_pos + = graph - > get_size ( ) * 0.5 ;
}
instance_pos / = graph - > get_zoom ( ) ;
2018-06-19 03:10:48 +02:00
int base = 1 ;
String name = base_name ;
while ( blend_tree - > has_node ( name ) ) {
base + + ;
name = base_name + " " + itos ( base ) ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Add Node to BlendTree " ) ) ;
2018-08-20 18:38:18 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " add_node " , name , anode , instance_pos / EDSCALE ) ;
2018-06-21 23:08:11 +02:00
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " remove_node " , name ) ;
2021-09-18 17:08:22 +02:00
if ( ! from_node . is_empty ( ) ) {
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " connect_node " , name , 0 , from_node ) ;
from_node = " " ;
}
if ( ! to_node . is_empty ( ) & & to_slot ! = - 1 ) {
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " connect_node " , to_node , to_slot , name ) ;
to_node = " " ;
to_slot = - 1 ;
}
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
}
2022-12-05 19:03:38 +01:00
void AnimationNodeBlendTreeEditor : : _popup ( bool p_has_input_ports , const Vector2 & p_node_position ) {
2021-09-18 17:08:22 +02:00
_update_options_menu ( p_has_input_ports ) ;
2021-08-31 17:43:35 +02:00
use_position_from_popup_menu = true ;
position_from_popup_menu = p_node_position ;
2022-12-05 19:03:38 +01:00
add_node - > get_popup ( ) - > set_position ( graph - > get_screen_position ( ) + graph - > get_local_mouse_position ( ) ) ;
2021-08-31 17:43:35 +02:00
add_node - > get_popup ( ) - > reset_size ( ) ;
2021-09-18 17:08:22 +02:00
add_node - > get_popup ( ) - > popup ( ) ;
}
void AnimationNodeBlendTreeEditor : : _popup_request ( const Vector2 & p_position ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2022-12-05 19:03:38 +01:00
_popup ( false , p_position ) ;
2021-09-18 17:08:22 +02:00
}
void AnimationNodeBlendTreeEditor : : _connection_to_empty ( const String & p_from , int p_from_slot , const Vector2 & p_release_position ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2021-09-18 17:08:22 +02:00
Ref < AnimationNode > node = blend_tree - > get_node ( p_from ) ;
if ( node . is_valid ( ) ) {
from_node = p_from ;
2022-12-05 19:03:38 +01:00
_popup ( true , p_release_position ) ;
2021-09-18 17:08:22 +02:00
}
}
void AnimationNodeBlendTreeEditor : : _connection_from_empty ( const String & p_to , int p_to_slot , const Vector2 & p_release_position ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2021-09-18 17:08:22 +02:00
Ref < AnimationNode > node = blend_tree - > get_node ( p_to ) ;
if ( node . is_valid ( ) ) {
to_node = p_to ;
to_slot = p_to_slot ;
2022-12-05 19:03:38 +01:00
_popup ( false , p_release_position ) ;
2021-09-18 17:08:22 +02:00
}
}
2023-01-10 09:05:09 +01:00
void AnimationNodeBlendTreeEditor : : _popup_hide ( ) {
to_node = " " ;
to_slot = - 1 ;
}
2018-08-20 18:38:18 +02:00
void AnimationNodeBlendTreeEditor : : _node_dragged ( const Vector2 & p_from , const Vector2 & p_to , const StringName & p_which ) {
2018-06-19 03:10:48 +02:00
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Node Moved " ) ) ;
2018-08-20 18:38:18 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " set_node_position " , p_which , p_to / EDSCALE ) ;
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " set_node_position " , p_which , p_from / EDSCALE ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
updating = false ;
}
void AnimationNodeBlendTreeEditor : : _connection_request ( const String & p_from , int p_from_index , const String & p_to , int p_to_index ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2018-06-19 03:10:48 +02:00
AnimationNodeBlendTree : : ConnectionError err = blend_tree - > can_connect_node ( p_to , p_to_index , p_from ) ;
2023-10-18 04:19:02 +02:00
if ( err = = AnimationNodeBlendTree : : CONNECTION_ERROR_CONNECTION_EXISTS ) {
blend_tree - > disconnect_node ( p_to , p_to_index ) ;
err = blend_tree - > can_connect_node ( p_to , p_to_index , p_from ) ;
}
2018-06-19 03:10:48 +02:00
if ( err ! = AnimationNodeBlendTree : : CONNECTION_OK ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Unable to connect, port may be in use or connection may be invalid. " ) ) ;
return ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Nodes Connected " ) ) ;
2018-06-21 23:08:11 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " connect_node " , p_to , p_to_index , p_from ) ;
2018-12-18 18:23:39 +01:00
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " disconnect_node " , p_to , p_to_index ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
}
void AnimationNodeBlendTreeEditor : : _disconnection_request ( const String & p_from , int p_from_index , const String & p_to , int p_to_index ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2018-06-19 03:10:48 +02:00
graph - > disconnect_node ( p_from , p_from_index , p_to , p_to_index ) ;
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Nodes Disconnected " ) ) ;
2018-06-21 23:08:11 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " disconnect_node " , p_to , p_to_index ) ;
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " connect_node " , p_to , p_to_index , p_from ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
updating = false ;
}
2024-02-15 17:25:58 +01:00
void AnimationNodeBlendTreeEditor : : _anim_selected ( int p_index , const Array & p_options , const String & p_node ) {
2018-06-19 03:10:48 +02:00
String option = p_options [ p_index ] ;
Ref < AnimationNodeAnimation > anim = blend_tree - > get_node ( p_node ) ;
ERR_FAIL_COND ( ! anim . is_valid ( ) ) ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Set Animation " ) ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > add_do_method ( anim . ptr ( ) , " set_animation " , option ) ;
undo_redo - > add_undo_method ( anim . ptr ( ) , " set_animation " , anim - > get_animation ( ) ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
}
2023-09-26 16:41:39 +02:00
void AnimationNodeBlendTreeEditor : : _delete_node_request ( const String & p_which ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Delete Node " ) ) ;
2018-06-21 23:08:11 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " remove_node " , p_which ) ;
2018-12-18 00:03:25 +01:00
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " add_node " , p_which , blend_tree - > get_node ( p_which ) , blend_tree . ptr ( ) - > get_node_position ( p_which ) ) ;
2018-06-19 03:10:48 +02:00
List < AnimationNodeBlendTree : : NodeConnection > conns ;
blend_tree - > get_node_connections ( & conns ) ;
2021-07-24 15:46:25 +02:00
for ( const AnimationNodeBlendTree : : NodeConnection & E : conns ) {
2021-07-16 05:45:57 +02:00
if ( E . output_node = = p_which | | E . input_node = = p_which ) {
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " connect_node " , E . input_node , E . input_index , E . output_node ) ;
2018-06-19 03:10:48 +02:00
}
}
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
}
2023-09-26 16:41:39 +02:00
void AnimationNodeBlendTreeEditor : : _delete_nodes_request ( const TypedArray < StringName > & p_nodes ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2019-04-08 04:11:53 +02:00
List < StringName > to_erase ;
2022-05-17 12:13:35 +02:00
if ( p_nodes . is_empty ( ) ) {
for ( int i = 0 ; i < graph - > get_child_count ( ) ; i + + ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( graph - > get_child ( i ) ) ;
2023-08-09 18:31:15 +02:00
if ( gn & & gn - > is_selected ( ) ) {
Ref < AnimationNode > anode = blend_tree - > get_node ( gn - > get_name ( ) ) ;
2024-02-07 02:37:26 +01:00
if ( anode - > is_deletable ( ) ) {
2022-05-17 12:13:35 +02:00
to_erase . push_back ( gn - > get_name ( ) ) ;
}
2019-04-08 04:11:53 +02:00
}
}
2022-05-17 12:13:35 +02:00
} else {
for ( int i = 0 ; i < p_nodes . size ( ) ; i + + ) {
2023-08-09 18:31:15 +02:00
Ref < AnimationNode > anode = blend_tree - > get_node ( p_nodes [ i ] ) ;
2024-02-07 02:37:26 +01:00
if ( anode - > is_deletable ( ) ) {
2023-08-09 18:31:15 +02:00
to_erase . push_back ( p_nodes [ i ] ) ;
}
2022-05-17 12:13:35 +02:00
}
2019-04-08 04:11:53 +02:00
}
2020-12-15 13:04:21 +01:00
if ( to_erase . is_empty ( ) ) {
2019-04-08 04:11:53 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-04-08 04:11:53 +02:00
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-04-08 04:11:53 +02:00
undo_redo - > create_action ( TTR ( " Delete Node(s) " ) ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & F : to_erase ) {
2023-09-26 16:41:39 +02:00
_delete_node_request ( F ) ;
2019-04-08 04:11:53 +02:00
}
undo_redo - > commit_action ( ) ;
}
2018-06-19 03:10:48 +02:00
void AnimationNodeBlendTreeEditor : : _node_selected ( Object * p_node ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2018-06-19 03:10:48 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( p_node ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( gn ) ;
2018-06-19 03:10:48 +02:00
String name = gn - > get_name ( ) ;
Ref < AnimationNode > anode = blend_tree - > get_node ( name ) ;
ERR_FAIL_COND ( ! anode . is_valid ( ) ) ;
EditorNode : : get_singleton ( ) - > push_item ( anode . ptr ( ) , " " , true ) ;
}
void AnimationNodeBlendTreeEditor : : _open_in_editor ( const String & p_which ) {
Ref < AnimationNode > an = blend_tree - > get_node ( p_which ) ;
2019-06-11 14:49:34 +02:00
ERR_FAIL_COND ( ! an . is_valid ( ) ) ;
2018-08-20 18:38:18 +02:00
AnimationTreeEditor : : get_singleton ( ) - > enter_editor ( p_which ) ;
2018-06-19 03:10:48 +02:00
}
void AnimationNodeBlendTreeEditor : : _filter_toggled ( ) {
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Toggle Filter On/Off " ) ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > add_do_method ( _filter_edit . ptr ( ) , " set_filter_enabled " , filter_enabled - > is_pressed ( ) ) ;
undo_redo - > add_undo_method ( _filter_edit . ptr ( ) , " set_filter_enabled " , _filter_edit - > is_filter_enabled ( ) ) ;
undo_redo - > add_do_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > add_undo_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
}
void AnimationNodeBlendTreeEditor : : _filter_edited ( ) {
TreeItem * edited = filters - > get_edited ( ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( edited ) ;
2018-06-19 03:10:48 +02:00
NodePath edited_path = edited - > get_metadata ( 0 ) ;
bool filtered = edited - > is_checked ( 0 ) ;
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Change Filter " ) ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > add_do_method ( _filter_edit . ptr ( ) , " set_filter_path " , edited_path , filtered ) ;
undo_redo - > add_undo_method ( _filter_edit . ptr ( ) , " set_filter_path " , edited_path , _filter_edit - > is_path_filtered ( edited_path ) ) ;
undo_redo - > add_do_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > add_undo_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
}
2023-04-30 20:20:23 +02:00
void AnimationNodeBlendTreeEditor : : _filter_fill_selection ( ) {
TreeItem * ti = filters - > get_root ( ) ;
if ( ! ti ) {
return ;
}
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Fill Selected Filter Children " ) ) ;
_filter_fill_selection_recursive ( undo_redo , ti , false ) ;
undo_redo - > add_do_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > add_undo_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
_update_filters ( _filter_edit ) ;
}
void AnimationNodeBlendTreeEditor : : _filter_invert_selection ( ) {
TreeItem * ti = filters - > get_root ( ) ;
if ( ! ti ) {
return ;
}
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Invert Filter Selection " ) ) ;
_filter_invert_selection_recursive ( undo_redo , ti ) ;
undo_redo - > add_do_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > add_undo_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
_update_filters ( _filter_edit ) ;
}
void AnimationNodeBlendTreeEditor : : _filter_clear_selection ( ) {
TreeItem * ti = filters - > get_root ( ) ;
if ( ! ti ) {
return ;
}
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Clear Filter Selection " ) ) ;
_filter_clear_selection_recursive ( undo_redo , ti ) ;
undo_redo - > add_do_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > add_undo_method ( this , " _update_filters " , _filter_edit ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
_update_filters ( _filter_edit ) ;
}
void AnimationNodeBlendTreeEditor : : _filter_fill_selection_recursive ( EditorUndoRedoManager * p_undo_redo , TreeItem * p_item , bool p_parent_filtered ) {
TreeItem * ti = p_item - > get_first_child ( ) ;
bool parent_filtered = p_parent_filtered ;
while ( ti ) {
NodePath item_path = ti - > get_metadata ( 0 ) ;
bool filtered = _filter_edit - > is_path_filtered ( item_path ) ;
parent_filtered | = filtered ;
p_undo_redo - > add_do_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , parent_filtered ) ;
p_undo_redo - > add_undo_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , filtered ) ;
_filter_fill_selection_recursive ( p_undo_redo , ti , parent_filtered ) ;
ti = ti - > get_next ( ) ;
parent_filtered = p_parent_filtered ;
}
}
void AnimationNodeBlendTreeEditor : : _filter_invert_selection_recursive ( EditorUndoRedoManager * p_undo_redo , TreeItem * p_item ) {
TreeItem * ti = p_item - > get_first_child ( ) ;
while ( ti ) {
NodePath item_path = ti - > get_metadata ( 0 ) ;
bool filtered = _filter_edit - > is_path_filtered ( item_path ) ;
p_undo_redo - > add_do_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , ! filtered ) ;
p_undo_redo - > add_undo_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , filtered ) ;
_filter_invert_selection_recursive ( p_undo_redo , ti ) ;
ti = ti - > get_next ( ) ;
}
}
void AnimationNodeBlendTreeEditor : : _filter_clear_selection_recursive ( EditorUndoRedoManager * p_undo_redo , TreeItem * p_item ) {
TreeItem * ti = p_item - > get_first_child ( ) ;
while ( ti ) {
NodePath item_path = ti - > get_metadata ( 0 ) ;
bool filtered = _filter_edit - > is_path_filtered ( item_path ) ;
p_undo_redo - > add_do_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , false ) ;
p_undo_redo - > add_undo_method ( _filter_edit . ptr ( ) , " set_filter_path " , item_path , filtered ) ;
_filter_clear_selection_recursive ( p_undo_redo , ti ) ;
ti = ti - > get_next ( ) ;
}
}
2018-06-19 03:10:48 +02:00
bool AnimationNodeBlendTreeEditor : : _update_filters ( const Ref < AnimationNode > & anode ) {
2020-05-14 16:41:43 +02:00
if ( updating | | _filter_edit ! = anode ) {
2018-06-19 03:10:48 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
2022-12-12 19:00:11 +01:00
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
return false ;
}
2023-07-20 17:34:06 +02:00
Node * base = tree - > get_node ( tree - > get_root_node ( ) ) ;
2018-06-19 03:10:48 +02:00
if ( ! base ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Animation player has no valid root node path, so unable to retrieve track names. " ) ) ;
return false ;
}
updating = true ;
2022-05-19 17:00:06 +02:00
HashSet < String > paths ;
2022-05-13 15:04:37 +02:00
HashMap < String , RBSet < String > > types ;
2018-06-19 03:10:48 +02:00
{
2022-09-29 11:53:28 +02:00
List < StringName > animation_list ;
2023-07-20 17:34:06 +02:00
tree - > get_animation_list ( & animation_list ) ;
2018-06-19 03:10:48 +02:00
2022-09-29 11:53:28 +02:00
for ( const StringName & E : animation_list ) {
2023-07-20 17:34:06 +02:00
Ref < Animation > anim = tree - > get_animation ( E ) ;
2018-06-19 03:10:48 +02:00
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
2019-11-09 21:52:22 +01:00
String track_path = anim - > track_get_path ( i ) ;
paths . insert ( track_path ) ;
String track_type_name ;
Animation : : TrackType track_type = anim - > track_get_type ( i ) ;
switch ( track_type ) {
case Animation : : TrackType : : TYPE_ANIMATION : {
track_type_name = TTR ( " Anim Clips " ) ;
} break ;
case Animation : : TrackType : : TYPE_AUDIO : {
track_type_name = TTR ( " Audio Clips " ) ;
} break ;
case Animation : : TrackType : : TYPE_METHOD : {
track_type_name = TTR ( " Functions " ) ;
} break ;
default : {
} break ;
}
2020-12-15 13:04:21 +01:00
if ( ! track_type_name . is_empty ( ) ) {
2019-11-09 21:52:22 +01:00
types [ track_path ] . insert ( track_type_name ) ;
}
2018-06-19 03:10:48 +02:00
}
}
}
filter_enabled - > set_pressed ( anode - > is_filter_enabled ( ) ) ;
filters - > clear ( ) ;
TreeItem * root = filters - > create_item ( ) ;
2022-05-13 15:04:37 +02:00
HashMap < String , TreeItem * > parenthood ;
2018-06-19 03:10:48 +02:00
2022-05-19 01:43:40 +02:00
for ( const String & E : paths ) {
NodePath path = E ;
2020-04-02 01:20:12 +02:00
TreeItem * ti = nullptr ;
2018-06-19 03:10:48 +02:00
String accum ;
for ( int i = 0 ; i < path . get_name_count ( ) ; i + + ) {
String name = path . get_name ( i ) ;
2021-12-09 10:42:46 +01:00
if ( ! accum . is_empty ( ) ) {
2018-06-19 03:10:48 +02:00
accum + = " / " ;
}
accum + = name ;
if ( ! parenthood . has ( accum ) ) {
if ( ti ) {
ti = filters - > create_item ( ti ) ;
} else {
ti = filters - > create_item ( root ) ;
}
parenthood [ accum ] = ti ;
ti - > set_text ( 0 , name ) ;
ti - > set_selectable ( 0 , false ) ;
ti - > set_editable ( 0 , false ) ;
if ( base - > has_node ( accum ) ) {
Node * node = base - > get_node ( accum ) ;
2018-09-02 23:40:51 +02:00
ti - > set_icon ( 0 , EditorNode : : get_singleton ( ) - > get_object_icon ( node , " Node " ) ) ;
2018-06-19 03:10:48 +02:00
}
} else {
ti = parenthood [ accum ] ;
}
}
2020-04-02 01:20:12 +02:00
Node * node = nullptr ;
2018-06-19 03:10:48 +02:00
if ( base - > has_node ( accum ) ) {
node = base - > get_node ( accum ) ;
}
2020-05-14 16:41:43 +02:00
if ( ! node ) {
2018-09-13 03:38:39 +02:00
continue ; //no node, can't edit
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
if ( path . get_subname_count ( ) ) {
String concat = path . get_concatenated_subnames ( ) ;
2020-03-26 22:49:16 +01:00
Skeleton3D * skeleton = Object : : cast_to < Skeleton3D > ( node ) ;
2018-06-19 03:10:48 +02:00
if ( skeleton & & skeleton - > find_bone ( concat ) ! = - 1 ) {
//path in skeleton
2019-06-26 15:08:25 +02:00
const String & bone = concat ;
2018-06-19 03:10:48 +02:00
int idx = skeleton - > find_bone ( bone ) ;
List < String > bone_path ;
while ( idx ! = - 1 ) {
bone_path . push_front ( skeleton - > get_bone_name ( idx ) ) ;
idx = skeleton - > get_bone_parent ( idx ) ;
}
accum + = " : " ;
for ( List < String > : : Element * F = bone_path . front ( ) ; F ; F = F - > next ( ) ) {
if ( F ! = bone_path . front ( ) ) {
accum + = " / " ;
}
accum + = F - > get ( ) ;
if ( ! parenthood . has ( accum ) ) {
ti = filters - > create_item ( ti ) ;
parenthood [ accum ] = ti ;
ti - > set_text ( 0 , F - > get ( ) ) ;
ti - > set_selectable ( 0 , false ) ;
ti - > set_editable ( 0 , false ) ;
2024-01-28 01:11:43 +01:00
ti - > set_icon ( 0 , get_editor_theme_icon ( SNAME ( " Bone " ) ) ) ;
2018-06-19 03:10:48 +02:00
} else {
ti = parenthood [ accum ] ;
}
}
2022-05-04 07:31:53 +02:00
ti - > set_editable ( 0 , ! read_only ) ;
2018-06-19 03:10:48 +02:00
ti - > set_selectable ( 0 , true ) ;
ti - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
ti - > set_text ( 0 , concat ) ;
ti - > set_checked ( 0 , anode - > is_path_filtered ( path ) ) ;
2024-01-28 01:11:43 +01:00
ti - > set_icon ( 0 , get_editor_theme_icon ( SNAME ( " Bone " ) ) ) ;
2018-06-19 03:10:48 +02:00
ti - > set_metadata ( 0 , path ) ;
} else {
//just a property
ti = filters - > create_item ( ti ) ;
ti - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
ti - > set_text ( 0 , concat ) ;
2022-05-04 07:31:53 +02:00
ti - > set_editable ( 0 , ! read_only ) ;
2018-06-19 03:10:48 +02:00
ti - > set_selectable ( 0 , true ) ;
ti - > set_checked ( 0 , anode - > is_path_filtered ( path ) ) ;
ti - > set_metadata ( 0 , path ) ;
}
} else {
if ( ti ) {
2019-11-09 21:52:22 +01:00
//just a node, not a property track
String types_text = " [ " ;
if ( types . has ( path ) ) {
2022-05-19 17:00:06 +02:00
RBSet < String > : : Iterator F = types [ path ] . begin ( ) ;
types_text + = * F ;
while ( F ) {
types_text + = " / " + * F ;
;
+ + F ;
2019-11-09 21:52:22 +01:00
}
}
types_text + = " ] " ;
ti = filters - > create_item ( ti ) ;
ti - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
ti - > set_text ( 0 , types_text ) ;
2022-05-04 07:31:53 +02:00
ti - > set_editable ( 0 , ! read_only ) ;
2018-06-19 03:10:48 +02:00
ti - > set_selectable ( 0 , true ) ;
ti - > set_checked ( 0 , anode - > is_path_filtered ( path ) ) ;
ti - > set_metadata ( 0 , path ) ;
}
}
}
updating = false ;
return true ;
}
2022-05-04 07:31:53 +02:00
void AnimationNodeBlendTreeEditor : : _inspect_filters ( const String & p_which ) {
if ( read_only ) {
filter_dialog - > set_title ( TTR ( " Inspect Filtered Tracks: " ) ) ;
} else {
filter_dialog - > set_title ( TTR ( " Edit Filtered Tracks: " ) ) ;
}
filter_enabled - > set_disabled ( read_only ) ;
2018-06-19 03:10:48 +02:00
Ref < AnimationNode > anode = blend_tree - > get_node ( p_which ) ;
ERR_FAIL_COND ( ! anode . is_valid ( ) ) ;
_filter_edit = anode ;
2020-05-14 16:41:43 +02:00
if ( ! _update_filters ( anode ) ) {
2018-06-19 03:10:48 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
2020-03-06 18:00:16 +01:00
filter_dialog - > popup_centered ( Size2 ( 500 , 500 ) * EDSCALE ) ;
2018-06-19 03:10:48 +02:00
}
2022-02-16 03:44:22 +01:00
void AnimationNodeBlendTreeEditor : : _update_editor_settings ( ) {
2022-10-18 16:43:37 +02:00
graph - > get_panner ( ) - > setup ( ( ViewPanner : : ControlScheme ) EDITOR_GET ( " editors/panning/sub_editors_panning_scheme " ) . operator int ( ) , ED_GET_SHORTCUT ( " canvas_item_editor/pan_view " ) , bool ( EDITOR_GET ( " editors/panning/simple_panning " ) ) ) ;
graph - > set_warped_panning ( bool ( EDITOR_GET ( " editors/panning/warped_mouse_panning " ) ) ) ;
2022-02-16 03:44:22 +01:00
}
2018-06-19 03:10:48 +02:00
void AnimationNodeBlendTreeEditor : : _notification ( int p_what ) {
2022-02-16 03:44:22 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
_update_editor_settings ( ) ;
} break ;
2022-01-13 17:19:15 +01:00
2022-02-16 03:44:22 +01:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
2022-11-23 00:14:08 +01:00
if ( EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " editors/panning " ) ) {
_update_editor_settings ( ) ;
}
2022-02-16 03:44:22 +01:00
} break ;
2018-12-17 02:18:04 +01:00
2022-02-16 03:44:22 +01:00
case NOTIFICATION_THEME_CHANGED : {
2024-05-14 15:50:53 +02:00
error_panel - > add_theme_style_override ( SceneStringName ( panel ) , get_theme_stylebox ( SceneStringName ( panel ) , SNAME ( " Tree " ) ) ) ;
2024-05-14 15:57:29 +02:00
error_label - > add_theme_color_override ( SceneStringName ( font_color ) , get_theme_color ( SNAME ( " error_color " ) , EditorStringName ( Editor ) ) ) ;
2018-06-19 03:10:48 +02:00
2022-02-16 03:44:22 +01:00
if ( is_visible_in_tree ( ) ) {
2022-09-01 16:00:55 +02:00
update_graph ( ) ;
2022-02-16 03:44:22 +01:00
}
} break ;
2018-06-19 03:10:48 +02:00
2022-02-16 03:44:22 +01:00
case NOTIFICATION_PROCESS : {
2022-12-12 19:00:11 +01:00
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
return ; // Node has been changed.
}
2022-02-16 03:44:22 +01:00
String error ;
2018-06-19 03:10:48 +02:00
2022-12-12 19:00:11 +01:00
if ( ! tree - > is_active ( ) ) {
2022-02-16 03:44:22 +01:00
error = TTR ( " AnimationTree is inactive. \n Activate to enable playback, check node warnings if activation fails. " ) ;
2022-12-12 19:00:11 +01:00
} else if ( tree - > is_state_invalid ( ) ) {
error = tree - > get_invalid_state_reason ( ) ;
2018-06-19 03:10:48 +02:00
}
2022-02-16 03:44:22 +01:00
if ( error ! = error_label - > get_text ( ) ) {
error_label - > set_text ( error ) ;
if ( ! error . is_empty ( ) ) {
error_panel - > show ( ) ;
} else {
error_panel - > hide ( ) ;
}
2018-06-19 03:10:48 +02:00
}
2022-02-16 03:44:22 +01:00
List < AnimationNodeBlendTree : : NodeConnection > conns ;
blend_tree - > get_node_connections ( & conns ) ;
for ( const AnimationNodeBlendTree : : NodeConnection & E : conns ) {
float activity = 0 ;
StringName path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + E . input_node ;
2022-12-12 19:00:11 +01:00
if ( ! tree - > is_state_invalid ( ) ) {
activity = tree - > get_connection_activity ( path , E . input_index ) ;
2022-02-16 03:44:22 +01:00
}
graph - > set_connection_activity ( E . output_node , 0 , E . input_node , E . input_index , activity ) ;
}
2018-06-19 03:10:48 +02:00
2023-07-20 17:34:06 +02:00
for ( const KeyValue < StringName , ProgressBar * > & E : animations ) {
Ref < AnimationNodeAnimation > an = blend_tree - > get_node ( E . key ) ;
if ( an . is_valid ( ) ) {
if ( tree - > has_animation ( an - > get_animation ( ) ) ) {
Ref < Animation > anim = tree - > get_animation ( an - > get_animation ( ) ) ;
if ( anim . is_valid ( ) ) {
//StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node;
2024-01-07 22:08:10 +01:00
StringName length_path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + String ( E . key ) + " /current_length " ;
StringName time_path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + String ( E . key ) + " /current_position " ;
E . value - > set_max ( tree - > get ( length_path ) ) ;
2023-07-20 17:34:06 +02:00
E . value - > set_value ( tree - > get ( time_path ) ) ;
2018-06-19 03:10:48 +02:00
}
}
}
}
2018-08-20 18:38:18 +02:00
2022-02-16 03:44:22 +01:00
for ( int i = 0 ; i < visible_properties . size ( ) ; i + + ) {
visible_properties [ i ] - > update_property ( ) ;
}
} break ;
2018-08-20 18:38:18 +02:00
2022-02-16 03:44:22 +01:00
case NOTIFICATION_VISIBILITY_CHANGED : {
set_process ( is_visible_in_tree ( ) ) ;
} break ;
2018-06-19 03:10:48 +02:00
}
}
void AnimationNodeBlendTreeEditor : : _scroll_changed ( const Vector2 & p_scroll ) {
2022-05-04 07:31:53 +02:00
if ( read_only ) {
return ;
}
2020-05-14 16:41:43 +02:00
if ( updating ) {
2018-06-19 03:10:48 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2018-06-19 03:10:48 +02:00
updating = true ;
blend_tree - > set_graph_offset ( p_scroll / EDSCALE ) ;
updating = false ;
}
void AnimationNodeBlendTreeEditor : : _bind_methods ( ) {
2022-09-01 16:00:55 +02:00
ClassDB : : bind_method ( " update_graph " , & AnimationNodeBlendTreeEditor : : update_graph ) ;
2018-06-19 03:10:48 +02:00
ClassDB : : bind_method ( " _update_filters " , & AnimationNodeBlendTreeEditor : : _update_filters ) ;
}
2020-04-02 01:20:12 +02:00
AnimationNodeBlendTreeEditor * AnimationNodeBlendTreeEditor : : singleton = nullptr ;
2018-06-19 03:10:48 +02:00
2022-09-01 16:00:55 +02:00
// AnimationNode's "node_changed" signal means almost update_input.
void AnimationNodeBlendTreeEditor : : _node_changed ( const StringName & p_node_name ) {
// TODO:
// Here is executed during the commit of EditorNode::undo_redo, it is not possible to create an undo_redo action here.
// The disconnect when the number of enabled inputs decreases is done in AnimationNodeBlendTree and update_graph().
// This means that there is no place to register undo_redo actions.
// In order to implement undo_redo correctly, we may need to implement AnimationNodeEdit such as AnimationTrackKeyEdit
// and add it to _node_selected() with EditorNode::get_singleton()->push_item(AnimationNodeEdit).
update_graph ( ) ;
}
2018-06-19 03:10:48 +02:00
void AnimationNodeBlendTreeEditor : : _node_renamed ( const String & p_text , Ref < AnimationNode > p_node ) {
2022-09-11 11:33:59 +02:00
if ( blend_tree . is_null ( ) ) {
return ;
}
2022-12-12 19:00:11 +01:00
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
return ;
}
2018-06-19 03:10:48 +02:00
String prev_name = blend_tree - > get_node_name ( p_node ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( prev_name . is_empty ( ) ) ;
2018-06-19 03:10:48 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( graph - > get_node ( prev_name ) ) ;
2023-09-09 17:24:40 +02:00
ERR_FAIL_NULL ( gn ) ;
2018-06-19 03:10:48 +02:00
2019-06-26 15:08:25 +02:00
const String & new_name = p_text ;
2018-06-19 03:10:48 +02:00
2022-02-03 17:03:38 +01:00
ERR_FAIL_COND ( new_name . is_empty ( ) | | new_name . contains ( " . " ) | | new_name . contains ( " / " ) ) ;
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
if ( new_name = = prev_name ) {
return ; //nothing to do
}
2018-06-19 03:10:48 +02:00
2019-06-26 15:08:25 +02:00
const String & base_name = new_name ;
2018-06-19 03:10:48 +02:00
int base = 1 ;
String name = base_name ;
while ( blend_tree - > has_node ( name ) ) {
base + + ;
name = base_name + " " + itos ( base ) ;
}
2018-08-20 18:38:18 +02:00
String base_path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) ;
2018-06-19 03:10:48 +02:00
updating = true ;
2022-12-23 23:53:16 +01:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2019-02-21 20:41:01 +01:00
undo_redo - > create_action ( TTR ( " Node Renamed " ) ) ;
2018-06-21 23:08:11 +02:00
undo_redo - > add_do_method ( blend_tree . ptr ( ) , " rename_node " , prev_name , name ) ;
undo_redo - > add_undo_method ( blend_tree . ptr ( ) , " rename_node " , name , prev_name ) ;
2022-09-01 16:00:55 +02:00
undo_redo - > add_do_method ( this , " update_graph " ) ;
undo_redo - > add_undo_method ( this , " update_graph " ) ;
2018-06-19 03:10:48 +02:00
undo_redo - > commit_action ( ) ;
updating = false ;
gn - > set_name ( new_name ) ;
gn - > set_size ( gn - > get_minimum_size ( ) ) ;
2018-08-20 18:38:18 +02:00
//change editors accordingly
for ( int i = 0 ; i < visible_properties . size ( ) ; i + + ) {
String pname = visible_properties [ i ] - > get_edited_property ( ) . operator String ( ) ;
if ( pname . begins_with ( base_path + prev_name ) ) {
2019-02-12 21:10:08 +01:00
String new_name2 = pname . replace_first ( base_path + prev_name , base_path + name ) ;
visible_properties [ i ] - > set_object_and_property ( visible_properties [ i ] - > get_edited_object ( ) , new_name2 ) ;
2018-08-20 18:38:18 +02:00
}
}
2018-08-23 21:44:10 +02:00
//recreate connections
graph - > clear_connections ( ) ;
2022-09-29 11:53:28 +02:00
List < AnimationNodeBlendTree : : NodeConnection > node_connections ;
blend_tree - > get_node_connections ( & node_connections ) ;
2018-08-23 21:44:10 +02:00
2022-09-29 11:53:28 +02:00
for ( const AnimationNodeBlendTree : : NodeConnection & E : node_connections ) {
2021-07-16 05:45:57 +02:00
StringName from = E . output_node ;
StringName to = E . input_node ;
int to_idx = E . input_index ;
2018-08-23 21:44:10 +02:00
graph - > connect_node ( from , 0 , to , to_idx ) ;
}
//update animations
2022-05-13 15:04:37 +02:00
for ( const KeyValue < StringName , ProgressBar * > & E : animations ) {
if ( E . key = = prev_name ) {
2018-08-23 21:44:10 +02:00
animations [ new_name ] = animations [ prev_name ] ;
animations . erase ( prev_name ) ;
break ;
}
}
2018-12-18 00:03:25 +01:00
2022-09-01 16:00:55 +02:00
update_graph ( ) ; // Needed to update the signal connections with the new name.
2022-10-30 18:50:27 +01:00
current_node_rename_text = String ( ) ;
2018-06-19 03:10:48 +02:00
}
2022-10-30 18:50:27 +01:00
void AnimationNodeBlendTreeEditor : : _node_renamed_focus_out ( Ref < AnimationNode > p_node ) {
if ( current_node_rename_text . is_empty ( ) ) {
2022-01-25 13:18:40 +01:00
return ; // The text_submitted signal triggered the graph update and freed the LineEdit.
}
2022-10-30 18:50:27 +01:00
_node_renamed ( current_node_rename_text , p_node ) ;
}
void AnimationNodeBlendTreeEditor : : _node_rename_lineedit_changed ( const String & p_text ) {
current_node_rename_text = p_text ;
2018-06-19 03:10:48 +02:00
}
2018-08-20 18:38:18 +02:00
bool AnimationNodeBlendTreeEditor : : can_edit ( const Ref < AnimationNode > & p_node ) {
Ref < AnimationNodeBlendTree > bt = p_node ;
return bt . is_valid ( ) ;
}
void AnimationNodeBlendTreeEditor : : edit ( const Ref < AnimationNode > & p_node ) {
if ( blend_tree . is_valid ( ) ) {
2022-09-01 16:00:55 +02:00
blend_tree - > disconnect ( " node_changed " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_changed ) ) ;
2018-08-20 18:38:18 +02:00
}
2019-07-11 20:18:53 +02:00
blend_tree = p_node ;
2018-08-20 18:38:18 +02:00
2022-05-04 07:31:53 +02:00
read_only = false ;
2018-08-20 18:38:18 +02:00
if ( blend_tree . is_null ( ) ) {
hide ( ) ;
} else {
2022-05-04 07:31:53 +02:00
read_only = EditorNode : : get_singleton ( ) - > is_resource_read_only ( blend_tree ) ;
2022-09-01 16:00:55 +02:00
blend_tree - > connect ( " node_changed " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_changed ) ) ;
2018-08-20 18:38:18 +02:00
2022-09-01 16:00:55 +02:00
update_graph ( ) ;
2018-08-20 18:38:18 +02:00
}
2022-05-04 07:31:53 +02:00
add_node - > set_disabled ( read_only ) ;
2023-10-02 13:43:08 +02:00
graph - > set_show_arrange_button ( ! read_only ) ;
2018-08-20 18:38:18 +02:00
}
2018-06-19 03:10:48 +02:00
AnimationNodeBlendTreeEditor : : AnimationNodeBlendTreeEditor ( ) {
singleton = this ;
updating = false ;
2021-08-31 17:43:35 +02:00
use_position_from_popup_menu = false ;
2018-06-19 03:10:48 +02:00
graph = memnew ( GraphEdit ) ;
add_child ( graph ) ;
graph - > add_valid_right_disconnect_type ( 0 ) ;
graph - > add_valid_left_disconnect_type ( 0 ) ;
graph - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2022-07-28 22:56:41 +02:00
graph - > connect ( " connection_request " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _connection_request ) , CONNECT_DEFERRED ) ;
graph - > connect ( " disconnection_request " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _disconnection_request ) , CONNECT_DEFERRED ) ;
2020-02-21 18:28:45 +01:00
graph - > connect ( " node_selected " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _node_selected ) ) ;
graph - > connect ( " scroll_offset_changed " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _scroll_changed ) ) ;
2023-09-26 16:41:39 +02:00
graph - > connect ( " delete_nodes_request " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _delete_nodes_request ) ) ;
2020-02-21 18:28:45 +01:00
graph - > connect ( " popup_request " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _popup_request ) ) ;
2021-09-18 17:08:22 +02:00
graph - > connect ( " connection_to_empty " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _connection_to_empty ) ) ;
graph - > connect ( " connection_from_empty " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _connection_from_empty ) ) ;
2022-10-18 16:43:37 +02:00
float graph_minimap_opacity = EDITOR_GET ( " editors/visual_editors/minimap_opacity " ) ;
2021-01-25 15:37:05 +01:00
graph - > set_minimap_opacity ( graph_minimap_opacity ) ;
2022-10-18 16:43:37 +02:00
float graph_lines_curvature = EDITOR_GET ( " editors/visual_editors/lines_curvature " ) ;
2022-05-30 15:38:13 +02:00
graph - > set_connection_lines_curvature ( graph_lines_curvature ) ;
2018-06-19 03:10:48 +02:00
VSeparator * vs = memnew ( VSeparator ) ;
2023-07-10 17:26:02 +02:00
graph - > get_menu_hbox ( ) - > add_child ( vs ) ;
graph - > get_menu_hbox ( ) - > move_child ( vs , 0 ) ;
2018-06-19 03:10:48 +02:00
add_node = memnew ( MenuButton ) ;
2023-07-10 17:26:02 +02:00
graph - > get_menu_hbox ( ) - > add_child ( add_node ) ;
2019-01-07 16:57:52 +01:00
add_node - > set_text ( TTR ( " Add Node... " ) ) ;
2023-07-10 17:26:02 +02:00
graph - > get_menu_hbox ( ) - > move_child ( add_node , 0 ) ;
2024-05-14 14:13:31 +02:00
add_node - > get_popup ( ) - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _add_node ) ) ;
2023-01-10 09:05:09 +01:00
add_node - > get_popup ( ) - > connect ( " popup_hide " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _popup_hide ) , CONNECT_DEFERRED ) ;
2022-07-28 22:56:41 +02:00
add_node - > connect ( " about_to_popup " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _update_options_menu ) . bind ( false ) ) ;
2022-05-04 07:31:53 +02:00
add_node - > set_disabled ( read_only ) ;
2018-06-21 20:45:44 +02:00
2018-06-19 03:10:48 +02:00
add_options . push_back ( AddOption ( " Animation " , " AnimationNodeAnimation " ) ) ;
2021-09-18 17:08:22 +02:00
add_options . push_back ( AddOption ( " OneShot " , " AnimationNodeOneShot " , 2 ) ) ;
add_options . push_back ( AddOption ( " Add2 " , " AnimationNodeAdd2 " , 2 ) ) ;
add_options . push_back ( AddOption ( " Add3 " , " AnimationNodeAdd3 " , 3 ) ) ;
add_options . push_back ( AddOption ( " Blend2 " , " AnimationNodeBlend2 " , 2 ) ) ;
add_options . push_back ( AddOption ( " Blend3 " , " AnimationNodeBlend3 " , 3 ) ) ;
2023-04-30 16:32:18 +02:00
add_options . push_back ( AddOption ( " Sub2 " , " AnimationNodeSub2 " , 2 ) ) ;
2023-02-01 12:49:31 +01:00
add_options . push_back ( AddOption ( " TimeSeek " , " AnimationNodeTimeSeek " , 1 ) ) ;
2021-09-18 17:08:22 +02:00
add_options . push_back ( AddOption ( " TimeScale " , " AnimationNodeTimeScale " , 1 ) ) ;
2018-06-19 03:10:48 +02:00
add_options . push_back ( AddOption ( " Transition " , " AnimationNodeTransition " ) ) ;
add_options . push_back ( AddOption ( " BlendTree " , " AnimationNodeBlendTree " ) ) ;
2018-06-22 17:13:43 +02:00
add_options . push_back ( AddOption ( " BlendSpace1D " , " AnimationNodeBlendSpace1D " ) ) ;
2018-06-22 15:17:54 +02:00
add_options . push_back ( AddOption ( " BlendSpace2D " , " AnimationNodeBlendSpace2D " ) ) ;
2018-06-25 21:21:57 +02:00
add_options . push_back ( AddOption ( " StateMachine " , " AnimationNodeStateMachine " ) ) ;
2018-06-19 03:10:48 +02:00
_update_options_menu ( ) ;
error_panel = memnew ( PanelContainer ) ;
add_child ( error_panel ) ;
error_label = memnew ( Label ) ;
error_panel - > add_child ( error_label ) ;
error_label - > set_text ( " eh " ) ;
filter_dialog = memnew ( AcceptDialog ) ;
add_child ( filter_dialog ) ;
filter_dialog - > set_title ( TTR ( " Edit Filtered Tracks: " ) ) ;
VBoxContainer * filter_vbox = memnew ( VBoxContainer ) ;
filter_dialog - > add_child ( filter_vbox ) ;
2023-04-30 20:20:23 +02:00
HBoxContainer * filter_hbox = memnew ( HBoxContainer ) ;
filter_vbox - > add_child ( filter_hbox ) ;
2018-06-19 03:10:48 +02:00
filter_enabled = memnew ( CheckBox ) ;
2019-03-25 01:54:29 +01:00
filter_enabled - > set_text ( TTR ( " Enable Filtering " ) ) ;
2024-05-14 09:40:21 +02:00
filter_enabled - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _filter_toggled ) ) ;
2023-04-30 20:20:23 +02:00
filter_hbox - > add_child ( filter_enabled ) ;
filter_fill_selection = memnew ( Button ) ;
filter_fill_selection - > set_text ( TTR ( " Fill Selected Children " ) ) ;
2024-05-14 09:40:21 +02:00
filter_fill_selection - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _filter_fill_selection ) ) ;
2023-04-30 20:20:23 +02:00
filter_hbox - > add_child ( filter_fill_selection ) ;
filter_invert_selection = memnew ( Button ) ;
filter_invert_selection - > set_text ( TTR ( " Invert " ) ) ;
2024-05-14 09:40:21 +02:00
filter_invert_selection - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _filter_invert_selection ) ) ;
2023-04-30 20:20:23 +02:00
filter_hbox - > add_child ( filter_invert_selection ) ;
filter_clear_selection = memnew ( Button ) ;
filter_clear_selection - > set_text ( TTR ( " Clear " ) ) ;
2024-05-14 09:40:21 +02:00
filter_clear_selection - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _filter_clear_selection ) ) ;
2023-04-30 20:20:23 +02:00
filter_hbox - > add_child ( filter_clear_selection ) ;
2018-06-19 03:10:48 +02:00
filters = memnew ( Tree ) ;
filter_vbox - > add_child ( filters ) ;
2024-03-17 09:28:18 +01:00
filters - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2018-06-19 03:10:48 +02:00
filters - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
filters - > set_hide_root ( true ) ;
2020-02-21 18:28:45 +01:00
filters - > connect ( " item_edited " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _filter_edited ) ) ;
2018-06-19 03:10:48 +02:00
2018-08-20 18:38:18 +02:00
open_file = memnew ( EditorFileDialog ) ;
add_child ( open_file ) ;
open_file - > set_title ( TTR ( " Open Animation Node " ) ) ;
2020-03-06 18:00:16 +01:00
open_file - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILE ) ;
2020-02-21 18:28:45 +01:00
open_file - > connect ( " file_selected " , callable_mp ( this , & AnimationNodeBlendTreeEditor : : _file_opened ) ) ;
2024-08-31 08:57:34 +02:00
animation_node_inspector_plugin = Ref < EditorInspectorPluginAnimationNodeAnimation > ( memnew ( EditorInspectorPluginAnimationNodeAnimation ) ) ;
EditorInspector : : add_inspector_plugin ( animation_node_inspector_plugin ) ;
}
AnimationNodeBlendTreeEditor : : ~ AnimationNodeBlendTreeEditor ( ) {
}
// EditorPluginAnimationNodeAnimation
void AnimationNodeAnimationEditor : : _open_set_custom_timeline_from_marker_dialog ( ) {
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
StringName anim_name = animation_node_animation - > get_animation ( ) ;
PackedStringArray markers = tree - > has_animation ( anim_name ) ? tree - > get_animation ( anim_name ) - > get_marker_names ( ) : PackedStringArray ( ) ;
dialog - > select_start - > clear ( ) ;
dialog - > select_start - > add_icon_item ( get_editor_theme_icon ( SNAME ( " PlayStart " ) ) , TTR ( " Start of Animation " ) ) ;
dialog - > select_start - > add_separator ( ) ;
dialog - > select_end - > clear ( ) ;
dialog - > select_end - > add_icon_item ( get_editor_theme_icon ( SNAME ( " PlayStartBackwards " ) ) , TTR ( " End of Animation " ) ) ;
dialog - > select_end - > add_separator ( ) ;
for ( const String & marker : markers ) {
dialog - > select_start - > add_item ( marker ) ;
dialog - > select_end - > add_item ( marker ) ;
}
// Because the default selections are always valid, and marker times won't change during the dialog, we can ensure that the user can only select valid markers.
// This invariant is maintained by _validate_markers.
dialog - > select_start - > select ( 0 ) ;
dialog - > select_end - > select ( 0 ) ;
dialog - > popup_centered ( Size2 ( 200 , 0 ) * EDSCALE ) ;
}
void AnimationNodeAnimationEditor : : _validate_markers ( int p_id ) {
// Note: p_id is ignored. It is included because OptionButton's item_changed signal always passes it.
int start_id = dialog - > select_start - > get_selected_id ( ) ;
int end_id = dialog - > select_end - > get_selected_id ( ) ;
StringName anim_name = animation_node_animation - > get_animation ( ) ;
Ref < Animation > animation = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) - > get_animation ( anim_name ) ;
ERR_FAIL_COND ( animation . is_null ( ) ) ;
double start_time = start_id < 2 ? 0 : animation - > get_marker_time ( dialog - > select_start - > get_item_text ( start_id ) ) ;
double end_time = end_id < 2 ? animation - > get_length ( ) : animation - > get_marker_time ( dialog - > select_end - > get_item_text ( end_id ) ) ;
// p_start and p_end have the same item count.
for ( int i = 2 ; i < dialog - > select_start - > get_item_count ( ) ; i + + ) {
String start_marker = dialog - > select_start - > get_item_text ( i ) ;
String end_marker = dialog - > select_end - > get_item_text ( i ) ;
dialog - > select_start - > set_item_disabled ( i , end_id > = 2 & & ( i = = end_id | | animation - > get_marker_time ( start_marker ) > end_time ) ) ;
dialog - > select_end - > set_item_disabled ( i , start_id > = 2 & & ( i = = start_id | | start_time > animation - > get_marker_time ( end_marker ) ) ) ;
}
}
void AnimationNodeAnimationEditor : : _confirm_set_custom_timeline_from_marker_dialog ( ) {
int start_id = dialog - > select_start - > get_selected_id ( ) ;
int end_id = dialog - > select_end - > get_selected_id ( ) ;
Ref < Animation > animation = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) - > get_animation ( animation_node_animation - > get_animation ( ) ) ;
ERR_FAIL_COND ( animation . is_null ( ) ) ;
double start_time = start_id < 2 ? 0 : animation - > get_marker_time ( dialog - > select_start - > get_item_text ( start_id ) ) ;
double end_time = end_id < 2 ? animation - > get_length ( ) : animation - > get_marker_time ( dialog - > select_end - > get_item_text ( end_id ) ) ;
double length = end_time - start_time ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Set Custom Timeline from Marker " ) ) ;
undo_redo - > add_do_method ( * animation_node_animation , " set_start_offset " , start_time ) ;
undo_redo - > add_undo_method ( * animation_node_animation , " set_start_offset " , animation_node_animation - > get_start_offset ( ) ) ;
undo_redo - > add_do_method ( * animation_node_animation , " set_stretch_time_scale " , false ) ;
undo_redo - > add_undo_method ( * animation_node_animation , " set_stretch_time_scale " , animation_node_animation - > is_stretching_time_scale ( ) ) ;
undo_redo - > add_do_method ( * animation_node_animation , " set_timeline_length " , length ) ;
undo_redo - > add_undo_method ( * animation_node_animation , " set_timeline_length " , animation_node_animation - > get_timeline_length ( ) ) ;
undo_redo - > add_do_method ( * animation_node_animation , " notify_property_list_changed " ) ;
undo_redo - > add_undo_method ( * animation_node_animation , " notify_property_list_changed " ) ;
undo_redo - > commit_action ( ) ;
}
AnimationNodeAnimationEditor : : AnimationNodeAnimationEditor ( Ref < AnimationNodeAnimation > p_animation_node_animation ) {
animation_node_animation = p_animation_node_animation ;
dialog = memnew ( AnimationNodeAnimationEditorDialog ) ;
add_child ( dialog ) ;
dialog - > set_hide_on_ok ( false ) ;
dialog - > select_start - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & AnimationNodeAnimationEditor : : _validate_markers ) ) ;
dialog - > select_end - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & AnimationNodeAnimationEditor : : _validate_markers ) ) ;
dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & AnimationNodeAnimationEditor : : _confirm_set_custom_timeline_from_marker_dialog ) ) ;
Control * top_spacer = memnew ( Control ) ;
add_child ( top_spacer ) ;
top_spacer - > set_custom_minimum_size ( Size2 ( 0 , 2 ) * EDSCALE ) ;
button = memnew ( Button ) ;
add_child ( button ) ;
button - > set_text ( TTR ( " Set Custom Timeline from Marker " ) ) ;
button - > set_h_size_flags ( Control : : SIZE_SHRINK_CENTER ) ;
button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & AnimationNodeAnimationEditor : : _open_set_custom_timeline_from_marker_dialog ) ) ;
Control * bottom_spacer = memnew ( Control ) ;
add_child ( bottom_spacer ) ;
bottom_spacer - > set_custom_minimum_size ( Size2 ( 0 , 2 ) * EDSCALE ) ;
}
AnimationNodeAnimationEditor : : ~ AnimationNodeAnimationEditor ( ) {
}
void AnimationNodeAnimationEditor : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_THEME_CHANGED : {
button - > set_theme_type_variation ( SNAME ( " InspectorActionButton " ) ) ;
button - > set_icon ( get_editor_theme_icon ( SNAME ( " Edit " ) ) ) ;
} break ;
}
}
bool EditorInspectorPluginAnimationNodeAnimation : : can_handle ( Object * p_object ) {
Ref < AnimationNodeAnimation > ana ( Object : : cast_to < AnimationNodeAnimation > ( p_object ) ) ;
return ana . is_valid ( ) & & ana - > is_using_custom_timeline ( ) ;
}
bool EditorInspectorPluginAnimationNodeAnimation : : parse_property ( Object * p_object , const Variant : : Type p_type , const String & p_path , const PropertyHint p_hint , const String & p_hint_text , const BitField < PropertyUsageFlags > p_usage , const bool p_wide ) {
Ref < AnimationNodeAnimation > ana ( Object : : cast_to < AnimationNodeAnimation > ( p_object ) ) ;
ERR_FAIL_COND_V ( ana . is_null ( ) , false ) ;
if ( p_path = = " timeline_length " ) {
add_custom_control ( memnew ( AnimationNodeAnimationEditor ( ana ) ) ) ;
}
return false ;
}
AnimationNodeAnimationEditorDialog : : AnimationNodeAnimationEditorDialog ( ) {
set_title ( TTR ( " Select Markers... " ) ) ;
VBoxContainer * vbox = memnew ( VBoxContainer ) ;
add_child ( vbox ) ;
vbox - > set_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
HBoxContainer * container_start = memnew ( HBoxContainer ) ;
vbox - > add_child ( container_start ) ;
Label * label_start = memnew ( Label ) ;
container_start - > add_child ( label_start ) ;
label_start - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
label_start - > set_stretch_ratio ( 1 ) ;
label_start - > set_text ( TTR ( " Start Marker " ) ) ;
select_start = memnew ( OptionButton ) ;
container_start - > add_child ( select_start ) ;
select_start - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
select_start - > set_stretch_ratio ( 2 ) ;
HBoxContainer * container_end = memnew ( HBoxContainer ) ;
vbox - > add_child ( container_end ) ;
Label * label_end = memnew ( Label ) ;
container_end - > add_child ( label_end ) ;
label_end - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
label_end - > set_stretch_ratio ( 1 ) ;
label_end - > set_text ( TTR ( " End Marker " ) ) ;
select_end = memnew ( OptionButton ) ;
container_end - > add_child ( select_end ) ;
select_end - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
select_end - > set_stretch_ratio ( 2 ) ;
}
AnimationNodeAnimationEditorDialog : : ~ AnimationNodeAnimationEditorDialog ( ) {
2018-06-19 03:10:48 +02:00
}