@ -50,6 +50,7 @@
# include "scene/gui/tree.h"
# include "scene/main/viewport.h"
# include "scene/main/window.h"
# include "scene/scene_string_names.h"
bool AnimationNodeStateMachineEditor : : can_edit ( const Ref < AnimationNode > & p_node ) {
Ref < AnimationNodeStateMachine > ansm = p_node ;
@ -67,7 +68,6 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
selected_transition_from = StringName ( ) ;
selected_transition_to = StringName ( ) ;
selected_transition_index = - 1 ;
selected_multi_transition = TransitionLine ( ) ;
selected_node = StringName ( ) ;
selected_nodes . clear ( ) ;
_update_mode ( ) ;
@ -78,14 +78,60 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
tool_connect - > set_disabled ( read_only ) ;
}
String AnimationNodeStateMachineEditor : : _get_root_playback_path ( String & r_node_directory ) {
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
Vector < String > edited_path = AnimationTreeEditor : : get_singleton ( ) - > get_edited_path ( ) ;
String base_path ;
Vector < String > node_directory_path ;
bool is_playable_anodesm_found = false ;
if ( edited_path . size ( ) ) {
while ( ! is_playable_anodesm_found ) {
base_path = String ( " / " ) . join ( edited_path ) ;
Ref < AnimationNodeStateMachine > anodesm = ! edited_path . size ( ) ? tree - > get_tree_root ( ) : tree - > get_tree_root ( ) - > find_node_by_path ( base_path ) ;
if ( ! anodesm . is_valid ( ) ) {
break ;
} else {
if ( anodesm - > get_state_machine_type ( ) ! = AnimationNodeStateMachine : : STATE_MACHINE_TYPE_GROUPED ) {
is_playable_anodesm_found = true ;
} else {
int idx = edited_path . size ( ) - 1 ;
node_directory_path . push_back ( edited_path [ idx ] ) ;
edited_path . remove_at ( idx ) ;
}
}
}
}
if ( is_playable_anodesm_found ) {
// Return Root/Nested state machine playback.
node_directory_path . reverse ( ) ;
r_node_directory = String ( " / " ) . join ( node_directory_path ) ;
if ( node_directory_path . size ( ) ) {
r_node_directory + = " / " ;
}
base_path = ! edited_path . size ( ) ? String ( SceneStringNames : : get_singleton ( ) - > parameters_base_path ) + " playback " : String ( SceneStringNames : : get_singleton ( ) - > parameters_base_path ) + base_path + " /playback " ;
} else {
// Hmmm, we have to return Grouped state machine playback...
// It will give the user the error that Root/Nested state machine should be retrieved, that would be kind :-)
r_node_directory = String ( ) ;
base_path = AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + " playback " ;
}
return base_path ;
}
void AnimationNodeStateMachineEditor : : _state_machine_gui_input ( const Ref < InputEvent > & p_event ) {
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
return ;
}
Ref < AnimationNodeStateMachinePlayback > playback = tree - > get ( AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + " playback " ) ;
if ( playback . is_null ( ) ) {
String node_directory ;
Ref < AnimationNodeStateMachinePlayback > playback = tree - > get ( _get_root_playback_path ( node_directory ) ) ;
if ( ! playback . is_valid ( ) ) {
return ;
}
@ -99,16 +145,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
// Group selected nodes on a state machine
if ( tool_select - > is_pressed ( ) & & k . is_valid ( ) & & k - > is_pressed ( ) & & k - > is_ctrl_pressed ( ) & & ! k - > is_shift_pressed ( ) & & k - > get_keycode ( ) = = Key : : G & & ! k - > is_echo ( ) ) {
_group_selected_nodes ( ) ;
}
// Ungroup state machine
if ( tool_select - > is_pressed ( ) & & k . is_valid ( ) & & k - > is_pressed ( ) & & k - > is_ctrl_pressed ( ) & & k - > is_shift_pressed ( ) & & k - > get_keycode ( ) = = Key : : G & & ! k - > is_echo ( ) ) {
_ungroup_selected_nodes ( ) ;
}
Ref < InputEventMouseButton > mb = p_event ;
// Add new node
@ -124,17 +160,16 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
selected_transition_from = StringName ( ) ;
selected_transition_to = StringName ( ) ;
selected_transition_index = - 1 ;
selected_multi_transition = TransitionLine ( ) ;
selected_node = StringName ( ) ;
for ( int i = node_rects . size ( ) - 1 ; i > = 0 ; i - - ) { //inverse to draw order
if ( node_rects [ i ] . play . has_point ( mb - > get_position ( ) ) ) { //edit name
if ( play_mode - > get_selected ( ) = = 1 | | ! playback - > is_playing ( ) ) {
// s tart
playback - > start ( node_ rects[ i ] . node_name ) ;
// S tart
playback - > start ( node_ directory + String ( node_ rects[ i ] . node_name ) ) ;
} else {
// t ravel
playback - > travel ( node_ rects[ i ] . node_name ) ;
// T ravel
playback - > travel ( node_ directory + String ( node_ rects[ i ] . node_name ) ) ;
}
state_machine_draw - > queue_redraw ( ) ;
return ;
@ -213,26 +248,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
selected_transition_index = closest ;
Ref < AnimationNodeStateMachineTransition > tr = state_machine - > get_transition ( closest ) ;
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
if ( ! transition_lines [ closest ] . multi_transitions . is_empty ( ) ) {
selected_transition_index = - 1 ;
selected_multi_transition = transition_lines [ closest ] ;
Ref < EditorAnimationMultiTransitionEdit > multi ;
multi . instantiate ( ) ;
multi - > add_transition ( selected_transition_from , selected_transition_to , tr ) ;
for ( int i = 0 ; i < transition_lines [ closest ] . multi_transitions . size ( ) ; i + + ) {
int index = transition_lines [ closest ] . multi_transitions [ i ] . transition_index ;
Ref < AnimationNodeStateMachineTransition > transition = state_machine - > get_transition ( index ) ;
StringName from = transition_lines [ closest ] . multi_transitions [ i ] . from_node ;
StringName to = transition_lines [ closest ] . multi_transitions [ i ] . to_node ;
multi - > add_transition ( from , to , transition ) ;
}
EditorNode : : get_singleton ( ) - > push_item ( multi . ptr ( ) , " " , true ) ;
if ( ! state_machine - > is_transition_across_group ( closest ) ) {
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
} else {
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
EditorNode : : get_singleton ( ) - > push_item ( nullptr , " " , true ) ;
}
}
@ -296,11 +316,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Transition exists! " ) ) ;
connecting = false ;
} else {
if ( anodesm . is_valid ( ) | | end_node . is_valid ( ) ) {
_open_connect_menu ( mb - > get_position ( ) ) ;
} else {
_add_transition ( ) ;
}
_add_transition ( ) ;
}
} else {
_open_menu ( mb - > get_position ( ) ) ;
@ -481,12 +497,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
String from = String ( transition_lines [ closest ] . from_node ) ;
String to = String ( transition_lines [ closest ] . to_node ) ;
String tooltip = from + " -> " + to ;
for ( int i = 0 ; i < transition_lines [ closest ] . multi_transitions . size ( ) ; i + + ) {
from = String ( transition_lines [ closest ] . multi_transitions [ i ] . from_node ) ;
to = String ( transition_lines [ closest ] . multi_transitions [ i ] . to_node ) ;
tooltip + = " \n " + from + " -> " + to ;
}
state_machine_draw - > set_tooltip_text ( tooltip ) ;
} else {
state_machine_draw - > set_tooltip_text ( " " ) ;
@ -522,224 +532,6 @@ Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Poi
return cursor_shape ;
}
void AnimationNodeStateMachineEditor : : _group_selected_nodes ( ) {
if ( ! selected_nodes . is_empty ( ) ) {
if ( selected_nodes . size ( ) = = 1 & & ( * selected_nodes . begin ( ) = = state_machine - > start_node | | * selected_nodes . begin ( ) = = state_machine - > end_node ) )
return ;
Ref < AnimationNodeStateMachine > group_sm = memnew ( AnimationNodeStateMachine ) ;
Vector2 group_position ;
Vector < NodeUR > nodes_ur ;
Vector < TransitionUR > transitions_ur ;
int base = 1 ;
String base_name = group_sm - > get_caption ( ) ;
String group_name = base_name ;
while ( state_machine - > has_node ( group_name ) & & ! selected_nodes . has ( group_name ) ) {
base + + ;
group_name = base_name + " " + itos ( base ) ;
}
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( " Group " ) ;
// Move selected nodes to the new state machine
for ( const StringName & E : selected_nodes ) {
if ( ! state_machine - > can_edit_node ( E ) ) {
continue ;
}
Ref < AnimationNode > node = state_machine - > get_node ( E ) ;
Vector2 node_position = state_machine - > get_node_position ( E ) ;
group_position + = node_position ;
NodeUR new_node ;
new_node . name = E ;
new_node . node = node ;
new_node . position = node_position ;
nodes_ur . push_back ( new_node ) ;
}
// Add the transitions to the new state machine
for ( int i = 0 ; i < state_machine - > get_transition_count ( ) ; i + + ) {
String from = state_machine - > get_transition_from ( i ) ;
String to = state_machine - > get_transition_to ( i ) ;
String local_from = from . get_slicec ( ' / ' , 0 ) ;
String local_to = to . get_slicec ( ' / ' , 0 ) ;
String old_from = from ;
String old_to = to ;
bool from_selected = false ;
bool to_selected = false ;
if ( selected_nodes . has ( local_from ) & & local_from ! = state_machine - > start_node ) {
from_selected = true ;
}
if ( selected_nodes . has ( local_to ) & & local_to ! = state_machine - > end_node ) {
to_selected = true ;
}
if ( ! from_selected & & ! to_selected ) {
continue ;
}
Ref < AnimationNodeStateMachineTransition > tr = state_machine - > get_transition ( i ) ;
if ( ! from_selected ) {
from = " ../ " + old_from ;
}
if ( ! to_selected ) {
to = " ../ " + old_to ;
}
TransitionUR new_tr ;
new_tr . new_from = from ;
new_tr . new_to = to ;
new_tr . old_from = old_from ;
new_tr . old_to = old_to ;
new_tr . transition = tr ;
transitions_ur . push_back ( new_tr ) ;
}
for ( int i = 0 ; i < nodes_ur . size ( ) ; i + + ) {
undo_redo - > add_do_method ( state_machine . ptr ( ) , " remove_node " , nodes_ur [ i ] . name ) ;
undo_redo - > add_undo_method ( group_sm . ptr ( ) , " remove_node " , nodes_ur [ i ] . name ) ;
}
undo_redo - > add_do_method ( state_machine . ptr ( ) , " add_node " , group_name , group_sm , group_position / nodes_ur . size ( ) ) ;
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " remove_node " , group_name ) ;
for ( int i = 0 ; i < nodes_ur . size ( ) ; i + + ) {
undo_redo - > add_do_method ( group_sm . ptr ( ) , " add_node " , nodes_ur [ i ] . name , nodes_ur [ i ] . node , nodes_ur [ i ] . position ) ;
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " add_node " , nodes_ur [ i ] . name , nodes_ur [ i ] . node , nodes_ur [ i ] . position ) ;
}
for ( int i = 0 ; i < transitions_ur . size ( ) ; i + + ) {
undo_redo - > add_do_method ( group_sm . ptr ( ) , " add_transition " , transitions_ur [ i ] . new_from , transitions_ur [ i ] . new_to , transitions_ur [ i ] . transition ) ;
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " add_transition " , transitions_ur [ i ] . old_from , transitions_ur [ i ] . old_to , transitions_ur [ i ] . transition ) ;
}
undo_redo - > add_do_method ( this , " _update_graph " ) ;
undo_redo - > add_undo_method ( this , " _update_graph " ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
selected_nodes . clear ( ) ;
selected_nodes . insert ( group_name ) ;
state_machine_draw - > queue_redraw ( ) ;
accept_event ( ) ;
_update_mode ( ) ;
}
}
void AnimationNodeStateMachineEditor : : _ungroup_selected_nodes ( ) {
bool find = false ;
HashSet < StringName > new_selected_nodes ;
for ( const StringName & E : selected_nodes ) {
Ref < AnimationNodeStateMachine > group_sm = state_machine - > get_node ( E ) ;
if ( group_sm . is_valid ( ) ) {
find = true ;
Vector2 group_position = state_machine - > get_node_position ( E ) ;
StringName group_name = E ;
List < AnimationNode : : ChildNode > nodes ;
group_sm - > get_child_nodes ( & nodes ) ;
Vector < NodeUR > nodes_ur ;
Vector < TransitionUR > transitions_ur ;
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( " Ungroup " ) ;
// Move all child nodes to current state machine
for ( int i = 0 ; i < nodes . size ( ) ; i + + ) {
if ( ! group_sm - > can_edit_node ( nodes [ i ] . name ) ) {
continue ;
}
Vector2 node_position = group_sm - > get_node_position ( nodes [ i ] . name ) ;
NodeUR new_node ;
new_node . name = nodes [ i ] . name ;
new_node . position = node_position ;
new_node . node = nodes [ i ] . node ;
nodes_ur . push_back ( new_node ) ;
}
for ( int i = 0 ; i < group_sm - > get_transition_count ( ) ; i + + ) {
String from = group_sm - > get_transition_from ( i ) ;
String to = group_sm - > get_transition_to ( i ) ;
Ref < AnimationNodeStateMachineTransition > tr = group_sm - > get_transition ( i ) ;
TransitionUR new_tr ;
new_tr . new_from = from . replace_first ( " ../ " , " " ) ;
new_tr . new_to = to . replace_first ( " ../ " , " " ) ;
new_tr . old_from = from ;
new_tr . old_to = to ;
new_tr . transition = tr ;
transitions_ur . push_back ( new_tr ) ;
}
for ( int i = 0 ; i < nodes_ur . size ( ) ; i + + ) {
undo_redo - > add_do_method ( group_sm . ptr ( ) , " remove_node " , nodes_ur [ i ] . name ) ;
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " remove_node " , nodes_ur [ i ] . name ) ;
}
undo_redo - > add_do_method ( state_machine . ptr ( ) , " remove_node " , group_name ) ;
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " add_node " , group_name , group_sm , group_position ) ;
for ( int i = 0 ; i < nodes_ur . size ( ) ; i + + ) {
new_selected_nodes . insert ( nodes_ur [ i ] . name ) ;
undo_redo - > add_do_method ( state_machine . ptr ( ) , " add_node " , nodes_ur [ i ] . name , nodes_ur [ i ] . node , nodes_ur [ i ] . position ) ;
undo_redo - > add_undo_method ( group_sm . ptr ( ) , " add_node " , nodes_ur [ i ] . name , nodes_ur [ i ] . node , nodes_ur [ i ] . position ) ;
}
for ( int i = 0 ; i < transitions_ur . size ( ) ; i + + ) {
if ( transitions_ur [ i ] . old_from ! = state_machine - > start_node & & transitions_ur [ i ] . old_to ! = state_machine - > end_node ) {
undo_redo - > add_do_method ( state_machine . ptr ( ) , " add_transition " , transitions_ur [ i ] . new_from , transitions_ur [ i ] . new_to , transitions_ur [ i ] . transition ) ;
}
undo_redo - > add_undo_method ( group_sm . ptr ( ) , " add_transition " , transitions_ur [ i ] . old_from , transitions_ur [ i ] . old_to , transitions_ur [ i ] . transition ) ;
}
for ( int i = 0 ; i < state_machine - > get_transition_count ( ) ; i + + ) {
String from = state_machine - > get_transition_from ( i ) ;
String to = state_machine - > get_transition_to ( i ) ;
Ref < AnimationNodeStateMachineTransition > tr = state_machine - > get_transition ( i ) ;
if ( from = = group_name | | to = = group_name ) {
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " add_transition " , from , to , tr ) ;
}
}
undo_redo - > add_do_method ( this , " _update_graph " ) ;
undo_redo - > add_undo_method ( this , " _update_graph " ) ;
undo_redo - > commit_action ( ) ;
updating = false ;
}
}
if ( find ) {
selected_nodes = new_selected_nodes ;
selected_node = StringName ( ) ;
state_machine_draw - > queue_redraw ( ) ;
accept_event ( ) ;
_update_mode ( ) ;
}
}
void AnimationNodeStateMachineEditor : : _open_menu ( const Vector2 & p_position ) {
AnimationTree * tree = AnimationTreeEditor : : get_singleton ( ) - > get_animation_tree ( ) ;
if ( ! tree ) {
@ -790,83 +582,8 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
add_node_pos = p_position / EDSCALE + state_machine - > get_graph_offset ( ) ;
}
void AnimationNodeStateMachineEditor : : _open_connect_menu ( const Vector2 & p_position ) {
ERR_FAIL_COND ( connecting_to_node = = StringName ( ) ) ;
Ref < AnimationNode > node = state_machine - > get_node ( connecting_to_node ) ;
Ref < AnimationNodeStateMachine > anodesm = node ;
Ref < AnimationNodeEndState > end_node = node ;
ERR_FAIL_COND ( ! anodesm . is_valid ( ) & & ! end_node . is_valid ( ) ) ;
connect_menu - > clear ( ) ;
state_machine_menu - > clear ( ) ;
end_menu - > clear ( ) ;
nodes_to_connect . clear ( ) ;
for ( int i = connect_menu - > get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
Node * child = connect_menu - > get_child ( i ) ;
if ( child - > is_class ( " PopupMenu " ) ) {
connect_menu - > remove_child ( child ) ;
}
}
connect_menu - > reset_size ( ) ;
state_machine_menu - > reset_size ( ) ;
end_menu - > reset_size ( ) ;
if ( anodesm . is_valid ( ) ) {
_create_submenu ( connect_menu , anodesm , connecting_to_node , connecting_to_node ) ;
} else {
_create_submenu ( connect_menu , state_machine , connecting_to_node , connecting_to_node , true ) ;
}
connect_menu - > add_submenu_item ( TTR ( " To " ) + " Animation " , connecting_to_node ) ;
if ( state_machine_menu - > get_item_count ( ) > 0 | | ! end_node . is_valid ( ) ) {
connect_menu - > add_submenu_item ( TTR ( " To " ) + " StateMachine " , " state_machines " ) ;
connect_menu - > add_child ( state_machine_menu ) ;
}
if ( end_node . is_valid ( ) ) {
connect_menu - > add_submenu_item ( TTR ( " To " ) + " End " , " end_nodes " ) ;
connect_menu - > add_child ( end_menu ) ;
} else {
state_machine_menu - > add_item ( connecting_to_node , nodes_to_connect . size ( ) ) ;
}
nodes_to_connect . push_back ( connecting_to_node ) ;
if ( nodes_to_connect . size ( ) = = 1 ) {
_add_transition ( ) ;
return ;
}
connect_menu - > set_position ( state_machine_draw - > get_screen_transform ( ) . xform ( p_position ) ) ;
connect_menu - > popup ( ) ;
}
bool AnimationNodeStateMachineEditor : : _create_submenu ( PopupMenu * p_menu , Ref < AnimationNodeStateMachine > p_nodesm , const StringName & p_name , const StringName & p_path , bool from_root , Vector < Ref < AnimationNodeStateMachine > > p_parents ) {
bool AnimationNodeStateMachineEditor : : _create_submenu ( PopupMenu * p_menu , Ref < AnimationNodeStateMachine > p_nodesm , const StringName & p_name , const StringName & p_path ) {
String prev_path ;
Vector < Ref < AnimationNodeStateMachine > > parents = p_parents ;
if ( from_root & & p_nodesm - > get_prev_state_machine ( ) = = nullptr ) {
return false ;
}
if ( from_root ) {
AnimationNodeStateMachine * prev = p_nodesm - > get_prev_state_machine ( ) ;
while ( prev ! = nullptr ) {
parents . push_back ( prev ) ;
p_nodesm = Ref < AnimationNodeStateMachine > ( prev ) ;
prev_path + = " ../ " ;
prev = prev - > get_prev_state_machine ( ) ;
}
end_menu - > add_item ( " Root " , nodes_to_connect . size ( ) ) ;
nodes_to_connect . push_back ( prev_path + state_machine - > end_node ) ;
prev_path . remove_at ( prev_path . size ( ) - 1 ) ;
}
List < StringName > nodes ;
p_nodesm - > get_node_list ( & nodes ) ;
@ -881,12 +598,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
if ( p_nodesm - > can_edit_node ( E ) ) {
Ref < AnimationNodeStateMachine > ansm = p_nodesm - > get_node ( E ) ;
String path ;
if ( from_root ) {
path = prev_path + " / " + E ;
} else {
path = String ( p_path ) + " / " + E ;
}
String path = String ( p_path ) + " / " + E ;
if ( ansm = = state_machine ) {
end_menu - > add_item ( E , nodes_to_connect . size ( ) ) ;
@ -895,25 +607,10 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
}
if ( ansm . is_valid ( ) ) {
bool parent_found = false ;
for ( int i = 0 ; i < parents . size ( ) ; i + + ) {
if ( parents [ i ] = = ansm ) {
path = path . replace_first ( " /../ " + E , " " ) ;
parent_found = true ;
break ;
}
}
if ( parent_found ) {
end_menu - > add_item ( E , nodes_to_connect . size ( ) ) ;
nodes_to_connect . push_back ( path + " / " + state_machine - > end_node ) ;
} else {
state_machine_menu - > add_item ( E , nodes_to_connect . size ( ) ) ;
nodes_to_connect . push_back ( path ) ;
}
state_machine_menu - > add_item ( E , nodes_to_connect . size ( ) ) ;
nodes_to_connect . push_back ( path ) ;
if ( _create_submenu ( nodes_menu , ansm , E , path , false , parents )) {
if ( _create_submenu ( nodes_menu , ansm , E , path ) ) {
nodes_menu - > add_submenu_item ( E , E ) ;
node_added = true ;
}
@ -939,7 +636,6 @@ void AnimationNodeStateMachineEditor::_delete_selected() {
while ( item ) {
if ( ! updating ) {
updating = true ;
selected_multi_transition = TransitionLine ( ) ;
undo_redo - > create_action ( " Transition(s) Removed " ) ;
}
@ -959,18 +655,10 @@ void AnimationNodeStateMachineEditor::_delete_selected() {
}
void AnimationNodeStateMachineEditor : : _delete_all ( ) {
Vector < TransitionLine > multi_transitions = selected_multi_transition . multi_transitions ;
selected_multi_transition = TransitionLine ( ) ;
updating = true ;
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( " Transition(s) Removed " ) ;
_erase_selected ( true ) ;
for ( int i = 0 ; i < multi_transitions . size ( ) ; i + + ) {
selected_transition_from = multi_transitions [ i ] . from_node ;
selected_transition_to = multi_transitions [ i ] . to_node ;
_erase_selected ( true ) ;
}
undo_redo - > commit_action ( ) ;
updating = false ;
@ -1120,14 +808,19 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
selected_transition_to = connecting_to_node ;
selected_transition_index = transition_lines . size ( ) ;
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
if ( ! state_machine - > is_transition_across_group ( selected_transition_index ) ) {
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
} else {
EditorNode : : get_singleton ( ) - > push_item ( tr . ptr ( ) , " " , true ) ;
EditorNode : : get_singleton ( ) - > push_item ( nullptr , " " , true ) ;
}
_update_mode ( ) ;
}
connecting = false ;
}
void AnimationNodeStateMachineEditor : : _connection_draw ( const Vector2 & p_from , const Vector2 & p_to , AnimationNodeStateMachineTransition : : SwitchMode p_mode , bool p_enabled , bool p_selected , bool p_travel , float p_fade_ratio , bool p_auto_advance , bool p_ multi_transitions ) {
void AnimationNodeStateMachineEditor : : _connection_draw ( const Vector2 & p_from , const Vector2 & p_to , AnimationNodeStateMachineTransition : : SwitchMode p_mode , bool p_enabled , bool p_selected , bool p_travel , float p_fade_ratio , bool p_auto_advance , bool p_ is_across_group ) {
Color linecolor = get_theme_color ( SNAME ( " font_color " ) , SNAME ( " Label " ) ) ;
Color icon_color ( 1 , 1 , 1 ) ;
Color accent = get_theme_color ( SNAME ( " accent_color " ) , SNAME ( " Editor " ) ) ;
@ -1173,11 +866,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
xf . columns [ 2 ] = ( p_from + p_to ) * 0.5 - xf . columns [ 1 ] * icon - > get_height ( ) * 0.5 - xf . columns [ 0 ] * icon - > get_height ( ) * 0.5 ;
state_machine_draw - > draw_set_transform_matrix ( xf ) ;
if ( p_multi_transitions ) {
state_machine_draw - > draw_texture ( icons [ 0 ] , Vector2 ( - icon - > get_width ( ) , 0 ) , icon_color ) ;
state_machine_draw - > draw_texture ( icons [ 0 ] , Vector2 ( ) , icon_color ) ;
state_machine_draw - > draw_texture ( icons [ 0 ] , Vector2 ( icon - > get_width ( ) , 0 ) , icon_color ) ;
} else {
if ( ! p_is_across_group ) {
state_machine_draw - > draw_texture ( icon , Vector2 ( ) , icon_color ) ;
}
state_machine_draw - > draw_set_transform_matrix ( Transform2D ( ) ) ;
@ -1344,17 +1033,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
for ( int i = 0 ; i < state_machine - > get_transition_count ( ) ; i + + ) {
TransitionLine tl ;
tl . transition_index = i ;
tl . from_node = state_machine - > get_transition_from ( i ) ;
StringName local_from = String ( tl . from_node ) . get_slicec ( ' / ' , 0 ) ;
local_from = local_from = = " .. " ? state_machine - > start_node : local_from ;
Vector2 ofs_from = ( dragging_selected & & selected_nodes . has ( local_from ) ) ? drag_ofs : Vector2 ( ) ;
tl . from = ( state_machine - > get_node_position ( local_from ) * EDSCALE ) + ofs_from - state_machine - > get_graph_offset ( ) * EDSCALE ;
Vector2 ofs_from = ( dragging_selected & & selected_nodes . has ( tl . from_node ) ) ? drag_ofs : Vector2 ( ) ;
tl . from = ( state_machine - > get_node_position ( tl . from_node ) * EDSCALE ) + ofs_from - state_machine - > get_graph_offset ( ) * EDSCALE ;
tl . to_node = state_machine - > get_transition_to ( i ) ;
StringName local_to = String ( tl . to_node ) . get_slicec ( ' / ' , 0 ) ;
local_to = local_to = = " .. " ? state_machine - > end_node : local_to ;
Vector2 ofs_to = ( dragging_selected & & selected_nodes . has ( local_to ) ) ? drag_ofs : Vector2 ( ) ;
tl . to = ( state_machine - > get_node_position ( local_to ) * EDSCALE ) + ofs_to - state_machine - > get_graph_offset ( ) * EDSCALE ;
Vector2 ofs_to = ( dragging_selected & & selected_nodes . has ( tl . to_node ) ) ? drag_ofs : Vector2 ( ) ;
tl . to = ( state_machine - > get_node_position ( tl . to_node ) * EDSCALE ) + ofs_to - state_machine - > get_graph_offset ( ) * EDSCALE ;
Ref < AnimationNodeStateMachineTransition > tr = state_machine - > get_transition ( i ) ;
tl . disabled = bool ( tr - > get_advance_mode ( ) = = AnimationNodeStateMachineTransition : : ADVANCE_MODE_DISABLED ) ;
@ -1366,35 +1052,36 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl . travel = false ;
tl . fade_ratio = 0.0 ;
tl . hidden = false ;
tl . is_across_group = state_machine - > is_transition_across_group ( i ) ;
if ( state_machine - > has_ local_transition( local_to , local_from ) ) { //offset if same exists
if ( state_machine - > has_ transition( tl . to_node , tl . from_node ) ) { //offset if same exists
Vector2 offset = - ( tl . from - tl . to ) . normalized ( ) . orthogonal ( ) * tr_bidi_offset ;
tl . from + = offset ;
tl . to + = offset ;
}
for ( int j = 0 ; j < node_rects . size ( ) ; j + + ) {
if ( node_rects [ j ] . node_name = = local_from ) {
if ( node_rects [ j ] . node_name = = tl. from_node ) {
_clip_src_line_to_rect ( tl . from , tl . to , node_rects [ j ] . node ) ;
}
if ( node_rects [ j ] . node_name = = local_to ) {
if ( node_rects [ j ] . node_name = = tl. to_node ) {
_clip_dst_line_to_rect ( tl . from , tl . to , node_rects [ j ] . node ) ;
}
}
tl . selected = selected_transition_from = = tl . from_node & & selected_transition_to = = tl . to_node ;
if ( blend_from = = local_from & & current = = local_to ) {
if ( blend_from = = tl. from_node & & current = = tl . to_node ) {
tl . travel = true ;
tl . fade_ratio = MIN ( 1.0 , fading_pos / fading_time ) ;
}
if ( travel_path . size ( ) ) {
if ( current = = local_from & & travel_path [ 0 ] = = local_to ) {
if ( current = = tl. from_node & & travel_path [ 0 ] = = tl. to_node ) {
tl . travel = true ;
} else {
for ( int j = 0 ; j < travel_path . size ( ) - 1 ; j + + ) {
if ( travel_path [ j ] = = local_from & & travel_path [ j + 1 ] = = local_to ) {
if ( travel_path [ j ] = = tl. from_node & & travel_path [ j + 1 ] = = tl. to_node ) {
tl . travel = true ;
break ;
}
@ -1408,17 +1095,11 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl . auto_advance = true ;
}
// check if already have this local transition
// check if already have this transition
for ( int j = 0 ; j < transition_lines . size ( ) ; j + + ) {
StringName from = String ( transition_lines [ j ] . from_node ) . get_slicec ( ' / ' , 0 ) ;
StringName to = String ( transition_lines [ j ] . to_node ) . get_slicec ( ' / ' , 0 ) ;
from = from = = " .. " ? state_machine - > start_node : from ;
to = to = = " .. " ? state_machine - > end_node : to ;
if ( from = = local_from & & to = = local_to ) {
if ( transition_lines [ j ] . from_node = = tl . from_node & & transition_lines [ j ] . to_node = = tl . to_node ) {
tl . hidden = true ;
transition_lines . write [ j ] . disabled = transition_lines [ j ] . disabled & & tl . disabled ;
transition_lines . write [ j ] . multi_transitions . push_back ( tl ) ;
}
}
transition_lines . push_back ( tl ) ;
@ -1427,7 +1108,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
for ( int i = 0 ; i < transition_lines . size ( ) ; i + + ) {
TransitionLine tl = transition_lines [ i ] ;
if ( ! tl . hidden ) {
_connection_draw ( tl . from , tl . to , tl . mode , ! tl . disabled , tl . selected , tl . travel , tl . fade_ratio , tl . auto_advance , ! tl . multi_transitions . is_empty ( ) ) ;
_connection_draw ( tl . from , tl . to , tl . mode , ! tl . disabled , tl . selected , tl . travel , tl . fade_ratio , tl . auto_advance , tl . is_across_group ) ;
}
}
@ -1481,6 +1162,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
state_machine_draw - > draw_string ( font , nr . name . position + Vector2 ( 0 , font - > get_ascent ( font_size ) ) , name , HORIZONTAL_ALIGNMENT_LEFT , - 1 , font_size , font_color ) ;
offset . x + = strsize + sep ;
nr . can_edit = needs_editor ;
if ( needs_editor ) {
nr . edit . position = offset + Vector2 ( 0 , ( h - edit - > get_height ( ) ) / 2 ) . floor ( ) ;
nr . edit . size = edit - > get_size ( ) ;
@ -1546,6 +1228,10 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String
const NodeRect & nr = node_rects [ idx ] ;
if ( nr . can_edit ) {
return ; // It is not AnimationNodeAnimation.
}
Vector2 from ;
from . x = nr . play . position . x ;
from . y = ( nr . play . position . y + nr . play . size . y + nr . node . position . y + nr . node . size . y ) * 0.5 ;
@ -1584,14 +1270,14 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() {
{
float len = MAX ( 0.0001 , current_length ) ;
float pos = CLAMP ( current_play_pos , 0 , len ) ;
float c = pos / len ;
float c = current_length = = HUGE_LENGTH ? 1 : ( pos / len ) ;
_state_machine_pos_draw_individual ( playback - > get_current_node ( ) , c ) ;
}
{
float len = MAX ( 0.0001 , fade_from_length ) ;
float pos = CLAMP ( fade_from_current_play_pos , 0 , len ) ;
float c = pos / len ;
float c = fade_from_length = = HUGE_LENGTH ? 1 : ( pos / len ) ;
_state_machine_pos_draw_individual ( playback - > get_fading_from_node ( ) , c ) ;
}
}
@ -1630,8 +1316,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
auto_advance - > set_icon ( get_theme_icon ( SNAME ( " AutoPlay " ) , SNAME ( " EditorIcons " ) ) ) ;
tool_erase - > set_icon ( get_theme_icon ( SNAME ( " Remove " ) , SNAME ( " EditorIcons " ) ) ) ;
tool_group - > set_icon ( get_theme_icon ( SNAME ( " Group " ) , SNAME ( " EditorIcons " ) ) ) ;
tool_ungroup - > set_icon ( get_theme_icon ( SNAME ( " Ungroup " ) , SNAME ( " EditorIcons " ) ) ) ;
play_mode - > clear ( ) ;
play_mode - > add_icon_item ( get_theme_icon ( SNAME ( " PlayTravel " ) , SNAME ( " EditorIcons " ) ) , TTR ( " Travel " ) ) ;
@ -1655,10 +1339,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
error = TTR ( " AnimationTree is inactive. \n Activate to enable playback, check node warnings if activation fails. " ) ;
} else if ( tree - > is_state_invalid ( ) ) {
error = tree - > get_invalid_state_reason ( ) ;
/*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
if ( state_machine - > get_start_node ( ) = = StringName ( ) | | state_machine - > get_end_node ( ) = = StringName ( ) ) {
error = TTR ( " Start and end nodes are needed for a sub-transition. " ) ;
} */
} else if ( playback . is_null ( ) ) {
error = vformat ( TTR ( " No playback resource set at path: %s. " ) , AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + " playback " ) ;
}
@ -1780,8 +1460,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
while ( anodesm . is_valid ( ) ) {
current_node_playback = tree - > get ( AnimationTreeEditor : : get_singleton ( ) - > get_base_path ( ) + next + " /playback " ) ;
next + = " / " + current_node_playback - > get_current_node ( ) ;
anodesm = anodesm - > get_node ( current_node_playback - > get_current_node ( ) ) ;
StringName cnode = current_node_playback - > get_current_node ( ) ;
next + = " / " + cnode ;
if ( ! anodesm - > has_node ( cnode ) ) {
break ;
}
anodesm = anodesm - > get_node ( cnode ) ;
}
// when current_node is a state machine, use playback of current_node to set play_pos
@ -1883,10 +1567,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
for ( int j = 0 ; j < state_machine - > get_transition_count ( ) ; j + + ) {
String from = state_machine - > get_transition_from ( j ) ;
String to = state_machine - > get_transition_to ( j ) ;
String local_from = from . get_slicec ( ' / ' , 0 ) ;
String local_to = to . get_slicec ( ' / ' , 0 ) ;
if ( local_from = = node_rects [ i ] . node_name | | local_to = = node_rects [ i ] . node_name ) {
if ( from = = node_rects [ i ] . node_name | | to = = node_rects [ i ] . node_name ) {
undo_redo - > add_undo_method ( state_machine . ptr ( ) , " add_transition " , from , to , state_machine - > get_transition ( j ) ) ;
}
}
@ -1903,30 +1584,6 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
selected_nodes . clear ( ) ;
}
if ( ! selected_multi_transition . multi_transitions . is_empty ( ) ) {
delete_tree - > clear ( ) ;
TreeItem * root = delete_tree - > create_item ( ) ;
TreeItem * item = delete_tree - > create_item ( root ) ;
item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
item - > set_text ( 0 , String ( selected_transition_from ) + " -> " + selected_transition_to ) ;
item - > set_editable ( 0 , true ) ;
for ( int i = 0 ; i < selected_multi_transition . multi_transitions . size ( ) ; i + + ) {
String from = selected_multi_transition . multi_transitions [ i ] . from_node ;
String to = selected_multi_transition . multi_transitions [ i ] . to_node ;
item = delete_tree - > create_item ( root ) ;
item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
item - > set_text ( 0 , from + " -> " + to ) ;
item - > set_editable ( 0 , true ) ;
}
delete_window - > popup_centered ( Vector2 ( 400 , 200 ) ) ;
return ;
}
if ( selected_transition_to ! = StringName ( ) & & selected_transition_from ! = StringName ( ) & & state_machine - > has_transition ( selected_transition_from , selected_transition_to ) ) {
Ref < AnimationNodeStateMachineTransition > tr = state_machine - > get_transition ( state_machine - > find_transition ( selected_transition_from , selected_transition_to ) ) ;
if ( ! p_nested_action ) {
@ -1945,7 +1602,6 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
selected_transition_from = StringName ( ) ;
selected_transition_to = StringName ( ) ;
selected_transition_index = - 1 ;
selected_multi_transition = TransitionLine ( ) ;
}
state_machine_draw - > queue_redraw ( ) ;
@ -1957,24 +1613,6 @@ void AnimationNodeStateMachineEditor::_update_mode() {
bool nothing_selected = selected_nodes . is_empty ( ) & & selected_transition_from = = StringName ( ) & & selected_transition_to = = StringName ( ) ;
bool start_end_selected = selected_nodes . size ( ) = = 1 & & ( * selected_nodes . begin ( ) = = state_machine - > start_node | | * selected_nodes . begin ( ) = = state_machine - > end_node ) ;
tool_erase - > set_disabled ( nothing_selected | | start_end_selected | | read_only ) ;
if ( selected_nodes . is_empty ( ) | | start_end_selected | | read_only ) {
tool_group - > set_disabled ( true ) ;
tool_group - > set_visible ( true ) ;
tool_ungroup - > set_visible ( false ) ;
} else {
Ref < AnimationNodeStateMachine > ansm = state_machine - > get_node ( * selected_nodes . begin ( ) ) ;
if ( selected_nodes . size ( ) = = 1 & & ansm . is_valid ( ) ) {
tool_group - > set_disabled ( true ) ;
tool_group - > set_visible ( false ) ;
tool_ungroup - > set_visible ( true ) ;
} else {
tool_group - > set_disabled ( false ) ;
tool_group - > set_visible ( true ) ;
tool_ungroup - > set_visible ( false ) ;
}
}
} else {
selection_tools_hb - > hide ( ) ;
}
@ -2037,20 +1675,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
top_hb - > add_child ( selection_tools_hb ) ;
selection_tools_hb - > add_child ( memnew ( VSeparator ) ) ;
tool_group = memnew ( Button ) ;
tool_group - > set_flat ( true ) ;
tool_group - > set_tooltip_text ( TTR ( " Group Selected Node(s) " ) + " (Ctrl+G) " ) ;
tool_group - > connect ( " pressed " , callable_mp ( this , & AnimationNodeStateMachineEditor : : _group_selected_nodes ) ) ;
tool_group - > set_disabled ( true ) ;
selection_tools_hb - > add_child ( tool_group ) ;
tool_ungroup = memnew ( Button ) ;
tool_ungroup - > set_flat ( true ) ;
tool_ungroup - > set_tooltip_text ( TTR ( " Ungroup Selected Node " ) + " (Ctrl+Shift+G) " ) ;
tool_ungroup - > connect ( " pressed " , callable_mp ( this , & AnimationNodeStateMachineEditor : : _ungroup_selected_nodes ) ) ;
tool_ungroup - > set_visible ( false ) ;
selection_tools_hb - > add_child ( tool_ungroup ) ;
tool_erase = memnew ( Button ) ;
tool_erase - > set_flat ( true ) ;
tool_erase - > set_tooltip_text ( TTR ( " Remove selected node or transition. " ) ) ;