summaryrefslogtreecommitdiffstats
path: root/editor/animation_track_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/animation_track_editor.cpp')
-rw-r--r--editor/animation_track_editor.cpp205
1 files changed, 154 insertions, 51 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 8268cf10ae..3c704b3473 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -35,7 +35,6 @@
#include "core/input/input.h"
#include "editor/animation_bezier_editor.h"
#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
@@ -43,6 +42,7 @@
#include "editor/gui/scene_tree_editor.h"
#include "editor/inspector_dock.h"
#include "editor/plugins/animation_player_editor_plugin.h"
+#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_player.h"
#include "scene/animation/tween.h"
#include "scene/gui/check_box.h"
@@ -1247,6 +1247,58 @@ void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) {
}
void AnimationTimelineEdit::_zoom_changed(double) {
+ double zoom_pivot = 0; // Point on timeline to stay fixed.
+ double zoom_pivot_delta = 0; // Delta seconds from left-most point on timeline to zoom pivot.
+
+ int timeline_width_pixels = get_size().width - get_buttons_width() - get_name_limit();
+ double timeline_width_seconds = timeline_width_pixels / last_zoom_scale; // Length (in seconds) of visible part of timeline before zoom.
+ double updated_timeline_width_seconds = timeline_width_pixels / get_zoom_scale(); // Length after zoom.
+ double updated_timeline_half_width = updated_timeline_width_seconds / 2.0;
+ bool zooming = updated_timeline_width_seconds < timeline_width_seconds;
+
+ double timeline_left = get_value();
+ double timeline_right = timeline_left + timeline_width_seconds;
+ double timeline_center = timeline_left + timeline_width_seconds / 2.0;
+
+ if (zoom_callback_occured) { // Zooming with scroll wheel will focus on the position of the mouse.
+ double zoom_scroll_origin_norm = (zoom_scroll_origin.x - get_name_limit()) / timeline_width_pixels;
+ zoom_scroll_origin_norm = MAX(zoom_scroll_origin_norm, 0);
+ zoom_pivot = timeline_left + timeline_width_seconds * zoom_scroll_origin_norm;
+ zoom_pivot_delta = updated_timeline_width_seconds * zoom_scroll_origin_norm;
+ zoom_callback_occured = false;
+ } else { // Zooming with slider will depend on the current play position.
+ // If the play position is not in range, or exactly in the center, zoom in on the center.
+ if (get_play_position() < timeline_left || get_play_position() > timeline_left + timeline_width_seconds || get_play_position() == timeline_center) {
+ zoom_pivot = timeline_center;
+ zoom_pivot_delta = updated_timeline_half_width;
+ }
+ // Zoom from right if play position is right of center,
+ // and shrink from right if play position is left of center.
+ else if ((get_play_position() > timeline_center) == zooming) {
+ // If play position crosses to other side of center, center it.
+ bool center_passed = (get_play_position() < timeline_right - updated_timeline_half_width) == zooming;
+ zoom_pivot = center_passed ? get_play_position() : timeline_right;
+ double center_offset = CMP_EPSILON * (zooming ? 1 : -1); // Small offset to prevent crossover.
+ zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : updated_timeline_width_seconds;
+ }
+ // Zoom from left if play position is left of center,
+ // and shrink from left if play position is right of center.
+ else if ((get_play_position() <= timeline_center) == zooming) {
+ // If play position crosses to other side of center, center it.
+ bool center_passed = (get_play_position() > timeline_left + updated_timeline_half_width) == zooming;
+ zoom_pivot = center_passed ? get_play_position() : timeline_left;
+ double center_offset = CMP_EPSILON * (zooming ? -1 : 1); // Small offset to prevent crossover.
+ zoom_pivot_delta = center_passed ? updated_timeline_half_width + center_offset : 0;
+ }
+ }
+
+ double hscroll_pos = zoom_pivot - zoom_pivot_delta;
+ hscroll_pos = CLAMP(hscroll_pos, hscroll->get_min(), hscroll->get_max());
+
+ hscroll->set_value(hscroll_pos);
+ hscroll_on_zoom_buffer = hscroll_pos; // In case of page update.
+ last_zoom_scale = get_zoom_scale();
+
queue_redraw();
play_position->queue_redraw();
emit_signal(SNAME("zoom_changed"));
@@ -1428,6 +1480,11 @@ void AnimationTimelineEdit::_notification(int p_what) {
set_page(zoomw / scale);
+ if (hscroll->is_visible() && hscroll_on_zoom_buffer >= 0) {
+ hscroll->set_value(hscroll_on_zoom_buffer);
+ hscroll_on_zoom_buffer = -1.0;
+ }
+
int end_px = (l - get_value()) * scale;
int begin_px = -get_value() * scale;
Color notimecol = get_theme_color(SNAME("dark_color_2"), EditorStringName(Editor));
@@ -1733,7 +1790,9 @@ void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent>
void AnimationTimelineEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
double current_zoom_value = get_zoom()->get_value();
- get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor));
+ zoom_scroll_origin = p_origin;
+ zoom_callback_occured = true;
+ get_zoom()->set_value(MAX(0.01, current_zoom_value - (1.0 - p_zoom_factor)));
}
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
@@ -1809,6 +1868,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
len_hb->hide();
panner.instantiate();
+ panner->set_scroll_zoom_factor(SCROLL_ZOOM_FACTOR);
panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback));
panner->set_pan_axis(ViewPanner::PAN_AXIS_HORIZONTAL);
@@ -1861,7 +1921,7 @@ void AnimationTrackEdit::_notification(int p_what) {
Color linecolor = color;
linecolor.a = 0.2;
- Color dc = get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor));
+ Color dc = get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor));
// NAMES AND ICONS //
@@ -2718,9 +2778,9 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
PropertyInfo prop_info;
ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
#ifdef DISABLE_DEPRECATED
- bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians_as_degrees") != -1;
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.contains("radians_as_degrees");
#else
- bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.contains("radians");
#endif // DISABLE_DEPRECATED
if (is_angle) {
menu->add_icon_item(get_editor_theme_icon(SNAME("InterpLinearAngle")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
@@ -4190,27 +4250,11 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
bool create_reset_track = p_reset_wanted && track_type_is_resettable(p_id.type);
Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
+ Animation::InterpolationType interp_type = Animation::INTERPOLATION_LINEAR;
+ bool loop_wrap = true;
if (create_normal_track || create_reset_track) {
if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) {
- // Hack.
- NodePath np;
- animation->add_track(p_id.type);
- animation->track_set_path(animation->get_track_count() - 1, p_id.path);
- PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
- animation->remove_track(animation->get_track_count() - 1); // Hack.
-
- if (h.type == Variant::FLOAT ||
- h.type == Variant::VECTOR2 ||
- h.type == Variant::RECT2 ||
- h.type == Variant::VECTOR3 ||
- h.type == Variant::AABB ||
- h.type == Variant::QUATERNION ||
- h.type == Variant::COLOR ||
- h.type == Variant::PLANE ||
- h.type == Variant::TRANSFORM2D ||
- h.type == Variant::TRANSFORM3D) {
- update_mode = Animation::UPDATE_CONTINUOUS;
- }
+ _fetch_value_track_options(p_id.path, &update_mode, &interp_type, &loop_wrap);
}
}
@@ -4237,6 +4281,8 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
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);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", p_id.track_idx, interp_type);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", p_id.track_idx, loop_wrap);
if (p_id.type == Animation::TYPE_VALUE) {
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", p_id.track_idx, update_mode);
}
@@ -4567,7 +4613,7 @@ void AnimationTrackEditor::_animation_changed() {
}
animation_changing_awaiting_update = true;
- call_deferred(SNAME("_animation_update"));
+ callable_mp(this, &AnimationTrackEditor::_animation_update).call_deferred();
}
void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
@@ -4824,36 +4870,82 @@ void AnimationTrackEditor::_add_track(int p_type) {
pick_track->get_filter_line_edit()->grab_focus();
}
+void AnimationTrackEditor::_fetch_value_track_options(const NodePath &p_path, Animation::UpdateMode *r_update_mode, Animation::InterpolationType *r_interpolation_type, bool *r_loop_wrap) {
+ AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
+ if (player->has_animation(SceneStringNames::get_singleton()->RESET)) {
+ Ref<Animation> reset_anim = player->get_animation(SceneStringNames::get_singleton()->RESET);
+ int rt = reset_anim->find_track(p_path, Animation::TrackType::TYPE_VALUE);
+ if (rt >= 0) {
+ *r_update_mode = reset_anim->value_track_get_update_mode(rt);
+ *r_interpolation_type = reset_anim->track_get_interpolation_type(rt);
+ *r_loop_wrap = reset_anim->track_get_interpolation_loop_wrap(rt);
+ return;
+ }
+ rt = reset_anim->find_track(p_path, Animation::TrackType::TYPE_BEZIER);
+ if (rt >= 0) {
+ *r_interpolation_type = reset_anim->track_get_interpolation_type(rt);
+ *r_loop_wrap = reset_anim->track_get_interpolation_loop_wrap(rt);
+ return;
+ }
+ }
+
+ // Hack.
+ NodePath np;
+ animation->add_track(Animation::TYPE_VALUE);
+ animation->track_set_path(animation->get_track_count() - 1, p_path);
+ PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
+ animation->remove_track(animation->get_track_count() - 1); // Hack.
+ switch (h.type) {
+ case Variant::FLOAT: {
+#ifdef DISABLE_DEPRECATED
+ bool is_angle = h.type == Variant::FLOAT && h.hint_string.contains("radians_as_degrees");
+#else
+ bool is_angle = h.type == Variant::FLOAT && h.hint_string.contains("radians");
+#endif // DISABLE_DEPRECATED
+ if (is_angle) {
+ *r_interpolation_type = Animation::INTERPOLATION_LINEAR_ANGLE;
+ }
+ [[fallthrough]];
+ }
+ case Variant::VECTOR2:
+ case Variant::RECT2:
+ case Variant::VECTOR3:
+ case Variant::TRANSFORM2D:
+ case Variant::VECTOR4:
+ case Variant::PLANE:
+ case Variant::QUATERNION:
+ case Variant::AABB:
+ case Variant::BASIS:
+ case Variant::TRANSFORM3D:
+ case Variant::PROJECTION:
+ case Variant::COLOR:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY: {
+ *r_update_mode = Animation::UPDATE_CONTINUOUS;
+ } break;
+ default: {
+ }
+ }
+}
+
void AnimationTrackEditor::_new_track_property_selected(String p_name) {
String full_path = String(adding_track_path) + ":" + p_name;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- if (adding_track_type == Animation::TYPE_VALUE) {
- Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
- {
- // Hack.
- NodePath np;
- animation->add_track(Animation::TYPE_VALUE);
- animation->track_set_path(animation->get_track_count() - 1, full_path);
- PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
- animation->remove_track(animation->get_track_count() - 1); // Hack.
- if (h.type == Variant::FLOAT ||
- h.type == Variant::VECTOR2 ||
- h.type == Variant::RECT2 ||
- h.type == Variant::VECTOR3 ||
- h.type == Variant::AABB ||
- h.type == Variant::QUATERNION ||
- h.type == Variant::COLOR ||
- h.type == Variant::PLANE ||
- h.type == Variant::TRANSFORM2D ||
- h.type == Variant::TRANSFORM3D) {
- update_mode = Animation::UPDATE_CONTINUOUS;
- }
- }
+ Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
+ Animation::InterpolationType interp_type = Animation::INTERPOLATION_LINEAR;
+ bool loop_wrap = true;
+ _fetch_value_track_options(full_path, &update_mode, &interp_type, &loop_wrap);
+ if (adding_track_type == Animation::TYPE_VALUE) {
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), full_path);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", animation->get_track_count(), interp_type);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", animation->get_track_count(), loop_wrap);
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", animation->get_track_count(), update_mode);
undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
undo_redo->commit_action();
@@ -4877,8 +4969,11 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
undo_redo->create_action(TTR("Add Bezier Track"));
int base_track = animation->get_track_count();
for (int i = 0; i < subindices.size(); i++) {
+ int track_idx = base_track + i;
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
- undo_redo->add_do_method(animation.ptr(), "track_set_path", base_track + i, full_path + subindices[i]);
+ undo_redo->add_do_method(animation.ptr(), "track_set_path", track_idx, full_path + subindices[i]);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track_idx, interp_type);
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track_idx, loop_wrap);
undo_redo->add_undo_method(animation.ptr(), "remove_track", base_track);
}
undo_redo->commit_action();
@@ -5458,8 +5553,7 @@ void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p
}
void AnimationTrackEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
- double current_zoom_value = timeline->get_zoom()->get_value();
- timeline->get_zoom()->set_value(MAX(0.01, current_zoom_value * p_zoom_factor));
+ timeline->_zoom_callback(p_zoom_factor, p_origin, p_event);
}
void AnimationTrackEditor::_cancel_bezier_edit() {
@@ -6038,6 +6132,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
existing_idx = reset->track_find_key(dst_track, 0, Animation::FIND_MODE_APPROX);
}
+ if (animation->track_get_type(sk.track) == Animation::TYPE_VALUE) {
+ undo_redo->add_do_method(reset.ptr(), "value_track_set_update_mode", dst_track, animation->value_track_get_update_mode(sk.track));
+ }
+ if (animation->track_get_type(sk.track) == Animation::TYPE_AUDIO) {
+ undo_redo->add_do_method(reset.ptr(), "audio_track_set_use_blend", dst_track, animation->audio_track_is_use_blend(sk.track));
+ }
+ undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_type", dst_track, animation->track_get_interpolation_type(sk.track));
+ undo_redo->add_do_method(reset.ptr(), "track_set_interpolation_loop_wrap", dst_track, animation->track_get_interpolation_loop_wrap(sk.track));
+
undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key));
undo_redo->add_undo_method(reset.ptr(), "track_remove_key_at_time", dst_track, 0);
@@ -6375,7 +6478,6 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
ClassDB::bind_method("_redraw_tracks", &AnimationTrackEditor::_redraw_tracks);
ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
@@ -6489,6 +6591,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
timeline->connect("length_changed", callable_mp(this, &AnimationTrackEditor::_update_length));
panner.instantiate();
+ panner->set_scroll_zoom_factor(AnimationTimelineEdit::SCROLL_ZOOM_FACTOR);
panner->set_callbacks(callable_mp(this, &AnimationTrackEditor::_pan_callback), callable_mp(this, &AnimationTrackEditor::_zoom_callback));
scroll = memnew(ScrollContainer);