Browse Source

Improve scrolling actions in the animation track editor

- Implement timeline scrobbling using Alt + Mouse wheel anywhere in the
  animation track editor.
  - Snap settings are followed, and precise snapping can be obtained by also
    holding down Shift.
  - This modifier wasn't used by anything in the animation editor.
- Allow zooming by using Ctrl + Mouse wheel on the timeline itself.
  - Previously, this was only possible on the track area, not the timeline.
Hugo Locurcio 4 years ago
parent
commit
a623eb5083
2 changed files with 124 additions and 54 deletions
  1. 95 35
      editor/animation_track_editor.cpp
  2. 29 19
      editor/animation_track_editor.h

+ 95 - 35
editor/animation_track_editor.cpp

@@ -1595,6 +1595,10 @@ void AnimationTimelineEdit::set_zoom(Range *p_zoom) {
 	zoom->connect("value_changed", this, "_zoom_changed");
 	zoom->connect("value_changed", this, "_zoom_changed");
 }
 }
 
 
+void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) {
+	track_edit = p_track_edit;
+}
+
 void AnimationTimelineEdit::set_play_position(float p_pos) {
 void AnimationTimelineEdit::set_play_position(float p_pos) {
 	play_position_pos = p_pos;
 	play_position_pos = p_pos;
 	play_position->update();
 	play_position->update();
@@ -1650,7 +1654,33 @@ void AnimationTimelineEdit::_play_position_draw() {
 }
 }
 
 
 void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
 void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
-	Ref<InputEventMouseButton> mb = p_event;
+	ERR_FAIL_COND(p_event.is_null());
+
+	const Ref<InputEventMouseButton> mb = p_event;
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+		get_zoom()->set_value(get_zoom()->get_value() * 1.05);
+		accept_event();
+	}
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+		get_zoom()->set_value(get_zoom()->get_value() / 1.05);
+		accept_event();
+	}
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_alt() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+		if (track_edit) {
+			track_edit->get_editor()->goto_prev_step(true);
+		}
+		accept_event();
+	}
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_alt() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+		if (track_edit) {
+			track_edit->get_editor()->goto_next_step(true);
+		}
+		accept_event();
+	}
 
 
 	if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
 	if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
 		dragging_hsize = true;
 		dragging_hsize = true;
@@ -1753,6 +1783,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
 	editing = false;
 	editing = false;
 	name_limit = 150 * EDSCALE;
 	name_limit = 150 * EDSCALE;
 	zoom = nullptr;
 	zoom = nullptr;
+	track_edit = nullptr;
 
 
 	play_position_pos = 0;
 	play_position_pos = 0;
 	play_position = memnew(Control);
 	play_position = memnew(Control);
@@ -2316,6 +2347,7 @@ void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
 
 
 void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
 void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
 	timeline = p_timeline;
 	timeline = p_timeline;
+	timeline->set_track_edit(this);
 	timeline->connect("zoom_changed", this, "_zoom_changed");
 	timeline->connect("zoom_changed", this, "_zoom_changed");
 	timeline->connect("name_limit_changed", this, "_zoom_changed");
 	timeline->connect("name_limit_changed", this, "_zoom_changed");
 }
 }
@@ -4960,6 +4992,16 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
 		scroll->accept_event();
 		scroll->accept_event();
 	}
 	}
 
 
+	if (mb.is_valid() && mb->is_pressed() && mb->get_alt() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+		goto_prev_step(true);
+		scroll->accept_event();
+	}
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_alt() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+		goto_next_step(true);
+		scroll->accept_event();
+	}
+
 	if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
 	if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
 		if (mb->is_pressed()) {
 		if (mb->is_pressed()) {
 			box_selecting = true;
 			box_selecting = true;
@@ -5139,6 +5181,56 @@ void AnimationTrackEditor::_edit_menu_about_to_show() {
 	edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
 	edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
 }
 }
 
 
+void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) {
+	if (animation.is_null()) {
+		return;
+	}
+	float step = animation->get_step();
+	if (step == 0) {
+		step = 1;
+	}
+	if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+		// Use more precise snapping when holding Shift.
+		// This is used when scrobbling the timeline using Alt + Mouse wheel.
+		step *= 0.25;
+	}
+
+	float pos = timeline->get_play_position();
+	pos = Math::stepify(pos - step, step);
+	if (pos < 0) {
+		pos = 0;
+	}
+	set_anim_pos(pos);
+	emit_signal("timeline_changed", pos, true);
+}
+
+void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) {
+	if (animation.is_null()) {
+		return;
+	}
+	float step = animation->get_step();
+	if (step == 0) {
+		step = 1;
+	}
+	if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+		// Use more precise snapping when holding Shift.
+		// This is used when scrobbling the timeline using Alt + Mouse wheel.
+		// Do not use precise snapping when using the menu action or keyboard shortcut,
+		// as the default keyboard shortcut requires pressing Shift.
+		step *= 0.25;
+	}
+
+	float pos = timeline->get_play_position();
+
+	pos = Math::stepify(pos + step, step);
+	if (pos > animation->get_length()) {
+		pos = animation->get_length();
+	}
+	set_anim_pos(pos);
+
+	emit_signal("timeline_changed", pos, true);
+}
+
 void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 	last_menu_track_opt = p_option;
 	last_menu_track_opt = p_option;
 	switch (p_option) {
 	switch (p_option) {
@@ -5424,42 +5516,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 			}
 			}
 		} break;
 		} break;
 		case EDIT_GOTO_NEXT_STEP: {
 		case EDIT_GOTO_NEXT_STEP: {
-			if (animation.is_null()) {
-				break;
-			}
-			float step = animation->get_step();
-			if (step == 0) {
-				step = 1;
-			}
-
-			float pos = timeline->get_play_position();
-
-			pos = Math::stepify(pos + step, step);
-			if (pos > animation->get_length()) {
-				pos = animation->get_length();
-			}
-			set_anim_pos(pos);
-
-			emit_signal("timeline_changed", pos, true);
-
+			goto_next_step(false);
 		} break;
 		} break;
 		case EDIT_GOTO_PREV_STEP: {
 		case EDIT_GOTO_PREV_STEP: {
-			if (animation.is_null()) {
-				break;
-			}
-			float step = animation->get_step();
-			if (step == 0) {
-				step = 1;
-			}
-
-			float pos = timeline->get_play_position();
-			pos = Math::stepify(pos - step, step);
-			if (pos < 0) {
-				pos = 0;
-			}
-			set_anim_pos(pos);
-			emit_signal("timeline_changed", pos, true);
-
+			goto_prev_step(false);
 		} break;
 		} break;
 		case EDIT_APPLY_RESET: {
 		case EDIT_APPLY_RESET: {
 			AnimationPlayerEditor::singleton->get_player()->apply_reset(true);
 			AnimationPlayerEditor::singleton->get_player()->apply_reset(true);

+ 29 - 19
editor/animation_track_editor.h

@@ -48,10 +48,13 @@
 #include "scene/resources/animation.h"
 #include "scene/resources/animation.h"
 #include "scene_tree_editor.h"
 #include "scene_tree_editor.h"
 
 
+class AnimationTrackEdit;
+
 class AnimationTimelineEdit : public Range {
 class AnimationTimelineEdit : public Range {
 	GDCLASS(AnimationTimelineEdit, Range);
 	GDCLASS(AnimationTimelineEdit, Range);
 
 
 	Ref<Animation> animation;
 	Ref<Animation> animation;
+	AnimationTrackEdit *track_edit;
 	int name_limit;
 	int name_limit;
 	Range *zoom;
 	Range *zoom;
 	Range *h_scroll;
 	Range *h_scroll;
@@ -100,6 +103,7 @@ public:
 
 
 	virtual Size2 get_minimum_size() const;
 	virtual Size2 get_minimum_size() const;
 	void set_animation(const Ref<Animation> &p_animation);
 	void set_animation(const Ref<Animation> &p_animation);
+	void set_track_edit(AnimationTrackEdit *p_track_edit);
 	void set_zoom(Range *p_zoom);
 	void set_zoom(Range *p_zoom);
 	Range *get_zoom() const { return zoom; }
 	Range *get_zoom() const { return zoom; }
 	void set_undo_redo(UndoRedo *p_undo_redo);
 	void set_undo_redo(UndoRedo *p_undo_redo);
@@ -274,25 +278,6 @@ public:
 class AnimationTrackEditor : public VBoxContainer {
 class AnimationTrackEditor : public VBoxContainer {
 	GDCLASS(AnimationTrackEditor, VBoxContainer);
 	GDCLASS(AnimationTrackEditor, VBoxContainer);
 
 
-	enum {
-		EDIT_COPY_TRACKS,
-		EDIT_COPY_TRACKS_CONFIRM,
-		EDIT_PASTE_TRACKS,
-		EDIT_SCALE_SELECTION,
-		EDIT_SCALE_FROM_CURSOR,
-		EDIT_SCALE_CONFIRM,
-		EDIT_DUPLICATE_SELECTION,
-		EDIT_DUPLICATE_TRANSPOSED,
-		EDIT_DELETE_SELECTION,
-		EDIT_GOTO_NEXT_STEP,
-		EDIT_GOTO_PREV_STEP,
-		EDIT_APPLY_RESET,
-		EDIT_OPTIMIZE_ANIMATION,
-		EDIT_OPTIMIZE_ANIMATION_CONFIRM,
-		EDIT_CLEAN_UP_ANIMATION,
-		EDIT_CLEAN_UP_ANIMATION_CONFIRM
-	};
-
 	Ref<Animation> animation;
 	Ref<Animation> animation;
 	Node *root;
 	Node *root;
 
 
@@ -503,6 +488,25 @@ protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 
 
 public:
 public:
+	enum {
+		EDIT_COPY_TRACKS,
+		EDIT_COPY_TRACKS_CONFIRM,
+		EDIT_PASTE_TRACKS,
+		EDIT_SCALE_SELECTION,
+		EDIT_SCALE_FROM_CURSOR,
+		EDIT_SCALE_CONFIRM,
+		EDIT_DUPLICATE_SELECTION,
+		EDIT_DUPLICATE_TRANSPOSED,
+		EDIT_DELETE_SELECTION,
+		EDIT_GOTO_NEXT_STEP,
+		EDIT_GOTO_PREV_STEP,
+		EDIT_APPLY_RESET,
+		EDIT_OPTIMIZE_ANIMATION,
+		EDIT_OPTIMIZE_ANIMATION_CONFIRM,
+		EDIT_CLEAN_UP_ANIMATION,
+		EDIT_CLEAN_UP_ANIMATION_CONFIRM
+	};
+
 	void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
 	void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
 	void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
 	void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
 
 
@@ -533,6 +537,12 @@ public:
 	float snap_time(float p_value, bool p_relative = false);
 	float snap_time(float p_value, bool p_relative = false);
 	bool is_grouping_tracks();
 	bool is_grouping_tracks();
 
 
+	/** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */
+	void goto_prev_step(bool p_from_mouse_event);
+
+	/** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */
+	void goto_next_step(bool p_from_mouse_event);
+
 	MenuButton *get_edit_menu();
 	MenuButton *get_edit_menu();
 	AnimationTrackEditor();
 	AnimationTrackEditor();
 	~AnimationTrackEditor();
 	~AnimationTrackEditor();