From 5ab4914cd1e5ca3b770481491f2a3677ce172b28 Mon Sep 17 00:00:00 2001 From: Harmony Monroe Date: Wed, 26 Aug 2020 21:42:32 -0400 Subject: [PATCH] Aseprite Importer Plugin added - player Animations added --- Image/player.json | 136 ++++++++ Image/player.png | Bin 0 -> 847 bytes Scene/Player.tscn | 198 ++++++++++- Script/Actor.gd | 2 +- Script/Player.gd | 39 ++- addons/aseprite_importer/LICENSE | 21 ++ .../classes/AsepriteImportData.gd | 187 +++++++++++ .../classes/AsepriteImporter.gd | 153 +++++++++ .../aseprite_importer/classes/EditorTheme.gd | 26 ++ addons/aseprite_importer/interface/Main.gd | 156 +++++++++ addons/aseprite_importer/interface/Main.tscn | 100 ++++++ .../interface/icons/dark_icon.png | Bin 0 -> 226 bytes .../interface/icons/light_icon.png | Bin 0 -> 225 bytes .../interface/import_menu/JSONImportMenu.gd | 92 +++++ .../interface/import_menu/JSONImportMenu.tscn | 78 +++++ .../import_menu/SelectAnimationPlayerMenu.gd | 64 ++++ .../SelectAnimationPlayerMenu.tscn | 53 +++ .../interface/import_menu/SelectNodeDialog.gd | 144 ++++++++ .../import_menu/SelectNodeDialog.tscn | 98 ++++++ .../interface/import_menu/SelectSpriteMenu.gd | 81 +++++ .../import_menu/SelectSpriteMenu.tscn | 43 +++ .../interface/import_menu/TagsMenu.gd | 202 +++++++++++ .../interface/import_menu/TagsMenu.tscn | 41 +++ .../spritesheet_inspector/ColorMenuItem.gd | 95 ++++++ .../spritesheet_inspector/ColorMenuItem.tscn | 37 ++ .../spritesheet_inspector/SettingsMenu.gd | 74 ++++ .../SpritesheetInspector.gd | 247 ++++++++++++++ .../SpritesheetInspector.tscn | 255 ++++++++++++++ .../spritesheet_inspector/SpritesheetView.gd | 315 ++++++++++++++++++ .../SpritesheetView.tscn | 48 +++ .../godot_button/godot_hover.png | Bin 0 -> 230 bytes .../godot_button/godot_normal.png | Bin 0 -> 224 bytes .../godot_button/godot_pressed.png | Bin 0 -> 212 bytes addons/aseprite_importer/plugin.cfg | 7 + addons/aseprite_importer/plugin.gd | 101 ++++++ project.godot | 24 +- 36 files changed, 3086 insertions(+), 31 deletions(-) create mode 100644 Image/player.json create mode 100644 Image/player.png create mode 100644 addons/aseprite_importer/LICENSE create mode 100644 addons/aseprite_importer/classes/AsepriteImportData.gd create mode 100644 addons/aseprite_importer/classes/AsepriteImporter.gd create mode 100644 addons/aseprite_importer/classes/EditorTheme.gd create mode 100644 addons/aseprite_importer/interface/Main.gd create mode 100644 addons/aseprite_importer/interface/Main.tscn create mode 100644 addons/aseprite_importer/interface/icons/dark_icon.png create mode 100644 addons/aseprite_importer/interface/icons/light_icon.png create mode 100644 addons/aseprite_importer/interface/import_menu/JSONImportMenu.gd create mode 100644 addons/aseprite_importer/interface/import_menu/JSONImportMenu.tscn create mode 100644 addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.gd create mode 100644 addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.tscn create mode 100644 addons/aseprite_importer/interface/import_menu/SelectNodeDialog.gd create mode 100644 addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn create mode 100644 addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.gd create mode 100644 addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.tscn create mode 100644 addons/aseprite_importer/interface/import_menu/TagsMenu.gd create mode 100644 addons/aseprite_importer/interface/import_menu/TagsMenu.tscn create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.gd create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.tscn create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/SettingsMenu.gd create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.gd create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.tscn create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.gd create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.tscn create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_hover.png create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_normal.png create mode 100644 addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_pressed.png create mode 100644 addons/aseprite_importer/plugin.cfg create mode 100644 addons/aseprite_importer/plugin.gd diff --git a/Image/player.json b/Image/player.json new file mode 100644 index 0000000..a9f4b79 --- /dev/null +++ b/Image/player.json @@ -0,0 +1,136 @@ +{ "frames": { + "player (Layer) 0.aseprite": { + "frame": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 400 + }, + "player (Layer) 1.aseprite": { + "frame": { "x": 8, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 2.aseprite": { + "frame": { "x": 16, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 3.aseprite": { + "frame": { "x": 24, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + }, + "player (Layer) 4.aseprite": { + "frame": { "x": 32, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 5.aseprite": { + "frame": { "x": 40, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + }, + "player (Layer) 6.aseprite": { + "frame": { "x": 48, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + }, + "player (Layer) 7.aseprite": { + "frame": { "x": 56, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 400 + }, + "player (Layer) 8.aseprite": { + "frame": { "x": 64, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 9.aseprite": { + "frame": { "x": 72, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 10.aseprite": { + "frame": { "x": 80, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + }, + "player (Layer) 11.aseprite": { + "frame": { "x": 88, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 200 + }, + "player (Layer) 12.aseprite": { + "frame": { "x": 96, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + }, + "player (Layer) 13.aseprite": { + "frame": { "x": 104, "y": 0, "w": 8, "h": 24 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 8, "h": 24 }, + "sourceSize": { "w": 8, "h": 24 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.2.24-x64", + "image": "player.png", + "format": "RGBA8888", + "size": { "w": 112, "h": 24 }, + "scale": "1", + "frameTags": [ + { "name": "idle", "from": 0, "to": 1, "direction": "forward" }, + { "name": "run", "from": 2, "to": 5, "direction": "forward" }, + { "name": "jump", "from": 6, "to": 6, "direction": "forward" }, + { "name": "box_idle", "from": 7, "to": 8, "direction": "forward" }, + { "name": "box_run", "from": 9, "to": 12, "direction": "forward" }, + { "name": "box_jump", "from": 13, "to": 13, "direction": "forward" } + ], + "layers": [ + { "name": "Layer", "opacity": 255, "blendMode": "normal" } + ], + "slices": [ + ] + } +} diff --git a/Image/player.png b/Image/player.png new file mode 100644 index 0000000000000000000000000000000000000000..84f3f825bde4eb743541ae1795a0c527b668dacf GIT binary patch literal 847 zcmV-V1F-ywP)Px&2}wjjRA_i73IM^rZbe^k4`rt&11IOKBsGQYCs(4+;f~ z7E0^Mf=~pZf+qz@4r&?_J$RB{79$dJ>7}+P$Wmx2da=D#WqR1|y4&o|Bu>OOod+SC zdGp?UKf9A1KtVx4K|w)5K|w)5p(4=#4q&%q_I#A__;|L!t)Z-5gqm+)wHh!KE4aop zxoAak$m;#DZyG35z@bu*c|-%j)6ui^a61!59P%qu{90RR}8 zBYaqK^A}qQccV;C8l=tW3;aCGel z0|0$QBkf8HH@>O#I!c;UOaPG-rp5+@>+kja0(#OQZCkt=ZXy8Y0?QjrPZ|UO+IDg- z{?!uG!(q}JLQEeU003zDMd-b4fa7?gCk=4@8$xzmso_3o`9(atdd3=J5XILJawbkV z6$T int: + var file := File.new() + + var error := file.open(filepath, File.READ) + if error != OK: + return error + + var file_text = file.get_as_text() + file.close() + + var json := JSON.parse(file_text) + if json.error != OK: + return Error.ERR_JSON_PARSE_ERROR + + error = _validate_json(json) + if error != OK: + return error + + json_filepath = filepath + json_data = json.result + + return OK + + +func get_frame_array() -> Array: + if not json_data: + return [] + + var frame_data = json_data.frames + if frame_data is Dictionary: + return frame_data.values() + + return frame_data + + +func get_image_filename() -> String: + if not (json_data and json_data.meta.has("image")): + return "" + + return json_data.meta.image + + +func get_image_size() -> Vector2: + if not json_data: + return Vector2.ZERO + + var image_size : Dictionary = json_data.meta.size + return Vector2( + image_size.w, + image_size.h + ) + + +func get_tag(tag_idx : int) -> Dictionary: + var tags := get_tags() + + if tag_idx >= 0 and tag_idx < tags.size(): + return tags[tag_idx] + + return {} + + +func get_tags() -> Array: + if not json_data: + return [] + + return json_data.meta.frameTags + + +static func _validate_json(json : JSONParseResult) -> int: + var data : Dictionary = json.result + + if not (data is Dictionary and data.has_all(["frames", "meta"])): + return Error.ERR_INVALID_JSON_DATA + + # "frames" validation + var frames = data.frames + var is_hash := frames is Dictionary + + for frame in frames: + if is_hash: + frame = frames[frame] + + if not _match_template(frame, FRAME_TEMPLATE): + return Error.ERR_INVALID_JSON_DATA + + # "meta" validation + if not _match_template(data.meta, META_TEMPLATE): + var meta := data.meta as Dictionary + + if not meta.has("frameTags"): + return Error.ERR_MISSING_FRAME_TAGS + elif meta.frameTags == []: + return Error.ERR_EMPTY_FRAME_TAGS + + return Error.ERR_INVALID_JSON_DATA + + return OK + + +""" +This helper function recursively walks an Array or a Dictionary checking if each +children's type matches the template +""" +static func _match_template(data, template) -> bool: + match typeof(template): + TYPE_INT: + # When parsed, the JSON interprets integer values as floats + if template == TYPE_INT and typeof(data) == TYPE_REAL: + return true + return typeof(data) == template + TYPE_DICTIONARY: + if typeof(data) != TYPE_DICTIONARY: + return false + + if not data.has_all(template.keys()): + return false + + for key in template: + if not _match_template(data[key], template[key]): + return false + TYPE_ARRAY: + if typeof(data) != TYPE_ARRAY: + return false + + if data.empty(): + return false + + for element in data: + if not _match_template(element, template[0]): + return false + + return true diff --git a/addons/aseprite_importer/classes/AsepriteImporter.gd b/addons/aseprite_importer/classes/AsepriteImporter.gd new file mode 100644 index 0000000..dd4d8d6 --- /dev/null +++ b/addons/aseprite_importer/classes/AsepriteImporter.gd @@ -0,0 +1,153 @@ +tool +extends Node +class_name AsepriteImporter + + +enum Error{ + OK, + INVALID_JSON_DATA, + MISSING_JSON_DATA, + MISSING_ANIMATION_PLAYER, + MISSING_SPRITE, + NO_TAGS_SELECTED, + DUPLICATE_TAG_NAME, + MISSING_TEXTURE, +} + + +static func generate_animations(import_data : AsepriteImportData, selected_tags : Array, + animation_player : AnimationPlayer, sprite : Node, texture : Texture) -> int: + + if not(import_data and import_data.json_data): + return Error.MISSING_JSON_DATA + + var frame_tags : Array = import_data.get_tags() + + if not selected_tags: + return Error.NO_TAGS_SELECTED + else: + var tag_names := [] + for tag_idx in selected_tags: + var tag_name : String = frame_tags[tag_idx].name + + if tag_names.has(tag_name): + return Error.DUPLICATE_TAG_NAME + else: + tag_names.append(tag_name) + + if not animation_player: + return Error.MISSING_ANIMATION_PLAYER + + if not(sprite is Sprite or sprite is Sprite3D): + return Error.MISSING_SPRITE + + if texture == null: + return Error.MISSING_TEXTURE + + var animation_root_path := animation_player.root_node + var animation_root_node := animation_player.get_node(animation_root_path) + var sprite_relative_path := str(animation_root_node.get_path_to(sprite)) + + # These are tracks that will be used + var tracks := { + "region" : { + path = (sprite_relative_path + ":region_rect"), + }, + "offset" : { + path = (sprite_relative_path + ":offset") + } + } + + var frames := import_data.get_frame_array() + var is_sprite3d := sprite is Sprite3D + + # Iterate over each tag (animation) + for tag_idx in selected_tags: + var tag : Dictionary = frame_tags[tag_idx] + + var animation : Animation + # Check if the animation already exists + if animation_player.has_animation(tag.name): + animation = animation_player.get_animation(tag.name) + else: + # If it doesn't, adds a new one + animation = Animation.new() + # warning-ignore:return_value_discarded + animation_player.add_animation(tag.name, animation) + + # Setup the animation tracks + for track_name in tracks: + var track : Dictionary = tracks[track_name] + + track.idx = animation.find_track(track.path) + + # Checks if the track doesn't exist + if track.idx == -1: + # Create a new_track + track.idx = animation.add_track(Animation.TYPE_VALUE) + animation.track_set_path(track.idx, track.path) + else: + # Remove all existing keys from the track + for key_idx in range(animation.track_get_key_count(track.idx)): + animation.track_remove_key(track.idx, 0) + + # Set the track Interpolation Mode to Nearest + animation.track_set_interpolation_type(track.idx, Animation.INTERPOLATION_NEAREST) + #Enable the track + animation.track_set_enabled(track.idx, true) + + var time := 0.0 + var frame_idxs := range(tag.from, tag.to + 1) + + # Modify the frame order based on the tag's direction + match tag.direction: + "reverse": + frame_idxs.invert() + "pingpong": + var pong_frame_idxs := range(tag.from + 1, tag.to) + pong_frame_idxs.invert() + frame_idxs += pong_frame_idxs + + # Insert the new keys + for i in frame_idxs: + var frame : Dictionary = frames[i] + + # Get the region of the spritesheet that has the frame + var rect = frame.frame + var region = Rect2(rect.x, rect.y, rect.w, rect.h) + + # Insert the new key for the region track + animation.track_insert_key(tracks.region.idx, time, region) + + # Get the center of the frame in the original size + var source_size : Dictionary = frame.sourceSize + var source_center_x : float = source_size.w / 2 + var source_center_y : float = source_size.h / 2 + + # Get the center of the trimmed frame in the spritesheet + var trim_rect : Dictionary = frame.spriteSourceSize + var trim_rect_center_x : float = trim_rect.x + (trim_rect.w / 2) + var trim_rect_center_y : float = trim_rect.y + (trim_rect.h / 2) + + # Calculate the offset between the trimmed frame center and original frame center + var offset_x := trim_rect_center_x - source_center_x + var offset_y := trim_rect_center_y - source_center_y + + # Invert the vertical offset when the selected sprite is a Sprite3D + if is_sprite3d: + offset_y *= -1 + + # Insert the new key for the offset track + animation.track_insert_key(tracks.offset.idx, time, Vector2(offset_x, offset_y)) + + # Add up the current frame's duration for the next key position + time += frame.duration / 1000 + + # Set the animation length equal to the sum of all frame's durations + animation.length = time + + sprite.texture = texture + sprite.region_enabled = true + sprite.centered = true + + return OK diff --git a/addons/aseprite_importer/classes/EditorTheme.gd b/addons/aseprite_importer/classes/EditorTheme.gd new file mode 100644 index 0000000..55ef661 --- /dev/null +++ b/addons/aseprite_importer/classes/EditorTheme.gd @@ -0,0 +1,26 @@ +tool +extends Node +class_name EditorTheme + + +var _theme : Theme + + +func _init(theme : Theme) -> void: + _theme = theme + + +func get_color(color_name : String, color_list := "Editor") -> Color: + return _theme.get_color(color_name, color_list) + + +func get_font(font_name : String, font_list := "EditorFonts") -> Font: + return _theme.get_font(font_name, font_list) + + +func get_icon(icon_name : String, icon_list := "EditorIcons") -> Texture: + return _theme.get_icon(icon_name, icon_list) + + +func get_stylebox(stylebox_name : String, stylebox_list := "EditorStyles") -> StyleBox: + return _theme.get_stylebox(stylebox_name, stylebox_list) diff --git a/addons/aseprite_importer/interface/Main.gd b/addons/aseprite_importer/interface/Main.gd new file mode 100644 index 0000000..6750d18 --- /dev/null +++ b/addons/aseprite_importer/interface/Main.gd @@ -0,0 +1,156 @@ +tool +extends PanelContainer + +onready var import_menu : Container = $Body/ImportMenu +onready var steps : Container = import_menu.get_node("Steps") +onready var json_import_menu : Container = steps.get_node("JSONImportMenu") +onready var tags_menu : Container = steps.get_node("TagsMenu") +onready var select_animation_player_menu = steps.get_node("SelectAnimationPlayerMenu") +onready var select_sprite_menu = steps.get_node("SelectSpriteMenu") +onready var generate_button : Button = steps.get_node("GenerateButton") + +onready var spritesheet_inspector : Container = $Body/SpritesheetInspector + +onready var alert_dialog : AcceptDialog = $AlertDialog + + +const ERROR_MSG := { + AsepriteImporter.Error.MISSING_JSON_DATA : "Missing JSON Data!", + AsepriteImporter.Error.MISSING_ANIMATION_PLAYER : "Select an AnimationPlayer node!", + AsepriteImporter.Error.MISSING_SPRITE : "Select a Sprite node!", + AsepriteImporter.Error.NO_TAGS_SELECTED : "No tags selected to import!", + AsepriteImporter.Error.DUPLICATE_TAG_NAME : "Two or more of the selected tags share the same name\nSelect only tags with distinct names", + AsepriteImporter.Error.MISSING_TEXTURE: "No texture selected!", +} + +const IMPORT_MENU_INITIAL_WIDTH := 300 + + +var import_data : AsepriteImportData + +var _is_ready := false + + +signal animations_generated(animation_player) + + +func _ready() -> void: + import_menu.rect_size.x = IMPORT_MENU_INITIAL_WIDTH + + alert_dialog.set_as_toplevel(true) + + json_import_menu.connect("data_imported", self, "_on_JSONImportMenu_data_imported") + json_import_menu.connect("data_cleared", self, "_on_JSONImportMenu_data_cleared") + tags_menu.connect("frame_selected", self, "_on_TagSelectMenu_frame_selected") + tags_menu.connect("tag_selected", self, "_on_TagSelectMenu_tag_selected") + generate_button.connect("pressed", self, "_on_GenerateButton_pressed") + + +func get_state() -> Dictionary: + var state := { + "import_data" : import_data, + "tags_menu" : tags_menu.get_state(), + "select_sprite_menu" : select_sprite_menu.get_state(), + "select_animation_player_menu" : select_animation_player_menu.get_state(), + "spritesheet_inspector" : spritesheet_inspector.get_state(), + } + + return state + + +func set_state(new_state : Dictionary) -> void: + var json_filepath := "" + var tags := [] + var selected_tags := [] + + if new_state.get("import_data", false): + import_data = new_state.import_data + json_filepath = import_data.json_filepath + tags = import_data.get_tags() + spritesheet_inspector.frames = import_data.get_frame_array() + +# var selected_tag := import_data.get_tag(tag_name) +# if selected_tag: +# spritesheet_inspector.select_frames(range(selected_tag.from, selected_tag.to + 1)) + else: + import_data = null + new_state.erase("tags_menu") +# new_state.erase("spritesheet_inspector") + + json_import_menu.set_json_filepath(json_filepath) + + select_sprite_menu.set_state(new_state.get("select_sprite_menu", {})) + + select_animation_player_menu.set_state(new_state.get("select_animation_player_menu", {})) + + spritesheet_inspector.set_state(new_state.get("spritesheet_inspector", {})) + + tags_menu.load_tags(tags) + tags_menu.set_state(new_state.get("tags_menu", {})) + + +func _show_alert(message : String) -> void: + alert_dialog.dialog_text = message + alert_dialog.popup_centered() + + +func _update_theme(editor_theme : EditorTheme) -> void: + generate_button.icon = editor_theme.get_icon("ImportCheck") + + +# Signal Callbacks +func _on_GenerateButton_pressed() -> void: + var selected_tags : Array = tags_menu.get_selected_tags() + var animation_player : AnimationPlayer = select_animation_player_menu.animation_player + var sprite : Node = select_sprite_menu.sprite + var texture : Texture = spritesheet_inspector.get_texture() + + var error := AsepriteImporter.generate_animations(import_data, selected_tags, animation_player, sprite, texture) + + if error != OK: + var error_msg : String + + if ERROR_MSG.has(error): + error_msg = ERROR_MSG[error] + else: + error_msg = "An error ocurred!" + + _show_alert(error_msg) + else: + emit_signal("animations_generated", animation_player) + + +func _on_JSONImportMenu_data_imported(new_import_data : AsepriteImportData) -> void: + import_data = new_import_data + + var tags : Array = import_data.get_tags() + tags_menu.load_tags(tags) + + var json_filepath := import_data.json_filepath + var json_dir_path := json_filepath.rsplit("/", true, 1)[0] + + var image_filepath := "" + + var image_filename := import_data.get_image_filename() + + image_filepath = str(json_dir_path, "/", image_filename) + + spritesheet_inspector.texture_size = import_data.get_image_size() + spritesheet_inspector.frames = import_data.get_frame_array() + spritesheet_inspector.load_texture(image_filepath) + + +func _on_JSONImportMenu_data_cleared() -> void: + import_data = null + + spritesheet_inspector.clear_texture() + tags_menu.clear_options() + + +func _on_TagSelectMenu_frame_selected(idx : int) -> void: + spritesheet_inspector.select_frames([idx]) + + +func _on_TagSelectMenu_tag_selected(tag_idx : int) -> void: + var selected_tag := import_data.get_tag(tag_idx) + spritesheet_inspector.select_frames(range(selected_tag.from, selected_tag.to + 1)) diff --git a/addons/aseprite_importer/interface/Main.tscn b/addons/aseprite_importer/interface/Main.tscn new file mode 100644 index 0000000..9d93c63 --- /dev/null +++ b/addons/aseprite_importer/interface/Main.tscn @@ -0,0 +1,100 @@ +[gd_scene load_steps=9 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/Main.gd" type="Script" id=1] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/JSONImportMenu.tscn" type="PackedScene" id=3] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/TagsMenu.tscn" type="PackedScene" id=4] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.tscn" type="PackedScene" id=5] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.tscn" type="PackedScene" id=6] + +[sub_resource type="Image" id=3] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 229, 127, 0, 113, 241, 127, 0, 113, 240, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 229, 127, 0, 114, 229, 127, 20, 113, 241, 127, 184, 113, 240, 127, 144, 113, 240, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 229, 127, 0, 114, 229, 127, 20, 114, 241, 127, 210, 115, 242, 128, 255, 114, 241, 127, 170, 114, 241, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 229, 127, 0, 114, 229, 127, 20, 114, 241, 126, 209, 115, 242, 128, 255, 114, 241, 127, 210, 109, 230, 121, 21, 109, 230, 121, 0, 0, 0, 0, 0, 113, 240, 127, 0, 113, 241, 127, 0, 114, 229, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 235, 123, 0, 114, 229, 127, 20, 114, 241, 127, 208, 115, 242, 128, 255, 114, 241, 127, 210, 104, 231, 127, 22, 106, 230, 124, 0, 0, 0, 0, 0, 113, 240, 127, 0, 113, 240, 127, 144, 113, 241, 127, 184, 114, 229, 127, 20, 114, 229, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 240, 123, 0, 107, 241, 120, 19, 114, 241, 126, 207, 115, 242, 128, 255, 114, 241, 126, 211, 104, 231, 127, 22, 104, 231, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 241, 127, 0, 114, 241, 127, 170, 115, 242, 128, 255, 114, 241, 127, 210, 114, 229, 127, 20, 114, 229, 127, 0, 113, 240, 127, 0, 113, 240, 127, 18, 114, 241, 126, 207, 115, 242, 128, 255, 114, 241, 127, 212, 104, 231, 127, 22, 104, 231, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 230, 121, 0, 109, 230, 121, 21, 114, 241, 127, 210, 115, 242, 128, 255, 114, 241, 126, 209, 114, 229, 127, 20, 113, 240, 127, 18, 114, 241, 126, 207, 115, 242, 128, 255, 114, 241, 126, 213, 104, 231, 127, 22, 104, 231, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 230, 124, 0, 104, 231, 127, 22, 114, 241, 127, 210, 115, 242, 128, 255, 114, 241, 126, 207, 113, 241, 127, 206, 115, 242, 128, 255, 114, 241, 126, 213, 110, 232, 121, 23, 107, 231, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 231, 127, 0, 104, 231, 127, 22, 114, 241, 127, 212, 115, 242, 128, 255, 115, 242, 128, 255, 114, 241, 126, 213, 106, 233, 127, 24, 108, 232, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 231, 127, 0, 104, 231, 127, 22, 113, 241, 127, 186, 114, 241, 126, 187, 106, 233, 127, 24, 106, 233, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 231, 127, 0, 113, 241, 127, 0, 114, 241, 126, 0, 106, 233, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=2] +flags = 0 +flags = 0 +image = SubResource( 3 ) +size = Vector2( 16, 16 ) + +[node name="Main" type="PanelContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Body" type="HSplitContainer" parent="."] +margin_left = 7.0 +margin_top = 7.0 +margin_right = 1017.0 +margin_bottom = 593.0 +size_flags_vertical = 3 + +[node name="ImportMenu" type="ScrollContainer" parent="Body"] +margin_right = 300.0 +margin_bottom = 586.0 +rect_min_size = Vector2( 300, 0 ) +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +scroll_horizontal = 100 + +[node name="Steps" type="VBoxContainer" parent="Body/ImportMenu"] +margin_right = 300.0 +margin_bottom = 586.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_constants/separation = 12 + +[node name="JSONImportMenu" parent="Body/ImportMenu/Steps" instance=ExtResource( 3 )] +margin_right = 300.0 + +[node name="TagsMenu" parent="Body/ImportMenu/Steps" instance=ExtResource( 4 )] +margin_top = 50.0 +margin_right = 300.0 +margin_bottom = 432.0 + +[node name="SelectAnimationPlayerMenu" parent="Body/ImportMenu/Steps" instance=ExtResource( 2 )] +margin_top = 444.0 +margin_right = 300.0 +margin_bottom = 484.0 + +[node name="SelectSpriteMenu" parent="Body/ImportMenu/Steps" instance=ExtResource( 5 )] +margin_top = 496.0 +margin_right = 300.0 +margin_bottom = 536.0 + +[node name="HSeparator" type="HSeparator" parent="Body/ImportMenu/Steps"] +margin_top = 548.0 +margin_right = 300.0 +margin_bottom = 552.0 + +[node name="GenerateButton" type="Button" parent="Body/ImportMenu/Steps"] +margin_top = 564.0 +margin_right = 300.0 +margin_bottom = 586.0 +hint_tooltip = "Generate the animations in the selected AnimationPlayer node" +size_flags_horizontal = 3 +text = "Generate Animations" +icon = SubResource( 2 ) + +[node name="SpritesheetInspector" parent="Body" instance=ExtResource( 6 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 312.0 +margin_right = 1010.0 +margin_bottom = 586.0 + +[node name="AlertDialog" type="AcceptDialog" parent="."] +margin_right = 83.0 +margin_bottom = 58.0 +popup_exclusive = true diff --git a/addons/aseprite_importer/interface/icons/dark_icon.png b/addons/aseprite_importer/interface/icons/dark_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dddc808c616fe26fb6dada7fd480696702b47d53 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~l>na*S9ON} zBK%VJb`Gw+2aIBS{{R2~Vd`0TcXw@V?FSDYOq@6|bIuEO<3lAt^*kj(e!&bt6)?bg zBtQ))9^&cZ7$Pw>x8IZRfB^^dW9Cgi|F@r3+q!Z_bF-|&qd5!*JeVhGSbjdc(7Liw zRp6}7>zWW_wN!=3wXsdvt}O2YdwtrM>)v$#QdRn4;ktw8uU9(HU@u@~Io`~p%n3A~ N!PC{xWt~$(69CFQReAsb literal 0 HcmV?d00001 diff --git a/addons/aseprite_importer/interface/icons/light_icon.png b/addons/aseprite_importer/interface/icons/light_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8502f1956c28ee5c9809a5dd0ed3e5f07fb73091 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~l>na*S9ON} zBK%VJb`Gw+2aIBS{{R2~Vd`0TcXw@V?FSDYOq@6|bIuEO<3lAt^*kj(e!&bt6)?bg zBtQ))9_;Dj7$Pw>x8IwOL6O5*le4?%KXbo`nz7XVMYm3=&(dY+F;U>`JZs#(?g^Wo zqmk09IQLcRceD%md-t;3?kInIB19v5=e8%$H#f`w;^kX!d)SD7YbdL|D(@L3pz#cz Lu6{1-oD!MMeta->Tags when exporting the spritesheet from Aseprite" +const MSG_EMPTY_FRAME_TAGS = \ + "Animation tags not defined in the JSON file\n\n" + \ + "Add tags in the Aseprite timeline to define the frames inside each animation" + + +signal data_imported(import_data) +signal data_cleared + + +func _ready(): + clear_button.hide() + + alert_dialog.set_as_toplevel(true) + + import_button.connect("pressed", self, "_on_ImportButton_pressed") + clear_button.connect("pressed", self, "_on_ClearButton_pressed") + file_dialog.connect("file_selected", self, "_on_FileDialog_file_selected") + + +func set_json_filepath(new_filepath : String) -> void: + if new_filepath: + import_button.text = new_filepath + clear_button.show() + else: + import_button.text = IMPORT_BUTTON_DEFAULT_TEXT + clear_button.hide() + + +func _update_theme(editor_theme : EditorTheme) -> void: + import_button.icon = editor_theme.get_icon("Load") + clear_button.icon = editor_theme.get_icon("Clear") + + +#Signal Callbacks +func _on_ImportButton_pressed() -> void: + file_dialog.invalidate() + file_dialog.popup_centered_ratio(0.5) + + +func _on_ClearButton_pressed() -> void: + set_json_filepath("") + emit_signal("data_cleared") + + +func _on_FileDialog_file_selected(path : String) -> void: + var import_data := AsepriteImportData.new() + var error := import_data.load(path) + + if error != OK: + var error_msg : String + + match error: + AsepriteImportData.Error.ERR_JSON_PARSE_ERROR: + error_msg = MSG_JSON_PARSE_ERROR + AsepriteImportData.Error.ERR_INVALID_JSON_DATA: + error_msg = MSG_INVALID_JSON_DATA + AsepriteImportData.Error.ERR_MISSING_FRAME_TAGS: + error_msg = MSG_MISSING_FRAME_TAGS + AsepriteImportData.Error.ERR_EMPTY_FRAME_TAGS: + error_msg = MSG_EMPTY_FRAME_TAGS + _: + error_msg = MSG_JSON_OPEN_FILE_ERROR % [path, error] + + set_json_filepath("") + + yield(get_tree(), "idle_frame") + alert_dialog.dialog_text = error_msg + alert_dialog.popup_centered() + else: + set_json_filepath(path) + + emit_signal("data_imported", import_data) diff --git a/addons/aseprite_importer/interface/import_menu/JSONImportMenu.tscn b/addons/aseprite_importer/interface/import_menu/JSONImportMenu.tscn new file mode 100644 index 0000000..638092e --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/JSONImportMenu.tscn @@ -0,0 +1,78 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/JSONImportMenu.gd" type="Script" id=1] + +[sub_resource type="Image" id=3] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 179, 223, 223, 223, 179, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 220, 220, 220, 59, 223, 223, 223, 201, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 200, 220, 220, 220, 59, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 199, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 198, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 203, 223, 223, 223, 203, 223, 223, 223, 152, 223, 223, 223, 152, 222, 222, 222, 101, 222, 222, 222, 101, 219, 219, 219, 50, 219, 219, 219, 50, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 222, 222, 222, 0, 219, 219, 219, 0, 219, 219, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=2] +flags = 0 +flags = 0 +image = SubResource( 3 ) +size = Vector2( 16, 16 ) + +[node name="JSONImport" type="VBoxContainer"] +margin_right = 91.0 +margin_bottom = 38.0 +size_flags_horizontal = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="."] +margin_right = 91.0 +margin_bottom = 14.0 +text = "JSON Data" +valign = 1 + +[node name="InputContainer" type="HBoxContainer" parent="."] +margin_top = 18.0 +margin_right = 91.0 +margin_bottom = 38.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ImportButton" type="Button" parent="InputContainer"] +margin_right = 91.0 +margin_bottom = 20.0 +hint_tooltip = "Import a Aseprite JSON file" +size_flags_horizontal = 3 +text = "Import JSON" + +[node name="ClearButton" type="Button" parent="InputContainer"] +visible = false +margin_left = 143.0 +margin_top = -18.0 +margin_right = 187.0 +margin_bottom = 2.0 +text = "Clear" +icon = SubResource( 2 ) + +[node name="FileDialog" type="FileDialog" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_bottom = 110.0 +window_title = "Select the JSON file" +resizable = true +mode_overrides_title = false +mode = 0 +filters = PoolStringArray( "*.json ; JSON Files" ) +show_hidden_files = true + +[node name="AlertDialog" type="AcceptDialog" parent="."] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_top = 42.0 +margin_right = 400.0 +margin_bottom = 100.0 +popup_exclusive = true diff --git a/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.gd b/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.gd new file mode 100644 index 0000000..cfdfc33 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.gd @@ -0,0 +1,64 @@ +tool +extends Container + + +onready var select_button : Button = $Button +onready var select_node_dialog : WindowDialog = $SelectNodeDialog + + +const SELECT_BUTTON_DEFAULT_TEXT := "Select a Node" + + +var animation_player : AnimationPlayer setget set_animation_player + + +signal node_selected(animation_player) + + +func _ready(): + select_node_dialog.class_filters = ["AnimationPlayer"] + + select_button.connect("pressed", self, "_on_SelectButton_pressed") + select_node_dialog.connect("node_selected", self, "_on_SelectNodeDialog_node_selected") + + +func get_state() -> Dictionary: + var state := {} + + if animation_player: + state.animation_player = animation_player + + return state + + +func set_state(new_state : Dictionary) -> void: + var new_animation_player : Node = new_state.get("animation_player") + + if new_animation_player != null : + self.animation_player = new_animation_player + else: + animation_player = null + select_button.text = SELECT_BUTTON_DEFAULT_TEXT + + +func _update_theme(editor_theme : EditorTheme) -> void: + select_button.icon = editor_theme.get_icon("AnimationPlayer") + + +# Setters and Getters +func set_animation_player(node : AnimationPlayer) -> void: + animation_player = node + + var node_path := node.owner.get_parent().get_path_to(node) + select_button.text = node_path + + +# Signal Callbacks +func _on_SelectButton_pressed() -> void: + if select_node_dialog.initialize(): + select_node_dialog.popup_centered_ratio(.5) + + +func _on_SelectNodeDialog_node_selected(selected_node : Node) -> void: + self.animation_player = selected_node + emit_signal("node_selected", selected_node) diff --git a/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.tscn b/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.tscn new file mode 100644 index 0000000..b8b67b2 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.tscn @@ -0,0 +1,53 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn" type="PackedScene" id=1] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectAnimationPlayerMenu.gd" type="Script" id=2] + +[sub_resource type="Image" id=1] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 206, 164, 241, 0, 204, 159, 235, 0, 0, 0, 0, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 164, 241, 0, 0, 0, 0, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 161, 238, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 162, 239, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 204, 159, 235, 40, 205, 161, 238, 0, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 255, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 255, 206, 164, 241, 0, 0, 0, 0, 0, 206, 164, 241, 0, 204, 159, 235, 0, 0, 0, 0, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 206, 164, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 164, 241, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=2] +flags = 0 +flags = 0 +image = SubResource( 1 ) +size = Vector2( 16, 16 ) + +[node name="SelectAnimationPlayer" type="VBoxContainer"] +margin_right = 148.0 +margin_bottom = 38.0 +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="."] +margin_right = 148.0 +margin_bottom = 14.0 +text = "Select AnimationPlayer" + +[node name="Button" type="Button" parent="."] +margin_top = 18.0 +margin_right = 148.0 +margin_bottom = 40.0 +hint_tooltip = "Select a AnimationPlayer node from the current scene" +text = "Select Node" +icon = SubResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="SelectNodeDialog" parent="." instance=ExtResource( 1 )] +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 42.0 +margin_right = 245.0 +margin_bottom = 43.0 +window_title = "Select the AnimationPlayer Node" diff --git a/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.gd b/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.gd new file mode 100644 index 0000000..9ddd97f --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.gd @@ -0,0 +1,144 @@ +tool +extends WindowDialog + + +onready var body : VBoxContainer = $MarginContainer/Body + +onready var edited_scene_view : Container = body.get_node('EditedSceneView') +onready var scene_tree : Tree = edited_scene_view.get_node('SceneTree') + +onready var footer : HBoxContainer = body.get_node('Footer') +onready var confirm_button : Button = footer.get_node('ConfirmButton') +onready var cancel_button : Button = footer.get_node('CancelButton') + +onready var alert_dialog : AcceptDialog = $AlertDialog + + +enum Columns { + NAME, + PATH, +} + + +const MSG_EMPTY_SCENE = 'The current scene is empty!' +const MSG_UNSAVED_SCENE = 'The current scene is still not saved!' +const MSG_NO_FILTERED_NODES_IN_SCENE = "There aren't any %s nodes in the current scene" + +const WINDOW_TITLE_DEFAULT = 'Select a Node' +const WINDOW_TITLE_WITH_FILTER = "Select the %s Node" + +const DISABLED_ICON_MODULATE := Color(1, 1, 1, .5) + + +var class_filters : Array setget set_class_filters +var edited_scene_root : Node + + +var _editor_theme : EditorTheme + + +signal node_selected(selected_node) + + +func _ready(): + self.class_filters = class_filters + + scene_tree.columns = Columns.size() + scene_tree.set_column_expand(Columns.PATH, false) + + alert_dialog.set_as_toplevel(true) + + scene_tree.connect('item_activated', self, '_on_node_selected') + confirm_button.connect('pressed', self, '_on_node_selected') + cancel_button.connect('pressed', self, 'hide') + + +func initialize() -> bool: + edited_scene_root = get_tree().get_edited_scene_root() + if edited_scene_root == null: + _show_alert(MSG_EMPTY_SCENE) + return false + + var scene_filename := edited_scene_root.filename + if not scene_filename: + _show_alert(MSG_UNSAVED_SCENE) + return false + + scene_tree.clear() + + var filtered_node_count := _add_node_to_scene_tree(edited_scene_root) + + if class_filters and filtered_node_count == 0: + var filters_str := PoolStringArray(class_filters).join(" / ") + _show_alert(MSG_NO_FILTERED_NODES_IN_SCENE % filters_str) + return false + + return true + + +func _add_node_to_scene_tree(node : Node, parent : TreeItem = null) -> int: + var tree_item := scene_tree.create_item(parent) + + var node_class := node.get_class() + + tree_item.set_icon(Columns.NAME, _editor_theme.get_icon(node_class)) + tree_item.set_text(Columns.NAME, node.name) + + tree_item.set_text(Columns.PATH, edited_scene_root.get_path_to(node)) + + var disabled_font_color := _editor_theme.get_color("disabled_font_color") + + var filtered_node_count := 0 + if class_filters: + var is_valid := false + + for filter in class_filters: + if node.is_class(filter): + is_valid = true + filtered_node_count += 1 + break + + if not is_valid: + tree_item.set_selectable(Columns.NAME, false) + tree_item.set_icon_modulate(Columns.NAME, DISABLED_ICON_MODULATE) + tree_item.set_custom_color(Columns.NAME, disabled_font_color) + + + for child in node.get_children(): + if child.owner == edited_scene_root: + filtered_node_count += _add_node_to_scene_tree(child, tree_item) + + return filtered_node_count + + +func _show_alert(message : String) -> void: + alert_dialog.dialog_text = message + alert_dialog.popup_centered() + + +func _update_theme(editor_theme : EditorTheme) -> void: + _editor_theme = editor_theme + + +# Setters and Getters +func set_class_filters(filters : Array) -> void: + class_filters = filters + + if class_filters != []: + var filters_str := PoolStringArray(class_filters).join(" / ") + window_title = WINDOW_TITLE_WITH_FILTER % filters_str + else: + window_title = WINDOW_TITLE_DEFAULT + + +# Signal Callbacks +func _on_node_selected() -> void: + var selected_item := scene_tree.get_selected() + + if selected_item: + var node_path := selected_item.get_text(Columns.PATH) + var selected_node := edited_scene_root.get_node(node_path) + + emit_signal('node_selected', selected_node) + + hide() diff --git a/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn b/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn new file mode 100644 index 0000000..be818a3 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn @@ -0,0 +1,98 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectNodeDialog.gd" type="Script" id=1] + +[node name="SelectNodeDialog" type="WindowDialog"] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -150.0 +margin_top = -100.0 +margin_right = 150.0 +margin_bottom = 100.0 +rect_min_size = Vector2( 300, 200 ) +size_flags_horizontal = 3 +size_flags_vertical = 3 +window_title = "Select a Node" +resizable = true +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +custom_constants/margin_right = 8 +custom_constants/margin_top = 8 +custom_constants/margin_left = 8 +custom_constants/margin_bottom = 8 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Body" type="VBoxContainer" parent="MarginContainer"] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 292.0 +margin_bottom = 192.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="EditedSceneView" type="VBoxContainer" parent="MarginContainer/Body"] +margin_right = 284.0 +margin_bottom = 160.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="MarginContainer/Body/EditedSceneView"] +margin_right = 284.0 +margin_bottom = 14.0 +size_flags_horizontal = 3 +text = "Current Edited Scene:" + +[node name="SceneTree" type="Tree" parent="MarginContainer/Body/EditedSceneView"] +margin_top = 18.0 +margin_right = 284.0 +margin_bottom = 160.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +columns = 2 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Footer" type="HBoxContainer" parent="MarginContainer/Body"] +margin_top = 164.0 +margin_right = 284.0 +margin_bottom = 184.0 +size_flags_horizontal = 3 + +[node name="ConfirmButton" type="Button" parent="MarginContainer/Body/Footer"] +margin_left = 25.0 +margin_right = 114.0 +margin_bottom = 20.0 +size_flags_horizontal = 6 +text = "Select Node" + +[node name="CancelButton" type="Button" parent="MarginContainer/Body/Footer"] +margin_left = 187.0 +margin_right = 241.0 +margin_bottom = 20.0 +size_flags_horizontal = 6 +text = "Cancel" + +[node name="AlertDialog" type="AcceptDialog" parent="."] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -41.5 +margin_top = -29.0 +margin_right = 41.5 +margin_bottom = 29.0 +popup_exclusive = true diff --git a/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.gd b/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.gd new file mode 100644 index 0000000..1845071 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.gd @@ -0,0 +1,81 @@ +tool +extends Container + + +onready var select_button : Button = $Button +onready var select_node_dialog : WindowDialog = $SelectNodeDialog + + +const SELECT_BUTTON_DEFAULT_TEXT := "Select a Node" + + +var sprite : Node setget set_sprite + +var _sprite_icon : Texture +var _sprite3d_icon : Texture + + +signal node_selected(sprite) + + +func _ready(): + select_node_dialog.class_filters = ["Sprite", "Sprite3D"] + + select_button.connect("pressed", self, "_on_SelectButton_pressed") + select_node_dialog.connect("node_selected", self, "_on_SelectNodeDialog_node_selected") + + +func get_state() -> Dictionary: + var state := {} + + if sprite: + state.sprite = sprite + + return state + + +func set_state(new_state : Dictionary) -> void: + var new_sprite : Node = new_state.get("sprite") + + if new_sprite != null: + self.sprite = new_sprite + else: + sprite = null + select_button.text = SELECT_BUTTON_DEFAULT_TEXT + select_button.icon = _sprite_icon + + +func _update_theme(editor_theme : EditorTheme) -> void: + var is_sprite3d := select_button.icon == _sprite3d_icon + + _sprite_icon = editor_theme.get_icon("Sprite") + _sprite3d_icon = editor_theme.get_icon("Sprite3D") + + if is_sprite3d: + select_button.icon = _sprite3d_icon + else: + select_button.icon = _sprite_icon + + +# Setters and Getters +func set_sprite(node : Node) -> void: + sprite = node + + var node_path := node.owner.get_parent().get_path_to(node) + select_button.text = node_path + + if node.is_class("Sprite"): + select_button.icon = _sprite_icon + elif node.is_class("Sprite3D"): + select_button.icon = _sprite3d_icon + + +# Signal Callbacks +func _on_SelectButton_pressed() -> void: + if select_node_dialog.initialize(): + select_node_dialog.popup_centered_ratio(.5) + + +func _on_SelectNodeDialog_node_selected(selected_node : Node) -> void: + self.sprite = selected_node + emit_signal("node_selected", selected_node) diff --git a/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.tscn b/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.tscn new file mode 100644 index 0000000..40332c6 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectNodeDialog.tscn" type="PackedScene" id=1] +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/SelectSpriteMenu.gd" type="Script" id=2] + +[sub_resource type="Image" id=3] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 163, 182, 236, 0, 164, 182, 242, 0, 164, 182, 242, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 164, 182, 242, 0, 164, 182, 242, 0, 160, 179, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 180, 236, 0, 163, 182, 236, 28, 164, 182, 242, 169, 164, 182, 242, 229, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 229, 164, 182, 242, 169, 160, 179, 236, 27, 160, 179, 236, 0, 0, 0, 0, 0, 160, 179, 236, 0, 160, 179, 236, 27, 164, 182, 242, 236, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 236, 160, 179, 236, 27, 160, 179, 236, 0, 164, 181, 242, 0, 164, 181, 242, 164, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 181, 242, 163, 164, 181, 242, 0, 164, 182, 242, 0, 164, 182, 242, 225, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 225, 164, 182, 242, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 163, 182, 240, 70, 163, 182, 240, 70, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 163, 182, 240, 70, 163, 182, 240, 70, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 241, 0, 164, 182, 241, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 241, 0, 164, 182, 241, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 241, 0, 164, 182, 241, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 241, 0, 164, 182, 241, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 163, 182, 240, 70, 163, 182, 240, 70, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 163, 182, 240, 70, 163, 182, 240, 70, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 0, 164, 182, 242, 0, 164, 182, 242, 226, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 252, 163, 182, 241, 95, 163, 182, 241, 95, 164, 182, 242, 201, 164, 182, 242, 201, 163, 182, 241, 95, 163, 182, 241, 95, 164, 182, 242, 251, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 225, 164, 182, 242, 0, 164, 181, 242, 0, 164, 181, 242, 164, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 163, 182, 236, 28, 163, 182, 239, 0, 163, 177, 238, 0, 163, 177, 238, 0, 163, 181, 240, 0, 161, 178, 238, 30, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 181, 242, 164, 164, 181, 242, 0, 160, 179, 236, 0, 160, 179, 236, 27, 164, 182, 242, 237, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 226, 163, 182, 242, 84, 163, 173, 234, 25, 163, 173, 234, 25, 165, 183, 243, 85, 164, 182, 242, 226, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 237, 160, 179, 236, 27, 160, 179, 236, 0, 0, 0, 0, 0, 161, 180, 236, 0, 163, 182, 236, 28, 164, 182, 242, 169, 164, 182, 242, 229, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 165, 183, 243, 255, 164, 182, 242, 229, 164, 182, 242, 169, 160, 179, 236, 27, 160, 179, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 182, 236, 0, 164, 182, 242, 0, 164, 182, 242, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 165, 183, 243, 0, 164, 182, 242, 0, 164, 182, 242, 0, 160, 179, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=2] +flags = 0 +flags = 0 +image = SubResource( 3 ) +size = Vector2( 16, 16 ) + +[node name="SelectSprite" type="VBoxContainer"] +margin_right = 89.0 +margin_bottom = 38.0 +size_flags_horizontal = 3 +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="."] +margin_right = 107.0 +margin_bottom = 14.0 +text = "Select Sprite" + +[node name="Button" type="Button" parent="."] +margin_top = 18.0 +margin_right = 107.0 +margin_bottom = 40.0 +hint_tooltip = "Select a Sprite node from the current scene" +text = "Select Node" +icon = SubResource( 2 ) + +[node name="SelectNodeDialog" parent="." instance=ExtResource( 1 )] diff --git a/addons/aseprite_importer/interface/import_menu/TagsMenu.gd b/addons/aseprite_importer/interface/import_menu/TagsMenu.gd new file mode 100644 index 0000000..866b009 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/TagsMenu.gd @@ -0,0 +1,202 @@ +tool +extends Container + + +onready var select_all_button : CheckBox = find_node("SelectAllButton") +onready var options_list : VBoxContainer = find_node("OptionsList") +onready var tree : Tree = $Tree + + +enum Columns { + SELECTED, + NAME, + START, + END, + DIRECTION, +} + + +var _tree_root : TreeItem +var _options := [] +var _toggling_option := false + + +signal frame_selected(idx) +signal selected_tags_changed(selected_tags) +signal tag_selected(tag_name) + + +func _ready(): + clear_options() + + tree.columns = Columns.size() + + tree.set_column_expand(Columns.SELECTED, false) + tree.set_column_min_width(Columns.SELECTED, 32) + + tree.set_column_title(Columns.NAME, "Name") + tree.set_column_expand(Columns.NAME, true) + tree.set_column_min_width(Columns.START, 48) + + tree.set_column_title(Columns.START, "Start") + tree.set_column_expand(Columns.START, false) + tree.set_column_min_width(Columns.START, 48) + + tree.set_column_title(Columns.END, "End") + tree.set_column_expand(Columns.END, false) + tree.set_column_min_width(Columns.END, 48) + + tree.set_column_title(Columns.DIRECTION, "Direction") + tree.set_column_expand(Columns.DIRECTION, false) + tree.set_column_min_width(Columns.DIRECTION, 84) + + tree.set_column_titles_visible(true) + + select_all_button.connect("toggled", self, "_on_SelectAllButton_toggled") + tree.connect("cell_selected", self, "_on_Tree_cell_selected") + tree.connect("item_edited", self, "_on_Tree_item_edited") + + +func clear_options() -> void: + select_all_button.hide() + + for option in _options: + option.free() + _options.clear() + + tree.clear() + + _tree_root = tree.create_item() + + +func load_tags(tags : Array) -> void: + clear_options() + + if tags == []: + return + + for tag in tags: + var new_tree_item := tree.create_item(_tree_root) + + new_tree_item.set_cell_mode(Columns.SELECTED, TreeItem.CELL_MODE_CHECK) + new_tree_item.set_editable(Columns.SELECTED, true) + new_tree_item.set_checked(Columns.SELECTED, true) + new_tree_item.set_selectable(Columns.SELECTED, false) + + new_tree_item.set_text(Columns.NAME, tag.name) + + new_tree_item.set_text(Columns.START, str(floor(tag.from))) + new_tree_item.set_text_align(Columns.START, TreeItem.ALIGN_CENTER) + + new_tree_item.set_text(Columns.END, str(floor(tag.to))) + new_tree_item.set_text_align(Columns.END, TreeItem.ALIGN_CENTER) + + new_tree_item.set_text(Columns.DIRECTION, " %s" % tag.direction) + new_tree_item.set_selectable(Columns.DIRECTION, false) + + _options.append(new_tree_item) + + select_all_button.pressed = true + select_all_button.show() + + +func get_selected_tags() -> Array: + var selected_tags := [] + + for i in range(_options.size()): + var item : TreeItem = _options[i] + if item.is_checked(Columns.SELECTED): + selected_tags.append(i) + + return selected_tags + + +func get_state() -> Dictionary: + var state := { + selected_tags = get_selected_tags() + } + + var selected_item := tree.get_selected() + if selected_item != null: + var selected_column := tree.get_selected_column() + + var item_idx := _options.find(selected_item) + + state.selected_cell = Vector2(selected_column, item_idx) + + return state + + +func set_state(new_state : Dictionary) -> void: + if new_state.has("selected_tags") and _options != []: + select_all_button.pressed = false + + for tag in new_state.selected_tags: + _options[tag].set_checked(Columns.SELECTED, true) + + if new_state.has("selected_cell"): + var selected_cell : Vector2 = new_state.selected_cell + var tree_item : TreeItem = _options[selected_cell.y] + var column : int = selected_cell.x + + tree_item.select(column) + + match column: + Columns.NAME: + emit_signal("tag_selected", selected_cell.y) + Columns.START, Columns.END: + emit_signal("frame_selected", int(tree_item.get_text(column))) + + + for option in _options: + if not option.is_checked(Columns.SELECTED): + return + + _toggling_option = true + select_all_button.pressed = true + _toggling_option = false + + +# Signal Callbacks +func _on_SelectAllButton_toggled(button_pressed : bool) -> void: + if _toggling_option: + return + + for option in _options: + option.set_checked(Columns.SELECTED, button_pressed) + + emit_signal("selected_tags_changed", get_selected_tags()) + + +func _on_Tree_cell_selected() -> void: + var selected_column := tree.get_selected_column() + var selected_item := tree.get_selected() + + match selected_column: + Columns.NAME: + emit_signal("tag_selected", _options.find(selected_item)) + Columns.START, Columns.END: + emit_signal("frame_selected", int(selected_item.get_text(selected_column))) + + +func _on_Tree_item_edited() -> void: + _toggling_option = true + + if select_all_button.pressed: + for option in _options: + if option.is_checked(Columns.SELECTED): + select_all_button.pressed = false + break + else: + var is_all_selected := true + for option in _options: + if not option.is_checked(Columns.SELECTED): + is_all_selected = false + break + + if is_all_selected: + select_all_button.pressed = true + + _toggling_option = false + + emit_signal("selected_tags_changed", get_selected_tags()) diff --git a/addons/aseprite_importer/interface/import_menu/TagsMenu.tscn b/addons/aseprite_importer/interface/import_menu/TagsMenu.tscn new file mode 100644 index 0000000..499ea33 --- /dev/null +++ b/addons/aseprite_importer/interface/import_menu/TagsMenu.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/import_menu/TagsMenu.gd" type="Script" id=1] + + + +[node name="TagSelectMenu" type="VBoxContainer"] +rect_min_size = Vector2( 0, 120 ) +size_flags_vertical = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Header" type="HBoxContainer" parent="."] +margin_right = 28.0 +margin_bottom = 14.0 + +[node name="Label" type="Label" parent="Header"] +margin_right = 28.0 +margin_bottom = 14.0 +size_flags_horizontal = 3 +text = "Tags" +valign = 1 + +[node name="SelectAllButton" type="CheckBox" parent="Header"] +visible = false +margin_left = 32.0 +margin_right = 120.0 +margin_bottom = 24.0 +size_flags_horizontal = 8 +text = "Select All" + +[node name="Tree" type="Tree" parent="."] +margin_top = 18.0 +margin_right = 28.0 +margin_bottom = 120.0 +size_flags_vertical = 3 +columns = 5 +hide_folding = true +hide_root = true diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.gd b/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.gd new file mode 100644 index 0000000..c1415ae --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.gd @@ -0,0 +1,95 @@ +tool +extends Container + + +onready var label : Label = $Header/Label +onready var visibility_button: Button = $Header/VisibilityButton +onready var color_picker : ColorPickerButton = $ColorPicker + + +export var label_text := '' setget set_label_text +export var visibility := true setget set_visibility +export var show_visibility_button := true setget set_show_visibility_button +export var color_value := Color.black setget set_color_value +export var color_edit_alpha := true setget set_color_edit_alpha +export(String, MULTILINE) var color_picker_tooltip := "" setget set_color_picker_tooltip + + +var _visible_icon : Texture +var _hidden_icon : Texture + + +signal property_changed(color_menu_item) + + +func _ready(): + self.label_text = label_text + self.visibility = visibility + self.show_visibility_button = show_visibility_button + self.color_value = color_value + self.color_edit_alpha = color_edit_alpha + self.color_picker_tooltip = color_picker_tooltip + + visibility_button.connect('pressed', self, '_on_ViewButton_pressed') + color_picker.connect('color_changed', self, '_on_ColorPicker_color_changed') + + +func _update_theme(editor_theme : EditorTheme) -> void: + _visible_icon = editor_theme.get_icon('GuiVisibilityVisible') + _hidden_icon = editor_theme.get_icon('GuiVisibilityHidden') + + self.visibility = visibility + + +# Setters and Getters +func set_color_picker_tooltip(text : String) -> void: + color_picker_tooltip = text + if color_picker: + color_picker.hint_tooltip = text + + +func set_color_value(color: Color) -> void: + color_value = color + if color_picker: + color_picker.color = color_value + + +func set_color_edit_alpha(value : bool) -> void: + color_edit_alpha = value + if color_picker: + color_picker.edit_alpha = color_edit_alpha + + +func set_label_text(text : String) -> void: + label_text = text + if label: + label.text = label_text + + +func set_show_visibility_button(show_button : bool) -> void: + show_visibility_button = show_button + if visibility_button: + visibility_button.visible = show_visibility_button + + +func set_visibility(value : bool) -> void: + visibility = value + + if visibility_button: + if visibility: + visibility_button.icon = _visible_icon + visibility_button.modulate.a = 1 + else: + visibility_button.icon = _hidden_icon + visibility_button.modulate.a = .5 + + +# Signal Callbacks +func _on_ColorPicker_color_changed(color : Color) -> void: + color_value = color + emit_signal('property_changed', self) + + +func _on_ViewButton_pressed() -> void: + self.visibility = !visibility + emit_signal('property_changed', self) diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.tscn b/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.tscn new file mode 100644 index 0000000..65a46a7 --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.gd" type="Script" id=1] + +[node name="ColorMenuItem" type="VBoxContainer"] +margin_right = 103.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Header" type="HBoxContainer" parent="."] +margin_right = 116.0 +margin_bottom = 22.0 +rect_min_size = Vector2( 0, 22 ) + +[node name="Label" type="Label" parent="Header"] +margin_top = 4.0 +margin_right = 100.0 +margin_bottom = 18.0 +size_flags_horizontal = 3 +text = "ColorMenuItem" + +[node name="VisibilityButton" type="ToolButton" parent="Header"] +margin_left = 104.0 +margin_right = 116.0 +margin_bottom = 22.0 +hint_tooltip = "Toggle Visibility" +size_flags_horizontal = 8 +shortcut_in_tooltip = false + +[node name="ColorPicker" type="ColorPickerButton" parent="."] +margin_top = 26.0 +margin_right = 116.0 +margin_bottom = 46.0 diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/SettingsMenu.gd b/addons/aseprite_importer/interface/spritesheet_inspector/SettingsMenu.gd new file mode 100644 index 0000000..1d1fd3a --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/SettingsMenu.gd @@ -0,0 +1,74 @@ +tool +extends Container + + +onready var options : Container = $Options + + +const PROP_TO_COLOR_MENU := { + frame_border = "FrameBorder", + selection_border = "SelectionBorder", + texture_background = "TextureBackground", + inspector_background = "InspectorBackground", +} + +const DEFAULT_SETTINGS :={ + frame_border = { + color = Color("#808080"), + visibility = true, + }, + selection_border = { + color = Color.yellow, + visibility = true, + }, + texture_background = { + color = Color("#404040"), + visibility = true, + }, + inspector_background = { + color = Color.black, + }, +} + + +var settings := DEFAULT_SETTINGS.duplicate(true) setget set_settings + + +signal settings_changed(settings) + + +func _ready(): + for property in PROP_TO_COLOR_MENU: + var node_name : String = PROP_TO_COLOR_MENU[property] + var color_menu = options.get_node(node_name) + + color_menu.set_meta("property", property) + + color_menu.connect("property_changed", self, "_on_ColorMenuItem_property_changed") + + +# Setters and Getters +func set_settings(new_settings : Dictionary) -> void: + if new_settings: + settings = new_settings + else: + settings = DEFAULT_SETTINGS.duplicate(true) + + for property in PROP_TO_COLOR_MENU: + var node_name : String = PROP_TO_COLOR_MENU[property] + var color_menu = options.get_node(node_name) + + color_menu.color_value = settings[property].color + color_menu.visibility = settings[property].get("visibility", false) + + emit_signal("settings_changed", settings) + + +# Signal Callbacks +func _on_ColorMenuItem_property_changed(color_menu_item : Node) -> void: + var property : String = color_menu_item.get_meta("property") + + settings[property]["color"] = color_menu_item.color_value + settings[property]["visibility"] = color_menu_item.visibility + + emit_signal("settings_changed", settings) diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.gd b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.gd new file mode 100644 index 0000000..fc06ccb --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.gd @@ -0,0 +1,247 @@ +tool +extends Container + + +onready var header : HBoxContainer= $Header +onready var filename_label : Label = header.find_node("Filename") +onready var settings_button : Button = header.find_node("SettingsButton") + +onready var body : Container = $Body +onready var warning_message : Label = body.find_node("WarningMessage") +onready var search_file_button : Button = body.find_node("SearchFileButton") + +onready var spritesheet_view : Container = body.find_node("SpritesheetView") + +onready var settings_menu : Container = body.get_node("SettingsMenu") + +onready var footer : HBoxContainer = $Footer +onready var frame_count : Label = footer.get_node("FrameCount") +onready var zoom_button : Button = footer.get_node("ZoomButton") +onready var zoom_slider : HSlider = footer.get_node("ZoomSlider") + +onready var file_dialog : FileDialog = $FileDialog + + +const MSG_MISSING_IMAGE_PARAMETER = "The imported JSON doesn't contain the spritesheet file name" +const MSG_IMPORT_JSON = "Import a Aseprite JSON file to \npreview the spritesheet" +const MSG_INVALID_TEXTURE_SIZE = "The selected texture size %s doesn't match the JSON %s" +const MSG_LOAD_ERROR = "Error on loading the file!" +const MSG_SPRITESHEET_NOT_FOUND = "Spritesheet \"%s\" not found!" + + +var texture_size : Vector2 setget set_texture_size +var frames := [] + +var _zoom_update := false + + +func _ready() -> void: + clear_texture() + + settings_button.pressed = false + warning_message.text = MSG_IMPORT_JSON + search_file_button.hide() + spritesheet_view.hide() + settings_menu.hide() + + var settings = settings_menu.settings + spritesheet_view.load_settings(settings) + + settings_button.connect("toggled", self, "_on_SettingsButton_toggled") + search_file_button.connect("pressed", self, "_on_SearchFileButton_pressed") + spritesheet_view.connect("zoom_changed", self, "_on_SpritesheetInspector_zoom_changed") + settings_menu.connect("settings_changed", self, "_on_SettingsMenu_settings_changed") + zoom_button.connect("pressed", self, "_on_ZoomButton_pressed") + zoom_slider.connect("value_changed", self, "_on_ZoomSlider_value_changed") + file_dialog.connect("file_selected", self, "_on_FileDialog_file_selected") + + +func clear_texture() -> void: + filename_label.text = "" + spritesheet_view.hide() + spritesheet_view.texture = null + + warning_message.text = MSG_IMPORT_JSON + search_file_button.hide() + + footer.hide() + + +func get_state() -> Dictionary: + var state := {} + + if spritesheet_view.texture: + state.texture = spritesheet_view.texture + state.zoom = spritesheet_view.zoom + state.offset = spritesheet_view.offset + + state.warning_msg = warning_message.text + state.search_file_button_visible =search_file_button.visible + state.settings = settings_menu.settings + + return state + + +func get_texture() -> Texture: + return spritesheet_view.texture + + +func load_texture(path : String) -> int: + if not path: + _show_find_file_prompt(MSG_MISSING_IMAGE_PARAMETER) + + return ERR_INVALID_DATA + + clear_texture() + + var split_path := path.rsplit("/", true, 1) + var dir_path := split_path[0] + var file_name := split_path[1] + + if file_name == "": + _show_find_file_prompt(MSG_MISSING_IMAGE_PARAMETER) + file_dialog.current_dir = dir_path + + return ERR_INVALID_DATA + + var file := File.new() + + if !file.file_exists(path): + _show_find_file_prompt(MSG_SPRITESHEET_NOT_FOUND % file_name) + file_dialog.current_dir = dir_path + + return ERR_FILE_NOT_FOUND + + var new_texture : Texture = load(path) + + if new_texture == null: + _show_find_file_prompt(MSG_LOAD_ERROR) + + return ERR_INVALID_DATA + + var new_texture_size := new_texture.get_size() + if new_texture_size != texture_size: + var message := MSG_INVALID_TEXTURE_SIZE % [new_texture.get_size(), texture_size] + _show_find_file_prompt(message) + + return ERR_INVALID_DATA + + spritesheet_view.texture = new_texture + spritesheet_view.frames = frames + spritesheet_view.selected_frames = [] + + filename_label.text = file_name + + _update_frames_count() + + spritesheet_view.show() + footer.show() + + return OK + + +func select_frames(selected_frames : Array) -> void: + spritesheet_view.selected_frames = selected_frames + + +func set_state(new_state : Dictionary) -> void: + if new_state.get("texture", false): + spritesheet_view.texture = new_state.texture + + spritesheet_view.zoom = new_state.zoom + spritesheet_view.offset = new_state.offset + + spritesheet_view.frames = frames + spritesheet_view.selected_frames = new_state.get("selected_frames", []) + + filename_label.text = new_state.texture.resource_path + + _update_frames_count() + + spritesheet_view.show() + footer.show() + else: + clear_texture() + + warning_message.text = new_state.get("warning_msg", MSG_IMPORT_JSON) + search_file_button.visible = new_state.get("search_file_button_visible", (warning_message.text != MSG_IMPORT_JSON)) + settings_menu.settings = new_state.get("settings", {}) + + +func _show_find_file_prompt(message : String) -> void: + clear_texture() + warning_message.text = message + search_file_button.show() + + +func _update_frames_count() -> void: + var frames_size := frames.size() + + if frames_size <= 0: + frame_count.text = "" + return + + frame_count.text = "%d frames" % frames_size + + var distinct_regions := [] + + for frame in frames: + var region : Dictionary = frame.frame + var rect := Rect2(region.x, region.y, region.w, region.h) + + if distinct_regions.find(rect) == -1: + distinct_regions.append(rect) + + var distinct_frames_size := distinct_regions.size() + + if frames_size > distinct_frames_size: + var merged_frames_count := frames_size - distinct_frames_size + + frame_count.text += " (%d merged)" % merged_frames_count + + +func _update_theme(editor_theme : EditorTheme) -> void: + settings_button.icon = editor_theme.get_icon("Tools") + search_file_button.icon = editor_theme.get_icon("Load") + zoom_button.icon = editor_theme.get_icon("Zoom") + + +# Setters and Getters +func set_texture_size(value : Vector2) -> void: + texture_size = value + + +# Signal Callbacks +func _on_FileDialog_file_selected(path) -> void: + load_texture(path) + + +func _on_SearchFileButton_pressed() -> void: + file_dialog.invalidate() + file_dialog.popup_centered_ratio(.5) + + +func _on_SettingsButton_toggled(button_pressed : bool) -> void: + settings_menu.visible = button_pressed + + +func _on_SettingsMenu_settings_changed(settings : Dictionary) -> void: + spritesheet_view.load_settings(settings) + + +func _on_SpritesheetInspector_zoom_changed(new_zoom : int) -> void: + _zoom_update = true + + zoom_button.text = "%d X" % new_zoom + zoom_slider.value = new_zoom + + _zoom_update = false + + +func _on_ZoomButton_pressed() -> void: + zoom_slider.value = 1 + + +func _on_ZoomSlider_value_changed(value : float) -> void: + if not _zoom_update: + spritesheet_view.zoom = round(value) diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.tscn b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.tscn new file mode 100644 index 0000000..fd89a39 --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.tscn @@ -0,0 +1,255 @@ +[gd_scene load_steps=14 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/ColorMenuItem.tscn" type="PackedScene" id=1] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.tscn" type="PackedScene" id=2] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/SettingsMenu.gd" type="Script" id=3] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetInspector.gd" type="Script" id=4] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_hover.png" type="Texture" id=5] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_normal.png" type="Texture" id=6] +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_pressed.png" type="Texture" id=7] + +[sub_resource type="Image" id=7] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 224, 224, 224, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 224, 224, 224, 255, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 112, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 112, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 189, 224, 224, 224, 255, 223, 223, 223, 189, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 122, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 223, 223, 223, 122, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 190, 224, 224, 224, 255, 222, 222, 222, 190, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 212, 224, 224, 224, 255, 223, 223, 223, 0, 223, 223, 223, 0, 224, 224, 224, 255, 223, 223, 223, 211, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 61, 224, 224, 224, 255, 221, 221, 221, 61, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 212, 224, 224, 224, 255, 222, 222, 222, 70, 222, 222, 222, 70, 224, 224, 224, 255, 223, 223, 223, 212, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 224, 224, 224, 255, 222, 222, 222, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 122, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 122, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 114, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 113, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 247, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 247, 222, 222, 222, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 185, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 185, 223, 223, 223, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 30, 222, 222, 222, 181, 223, 223, 223, 254, 222, 222, 222, 181, 221, 221, 221, 30, 221, 221, 221, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 180, 223, 223, 223, 180, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 222, 222, 222, 0, 223, 223, 223, 0, 222, 222, 222, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=2] +flags = 0 +flags = 0 +image = SubResource( 7 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=8] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 201, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 199, 222, 222, 222, 70, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 70, 222, 222, 222, 199, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 180, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 222, 222, 222, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 217, 217, 217, 0, 222, 222, 222, 173, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 173, 222, 222, 222, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 212, 212, 212, 0, 212, 212, 212, 18, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 232, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 221, 221, 221, 0, 221, 221, 221, 60, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 188, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 222, 222, 222, 0, 222, 222, 222, 103, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 147, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 223, 223, 223, 0, 223, 223, 223, 145, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 104, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 223, 223, 223, 0, 223, 223, 223, 187, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 62, 222, 222, 222, 0, 224, 224, 224, 0, 224, 224, 224, 255, 223, 223, 223, 0, 222, 222, 222, 0, 223, 223, 223, 230, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 214, 214, 214, 19, 214, 214, 214, 0, 223, 223, 223, 0, 223, 223, 223, 200, 222, 222, 222, 70, 221, 221, 221, 75, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 193, 218, 218, 218, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 202, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 198, 220, 220, 220, 51, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 222, 222, 222, 0, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=4] +flags = 0 +flags = 0 +image = SubResource( 8 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=9] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 57, 223, 223, 223, 177, 223, 223, 223, 228, 223, 223, 223, 234, 223, 223, 223, 185, 221, 221, 221, 61, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 118, 223, 223, 223, 253, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 56, 223, 223, 223, 251, 222, 222, 222, 247, 222, 222, 222, 116, 223, 223, 223, 24, 220, 220, 220, 22, 223, 223, 223, 115, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 222, 222, 222, 0, 222, 222, 222, 174, 223, 223, 223, 254, 222, 222, 222, 116, 222, 222, 222, 0, 223, 223, 223, 0, 220, 220, 220, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 224, 223, 223, 223, 254, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 229, 223, 223, 223, 254, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 223, 223, 223, 254, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 179, 223, 223, 223, 254, 223, 223, 223, 115, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 222, 222, 222, 116, 223, 223, 223, 254, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 57, 223, 223, 223, 252, 223, 223, 223, 246, 222, 222, 222, 116, 223, 223, 223, 24, 223, 223, 223, 24, 222, 222, 222, 116, 223, 223, 223, 246, 223, 223, 223, 254, 222, 222, 222, 86, 218, 218, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 118, 223, 223, 223, 253, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 219, 219, 219, 58, 223, 223, 223, 177, 223, 223, 223, 228, 223, 223, 223, 237, 222, 222, 222, 183, 223, 223, 223, 80, 223, 223, 223, 209, 223, 223, 223, 254, 223, 223, 223, 208, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 219, 219, 219, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 220, 220, 220, 0, 218, 218, 218, 21, 223, 223, 223, 209, 223, 223, 223, 254, 222, 222, 222, 207, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 21, 223, 223, 223, 210, 223, 223, 223, 254, 222, 222, 222, 206, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 21, 223, 223, 223, 211, 223, 223, 223, 228, 219, 219, 219, 36, 219, 219, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 21, 218, 218, 218, 35, 218, 218, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=6] +flags = 0 +flags = 0 +image = SubResource( 9 ) +size = Vector2( 16, 16 ) + +[node name="SpritesheetInspector" type="VBoxContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +script = ExtResource( 4 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Header" type="HBoxContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 24.0 + +[node name="Filename" type="Label" parent="Header"] +margin_top = 5.0 +margin_bottom = 19.0 + +[node name="Buttons" type="HBoxContainer" parent="Header"] +margin_left = 942.0 +margin_right = 1024.0 +margin_bottom = 24.0 +size_flags_horizontal = 10 + +[node name="SettingsButton" type="ToolButton" parent="Header/Buttons"] +margin_right = 82.0 +margin_bottom = 24.0 +hint_tooltip = "Spritesheet Inspector's settings" +toggle_mode = true +text = "Settings" +icon = SubResource( 2 ) + +[node name="Body" type="HBoxContainer" parent="."] +margin_top = 28.0 +margin_right = 1024.0 +margin_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="MainView" type="MarginContainer" parent="Body"] +margin_right = 1024.0 +margin_bottom = 572.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="WarningView" type="VBoxContainer" parent="Body/MainView"] +margin_left = 415.0 +margin_top = 230.0 +margin_right = 608.0 +margin_bottom = 341.0 +size_flags_horizontal = 6 +size_flags_vertical = 6 +custom_constants/separation = 16 + +[node name="GodotButton" type="TextureButton" parent="Body/MainView/WarningView"] +margin_left = 64.0 +margin_right = 128.0 +margin_bottom = 64.0 +rect_min_size = Vector2( 64, 64 ) +hint_tooltip = "Hello!" +focus_mode = 0 +mouse_default_cursor_shape = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +shortcut_in_tooltip = false +enabled_focus_mode = 0 +texture_normal = ExtResource( 6 ) +texture_pressed = ExtResource( 7 ) +texture_hover = ExtResource( 5 ) +expand = true + +[node name="WarningMessage" type="Label" parent="Body/MainView/WarningView"] +margin_top = 80.0 +margin_right = 193.0 +margin_bottom = 111.0 +size_flags_horizontal = 4 +size_flags_vertical = 0 +text = "Import a Aseprite JSON file to +preview the spritesheet" +align = 1 +valign = 1 + +[node name="SearchFileButton" type="Button" parent="Body/MainView/WarningView"] +visible = false +margin_left = 47.0 +margin_top = 127.0 +margin_right = 146.0 +margin_bottom = 149.0 +hint_tooltip = "Search for the spritesheet file" +size_flags_horizontal = 4 +size_flags_vertical = 0 +text = "Search File" +icon = SubResource( 4 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="SpritesheetView" parent="Body/MainView" instance=ExtResource( 2 )] +visible = false +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 1024.0 +margin_bottom = 572.0 + +[node name="SettingsMenu" type="ScrollContainer" parent="Body"] +visible = false +margin_left = 882.0 +margin_right = 1024.0 +margin_bottom = 572.0 +size_flags_horizontal = 8 +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +script = ExtResource( 3 ) + +[node name="Options" type="VBoxContainer" parent="Body/SettingsMenu"] +margin_right = 142.0 +margin_bottom = 196.0 + +[node name="FrameBorder" parent="Body/SettingsMenu/Options" instance=ExtResource( 1 )] +margin_right = 142.0 +label_text = "Frame Border" +visibility = true +show_visibility_button = true +color_value = Color( 0.501961, 0.501961, 0.501961, 1 ) +color_edit_alpha = false +color_picker_tooltip = "Change the border color of unselected frames" + +[node name="SelectionBorder" parent="Body/SettingsMenu/Options" instance=ExtResource( 1 )] +margin_top = 50.0 +margin_right = 142.0 +margin_bottom = 96.0 +label_text = "Selection Border" +visibility = true +show_visibility_button = true +color_value = Color( 1, 1, 0, 1 ) +color_edit_alpha = false +color_picker_tooltip = "Change the border color of selected frames" + +[node name="TextureBackground" parent="Body/SettingsMenu/Options" instance=ExtResource( 1 )] +margin_top = 100.0 +margin_right = 142.0 +margin_bottom = 146.0 +label_text = "Texture Background" +visibility = true +show_visibility_button = true +color_value = Color( 0.25098, 0.25098, 0.25098, 1 ) +color_edit_alpha = false +color_picker_tooltip = "Change the background color of the spritesheet's transparent area " + +[node name="InspectorBackground" parent="Body/SettingsMenu/Options" instance=ExtResource( 1 )] +margin_top = 150.0 +margin_right = 142.0 +margin_bottom = 196.0 +label_text = "Inspector Background" +visibility = false +show_visibility_button = false +color_value = Color( 0, 0, 0, 1 ) +color_edit_alpha = false +color_picker_tooltip = "Change the background color of the inspector" + +[node name="Footer" type="HBoxContainer" parent="."] +visible = false +margin_top = 218.0 +margin_right = 400.0 +margin_bottom = 240.0 + +[node name="FrameCount" type="Label" parent="Footer"] +margin_top = 4.0 +margin_bottom = 18.0 + +[node name="ZoomButton" type="ToolButton" parent="Footer"] +margin_left = 273.0 +margin_right = 300.0 +margin_bottom = 22.0 +size_flags_horizontal = 10 +text = "1 X" +icon = SubResource( 6 ) + +[node name="ZoomSlider" type="HSlider" parent="Footer"] +margin_left = 304.0 +margin_top = 3.0 +margin_right = 400.0 +margin_bottom = 19.0 +rect_min_size = Vector2( 96, 0 ) +size_flags_horizontal = 8 +size_flags_vertical = 6 +min_value = 1.0 +max_value = 8.0 +value = 1.0 + +[node name="FileDialog" type="FileDialog" parent="."] +margin_left = 186.0 +margin_right = 402.0 +margin_bottom = 240.0 +window_title = "Select the Spritesheet" +resizable = true +mode_overrides_title = false +mode = 0 +filters = PoolStringArray( "*.png ; PNG Files" ) +show_hidden_files = true diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.gd b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.gd new file mode 100644 index 0000000..107c4bb --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.gd @@ -0,0 +1,315 @@ +tool +extends Container + + +onready var h_scroll_bar : HScrollBar = $HScrollBar +onready var v_scroll_bar : VScrollBar = $VScrollBar + + +export(Texture) var texture : Texture setget set_texture +export(int, 1, 8) var zoom := 1 setget set_zoom +export(Vector2) var offset := Vector2.ZERO setget set_offset +export(bool)var zoom_to_fit := true + + +var frames = [] +var selected_frames := [] setget set_selected_frames + +var frame_border_color := Color.red +var frame_border_visibility := true + +var selection_border_color := Color.yellow +var selection_border_visibility := true + +var border_width := 2 + +var texture_background_color := Color.green +var texture_background_visibility := true + +var background_color := Color.blue + +var _full_rect := Rect2(Vector2.ZERO, rect_size) +var _render_rect : Rect2 +var _texture_size : Vector2 +var _min_offset : Vector2 +var _max_offset : Vector2 +var _zoom_pivot : Vector2 + +var _updating_scroll_bars := false +var _panning := false + + +signal zoom_changed(new_zoom) + + +func _ready() -> void: + h_scroll_bar.value = .5 + v_scroll_bar.value = .5 + + connect("resized", self, "_on_resized") + h_scroll_bar.connect("value_changed", self, "_on_HScrollBar_value_changed") + v_scroll_bar.connect("value_changed", self, "_on_VScrollBar_value_changed") + + update() + + +func _draw() -> void: + draw_rect(_full_rect, background_color) + + if not texture: + return + + if texture_background_visibility: + draw_rect(_render_rect, texture_background_color) + + draw_texture_rect(texture, _render_rect, false) + + if frame_border_visibility: + for frame_idx in range(frames.size()): + if (not selection_border_visibility) or (not frame_idx in selected_frames): + _draw_frame_border(frame_idx) + + if selection_border_visibility: + for frame_idx in selected_frames: + _draw_frame_border(frame_idx, true) + + +func _draw_frame_border(frame_idx : int, selected := false) -> void: + var sprite_region = frames[frame_idx].frame + + var frame_rect := _render_rect + frame_rect.position += Vector2(sprite_region.x, sprite_region.y) * zoom + frame_rect.size = Vector2(sprite_region.w, sprite_region.h) * zoom + + var border_color + + if frame_idx in selected_frames: + border_color = selection_border_color + else: + border_color = frame_border_color + + draw_rect(frame_rect, border_color, false, border_width) + + +func _gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + match event.button_index: + BUTTON_MIDDLE: + _panning = event.pressed + + if _panning: + mouse_default_cursor_shape = CURSOR_DRAG + else: + mouse_default_cursor_shape = CURSOR_ARROW + BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN: + if event.pressed: + _zoom_pivot = get_local_mouse_position() + + if event.button_index == BUTTON_WHEEL_UP: + self.zoom += 1 + else: + self.zoom -= 1 + + _zoom_pivot = _full_rect.size / 2 + elif event is InputEventMouseMotion: + if _panning: + self.offset += event.relative + + +func load_settings(settings : Dictionary) -> void: + frame_border_color = settings.frame_border.color + frame_border_visibility = settings.frame_border.visibility + + selection_border_color = settings.selection_border.color + selection_border_visibility = settings.selection_border.visibility + + texture_background_color = settings.texture_background.color + texture_background_visibility = settings.texture_background.visibility + + background_color = settings.inspector_background.color + + update() + + +func _update_offset_limits() -> void: + var full_rect_width := _full_rect.size.x + var render_rect_width := _render_rect.size.x + + if render_rect_width <= full_rect_width: + _min_offset.x = 0 + _max_offset.x = full_rect_width - render_rect_width + else: + _min_offset.x = -(render_rect_width - full_rect_width) + _max_offset.x = 0 + + var full_rect_height := _full_rect.size.y + var render_rect_height := _render_rect.size.y + + if render_rect_height <= full_rect_height: + _min_offset.y = 0 + _max_offset.y = full_rect_height - render_rect_height + else: + _min_offset.y = -(render_rect_height - full_rect_height) + _max_offset.y = 0 + + +func _update_scrollbars() ->void: + _updating_scroll_bars = true + + if h_scroll_bar: + var full_width:= _full_rect.size.x + var render_width:= _render_rect.size.x + + if render_width > full_width: + var h_page := full_width / render_width + + h_scroll_bar.page = h_page + h_scroll_bar.max_value = 1 + h_page + + var value := inverse_lerp(_max_offset.x, _min_offset.x, offset.x) + h_scroll_bar.value = value + + h_scroll_bar.show() + else: + h_scroll_bar.hide() + + if v_scroll_bar: + var full_height:= _full_rect.size.y + var render_height:= _render_rect.size.y + + if render_height > full_height: + var v_page := full_height / render_height + + v_scroll_bar.page = v_page + v_scroll_bar.max_value = 1 + v_page + + var value := inverse_lerp(_max_offset.y, _min_offset.y, offset.y) + v_scroll_bar.value = value + + v_scroll_bar.show() + else: + v_scroll_bar.hide() + + _updating_scroll_bars = false + + +# Setters and Getters +func set_offset(new_offset : Vector2) -> void: + new_offset.x = clamp(new_offset.x, _min_offset.x, _max_offset.x) + new_offset.y = clamp(new_offset.y, _min_offset.y, _max_offset.y) + + if new_offset == offset: + return + + offset = new_offset + + _render_rect.position = offset + + if not _updating_scroll_bars: + _update_scrollbars() + + update() + + +func set_selected_frames(selection : Array) -> void: + selected_frames = selection + + update() + + +func set_texture(new_texture) -> void: + texture = new_texture + + if texture == null: + return + + _texture_size = texture.get_size() + var full_rect_size := _full_rect.size + + if zoom_to_fit: + var ratio : Vector2 + + ratio.x = floor(full_rect_size.x / _texture_size.x) + ratio.y = floor(full_rect_size.y / _texture_size.y) + + self.zoom = min(ratio.x, ratio.y) + else: + self.zoom = 1 + + _update_offset_limits() + + self.offset = (_max_offset - _min_offset) / 2 + + +func set_zoom(new_zoom : int) -> void: + zoom = clamp(new_zoom, 1, 8) + + var new_render_rect_size := _texture_size * zoom + var relative_pivot := _zoom_pivot - offset + + var pivot_weight : Vector2 + + if _render_rect.size.x and _render_rect.size.y: + pivot_weight.x = relative_pivot.x / _render_rect.size.x + pivot_weight.y = relative_pivot.y / _render_rect.size.y + + var render_rect_size_diff := new_render_rect_size - _render_rect.size + var offset_diff := render_rect_size_diff * pivot_weight + + _render_rect.size = new_render_rect_size + + _update_offset_limits() + + _update_scrollbars() + + self.offset = offset - offset_diff + + emit_signal("zoom_changed", zoom) + + +# Signal Callbacks +func _on_resized() -> void: + _full_rect.size = rect_size + + _zoom_pivot = _full_rect.size / 2 + + _update_offset_limits() + + _update_scrollbars() + + self.offset = offset + + var rect := Rect2() + + rect.position.x = 0 + rect.position.y = (rect_size.y - h_scroll_bar.rect_size.y) + rect.size.x = (rect_size.x - v_scroll_bar.rect_size.x) + rect.size.y = h_scroll_bar.rect_size.y + + fit_child_in_rect(h_scroll_bar, rect) + + rect.position.x = (rect_size.x - v_scroll_bar.rect_size.x) + rect.position.y = 0 + rect.size.x = v_scroll_bar.rect_size.x + rect.size.y = (rect_size.y - h_scroll_bar.rect_size.y) + + fit_child_in_rect(v_scroll_bar, rect) + + + +func _on_HScrollBar_value_changed(value : float) -> void: + if _updating_scroll_bars: + return + + _updating_scroll_bars = true + self.offset.x = lerp(_max_offset.x, _min_offset.x, value) + _updating_scroll_bars = false + + +func _on_VScrollBar_value_changed(value : float) -> void: + if _updating_scroll_bars: + return + + _updating_scroll_bars = true + self.offset.y = lerp(_max_offset.y, _min_offset.y, value) + _updating_scroll_bars = false diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.tscn b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.tscn new file mode 100644 index 0000000..104e45f --- /dev/null +++ b/addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.tscn @@ -0,0 +1,48 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://addons/aseprite_importer/interface/spritesheet_inspector/SpritesheetView.gd" type="Script" id=2] + +[sub_resource type="StyleBoxFlat" id=1] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="Theme" id=2] +PanelContainer/styles/panel = SubResource( 1 ) + +[node name="SpritesheetView" type="Container"] +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_clip_content = true +theme = SubResource( 2 ) +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VScrollBar" type="VScrollBar" parent="."] +visible = false +margin_left = 1012.0 +margin_right = 1024.0 +margin_bottom = 588.0 +grow_horizontal = 0 +size_flags_horizontal = 8 +max_value = 1.0 +value = 0.5 + +[node name="HScrollBar" type="HScrollBar" parent="."] +visible = false +margin_top = 588.0 +margin_right = 1012.0 +margin_bottom = 600.0 +grow_vertical = 0 +size_flags_vertical = 8 +max_value = 1.0 +value = 0.5 diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_hover.png b/addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..5a617906fbee11a0d6d75d22cc6b4b8f40919b78 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~l>na*S9ON} zBK%VJb`Gw+2aIBS{{R2~Vd`0TcXw@V?FSDYtX{o3bIyxzSL0%V>Um0n{DK*PDqw)~ zNPrqpJi^n(F+^f&Zhtu60Rs+a!`J`Z^&~=;KCZQRV9?^hn2_2qvr*}H?&*+Q%zq^E z1TPlapPLtu>uhTAEj#7emvDz>;jm??%Yv?1Z1;M<_oE?S1#g_?`Dm@33>FiaGGmuA RtOwe`;OXk;vd$@?2>`2aSJVIi literal 0 HcmV?d00001 diff --git a/addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_normal.png b/addons/aseprite_importer/interface/spritesheet_inspector/godot_button/godot_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..f1e6c3890ef1f30d15f157bb032363c2a88c86ce GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~l>na*S9ON} zBK%VJb`Gw+2aIBS{{R2~Vd`0TcXw@V?FSDYtX{o3bIyxzSL0%V>Um0n{DK*PDqw)~ zNPrqpJjm0na*S9ON} zBK%VJb`Gw+2aIBS{{R2~Vd`0TcXw@V?FSDYtX{o3bIyxzSL0%V>Um0n{DK*PDqw)~ zNPrqp+|AR)F+^f&X}>2Qg8~ne>f8VKbHsCEwAgioogPW3F>Dd>(q5&dJG-uZQAp<- yR`riJ*$S@B-=~-)-pl(@;+y2&1AZ6&lrdS=F%^HhB%K5_k-^i|&t;ucLK6V4-A!l! literal 0 HcmV?d00001 diff --git a/addons/aseprite_importer/plugin.cfg b/addons/aseprite_importer/plugin.cfg new file mode 100644 index 0000000..51f771d --- /dev/null +++ b/addons/aseprite_importer/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Aseprite Importer" +description="Use the JSON data generated by Aseprite to import animations" +author="hectorid" +version="1.0.1" +script="plugin.gd" diff --git a/addons/aseprite_importer/plugin.gd b/addons/aseprite_importer/plugin.gd new file mode 100644 index 0000000..c3e60a4 --- /dev/null +++ b/addons/aseprite_importer/plugin.gd @@ -0,0 +1,101 @@ +tool +extends EditorPlugin + + +const INTERFACE_SCN = preload("interface/Main.tscn") + +const DARK_ICON = preload("interface/icons/dark_icon.png") +const LIGHT_ICON = preload("interface/icons/light_icon.png") + +var interface : Control + +var editor_interface := get_editor_interface() +var editor_base_control := editor_interface.get_base_control() +var editor_settings := editor_interface.get_editor_settings() +var editor_viewport := editor_interface.get_editor_viewport() + + +var _state_set := false + + +func _enter_tree() -> void: + interface = INTERFACE_SCN.instance() + + interface.connect("ready", self, "_on_interface_ready", [], CONNECT_ONESHOT) + + editor_viewport.add_child(interface) + make_visible(false) + + connect("scene_changed", self, "_on_scene_changed") + editor_settings.connect("settings_changed", self, "_on_settings_changed") + interface.connect("animations_generated", self, "_on_animations_generated") + + +func _exit_tree() -> void: + if interface: + interface.queue_free() + + +func has_main_screen(): + return true + + +func make_visible(visible: bool) -> void: + if interface: + if visible: + interface.show() + else: + interface.hide() + + +func get_plugin_name(): + return "Aseprite Importer" + + +func get_plugin_icon(): + var editor_theme := editor_base_control.theme + + if editor_theme.get_constant("dark_theme", "Editor"): + return LIGHT_ICON; + + return DARK_ICON; + + +func get_state() -> Dictionary: + return interface.get_state() + + +func set_state(state: Dictionary) -> void: + interface.set_state(state) + + _state_set = true + + +func _update_theme() -> void: + var editor_theme := EditorTheme.new(editor_base_control.theme) + interface.propagate_call("_update_theme", [editor_theme]) + + +# Signal Callbacks +func _on_animations_generated(animation_player : AnimationPlayer) -> void: + var editor_selection := get_editor_interface().get_selection() + + editor_selection.clear() + # Reselect the AnimationPlayer node to show the new animations + editor_selection.add_node(animation_player) + + +func _on_interface_ready() -> void: + _update_theme() + + +func _on_scene_changed(scene_root : Node) -> void: + if _state_set == false: + interface.set_state({}) + _state_set = false + + +func _on_settings_changed() -> void: + yield(editor_base_control, "draw") + + _update_theme() diff --git a/project.godot b/project.godot index 989bd47..0b69758 100644 --- a/project.godot +++ b/project.godot @@ -14,14 +14,32 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Script/Actor.gd" }, { +"base": "Node", +"class": "AsepriteImportData", +"language": "GDScript", +"path": "res://addons/aseprite_importer/classes/AsepriteImportData.gd" +}, { +"base": "Node", +"class": "AsepriteImporter", +"language": "GDScript", +"path": "res://addons/aseprite_importer/classes/AsepriteImporter.gd" +}, { "base": "Actor", "class": "Box", "language": "GDScript", "path": "res://Script/Box.gd" +}, { +"base": "Node", +"class": "EditorTheme", +"language": "GDScript", +"path": "res://addons/aseprite_importer/classes/EditorTheme.gd" } ] _global_script_class_icons={ "Actor": "", -"Box": "" +"AsepriteImportData": "", +"AsepriteImporter": "", +"Box": "", +"EditorTheme": "" } [application] @@ -45,6 +63,10 @@ window/dpi/allow_hidpi=true window/stretch/mode="2d" window/stretch/aspect="keep" +[editor_plugins] + +enabled=PoolStringArray( "aseprite_importer" ) + [importer_defaults] texture={