summaryrefslogtreecommitdiffstats
path: root/editor/animation_bezier_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/animation_bezier_editor.cpp')
-rw-r--r--editor/animation_bezier_editor.cpp205
1 files changed, 147 insertions, 58 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index fd06bf0533..a16446aea6 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/gui/editor_spin_slider.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/view_panner.h"
#include "scene/resources/text_line.h"
@@ -266,23 +267,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
RBMap<String, Vector<int>> track_indices;
int track_count = animation->get_track_count();
for (int i = 0; i < track_count; ++i) {
- if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
+ if (!_is_track_displayed(i)) {
continue;
}
String base_path = animation->track_get_path(i);
- if (is_filtered) {
- if (root && root->has_node(base_path)) {
- Node *node = root->get_node(base_path);
- if (!node) {
- continue; // No node, no filter.
- }
- if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
- continue; // Skip track due to not selected.
- }
- }
- }
-
int end = base_path.find(":");
if (end != -1) {
base_path = base_path.substr(0, end + 1);
@@ -520,28 +509,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
float scale = timeline->get_zoom_scale();
for (int i = 0; i < track_count; ++i) {
- if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i)) {
- continue;
- }
-
- if (hidden_tracks.has(i) || locked_tracks.has(i)) {
+ if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) {
continue;
}
int key_count = animation->track_get_key_count(i);
- String path = animation->track_get_path(i);
-
- if (is_filtered) {
- if (root && root->has_node(path)) {
- Node *node = root->get_node(path);
- if (!node) {
- continue; // No node, no filter.
- }
- if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
- continue; // Skip track due to not selected.
- }
- }
- }
for (int j = 0; j < key_count; ++j) {
float offset = animation->track_get_key_time(i, j);
@@ -648,6 +620,43 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
}
+// Check if a track is displayed in the bezier editor (track type = bezier and track not filtered).
+bool AnimationBezierTrackEdit::_is_track_displayed(int p_track_index) {
+ if (animation->track_get_type(p_track_index) != Animation::TrackType::TYPE_BEZIER) {
+ return false;
+ }
+
+ if (is_filtered) {
+ String path = animation->track_get_path(p_track_index);
+ if (root && root->has_node(path)) {
+ Node *node = root->get_node(path);
+ if (!node) {
+ return false; // No node, no filter.
+ }
+ if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ return false; // Skip track due to not selected.
+ }
+ }
+ }
+
+ return true;
+}
+
+// Check if the curves for a track are displayed in the editor (not hidden). Includes the check on the track visibility.
+bool AnimationBezierTrackEdit::_is_track_curves_displayed(int p_track_index) {
+ //Is the track is visible in the editor?
+ if (!_is_track_displayed(p_track_index)) {
+ return false;
+ }
+
+ //And curves visible?
+ if (hidden_tracks.has(p_track_index)) {
+ return false;
+ }
+
+ return true;
+}
+
Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
return animation;
}
@@ -741,6 +750,60 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
queue_redraw();
}
+void AnimationBezierTrackEdit::auto_fit_vertically() {
+ int track_count = animation->get_track_count();
+ real_t minimum_value = INFINITY;
+ real_t maximum_value = -INFINITY;
+
+ int nb_track_visible = 0;
+ for (int i = 0; i < track_count; ++i) {
+ if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) {
+ continue;
+ }
+
+ int key_count = animation->track_get_key_count(i);
+
+ for (int j = 0; j < key_count; ++j) {
+ real_t value = animation->bezier_track_get_key_value(i, j);
+
+ minimum_value = MIN(value, minimum_value);
+ maximum_value = MAX(value, maximum_value);
+
+ // We also want to includes the handles...
+ Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
+ Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
+
+ minimum_value = MIN(value + in_vec.y, minimum_value);
+ maximum_value = MAX(value + in_vec.y, maximum_value);
+ minimum_value = MIN(value + out_vec.y, minimum_value);
+ maximum_value = MAX(value + out_vec.y, maximum_value);
+ }
+
+ nb_track_visible++;
+ }
+
+ if (nb_track_visible == 0) {
+ // No visible track... we will not adjust the vertical zoom
+ return;
+ }
+
+ if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) {
+ _zoom_vertically(minimum_value, maximum_value);
+ queue_redraw();
+ }
+}
+
+void AnimationBezierTrackEdit::_zoom_vertically(real_t p_minimum_value, real_t p_maximum_value) {
+ real_t target_height = p_maximum_value - p_minimum_value;
+ if (target_height <= CMP_EPSILON) {
+ timeline_v_scroll = p_maximum_value;
+ return;
+ }
+
+ timeline_v_scroll = (p_maximum_value + p_minimum_value) / 2.0;
+ timeline_v_zoom = target_height / ((get_size().height - timeline->get_size().height) * 0.9);
+}
+
void AnimationBezierTrackEdit::_zoom_changed() {
queue_redraw();
play_position->queue_redraw();
@@ -838,7 +901,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) {
if (ED_IS_SHORTCUT("animation_editor/duplicate_selected_keys", p_event)) {
if (!read_only) {
- duplicate_selected_keys(-1.0);
+ duplicate_selected_keys(-1.0, false);
}
accept_event();
}
@@ -856,7 +919,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("animation_editor/paste_keys", p_event)) {
if (!read_only) {
- paste_keys(-1.0);
+ paste_keys(-1.0, false);
}
accept_event();
}
@@ -931,10 +994,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) {
- timeline_v_scroll = (maximum_value + minimum_value) / 2.0;
- if (maximum_value - minimum_value > CMP_EPSILON) {
- timeline_v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
- }
+ _zoom_vertically(minimum_value, maximum_value);
}
queue_redraw();
@@ -1179,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();
@@ -1260,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();
@@ -1274,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) {
@@ -1298,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;
@@ -1316,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);
}
@@ -1358,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);
@@ -1366,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();
}
}
@@ -1385,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();
@@ -1503,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);
@@ -1583,25 +1657,28 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
- while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
- time += 0.001;
- }
-
switch (p_index) {
case MENU_KEY_INSERT: {
if (animation->get_track_count() > 0) {
+ if (editor->snap->is_pressed() && editor->step->get_value() != 0) {
+ time = editor->snap_time(time);
+ }
+ while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
+ time += 0.001;
+ }
float h = (get_size().height / 2.0 - menu_insert_key.y) * timeline_v_zoom + timeline_v_scroll;
Array new_point = make_default_bezier_key(h);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
queue_redraw();
}
} break;
case MENU_KEY_DUPLICATE: {
- duplicate_selected_keys(time);
+ duplicate_selected_keys(time, true);
} break;
case MENU_KEY_DELETE: {
delete_selection();
@@ -1613,7 +1690,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
copy_selected_keys(false);
} break;
case MENU_KEY_PASTE: {
- paste_keys(time);
+ paste_keys(time, true);
} break;
case MENU_KEY_SET_HANDLE_FREE: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
@@ -1636,7 +1713,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
}
}
-void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs) {
+void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs, bool p_ofs_valid) {
if (selection.size() == 0) {
return;
}
@@ -1656,7 +1733,14 @@ void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs) {
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t t = animation->track_get_key_time(E->get().first, E->get().second);
- real_t insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position();
+ real_t insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position();
+
+ if (p_ofs_valid) {
+ if (editor->snap->is_pressed() && editor->step->get_value() != 0) {
+ insert_pos = editor->snap_time(insert_pos);
+ }
+ }
+
real_t dst_time = t + (insert_pos - top_time);
int existing_idx = animation->track_find_key(E->get().first, dst_time, Animation::FIND_MODE_APPROX);
@@ -1734,7 +1818,7 @@ void AnimationBezierTrackEdit::copy_selected_keys(bool p_cut) {
}
}
-void AnimationBezierTrackEdit::paste_keys(real_t p_ofs) {
+void AnimationBezierTrackEdit::paste_keys(real_t p_ofs, bool p_ofs_valid) {
if (editor->is_key_clipboard_active() && animation.is_valid() && (selected_track >= 0 && selected_track < animation->get_track_count())) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Paste Keys"));
@@ -1765,7 +1849,12 @@ void AnimationBezierTrackEdit::paste_keys(real_t p_ofs) {
for (int i = 0; i < editor->key_clipboard.keys.size(); i++) {
const AnimationTrackEditor::KeyClipboard::Key key = editor->key_clipboard.keys[i];
- float insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position();
+ float insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position();
+ if (p_ofs_valid) {
+ if (editor->snap->is_pressed() && editor->step->get_value() != 0) {
+ insert_pos = editor->snap_time(insert_pos);
+ }
+ }
float dst_time = key.time + insert_pos;
int existing_idx = animation->track_find_key(selected_track, dst_time, Animation::FIND_MODE_APPROX);