Skip to content

Commit a7abbe5

Browse files
committed
Allow jumping to previous/next keyframe in animation player
1 parent a1acd38 commit a7abbe5

4 files changed

+104
-29
lines changed

editor/animation_track_editor.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -4580,6 +4580,10 @@ bool AnimationTrackEditor::is_snap_enabled() const {
45804580
return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
45814581
}
45824582

4583+
bool AnimationTrackEditor::is_bezier_editor_active() const {
4584+
return bezier_edit->is_visible();
4585+
}
4586+
45834587
bool AnimationTrackEditor::can_add_reset_key() const {
45844588
for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
45854589
const Animation::TrackType track_type = animation->track_get_type(E.key.track);

editor/animation_track_editor.h

+1
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ class AnimationTrackEditor : public VBoxContainer {
729729
bool is_key_clipboard_active() const;
730730
bool is_moving_selection() const;
731731
bool is_snap_enabled() const;
732+
bool is_bezier_editor_active() const;
732733
bool can_add_reset_key() const;
733734
float get_moving_selection_offset() const;
734735
float snap_time(float p_value, bool p_relative = false);

editor/plugins/animation_player_editor_plugin.cpp

+98-29
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,69 @@ void AnimationPlayerEditor::_autoplay_pressed() {
224224
}
225225
}
226226

227+
void AnimationPlayerEditor::_go_to_nearest_keyframe(bool p_backward) {
228+
if (_get_current().is_empty()) {
229+
return;
230+
}
231+
232+
Ref<Animation> anim = player->get_animation(player->get_assigned_animation());
233+
234+
double current_time = player->get_current_animation_position();
235+
// Offset the time to avoid finding the same keyframe with Animation::track_find_key().
236+
double time_offset = MAX(CMP_EPSILON * 2, current_time * CMP_EPSILON * 2);
237+
double current_time_offset = current_time + (p_backward ? -time_offset : time_offset);
238+
239+
float nearest_key_time = p_backward ? 0 : anim->get_length();
240+
int track_count = anim->get_track_count();
241+
bool bezier_active = track_editor->is_bezier_editor_active();
242+
243+
Node *root = get_tree()->get_edited_scene_root();
244+
EditorSelection *selection = EditorNode::get_singleton()->get_editor_selection();
245+
246+
Vector<int> selected_tracks;
247+
for (int i = 0; i < track_count; ++i) {
248+
if (selection->is_selected(root->get_node_or_null(anim->track_get_path(i)))) {
249+
selected_tracks.push_back(i);
250+
}
251+
}
252+
253+
// Find the nearest keyframe in selection if the scene has selected nodes
254+
// or the nearest keyframe in the entire animation otherwise.
255+
if (selected_tracks.size() > 0) {
256+
for (int track : selected_tracks) {
257+
if (bezier_active && anim->track_get_type(track) != Animation::TYPE_BEZIER) {
258+
continue;
259+
}
260+
int key = anim->track_find_key(track, current_time_offset, Animation::FIND_MODE_NEAREST, false, !p_backward);
261+
if (key == -1) {
262+
continue;
263+
}
264+
double key_time = anim->track_get_key_time(track, key);
265+
if ((p_backward && key_time > nearest_key_time) || (!p_backward && key_time < nearest_key_time)) {
266+
nearest_key_time = key_time;
267+
}
268+
}
269+
} else {
270+
for (int track = 0; track < track_count; ++track) {
271+
if (bezier_active && anim->track_get_type(track) != Animation::TYPE_BEZIER) {
272+
continue;
273+
}
274+
int key = anim->track_find_key(track, current_time_offset, Animation::FIND_MODE_NEAREST, false, !p_backward);
275+
if (key == -1) {
276+
continue;
277+
}
278+
double key_time = anim->track_get_key_time(track, key);
279+
if ((p_backward && key_time > nearest_key_time) || (!p_backward && key_time < nearest_key_time)) {
280+
nearest_key_time = key_time;
281+
}
282+
}
283+
}
284+
285+
player->seek_internal(nearest_key_time, true, true, true);
286+
frame->set_value(nearest_key_time);
287+
track_editor->set_anim_pos(nearest_key_time);
288+
}
289+
227290
void AnimationPlayerEditor::_play_pressed() {
228291
String current = _get_current();
229292

@@ -1505,30 +1568,28 @@ void AnimationPlayerEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
15051568
ERR_FAIL_COND(p_ev.is_null());
15061569

15071570
Ref<InputEventKey> k = p_ev;
1508-
if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->is_alt_pressed() && !k->is_ctrl_pressed() && !k->is_meta_pressed()) {
1509-
switch (k->get_keycode()) {
1510-
case Key::A: {
1511-
if (!k->is_shift_pressed()) {
1512-
_play_bw_from_pressed();
1513-
} else {
1514-
_play_bw_pressed();
1515-
}
1516-
accept_event();
1517-
} break;
1518-
case Key::S: {
1519-
_stop_pressed();
1520-
accept_event();
1521-
} break;
1522-
case Key::D: {
1523-
if (!k->is_shift_pressed()) {
1524-
_play_from_pressed();
1525-
} else {
1526-
_play_pressed();
1527-
}
1528-
accept_event();
1529-
} break;
1530-
default:
1531-
break;
1571+
if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo()) {
1572+
if (ED_IS_SHORTCUT("animation_editor/stop_animation", p_ev)) {
1573+
_stop_pressed();
1574+
accept_event();
1575+
} else if (ED_IS_SHORTCUT("animation_editor/play_animation", p_ev)) {
1576+
_play_from_pressed();
1577+
accept_event();
1578+
} else if (ED_IS_SHORTCUT("animation_editor/play_animation_backwards", p_ev)) {
1579+
_play_bw_from_pressed();
1580+
accept_event();
1581+
} else if (ED_IS_SHORTCUT("animation_editor/play_animation_from_start", p_ev)) {
1582+
_play_pressed();
1583+
accept_event();
1584+
} else if (ED_IS_SHORTCUT("animation_editor/play_animation_from_end", p_ev)) {
1585+
_play_bw_pressed();
1586+
accept_event();
1587+
} else if (ED_IS_SHORTCUT("animation_editor/go_to_next_keyframe", p_ev)) {
1588+
_go_to_nearest_keyframe(false);
1589+
accept_event();
1590+
} else if (ED_IS_SHORTCUT("animation_editor/go_to_previous_keyframe", p_ev)) {
1591+
_go_to_nearest_keyframe(true);
1592+
accept_event();
15321593
}
15331594
}
15341595
}
@@ -1902,27 +1963,27 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
19021963

19031964
play_bw_from = memnew(Button);
19041965
play_bw_from->set_theme_type_variation("FlatButton");
1905-
play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)"));
1966+
play_bw_from->set_tooltip_text(TTR("Play Animation Backwards"));
19061967
hb->add_child(play_bw_from);
19071968

19081969
play_bw = memnew(Button);
19091970
play_bw->set_theme_type_variation("FlatButton");
1910-
play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)"));
1971+
play_bw->set_tooltip_text(TTR("Play Animation Backwards from End"));
19111972
hb->add_child(play_bw);
19121973

19131974
stop = memnew(Button);
19141975
stop->set_theme_type_variation("FlatButton");
1976+
stop->set_tooltip_text(TTR("Pause/Stop Animation"));
19151977
hb->add_child(stop);
1916-
stop->set_tooltip_text(TTR("Pause/stop animation playback. (S)"));
19171978

19181979
play = memnew(Button);
19191980
play->set_theme_type_variation("FlatButton");
1920-
play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)"));
1981+
play->set_tooltip_text(TTR("Play Animation from Start"));
19211982
hb->add_child(play);
19221983

19231984
play_from = memnew(Button);
19241985
play_from->set_theme_type_variation("FlatButton");
1925-
play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)"));
1986+
play_from->set_tooltip_text(TTR("Play Animation"));
19261987
hb->add_child(play_from);
19271988

19281989
frame = memnew(SpinBox);
@@ -2138,6 +2199,14 @@ void fragment() {
21382199
}
21392200
)");
21402201
RS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid());
2202+
2203+
ED_SHORTCUT("animation_editor/stop_animation", TTR("Pause/Stop Animation"), Key::S);
2204+
ED_SHORTCUT("animation_editor/play_animation", TTR("Play Animation"), Key::D);
2205+
ED_SHORTCUT("animation_editor/play_animation_backwards", TTR("Play Animation Backwards"), Key::A);
2206+
ED_SHORTCUT("animation_editor/play_animation_from_start", TTR("Play Animation from Start"), KeyModifierMask::SHIFT + Key::D);
2207+
ED_SHORTCUT("animation_editor/play_animation_from_end", TTR("Play Animation Backwards from End"), KeyModifierMask::SHIFT + Key::A);
2208+
ED_SHORTCUT("animation_editor/go_to_next_keyframe", TTR("Go to Next Keyframe"), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::D);
2209+
ED_SHORTCUT("animation_editor/go_to_previous_keyframe", TTR("Go to Previous Keyframe"), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::A);
21412210
}
21422211

21432212
AnimationPlayerEditor::~AnimationPlayerEditor() {

editor/plugins/animation_player_editor_plugin.h

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class AnimationPlayerEditor : public VBoxContainer {
178178

179179
void _select_anim_by_name(const String &p_anim);
180180
float _get_editor_step() const;
181+
void _go_to_nearest_keyframe(bool p_backward);
181182
void _play_pressed();
182183
void _play_from_pressed();
183184
void _play_bw_pressed();

0 commit comments

Comments
 (0)