Преглед на файлове

Merge pull request #88498 from CookieBadger/animation-fix-snapping-multiple

Fix snapping multiple keys in Animation
Rémi Verschelde преди 1 година
родител
ревизия
0ca0e8fc49
променени са 4 файла, в които са добавени 61 реда и са изтрити 25 реда
  1. 25 11
      editor/animation_bezier_editor.cpp
  2. 1 0
      editor/animation_bezier_editor.h
  3. 32 13
      editor/animation_track_editor.cpp
  4. 3 1
      editor/animation_track_editor.h

+ 25 - 11
editor/animation_bezier_editor.cpp

@@ -1239,6 +1239,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();
@@ -1320,7 +1321,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();
@@ -1334,7 +1335,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) {
@@ -1358,7 +1359,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;
@@ -1376,7 +1377,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);
 				}
 
@@ -1418,7 +1419,7 @@ 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);
@@ -1426,14 +1427,15 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
 
 				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();
 		}
 	}
@@ -1445,11 +1447,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();
@@ -1563,17 +1576,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);

+ 1 - 0
editor/animation_bezier_editor.h

@@ -109,6 +109,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;

+ 32 - 13
editor/animation_track_editor.cpp

@@ -2067,13 +2067,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;
 
@@ -2974,8 +2974,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);
 			}
@@ -3048,8 +3050,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);
 	}
 }
 
@@ -3092,12 +3104,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)) {
@@ -3108,12 +3124,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;
 			}
@@ -5506,7 +5525,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;
@@ -5531,13 +5550,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);
 	}
 
@@ -5557,7 +5576,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);

+ 3 - 1
editor/animation_track_editor.h

@@ -290,9 +290,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;