Skip to content

Commit 8a6fcd5

Browse files
QOL improvements when adding or selecting keyframes (#1423)
* Add support for animated layer effects and a keyframe-based timeline (#1417) * Start working on animatable layer effects * Interpolate colors & animated effects work on apply * Add nodes to change tween properties * Use smaller texts for the tween property option buttons * Fix crash when enabling animation, disabling and enabling it again * Remove keyframes * Load and save animated parameters in pxo files * Format * Start working on a keyframe based timeline * Create keyframes in the UI * Start working on keyframe value changing * Remove animated layer effect code from the layer FX settings * Refactor animated_params dictionary * Probably fix pxo loading At least old pxo files seem to be working properly * Update timeline when adding/removing keyframes * Use a tree for the layer elements Need to implement folding logic for the keyframes themselves though * Add a timeline cursor * Improve cursor moving logic * More timeline cursor improvements * Some UI improvements * Make timeline a bit prettier * Fix animated params pxo loading * Some small improvements * Fix scrolling * Don't create keyframe if there already is one * Fix frame container not resizing when clicking on keyframes * Added Constant transition * Add undo/redo when adding and deleting keyframes * Fix keyframe unselection * Start working on multiple selected keyframes * Change name of a script * Change properties of all selected keyframes With undo/redo support * [WIP] Move keyframes While it technically works, the UI side is not being updated. Also, I just realized that the way we're handling keyframe creation and deletion is wrong, because the nodes get freed when switching to a different layer, or a different project. So we most likely should just re-create the keyframe nodes when we add, delete or move them. Which means I also need to change the selected_keyframes array to store param_name and frame_index, instead of nodes. * Add IDs to keyframes for easier handling * Don't allow keyframes to go below frame 0 Mostly so they can't be lost. The proper solution would be to support negative frames, like Godot's animation player editor does, but this should work for now. * Zoom in the timeline * Support booleans and colors, scroll timeline when changing cel or layer * Implement the keyframe timeline inside the main timeline panel I feel like the UI does need some improvements still * Make properties grid container and delete keyframe button persistent nodes * Undo/redo refreshes the keyframe property UI * Hide tags when keyframe timeline is visible * Fix property nodes not having the correct name * Use a custom node to draw frames instead of using labels * Fix group layers passthrough mode not having its effect be animated * Don't create tracks for properties that currently cannot be animated Such as textures * Better documentation and future-proofing * Keyframe Animation QOL inprovements (#1420) * Fix keyframe getting created at the wrong frame when the uses right clicks at the same 'x-position' as the frame marking * Hide extra UI when no FX are present * formatting * Rename _hide_extra_UI to _hide_extra_ui Fix linting error --------- Co-authored-by: Emmanouil Papadeas <[email protected]> * Select newly added keyframe * only select keyframe if it's added for the first time * Improve selection of keyframes * Formatting * To move single keyframe, you no longer have to select it first * Formatting * Snap cursor to frame when drag is released * formatting --------- Co-authored-by: Emmanouil Papadeas <[email protected]>
1 parent a15cc8d commit 8a6fcd5

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

src/UI/Timeline/KeyframeTimeline/KeyframeButton.gd

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,22 @@ func _init() -> void:
2525

2626
func _on_gui_input(event: InputEvent) -> void:
2727
var selected_keyframe_buttons := KeyframeTimeline.get_selected_keyframe_buttons()
28-
if not self in selected_keyframe_buttons:
29-
return
3028
var parent := get_parent() as Control
29+
if not self in selected_keyframe_buttons:
30+
# Check if it was pressed just recently, if it is then we have to reset
31+
# selected_keyframe_buttons
32+
if (
33+
(
34+
event is InputEventMouseButton
35+
and event.button_index == MOUSE_BUTTON_LEFT
36+
and event.pressed
37+
and get_rect().has_point(parent.get_local_mouse_position())
38+
)
39+
or is_dragged
40+
):
41+
selected_keyframe_buttons = [self]
42+
else:
43+
return
3144
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
3245
if event.pressed:
3346
is_dragged = true
@@ -37,6 +50,12 @@ func _on_gui_input(event: InputEvent) -> void:
3750
else:
3851
if is_dragged:
3952
is_dragged = false
53+
# if the button was clicked to drag, while it wasn't selected then the
54+
# pressed signal isn't emitted yet (it emits on release), so we have to manually
55+
# emit it first
56+
if not button_pressed and self in selected_keyframe_buttons:
57+
button_pressed = true
58+
pressed.emit()
4059
updated_position.emit()
4160

4261
if event is InputEventMouseMotion and is_dragged:

src/UI/Timeline/KeyframeTimeline/KeyframeTimeline.gd

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ func append_keyframes_to_selection(rect: Rect2) -> void:
332332
for keyframe_button in track.get_children():
333333
if keyframe_button is not KeyframeButton:
334334
continue
335-
if rect.has_point(keyframe_button.position + track.position):
335+
var key_rect := Rect2(keyframe_button.position + track.position, keyframe_button.size)
336+
if rect.intersects(key_rect):
336337
selected_keyframes.append(keyframe_button.keyframe_id)
337338
keyframe_button.button_pressed = true
338339
select_keyframes()
@@ -394,6 +395,7 @@ func _update_keyframe_property_ui(dict: Dictionary, keyframe_id: int) -> void:
394395

395396
func add_effect_keyframe(effect: LayerEffect, frame_index: int, param_name: String) -> void:
396397
var next_keyframe_id := effect.layer.next_keyframe_id
398+
selected_keyframes = [next_keyframe_id]
397399
var undo_redo := Global.current_project.undo_redo
398400
undo_redo.create_action("Add keyframe")
399401
undo_redo.add_do_method(effect.set_keyframe.bind(param_name, frame_index))

src/UI/Timeline/KeyframeTimeline/KeyframeTimelineCursor.gd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,18 @@ func _on_keyframe_timeline_frame_display_gui_input(event: InputEvent) -> void:
3939
is_dragged = true
4040
_change_cel(event.global_position)
4141
else:
42+
# Snap the cursor to the frame, as we don't have any useful behavior defined for
43+
# cursor being in the middle of frames, this makes more sense
44+
var container_pos := keyframe_timeline_frame_display.get_global_rect().position.x
45+
var x_offset := keyframe_timeline_frame_display.x_offset
46+
var frame_pos = (
47+
Global.current_project.current_frame * KeyframeTimeline.frame_ui_size
48+
+ container_pos
49+
- x_offset
50+
)
51+
pos = frame_pos
4252
is_dragged = false
53+
4354
if event is InputEventMouseMotion and is_dragged:
4455
_change_cel(event.global_position)
4556

0 commit comments

Comments
 (0)