1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-20 12:33:14 +00:00

Change UI of layer buttons - bring the small buttons out of the main button

This makes the visible/lock/linked/expand buttons more clear that they are indeed buttons. This commit also slightly changes the look of child layers, as they only appear intended and they no longer change color.
This commit is contained in:
Emmanouil Papadeas 2024-03-14 20:13:42 +02:00
parent c1b78e4c01
commit d3be746290
3 changed files with 264 additions and 285 deletions

View file

@ -1,10 +1,21 @@
class_name LayerButton
extends Button
extends HBoxContainer
const HIERARCHY_DEPTH_PIXEL_SHIFT := 8
const HIERARCHY_DEPTH_PIXEL_SHIFT := 16
var layer_index := 0
var layer_index := 0:
set(value):
layer_index = value
if is_instance_valid(main_button):
main_button.layer_index = value
var button_pressed := false:
set(value):
button_pressed = value
main_button.button_pressed = value
get:
return main_button.button_pressed
@onready var main_button := %LayerMainButton as Button
@onready var expand_button := %ExpandButton as BaseButton
@onready var visibility_button := %VisibilityButton as BaseButton
@onready var lock_button := %LockButton as BaseButton
@ -17,6 +28,8 @@ var layer_index := 0
func _ready() -> void:
main_button.layer_index = layer_index
main_button.hierarchy_depth_pixel_shift = HIERARCHY_DEPTH_PIXEL_SHIFT
Global.cel_switched.connect(func(): z_index = 1 if button_pressed else 0)
var layer := Global.current_project.layers[layer_index]
if layer is PixelLayer:
@ -24,27 +37,20 @@ func _ready() -> void:
elif layer is GroupLayer:
expand_button.visible = true
custom_minimum_size.y = Global.animation_timeline.cel_size
label.text = layer.name
line_edit.text = layer.name
var layer_buttons := find_child("LayerButtons")
for child in layer_buttons.get_children():
for child in get_children():
if not child is Button:
continue
var texture = child.get_child(0)
if not texture is TextureRect:
continue
texture.modulate = Global.modulate_icon_color
# Visualize how deep into the hierarchy the layer is
var hierarchy_depth := layer.get_hierarchy_depth()
hierarchy_spacer.custom_minimum_size.x = hierarchy_depth * HIERARCHY_DEPTH_PIXEL_SHIFT
if Global.control.theme.get_color("font_color", "Button").v > 0.5: # Light text is dark theme
self_modulate.v = 1 + hierarchy_depth * 0.4
else: # Dark text should be light theme
self_modulate.v = 1 - hierarchy_depth * 0.075
update_buttons()
await get_tree().process_frame
queue_redraw()
func update_buttons() -> void:
@ -92,14 +98,6 @@ func _update_buttons_all_layers() -> void:
Global.cel_vbox.get_child(layer_button.get_index()).visible = expanded
func _draw() -> void:
if hierarchy_spacer.size.x > 0.1:
var color := Color(1, 1, 1, 0.33)
color.v = roundf(Global.control.theme.get_color("font_color", "Button").v)
var x := hierarchy_spacer.global_position.x - global_position.x + hierarchy_spacer.size.x
draw_line(Vector2(x, 0), Vector2(x, size.y), color)
func _input(event: InputEvent) -> void:
if (
(event.is_action_released(&"ui_accept") or event.is_action_released(&"ui_cancel"))
@ -109,7 +107,7 @@ func _input(event: InputEvent) -> void:
_save_layer_name(line_edit.text)
func _on_LayerContainer_gui_input(event: InputEvent) -> void:
func _on_main_button_gui_input(event: InputEvent) -> void:
var project := Global.current_project
if not event is InputEventMouseButton:
@ -147,7 +145,7 @@ func _on_LayerContainer_gui_input(event: InputEvent) -> void:
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
func _on_LineEdit_focus_exited() -> void:
func _on_layer_name_line_edit_focus_exited() -> void:
_save_layer_name(line_edit.text)
@ -160,13 +158,13 @@ func _save_layer_name(new_name: String) -> void:
Global.current_project.layers[layer_index].name = new_name
func _on_ExpandButton_pressed() -> void:
func _on_expand_button_pressed() -> void:
var layer := Global.current_project.layers[layer_index]
layer.expanded = !layer.expanded
_update_buttons_all_layers()
func _on_VisibilityButton_pressed() -> void:
func _on_visibility_button_pressed() -> void:
Global.canvas.selection.transform_content_confirm()
var layer := Global.current_project.layers[layer_index]
layer.visible = !layer.visible
@ -177,7 +175,7 @@ func _on_VisibilityButton_pressed() -> void:
_update_buttons_all_layers()
func _on_LockButton_pressed() -> void:
func _on_lock_button_pressed() -> void:
Global.canvas.selection.transform_content_confirm()
var layer := Global.current_project.layers[layer_index]
layer.locked = !layer.locked
@ -186,7 +184,7 @@ func _on_LockButton_pressed() -> void:
_update_buttons_all_layers()
func _on_LinkButton_pressed() -> void:
func _on_link_button_pressed() -> void:
Global.canvas.selection.transform_content_confirm()
var layer := Global.current_project.layers[layer_index]
if not layer is PixelLayer:
@ -206,180 +204,6 @@ func _select_current_layer() -> void:
Global.current_project.change_cel(-1, layer_index)
func _get_drag_data(_position: Vector2) -> Variant:
var layer := Global.current_project.layers[layer_index]
var layers := range(layer_index - layer.get_child_count(true), layer_index + 1)
var box := VBoxContainer.new()
for i in layers.size():
var button := Button.new()
button.custom_minimum_size = size
button.theme = Global.control.theme
button.text = Global.current_project.layers[layers[-1 - i]].name
box.add_child(button)
set_drag_preview(box)
return ["Layer", layer_index]
func _can_drop_data(_pos: Vector2, data) -> bool:
if typeof(data) != TYPE_ARRAY:
Global.animation_timeline.drag_highlight.visible = false
return false
if data[0] != "Layer":
Global.animation_timeline.drag_highlight.visible = false
return false
var curr_layer: BaseLayer = Global.current_project.layers[layer_index]
var drag_layer: BaseLayer = Global.current_project.layers[data[1]]
if curr_layer == drag_layer:
Global.animation_timeline.drag_highlight.visible = false
return false
var region: Rect2
var depth := curr_layer.get_hierarchy_depth()
if Input.is_action_pressed(&"ctrl"): # Swap layers
if drag_layer.is_ancestor_of(curr_layer) or curr_layer.is_ancestor_of(drag_layer):
Global.animation_timeline.drag_highlight.visible = false
return false
region = get_global_rect()
else: # Shift layers
if drag_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 (
curr_layer.accepts_child(drag_layer)
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
):
# Drawn regions are adjusted a bit from actual to clarify drop position
region = _get_region_rect(0.15, 0.85)
depth += 1
else:
# Top or bottom region?
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
region = _get_region_rect(-0.1, 0.15)
else:
region = _get_region_rect(0.85, 1.1)
# Shift drawn region to the right a bit for hierarchy depth visualization:
region.position.x += depth * HIERARCHY_DEPTH_PIXEL_SHIFT
region.size.x -= depth * HIERARCHY_DEPTH_PIXEL_SHIFT
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:
var drop_layer: int = data[1]
var project := Global.current_project
project.undo_redo.create_action("Change Layer Order")
var layers: Array = project.layers # This shouldn't be modified directly
var drop_from_indices := range(
drop_layer - layers[drop_layer].get_child_count(true), drop_layer + 1
)
var drop_from_parents := []
for i in range(drop_from_indices.size()):
drop_from_parents.append(layers[drop_from_indices[i]].parent)
if Input.is_action_pressed("ctrl"): # Swap layers
# a and b both need "from", "to", and "to_parents"
# a is this layer (and children), b is the dropped layers
var a := {
"from": range(layer_index - layers[layer_index].get_child_count(true), layer_index + 1)
}
var b := {"from": drop_from_indices}
if a.from[0] < b.from[0]:
a["to"] = range(b.from[-1] + 1 - a.from.size(), b.from[-1] + 1) # Size of a, start from end of b
b["to"] = range(a.from[0], a.from[0] + b.from.size()) # Size of b, start from beginning of a
else:
a["to"] = range(b.from[0], b.from[0] + a.from.size()) # Size of a, start from beginning of b
b["to"] = range(a.from[-1] + 1 - b.from.size(), a.from[-1] + 1) # Size of b, start from end of a
var a_from_parents := []
for l in a.from:
a_from_parents.append(layers[l].parent)
# to_parents starts as a dulpicate of from_parents, set the root layer's (with one layer or
# group with its children, this will always be the last layer [-1]) parent to the other
# root layer's parent
a["to_parents"] = a_from_parents.duplicate()
b["to_parents"] = drop_from_parents.duplicate()
a.to_parents[-1] = drop_from_parents[-1]
b.to_parents[-1] = a_from_parents[-1]
project.undo_redo.add_do_method(project.swap_layers.bind(a, b))
project.undo_redo.add_undo_method(
project.swap_layers.bind(
{"from": a.to, "to": a.from, "to_parents": a_from_parents},
{"from": b.to, "to": drop_from_indices, "to_parents": drop_from_parents}
)
)
else: # Move layers
var to_index: int # the index where the LOWEST moved layer should end up
var to_parent: BaseLayer
# If accepted as a child, is it in the center region?
if (
layers[layer_index].accepts_child(layers[drop_layer])
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
):
to_index = layer_index
to_parent = layers[layer_index]
else:
# Top or bottom region?
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
to_index = layer_index + 1
to_parent = layers[layer_index].parent
else:
# Place under the layer, if it has children, place after its lowest child
if layers[layer_index].has_children():
to_index = layers[layer_index].get_children(true)[0].index
if layers[layer_index].is_ancestor_of(layers[drop_layer]):
to_index += drop_from_indices.size()
else:
to_index = layer_index
to_parent = layers[layer_index].parent
if drop_layer < layer_index:
to_index -= drop_from_indices.size()
var drop_to_indices := range(to_index, to_index + drop_from_indices.size())
var to_parents := drop_from_parents.duplicate()
to_parents[-1] = to_parent
project.undo_redo.add_do_method(
project.move_layers.bind(drop_from_indices, drop_to_indices, to_parents)
)
project.undo_redo.add_undo_method(
project.move_layers.bind(drop_to_indices, drop_from_indices, drop_from_parents)
)
if project.current_layer == drop_layer:
project.undo_redo.add_do_method(project.change_cel.bind(-1, layer_index))
else:
project.undo_redo.add_do_method(project.change_cel.bind(-1, project.current_layer))
project.undo_redo.add_undo_method(project.change_cel.bind(-1, project.current_layer))
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_region_rect(y_begin: float, y_end: float) -> Rect2:
var rect := get_global_rect()
rect.position.y += rect.size.y * y_begin
rect.size.y *= y_end - y_begin
return rect
func _on_popup_menu_id_pressed(id: int) -> void:
var layer := Global.current_project.layers[layer_index]
if id == 0:

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://bai814sqvk68f"]
[gd_scene load_steps=8 format=3 uid="uid://bai814sqvk68f"]
[ext_resource type="Script" path="res://src/UI/Timeline/LayerButton.gd" id="1_6hlpe"]
[ext_resource type="Texture2D" uid="uid://c2b3htff5yox8" path="res://assets/graphics/layers/layer_visible.png" id="2_ef6fb"]
@ -6,72 +6,27 @@
[ext_resource type="Texture2D" uid="uid://dhc0pnnqojd2m" path="res://assets/graphics/layers/unlock.png" id="3_ah1my"]
[ext_resource type="Texture2D" uid="uid://cofw1x6chh4i" path="res://assets/graphics/layers/unlinked_layer.png" id="4_058qm"]
[ext_resource type="Texture2D" uid="uid://ieo8fsapcgsy" path="res://assets/graphics/layers/clipping_mask.png" id="6_73j5q"]
[ext_resource type="Script" path="res://src/UI/Timeline/LayerMainButton.gd" id="6_n8q6b"]
[node name="LayerButton" type="Button"]
offset_right = 200.0
offset_bottom = 36.0
focus_mode = 0
mouse_default_cursor_shape = 2
theme_type_variation = &"LayerFrameButton"
toggle_mode = true
action_mode = 0
script = ExtResource("1_6hlpe")
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 1
[node name="LayerButton" type="HBoxContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 0
size_flags_horizontal = 3
theme_override_constants/separation = 0
script = ExtResource("1_6hlpe")
[node name="EmptySpacer" type="Control" parent="HBoxContainer"]
layout_mode = 2
mouse_filter = 2
[node name="LayerButtons" type="HBoxContainer" parent="HBoxContainer"]
custom_minimum_size = Vector2(118, 0)
layout_mode = 2
theme_override_constants/separation = 10
[node name="ExpandButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
[node name="VisibilityButton" type="Button" parent="." groups=["UIButtons"]]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(22, 22)
custom_minimum_size = Vector2(28, 22)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Expand/collapse group"
mouse_default_cursor_shape = 2
flat = true
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/ExpandButton"]
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -11.0
offset_top = -11.0
offset_right = 11.0
offset_bottom = 11.0
size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource("2_enrtd")
[node name="VisibilityButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
unique_name_in_owner = true
custom_minimum_size = Vector2(22, 22)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Toggle layer's visibility"
focus_mode = 0
mouse_default_cursor_shape = 2
flat = true
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/VisibilityButton"]
[node name="TextureRect" type="TextureRect" parent="VisibilityButton"]
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
@ -85,18 +40,15 @@ size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource("2_ef6fb")
[node name="LockButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
[node name="LockButton" type="Button" parent="." groups=["UIButtons"]]
unique_name_in_owner = true
custom_minimum_size = Vector2(22, 22)
custom_minimum_size = Vector2(28, 22)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Lock/unlock layer"
focus_mode = 0
mouse_default_cursor_shape = 2
flat = true
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/LockButton"]
[node name="TextureRect" type="TextureRect" parent="LockButton"]
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
@ -110,20 +62,18 @@ size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource("3_ah1my")
[node name="LinkButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
[node name="LinkButton" type="Button" parent="." groups=["UIButtons"]]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(22, 22)
custom_minimum_size = Vector2(28, 22)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 4
tooltip_text = "Enable/disable automatic linking of new cels when creating new frames
Linked cels share content across multiple frames"
focus_mode = 0
mouse_default_cursor_shape = 2
flat = true
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/LinkButton"]
[node name="TextureRect" type="TextureRect" parent="LinkButton"]
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
@ -137,32 +87,70 @@ size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource("4_058qm")
[node name="LayerName" type="HBoxContainer" parent="HBoxContainer"]
[node name="ExpandButton" type="Button" parent="." groups=["UIButtons"]]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(28, 22)
layout_mode = 2
tooltip_text = "Expand/collapse group"
focus_mode = 0
mouse_default_cursor_shape = 2
[node name="TextureRect" type="TextureRect" parent="ExpandButton"]
layout_mode = 0
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -11.0
offset_top = -11.0
offset_right = 11.0
offset_bottom = 11.0
size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource("2_enrtd")
[node name="LayerMainButton" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
focus_mode = 0
mouse_default_cursor_shape = 2
alignment = 1
theme_type_variation = &"LayerFrameButton"
toggle_mode = true
action_mode = 0
script = ExtResource("6_n8q6b")
[node name="HierarchySpacer" type="Control" parent="HBoxContainer/LayerName"]
[node name="LayerName" type="HBoxContainer" parent="LayerMainButton"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
mouse_default_cursor_shape = 2
[node name="HierarchySpacer" type="Control" parent="LayerMainButton/LayerName"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="ClippingMask" type="TextureRect" parent="HBoxContainer/LayerName"]
[node name="ClippingMask" type="TextureRect" parent="LayerMainButton/LayerName"]
unique_name_in_owner = true
visible = false
layout_mode = 2
texture = ExtResource("6_73j5q")
stretch_mode = 5
[node name="LayerNameLabel" type="Label" parent="HBoxContainer/LayerName"]
[node name="LayerNameLabel" type="Label" parent="LayerMainButton/LayerName"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Layer 0"
clip_text = true
[node name="LayerNameLineEdit" type="LineEdit" parent="HBoxContainer/LayerName"]
[node name="LayerNameLineEdit" type="LineEdit" parent="LayerMainButton/LayerName"]
unique_name_in_owner = true
visible = false
layout_mode = 2
@ -173,10 +161,6 @@ editable = false
caret_blink = true
caret_blink_interval = 0.5
[node name="EmptySpacer" type="Control" parent="HBoxContainer/LayerName"]
layout_mode = 2
mouse_filter = 2
[node name="PopupMenu" type="PopupMenu" parent="."]
disable_3d = true
item_count = 1
@ -184,10 +168,10 @@ item_0/text = "Clipping mask"
item_0/checkable = 1
item_0/id = 0
[connection signal="gui_input" from="." to="." method="_on_LayerContainer_gui_input"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/ExpandButton" to="." method="_on_ExpandButton_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/VisibilityButton" to="." method="_on_VisibilityButton_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/LockButton" to="." method="_on_LockButton_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/LinkButton" to="." method="_on_LinkButton_pressed"]
[connection signal="focus_exited" from="HBoxContainer/LayerName/LayerNameLineEdit" to="." method="_on_LineEdit_focus_exited"]
[connection signal="pressed" from="VisibilityButton" to="." method="_on_visibility_button_pressed"]
[connection signal="pressed" from="LockButton" to="." method="_on_lock_button_pressed"]
[connection signal="pressed" from="LinkButton" to="." method="_on_link_button_pressed"]
[connection signal="pressed" from="ExpandButton" to="." method="_on_expand_button_pressed"]
[connection signal="gui_input" from="LayerMainButton" to="." method="_on_main_button_gui_input"]
[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"]

View file

@ -0,0 +1,171 @@
extends Button
## The entire purpose of this script is to handle layer drag and dropping.
var layer_index := 0
var hierarchy_depth_pixel_shift := 16
func _get_drag_data(_position: Vector2) -> Variant:
var layer := Global.current_project.layers[layer_index]
var layers := range(layer_index - layer.get_child_count(true), layer_index + 1)
var box := VBoxContainer.new()
for i in layers.size():
var button := Button.new()
button.custom_minimum_size = size
button.theme = Global.control.theme
button.text = Global.current_project.layers[layers[-1 - i]].name
box.add_child(button)
set_drag_preview(box)
return ["Layer", layer_index]
func _can_drop_data(_pos: Vector2, data) -> bool:
if typeof(data) != TYPE_ARRAY:
Global.animation_timeline.drag_highlight.visible = false
return false
if data[0] != "Layer":
Global.animation_timeline.drag_highlight.visible = false
return false
var curr_layer: BaseLayer = Global.current_project.layers[layer_index]
var drag_layer: BaseLayer = Global.current_project.layers[data[1]]
if curr_layer == drag_layer:
Global.animation_timeline.drag_highlight.visible = false
return false
var region: Rect2
var depth := curr_layer.get_hierarchy_depth()
if Input.is_action_pressed(&"ctrl"): # Swap layers
if drag_layer.is_ancestor_of(curr_layer) or curr_layer.is_ancestor_of(drag_layer):
Global.animation_timeline.drag_highlight.visible = false
return false
region = get_global_rect()
else: # Shift layers
if drag_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 (
curr_layer.accepts_child(drag_layer)
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
):
# Drawn regions are adjusted a bit from actual to clarify drop position
region = _get_region_rect(0.15, 0.85)
depth += 1
else:
# Top or bottom region?
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
region = _get_region_rect(-0.1, 0.15)
else:
region = _get_region_rect(0.85, 1.1)
# Shift drawn region to the right a bit for hierarchy depth visualization:
region.position.x += depth * hierarchy_depth_pixel_shift
region.size.x -= depth * hierarchy_depth_pixel_shift
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:
var drop_layer: int = data[1]
var project := Global.current_project
project.undo_redo.create_action("Change Layer Order")
var layers: Array = project.layers # This shouldn't be modified directly
var drop_from_indices := range(
drop_layer - layers[drop_layer].get_child_count(true), drop_layer + 1
)
var drop_from_parents := []
for i in range(drop_from_indices.size()):
drop_from_parents.append(layers[drop_from_indices[i]].parent)
if Input.is_action_pressed("ctrl"): # Swap layers
# a and b both need "from", "to", and "to_parents"
# a is this layer (and children), b is the dropped layers
var a := {
"from": range(layer_index - layers[layer_index].get_child_count(true), layer_index + 1)
}
var b := {"from": drop_from_indices}
if a.from[0] < b.from[0]:
a["to"] = range(b.from[-1] + 1 - a.from.size(), b.from[-1] + 1) # Size of a, start from end of b
b["to"] = range(a.from[0], a.from[0] + b.from.size()) # Size of b, start from beginning of a
else:
a["to"] = range(b.from[0], b.from[0] + a.from.size()) # Size of a, start from beginning of b
b["to"] = range(a.from[-1] + 1 - b.from.size(), a.from[-1] + 1) # Size of b, start from end of a
var a_from_parents := []
for l in a.from:
a_from_parents.append(layers[l].parent)
# to_parents starts as a dulpicate of from_parents, set the root layer's (with one layer or
# group with its children, this will always be the last layer [-1]) parent to the other
# root layer's parent
a["to_parents"] = a_from_parents.duplicate()
b["to_parents"] = drop_from_parents.duplicate()
a.to_parents[-1] = drop_from_parents[-1]
b.to_parents[-1] = a_from_parents[-1]
project.undo_redo.add_do_method(project.swap_layers.bind(a, b))
project.undo_redo.add_undo_method(
project.swap_layers.bind(
{"from": a.to, "to": a.from, "to_parents": a_from_parents},
{"from": b.to, "to": drop_from_indices, "to_parents": drop_from_parents}
)
)
else: # Move layers
var to_index: int # the index where the LOWEST moved layer should end up
var to_parent: BaseLayer
# If accepted as a child, is it in the center region?
if (
layers[layer_index].accepts_child(layers[drop_layer])
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
):
to_index = layer_index
to_parent = layers[layer_index]
else:
# Top or bottom region?
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
to_index = layer_index + 1
to_parent = layers[layer_index].parent
else:
# Place under the layer, if it has children, place after its lowest child
if layers[layer_index].has_children():
to_index = layers[layer_index].get_children(true)[0].index
if layers[layer_index].is_ancestor_of(layers[drop_layer]):
to_index += drop_from_indices.size()
else:
to_index = layer_index
to_parent = layers[layer_index].parent
if drop_layer < layer_index:
to_index -= drop_from_indices.size()
var drop_to_indices := range(to_index, to_index + drop_from_indices.size())
var to_parents := drop_from_parents.duplicate()
to_parents[-1] = to_parent
project.undo_redo.add_do_method(
project.move_layers.bind(drop_from_indices, drop_to_indices, to_parents)
)
project.undo_redo.add_undo_method(
project.move_layers.bind(drop_to_indices, drop_from_indices, drop_from_parents)
)
if project.current_layer == drop_layer:
project.undo_redo.add_do_method(project.change_cel.bind(-1, layer_index))
else:
project.undo_redo.add_do_method(project.change_cel.bind(-1, project.current_layer))
project.undo_redo.add_undo_method(project.change_cel.bind(-1, project.current_layer))
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_region_rect(y_begin: float, y_end: float) -> Rect2:
var rect := get_global_rect()
rect.position.y += rect.size.y * y_begin
rect.size.y *= y_end - y_begin
return rect