Skip to content

Commit

Permalink
Fix snapping multiple keys in Animation
Browse files Browse the repository at this point in the history
  • Loading branch information
CookieBadger committed Mar 18, 2024
1 parent 25a52c6 commit d88df64
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 25 deletions.
36 changes: 25 additions & 11 deletions editor/animation_bezier_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {

moving_selection_attempt = true;
moving_selection = false;
moving_selection_mouse_begin_x = mb->get_position().x;
moving_selection_from_key = index;
moving_selection_from_track = selected_track;
moving_selection_offset = Vector2();
Expand Down Expand Up @@ -1258,7 +1259,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {

if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (!read_only) {
if (moving_selection && (abs(moving_selection_offset.x) > 0 || abs(moving_selection_offset.y) > 0)) {
if (moving_selection && (abs(moving_selection_offset.x) > CMP_EPSILON || abs(moving_selection_offset.y) > CMP_EPSILON)) {
//combit it

EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Expand All @@ -1272,7 +1273,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
// 2- remove overlapped keys
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
real_t newtime = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x;

int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) {
Expand All @@ -1296,7 +1297,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {

// 3-move the keys (re insert them)
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
real_t newpos = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x;
Array key = animation->track_get_key_value(E->get().first, E->get().second);
real_t h = key[0];
h += moving_selection_offset.y;
Expand All @@ -1314,7 +1315,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {

// 4-(undo) remove inserted keys
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
real_t newpos = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x;
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
}

Expand Down Expand Up @@ -1356,22 +1357,23 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {

for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x);
real_t newpos = oldpos + moving_selection_offset.x;

undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
}

undo_redo->commit_action();

moving_selection = false;
} else if (select_single_attempt != IntPair(-1, -1)) {
selection.clear();
selection.insert(select_single_attempt);
set_animation_and_track(animation, select_single_attempt.first, read_only);
}

moving_selection = false;
moving_selection_attempt = false;
moving_selection_mouse_begin_x = 0.0;
queue_redraw();
}
}
Expand All @@ -1383,11 +1385,22 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = IntPair(-1, -1);
}

float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll;
float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value());

if (!read_only) {
moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll;
float moving_selection_begin_time = ((moving_selection_mouse_begin_x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
float new_time = ((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
float moving_selection_pivot = animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key);
float time_delta = new_time - moving_selection_begin_time;

float snapped_time = editor->snap_time(moving_selection_pivot + time_delta);
float time_offset = 0.0;
if (abs(moving_selection_offset.x) > CMP_EPSILON || (snapped_time > moving_selection_pivot && time_delta > CMP_EPSILON) || (snapped_time < moving_selection_pivot && time_delta < -CMP_EPSILON)) {
time_offset = snapped_time - moving_selection_pivot;
}
float moving_selection_begin_value = animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key);
float y_offset = y - moving_selection_begin_value;

moving_selection_offset = Vector2(time_offset, y_offset);
}

additional_moving_handle_lefts.clear();
Expand Down Expand Up @@ -1501,17 +1514,18 @@ bool AnimationBezierTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p
moving_selection_attempt = true;
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
moving_selection_mouse_begin_x = p_pos.x;
moving_selection_offset = Vector2();
moving_handle_track = pair.first;
moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);

if (selection.has(pair)) {
select_single_attempt = pair;
moving_selection = false;
} else {
moving_selection = true;
}
select_single_attempt = pair;
}

set_animation_and_track(animation, pair.first, read_only);
Expand Down
1 change: 1 addition & 0 deletions editor/animation_bezier_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class AnimationBezierTrackEdit : public Control {
typedef Pair<int, int> IntPair;

bool moving_selection_attempt = false;
float moving_selection_mouse_begin_x = 0.0;
IntPair select_single_attempt;
bool moving_selection = false;
int moving_selection_from_key = 0;
Expand Down
45 changes: 32 additions & 13 deletions editor/animation_track_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,13 +2000,13 @@ void AnimationTrackEdit::_notification(int p_what) {
for (int i = 0; i < animation->track_get_key_count(track); i++) {
float offset = animation->track_get_key_time(track, i) - timeline->get_value();
if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
offset = editor->snap_time(offset + editor->get_moving_selection_offset(), true);
offset = offset + editor->get_moving_selection_offset();
}
offset = offset * scale + limit;
if (i < animation->track_get_key_count(track) - 1) {
float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value();
if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) {
offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset());
offset_n = offset_n + editor->get_moving_selection_offset();
}
offset_n = offset_n * scale + limit;

Expand Down Expand Up @@ -2907,8 +2907,10 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && moving_selection_attempt) {
if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
moving_selection_attempt = false;
if (moving_selection) {
emit_signal(SNAME("move_selection_commit"));
if (moving_selection && moving_selection_effective) {
if (abs(editor->get_moving_selection_offset()) > CMP_EPSILON) {
emit_signal(SNAME("move_selection_commit"));
}
} else if (select_single_attempt != -1) {
emit_signal(SNAME("select_key"), select_single_attempt, true);
}
Expand Down Expand Up @@ -2981,8 +2983,18 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("move_selection_begin"));
}

float new_ofs = (mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale();
emit_signal(SNAME("move_selection"), new_ofs - moving_selection_from_ofs);
float moving_begin_time = ((moving_selection_mouse_begin_x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
float new_time = ((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
float delta = new_time - moving_begin_time;
float snapped_time = editor->snap_time(moving_selection_pivot + delta);

float offset = 0.0;
if (abs(editor->get_moving_selection_offset()) > CMP_EPSILON || (snapped_time > moving_selection_pivot && delta > CMP_EPSILON) || (snapped_time < moving_selection_pivot && delta < -CMP_EPSILON)) {
offset = snapped_time - moving_selection_pivot;
moving_selection_effective = true;
}

emit_signal(SNAME("move_selection"), offset);
}
}

Expand Down Expand Up @@ -3025,12 +3037,16 @@ bool AnimationTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p_aggre
if (editor->is_key_selected(track, key_idx)) {
if (p_deselectable) {
emit_signal(SNAME("deselect_key"), key_idx);
moving_selection_pivot = 0.0f;
moving_selection_mouse_begin_x = 0.0f;
}
} else {
emit_signal(SNAME("select_key"), key_idx, false);
moving_selection_attempt = true;
moving_selection_effective = false;
select_single_attempt = -1;
moving_selection_from_ofs = (p_pos.x - limit) / timeline->get_zoom_scale();
moving_selection_pivot = animation->track_get_key_time(track, key_idx);
moving_selection_mouse_begin_x = p_pos.x;
}
} else {
if (!editor->is_key_selected(track, key_idx)) {
Expand All @@ -3041,12 +3057,15 @@ bool AnimationTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p_aggre
}

moving_selection_attempt = true;
moving_selection_from_ofs = (p_pos.x - limit) / timeline->get_zoom_scale();
moving_selection_effective = false;
moving_selection_pivot = animation->track_get_key_time(track, key_idx);
moving_selection_mouse_begin_x = p_pos.x;
}

if (read_only) {
moving_selection_attempt = false;
moving_selection_from_ofs = 0.0f;
moving_selection_pivot = 0.0f;
moving_selection_mouse_begin_x = 0.0f;
}
return true;
}
Expand Down Expand Up @@ -5423,7 +5442,7 @@ void AnimationTrackEditor::_move_selection_commit() {
}
// 2 - Remove overlapped keys.
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newtime = snap_time(E->get().pos + motion);
float newtime = E->get().pos + motion;
int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) {
continue;
Expand All @@ -5448,13 +5467,13 @@ void AnimationTrackEditor::_move_selection_commit() {

// 3 - Move the keys (Reinsert them).
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
float newpos = E->get().pos + motion;
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}

// 4 - (Undo) Remove inserted keys.
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
float newpos = E->get().pos + motion;
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}

Expand All @@ -5474,7 +5493,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 7 - Reselect.
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float oldpos = E->get().pos;
float newpos = snap_time(oldpos + motion);
float newpos = oldpos + motion;

undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
Expand Down
4 changes: 3 additions & 1 deletion editor/animation_track_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,11 @@ class AnimationTrackEdit : public Control {
mutable int dropping_at = 0;
float insert_at_pos = 0.0f;
bool moving_selection_attempt = false;
bool moving_selection_effective = false;
float moving_selection_pivot = 0.0f;
float moving_selection_mouse_begin_x = 0.0f;
int select_single_attempt = -1;
bool moving_selection = false;
float moving_selection_from_ofs = 0.0f;

bool in_group = false;
AnimationTrackEditor *editor = nullptr;
Expand Down

0 comments on commit d88df64

Please sign in to comment.