|
@@ -3306,6 +3306,17 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) {
|
|
|
bezier_edit->set_play_position(p_pos);
|
|
|
}
|
|
|
|
|
|
+static bool track_type_is_resettable(Animation::TrackType p_type) {
|
|
|
+ switch (p_type) {
|
|
|
+ case Animation::TYPE_VALUE:
|
|
|
+ case Animation::TYPE_BEZIER:
|
|
|
+ case Animation::TYPE_TRANSFORM:
|
|
|
+ return true;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
|
|
|
if (insert_frame != Engine::get_singleton()->get_frames_drawn()) {
|
|
|
//clear insert list for the frame if frame changed
|
|
@@ -3326,40 +3337,57 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
|
|
|
|
|
|
insert_data.push_back(p_id);
|
|
|
|
|
|
- if (p_id.track_idx == -1) {
|
|
|
- if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
|
|
|
- //potential new key, does not exist
|
|
|
- int num_tracks = 0;
|
|
|
- bool all_bezier = true;
|
|
|
- for (int i = 0; i < insert_data.size(); i++) {
|
|
|
- if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
|
|
|
- all_bezier = false;
|
|
|
- }
|
|
|
+ bool reset_allowed = true;
|
|
|
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
|
|
|
+ if (player->has_animation("RESET") && player->get_animation("RESET") == animation) {
|
|
|
+ // Avoid messing with the reset animation itself
|
|
|
+ reset_allowed = false;
|
|
|
+ } else {
|
|
|
+ bool some_resettable = false;
|
|
|
+ for (int i = 0; i < insert_data.size(); i++) {
|
|
|
+ if (track_type_is_resettable(insert_data[i].type)) {
|
|
|
+ some_resettable = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!some_resettable) {
|
|
|
+ reset_allowed = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (insert_data[i].track_idx == -1) {
|
|
|
- ++num_tracks;
|
|
|
- }
|
|
|
+ if (p_id.track_idx == -1) {
|
|
|
+ //potential new key, does not exist
|
|
|
+ int num_tracks = 0;
|
|
|
+ bool all_bezier = true;
|
|
|
+ for (int i = 0; i < insert_data.size(); i++) {
|
|
|
+ if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER)
|
|
|
+ all_bezier = false;
|
|
|
+
|
|
|
+ if (insert_data[i].track_idx == -1) {
|
|
|
+ ++num_tracks;
|
|
|
+ }
|
|
|
|
|
|
- if (insert_data[i].type != Animation::TYPE_VALUE) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (insert_data[i].type != Animation::TYPE_VALUE) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- switch (insert_data[i].value.get_type()) {
|
|
|
- case Variant::INT:
|
|
|
- case Variant::REAL:
|
|
|
- case Variant::VECTOR2:
|
|
|
- case Variant::VECTOR3:
|
|
|
- case Variant::QUAT:
|
|
|
- case Variant::PLANE:
|
|
|
- case Variant::COLOR: {
|
|
|
- // Valid.
|
|
|
- } break;
|
|
|
- default: {
|
|
|
- all_bezier = false;
|
|
|
- }
|
|
|
+ switch (insert_data[i].value.get_type()) {
|
|
|
+ case Variant::INT:
|
|
|
+ case Variant::REAL:
|
|
|
+ case Variant::VECTOR2:
|
|
|
+ case Variant::VECTOR3:
|
|
|
+ case Variant::QUAT:
|
|
|
+ case Variant::PLANE:
|
|
|
+ case Variant::COLOR: {
|
|
|
+ // Valid.
|
|
|
+ } break;
|
|
|
+ default: {
|
|
|
+ all_bezier = false;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
|
|
|
if (num_tracks == 1) {
|
|
|
insert_confirm_text->set_text(vformat(TTR("Create NEW track for %s and insert key?"), p_id.query));
|
|
|
} else {
|
|
@@ -3367,23 +3395,26 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
|
|
|
}
|
|
|
|
|
|
insert_confirm_bezier->set_visible(all_bezier);
|
|
|
+ insert_confirm_reset->set_visible(reset_allowed);
|
|
|
+
|
|
|
insert_confirm->get_ok()->set_text(TTR("Create"));
|
|
|
insert_confirm->popup_centered_minsize();
|
|
|
insert_query = true;
|
|
|
} else {
|
|
|
- call_deferred("_insert_delay");
|
|
|
+ call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks"));
|
|
|
insert_queue = true;
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
if (!insert_query && !insert_queue) {
|
|
|
- call_deferred("_insert_delay");
|
|
|
+ // Create Beziers wouldn't make sense in this case, where no tracks are being created
|
|
|
+ call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false);
|
|
|
insert_queue = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void AnimationTrackEditor::_insert_delay() {
|
|
|
+void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_beziers) {
|
|
|
if (insert_query) {
|
|
|
//discard since it's entered into query mode
|
|
|
insert_queue = false;
|
|
@@ -3392,13 +3423,18 @@ void AnimationTrackEditor::_insert_delay() {
|
|
|
|
|
|
undo_redo->create_action(TTR("Anim Insert"));
|
|
|
|
|
|
- int last_track = animation->get_track_count();
|
|
|
+ Ref<Animation> reset_anim;
|
|
|
+ if (p_create_reset) {
|
|
|
+ reset_anim = _create_and_get_reset_animation();
|
|
|
+ }
|
|
|
+
|
|
|
+ TrackIndices next_tracks(animation.ptr(), reset_anim.ptr());
|
|
|
bool advance = false;
|
|
|
while (insert_data.size()) {
|
|
|
if (insert_data.front()->get().advance) {
|
|
|
advance = true;
|
|
|
}
|
|
|
- last_track = _confirm_insert(insert_data.front()->get(), last_track);
|
|
|
+ next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_create_reset, reset_anim, p_create_beziers);
|
|
|
insert_data.pop_front();
|
|
|
}
|
|
|
|
|
@@ -3689,12 +3725,34 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
|
|
|
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
|
|
|
+ if (player->has_animation("RESET")) {
|
|
|
+ return player->get_animation("RESET");
|
|
|
+ } else {
|
|
|
+ Ref<Animation> reset_anim;
|
|
|
+ reset_anim.instance();
|
|
|
+ reset_anim->set_length(ANIM_MIN_LENGTH);
|
|
|
+ undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim);
|
|
|
+ undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
|
|
|
+ undo_redo->add_undo_method(player, "remove_animation", "RESET");
|
|
|
+ undo_redo->add_undo_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
|
|
|
+ return reset_anim;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void AnimationTrackEditor::_confirm_insert_list() {
|
|
|
undo_redo->create_action(TTR("Anim Create & Insert"));
|
|
|
|
|
|
- int last_track = animation->get_track_count();
|
|
|
+ bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed();
|
|
|
+ Ref<Animation> reset_anim;
|
|
|
+ if (create_reset) {
|
|
|
+ reset_anim = _create_and_get_reset_animation();
|
|
|
+ }
|
|
|
+
|
|
|
+ TrackIndices next_tracks(animation.ptr(), reset_anim.ptr());
|
|
|
while (insert_data.size()) {
|
|
|
- last_track = _confirm_insert(insert_data.front()->get(), last_track, insert_confirm_bezier->is_pressed());
|
|
|
+ next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, create_reset, reset_anim, insert_confirm_bezier->is_pressed());
|
|
|
insert_data.pop_front();
|
|
|
}
|
|
|
|
|
@@ -3813,11 +3871,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool
|
|
|
return subindices;
|
|
|
}
|
|
|
|
|
|
-int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers) {
|
|
|
- if (p_last_track == -1) {
|
|
|
- p_last_track = animation->get_track_count();
|
|
|
- }
|
|
|
-
|
|
|
+AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, Ref<Animation> p_reset_anim, bool p_create_beziers) {
|
|
|
bool created = false;
|
|
|
if (p_id.track_idx < 0) {
|
|
|
if (p_create_beziers) {
|
|
@@ -3829,10 +3883,10 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
|
|
|
id.type = Animation::TYPE_BEZIER;
|
|
|
id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length()));
|
|
|
id.path = String(p_id.path) + subindices[i];
|
|
|
- _confirm_insert(id, p_last_track + i);
|
|
|
+ p_next_tracks = _confirm_insert(id, p_next_tracks, p_create_reset, p_reset_anim, false);
|
|
|
}
|
|
|
|
|
|
- return p_last_track + subindices.size();
|
|
|
+ return p_next_tracks;
|
|
|
}
|
|
|
}
|
|
|
created = true;
|
|
@@ -3869,7 +3923,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- p_id.track_idx = p_last_track;
|
|
|
+ p_id.track_idx = p_next_tracks.normal;
|
|
|
|
|
|
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);
|
|
@@ -3921,7 +3975,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
|
|
|
// Just remove the track.
|
|
|
undo_redo->add_undo_method(this, "_clear_selection", false);
|
|
|
undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
|
|
|
- p_last_track++;
|
|
|
+ p_next_tracks.normal++;
|
|
|
} else {
|
|
|
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time);
|
|
|
int existing = animation->track_find_key(p_id.track_idx, time, true);
|
|
@@ -3932,9 +3986,27 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (p_create_reset && track_type_is_resettable(p_id.type)) {
|
|
|
+ bool create_reset_track = true;
|
|
|
+ Animation *reset_anim = p_reset_anim.ptr();
|
|
|
+ for (int i = 0; i < reset_anim->get_track_count(); i++) {
|
|
|
+ if (reset_anim->track_get_path(i) == p_id.path) {
|
|
|
+ create_reset_track = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (create_reset_track) {
|
|
|
+ undo_redo->add_do_method(reset_anim, "add_track", p_id.type);
|
|
|
+ undo_redo->add_do_method(reset_anim, "track_set_path", p_next_tracks.reset, p_id.path);
|
|
|
+ undo_redo->add_do_method(reset_anim, "track_insert_key", p_next_tracks.reset, 0.0f, value);
|
|
|
+ undo_redo->add_undo_method(reset_anim, "remove_track", reset_anim->get_track_count());
|
|
|
+ p_next_tracks.reset++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
undo_redo->commit_action();
|
|
|
|
|
|
- return p_last_track;
|
|
|
+ return p_next_tracks;
|
|
|
}
|
|
|
|
|
|
void AnimationTrackEditor::show_select_node_warning(bool p_show) {
|
|
@@ -4229,6 +4301,7 @@ void AnimationTrackEditor::_notification(int p_what) {
|
|
|
selected_filter->set_icon(get_icon("AnimationFilter", "EditorIcons"));
|
|
|
imported_anim_warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
|
|
|
main_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
|
|
|
+ edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_icon("Reload", "EditorIcons"));
|
|
|
}
|
|
|
|
|
|
if (p_what == NOTIFICATION_READY) {
|
|
@@ -5062,6 +5135,12 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
|
|
|
_update_key_edit();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+void AnimationTrackEditor::_edit_menu_about_to_show() {
|
|
|
+ AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
|
|
|
+ edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
|
|
|
+}
|
|
|
+
|
|
|
void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|
|
last_menu_track_opt = p_option;
|
|
|
switch (p_option) {
|
|
@@ -5383,6 +5462,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
|
|
|
set_anim_pos(pos);
|
|
|
emit_signal("timeline_changed", pos, true);
|
|
|
|
|
|
+ } break;
|
|
|
+ case EDIT_APPLY_RESET: {
|
|
|
+ AnimationPlayerEditor::singleton->get_player()->apply_reset(true);
|
|
|
+
|
|
|
} break;
|
|
|
case EDIT_OPTIMIZE_ANIMATION: {
|
|
|
optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
|
|
@@ -5573,6 +5656,7 @@ void AnimationTrackEditor::_bind_methods() {
|
|
|
ClassDB::bind_method("_bezier_edit", &AnimationTrackEditor::_bezier_edit);
|
|
|
ClassDB::bind_method("_cancel_bezier_edit", &AnimationTrackEditor::_cancel_bezier_edit);
|
|
|
ClassDB::bind_method("_edit_menu_pressed", &AnimationTrackEditor::_edit_menu_pressed);
|
|
|
+ ClassDB::bind_method("_edit_menu_about_to_show", &AnimationTrackEditor::_edit_menu_about_to_show);
|
|
|
ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
|
|
|
ClassDB::bind_method("_selection_changed", &AnimationTrackEditor::_selection_changed);
|
|
|
ClassDB::bind_method("_snap_mode_changed", &AnimationTrackEditor::_snap_mode_changed);
|
|
@@ -5744,10 +5828,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|
|
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP);
|
|
|
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP);
|
|
|
edit->get_popup()->add_separator();
|
|
|
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
|
|
|
+ edit->get_popup()->add_separator();
|
|
|
edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION);
|
|
|
edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION);
|
|
|
|
|
|
edit->get_popup()->connect("id_pressed", this, "_edit_menu_pressed");
|
|
|
+ edit->get_popup()->connect("about_to_show", this, "_edit_menu_about_to_show");
|
|
|
|
|
|
pick_track = memnew(SceneTreeDialog);
|
|
|
add_child(pick_track);
|
|
@@ -5773,9 +5860,16 @@ AnimationTrackEditor::AnimationTrackEditor() {
|
|
|
insert_confirm->add_child(icvb);
|
|
|
insert_confirm_text = memnew(Label);
|
|
|
icvb->add_child(insert_confirm_text);
|
|
|
+ HBoxContainer *ichb = memnew(HBoxContainer);
|
|
|
+ icvb->add_child(ichb);
|
|
|
insert_confirm_bezier = memnew(CheckBox);
|
|
|
insert_confirm_bezier->set_text(TTR("Use Bezier Curves"));
|
|
|
- icvb->add_child(insert_confirm_bezier);
|
|
|
+ insert_confirm_bezier->set_pressed(EDITOR_GET("editors/animation/default_create_bezier_tracks"));
|
|
|
+ ichb->add_child(insert_confirm_bezier);
|
|
|
+ insert_confirm_reset = memnew(CheckBox);
|
|
|
+ insert_confirm_reset->set_text(TTR("Create RESET Track(s)"));
|
|
|
+ insert_confirm_reset->set_pressed(EDITOR_GET("editors/animation/default_create_reset_tracks"));
|
|
|
+ ichb->add_child(insert_confirm_reset);
|
|
|
keying = false;
|
|
|
moving_selection = false;
|
|
|
key_edit = nullptr;
|