246 lines
7.7 KiB
GDScript
246 lines
7.7 KiB
GDScript
@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()
|