1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

Implement the ability to move all selected cels on between different frames, but on the same layer

You currently cannot move multiple cels on different layers, they still act as swapping. Eventually I'd also like to implement moving cels between different layers, but they would also have to be on the same frame. I don't think moving cels between different layers and frames at the same time is possible.
This commit is contained in:
Emmanouil Papadeas 2024-08-13 23:25:29 +03:00
parent 1a99d524d1
commit 1d5de2ed86
2 changed files with 117 additions and 49 deletions

View file

@ -751,19 +751,34 @@ func swap_layers(a: Dictionary, b: Dictionary) -> void:
_update_layer_ui() _update_layer_ui()
func move_cel(from_frame: int, to_frame: int, layer: int) -> void: ## Moves multiple cels between different frames, but on the same layer.
## TODO: Perhaps figure out a way to optimize this. Right now it copies all of the cels of
## a layer into a temporary array, sorts it and then copies it into each frame's `cels` array
## on that layer. This was done in order to replicate the code from [method move_frames].
## TODO: Make a method like this, but for moving cels between different layers, on the same frame.
func move_cels_same_layer(
from_indices: PackedInt32Array, to_indices: PackedInt32Array, layer: int
) -> void:
Global.canvas.selection.transform_content_confirm() Global.canvas.selection.transform_content_confirm()
selected_cels.clear() selected_cels.clear()
var cel: BaseCel = frames[from_frame].cels[layer] var cels: Array[BaseCel] = []
if from_frame < to_frame: for frame in frames:
for f in range(from_frame, to_frame): # Forward range cels.append(frame.cels[layer])
frames[f].cels[layer] = frames[f + 1].cels[layer] # Move left var removed_cels: Array[BaseCel] = []
else: for i in from_indices.size():
for f in range(from_frame, to_frame, -1): # Backward range # With each removed index, future indices need to be lowered, so subtract by i
frames[f].cels[layer] = frames[f - 1].cels[layer] # Move right removed_cels.append(cels.pop_at(from_indices[i] - i))
frames[to_frame].cels[layer] = cel for i in to_indices.size():
Global.animation_timeline.project_cel_removed(from_frame, layer) cels.insert(to_indices[i], removed_cels[i])
Global.animation_timeline.project_cel_added(to_frame, layer) for i in frames.size():
var new_cel := cels[i]
frames[i].cels[layer] = new_cel
for i in from_indices.size():
# With each removed index, future indices need to be lowered, so subtract by i
Global.animation_timeline.project_cel_removed(from_indices[i] - i, layer)
for i in to_indices.size():
Global.animation_timeline.project_cel_added(to_indices[i], layer)
# Update the cel buttons for this layer: # Update the cel buttons for this layer:
var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - layer) var cel_hbox: HBoxContainer = Global.cel_vbox.get_child(layers.size() - 1 - layer)

View file

@ -260,53 +260,92 @@ func _get_drag_data(_position: Vector2) -> Variant:
texture_rect.texture = cel_texture.texture texture_rect.texture = cel_texture.texture
button.add_child(texture_rect) button.add_child(texture_rect)
set_drag_preview(button) set_drag_preview(button)
return ["Cel", _get_cel_indices()]
return ["Cel", frame, layer]
func _can_drop_data(_pos: Vector2, data) -> bool: func _can_drop_data(_pos: Vector2, data) -> bool:
var project := Global.current_project var project := Global.current_project
if typeof(data) == TYPE_ARRAY and data[0] == "Cel": if typeof(data) != TYPE_ARRAY:
var drag_frame = data[1] Global.animation_timeline.drag_highlight.visible = false
var drag_layer = data[2] return false
if project.layers[drag_layer].get_script() == project.layers[layer].get_script(): if data[0] != "Cel":
if ( # If both cels are on the same layer, or both are not linked Global.animation_timeline.drag_highlight.visible = false
drag_layer == layer return false
or ( var drop_cels: Array = data[1]
project.frames[frame].cels[layer].link_set == null drop_cels.sort_custom(_sort_cel_indices_by_frame)
and project.frames[drag_frame].cels[drag_layer].link_set == null var drop_frames: PackedInt32Array = []
) var drop_layers: PackedInt32Array = []
): for cel_idx in drop_cels:
if not (drag_frame == frame and drag_layer == layer): drop_frames.append(cel_idx[0])
var region: Rect2 drop_layers.append(cel_idx[1])
if Input.is_action_pressed("ctrl") or layer != drag_layer: # Swap cels # Can't move to the same cel
region = get_global_rect() for drop_frame in drop_frames:
else: # Move cels if drop_frame == frame and drop_layers[-1] == layer:
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left Global.animation_timeline.drag_highlight.visible = false
region = _get_region_rect(-0.125, 0.125) return false
region.position.x -= 2 # Container spacing # Can't move different types of layers between them
else: # Right for drop_layer in drop_layers:
region = _get_region_rect(0.875, 1.125) if project.layers[drop_layer].get_script() != project.layers[layer].get_script():
region.position.x += 2 # Container spacing Global.animation_timeline.drag_highlight.visible = false
Global.animation_timeline.drag_highlight.global_position = region.position return false
Global.animation_timeline.drag_highlight.size = region.size
Global.animation_timeline.drag_highlight.visible = true var drop_layer := drop_layers[0]
return true # Check if all dropped cels are on the same layer
var different_layers := false
for l in drop_layers:
if l != layer:
different_layers = true
# Check if any of the dropped cels are linked
var are_dropped_cels_linked := false
for f in drop_frames:
if project.frames[f].cels[drop_layer].link_set != null:
are_dropped_cels_linked = true
if ( # If both cels are on the same layer, or both are not linked
drop_layer == layer
or (project.frames[frame].cels[layer].link_set == null and not are_dropped_cels_linked)
):
var region: Rect2
if Input.is_action_pressed("ctrl") or different_layers: # Swap cels
region = get_global_rect()
else: # Move cels
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
region = _get_region_rect(-0.125, 0.125)
region.position.x -= 2 # Container spacing
else: # Right
region = _get_region_rect(0.875, 1.125)
region.position.x += 2 # Container spacing
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
Global.animation_timeline.drag_highlight.visible = false Global.animation_timeline.drag_highlight.visible = false
return false return false
func _drop_data(_pos: Vector2, data) -> void: func _drop_data(_pos: Vector2, data) -> void:
var drop_frame: int = data[1] var drop_cels: Array = data[1]
var drop_layer: int = data[2] drop_cels.sort_custom(_sort_cel_indices_by_frame)
var project := Global.current_project var drop_frames: PackedInt32Array = []
var drop_layers: PackedInt32Array = []
for cel_idx in drop_cels:
drop_frames.append(cel_idx[0])
drop_layers.append(cel_idx[1])
var drop_layer := drop_layers[0]
var different_layers := false
for l in drop_layers:
if l != layer:
different_layers = true
var project := Global.current_project
project.undo_redo.create_action("Move Cels") project.undo_redo.create_action("Move Cels")
if Input.is_action_pressed("ctrl") or layer != drop_layer: # Swap cels if Input.is_action_pressed("ctrl") or different_layers: # Swap cels
project.undo_redo.add_do_method(project.swap_cel.bind(frame, layer, drop_frame, drop_layer)) project.undo_redo.add_do_method(
project.swap_cel.bind(frame, layer, drop_frames[0], drop_layer)
)
project.undo_redo.add_undo_method( project.undo_redo.add_undo_method(
project.swap_cel.bind(frame, layer, drop_frame, drop_layer) project.swap_cel.bind(frame, layer, drop_frames[0], drop_layer)
) )
else: # Move cels else: # Move cels
var to_frame: int var to_frame: int
@ -314,10 +353,16 @@ func _drop_data(_pos: Vector2, data) -> void:
to_frame = frame to_frame = frame
else: # Right else: # Right
to_frame = frame + 1 to_frame = frame + 1
if drop_frame < frame: for drop_frame in drop_frames:
to_frame -= 1 if drop_frame < frame:
project.undo_redo.add_do_method(project.move_cel.bind(drop_frame, to_frame, layer)) to_frame -= 1
project.undo_redo.add_undo_method(project.move_cel.bind(to_frame, drop_frame, layer)) var to_frames := range(to_frame, to_frame + drop_frames.size())
project.undo_redo.add_do_method(
project.move_cels_same_layer.bind(drop_frames, to_frames, layer)
)
project.undo_redo.add_undo_method(
project.move_cels_same_layer.bind(to_frames, drop_frames, layer)
)
project.undo_redo.add_do_method(project.change_cel.bind(frame, layer)) project.undo_redo.add_do_method(project.change_cel.bind(frame, layer))
project.undo_redo.add_undo_method( project.undo_redo.add_undo_method(
@ -343,3 +388,11 @@ func _get_cel_indices(add_current_cel := false) -> Array:
else: else:
indices = [[frame, layer]] indices = [[frame, layer]]
return indices return indices
func _sort_cel_indices_by_frame(a: Array, b: Array) -> bool:
var frame_a: int = a[0]
var frame_b: int = b[0]
if frame_a < frame_b:
return true
return false