1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-08 11:29:47 +00:00
Pixelorama/src/UI/Timeline/CelButton.gd
2021-12-02 02:22:32 +02:00

273 lines
9.8 KiB
GDScript

extends Button
enum MenuOptions { DELETE, LINK, PROPERTIES }
var frame := 0
var layer := 0
var cel: Cel
var image: Image
onready var popup_menu: PopupMenu = $PopupMenu
func _ready() -> void:
button_setup()
func button_setup() -> void:
rect_min_size.x = Global.animation_timeline.cel_size
rect_min_size.y = Global.animation_timeline.cel_size
hint_tooltip = tr("Frame: %s, Layer: %s") % [frame + 1, layer]
if Global.current_project.frames[frame] in Global.current_project.layers[layer].linked_cels:
get_node("LinkedIndicator").visible = true
popup_menu.set_item_text(MenuOptions.LINK, "Unlink Cel")
popup_menu.set_item_metadata(MenuOptions.LINK, "Unlink Cel")
else:
get_node("LinkedIndicator").visible = false
popup_menu.set_item_text(MenuOptions.LINK, "Link Cel")
popup_menu.set_item_metadata(MenuOptions.LINK, "Link Cel")
# Reset the checkers size because it assumes you want the same size as the canvas
var checker = $CelTexture/TransparentChecker
checker.rect_size = checker.get_parent().rect_size
cel = Global.current_project.frames[frame].cels[layer]
image = cel.image
func _on_CelButton_resized() -> void:
get_node("CelTexture").rect_min_size.x = rect_min_size.x - 4
get_node("CelTexture").rect_min_size.y = rect_min_size.y - 4
get_node("LinkedIndicator").polygon[1].x = rect_min_size.x
get_node("LinkedIndicator").polygon[2].x = rect_min_size.x
get_node("LinkedIndicator").polygon[2].y = rect_min_size.y
get_node("LinkedIndicator").polygon[3].y = rect_min_size.y
func _on_CelButton_pressed() -> void:
var project = Global.current_project
if Input.is_action_just_released("left_mouse"):
Global.canvas.selection.transform_content_confirm()
var change_cel := true
var prev_curr_frame: int = project.current_frame
var prev_curr_layer: int = project.current_layer
if Input.is_action_pressed("shift"):
var frame_diff_sign = sign(frame - prev_curr_frame)
if frame_diff_sign == 0:
frame_diff_sign = 1
var layer_diff_sign = sign(layer - prev_curr_layer)
if layer_diff_sign == 0:
layer_diff_sign = 1
for i in range(prev_curr_frame, frame + frame_diff_sign, frame_diff_sign):
for j in range(prev_curr_layer, layer + layer_diff_sign, layer_diff_sign):
var frame_layer := [i, j]
if !project.selected_cels.has(frame_layer):
project.selected_cels.append(frame_layer)
elif Input.is_action_pressed("ctrl"):
var frame_layer := [frame, layer]
if project.selected_cels.has(frame_layer):
if project.selected_cels.size() > 1:
project.selected_cels.erase(frame_layer)
change_cel = false
else:
project.selected_cels.append(frame_layer)
else: # If the button is pressed without Shift or Control
project.selected_cels.clear()
var frame_layer := [frame, layer]
if !project.selected_cels.has(frame_layer):
project.selected_cels.append(frame_layer)
if change_cel:
project.current_frame = frame
project.current_layer = layer
else:
project.current_frame = project.selected_cels[0][0]
project.current_layer = project.selected_cels[0][1]
release_focus()
elif Input.is_action_just_released("right_mouse"):
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
pressed = !pressed
elif Input.is_action_just_released("middle_mouse"):
pressed = !pressed
delete_cel_contents()
else: # An example of this would be Space
pressed = !pressed
func _on_PopupMenu_id_pressed(id: int) -> void:
match id:
MenuOptions.DELETE:
delete_cel_contents()
MenuOptions.LINK:
var f: Frame = Global.current_project.frames[frame]
var cel_index: int = Global.current_project.layers[layer].linked_cels.find(f)
var new_layers: Array = Global.current_project.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels: Array = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(
new_layers[i].name,
new_layers[i].visible,
new_layers[i].locked,
new_layers[i].frame_container,
new_layers[i].new_cels_linked,
new_linked_cels
)
var new_cels: Array = f.cels.duplicate()
for i in new_cels.size():
new_cels[i] = Cel.new(
new_cels[i].image, new_cels[i].opacity, new_cels[i].image_texture
)
if popup_menu.get_item_metadata(MenuOptions.LINK) == "Unlink Cel":
new_layers[layer].linked_cels.remove(cel_index)
var sprite := Image.new()
sprite.copy_from(f.cels[layer].image)
var sprite_texture := ImageTexture.new()
sprite_texture.create_from_image(sprite, 0)
new_cels[layer].image = sprite
new_cels[layer].image_texture = sprite_texture
Global.current_project.undo_redo.create_action("Unlink Cel")
Global.current_project.undo_redo.add_do_property(
Global.current_project, "layers", new_layers
)
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
Global.current_project.undo_redo.add_undo_property(
Global.current_project, "layers", Global.current_project.layers
)
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
Global.current_project.undo_redo.commit_action()
elif popup_menu.get_item_metadata(MenuOptions.LINK) == "Link Cel":
new_layers[layer].linked_cels.append(f)
Global.current_project.undo_redo.create_action("Link Cel")
Global.current_project.undo_redo.add_do_property(
Global.current_project, "layers", new_layers
)
if new_layers[layer].linked_cels.size() > 1:
# If there are already linked cels, set the current cel's image
# to the first linked cel's image
new_cels[layer].image = new_layers[layer].linked_cels[0].cels[layer].image
new_cels[layer].image_texture = new_layers[layer].linked_cels[0].cels[layer].image_texture
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
Global.current_project.undo_redo.add_undo_property(
Global.current_project, "layers", Global.current_project.layers
)
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
Global.current_project.undo_redo.commit_action()
func delete_cel_contents() -> void:
if image.is_invisible():
return
var project = Global.current_project
image.unlock()
var data := image.data
project.undos += 1
project.undo_redo.create_action("Draw")
project.undo_redo.add_undo_property(image, "data", data)
project.undo_redo.add_undo_method(Global, "undo_or_redo", true, frame, layer, project)
image.fill(0)
project.undo_redo.add_do_property(image, "data", image.data)
project.undo_redo.add_do_method(Global, "undo_or_redo", false, frame, layer, project)
project.undo_redo.commit_action()
func get_drag_data(_position) -> Array:
var button := Button.new()
button.rect_size = rect_size
button.theme = Global.control.theme
var texture_rect := TextureRect.new()
texture_rect.rect_size = $CelTexture.rect_size
texture_rect.rect_position = $CelTexture.rect_position
texture_rect.expand = true
texture_rect.texture = $CelTexture.texture
button.add_child(texture_rect)
set_drag_preview(button)
return ["Cel", frame, layer]
func can_drop_data(_pos, data) -> bool:
if typeof(data) == TYPE_ARRAY and data[0] == "Cel":
var new_frame = data[1]
var new_layer = data[2]
if (
Global.current_project.frames[frame] in Global.current_project.layers[layer].linked_cels
or (
Global.current_project.frames[new_frame]
in Global.current_project.layers[new_layer].linked_cels
)
):
# If the cel we're dragging or the cel we are targeting are linked, don't allow dragging
return false
else:
return true
else:
return false
func drop_data(_pos, data) -> void:
var new_frame = data[1]
var new_layer = data[2]
if new_frame == frame and new_layer == layer:
return
var this_frame_new_cels = Global.current_project.frames[frame].cels.duplicate()
var new_frame_new_cels
var temp = this_frame_new_cels[layer]
this_frame_new_cels[layer] = Global.current_project.frames[new_frame].cels[new_layer]
if frame == new_frame:
this_frame_new_cels[new_layer] = temp
else:
new_frame_new_cels = Global.current_project.frames[new_frame].cels.duplicate()
new_frame_new_cels[new_layer] = temp
Global.current_project.undo_redo.create_action("Move Cels")
Global.current_project.undo_redo.add_do_property(
Global.current_project.frames[frame], "cels", this_frame_new_cels
)
Global.current_project.undo_redo.add_do_property(Global.current_project, "current_layer", layer)
Global.current_project.undo_redo.add_undo_property(
Global.current_project, "current_layer", Global.current_project.current_layer
)
if frame != new_frame: # If the cel moved to a different frame
Global.current_project.undo_redo.add_do_property(
Global.current_project.frames[new_frame], "cels", new_frame_new_cels
)
Global.current_project.undo_redo.add_do_property(
Global.current_project, "current_frame", frame
)
Global.current_project.undo_redo.add_undo_property(
Global.current_project, "current_frame", Global.current_project.current_frame
)
Global.current_project.undo_redo.add_undo_property(
Global.current_project.frames[new_frame],
"cels",
Global.current_project.frames[new_frame].cels
)
Global.current_project.undo_redo.add_undo_property(
Global.current_project.frames[frame], "cels", Global.current_project.frames[frame].cels
)
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
Global.current_project.undo_redo.commit_action()