-Added trigger mode to tracks, useful for properties that work as triggers, such as playing a sample, an animation, etc.

-Better interpolation of discrete tracks, fixes #4417
This commit is contained in:
Juan Linietsky 2016-06-19 01:43:02 -03:00
parent 29177e1e9b
commit 7c20c386c5
12 changed files with 105 additions and 57 deletions

View File

@ -88,6 +88,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_RESTART_IF_CHANGED=4096,
PROPERTY_USAGE_SCRIPT_VARIABLE=8192,
PROPERTY_USAGE_STORE_IF_NULL=16384,
PROPERTY_USAGE_ANIMATE_AS_TRIGGER=32768,
PROPERTY_USAGE_DEFAULT=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_INTERNATIONALIZED,

View File

@ -81,7 +81,7 @@ void SamplePlayer2D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR));
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_ANIMATE_AS_TRIGGER));
}
void SamplePlayer2D::_notification(int p_what) {

View File

@ -82,7 +82,7 @@ void SpatialSamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR));
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_ANIMATE_AS_TRIGGER));
}
void SpatialSamplePlayer::_notification(int p_what) {

View File

@ -301,7 +301,7 @@ void AnimationCache::set_all(float p_time, float p_delta) {
} break;
case Animation::TYPE_VALUE: {
if (animation->value_track_is_continuous(i)) {
if (animation->value_track_get_update_mode(i)==Animation::UPDATE_CONTINUOUS || (animation->value_track_get_update_mode(i)==Animation::UPDATE_DISCRETE && p_delta==0)) {
Variant v = animation->value_track_interpolate(i,p_time);
set_track_value(i,v);
} else {

View File

@ -174,7 +174,7 @@ void AnimationPlayer::_get_property_list( List<PropertyInfo> *p_list) const {
hint+=E->get();
}
p_list->push_back( PropertyInfo( Variant::STRING, "playback/play", PROPERTY_HINT_ENUM, hint,PROPERTY_USAGE_EDITOR) );
p_list->push_back( PropertyInfo( Variant::STRING, "playback/play", PROPERTY_HINT_ENUM, hint,PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_ANIMATE_AS_TRIGGER) );
p_list->push_back( PropertyInfo( Variant::BOOL, "playback/active", PROPERTY_HINT_NONE,"" ) );
p_list->push_back( PropertyInfo( Variant::REAL, "playback/speed", PROPERTY_HINT_RANGE, "-64,64,0.01") );
@ -421,12 +421,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
TrackNodeCache::PropertyAnim *pa = &E->get();
if (a->value_track_is_continuous(i) || p_delta==0) { //delta == 0 means seek
if (a->value_track_get_update_mode(i)==Animation::UPDATE_CONTINUOUS || (p_delta==0 && a->value_track_get_update_mode(i)==Animation::UPDATE_DISCRETE)) { //delta == 0 means seek
Variant value=a->value_track_interpolate(i,p_time);
if (p_delta==0 && value.get_type()==Variant::STRING)
continue; // doing this with strings is messy, should find another way
//thanks to trigger mode, this should be solved now..
//if (p_delta==0 && value.get_type()==Variant::STRING)
// continue; // doing this with strings is messy, should find another way
if (pa->accum_pass!=accum_pass) {
ERR_CONTINUE( cache_update_prop_size >= NODE_CACHE_UPDATE_MAX );
cache_update_prop[cache_update_prop_size++]=pa;
@ -437,11 +438,12 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
}
} else if (p_allow_discrete) {
} else if (p_allow_discrete && p_delta!=0) {
List<int> indices;
a->value_track_get_key_indices(i,p_time,p_delta,&indices);
for(List<int>::Element *F=indices.front();F;F=F->next()) {
Variant value=a->track_get_key_value(i,F->get());

View File

@ -825,7 +825,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
} break;
case Animation::TYPE_VALUE: { ///< Set a value in a property, can be interpolated.
if (a->value_track_is_continuous(tr.local_track)) {
if (a->value_track_get_update_mode(tr.local_track)==Animation::UPDATE_CONTINUOUS) {
Variant value = a->value_track_interpolate(tr.local_track,anim_list->time);
Variant::blend(tr.track->value,value,blend,tr.track->value);
} else {

View File

@ -152,7 +152,7 @@ void SamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR));
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_ANIMATE_AS_TRIGGER));
p_list->push_back( PropertyInfo( Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,256,1"));
p_list->push_back( PropertyInfo( Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE, "SampleLibrary"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"));

View File

@ -154,8 +154,20 @@ bool Animation::_set(const StringName& p_name, const Variant& p_value) {
Dictionary d = p_value;
ERR_FAIL_COND_V(!d.has("times"),false);
ERR_FAIL_COND_V(!d.has("values"),false);
if (d.has("cont"))
vt->continuous=d["cont"];
if (d.has("cont")) {
bool v = d["cont"];
vt->update_mode=v?UPDATE_CONTINUOUS:UPDATE_DISCRETE;
}
if (d.has("update")) {
int um =d["update"];
if (um<0)
um=0;
else if (um>2)
um=2;
vt->update_mode=UpdateMode(um);
}
DVector<float> times=d["times"];
Array values=d["values"];
@ -353,7 +365,7 @@ bool Animation::_get(const StringName& p_name,Variant &r_ret) const {
d["transitions"]=key_transitions;
d["values"]=key_values;
if (track_get_type(track)==TYPE_VALUE) {
d["cont"]=value_track_is_continuous(track);
d["update"]=value_track_get_update_mode(track);
}
r_ret=d;
@ -394,7 +406,7 @@ bool Animation::_get(const StringName& p_name,Variant &r_ret) const {
d["transitions"]=key_transitions;
d["values"]=key_values;
if (track_get_type(track)==TYPE_VALUE) {
d["cont"]=value_track_is_continuous(track);
d["update"]=value_track_get_update_mode(track);
}
r_ret=d;
@ -1373,7 +1385,7 @@ Variant Animation::value_track_interpolate(int p_track, float p_time) const {
bool ok;
Variant res = _interpolate( vt->values, p_time, vt->interpolation, &ok );
Variant res = _interpolate( vt->values, p_time, vt->update_mode==UPDATE_CONTINUOUS?vt->interpolation:INTERPOLATION_NEAREST, &ok );
if (ok) {
@ -1461,28 +1473,30 @@ void Animation::value_track_get_key_indices(int p_track, float p_time, float p_d
}
void Animation::value_track_set_continuous(int p_track, bool p_continuous) {
void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t=tracks[p_track];
ERR_FAIL_COND( t->type != TYPE_VALUE );
ERR_FAIL_INDEX(p_mode,3);
ValueTrack * vt = static_cast<ValueTrack*>(t);
vt->continuous=p_continuous;
vt->update_mode=p_mode;
}
bool Animation::value_track_is_continuous(int p_track) const{
Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), false);
ERR_FAIL_INDEX_V(p_track, tracks.size(), UPDATE_CONTINUOUS);
Track *t=tracks[p_track];
ERR_FAIL_COND_V( t->type != TYPE_VALUE, false );
ERR_FAIL_COND_V( t->type != TYPE_VALUE, UPDATE_CONTINUOUS );
ValueTrack * vt = static_cast<ValueTrack*>(t);
return vt->continuous;
return vt->update_mode;
}
void Animation::_method_track_get_key_indices_in_range(const MethodTrack * mt, float from_time, float to_time,List<int> *p_indices) const {
if (from_time!=length && to_time==length)
@ -1676,8 +1690,8 @@ void Animation::_bind_methods() {
ObjectTypeDB::bind_method(_MD("transform_track_interpolate","idx","time_sec"),&Animation::_transform_track_interpolate);
ObjectTypeDB::bind_method(_MD("value_track_set_continuous","idx","continuous"),&Animation::value_track_set_continuous);
ObjectTypeDB::bind_method(_MD("value_track_is_continuous","idx"),&Animation::value_track_is_continuous);
ObjectTypeDB::bind_method(_MD("value_track_set_update_mode","idx","mode"),&Animation::value_track_set_update_mode);
ObjectTypeDB::bind_method(_MD("value_track_get_update_mode","idx"),&Animation::value_track_get_update_mode);
ObjectTypeDB::bind_method(_MD("value_track_get_key_indices","idx","time_sec","delta"),&Animation::_value_track_get_key_indices);
@ -1704,6 +1718,11 @@ void Animation::_bind_methods() {
BIND_CONSTANT( INTERPOLATION_LINEAR );
BIND_CONSTANT( INTERPOLATION_CUBIC );
BIND_CONSTANT( UPDATE_CONTINUOUS );
BIND_CONSTANT( UPDATE_DISCRETE );
BIND_CONSTANT( UPDATE_TRIGGER );
}
void Animation::clear() {

View File

@ -58,6 +58,13 @@ public:
INTERPOLATION_CUBIC
};
enum UpdateMode {
UPDATE_CONTINUOUS,
UPDATE_DISCRETE,
UPDATE_TRIGGER,
};
private:
struct Track {
@ -105,10 +112,11 @@ private:
struct ValueTrack : public Track {
bool continuous;
UpdateMode update_mode;
bool update_on_seek;
Vector< TKey<Variant> > values;
ValueTrack() { type=TYPE_VALUE; continuous=true; }
ValueTrack() { type=TYPE_VALUE; update_mode=UPDATE_CONTINUOUS; }
};
@ -253,8 +261,9 @@ public:
Variant value_track_interpolate(int p_track, float p_time) const;
void value_track_get_key_indices(int p_track, float p_time, float p_delta,List<int> *p_indices) const;
void value_track_set_continuous(int p_track, bool p_continuous);
bool value_track_is_continuous(int p_track) const;
void value_track_set_update_mode(int p_track, UpdateMode p_mode);
UpdateMode value_track_get_update_mode(int p_track) const;
void method_track_get_key_indices(int p_track, float p_time, float p_delta,List<int> *p_indices) const;
Vector<Variant> method_track_get_params(int p_track,int p_key_idx) const;
@ -281,5 +290,8 @@ public:
VARIANT_ENUM_CAST( Animation::TrackType );
VARIANT_ENUM_CAST( Animation::InterpolationType );
VARIANT_ENUM_CAST( Animation::UpdateMode );
#endif

View File

@ -754,7 +754,7 @@ void AnimationKeyEditor::_menu_track(int p_type) {
undo_redo->add_undo_method(animation.ptr(),"track_set_interpolation_type",idx,animation->track_get_interpolation_type(idx));
if (animation->track_get_type(idx)==Animation::TYPE_VALUE) {
undo_redo->add_undo_method(animation.ptr(),"value_track_set_continuous",idx,animation->value_track_is_continuous(idx));
undo_redo->add_undo_method(animation.ptr(),"value_track_set_update_mode",idx,animation->value_track_get_update_mode(idx));
}
@ -918,7 +918,7 @@ void AnimationKeyEditor::_menu_track(int p_type) {
pos=animation->get_length();
timeline_pos=pos;
track_pos->update();
emit_signal("timeline_changed",pos);
emit_signal("timeline_changed",pos,true);
} break;
case TRACK_MENU_PREV_STEP: {
@ -934,7 +934,7 @@ void AnimationKeyEditor::_menu_track(int p_type) {
pos=0;
timeline_pos=pos;
track_pos->update();
emit_signal("timeline_changed",pos);
emit_signal("timeline_changed",pos,true);
} break;
@ -1169,8 +1169,9 @@ void AnimationKeyEditor::_track_editor_draw() {
get_icon("InterpCubic","EditorIcons")
};
Ref<Texture> cont_icon[3]={
get_icon("TrackContinuous","EditorIcons"),
get_icon("TrackDiscrete","EditorIcons"),
get_icon("TrackContinuous","EditorIcons")
get_icon("TrackTrigger","EditorIcons")
};
Ref<Texture> type_icon[3]={
get_icon("KeyValue","EditorIcons"),
@ -1442,15 +1443,15 @@ void AnimationKeyEditor::_track_editor_draw() {
if (animation->track_get_type(idx)==Animation::TYPE_VALUE) {
int continuous = animation->value_track_is_continuous(idx)?1:0;
int umode = animation->value_track_get_update_mode(idx);
icon_ofs.x-=hsep;
icon_ofs.x-=down_icon->get_width();
te->draw_texture(down_icon,icon_ofs);
icon_ofs.x-=hsep;
icon_ofs.x-=cont_icon[continuous]->get_width();
te->draw_texture(cont_icon[continuous],icon_ofs);
icon_ofs.x-=cont_icon[umode]->get_width();
te->draw_texture(cont_icon[umode],icon_ofs);
} else {
icon_ofs.x -= hsep*2 + cont_icon[0]->get_width() + down_icon->get_width();
@ -1626,8 +1627,8 @@ void AnimationKeyEditor::_track_menu_selected(int p_idx) {
ERR_FAIL_INDEX(cont_editing,animation->get_track_count());
undo_redo->create_action(TTR("Anim Track Change Value Mode"));
undo_redo->add_do_method(animation.ptr(),"value_track_set_continuous",cont_editing,p_idx);
undo_redo->add_undo_method(animation.ptr(),"value_track_set_continuous",cont_editing,animation->value_track_is_continuous(cont_editing));
undo_redo->add_do_method(animation.ptr(),"value_track_set_update_mode",cont_editing,p_idx);
undo_redo->add_undo_method(animation.ptr(),"value_track_set_update_mode",cont_editing,animation->value_track_get_update_mode(cont_editing));
undo_redo->commit_action();
}
@ -1820,8 +1821,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
get_icon("InterpCubic","EditorIcons")
};
Ref<Texture> cont_icon[3]={
get_icon("TrackContinuous","EditorIcons"),
get_icon("TrackDiscrete","EditorIcons"),
get_icon("TrackContinuous","EditorIcons")
get_icon("TrackTrigger","EditorIcons")
};
Ref<Texture> type_icon[3]={
get_icon("KeyValue","EditorIcons"),
@ -1972,7 +1974,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
click.click=ClickOver::CLICK_DRAG_TIMELINE;
click.at=Point2(mb.x,mb.y);
click.to=click.at;
emit_signal("timeline_changed",pos);
emit_signal("timeline_changed",pos,false);
}
@ -2184,8 +2186,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
track_menu->clear();
track_menu->set_size(Point2(1,1));
static const char *cont_name[3]={"Discrete","Continuous"};
for(int i=0;i<2;i++) {
String cont_name[3]={TTR("Continuous"),TTR("Discrete"),TTR("Trigger")};
for(int i=0;i<3;i++) {
track_menu->add_icon_item(cont_icon[i],cont_name[i]);
}
@ -2594,7 +2596,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
timeline_pos=pos;
emit_signal("timeline_changed",pos);
emit_signal("timeline_changed",pos,true);
@ -2940,8 +2942,9 @@ void AnimationKeyEditor::_notification(int p_what) {
get_icon("InterpCubic","EditorIcons")
};
Ref<Texture> cont_icon[3]={
get_icon("TrackContinuous","EditorIcons"),
get_icon("TrackDiscrete","EditorIcons"),
get_icon("TrackContinuous","EditorIcons")
get_icon("TrackTrigger","EditorIcons")
};
//right_data_size_cache = remove_icon->get_width() + move_up_icon->get_width() + move_down_icon->get_width() + down_icon->get_width() *2 + interp_icon[0]->get_width() + cont_icon[0]->get_width() + add_key_icon->get_width() + hsep*11;
@ -3311,7 +3314,7 @@ int AnimationKeyEditor::_confirm_insert(InsertData p_id,int p_last_track) {
created=true;
undo_redo->create_action(TTR("Anim Insert Track & Key"));
bool continuous=false;
Animation::UpdateMode update_mode=Animation::UPDATE_DISCRETE;
if (p_id.type==Animation::TYPE_VALUE) {
//wants a new tack
@ -3324,16 +3327,21 @@ int AnimationKeyEditor::_confirm_insert(InsertData p_id,int p_last_track) {
PropertyInfo h = _find_hint_for_track(animation->get_track_count()-1,np);
animation->remove_track(animation->get_track_count()-1); //hack
continuous =
h.type==Variant::REAL ||
if ( h.type==Variant::REAL ||
h.type==Variant::VECTOR2 ||
h.type==Variant::RECT2 ||
h.type==Variant::VECTOR3 ||
h.type==Variant::_AABB ||
h.type==Variant::QUAT ||
h.type==Variant::COLOR ||
h.type==Variant::TRANSFORM ;
h.type==Variant::TRANSFORM ) {
update_mode=Animation::UPDATE_CONTINUOUS;
}
if (h.usage&PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
update_mode=Animation::UPDATE_TRIGGER;
}
}
}
@ -3342,7 +3350,7 @@ int AnimationKeyEditor::_confirm_insert(InsertData p_id,int p_last_track) {
undo_redo->add_do_method(animation.ptr(),"add_track",p_id.type);
undo_redo->add_do_method(animation.ptr(),"track_set_path",p_id.track_idx,p_id.path);
if (p_id.type==Animation::TYPE_VALUE)
undo_redo->add_do_method(animation.ptr(),"value_track_set_continuous",p_id.track_idx,continuous);
undo_redo->add_do_method(animation.ptr(),"value_track_set_update_mode",p_id.track_idx,update_mode);
} else {
undo_redo->create_action(TTR("Anim Insert Key"));
@ -3536,7 +3544,7 @@ void AnimationKeyEditor::_insert_delay() {
pos=animation->get_length();
timeline_pos=pos;
track_pos->update();
emit_signal("timeline_changed",pos);
emit_signal("timeline_changed",pos,true);
}
insert_queue=false;
}
@ -3759,7 +3767,7 @@ void AnimationKeyEditor::_bind_methods() {
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
ADD_SIGNAL( MethodInfo("keying_changed" ) );
ADD_SIGNAL( MethodInfo("timeline_changed", PropertyInfo(Variant::REAL,"pos") ) );
ADD_SIGNAL( MethodInfo("timeline_changed", PropertyInfo(Variant::REAL,"pos"), PropertyInfo(Variant::BOOL,"drag") ) );
ADD_SIGNAL( MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL,"len") ) );
ADD_SIGNAL( MethodInfo("animation_step_changed", PropertyInfo(Variant::REAL,"step") ) );
ADD_SIGNAL( MethodInfo("key_edited", PropertyInfo(Variant::INT,"track"), PropertyInfo(Variant::INT,"key") ) );

View File

@ -952,7 +952,7 @@ void AnimationPlayerEditor::_animation_duplicate() {
}
void AnimationPlayerEditor::_seek_value_changed(float p_value) {
void AnimationPlayerEditor::_seek_value_changed(float p_value,bool p_set) {
if (updating || !player || player->is_playing()) {
return;
@ -980,7 +980,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value) {
pos=anim->get_length();
}
if (player->is_valid()) {
if (player->is_valid() && !p_set) {
float cpos = player->get_current_animation_pos();
player->seek_delta(pos,pos-cpos);
@ -988,6 +988,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value) {
player->seek(pos,true);
}
key_editor->set_anim_pos(pos);
updating=true;
@ -1078,6 +1079,7 @@ void AnimationPlayerEditor::_editor_load(){
void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) {
frame->set_max(p_len);
}
@ -1092,7 +1094,7 @@ void AnimationPlayerEditor::_animation_key_editor_anim_step_changed(float p_len)
}
void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos) {
void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos,bool p_drag) {
if (!is_visible())
return;
@ -1102,7 +1104,11 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos) {
if (player->is_playing() )
return;
frame->set_val(p_pos);
updating=true;
frame->set_val(p_pos);
updating=false;
_seek_value_changed(p_pos,!p_drag);
EditorNode::get_singleton()->get_property_editor()->refresh();
@ -1254,7 +1260,7 @@ void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_animation_edit"),&AnimationPlayerEditor::_animation_edit);
ObjectTypeDB::bind_method(_MD("_animation_resource_edit"),&AnimationPlayerEditor::_animation_resource_edit);
ObjectTypeDB::bind_method(_MD("_dialog_action"),&AnimationPlayerEditor::_dialog_action);
ObjectTypeDB::bind_method(_MD("_seek_value_changed"),&AnimationPlayerEditor::_seek_value_changed);
ObjectTypeDB::bind_method(_MD("_seek_value_changed"),&AnimationPlayerEditor::_seek_value_changed,DEFVAL(true));
ObjectTypeDB::bind_method(_MD("_animation_player_changed"),&AnimationPlayerEditor::_animation_player_changed);
ObjectTypeDB::bind_method(_MD("_blend_edited"),&AnimationPlayerEditor::_blend_edited);
// ObjectTypeDB::bind_method(_MD("_seek_frame_changed"),&AnimationPlayerEditor::_seek_frame_changed);

View File

@ -145,7 +145,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _scale_changed(const String& p_scale);
void _dialog_action(String p_file);
void _seek_frame_changed(const String& p_frame);
void _seek_value_changed(float p_value);
void _seek_value_changed(float p_value, bool p_set=false);
void _blend_editor_next_changed(const int p_idx);
void _list_changed();
@ -158,7 +158,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_player_changed(Object *p_pl);
void _animation_key_editor_seek(float p_pos);
void _animation_key_editor_seek(float p_pos, bool p_drag);
void _animation_key_editor_anim_len_changed(float p_new);
void _animation_key_editor_anim_step_changed(float p_len);