From e6c5f88c0b826e945420cdb8fd70dcded6d683ca Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas Date: Fri, 16 Jun 2023 18:28:05 +0300 Subject: [PATCH] Add a reverse frames menu option in the right click frame menu Is enabled only when multiple frames are selected. --- Translations/Translations.pot | 4 ++ src/Classes/Project.gd | 65 ++++++++++++++-------------- src/UI/Timeline/AnimationTimeline.gd | 16 +++++++ src/UI/Timeline/FrameButton.gd | 37 ++++++++++------ src/UI/Timeline/FrameButton.tscn | 2 +- 5 files changed, 76 insertions(+), 48 deletions(-) diff --git a/Translations/Translations.pot b/Translations/Translations.pot index c14a7734f..01c89d4e5 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -1716,6 +1716,10 @@ msgstr "" msgid "Frame properties" msgstr "" +#. Found on the popup menu that appears when a user right-clicks on a frame button. When clicked, the order of the selected frames is being reversed. +msgid "Reverse Frames" +msgstr "" + msgid "Layer" msgstr "" diff --git a/src/Classes/Project.gd b/src/Classes/Project.gd index 11f232598..0875fde52 100644 --- a/src/Classes/Project.gd +++ b/src/Classes/Project.gd @@ -672,17 +672,7 @@ func add_frames(new_frames: Array, indices: Array) -> void: # indices should be # Add frame frames.insert(indices[i], new_frames[i]) Global.animation_timeline.project_frame_added(indices[i]) - # Update the frames and frame buttons: - for f in frames.size(): - Global.frame_hbox.get_child(f).frame = f - Global.frame_hbox.get_child(f).text = str(f + 1) - # Update the cel buttons: - for l in layers.size(): - var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - l) - for f in frames.size(): - cel_hbox.get_child(f).frame = f - cel_hbox.get_child(f).button_setup() - _set_timeline_first_and_last_frames() + _update_frame_ui() func remove_frames(indices: Array) -> void: # indices should be in ascending order @@ -701,17 +691,7 @@ func remove_frames(indices: Array) -> void: # indices should be in ascending or # Remove frame frames.remove(indices[i] - i) Global.animation_timeline.project_frame_removed(indices[i] - i) - # Update the frames and frame buttons: - for f in frames.size(): - Global.frame_hbox.get_child(f).frame = f - Global.frame_hbox.get_child(f).text = str(f + 1) - # Update the cel buttons: - for l in layers.size(): - var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - l) - for f in frames.size(): - cel_hbox.get_child(f).frame = f - cel_hbox.get_child(f).button_setup() - _set_timeline_first_and_last_frames() + _update_frame_ui() func move_frame(from_index: int, to_index: int) -> void: @@ -722,17 +702,7 @@ func move_frame(from_index: int, to_index: int) -> void: Global.animation_timeline.project_frame_removed(from_index) frames.insert(to_index, frame) Global.animation_timeline.project_frame_added(to_index) - # Update the frames and frame buttons: - for f in frames.size(): - Global.frame_hbox.get_child(f).frame = f - Global.frame_hbox.get_child(f).text = str(f + 1) - # Update the cel buttons: - for l in layers.size(): - var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - l) - for f in frames.size(): - cel_hbox.get_child(f).frame = f - cel_hbox.get_child(f).button_setup() - _set_timeline_first_and_last_frames() + _update_frame_ui() func swap_frame(a_index: int, b_index: int) -> void: @@ -748,6 +718,22 @@ func swap_frame(a_index: int, b_index: int) -> void: _set_timeline_first_and_last_frames() +func reverse_frames(frame_indices: Array) -> void: + Global.canvas.selection.transform_content_confirm() +# warning-ignore:integer_division + for i in frame_indices.size() / 2: + var index: int = frame_indices[i] + var reverse_index: int = frame_indices[-i - 1] + var temp: Frame = frames[index] + frames[index] = frames[reverse_index] + frames[reverse_index] = temp + Global.animation_timeline.project_frame_removed(index) + Global.animation_timeline.project_frame_added(index) + Global.animation_timeline.project_frame_removed(reverse_index) + Global.animation_timeline.project_frame_added(reverse_index) + _set_timeline_first_and_last_frames() + + func add_layers(new_layers: Array, indices: Array, cels: Array) -> void: # cels is 2d Array of cels Global.canvas.selection.transform_content_confirm() selected_cels.clear() @@ -899,3 +885,16 @@ func swap_cel(a_frame: int, a_layer: int, b_frame: int, b_layer: int) -> void: Global.animation_timeline.project_cel_added(a_frame, a_layer) Global.animation_timeline.project_cel_removed(b_frame, b_layer) Global.animation_timeline.project_cel_added(b_frame, b_layer) + + +func _update_frame_ui() -> void: + for f in frames.size(): # Update the frames and frame buttons + Global.frame_hbox.get_child(f).frame = f + Global.frame_hbox.get_child(f).text = str(f + 1) + + for l in layers.size(): # Update the cel buttons + var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - l) + for f in frames.size(): + cel_hbox.get_child(f).frame = f + cel_hbox.get_child(f).button_setup() + _set_timeline_first_and_last_frames() diff --git a/src/UI/Timeline/AnimationTimeline.gd b/src/UI/Timeline/AnimationTimeline.gd index ee67ee7c1..214d77b84 100644 --- a/src/UI/Timeline/AnimationTimeline.gd +++ b/src/UI/Timeline/AnimationTimeline.gd @@ -389,6 +389,22 @@ func _on_MoveRight_pressed() -> void: Global.frame_hbox.get_child(frame).change_frame_order(1) +func reverse_frames() -> void: + var project = Global.current_project + var indices := [] + for cel in Global.current_project.selected_cels: + var f: int = cel[0] + if not f in indices: + indices.append(f) + indices.sort() + project.undo_redo.create_action("Change Frame Order") + project.undo_redo.add_do_method(project, "reverse_frames", indices) + project.undo_redo.add_undo_method(project, "reverse_frames", indices) + project.undo_redo.add_undo_method(Global, "undo_or_redo", true) + project.undo_redo.add_do_method(Global, "undo_or_redo", false) + project.undo_redo.commit_action() + + func _on_OnionSkinning_pressed() -> void: Global.onion_skinning = !Global.onion_skinning Global.canvas.refresh_onion() diff --git a/src/UI/Timeline/FrameButton.gd b/src/UI/Timeline/FrameButton.gd index 27b03a986..49e071ab4 100644 --- a/src/UI/Timeline/FrameButton.gd +++ b/src/UI/Timeline/FrameButton.gd @@ -1,5 +1,7 @@ extends Button +enum { REMOVE, CLONE, MOVE_LEFT, MOVE_RIGHT, PROPERTIES, REVERSE } + var frame := 0 onready var popup_menu: PopupMenu = $PopupMenu @@ -15,7 +17,7 @@ func _ready() -> void: func _update_tooltip() -> void: var duration: float = Global.current_project.frames[frame].duration - var duration_sec: float = duration * (1.0 / Global.current_project.fps) + var duration_sec := duration * (1.0 / Global.current_project.fps) var duration_str := str(duration_sec) if "." in duration_str: # If its a decimal value duration_str = "%.2f" % duration_sec # Up to 2 decimal places @@ -25,9 +27,9 @@ func _update_tooltip() -> void: func _button_pressed() -> void: if Input.is_action_just_released("left_mouse"): Global.canvas.selection.transform_content_confirm() - var prev_curr_frame: int = Global.current_project.current_frame + var prev_curr_frame := Global.current_project.current_frame if Input.is_action_pressed("shift"): - var frame_diff_sign = sign(frame - prev_curr_frame) + var frame_diff_sign := sign(frame - prev_curr_frame) if frame_diff_sign == 0: frame_diff_sign = 1 for i in range(prev_curr_frame, frame + frame_diff_sign, frame_diff_sign): @@ -50,15 +52,20 @@ func _button_pressed() -> void: elif Input.is_action_just_released("right_mouse"): if Global.current_project.frames.size() == 1: - popup_menu.set_item_disabled(0, true) - popup_menu.set_item_disabled(2, true) - popup_menu.set_item_disabled(3, true) + popup_menu.set_item_disabled(REMOVE, true) + popup_menu.set_item_disabled(MOVE_LEFT, true) + popup_menu.set_item_disabled(MOVE_RIGHT, true) + popup_menu.set_item_disabled(REVERSE, true) else: - popup_menu.set_item_disabled(0, false) + popup_menu.set_item_disabled(REMOVE, false) + if Global.current_project.selected_cels.size() > 1: + popup_menu.set_item_disabled(REVERSE, false) + else: + popup_menu.set_item_disabled(REVERSE, true) if frame > 0: - popup_menu.set_item_disabled(2, false) + popup_menu.set_item_disabled(MOVE_LEFT, false) if frame < Global.current_project.frames.size() - 1: - popup_menu.set_item_disabled(3, false) + popup_menu.set_item_disabled(MOVE_RIGHT, false) popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE)) pressed = !pressed elif Input.is_action_just_released("middle_mouse"): @@ -70,19 +77,21 @@ func _button_pressed() -> void: func _on_PopupMenu_id_pressed(id: int) -> void: match id: - 0: # Remove Frame + REMOVE: Global.animation_timeline.delete_frames() - 1: # Clone Frame + CLONE: Global.animation_timeline.copy_frames() - 2: # Move Left + MOVE_LEFT: change_frame_order(-1) - 3: # Move Right + MOVE_RIGHT: change_frame_order(1) - 4: # Frame Properties + PROPERTIES: frame_properties.popup_centered() Global.dialog_open(true) frame_properties.set_frame_label(frame) frame_properties.set_frame_dur(Global.current_project.frames[frame].duration) + REVERSE: + Global.animation_timeline.reverse_frames() func change_frame_order(rate: int) -> void: diff --git a/src/UI/Timeline/FrameButton.tscn b/src/UI/Timeline/FrameButton.tscn index 37ae95090..6a2b6329d 100644 --- a/src/UI/Timeline/FrameButton.tscn +++ b/src/UI/Timeline/FrameButton.tscn @@ -20,7 +20,7 @@ __meta__ = { margin_right = 20.0 margin_bottom = 20.0 mouse_default_cursor_shape = 2 -items = [ "Remove Frame", null, 0, false, true, -1, 0, null, "", false, "Clone Frame", null, 0, false, false, -1, 0, null, "", false, "Move Left", null, 0, false, true, -1, 0, null, "", false, "Move Right", null, 0, false, true, -1, 0, null, "", false, "Frame Properties", null, 0, false, false, -1, 0, null, "", false ] +items = [ "Remove Frame", null, 0, false, true, -1, 0, null, "", false, "Clone Frame", null, 0, false, false, -1, 0, null, "", false, "Move Left", null, 0, false, true, -1, 0, null, "", false, "Move Right", null, 0, false, true, -1, 0, null, "", false, "Frame Properties", null, 0, false, false, -1, 0, null, "", false, "Reverse Frames", null, 0, false, true, 5, 0, null, "", false ] __meta__ = { "_edit_use_anchors_": false }