Skip to content

Commit

Permalink
Make bezier handle type a property of keyframes, update interface
Browse files Browse the repository at this point in the history
- Remove unused code related to old close icon (now replaced with a button)
- Add bezier handle options to right-click menu
- Provide optional scale for balanced handle move
- Remove mirror handle mode, only keep balanced
- Update animation reference
  • Loading branch information
NathanLovato committed Oct 2, 2021
1 parent 06e2cef commit 7d20bc8
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 110 deletions.
23 changes: 23 additions & 0 deletions doc/classes/Animation.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@
Sets the stream of the key identified by [code]key_idx[/code] to value [code]stream[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="bezier_track_get_key_handle_mode" qualifiers="const">
<return type="int" />
<argument index="0" name="track_idx" type="int" />
<argument index="1" name="key_idx" type="int" />
<description>
Returns the handle mode of the key identified by [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_get_key_in_handle" qualifiers="const">
<return type="Vector2" />
<argument index="0" name="track_idx" type="int" />
Expand Down Expand Up @@ -174,6 +182,15 @@
Returns the interpolated value at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_handle_mode">
<return type="void" />
<argument index="0" name="track_idx" type="int" />
<argument index="1" name="key_idx" type="int" />
<argument index="2" name="key_handle_mode" type="int" enum="Animation.HandleMode" />
<description>
Changes the handle mode of the keyframe at the given [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_in_handle">
<return type="void" />
<argument index="0" name="track_idx" type="int" />
Expand Down Expand Up @@ -577,5 +594,11 @@
<constant name="UPDATE_CAPTURE" value="3" enum="UpdateMode">
Same as linear interpolation, but also interpolates from the current value (i.e. dynamically at runtime) if the first key isn't at 0 seconds.
</constant>
<constant name="HANDLE_MODE_FREE" value="0" enum="HandleMode">
Assigning the free handle mode to a Bezier Track's keyframe allows you to edit the keyframe's left and right handles independently from one another.
</constant>
<constant name="HANDLE_MODE_BALANCED" value="1" enum="HandleMode">
Assigning the balanced handle mode to a Bezier Track's keyframe makes it so the two handles of the keyframe always stay aligned when changing either the keyframe's left or right handle.
</constant>
</constants>
</class>
110 changes: 52 additions & 58 deletions editor/animation_bezier_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,6 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
bezier_icon = get_theme_icon(SNAME("KeyBezierPoint"), SNAME("EditorIcons"));
bezier_handle_icon = get_theme_icon(SNAME("KeyBezierHandle"), SNAME("EditorIcons"));
selected_icon = get_theme_icon(SNAME("KeyBezierSelected"), SNAME("EditorIcons"));
if (handle_mode_option->get_item_count() == 0) {
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Free"), HANDLE_MODE_FREE);
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Balanced"), HANDLE_MODE_BALANCED);
handle_mode_option->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Mirror"), HANDLE_MODE_MIRROR);
}
}
if (p_what == NOTIFICATION_RESIZED) {
int right_limit = get_size().width - timeline->get_buttons_width();
Expand Down Expand Up @@ -581,11 +576,21 @@ void AnimationBezierTrackEdit::_clear_selection() {
update();
}

void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) {
undo_redo->create_action(TTR("Update Selected Key Handles"));
for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
const int key_index = E->get();
animation->bezier_track_set_key_handle_mode(track, key_index, p_mode);
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, animation->bezier_track_get_key_handle_mode(track, key_index));
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, p_mode);
}
undo_redo->commit_action();
}

void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p_anim) {
if (!(animation == p_anim)) {
return;
}
//selection.clear();
_clear_selection();
}

Expand Down Expand Up @@ -667,6 +672,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
menu->add_separator();
menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
menu->add_separator();
menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
}

menu->set_as_minsize();
Expand All @@ -676,10 +684,6 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}

if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (close_icon_rect.has_point(mb->get_position())) {
emit_signal(SNAME("close_request"));
return;
}
for (const KeyValue<int, Rect2> &E : subtracks) {
if (E.value.has_point(mb->get_position())) {
set_animation_and_track(animation, E.key);
Expand Down Expand Up @@ -746,7 +750,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//insert new point
if (mb->is_command_pressed() && mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
Array new_point;
new_point.resize(5);
new_point.resize(6);

float h = (get_size().height / 2 - mb->get_position().y) * v_zoom + v_scroll;

Expand All @@ -755,6 +759,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
new_point[5] = 0;

float time = ((mb->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(track, time, true) != -1) {
Expand Down Expand Up @@ -822,18 +827,6 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
update();
}

if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
undo_redo->create_action(TTR("Move Bezier Points"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left);
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right);
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, animation->bezier_track_get_key_in_handle(track, moving_handle_key));
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, animation->bezier_track_get_key_out_handle(track, moving_handle_key));
undo_redo->commit_action();

moving_handle = 0;
update();
}

if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (moving_selection) {
//combit it
Expand Down Expand Up @@ -973,46 +966,43 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
update();
}

if (moving_handle != 0 && mm.is_valid()) {
float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();

Vector2 key_pos = Vector2(animation->track_get_key_time(track, moving_handle_key), animation->bezier_track_get_key_value(track, moving_handle_key));

Vector2 moving_handle_value = Vector2(x, y) - key_pos;

const bool is_dragging_key_handle = moving_handle != 0 && mm.is_valid();
if (is_dragging_key_handle) {
moving_handle_left = animation->bezier_track_get_key_in_handle(track, moving_handle_key);
moving_handle_right = animation->bezier_track_get_key_out_handle(track, moving_handle_key);

const float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
const float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
const Vector2 key_pos = Vector2(animation->track_get_key_time(track, moving_handle_key), animation->bezier_track_get_key_value(track, moving_handle_key));
const Vector2 moving_handle_value = Vector2(x, y) - key_pos;

const Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
if (moving_handle == -1) {
animation->bezier_track_set_key_in_handle(track, moving_handle_key, moving_handle_value, scale);
moving_handle_left = moving_handle_value;
if (moving_handle_left.x > 0) {
moving_handle_left.x = 0;
}

if (handle_mode_option->get_selected() == HANDLE_MODE_BALANCED) {
Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
moving_handle_right = (-(moving_handle_left * scale).normalized() * (moving_handle_right * scale).length()) / scale;

} else if (handle_mode_option->get_selected() == HANDLE_MODE_MIRROR) {
moving_handle_right = -moving_handle_left;
}
}

if (moving_handle == 1) {
moving_handle_right = animation->bezier_track_get_key_out_handle(track, moving_handle_key);
} else if (moving_handle == 1) {
animation->bezier_track_set_key_out_handle(track, moving_handle_key, moving_handle_value, scale);
moving_handle_right = moving_handle_value;
if (moving_handle_right.x < 0) {
moving_handle_right.x = 0;
}
moving_handle_left = animation->bezier_track_get_key_in_handle(track, moving_handle_key);
}
update();
}

if (handle_mode_option->get_selected() == HANDLE_MODE_BALANCED) {
Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
moving_handle_left = (-(moving_handle_right * scale).normalized() * (moving_handle_left * scale).length()) / scale;
} else if (handle_mode_option->get_selected() == HANDLE_MODE_MIRROR) {
moving_handle_left = -moving_handle_right;
}
const bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT;
if (is_finishing_key_handle_drag) {
undo_redo->create_action(TTR("Move Bezier Points"));
const Vector2 scale = Vector2(timeline->get_zoom_scale(), v_zoom);
if (moving_handle == -1) {
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left, scale);
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, animation->bezier_track_get_key_in_handle(track, moving_handle_key));
} else if (moving_handle == 1) {
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right, scale);
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, animation->bezier_track_get_key_out_handle(track, moving_handle_key));
}
undo_redo->commit_action();

moving_handle = 0;
update();
}
}
Expand All @@ -1021,7 +1011,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
switch (p_index) {
case MENU_KEY_INSERT: {
Array new_point;
new_point.resize(5);
new_point.resize(6);

float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;

Expand All @@ -1030,6 +1020,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
new_point[5] = 0;

float time = ((menu_insert_key.x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(track, time, true) != -1) {
Expand All @@ -1048,6 +1039,12 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
case MENU_KEY_DELETE: {
delete_selection();
} break;
case MENU_KEY_SET_HANDLE_FREE: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
} break;
case MENU_KEY_SET_HANDLE_BALANCED: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED);
} break;
}
}

Expand Down Expand Up @@ -1150,8 +1147,6 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
set_focus_mode(FOCUS_CLICK);

set_clip_contents(true);
handle_mode = HANDLE_MODE_FREE;
handle_mode_option = memnew(OptionButton);

close_button = memnew(Button);
close_button->connect("pressed", Callable(this, SNAME("emit_signal")), varray(SNAME("close_request")));
Expand All @@ -1160,7 +1155,6 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
right_column = memnew(VBoxContainer);
right_column->add_child(close_button);
right_column->add_spacer();
right_column->add_child(handle_mode_option);
add_child(right_column);

menu = memnew(PopupMenu);
Expand Down
17 changes: 5 additions & 12 deletions editor/animation_bezier_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,14 @@
class AnimationBezierTrackEdit : public Control {
GDCLASS(AnimationBezierTrackEdit, Control);

enum HandleMode {
HANDLE_MODE_FREE,
HANDLE_MODE_BALANCED,
HANDLE_MODE_MIRROR
};

enum {
MENU_KEY_INSERT,
MENU_KEY_DUPLICATE,
MENU_KEY_DELETE
MENU_KEY_DELETE,
MENU_KEY_SET_HANDLE_FREE,
MENU_KEY_SET_HANDLE_BALANCED,
};

HandleMode handle_mode;
OptionButton *handle_mode_option;

VBoxContainer *right_column;
Button *close_button;

Expand All @@ -69,8 +62,6 @@ class AnimationBezierTrackEdit : public Control {
Ref<Texture2D> bezier_handle_icon;
Ref<Texture2D> selected_icon;

Rect2 close_icon_rect;

Map<int, Rect2> subtracks;

float v_scroll = 0;
Expand Down Expand Up @@ -104,10 +95,12 @@ class AnimationBezierTrackEdit : public Control {
int moving_handle_key = 0;
Vector2 moving_handle_left;
Vector2 moving_handle_right;
int moving_handle_mode; // value from Animation::HandleMode

void _clear_selection();
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
void _change_selected_keys_handle_mode(Animation::HandleMode p_mode);

Vector2 menu_insert_key;

Expand Down
Loading

0 comments on commit 7d20bc8

Please sign in to comment.