1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-31 07:29:49 +00:00

Move all selected frames - implements #743

This only works for frames at the moment, not layers and cels. Layers may be harder to support because they also have children. Supports both the "move left/right" options and drag and dropping. Frame swapping (with control) only works when one frame is selected, because I am unsure how they should be handled, especially when the selected frames are not continuous.

Didn't encounter any issues on my testing, but more testing is always welcome.
This commit is contained in:
Emmanouil Papadeas 2024-04-11 18:03:43 +03:00
parent 529962f91f
commit 7507206726
3 changed files with 81 additions and 58 deletions

View file

@ -630,14 +630,18 @@ func remove_frames(indices: Array) -> void: # indices should be in ascending or
_update_frame_ui() _update_frame_ui()
func move_frame(from_index: int, to_index: int) -> void: # from_indices and to_indicies should be in ascending order
func move_frames(from_indices: PackedInt32Array, to_indices: PackedInt32Array) -> void:
Global.canvas.selection.transform_content_confirm() Global.canvas.selection.transform_content_confirm()
selected_cels.clear() selected_cels.clear()
var frame := frames[from_index] var removed_frames := []
frames.remove_at(from_index) for i in from_indices.size():
Global.animation_timeline.project_frame_removed(from_index) # With each removed index, future indices need to be lowered, so subtract by i
frames.insert(to_index, frame) removed_frames.append(frames.pop_at(from_indices[i] - i))
Global.animation_timeline.project_frame_added(to_index) Global.animation_timeline.project_frame_removed(from_indices[i] - i)
for i in to_indices.size():
frames.insert(to_indices[i], removed_frames[i])
Global.animation_timeline.project_frame_added(to_indices[i])
_update_frame_ui() _update_frame_ui()

View file

@ -509,13 +509,46 @@ func _on_FrameTagButton_pressed() -> void:
func _on_MoveLeft_pressed() -> void: func _on_MoveLeft_pressed() -> void:
if Global.current_project.current_frame == 0: if Global.current_project.current_frame == 0:
return return
Global.frame_hbox.get_child(Global.current_project.current_frame).change_frame_order(-1) move_frames(Global.current_project.current_frame, -1)
func _on_MoveRight_pressed() -> void: func _on_MoveRight_pressed() -> void:
if Global.current_project.current_frame == Global.current_project.frames.size() - 1: if Global.current_project.current_frame == Global.current_project.frames.size() - 1:
return return
Global.frame_hbox.get_child(Global.current_project.current_frame).change_frame_order(1) move_frames(Global.current_project.current_frame, 1)
func move_frames(frame: int, rate: int) -> void:
var project := Global.current_project
var frame_indices: PackedInt32Array = []
var moved_frame_indices: PackedInt32Array = []
for cel in project.selected_cels:
var frame_index: int = cel[0]
if not frame_indices.has(frame_index):
frame_indices.append(frame_index)
moved_frame_indices.append(frame_index + rate)
frame_indices.sort()
moved_frame_indices.sort()
if not frame in frame_indices:
frame_indices = [frame]
moved_frame_indices = [frame + rate]
for moved_index in moved_frame_indices:
# Don't allow frames to be moved if they are out of bounds
if moved_index < 0 or moved_index >= project.frames.size():
return
project.undo_redo.create_action("Change Frame Order")
project.undo_redo.add_do_method(project.move_frames.bind(frame_indices, moved_frame_indices))
project.undo_redo.add_undo_method(project.move_frames.bind(moved_frame_indices, frame_indices))
if project.current_frame in frame_indices:
project.undo_redo.add_do_method(project.change_cel.bind(frame + rate))
else:
project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true))
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))
project.undo_redo.commit_action()
func reverse_frames(indices := []) -> void: func reverse_frames(indices := []) -> void:

View file

@ -84,9 +84,9 @@ func _on_PopupMenu_id_pressed(id: int) -> void:
CLONE: CLONE:
Global.animation_timeline.copy_frames(indices) Global.animation_timeline.copy_frames(indices)
MOVE_LEFT: MOVE_LEFT:
change_frame_order(-1) Global.animation_timeline.move_frames(frame, -1)
MOVE_RIGHT: MOVE_RIGHT:
change_frame_order(1) Global.animation_timeline.move_frames(frame, 1)
PROPERTIES: PROPERTIES:
frame_properties.frame_indices = indices frame_properties.frame_indices = indices
frame_properties.popup_centered() frame_properties.popup_centered()
@ -97,25 +97,6 @@ func _on_PopupMenu_id_pressed(id: int) -> void:
DrawingAlgos.center(indices) DrawingAlgos.center(indices)
func change_frame_order(rate: int) -> void:
var change := frame + rate
var project := Global.current_project
project.undo_redo.create_action("Change Frame Order")
project.undo_redo.add_do_method(project.move_frame.bind(frame, change))
project.undo_redo.add_undo_method(project.move_frame.bind(change, frame))
if project.current_frame == frame:
project.undo_redo.add_do_method(project.change_cel.bind(change))
else:
project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true))
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))
project.undo_redo.commit_action()
func _get_drag_data(_position: Vector2) -> Variant: func _get_drag_data(_position: Vector2) -> Variant:
var button := Button.new() var button := Button.new()
button.size = size button.size = size
@ -123,50 +104,55 @@ func _get_drag_data(_position: Vector2) -> Variant:
button.text = text button.text = text
set_drag_preview(button) set_drag_preview(button)
return ["Frame", frame] return ["Frame", _get_frame_indices()]
func _can_drop_data(_pos: Vector2, data) -> bool: func _can_drop_data(_pos: Vector2, data) -> bool:
if typeof(data) == TYPE_ARRAY: if typeof(data) != TYPE_ARRAY:
if data[0] == "Frame": Global.animation_timeline.drag_highlight.visible = false
if data[1] != frame: # Can't move to same frame return false
var region: Rect2 if data[0] != "Frame":
if Input.is_action_pressed("ctrl"): # Swap frames Global.animation_timeline.drag_highlight.visible = false
region = get_global_rect() return false
else: # Move frames var drop_frames: PackedInt32Array = data[1]
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Can't move to same frame
region = _get_region_rect(-0.125, 0.125) if drop_frames[-1] == frame:
region.position.x -= 2 # Container spacing Global.animation_timeline.drag_highlight.visible = false
else: return false
region = _get_region_rect(0.875, 1.125) var region: Rect2
region.position.x += 2 # Container spacing if Input.is_action_pressed("ctrl") and drop_frames.size() == 1: # Swap frames
Global.animation_timeline.drag_highlight.global_position = region.position region = get_global_rect()
Global.animation_timeline.drag_highlight.size = region.size else: # Move frames
Global.animation_timeline.drag_highlight.visible = true if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
return true region = _get_region_rect(-0.125, 0.125)
Global.animation_timeline.drag_highlight.visible = false else:
return false region = _get_region_rect(0.875, 1.125)
Global.animation_timeline.drag_highlight.global_position = region.position
Global.animation_timeline.drag_highlight.size = region.size
Global.animation_timeline.drag_highlight.visible = true
return true
func _drop_data(_pos: Vector2, data) -> void: func _drop_data(_pos: Vector2, data) -> void:
var drop_frame: int = data[1] var drop_frames: PackedInt32Array = data[1]
var project := Global.current_project var project := Global.current_project
project.undo_redo.create_action("Change Frame Order") project.undo_redo.create_action("Change Frame Order")
if Input.is_action_pressed("ctrl"): # Swap frames if Input.is_action_pressed("ctrl") and drop_frames.size() == 1: # Swap frames
project.undo_redo.add_do_method(project.swap_frame.bind(frame, drop_frame)) project.undo_redo.add_do_method(project.swap_frame.bind(frame, drop_frames[0]))
project.undo_redo.add_undo_method(project.swap_frame.bind(frame, drop_frame)) project.undo_redo.add_undo_method(project.swap_frame.bind(frame, drop_frames[0]))
else: # Move frames else: # Move frames
var to_frame: int var to_frame: int
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
to_frame = frame to_frame = frame
else: # Right else: # Right
to_frame = frame + 1 to_frame = frame + 1
if drop_frame < frame: if drop_frames[-1] < frame:
to_frame -= 1 to_frame -= drop_frames.size()
project.undo_redo.add_do_method(project.move_frame.bind(drop_frame, to_frame)) var to_frames := range(to_frame, to_frame + drop_frames.size())
project.undo_redo.add_undo_method(project.move_frame.bind(to_frame, drop_frame)) project.undo_redo.add_do_method(project.move_frames.bind(drop_frames, to_frames))
project.undo_redo.add_undo_method(project.move_frames.bind(to_frames, drop_frames))
if project.current_frame == drop_frame: if project.current_frame in drop_frames:
project.undo_redo.add_do_method(project.change_cel.bind(frame)) project.undo_redo.add_do_method(project.change_cel.bind(frame))
else: else:
project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame)) project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame))