diff options
Diffstat (limited to 'editor/animation_track_editor.cpp')
-rw-r--r-- | editor/animation_track_editor.cpp | 205 |
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); |