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:
parent
c1b78e4c01
commit
d3be746290
3 changed files with 264 additions and 285 deletions
|
@ -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:
|
||||
|
|
|
@ -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"]
|
||||
|
|
171
src/UI/Timeline/LayerMainButton.gd
Normal file
171
src/UI/Timeline/LayerMainButton.gd
Normal 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
|
Loading…
Add table
Reference in a new issue