1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-08 19:39:50 +00:00
Pixelorama/src/UI/Timeline/FrameButton.gd
2023-12-06 03:22:33 +02:00

195 lines
7 KiB
GDScript

extends Button
enum { PROPERTIES, REMOVE, CLONE, MOVE_LEFT, MOVE_RIGHT, REVERSE, CENTER }
var frame := 0
@onready var popup_menu: PopupMenu = $PopupMenu
@onready var frame_properties: ConfirmationDialog = Global.control.find_child("FrameProperties")
func _ready() -> void:
custom_minimum_size.x = Global.animation_timeline.cel_size
text = str(frame + 1)
pressed.connect(_button_pressed)
mouse_entered.connect(_update_tooltip)
func _update_tooltip() -> void:
var duration := Global.current_project.frames[frame].duration
var duration_sec := duration * (1.0 / Global.current_project.fps)
var duration_str := str(duration_sec)
if "." in duration_str: # If its a decimal value
duration_str = "%.2f" % duration_sec # Up to 2 decimal places
tooltip_text = "%s: %sx (%s sec)" % [tr("Duration"), str(duration), duration_str]
func _button_pressed() -> void:
if Input.is_action_just_released("left_mouse"):
Global.canvas.selection.transform_content_confirm()
var prev_curr_frame := Global.current_project.current_frame
if Input.is_action_pressed("shift"):
var frame_diff_sign := signi(frame - prev_curr_frame)
if frame_diff_sign == 0:
frame_diff_sign = 1
for i in range(prev_curr_frame, frame + frame_diff_sign, frame_diff_sign):
for j in range(0, Global.current_project.layers.size()):
var frame_layer := [i, j]
if !Global.current_project.selected_cels.has(frame_layer):
Global.current_project.selected_cels.append(frame_layer)
elif Input.is_action_pressed("ctrl"):
for j in range(0, Global.current_project.layers.size()):
var frame_layer := [frame, j]
if !Global.current_project.selected_cels.has(frame_layer):
Global.current_project.selected_cels.append(frame_layer)
else: # If the button is pressed without Shift or Control
Global.current_project.selected_cels.clear()
var frame_layer := [frame, Global.current_project.current_layer]
if !Global.current_project.selected_cels.has(frame_layer):
Global.current_project.selected_cels.append(frame_layer)
Global.current_project.change_cel(frame, -1)
elif Input.is_action_just_released("right_mouse"):
if Global.current_project.frames.size() == 1:
popup_menu.set_item_disabled(REMOVE, true)
popup_menu.set_item_disabled(MOVE_LEFT, true)
popup_menu.set_item_disabled(MOVE_RIGHT, true)
popup_menu.set_item_disabled(REVERSE, true)
else:
popup_menu.set_item_disabled(REMOVE, false)
if Global.current_project.selected_cels.size() > 1:
popup_menu.set_item_disabled(REVERSE, false)
else:
popup_menu.set_item_disabled(REVERSE, true)
if frame > 0:
popup_menu.set_item_disabled(MOVE_LEFT, false)
if frame < Global.current_project.frames.size() - 1:
popup_menu.set_item_disabled(MOVE_RIGHT, false)
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
button_pressed = !button_pressed
elif Input.is_action_just_released("middle_mouse"):
button_pressed = !button_pressed
Global.animation_timeline.delete_frames(_get_frame_indices())
else: # An example of this would be Space
button_pressed = !button_pressed
func _on_PopupMenu_id_pressed(id: int) -> void:
var indices := _get_frame_indices()
match id:
REMOVE:
Global.animation_timeline.delete_frames(indices)
CLONE:
Global.animation_timeline.copy_frames(indices)
MOVE_LEFT:
change_frame_order(-1)
MOVE_RIGHT:
change_frame_order(1)
PROPERTIES:
frame_properties.frame_indices = indices
frame_properties.popup_centered()
Global.dialog_open(true)
REVERSE:
Global.animation_timeline.reverse_frames(indices)
CENTER:
DrawingAlgos.center(indices)
func change_frame_order(rate: int) -> void:
var change := frame + rate
var project := Global.current_project
project.undo_redo.create_action("Change Frame Order")
project.undo_redo.add_do_method(project.move_frame.bind(frame, change))
project.undo_redo.add_undo_method(project.move_frame.bind(change, frame))
if project.current_frame == frame:
project.undo_redo.add_do_method(project.change_cel.bind(change))
else:
project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(project.change_cel.bind(project.current_frame))
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_drag_data(_position: Vector2) -> Variant:
var button := Button.new()
button.size = size
button.theme = Global.control.theme
button.text = text
set_drag_preview(button)
return ["Frame", frame]
func _can_drop_data(_pos: Vector2, data) -> bool:
if typeof(data) == TYPE_ARRAY:
if data[0] == "Frame":
if data[1] != frame: # Can't move to same frame
var region: Rect2
if Input.is_action_pressed("ctrl"): # Swap frames
region = get_global_rect()
else: # Move frames
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
region = _get_region_rect(-0.125, 0.125)
region.position.x -= 2 # Container spacing
else:
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
return false
func _drop_data(_pos: Vector2, data) -> void:
var drop_frame: int = data[1]
var project := Global.current_project
project.undo_redo.create_action("Change Frame Order")
if Input.is_action_pressed("ctrl"): # Swap frames
project.undo_redo.add_do_method(project.swap_frame.bind(frame, drop_frame))
project.undo_redo.add_undo_method(project.swap_frame.bind(frame, drop_frame))
else: # Move frames
var to_frame: int
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
to_frame = frame
else: # Right
to_frame = frame + 1
if drop_frame < frame:
to_frame -= 1
project.undo_redo.add_do_method(project.move_frame.bind(drop_frame, to_frame))
project.undo_redo.add_undo_method(project.move_frame.bind(to_frame, drop_frame))
if project.current_frame == drop_frame:
project.undo_redo.add_do_method(project.change_cel.bind(frame))
else:
project.undo_redo.add_do_method(project.change_cel.bind(project.current_frame))
project.undo_redo.add_undo_method(project.change_cel.bind(project.current_frame))
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(x_begin: float, x_end: float) -> Rect2:
var rect := get_global_rect()
rect.position.x += rect.size.x * x_begin
rect.size.x *= x_end - x_begin
return rect
func _get_frame_indices() -> Array:
var indices := []
for cel in Global.current_project.selected_cels:
var f: int = cel[0]
if not f in indices:
indices.append(f)
indices.sort()
if not frame in indices:
indices = [frame]
return indices