mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
Move all selected layers with drag & drop
Similar to 7507206726
but for layers. Layer swapping (with control) only works when one layer is selected. The move up/down buttons in the timeline only work with one layer as of this commit.
This commit is contained in:
parent
4ddcf37d0b
commit
6c002756c7
|
@ -110,38 +110,40 @@ func _input(event: InputEvent) -> void:
|
||||||
_save_layer_name(line_edit.text)
|
_save_layer_name(line_edit.text)
|
||||||
|
|
||||||
|
|
||||||
func _on_main_button_gui_input(event: InputEvent) -> void:
|
func _on_layer_main_button_pressed() -> void:
|
||||||
var project := Global.current_project
|
var project := Global.current_project
|
||||||
|
Global.canvas.selection.transform_content_confirm()
|
||||||
|
var prev_curr_layer := project.current_layer
|
||||||
|
if Input.is_action_pressed(&"shift"):
|
||||||
|
var layer_diff_sign := signi(layer_index - prev_curr_layer)
|
||||||
|
if layer_diff_sign == 0:
|
||||||
|
layer_diff_sign = 1
|
||||||
|
for i in range(0, project.frames.size()):
|
||||||
|
for j in range(prev_curr_layer, layer_index + layer_diff_sign, layer_diff_sign):
|
||||||
|
var frame_layer := [i, j]
|
||||||
|
if !project.selected_cels.has(frame_layer):
|
||||||
|
project.selected_cels.append(frame_layer)
|
||||||
|
project.change_cel(-1, layer_index)
|
||||||
|
elif Input.is_action_pressed(&"ctrl"):
|
||||||
|
for i in range(0, project.frames.size()):
|
||||||
|
var frame_layer := [i, layer_index]
|
||||||
|
if !project.selected_cels.has(frame_layer):
|
||||||
|
project.selected_cels.append(frame_layer)
|
||||||
|
project.change_cel(-1, layer_index)
|
||||||
|
else: # If the button is pressed without Shift or Control
|
||||||
|
_select_current_layer()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_main_button_gui_input(event: InputEvent) -> void:
|
||||||
if not event is InputEventMouseButton:
|
if not event is InputEventMouseButton:
|
||||||
return
|
return
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
Global.canvas.selection.transform_content_confirm()
|
|
||||||
var prev_curr_layer := project.current_layer
|
|
||||||
if Input.is_action_pressed(&"shift"):
|
|
||||||
var layer_diff_sign := signi(layer_index - prev_curr_layer)
|
|
||||||
if layer_diff_sign == 0:
|
|
||||||
layer_diff_sign = 1
|
|
||||||
for i in range(0, project.frames.size()):
|
|
||||||
for j in range(prev_curr_layer, layer_index + layer_diff_sign, layer_diff_sign):
|
|
||||||
var frame_layer := [i, j]
|
|
||||||
if !project.selected_cels.has(frame_layer):
|
|
||||||
project.selected_cels.append(frame_layer)
|
|
||||||
project.change_cel(-1, layer_index)
|
|
||||||
elif Input.is_action_pressed(&"ctrl"):
|
|
||||||
for i in range(0, project.frames.size()):
|
|
||||||
var frame_layer := [i, layer_index]
|
|
||||||
if !project.selected_cels.has(frame_layer):
|
|
||||||
project.selected_cels.append(frame_layer)
|
|
||||||
project.change_cel(-1, layer_index)
|
|
||||||
else: # If the button is pressed without Shift or Control
|
|
||||||
_select_current_layer()
|
|
||||||
|
|
||||||
if event.double_click:
|
if event.double_click:
|
||||||
label.visible = false
|
label.visible = false
|
||||||
line_edit.visible = true
|
line_edit.visible = true
|
||||||
line_edit.editable = true
|
line_edit.editable = true
|
||||||
line_edit.grab_focus()
|
line_edit.grab_focus()
|
||||||
|
|
||||||
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
||||||
var layer := Global.current_project.layers[layer_index]
|
var layer := Global.current_project.layers[layer_index]
|
||||||
if not layer is GroupLayer:
|
if not layer is GroupLayer:
|
||||||
|
@ -218,7 +220,7 @@ func _on_popup_menu_id_pressed(id: int) -> void:
|
||||||
Global.canvas.draw_layers()
|
Global.canvas.draw_layers()
|
||||||
|
|
||||||
|
|
||||||
func _get_layer_indices() -> Array:
|
func _get_layer_indices() -> PackedInt32Array:
|
||||||
var indices := []
|
var indices := []
|
||||||
for cel in Global.current_project.selected_cels:
|
for cel in Global.current_project.selected_cels:
|
||||||
var l: int = cel[1]
|
var l: int = cel[1]
|
||||||
|
|
|
@ -123,7 +123,6 @@ focus_mode = 0
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
theme_type_variation = &"LayerFrameButton"
|
theme_type_variation = &"LayerFrameButton"
|
||||||
toggle_mode = true
|
toggle_mode = true
|
||||||
action_mode = 0
|
|
||||||
script = ExtResource("6_n8q6b")
|
script = ExtResource("6_n8q6b")
|
||||||
|
|
||||||
[node name="LayerName" type="HBoxContainer" parent="LayerMainButton"]
|
[node name="LayerName" type="HBoxContainer" parent="LayerMainButton"]
|
||||||
|
@ -180,5 +179,6 @@ item_1/id = 1
|
||||||
[connection signal="pressed" from="HBoxContainer/LinkButton" to="." method="_on_link_button_pressed"]
|
[connection signal="pressed" from="HBoxContainer/LinkButton" to="." method="_on_link_button_pressed"]
|
||||||
[connection signal="pressed" from="HBoxContainer/ExpandButton" to="." method="_on_expand_button_pressed"]
|
[connection signal="pressed" from="HBoxContainer/ExpandButton" to="." method="_on_expand_button_pressed"]
|
||||||
[connection signal="gui_input" from="LayerMainButton" to="." method="_on_main_button_gui_input"]
|
[connection signal="gui_input" from="LayerMainButton" to="." method="_on_main_button_gui_input"]
|
||||||
|
[connection signal="pressed" from="LayerMainButton" to="." method="_on_layer_main_button_pressed"]
|
||||||
[connection signal="focus_exited" from="LayerMainButton/LayerName/LayerNameLineEdit" to="." method="_on_layer_name_line_edit_focus_exited"]
|
[connection signal="focus_exited" from="LayerMainButton/LayerName/LayerNameLineEdit" to="." method="_on_layer_name_line_edit_focus_exited"]
|
||||||
[connection signal="id_pressed" from="PopupMenu" to="." method="_on_popup_menu_id_pressed"]
|
[connection signal="id_pressed" from="PopupMenu" to="." method="_on_popup_menu_id_pressed"]
|
||||||
|
|
|
@ -7,8 +7,15 @@ var hierarchy_depth_pixel_shift := 16
|
||||||
|
|
||||||
|
|
||||||
func _get_drag_data(_position: Vector2) -> Variant:
|
func _get_drag_data(_position: Vector2) -> Variant:
|
||||||
var layer := Global.current_project.layers[layer_index]
|
var layers := _get_layer_indices()
|
||||||
var layers := range(layer_index - layer.get_child_count(true), layer_index + 1)
|
for layer_i in layers: # Add child layers, if we have selected groups
|
||||||
|
var layer := Global.current_project.layers[layer_i]
|
||||||
|
for child in layer.get_children(true):
|
||||||
|
var child_index := Global.current_project.layers.find(child)
|
||||||
|
if not child_index in layers: # Do not add the same index multiple times
|
||||||
|
layers.append(child_index)
|
||||||
|
layers.sort()
|
||||||
|
|
||||||
var box := VBoxContainer.new()
|
var box := VBoxContainer.new()
|
||||||
for i in layers.size():
|
for i in layers.size():
|
||||||
var button := Button.new()
|
var button := Button.new()
|
||||||
|
@ -17,47 +24,51 @@ func _get_drag_data(_position: Vector2) -> Variant:
|
||||||
button.text = Global.current_project.layers[layers[-1 - i]].name
|
button.text = Global.current_project.layers[layers[-1 - i]].name
|
||||||
box.add_child(button)
|
box.add_child(button)
|
||||||
set_drag_preview(box)
|
set_drag_preview(box)
|
||||||
|
return ["Layer", layers]
|
||||||
return ["Layer", layer_index]
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
Global.animation_timeline.drag_highlight.visible = false
|
Global.animation_timeline.drag_highlight.visible = false
|
||||||
return false
|
return false
|
||||||
if data[0] != "Layer":
|
if data[0] != "Layer":
|
||||||
Global.animation_timeline.drag_highlight.visible = false
|
Global.animation_timeline.drag_highlight.visible = false
|
||||||
return false
|
return false
|
||||||
var curr_layer: BaseLayer = Global.current_project.layers[layer_index]
|
var curr_layer := Global.current_project.layers[layer_index]
|
||||||
var drag_layer: BaseLayer = Global.current_project.layers[data[1]]
|
var drop_layers: PackedInt32Array = data[1]
|
||||||
if curr_layer == drag_layer:
|
# Can't move to the same layer
|
||||||
Global.animation_timeline.drag_highlight.visible = false
|
for drop_layer in drop_layers:
|
||||||
return false
|
if drop_layer == layer_index:
|
||||||
|
Global.animation_timeline.drag_highlight.visible = false
|
||||||
|
return false
|
||||||
|
|
||||||
var region: Rect2
|
var region: Rect2
|
||||||
var depth := curr_layer.get_hierarchy_depth()
|
var depth := curr_layer.get_hierarchy_depth()
|
||||||
if Input.is_action_pressed(&"ctrl"): # Swap layers
|
var last_layer := Global.current_project.layers[drop_layers[-1]]
|
||||||
if drag_layer.is_ancestor_of(curr_layer) or curr_layer.is_ancestor_of(drag_layer):
|
if Input.is_action_pressed(&"ctrl") and drop_layers.size() == 1: # Swap layers
|
||||||
|
if last_layer.is_ancestor_of(curr_layer) or curr_layer.is_ancestor_of(last_layer):
|
||||||
Global.animation_timeline.drag_highlight.visible = false
|
Global.animation_timeline.drag_highlight.visible = false
|
||||||
return false
|
return false
|
||||||
region = get_global_rect()
|
region = get_global_rect()
|
||||||
else: # Shift layers
|
else: # Shift layers
|
||||||
if drag_layer.is_ancestor_of(curr_layer):
|
for drop_layer_index in drop_layers:
|
||||||
Global.animation_timeline.drag_highlight.visible = false
|
var drop_layer := Global.current_project.layers[drop_layer_index]
|
||||||
return false
|
if drop_layer.is_ancestor_of(curr_layer):
|
||||||
|
Global.animation_timeline.drag_highlight.visible = false
|
||||||
|
return false
|
||||||
# If accepted as a child, is it in the center region?
|
# If accepted as a child, is it in the center region?
|
||||||
if (
|
if (
|
||||||
curr_layer.accepts_child(drag_layer)
|
curr_layer.accepts_child(last_layer) # Any dropped layer should probably work here
|
||||||
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
|
and pos.y > size.y / 4.0
|
||||||
|
and pos.y < 3.0 * size.y / 4.0
|
||||||
):
|
):
|
||||||
# Drawn regions are adjusted a bit from actual to clarify drop position
|
# Drawn regions are adjusted a bit from actual to clarify drop position
|
||||||
region = _get_region_rect(0.15, 0.85)
|
region = _get_region_rect(0.15, 0.85)
|
||||||
depth += 1
|
depth += 1
|
||||||
else:
|
else:
|
||||||
# Top or bottom region?
|
if pos.y < size.y / 2.0: # Top region
|
||||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
|
|
||||||
region = _get_region_rect(-0.1, 0.15)
|
region = _get_region_rect(-0.1, 0.15)
|
||||||
else:
|
else: # Bottom region
|
||||||
region = _get_region_rect(0.85, 1.1)
|
region = _get_region_rect(0.85, 1.1)
|
||||||
# Shift drawn region to the right a bit for hierarchy depth visualization:
|
# Shift drawn region to the right a bit for hierarchy depth visualization:
|
||||||
region.position.x += depth * hierarchy_depth_pixel_shift
|
region.position.x += depth * hierarchy_depth_pixel_shift
|
||||||
|
@ -68,24 +79,39 @@ func _can_drop_data(_pos: Vector2, data) -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
func _drop_data(_pos: Vector2, data) -> void:
|
func _drop_data(pos: Vector2, data) -> void:
|
||||||
var drop_layer: int = data[1]
|
var initial_drop_layers: PackedInt32Array = data[1]
|
||||||
var project := Global.current_project
|
var project := Global.current_project
|
||||||
project.undo_redo.create_action("Change Layer Order")
|
var curr_layer := project.layers[layer_index]
|
||||||
var layers := project.layers # This shouldn't be modified directly
|
var layers := project.layers # This shouldn't be modified directly
|
||||||
var drop_from_indices: PackedInt32Array = range(
|
var drop_from_indices: PackedInt32Array = []
|
||||||
drop_layer - layers[drop_layer].get_child_count(true), drop_layer + 1
|
var children_indices: PackedInt32Array = [] # Child layer indices, if a group layer is selected
|
||||||
)
|
# Add dropped indices to drop_from_indices
|
||||||
|
# We do this in case a child layer is selected along with its ancestor,
|
||||||
|
# we don't want both of them to be in the final array, as ancestors will automatically include
|
||||||
|
# their children anyway.
|
||||||
|
for drop_layer_index in initial_drop_layers:
|
||||||
|
if not drop_layer_index in drop_from_indices: # Do not add the same index multiple times
|
||||||
|
drop_from_indices.append(drop_layer_index)
|
||||||
|
var drop_layer := project.layers[drop_layer_index]
|
||||||
|
for child in drop_layer.get_children(true):
|
||||||
|
var child_index := project.layers.find(child)
|
||||||
|
if not child_index in children_indices:
|
||||||
|
children_indices.append(child_index)
|
||||||
|
if not child_index in drop_from_indices: # Do not add the same index multiple times
|
||||||
|
drop_from_indices.append(child_index)
|
||||||
|
drop_from_indices.sort()
|
||||||
|
children_indices.sort()
|
||||||
|
|
||||||
var drop_from_parents := []
|
var drop_from_parents := []
|
||||||
for i in range(drop_from_indices.size()):
|
for i in range(drop_from_indices.size()):
|
||||||
drop_from_parents.append(layers[drop_from_indices[i]].parent)
|
drop_from_parents.append(layers[drop_from_indices[i]].parent)
|
||||||
|
|
||||||
if Input.is_action_pressed("ctrl"): # Swap layers
|
project.undo_redo.create_action("Change Layer Order")
|
||||||
|
if Input.is_action_pressed("ctrl") and initial_drop_layers.size() == 1: # Swap layers
|
||||||
# a and b both need "from", "to", and "to_parents"
|
# a and b both need "from", "to", and "to_parents"
|
||||||
# a is this layer (and children), b is the dropped layers
|
# a is this layer (and children), b is the dropped layers
|
||||||
var a := {
|
var a := {"from": range(layer_index - curr_layer.get_child_count(true), layer_index + 1)}
|
||||||
"from": range(layer_index - layers[layer_index].get_child_count(true), layer_index + 1)
|
|
||||||
}
|
|
||||||
var b := {"from": drop_from_indices}
|
var b := {"from": drop_from_indices}
|
||||||
|
|
||||||
if a.from[0] < b.from[0]:
|
if a.from[0] < b.from[0]:
|
||||||
|
@ -118,35 +144,40 @@ func _drop_data(_pos: Vector2, data) -> void:
|
||||||
else: # Move layers
|
else: # Move layers
|
||||||
var to_index: int # the index where the LOWEST moved layer should end up
|
var to_index: int # the index where the LOWEST moved layer should end up
|
||||||
var to_parent: BaseLayer
|
var to_parent: BaseLayer
|
||||||
|
var last_layer := project.layers[drop_from_indices[-1]]
|
||||||
# If accepted as a child, is it in the center region?
|
# If accepted as a child, is it in the center region?
|
||||||
if (
|
if (
|
||||||
layers[layer_index].accepts_child(layers[drop_layer])
|
curr_layer.accepts_child(last_layer) # Any dropped layer should probably work here
|
||||||
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
|
and pos.y > size.y / 4.0
|
||||||
|
and pos.y < 3.0 * size.y / 4.0
|
||||||
):
|
):
|
||||||
to_index = layer_index
|
to_index = layer_index
|
||||||
to_parent = layers[layer_index]
|
to_parent = curr_layer
|
||||||
else:
|
else:
|
||||||
# Top or bottom region?
|
if pos.y < size.y / 2.0: # Top region
|
||||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
|
|
||||||
to_index = layer_index + 1
|
to_index = layer_index + 1
|
||||||
to_parent = layers[layer_index].parent
|
to_parent = curr_layer.parent
|
||||||
else:
|
else: # Bottom region
|
||||||
# Place under the layer, if it has children, place after its lowest child
|
# Place under the layer, if it has children, place after its lowest child
|
||||||
if layers[layer_index].has_children():
|
if curr_layer.has_children():
|
||||||
to_index = layers[layer_index].get_children(true)[0].index
|
to_index = curr_layer.get_children(true)[0].index
|
||||||
|
for drop_layer in drop_from_indices:
|
||||||
if layers[layer_index].is_ancestor_of(layers[drop_layer]):
|
if curr_layer.is_ancestor_of(layers[drop_layer]):
|
||||||
to_index += drop_from_indices.size()
|
to_index += 1
|
||||||
else:
|
else:
|
||||||
to_index = layer_index
|
to_index = layer_index
|
||||||
to_parent = layers[layer_index].parent
|
to_parent = curr_layer.parent
|
||||||
|
|
||||||
if drop_layer < layer_index:
|
for drop_layer in drop_from_indices:
|
||||||
to_index -= drop_from_indices.size()
|
if drop_layer < layer_index:
|
||||||
|
to_index -= 1
|
||||||
|
|
||||||
var drop_to_indices: PackedInt32Array = range(to_index, to_index + drop_from_indices.size())
|
var drop_to_indices: PackedInt32Array = range(to_index, to_index + drop_from_indices.size())
|
||||||
var to_parents := drop_from_parents.duplicate()
|
var to_parents := drop_from_parents.duplicate()
|
||||||
to_parents[-1] = to_parent
|
for i in to_parents.size():
|
||||||
|
# Re-parent only the parent layers, not the child layers of a group
|
||||||
|
if not drop_from_indices[i] in children_indices:
|
||||||
|
to_parents[i] = to_parent
|
||||||
|
|
||||||
project.undo_redo.add_do_method(
|
project.undo_redo.add_do_method(
|
||||||
project.move_layers.bind(drop_from_indices, drop_to_indices, to_parents)
|
project.move_layers.bind(drop_from_indices, drop_to_indices, to_parents)
|
||||||
|
@ -154,7 +185,7 @@ func _drop_data(_pos: Vector2, data) -> void:
|
||||||
project.undo_redo.add_undo_method(
|
project.undo_redo.add_undo_method(
|
||||||
project.move_layers.bind(drop_to_indices, drop_from_indices, drop_from_parents)
|
project.move_layers.bind(drop_to_indices, drop_from_indices, drop_from_parents)
|
||||||
)
|
)
|
||||||
if project.current_layer == drop_layer:
|
if project.current_layer in drop_from_indices:
|
||||||
project.undo_redo.add_do_method(project.change_cel.bind(-1, layer_index))
|
project.undo_redo.add_do_method(project.change_cel.bind(-1, layer_index))
|
||||||
else:
|
else:
|
||||||
project.undo_redo.add_do_method(project.change_cel.bind(-1, project.current_layer))
|
project.undo_redo.add_do_method(project.change_cel.bind(-1, project.current_layer))
|
||||||
|
@ -169,3 +200,15 @@ func _get_region_rect(y_begin: float, y_end: float) -> Rect2:
|
||||||
rect.position.y += rect.size.y * y_begin
|
rect.position.y += rect.size.y * y_begin
|
||||||
rect.size.y *= y_end - y_begin
|
rect.size.y *= y_end - y_begin
|
||||||
return rect
|
return rect
|
||||||
|
|
||||||
|
|
||||||
|
func _get_layer_indices() -> PackedInt32Array:
|
||||||
|
var indices := []
|
||||||
|
for cel in Global.current_project.selected_cels:
|
||||||
|
var l: int = cel[1]
|
||||||
|
if not l in indices:
|
||||||
|
indices.append(l)
|
||||||
|
indices.sort()
|
||||||
|
if not layer_index in indices:
|
||||||
|
indices = [layer_index]
|
||||||
|
return indices
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
extends AcceptDialog
|
extends AcceptDialog
|
||||||
|
|
||||||
var layer_indices: Array
|
var layer_indices: PackedInt32Array
|
||||||
|
|
||||||
@onready var name_line_edit := $GridContainer/NameLineEdit as LineEdit
|
@onready var name_line_edit := $GridContainer/NameLineEdit as LineEdit
|
||||||
@onready var opacity_slider := $GridContainer/OpacitySlider as ValueSlider
|
@onready var opacity_slider := $GridContainer/OpacitySlider as ValueSlider
|
||||||
|
|
Loading…
Reference in a new issue