StickerClone/addons/modular_sprite_animation_factory/dock/msaf_dock.gd

247 lines
7.7 KiB
GDScript3
Raw Normal View History

2024-07-19 23:01:49 +00:00
@tool
extends Control
var sprite_node_names
var selected_sprite_nodes: Array[bool] = []
var selected_library = ""
var lib_names: Array[StringName] = []
var animation_parts: Array[MSAFPart] = []
var checked_tex = preload("res://addons/modular_sprite_animation_factory/assets/checkbox-circle.png")
var unchecked_tex = preload("res://addons/modular_sprite_animation_factory/assets/checkbox-blank-circle.png")
var anim_player: AnimationPlayer
func setup_dock(node_names, animation_player):
anim_player = animation_player
sprite_node_names = node_names
refresh_all()
func refresh_all():
update_library_list()
update_sprite_node_list()
update_visible_anim()
update_animation_list()
%ChangeNotAppliedLabel.visible = false
func update_sprite_node_list():
%SpriteNodeItemList.clear()
selected_sprite_nodes.clear()
var existing_selected_nodes: Array[String] = []
var lib = anim_player.get_animation_library(selected_library)
var has_animation = false
# Check the first animation in the library, to set the default selected state of the sprite nodes
if lib:
if lib.get_animation_list().size() > 0:
var first_anim = lib.get_animation(lib.get_animation_list()[0])
has_animation = true
for i in first_anim.get_track_count():
var path = first_anim.track_get_path(i)
if path.get_subname_count() > 0 and path.get_subname(0) == "frame" and path.get_name_count() > 0:
existing_selected_nodes.append(path.get_name(0))
for i in sprite_node_names.size():
if !has_animation or existing_selected_nodes.has(sprite_node_names[i]):
# If no animation in the library, default to true
# Or existing animation contains the node track, then its true as well
selected_sprite_nodes.append(true)
%SpriteNodeItemList.add_item(sprite_node_names[i], checked_tex, true)
else:
selected_sprite_nodes.append(false)
%SpriteNodeItemList.add_item(sprite_node_names[i], unchecked_tex, true)
%SpriteNodeItemList.set_item_icon_modulate(i, Color.WHITE)
func update_library_list():
lib_names = anim_player.get_animation_library_list()
%LibraryItemList.clear()
for i in lib_names.size():
var item_string: String
if lib_names[i] == "":
item_string = "[Global]"
else:
item_string = lib_names[i]
if lib_names[i] == selected_library:
%LibraryItemList.select(i)
item_string += " (selected)"
%LibraryItemList.add_item(item_string, null, true)
func update_visible_anim():
animation_parts.clear()
var lib = anim_player.get_animation_library(selected_library)
if !lib:
return
var visible_anims = lib.get_animation_list()
# convert all animation to MSAFPart
for anim_name in visible_anims:
var animation = lib.get_animation(anim_name)
var new_part = MSAFPart.new()
new_part.animation_name = anim_name
new_part.loop = animation.loop_mode != Animation.LOOP_NONE
if animation.get_track_count() > 0:
var key_count = animation.track_get_key_count(0)
if key_count > 1:
new_part.start_index = animation.track_get_key_value(0, 0)
new_part.end_index = animation.track_get_key_value(0, key_count - 1)
new_part.fps = key_count / animation.length
else:
new_part.start_index = animation.track_get_key_value(0, 0)
new_part.end_index = animation.track_get_key_value(0, 0)
new_part.fps = 1
else:
new_part.start_index = -1
new_part.end_index = -1
new_part.fps = -1
animation_parts.append(new_part)
func update_animation_list():
%AnimationItemList.clear()
for anim_part in animation_parts:
var item_string = anim_part.animation_name
if anim_part.loop:
item_string += " (loop)"
if anim_part.fps > 0:
item_string += " [%d - %d]" % [anim_part.start_index, anim_part.end_index]
item_string += " %.2f fps" % anim_part.fps
else:
item_string += " [? - ?] ? fps"
%AnimationItemList.add_item(item_string, null, true)
func _on_library_item_list_item_selected(index):
var previously_selected_lib = selected_library
if index < lib_names.size():
selected_library = lib_names[index]
if previously_selected_lib != selected_library:
if selected_library == "":
print("MSAF Selected library: [Global]")
else:
print("MSAF Selected library: ", selected_library)
refresh_all()
func _on_sprite_node_item_list_item_selected(index):
# toggle item
if selected_sprite_nodes[index]:
%SpriteNodeItemList.set_item_icon(index, unchecked_tex)
else:
%SpriteNodeItemList.set_item_icon(index, checked_tex)
selected_sprite_nodes[index] = !selected_sprite_nodes[index]
func _on_select_all_button_pressed():
print("MSAF select all sprite nodes")
for i in sprite_node_names.size():
%SpriteNodeItemList.set_item_icon(i, checked_tex)
selected_sprite_nodes[i] = true
func _on_select_none_button_pressed():
print("MSAF select none sprite nodes")
for i in sprite_node_names.size():
%SpriteNodeItemList.set_item_icon(i, unchecked_tex)
selected_sprite_nodes[i] = false
func _on_delete_anim_button_pressed():
var selected_item_indexes = %AnimationItemList.get_selected_items()
if selected_item_indexes.size() > 0:
var selected_index = selected_item_indexes[0]
print("MSAF deleted animation: ", animation_parts[selected_index].animation_name)
animation_parts.remove_at(selected_index)
update_animation_list()
%ChangeNotAppliedLabel.visible = true
func _on_add_anim_button_pressed():
print("MSAF added new animation")
if %AnimNameLineEdit.text == "" or %AnimNameLineEdit.text.contains("/"):
$AcceptDialog.dialog_text = "Invalid animation name"
%AcceptDialog.popup_centered()
return
if !%StartFrameLineEdit.text.is_valid_int() or !%EndFrameLineEdit.text.is_valid_int():
$AcceptDialog.dialog_text = "Start and end frame needs to be integer"
%AcceptDialog.popup_centered()
return
if !%FPSLineEdit.text.is_valid_float() and float(%FPSLineEdit.text) <= 0:
$AcceptDialog.dialog_text = "Invalid FPS number"
%AcceptDialog.popup_centered()
return
var new_part = MSAFPart.new()
new_part.animation_name = %AnimNameLineEdit.text
new_part.loop = %LoopCheckButton.button_pressed
new_part.start_index = int(%StartFrameLineEdit.text)
new_part.end_index = int(%EndFrameLineEdit.text)
new_part.fps = float(%FPSLineEdit.text)
animation_parts.append(new_part)
update_animation_list()
%ChangeNotAppliedLabel.visible = true
func _on_generate_button_pressed():
var lib = anim_player.get_animation_library(selected_library)
if !lib:
$AcceptDialog.dialog_text = "No library selected"
%AcceptDialog.popup_centered()
return
if %OverwriteCheckBox.button_pressed: # overwrite is checked
for existing_anim in lib.get_animation_list():
lib.remove_animation(existing_anim)
for anim_part in animation_parts:
if anim_part.fps <= 0:
# invalid animation part, skip this one
continue
if lib.has_animation(anim_part.animation_name): # if already exist
if !%OverwriteCheckBox.button_pressed: # overwrite is not checked
continue # skip this one
var animation = Animation.new()
animation.length = float(anim_part.end_index - anim_part.start_index + 1) / anim_part.fps
if anim_part.loop:
animation.loop_mode = Animation.LOOP_LINEAR
else:
animation.loop_mode = Animation.LOOP_NONE
for i in sprite_node_names.size():
if !selected_sprite_nodes[i]:
# this sprite node is not selected, skip it
continue
# add a track for each sprite node
animation.add_track(Animation.TYPE_VALUE)
animation.value_track_set_update_mode(i, Animation.UPDATE_DISCRETE)
animation.track_set_path(i, "%s:frame" % sprite_node_names[i])
# add a the frames to the track
for j in range(anim_part.start_index, anim_part.end_index + 1):
animation.track_insert_key(i, float(j - anim_part.start_index) / anim_part.fps, j)
lib.add_animation(anim_part.animation_name, animation)
%ChangeNotAppliedLabel.visible = false
refresh_all()
func _on_refresh_button_pressed():
refresh_all()