diff --git a/CHANGELOG.md b/CHANGELOG.md index c594ef255..8d634eee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,13 @@ Igor Santarek (jegor377), rob-a-bolton - Drawing is no longer limited by the canvas boundaries. This means that, if you have a brush largen than 1px, you can draw on the edges of the canvas. All pixels that are being drawn outside of the canvas will still have no effect. - Language and theme checkboxes are now radio buttons. - The Blue theme has more similar margins and seperations with the rest of the themes. +- The guides are now the same for all frames. ### Fixed - Fixed failed imports of gpl palettes by adding support for the newer variant of gpl files. ([#250](https://github.com/Orama-Interactive/Pixelorama/pull/250)) - Fixed alpha blending and lighting/darkening issues when drawing pixels with mirroring. - Fixed issue where if you moved a frame to the start (move left), it was invisible. +- Fixed a rare issue with Undo/Redo not working while motion drawing and making lines.

## [v0.7] - 2020-05-16 diff --git a/project.godot b/project.godot index 97cebc2f2..261ed9fed 100644 --- a/project.godot +++ b/project.godot @@ -24,6 +24,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Classes/Cel.gd" }, { +"base": "Reference", +"class": "Frame", +"language": "GDScript", +"path": "res://src/Classes/Frame.gd" +}, { "base": "Line2D", "class": "Guide", "language": "GDScript", @@ -53,6 +58,7 @@ _global_script_class_icons={ "AnimationTag": "", "Canvas": "", "Cel": "", +"Frame": "", "Guide": "", "Layer": "", "LayerButton": "", @@ -71,7 +77,7 @@ boot_splash/bg_color=Color( 0.145098, 0.145098, 0.164706, 1 ) config/icon="res://assets/graphics/icons/icon.png" config/macos_native_icon="res://assets/graphics/icons/icon.icns" config/windows_native_icon="res://assets/graphics/icons/icon.ico" -config/Version="v0.7" +config/Version="v0.7.1" [autoload] diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index afac91742..126dff08c 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -35,7 +35,7 @@ var undos := 0 # The number of times we added undo properties var project_has_changed := false # Checks if the user has made changes to the project # Canvas related stuff -var canvases := [] setget canvases_changed +var frames := [] setget frames_changed var layers := [] setget layers_changed var layers_changed_skip := false var current_frame := 0 setget frame_changed @@ -57,7 +57,6 @@ var animation_tags := [] setget animation_tags_changed var play_only_tags := true var theme_type : int = Theme_Types.DARK -var is_default_image := true var default_image_width := 64 var default_image_height := 64 var default_fill_color := Color(0, 0, 0, 0) @@ -136,7 +135,6 @@ var top_menu_container : Panel var left_cursor : Sprite var right_cursor : Sprite var canvas : Canvas -var canvas_parent : Node var main_viewport : ViewportContainer var second_viewport : ViewportContainer var camera : Camera2D @@ -225,7 +223,6 @@ var edit_palette_popup : WindowDialog var new_palette_dialog : ConfirmationDialog var new_palette_name_line_edit : LineEdit var palette_import_file_dialog : FileDialog - var error_dialog : AcceptDialog onready var current_version : String = ProjectSettings.get_setting("application/config/Version") @@ -251,15 +248,13 @@ func _ready() -> void: left_cursor = find_node_by_name(root, "LeftCursor") right_cursor = find_node_by_name(root, "RightCursor") canvas = find_node_by_name(root, "Canvas") - canvases.append(canvas) left_cursor_tool_texture = ImageTexture.new() left_cursor_tool_texture.create_from_image(preload("res://assets/graphics/cursor_icons/pencil_cursor.png")) right_cursor_tool_texture = ImageTexture.new() right_cursor_tool_texture.create_from_image(preload("res://assets/graphics/cursor_icons/eraser_cursor.png")) - canvas_parent = canvas.get_parent() main_viewport = find_node_by_name(root, "ViewportContainer") second_viewport = find_node_by_name(root, "ViewportContainer2") - camera = find_node_by_name(canvas_parent, "Camera2D") + camera = find_node_by_name(main_viewport, "Camera2D") camera2 = find_node_by_name(root, "Camera2D2") camera_preview = find_node_by_name(root, "CameraPreview") selection_rectangle = find_node_by_name(root, "SelectionRectangle") @@ -404,33 +399,26 @@ func general_redo() -> void: notification_label("Redo: %s" % action_name) -func undo(_canvases : Array, layer_index : int = -1) -> void: +func undo(_frame_index := -1, _layer_index := -1) -> void: general_undo() var action_name := undo_redo.get_current_action_name() if action_name == "Draw" or action_name == "Rectangle Select" or action_name == "Scale" or action_name == "Merge Layer" or action_name == "Link Cel" or action_name == "Unlink Cel": - for c in _canvases: - if layer_index > -1: - c.update_texture(layer_index) - else: - for i in c.layers.size(): - c.update_texture(i) + if _layer_index > -1 and _frame_index > -1: + canvas.update_texture(_layer_index, _frame_index) + else: + for i in frames.size(): + for j in layers.size(): + canvas.update_texture(j, i) - if action_name == "Scale": - c.camera_zoom() + if action_name == "Scale": + canvas.camera_zoom() - if action_name == "Add Frame": - canvas_parent.remove_child(_canvases[0]) - # This actually means that canvases.size is one, but it hasn't been updated yet - if canvases.size() == 2: # Stop animating + elif "Frame" in action_name: + # This actually means that frames.size is one, but it hasn't been updated yet + if frames.size() == 2: # Stop animating play_forward.pressed = false play_backwards.pressed = false animation_timer.stop() - elif action_name == "Remove Frame": - canvas_parent.add_child(_canvases[0]) - canvas_parent.move_child(_canvases[0], _canvases[0].frame) - elif action_name == "Change Frame Order": - canvas_parent.move_child(_canvases[0], _canvases[0].frame) - canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0) canvas.update() if !project_has_changed: @@ -438,31 +426,25 @@ func undo(_canvases : Array, layer_index : int = -1) -> void: self.window_title = window_title + "(*)" -func redo(_canvases : Array, layer_index : int = -1) -> void: +func redo(_frame_index := -1, _layer_index := -1) -> void: general_redo() var action_name := undo_redo.get_current_action_name() if action_name == "Draw" or action_name == "Rectangle Select" or action_name == "Scale" or action_name == "Merge Layer" or action_name == "Link Cel" or action_name == "Unlink Cel": - for c in _canvases: - if layer_index > -1: - c.update_texture(layer_index) - else: - for i in c.layers.size(): - c.update_texture(i) + if _layer_index > -1 and _frame_index > -1: + canvas.update_texture(_layer_index, _frame_index) + else: + for i in frames.size(): + for j in layers.size(): + canvas.update_texture(j, i) - if action_name == "Scale": - c.camera_zoom() + if action_name == "Scale": + canvas.camera_zoom() - if action_name == "Add Frame": - canvas_parent.add_child(_canvases[0]) - elif action_name == "Remove Frame": - canvas_parent.remove_child(_canvases[0]) - if canvases.size() == 1: # Stop animating + elif "Frame" in action_name: + if frames.size() == 1: # Stop animating play_forward.pressed = false play_backwards.pressed = false animation_timer.stop() - elif action_name == "Change Frame Order": - canvas_parent.move_child(_canvases[0], _canvases[0].frame) - canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0) canvas.update() if !project_has_changed: @@ -475,8 +457,8 @@ func title_changed(value : String) -> void: OS.set_window_title(value) -func canvases_changed(value : Array) -> void: - canvases = value +func frames_changed(value : Array) -> void: + frames = value for container in frames_container.get_children(): for button in container.get_children(): container.remove_child(button) @@ -490,7 +472,7 @@ func canvases_changed(value : Array) -> void: for i in range(layers.size() - 1, -1, -1): frames_container.add_child(layers[i].frame_container) - for j in range(canvases.size()): + for j in range(frames.size()): var label := Label.new() label.rect_min_size.x = 36 label.align = Label.ALIGN_CENTER @@ -501,7 +483,7 @@ func canvases_changed(value : Array) -> void: var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance() cel_button.frame = j cel_button.layer = i - cel_button.get_child(0).texture = Global.canvases[j].layers[i].image_texture + cel_button.get_child(0).texture = frames[j].cels[i].image_texture layers[i].frame_container.add_child(cel_button) @@ -509,19 +491,16 @@ func canvases_changed(value : Array) -> void: # otherwise, this code is useless in this context, since these values are being set # when the play buttons get pressed, anyway animation_timeline.first_frame = 0 - animation_timeline.last_frame = canvases.size() - 1 + animation_timeline.last_frame = frames.size() - 1 if play_only_tags: for tag in animation_tags: if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to: animation_timeline.first_frame = tag.from - 1 - animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1) + animation_timeline.last_frame = min(frames.size() - 1, tag.to - 1) -func clear_canvases() -> void: - for child in canvas_parent.get_children(): - if child is Canvas: - child.queue_free() - canvases.clear() +func clear_frames() -> void: + frames.clear() animation_tags.clear() self.animation_tags = animation_tags # To execute animation_tags_changed() @@ -564,11 +543,11 @@ func layers_changed(value : Array) -> void: layer_container.line_edit.text = layers[i].name frames_container.add_child(layers[i].frame_container) - for j in range(canvases.size()): + for j in range(frames.size()): var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance() cel_button.frame = j cel_button.layer = i - cel_button.get_child(0).texture = Global.canvases[j].layers[i].image_texture + cel_button.get_child(0).texture = frames[j].cels[i].image_texture layers[i].frame_container.add_child(cel_button) @@ -590,13 +569,9 @@ func layers_changed(value : Array) -> void: func frame_changed(value : int) -> void: current_frame = value - current_frame_mark_label.text = "%s/%s" % [str(current_frame + 1), canvases.size()] + current_frame_mark_label.text = "%s/%s" % [str(current_frame + 1), frames.size()] - var i := 0 - for c in canvases: # De-select all the other canvases/frames - c.visible = false - c.is_making_line = false - c.line_2d.set_point_position(1, c.line_2d.points[0]) + for i in frames.size(): # De-select all the other frames var text_color := Color.white if theme_type == Theme_Types.CARAMEL || theme_type == Theme_Types.LIGHT: text_color = Color.black @@ -604,27 +579,26 @@ func frame_changed(value : int) -> void: for layer in layers: if i < layer.frame_container.get_child_count(): layer.frame_container.get_child(i).pressed = false - i += 1 - # Select the new canvas/frame - canvas = canvases[current_frame] - canvas.visible = true + # Select the new frame frame_ids.get_child(current_frame).add_color_override("font_color", control.theme.get_color("Selected Color", "Label")) if current_frame < layers[current_layer].frame_container.get_child_count(): layers[current_layer].frame_container.get_child(current_frame).pressed = true - if canvases.size() == 1: + if frames.size() == 1: disable_button(remove_frame_button, true) elif !layers[current_layer].locked: disable_button(remove_frame_button, false) + Global.canvas.update() Global.transparent_checker._ready() # To update the rect size func layer_changed(value : int) -> void: current_layer = value - layer_opacity_slider.value = canvas.layers[current_layer].opacity * 100 - layer_opacity_spinbox.value = canvas.layers[current_layer].opacity * 100 + if current_frame < frames.size(): + layer_opacity_slider.value = frames[current_frame].cels[current_layer].opacity * 100 + layer_opacity_spinbox.value = frames[current_frame].cels[current_layer].opacity * 100 for container in layers_container.get_children(): container.pressed = false @@ -719,12 +693,12 @@ func animation_tags_changed(value : Array) -> void: # otherwise, this code is useless in this context, since these values are being set # when the play buttons get pressed, anyway animation_timeline.first_frame = 0 - animation_timeline.last_frame = canvases.size() - 1 + animation_timeline.last_frame = frames.size() - 1 if play_only_tags: for tag in animation_tags: if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to: animation_timeline.first_frame = tag.from - 1 - animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1) + animation_timeline.last_frame = min(frames.size() - 1, tag.to - 1) func update_hint_tooltips() -> void: diff --git a/src/Autoload/OpenSave.gd b/src/Autoload/OpenSave.gd index 3ccb6a729..2ea173063 100644 --- a/src/Autoload/OpenSave.gd +++ b/src/Autoload/OpenSave.gd @@ -36,17 +36,22 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void: # and the status would return "beta" var file_major_version = int(file_ver_splitted_numbers[0].replace("v", "")) var file_minor_version = int(file_ver_splitted_numbers[1]) - var _file_patch_version := 0 + var file_patch_version := 0 var _file_status_version : String if file_ver_splitted_numbers.size() > 2: - _file_patch_version = int(file_ver_splitted_numbers[2]) + file_patch_version = int(file_ver_splitted_numbers[2]) if file_ver_splitted.size() > 1: _file_status_version = file_ver_splitted[1] if file_major_version == 0 and file_minor_version < 5: Global.notification_label("File is from an older version of Pixelorama, as such it might not work properly") + var new_guides := true + if file_major_version == 0: + if file_minor_version < 7 or (file_minor_version == 7 and file_patch_version == 0): + new_guides = false + var frame := 0 Global.layers.clear() @@ -65,10 +70,9 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void: global_layer_line = file.get_line() var frame_line := file.get_line() - Global.clear_canvases() + Global.clear_frames() while frame_line == "--": # Load frames - var canvas : Canvas = load("res://src/Canvas.tscn").instance() - Global.canvas = canvas + var frame_class := Frame.new() var width := file.get_16() var height := file.get_16() @@ -81,24 +85,49 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void: if frame == 0: var l := Layer.new(layer_name_old_version) Global.layers.append(l) - var layer_transparency := 1.0 + var cel_opacity := 1.0 if file_major_version >= 0 and file_minor_version > 5: - layer_transparency = file.get_float() + cel_opacity = file.get_float() var image := Image.new() image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer) image.lock() - canvas.layers.append(Cel.new(image, layer_transparency)) + frame_class.cels.append(Cel.new(image, cel_opacity)) if file_major_version >= 0 and file_minor_version >= 7: if frame in linked_cels[layer_i]: - Global.layers[layer_i].linked_cels.append(canvas) + Global.layers[layer_i].linked_cels.append(frame_class) layer_i += 1 layer_line = file.get_line() + if !new_guides: + var guide_line := file.get_line() # "guideline" no pun intended + while guide_line == "|": # Load guides + var guide := Guide.new() + guide.type = file.get_8() + if guide.type == guide.Types.HORIZONTAL: + guide.add_point(Vector2(-99999, file.get_16())) + guide.add_point(Vector2(99999, file.get_16())) + else: + guide.add_point(Vector2(file.get_16(), -99999)) + guide.add_point(Vector2(file.get_16(), 99999)) + guide.has_focus = false + Global.canvas.add_child(guide) + guide_line = file.get_line() + + Global.canvas.size = Vector2(width, height) + Global.frames.append(frame_class) + frame_line = file.get_line() + frame += 1 + + Global.frames = Global.frames # Just to call Global.frames_changed + Global.current_layer = Global.layers.size() - 1 + Global.current_frame = frame - 1 + Global.layers = Global.layers # Just to call Global.layers_changed + + if new_guides: var guide_line := file.get_line() # "guideline" no pun intended while guide_line == "|": # Load guides var guide := Guide.new() - guide.default_color = Color.purple guide.type = file.get_8() if guide.type == guide.Types.HORIZONTAL: guide.add_point(Vector2(-99999, file.get_16())) @@ -107,20 +136,9 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void: guide.add_point(Vector2(file.get_16(), -99999)) guide.add_point(Vector2(file.get_16(), 99999)) guide.has_focus = false - canvas.add_child(guide) + Global.canvas.add_child(guide) guide_line = file.get_line() - canvas.size = Vector2(width, height) - Global.canvases.append(canvas) - canvas.frame = frame - Global.canvas_parent.add_child(canvas) - frame_line = file.get_line() - frame += 1 - - Global.canvases = Global.canvases # Just to call Global.canvases_changed - Global.current_layer = Global.layers.size() - 1 - Global.current_frame = frame - 1 - Global.layers = Global.layers # Just to call Global.layers_changed # Load tool options Global.color_pickers[0].color = file.get_var() Global.color_pickers[1].color = file.get_var() @@ -163,6 +181,7 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void: tag_line = file.get_line() file.close() + Global.canvas.camera_zoom() if not untitled_backup: # Untitled backup should not change window title and save path @@ -186,37 +205,38 @@ func save_pxo_file(path : String, autosave : bool) -> void: file.store_8(layer.locked) file.store_8(layer.new_cels_linked) var linked_cels := [] - for canvas in layer.linked_cels: - linked_cels.append(canvas.frame) + for frame in layer.linked_cels: + linked_cels.append(Global.frames.find(frame)) file.store_var(linked_cels) # Linked cels as cel numbers file.store_line("END_GLOBAL_LAYERS") # Store frames - for canvas in Global.canvases: + for frame in Global.frames: file.store_line("--") - file.store_16(canvas.size.x) - file.store_16(canvas.size.y) - for layer in canvas.layers: # Store canvas layers + file.store_16(Global.canvas.size.x) + file.store_16(Global.canvas.size.y) + for cel in frame.cels: # Store canvas layers file.store_line("-") - file.store_buffer(layer.image.get_data()) - file.store_float(layer.opacity) + file.store_buffer(cel.image.get_data()) + file.store_float(cel.opacity) file.store_line("END_LAYERS") - # Store guides - for child in canvas.get_children(): - if child is Guide: - file.store_line("|") - file.store_8(child.type) - if child.type == child.Types.HORIZONTAL: - file.store_16(child.points[0].y) - file.store_16(child.points[1].y) - else: - file.store_16(child.points[1].x) - file.store_16(child.points[0].x) - file.store_line("END_GUIDES") file.store_line("END_FRAMES") + # Store guides + for child in Global.canvas.get_children(): + if child is Guide: + file.store_line("|") + file.store_8(child.type) + if child.type == child.Types.HORIZONTAL: + file.store_16(child.points[0].y) + file.store_16(child.points[1].y) + else: + file.store_16(child.points[1].x) + file.store_16(child.points[0].x) + file.store_line("END_GUIDES") + # Save tool options var left_color : Color = Global.color_pickers[0].color var right_color : Color = Global.color_pickers[1].color diff --git a/src/Canvas.gd b/src/Canvas.gd index 9f825d4dc..5e583be54 100644 --- a/src/Canvas.gd +++ b/src/Canvas.gd @@ -2,12 +2,9 @@ class_name Canvas extends Node2D -var layers := [] -var current_layer_index := 0 var location := Vector2.ZERO var size := Vector2(64, 64) var fill_color := Color(0, 0, 0, 0) -var frame := 0 var current_pixel := Vector2.ZERO # pretty much same as mouse_pos, but can be accessed externally var previous_mouse_pos := Vector2.ZERO var previous_mouse_pos_for_lines := Vector2.ZERO @@ -28,38 +25,9 @@ var pen_pressure := 1.0 # For tablet pressure sensitivity # Called when the node enters the scene tree for the first time. func _ready() -> void: - var fill_layers := layers.empty() - var layer_i := 0 - for l in Global.layers: - if fill_layers: - # The sprite itself - var sprite := Image.new() - if Global.is_default_image: - if Global.config_cache.has_section_key("preferences", "default_width"): - size.x = Global.config_cache.get_value("preferences", "default_width") - if Global.config_cache.has_section_key("preferences", "default_height"): - size.y = Global.config_cache.get_value("preferences", "default_height") - if Global.config_cache.has_section_key("preferences", "default_fill_color"): - fill_color = Global.config_cache.get_value("preferences", "default_fill_color") - Global.is_default_image = !Global.is_default_image - - sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8) - sprite.fill(fill_color) - sprite.lock() - - layers.append(Cel.new(sprite, 1.0)) - - if self in l.linked_cels: - # If the linked button is pressed, set as the Image & ImageTexture - # to be the same as the first linked cel - layers[layer_i].image = l.linked_cels[0].layers[layer_i].image - layers[layer_i].image_texture = l.linked_cels[0].layers[layer_i].image_texture - - layer_i += 1 - - # Only handle camera zoom settings & offset on the first frame - if Global.canvases[0] == self: - camera_zoom() + var frame : Frame = new_empty_frame(true) + Global.frames.append(frame) + camera_zoom() line_2d = Line2D.new() line_2d.width = 0.5 @@ -70,24 +38,25 @@ func _ready() -> void: func _draw() -> void: + var current_cels : Array = Global.frames[Global.current_frame].cels if Global.onion_skinning: onion_skinning() # Draw current frame layers - for i in range(layers.size()): - var modulate_color := Color(1, 1, 1, layers[i].opacity) + for i in range(Global.layers.size()): + var modulate_color := Color(1, 1, 1, current_cels[i].opacity) if Global.layers[i].visible: # if it's visible - draw_texture(layers[i].image_texture, location, modulate_color) + draw_texture(current_cels[i].image_texture, location, modulate_color) if Global.tile_mode: - draw_texture(layers[i].image_texture, Vector2(location.x, location.y + size.y), modulate_color) # Down - draw_texture(layers[i].image_texture, Vector2(location.x - size.x, location.y + size.y), modulate_color) # Down Left - draw_texture(layers[i].image_texture, Vector2(location.x - size.x, location.y), modulate_color) # Left - draw_texture(layers[i].image_texture, location - size, modulate_color) # Up left - draw_texture(layers[i].image_texture, Vector2(location.x, location.y - size.y), modulate_color) # Up - draw_texture(layers[i].image_texture, Vector2(location.x + size.x, location.y - size.y), modulate_color) # Up right - draw_texture(layers[i].image_texture, Vector2(location.x + size.x, location.y), modulate_color) # Right - draw_texture(layers[i].image_texture, location + size, modulate_color) # Down right + draw_texture(current_cels[i].image_texture, Vector2(location.x, location.y + size.y), modulate_color) # Down + draw_texture(current_cels[i].image_texture, Vector2(location.x - size.x, location.y + size.y), modulate_color) # Down Left + draw_texture(current_cels[i].image_texture, Vector2(location.x - size.x, location.y), modulate_color) # Left + draw_texture(current_cels[i].image_texture, location - size, modulate_color) # Up left + draw_texture(current_cels[i].image_texture, Vector2(location.x, location.y - size.y), modulate_color) # Up + draw_texture(current_cels[i].image_texture, Vector2(location.x + size.x, location.y - size.y), modulate_color) # Up right + draw_texture(current_cels[i].image_texture, Vector2(location.x + size.x, location.y), modulate_color) # Right + draw_texture(current_cels[i].image_texture, location + size, modulate_color) # Down right if Global.draw_grid: draw_grid(Global.grid_type) @@ -139,11 +108,6 @@ func _input(event : InputEvent) -> void: can_undo = true current_pixel = get_local_mouse_position() + location - if Global.current_frame != frame || Global.layers[Global.current_layer].locked: - previous_mouse_pos = current_pixel - previous_mouse_pos.x = clamp(previous_mouse_pos.x, location.x, location.x + size.x) - previous_mouse_pos.y = clamp(previous_mouse_pos.y, location.y, location.y + size.y) - return if Global.has_focus: update() @@ -290,8 +254,30 @@ func camera_zoom() -> void: Global.transparent_checker._ready() # To update the rect size +func new_empty_frame(first_time := false) -> Frame: + var frame := Frame.new() + for l in Global.layers: + # The sprite itself + var sprite := Image.new() + if first_time: + if Global.config_cache.has_section_key("preferences", "default_width"): + size.x = Global.config_cache.get_value("preferences", "default_width") + if Global.config_cache.has_section_key("preferences", "default_height"): + size.y = Global.config_cache.get_value("preferences", "default_height") + if Global.config_cache.has_section_key("preferences", "default_fill_color"): + fill_color = Global.config_cache.get_value("preferences", "default_fill_color") + + sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8) + sprite.fill(fill_color) + sprite.lock() + frame.cels.append(Cel.new(sprite, 1)) + + return frame + + func handle_tools(current_mouse_button : int, current_action : int, mouse_pos : Vector2, can_handle : bool) -> void: - var sprite : Image = layers[Global.current_layer].image + var current_cel : Cel = Global.frames[Global.current_frame].cels[Global.current_layer] + var sprite : Image = current_cel.image var mouse_pos_floored := mouse_pos.floor() var mouse_pos_ceiled := mouse_pos.ceil() @@ -428,27 +414,29 @@ func pencil_and_eraser(sprite : Image, mouse_pos : Vector2, color : Color, curre func handle_undo(action : String) -> void: if !can_undo: return - var canvases := [] + var frames := [] + var frame_index := -1 var layer_index := -1 if Global.animation_timer.is_stopped(): # if we're not animating, store only the current canvas - canvases = [self] + frames.append(Global.frames[Global.current_frame]) + frame_index = Global.current_frame layer_index = Global.current_layer - else: # If we're animating, store all canvases - canvases = Global.canvases + else: # If we're animating, store all frames + frames = Global.frames Global.undos += 1 Global.undo_redo.create_action(action) - for c in canvases: + for f in frames: # I'm not sure why I have to unlock it, but... # ...if I don't, it doesn't work properly - c.layers[Global.current_layer].image.unlock() - var data = c.layers[Global.current_layer].image.data - c.layers[Global.current_layer].image.lock() - Global.undo_redo.add_undo_property(c.layers[Global.current_layer].image, "data", data) + f.cels[Global.current_layer].image.unlock() + var data = f.cels[Global.current_layer].image.data + f.cels[Global.current_layer].image.lock() + Global.undo_redo.add_undo_property(f.cels[Global.current_layer].image, "data", data) if action == "Rectangle Select": var selected_pixels = Global.selected_pixels.duplicate() Global.undo_redo.add_undo_property(Global.selection_rectangle, "polygon", Global.selection_rectangle.polygon) Global.undo_redo.add_undo_property(Global, "selected_pixels", selected_pixels) - Global.undo_redo.add_undo_method(Global, "undo", canvases, layer_index) + Global.undo_redo.add_undo_method(Global, "undo", frame_index, layer_index) can_undo = false @@ -458,28 +446,33 @@ func handle_redo(action : String) -> void: if Global.undos < Global.undo_redo.get_version(): return - var canvases := [] + var frames := [] + var frame_index := -1 var layer_index := -1 if Global.animation_timer.is_stopped(): - canvases = [self] + frames.append(Global.frames[Global.current_frame]) + frame_index = Global.current_frame layer_index = Global.current_layer else: - canvases = Global.canvases - for c in canvases: - Global.undo_redo.add_do_property(c.layers[Global.current_layer].image, "data", c.layers[Global.current_layer].image.data) + frames = Global.frames + for f in frames: + Global.undo_redo.add_do_property(f.cels[Global.current_layer].image, "data", f.cels[Global.current_layer].image.data) if action == "Rectangle Select": Global.undo_redo.add_do_property(Global.selection_rectangle, "polygon", Global.selection_rectangle.polygon) Global.undo_redo.add_do_property(Global, "selected_pixels", Global.selected_pixels) - Global.undo_redo.add_do_method(Global, "redo", canvases, layer_index) + Global.undo_redo.add_do_method(Global, "redo", frame_index, layer_index) Global.undo_redo.commit_action() -func update_texture(layer_index : int) -> void: - layers[layer_index].image_texture.create_from_image(layers[layer_index].image, 0) +func update_texture(layer_index : int, frame_index := -1) -> void: + if frame_index == -1: + frame_index = Global.current_frame + var current_cel : Cel = Global.frames[frame_index].cels[layer_index] + current_cel.image_texture.create_from_image(current_cel.image, 0) var frame_texture_rect : TextureRect - frame_texture_rect = Global.find_node_by_name(Global.layers[layer_index].frame_container.get_child(frame), "CelTexture") - frame_texture_rect.texture = layers[layer_index].image_texture + frame_texture_rect = Global.find_node_by_name(Global.layers[layer_index].frame_container.get_child(frame_index), "CelTexture") + frame_texture_rect.texture = current_cel.image_texture func onion_skinning() -> void: @@ -493,7 +486,7 @@ func onion_skinning() -> void: for i in range(1, Global.onion_skinning_past_rate + 1): if Global.current_frame >= i: var layer_i := 0 - for layer in Global.canvases[Global.current_frame - i].layers: + for layer in Global.frames[Global.current_frame - i].cels: if Global.layers[layer_i].visible: color.a = 0.6 / i draw_texture(layer.image_texture, location, color) @@ -507,9 +500,9 @@ func onion_skinning() -> void: else: color = Color.white for i in range(1, Global.onion_skinning_future_rate + 1): - if Global.current_frame < Global.canvases.size() - i: + if Global.current_frame < Global.frames.size() - i: var layer_i := 0 - for layer in Global.canvases[Global.current_frame + i].layers: + for layer in Global.frames[Global.current_frame + i].cels: if Global.layers[layer_i].visible: color.a = 0.6 / i draw_texture(layer.image_texture, location, color) diff --git a/src/Classes/Frame.gd b/src/Classes/Frame.gd new file mode 100644 index 000000000..70e453fc6 --- /dev/null +++ b/src/Classes/Frame.gd @@ -0,0 +1,9 @@ +class_name Frame extends Reference +# A class for frame properties. +# A frame is a collection of cels, for each layer. + + +var cels : Array # An array of Cels + +func _init(_cels := []) -> void: + cels = _cels diff --git a/src/Main.gd b/src/Main.gd index ccb44c20a..4cda7c35c 100644 --- a/src/Main.gd +++ b/src/Main.gd @@ -364,10 +364,9 @@ func toggle_show_rulers() -> void: func toggle_show_guides() -> void: Global.show_guides = !Global.show_guides view_menu.set_item_checked(3, Global.show_guides) - for canvas in Global.canvases: - for guide in canvas.get_children(): - if guide is Guide: - guide.visible = Global.show_guides + for guide in Global.canvas.get_children(): + if guide is Guide: + guide.visible = Global.show_guides func toggle_show_anim_timeline() -> void: @@ -399,21 +398,21 @@ func show_scale_image_popup() -> void: func crop_image() -> void: # Use first cel as a starting rectangle - var used_rect : Rect2 = Global.canvases[0].layers[0].image.get_used_rect() + var used_rect : Rect2 = Global.frames[0].cels[0].image.get_used_rect() - for c in Global.canvases: + for f in Global.frames: # However, if first cel is empty, loop through all cels until we find one that isn't - for layer in c.layers: + for cel in f.cels: if used_rect != Rect2(0, 0, 0, 0): break else: - if layer[0].get_used_rect() != Rect2(0, 0, 0, 0): - used_rect = layer.image.get_used_rect() + if cel.image.get_used_rect() != Rect2(0, 0, 0, 0): + used_rect = cel.image.get_used_rect() # Merge all layers with content - for layer in c.layers: - if layer.image.get_used_rect() != Rect2(0, 0, 0, 0): - used_rect = used_rect.merge(layer.image.get_used_rect()) + for cel in f.cels: + if cel.image.get_used_rect() != Rect2(0, 0, 0, 0): + used_rect = used_rect.merge(cel.image.get_used_rect()) # If no layer has any content, just return if used_rect == Rect2(0, 0, 0, 0): @@ -423,17 +422,17 @@ func crop_image() -> void: var height := used_rect.size.y Global.undos += 1 Global.undo_redo.create_action("Scale") - for c in Global.canvases: - Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor()) + Global.undo_redo.add_do_property(Global.canvas, "size", Vector2(width, height).floor()) + for f in Global.frames: # Loop through all the layers to crop them - for j in range(Global.canvas.layers.size() - 1, -1, -1): - var sprite : Image = c.layers[j].image.get_rect(used_rect) - Global.undo_redo.add_do_property(c.layers[j].image, "data", sprite.data) - Global.undo_redo.add_undo_property(c.layers[j].image, "data", c.layers[j].image.data) + for j in range(Global.layers.size() - 1, -1, -1): + var sprite : Image = f.cels[j].image.get_rect(used_rect) + Global.undo_redo.add_do_property(f.cels[j].image, "data", sprite.data) + Global.undo_redo.add_undo_property(f.cels[j].image, "data", f.cels[j].image.data) - Global.undo_redo.add_undo_property(c, "size", c.size) - Global.undo_redo.add_undo_method(Global, "undo", Global.canvases) - Global.undo_redo.add_do_method(Global, "redo", Global.canvases) + Global.undo_redo.add_undo_property(Global.canvas, "size", Global.canvas.size) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() diff --git a/src/Preferences/PreferencesDialog.gd b/src/Preferences/PreferencesDialog.gd index 56247aea1..596912361 100644 --- a/src/Preferences/PreferencesDialog.gd +++ b/src/Preferences/PreferencesDialog.gd @@ -55,10 +55,9 @@ func _ready() -> void: Global.transparent_checker._ready() - for canvas in Global.canvases: - for guide in canvas.get_children(): - if guide is Guide: - guide.default_color = Global.guide_color + for guide in Global.canvas.get_children(): + if guide is Guide: + guide.default_color = Global.guide_color func _on_Preference_toggled(button_pressed : bool, prop : String) -> void: @@ -96,10 +95,9 @@ func preference_update(prop : String) -> void: Global.transparent_checker._ready() if prop in ["guide_color"]: - for canvas in Global.canvases: - for guide in canvas.get_children(): - if guide is Guide: - guide.default_color = Global.guide_color + for guide in Global.canvas.get_children(): + if guide is Guide: + guide.default_color = Global.guide_color Global.config_cache.save("user://cache.ini") diff --git a/src/SelectionRectangle.gd b/src/SelectionRectangle.gd index 09d907bf8..a4c9e3258 100644 --- a/src/SelectionRectangle.gd +++ b/src/SelectionRectangle.gd @@ -27,7 +27,7 @@ func _process(_delta : float) -> void: var start_pos := polygon[0] var end_pos := polygon[2] var current_layer_index : int = Global.current_layer - var layer : Image = Global.canvas.layers[current_layer_index].image + var layer : Image = Global.frames[Global.current_frame].cels[current_layer_index].image if end_pos == start_pos: visible = false diff --git a/src/UI/Dialogs/CreateNewImage.gd b/src/UI/Dialogs/CreateNewImage.gd index 61272127f..8a4e9a14f 100644 --- a/src/UI/Dialogs/CreateNewImage.gd +++ b/src/UI/Dialogs/CreateNewImage.gd @@ -73,22 +73,23 @@ func _on_CreateNewImage_confirmed() -> void: var width : int = width_value.value var height : int = height_value.value var fill_color : Color = fill_color_node.color - Global.clear_canvases() + Global.clear_frames() Global.layers.clear() Global.layers.append(Layer.new()) - Global.canvas = load("res://src/Canvas.tscn").instance() Global.canvas.size = Vector2(width, height).floor() + Global.canvas.fill_color = fill_color + var frame : Frame = Global.canvas.new_empty_frame() + Global.canvas.camera_zoom() + Global.frames.append(frame) - Global.canvases.append(Global.canvas) - Global.canvas_parent.add_child(Global.canvas) Global.current_layer = 0 - Global.canvases = Global.canvases # To trigger Global.canvases_changed() + Global.frames = Global.frames # To trigger Global.frames_changed() Global.current_frame = 0 Global.layers = Global.layers # To trigger Global.layers_changed() Global.project_has_changed = false if fill_color.a > 0: - Global.canvas.layers[0].image.fill(fill_color) - Global.canvas.layers[0].image.lock() + Global.frames[0].cels[0].image.fill(fill_color) + Global.frames[0].cels[0].image.lock() Global.canvas.update_texture(0) diff --git a/src/UI/Dialogs/ExportDialog.gd b/src/UI/Dialogs/ExportDialog.gd index f8c3117c2..6927e5134 100644 --- a/src/UI/Dialogs/ExportDialog.gd +++ b/src/UI/Dialogs/ExportDialog.gd @@ -3,7 +3,7 @@ extends AcceptDialog enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 } var current_tab : int = ExportTab.FRAME -# All canvases and their layers processed/blended into images +# All frames and their layers processed/blended into images var processed_images = [] # Image[] # Frame options @@ -11,7 +11,7 @@ var frame_number := 0 # Spritesheet options var frame_current_tag := 0 # Export only current frame tag -var canvas_size := 1 +var number_of_frames := 1 enum Orientation { ROWS = 0, COLUMNS = 1 } var orientation : int = Orientation.ROWS # How many rows/columns before new line is added @@ -90,7 +90,7 @@ func show_tab() -> void: $FrameTimer.stop() if not was_exported: frame_number = Global.current_frame + 1 - $VBoxContainer/FrameOptions/FrameNumber/FrameNumber.max_value = Global.canvases.size() + 1 + $VBoxContainer/FrameOptions/FrameNumber/FrameNumber.max_value = Global.frames.size() + 1 var prev_frame_number = $VBoxContainer/FrameOptions/FrameNumber/FrameNumber.value $VBoxContainer/FrameOptions/FrameNumber/FrameNumber.value = frame_number if prev_frame_number == frame_number: @@ -101,13 +101,13 @@ func show_tab() -> void: file_format = FileFormat.PNG if not was_exported: orientation = Orientation.ROWS - lines_count = int(ceil(sqrt(canvas_size))) + lines_count = int(ceil(sqrt(number_of_frames))) process_spritesheet() $VBoxContainer/File/FileFormat.selected = FileFormat.PNG $VBoxContainer/SpritesheetOptions/Frames/Frames.select(frame_current_tag) $FrameTimer.stop() $VBoxContainer/SpritesheetOptions/Orientation/Orientation.selected = orientation - $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.max_value = canvas_size + $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.max_value = number_of_frames $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.value = lines_count $VBoxContainer/SpritesheetOptions/Orientation/LinesCountLabel.text = "Columns:" $VBoxContainer/SpritesheetOptions.show() @@ -135,10 +135,10 @@ func external_export() -> void: func process_frame() -> void: - var canvas = Global.canvases[frame_number - 1] + var frame = Global.frames[frame_number - 1] var image := Image.new() - image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) - blend_layers(image, canvas) + image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) + blend_layers(image, frame) processed_images.clear() processed_images.append(image) @@ -149,12 +149,12 @@ func process_spritesheet() -> void: if frame_current_tag > 0: var frame_start = Global.animation_tags[frame_current_tag - 1].from var frame_end = Global.animation_tags[frame_current_tag - 1].to - frames = Global.canvases.slice(frame_start-1, frame_end-1, 1, true) + frames = Global.frames.slice(frame_start-1, frame_end-1, 1, true) else: - frames = Global.canvases + frames = Global.frames # Then store the size of frames for other functions - canvas_size = frames.size() + number_of_frames = frames.size() # If rows mode selected calculate columns count and vice versa var spritesheet_columns = lines_count if orientation == Orientation.ROWS else frames_divided_by_spritesheet_lines() @@ -170,26 +170,26 @@ func process_spritesheet() -> void: var hh := 0 var vv := 0 - for canvas in frames: + for frame in frames: if orientation == Orientation.ROWS: if vv < spritesheet_columns: - origin.x = canvas.size.x * vv + origin.x = Global.canvas.size.x * vv vv += 1 else: hh += 1 origin.x = 0 vv = 1 - origin.y = canvas.size.y * hh + origin.y = Global.canvas.size.y * hh else: if hh < spritesheet_rows: - origin.y = canvas.size.y * hh + origin.y = Global.canvas.size.y * hh hh += 1 else: vv += 1 origin.y = 0 hh = 1 - origin.x = canvas.size.x * vv - blend_layers(whole_image, canvas, origin) + origin.x = Global.canvas.size.x * vv + blend_layers(whole_image, frame, origin) processed_images.clear() processed_images.append(whole_image) @@ -197,10 +197,10 @@ func process_spritesheet() -> void: func process_animation() -> void: processed_images.clear() - for canvas in Global.canvases: + for frame in Global.frames: var image := Image.new() - image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) - blend_layers(image, canvas) + image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) + blend_layers(image, frame) processed_images.append(image) @@ -361,21 +361,21 @@ func export_processed_images(ignore_overwrites : bool) -> void: # Blends canvas layers into passed image starting from the origin position -func blend_layers(image: Image, canvas: Canvas, origin: Vector2 = Vector2(0, 0)) -> void: +func blend_layers(image : Image, frame : Frame, origin : Vector2 = Vector2(0, 0)) -> void: image.lock() var layer_i := 0 - for layer in canvas.layers: + for cel in frame.cels: if Global.layers[layer_i].visible: - var layer_image := Image.new() - layer_image.copy_from(layer.image) - layer_image.lock() - if layer.opacity < 1: # If we have layer transparency - for xx in layer_image.get_size().x: - for yy in layer_image.get_size().y: - var pixel_color := layer_image.get_pixel(xx, yy) - var alpha : float = pixel_color.a * layer.opacity - layer_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) - DrawingAlgos.blend_rect(image, layer_image, Rect2(canvas.position, canvas.size), origin) + var cel_image := Image.new() + cel_image.copy_from(cel.image) + cel_image.lock() + if cel.opacity < 1: # If we have cel transparency + for xx in cel_image.get_size().x: + for yy in cel_image.get_size().y: + var pixel_color := cel_image.get_pixel(xx, yy) + var alpha : float = pixel_color.a * cel.opacity + cel_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) + DrawingAlgos.blend_rect(image, cel_image, Rect2(Global.canvas.location, Global.canvas.size), origin) layer_i += 1 image.unlock() @@ -416,7 +416,7 @@ func create_export_path(multifile: bool, frame: int = 0) -> String: func frames_divided_by_spritesheet_lines() -> int: - return int(ceil(canvas_size / float(lines_count))) + return int(ceil(number_of_frames / float(lines_count))) func file_format_string(format_enum : int) -> String: @@ -476,7 +476,7 @@ func store_export_settings() -> void: # Fill the dialog with previous export settings func restore_previous_export_settings() -> void: current_tab = exported_tab - frame_number = exported_frame_number if exported_frame_number <= Global.canvases.size() else Global.canvases.size() + frame_number = exported_frame_number if exported_frame_number <= Global.frames.size() else Global.frames.size() frame_current_tag = exported_frame_current_tag if exported_frame_current_tag <= Global.animation_tags.size() else 0 orientation = exported_orientation lines_count = exported_lines_count @@ -667,5 +667,5 @@ func _on_Frames_item_selected(id : int) -> void: frame_current_tag = id process_spritesheet() set_preview() - $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.max_value = canvas_size + $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.max_value = number_of_frames $VBoxContainer/SpritesheetOptions/Orientation/LinesCount.value = lines_count diff --git a/src/UI/Dialogs/ImportSprites.gd b/src/UI/Dialogs/ImportSprites.gd index 389f97931..cb6435057 100644 --- a/src/UI/Dialogs/ImportSprites.gd +++ b/src/UI/Dialogs/ImportSprites.gd @@ -37,19 +37,14 @@ func _on_VerticalFrames_value_changed(value) -> void: func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void: Global.control.opensprite_file_selected = true if !new_frame: # If we're not adding a new frame, delete the previous - Global.clear_canvases() + Global.clear_frames() Global.layers.clear() - # Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), - # will new frames be linked boolean (4), Array of linked frames (5)] Global.layers.append(Layer.new()) Global.current_layer = 0 var first_path : String = paths[0] - var i : int = Global.canvases.size() + var i : int = Global.frames.size() if !import_spritesheet: - # Find the biggest image and let it handle the camera zoom options - var max_size : Vector2 - var biggest_canvas : Canvas for path in paths: var image := Image.new() var err := image.load(path) @@ -60,35 +55,23 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void: Global.dialog_open(true) continue - var canvas : Canvas = load("res://src/Canvas.tscn").instance() - canvas.size = image.get_size() + Global.canvas.size = image.get_size() + var frame := Frame.new() image.convert(Image.FORMAT_RGBA8) image.lock() - canvas.layers.append(Cel.new(image, 1)) + frame.cels.append(Cel.new(image, 1)) for _i in range(1, Global.layers.size()): var empty_sprite := Image.new() - empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) + empty_sprite.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) empty_sprite.fill(Color(0, 0, 0, 0)) empty_sprite.lock() - canvas.layers.append(Cel.new(empty_sprite, 1)) + frame.cels.append(Cel.new(empty_sprite, 1)) - canvas.frame = i - Global.canvases.append(canvas) - Global.canvas_parent.add_child(canvas) - canvas.visible = false - if path == paths[0]: # If it's the first file - max_size = canvas.size - biggest_canvas = canvas - else: - if canvas.size > max_size: - biggest_canvas = canvas + Global.frames.append(frame) i += 1 - if biggest_canvas: - biggest_canvas.camera_zoom() - else: var image := Image.new() var err := image.load(first_path) @@ -105,36 +88,31 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void: var frame_height := image.get_size().y / spritesheet_vertical for yy in range(spritesheet_vertical): for xx in range(spritesheet_horizontal): - var canvas : Canvas = load("res://src/Canvas.tscn").instance() + var frame := Frame.new() var cropped_image := Image.new() cropped_image = image.get_rect(Rect2(frame_width * xx, frame_height * yy, frame_width, frame_height)) - canvas.size = cropped_image.get_size() + Global.canvas.size = cropped_image.get_size() cropped_image.convert(Image.FORMAT_RGBA8) cropped_image.lock() - canvas.layers.append(Cel.new(cropped_image, 1)) + frame.cels.append(Cel.new(cropped_image, 1)) for _i in range(1, Global.layers.size()): var empty_sprite := Image.new() - empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) + empty_sprite.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) empty_sprite.fill(Color(0, 0, 0, 0)) empty_sprite.lock() - canvas.layers.append(Cel.new(empty_sprite, 1)) + frame.cels.append(Cel.new(empty_sprite, 1)) - canvas.frame = i - Global.canvases.append(canvas) - Global.canvas_parent.add_child(canvas) - canvas.visible = false + Global.frames.append(frame) i += 1 - Global.canvases[Global.canvases.size() - 1].camera_zoom() + Global.canvas.camera_zoom() - Global.canvases = Global.canvases # Just to call Global.canvases_changed + Global.frames = Global.frames # Just to call Global.frames_changed Global.current_frame = i - 1 - Global.canvas = Global.canvases[Global.canvases.size() - 1] if !new_frame: Global.layers = Global.layers # Just to call Global.layers_changed - Global.canvas.visible = true Global.window_title = first_path.get_file() + " (" + tr("imported") + ") - Pixelorama " + Global.current_version if Global.project_has_changed: @@ -143,4 +121,3 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void: var directory_path := first_path.get_basename().replace(file_name, "") Global.export_dialog.directory_path = directory_path Global.export_dialog.file_name = file_name - diff --git a/src/UI/Dialogs/ScaleImage.gd b/src/UI/Dialogs/ScaleImage.gd index dc308a5fc..fc731188d 100644 --- a/src/UI/Dialogs/ScaleImage.gd +++ b/src/UI/Dialogs/ScaleImage.gd @@ -7,17 +7,17 @@ func _on_ScaleImage_confirmed() -> void: var interpolation : int = $VBoxContainer/OptionsContainer/InterpolationType.selected Global.undos += 1 Global.undo_redo.create_action("Scale") + Global.undo_redo.add_do_property(Global.canvas, "size", Vector2(width, height).floor()) - for c in Global.canvases: - Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor()) - for i in range(c.layers.size() - 1, -1, -1): + for f in Global.frames: + for i in range(f.cels.size() - 1, -1, -1): var sprite := Image.new() - sprite.copy_from(c.layers[i].image) + sprite.copy_from(f.cels[i].image) sprite.resize(width, height, interpolation) - Global.undo_redo.add_do_property(c.layers[i].image, "data", sprite.data) - Global.undo_redo.add_undo_property(c.layers[i].image, "data", c.layers[i].image.data) - Global.undo_redo.add_undo_property(c, "size", c.size) + Global.undo_redo.add_do_property(f.cels[i].image, "data", sprite.data) + Global.undo_redo.add_undo_property(f.cels[i].image, "data", f.cels[i].image.data) - Global.undo_redo.add_undo_method(Global, "undo", Global.canvases) - Global.undo_redo.add_do_method(Global, "redo", Global.canvases) + Global.undo_redo.add_undo_property(Global.canvas, "size", Global.canvas.size) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() diff --git a/src/UI/Timeline/AnimationTimeline.gd b/src/UI/Timeline/AnimationTimeline.gd index b20abf4f6..eeccd8583 100644 --- a/src/UI/Timeline/AnimationTimeline.gd +++ b/src/UI/Timeline/AnimationTimeline.gd @@ -4,7 +4,7 @@ var fps := 6.0 var animation_loop := 1 # 0 is no loop, 1 is cycle loop, 2 is ping-pong loop var animation_forward := true var first_frame := 0 -var last_frame : int = Global.canvases.size() - 1 +var last_frame : int = Global.frames.size() - 1 var timeline_scroll : ScrollContainer var tag_scroll_container : ScrollContainer @@ -24,47 +24,48 @@ func _h_scroll_changed(value : float) -> void: func add_frame() -> void: - var new_canvas : Canvas = load("res://src/Canvas.tscn").instance() - new_canvas.size = Global.canvas.size - new_canvas.frame = Global.canvases.size() + var frame : Frame = Global.canvas.new_empty_frame() + var new_frames : Array = Global.frames.duplicate() + new_frames.append(frame) + var new_layers : Array = Global.layers.duplicate() + # Loop through the array to create new classes for each element, so that they + # won't be the same as the original array's classes. Needed for undo/redo to work properly. + for i in new_layers.size(): + var new_linked_cels = new_layers[i].linked_cels.duplicate() + new_layers[i] = Layer.new(new_layers[i].name, new_layers[i].visible, new_layers[i].locked, new_layers[i].frame_container, new_layers[i].new_cels_linked, new_linked_cels) - var new_canvases : Array = Global.canvases.duplicate() - new_canvases.append(new_canvas) + for l_i in range(new_layers.size()): + if new_layers[l_i].new_cels_linked: # If the link button is pressed + new_layers[l_i].linked_cels.append(frame) + frame.cels[l_i].image = new_layers[l_i].linked_cels[0].cels[l_i].image + frame.cels[l_i].image_texture = new_layers[l_i].linked_cels[0].cels[l_i].image_texture Global.undos += 1 Global.undo_redo.create_action("Add Frame") - Global.undo_redo.add_do_method(Global, "redo", [new_canvas]) - Global.undo_redo.add_undo_method(Global, "undo", [new_canvas]) + Global.undo_redo.add_do_method(Global, "redo") + Global.undo_redo.add_undo_method(Global, "undo") - Global.undo_redo.add_do_property(Global, "canvases", new_canvases) - Global.undo_redo.add_do_property(Global, "canvas", new_canvas) - Global.undo_redo.add_do_property(Global, "current_frame", new_canvases.size() - 1) + Global.undo_redo.add_do_property(Global, "frames", new_frames) + Global.undo_redo.add_do_property(Global, "current_frame", new_frames.size() - 1) + Global.undo_redo.add_do_property(Global, "layers", new_layers) - for c in Global.canvases: - Global.undo_redo.add_do_property(c, "visible", false) - Global.undo_redo.add_undo_property(c, "visible", c.visible) - - for l_i in range(Global.layers.size()): - if Global.layers[l_i].new_cels_linked: # If the link button is pressed - Global.layers[l_i].linked_cels.append(new_canvas) - - Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases) - Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas) + Global.undo_redo.add_undo_property(Global, "frames", Global.frames) Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame) + Global.undo_redo.add_undo_property(Global, "layers", Global.layers) Global.undo_redo.commit_action() func _on_DeleteFrame_pressed(frame := -1) -> void: - if Global.canvases.size() == 1: + if Global.frames.size() == 1: return if frame == -1: frame = Global.current_frame - var canvas : Canvas = Global.canvases[frame] - var new_canvases : Array = Global.canvases.duplicate() - new_canvases.erase(canvas) + var frame_to_delete : Frame = Global.frames[frame] + var new_frames : Array = Global.frames.duplicate() + new_frames.erase(frame_to_delete) var current_frame := Global.current_frame - if current_frame > 0 && current_frame == new_canvases.size(): # If it's the last frame + if current_frame > 0 && current_frame == new_frames.size(): # If it's the last frame current_frame -= 1 var new_animation_tags := Global.animation_tags.duplicate() @@ -96,34 +97,24 @@ func _on_DeleteFrame_pressed(frame := -1) -> void: for layer in new_layers: for linked in layer.linked_cels: - if linked == Global.canvases[frame]: + if linked == Global.frames[frame]: layer.linked_cels.erase(linked) Global.undos += 1 Global.undo_redo.create_action("Remove Frame") - Global.undo_redo.add_do_property(Global, "canvases", new_canvases) - Global.undo_redo.add_do_property(Global, "canvas", new_canvases[current_frame]) + Global.undo_redo.add_do_property(Global, "frames", new_frames) Global.undo_redo.add_do_property(Global, "current_frame", current_frame) Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags) Global.undo_redo.add_do_property(Global, "layers", new_layers) - # Change the frame value of the canvaseso on the right - # for example, if frame "3" was deleted, then "4" would have to become "3" - for i in range(frame, new_canvases.size()): - var c : Canvas = new_canvases[i] - Global.undo_redo.add_do_property(c, "frame", i) - Global.undo_redo.add_undo_property(c, "frame", c.frame) - - - Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases) - Global.undo_redo.add_undo_property(Global, "canvas", canvas) + Global.undo_redo.add_undo_property(Global, "frames", Global.frames) Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame) Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) - Global.undo_redo.add_do_method(Global, "redo", [canvas]) - Global.undo_redo.add_undo_method(Global, "undo", [canvas]) + Global.undo_redo.add_do_method(Global, "redo") + Global.undo_redo.add_undo_method(Global, "undo") Global.undo_redo.commit_action() @@ -131,19 +122,16 @@ func _on_CopyFrame_pressed(frame := -1) -> void: if frame == -1: frame = Global.current_frame - var canvas : Canvas = Global.canvases[frame] - var new_canvas : Canvas = load("res://src/Canvas.tscn").instance() - new_canvas.size = Global.canvas.size - new_canvas.frame = Global.canvases.size() + var new_frame := Frame.new() - var new_canvases := Global.canvases.duplicate() - new_canvases.insert(frame + 1, new_canvas) + var new_frames := Global.frames.duplicate() + new_frames.insert(frame + 1, new_frame) - for layer in canvas.layers: # Copy every layer + for cel in Global.frames[frame].cels: # Copy every cel var sprite := Image.new() - sprite.copy_from(layer.image) + sprite.copy_from(cel.image) sprite.lock() - new_canvas.layers.append(Cel.new(sprite, layer.opacity)) + new_frame.cels.append(Cel.new(sprite, cel.opacity)) var new_animation_tags := Global.animation_tags.duplicate() # Loop through the tags to create new classes for them, so that they won't be the same @@ -158,28 +146,18 @@ func _on_CopyFrame_pressed(frame := -1) -> void: Global.undos += 1 Global.undo_redo.create_action("Add Frame") - Global.undo_redo.add_do_method(Global, "redo", [new_canvas]) - Global.undo_redo.add_undo_method(Global, "undo", [new_canvas]) + Global.undo_redo.add_do_method(Global, "redo") + Global.undo_redo.add_undo_method(Global, "undo") - Global.undo_redo.add_do_property(Global, "canvases", new_canvases) - Global.undo_redo.add_do_property(Global, "canvas", new_canvas) + Global.undo_redo.add_do_property(Global, "frames", new_frames) Global.undo_redo.add_do_property(Global, "current_frame", frame + 1) Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags) for i in range(Global.layers.size()): for child in Global.layers[i].frame_container.get_children(): Global.undo_redo.add_do_property(child, "pressed", false) Global.undo_redo.add_undo_property(child, "pressed", child.pressed) - for c in Global.canvases: - Global.undo_redo.add_do_property(c, "visible", false) - Global.undo_redo.add_undo_property(c, "visible", c.visible) - for i in range(frame, new_canvases.size()): - var c : Canvas = new_canvases[i] - Global.undo_redo.add_do_property(c, "frame", i) - Global.undo_redo.add_undo_property(c, "frame", c.frame) - - Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases) - Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas) + Global.undo_redo.add_undo_property(Global, "frames", Global.frames) Global.undo_redo.add_undo_property(Global, "current_frame", frame) Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags) Global.undo_redo.commit_action() @@ -276,12 +254,12 @@ func _on_AnimationTimer_timeout() -> void: func play_animation(play : bool, forward_dir : bool) -> void: first_frame = 0 - last_frame = Global.canvases.size() - 1 + last_frame = Global.frames.size() - 1 if Global.play_only_tags: for tag in Global.animation_tags: if Global.current_frame + 1 >= tag.from && Global.current_frame + 1 <= tag.to: first_frame = tag.from - 1 - last_frame = min(Global.canvases.size() - 1, tag.to - 1) + last_frame = min(Global.frames.size() - 1, tag.to - 1) if first_frame == last_frame: if forward_dir: @@ -310,7 +288,7 @@ func play_animation(play : bool, forward_dir : bool) -> void: func _on_NextFrame_pressed() -> void: - if Global.current_frame < Global.canvases.size() - 1: + if Global.current_frame < Global.frames.size() - 1: Global.current_frame += 1 @@ -320,7 +298,7 @@ func _on_PreviousFrame_pressed() -> void: func _on_LastFrame_pressed() -> void: - Global.current_frame = Global.canvases.size() - 1 + Global.current_frame = Global.frames.size() - 1 func _on_FirstFrame_pressed() -> void: @@ -359,27 +337,27 @@ func add_layer(is_new := true) -> void: Global.undos += 1 Global.undo_redo.create_action("Add Layer") - for c in Global.canvases: + for f in Global.frames: var new_layer := Image.new() if is_new: - new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8) + new_layer.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) else: # Clone layer - new_layer.copy_from(c.layers[Global.current_layer].image) + new_layer.copy_from(f.cels[Global.current_layer].image) new_layer.lock() - var new_canvas_layers : Array = c.layers.duplicate() - new_canvas_layers.append(Cel.new(new_layer, 1)) - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + var new_cels : Array = f.cels.duplicate() + new_cels.append(Cel.new(new_layer, 1)) + Global.undo_redo.add_do_property(f, "cels", new_cels) + Global.undo_redo.add_undo_property(f, "cels", f.cels) Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer + 1) Global.undo_redo.add_do_property(Global, "layers", new_layers) Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas]) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvas]) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() @@ -393,17 +371,17 @@ func _on_RemoveLayer_pressed() -> void: else: Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer) - for c in Global.canvases: - var new_canvas_layers : Array = c.layers.duplicate() - new_canvas_layers.remove(Global.current_layer) - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + for f in Global.frames: + var new_cels : Array = f.cels.duplicate() + new_cels.remove(Global.current_layer) + Global.undo_redo.add_do_property(f, "cels", new_cels) + Global.undo_redo.add_undo_property(f, "cels", f.cels) Global.undo_redo.add_do_property(Global, "layers", new_layers) Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvas]) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas]) + Global.undo_redo.add_do_method(Global, "redo") + Global.undo_redo.add_undo_method(Global, "undo") Global.undo_redo.commit_action() @@ -415,21 +393,21 @@ func change_layer_order(rate : int) -> void: new_layers[Global.current_layer] = new_layers[change] new_layers[change] = temp Global.undo_redo.create_action("Change Layer Order") - for c in Global.canvases: - var new_canvas_layers : Array = c.layers.duplicate() - var temp_canvas = new_canvas_layers[Global.current_layer] - new_canvas_layers[Global.current_layer] = new_canvas_layers[change] - new_canvas_layers[change] = temp_canvas - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + for f in Global.frames: + var new_cels : Array = f.cels.duplicate() + var temp_canvas = new_cels[Global.current_layer] + new_cels[Global.current_layer] = new_cels[change] + new_cels[change] = temp_canvas + Global.undo_redo.add_do_property(f, "cels", new_cels) + Global.undo_redo.add_undo_property(f, "cels", f.cels) Global.undo_redo.add_do_property(Global, "current_layer", change) Global.undo_redo.add_do_property(Global, "layers", new_layers) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas]) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvas]) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() @@ -443,35 +421,35 @@ func _on_MergeDownLayer_pressed() -> void: Global.undos += 1 Global.undo_redo.create_action("Merge Layer") - for c in Global.canvases: - var new_canvas_layers : Array = c.layers.duplicate() - for i in new_canvas_layers.size(): - new_canvas_layers[i] = Cel.new(new_canvas_layers[i].image, new_canvas_layers[i].opacity) + for f in Global.frames: + var new_cels : Array = f.cels.duplicate() + for i in new_cels.size(): + new_cels[i] = Cel.new(new_cels[i].image, new_cels[i].opacity) var selected_layer := Image.new() - selected_layer.copy_from(new_canvas_layers[Global.current_layer].image) + selected_layer.copy_from(new_cels[Global.current_layer].image) selected_layer.lock() - if c.layers[Global.current_layer].opacity < 1: # If we have layer transparency + if f.cels[Global.current_layer].opacity < 1: # If we have layer transparency for xx in selected_layer.get_size().x: for yy in selected_layer.get_size().y: var pixel_color : Color = selected_layer.get_pixel(xx, yy) - var alpha : float = pixel_color.a * c.layers[Global.current_layer].opacity + var alpha : float = pixel_color.a * f.cels[Global.current_layer].opacity selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) var new_layer := Image.new() - new_layer.copy_from(c.layers[Global.current_layer - 1].image) + new_layer.copy_from(f.cels[Global.current_layer - 1].image) new_layer.lock() - DrawingAlgos.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO) - new_canvas_layers.remove(Global.current_layer) - if !selected_layer.is_invisible() and Global.layers[Global.current_layer - 1].linked_cels.size() > 1 and (c in Global.layers[Global.current_layer - 1].linked_cels): - new_layers[Global.current_layer - 1].linked_cels.erase(c) - new_canvas_layers[Global.current_layer - 1].image = new_layer + DrawingAlgos.blend_rect(new_layer, selected_layer, Rect2(Global.canvas.location, Global.canvas.size), Vector2.ZERO) + new_cels.remove(Global.current_layer) + if !selected_layer.is_invisible() and Global.layers[Global.current_layer - 1].linked_cels.size() > 1 and (f in Global.layers[Global.current_layer - 1].linked_cels): + new_layers[Global.current_layer - 1].linked_cels.erase(f) + new_cels[Global.current_layer - 1].image = new_layer else: - Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1].image, "data", new_layer.data) - Global.undo_redo.add_undo_property(c.layers[Global.current_layer - 1].image, "data", c.layers[Global.current_layer - 1].image.data) + Global.undo_redo.add_do_property(f.cels[Global.current_layer - 1].image, "data", new_layer.data) + Global.undo_redo.add_undo_property(f.cels[Global.current_layer - 1].image, "data", f.cels[Global.current_layer - 1].image.data) - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + Global.undo_redo.add_do_property(f, "cels", new_cels) + Global.undo_redo.add_undo_property(f, "cels", f.cels) new_layers.remove(Global.current_layer) Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer - 1) @@ -479,13 +457,13 @@ func _on_MergeDownLayer_pressed() -> void: Global.undo_redo.add_undo_property(Global, "layers", Global.layers) Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer) - Global.undo_redo.add_undo_method(Global, "undo", Global.canvases) - Global.undo_redo.add_do_method(Global, "redo", Global.canvases) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() func _on_OpacitySlider_value_changed(value) -> void: - Global.canvas.layers[Global.current_layer].opacity = value / 100 + Global.frames[Global.current_frame].cels[Global.current_layer].opacity = value / 100 Global.layer_opacity_slider.value = value Global.layer_opacity_slider.value = value Global.layer_opacity_spinbox.value = value diff --git a/src/UI/Timeline/CelButton.gd b/src/UI/Timeline/CelButton.gd index bc75b9fb5..7516a0193 100644 --- a/src/UI/Timeline/CelButton.gd +++ b/src/UI/Timeline/CelButton.gd @@ -8,7 +8,7 @@ onready var popup_menu : PopupMenu = $PopupMenu func _ready() -> void: hint_tooltip = "Frame: %s, Layer: %s" % [frame + 1, layer] - if Global.canvases[frame] in Global.layers[layer].linked_cels: + if Global.frames[frame] in Global.layers[layer].linked_cels: get_node("LinkedIndicator").visible = true popup_menu.set_item_text(4, "Unlink Cel") popup_menu.set_item_metadata(4, "Unlink Cel") @@ -23,7 +23,7 @@ func _on_CelButton_pressed() -> void: Global.current_frame = frame Global.current_layer = layer elif Input.is_action_just_released("right_mouse"): - if Global.canvases.size() == 1: + if Global.frames.size() == 1: popup_menu.set_item_disabled(0, true) popup_menu.set_item_disabled(2, true) popup_menu.set_item_disabled(3, true) @@ -31,7 +31,7 @@ func _on_CelButton_pressed() -> void: popup_menu.set_item_disabled(0, false) if frame > 0: popup_menu.set_item_disabled(2, false) - if frame < Global.canvases.size() - 1: + if frame < Global.frames.size() - 1: popup_menu.set_item_disabled(3, false) popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE)) pressed = !pressed @@ -53,73 +53,68 @@ func _on_PopupMenu_id_pressed(ID : int) -> void: 3: # Move Right change_frame_order(1) 4: # Unlink Cel - var cel_index : int = Global.layers[layer].linked_cels.find(Global.canvases[frame]) - var c = Global.canvases[frame] + var cel_index : int = Global.layers[layer].linked_cels.find(Global.frames[frame]) + var f = Global.frames[frame] var new_layers : Array = Global.layers.duplicate() # Loop through the array to create new classes for each element, so that they # won't be the same as the original array's classes. Needed for undo/redo to work properly. for i in new_layers.size(): var new_linked_cels = new_layers[i].linked_cels.duplicate() new_layers[i] = Layer.new(new_layers[i].name, new_layers[i].visible, new_layers[i].locked, new_layers[i].frame_container, new_layers[i].new_cels_linked, new_linked_cels) - var new_canvas_layers : Array = c.layers.duplicate() - for i in new_canvas_layers.size(): - new_canvas_layers[i] = Cel.new(new_canvas_layers[i].image, new_canvas_layers[i].opacity) + var new_cels : Array = f.cels.duplicate() + for i in new_cels.size(): + new_cels[i] = Cel.new(new_cels[i].image, new_cels[i].opacity) if popup_menu.get_item_metadata(4) == "Unlink Cel": new_layers[layer].linked_cels.remove(cel_index) var sprite := Image.new() - sprite.copy_from(Global.canvases[frame].layers[layer].image) + sprite.copy_from(Global.frames[frame].cels[layer].image) sprite.lock() - new_canvas_layers[layer].image = sprite + new_cels[layer].image = sprite Global.undo_redo.create_action("Unlink Cel") Global.undo_redo.add_do_property(Global, "layers", new_layers) - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) + Global.undo_redo.add_do_property(f, "cels", new_cels) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + Global.undo_redo.add_undo_property(f, "cels", f.cels) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]], layer) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() elif popup_menu.get_item_metadata(4) == "Link Cel": - new_layers[layer].linked_cels.append(Global.canvases[frame]) + new_layers[layer].linked_cels.append(Global.frames[frame]) Global.undo_redo.create_action("Link Cel") Global.undo_redo.add_do_property(Global, "layers", new_layers) if new_layers[layer].linked_cels.size() > 1: # If there are already linked cels, set the current cel's image # to the first linked cel's image - new_canvas_layers[layer].image = new_layers[layer].linked_cels[0].layers[layer].image - new_canvas_layers[layer].image_texture = new_layers[layer].linked_cels[0].layers[layer].image_texture - Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) - Global.undo_redo.add_undo_property(c, "layers", c.layers) + new_cels[layer].image = new_layers[layer].linked_cels[0].cels[layer].image + new_cels[layer].image_texture = new_layers[layer].linked_cels[0].cels[layer].image_texture + Global.undo_redo.add_do_property(f, "cels", new_cels) + Global.undo_redo.add_undo_property(f, "cels", f.cels) Global.undo_redo.add_undo_property(Global, "layers", Global.layers) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]], layer) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() func change_frame_order(rate : int) -> void: var change = frame + rate - var new_canvases : Array = Global.canvases.duplicate() - var temp = new_canvases[frame] - new_canvases[frame] = new_canvases[change] - new_canvases[change] = temp + var new_frames : Array = Global.frames.duplicate() + var temp = new_frames[frame] + new_frames[frame] = new_frames[change] + new_frames[change] = temp Global.undo_redo.create_action("Change Frame Order") - Global.undo_redo.add_do_property(Global, "canvases", new_canvases) - Global.undo_redo.add_do_property(Global.canvases[frame], "frame", change) - Global.undo_redo.add_do_property(Global.canvases[change], "frame", frame) + Global.undo_redo.add_do_property(Global, "frames", new_frames) if Global.current_frame == frame: Global.undo_redo.add_do_property(Global, "current_frame", change) Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame) - Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases) - Global.undo_redo.add_undo_property(Global.canvases[frame], "frame", frame) - Global.undo_redo.add_undo_property(Global.canvases[change], "frame", change) + Global.undo_redo.add_undo_property(Global, "frames", Global.frames) - Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]]) - Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]]) + Global.undo_redo.add_undo_method(Global, "undo") + Global.undo_redo.add_do_method(Global, "redo") Global.undo_redo.commit_action() - diff --git a/src/UI/Timeline/FrameTagDialog.gd b/src/UI/Timeline/FrameTagDialog.gd index b3be07a6e..05ece7c74 100644 --- a/src/UI/Timeline/FrameTagDialog.gd +++ b/src/UI/Timeline/FrameTagDialog.gd @@ -86,8 +86,8 @@ func _on_TagOptions_confirmed() -> void: var tag_from : int = options_dialog.get_node("GridContainer/FromSpinBox").value var tag_to : int = options_dialog.get_node("GridContainer/ToSpinBox").value - if tag_to > Global.canvases.size(): - tag_to = Global.canvases.size() + if tag_to > Global.frames.size(): + tag_to = Global.frames.size() if tag_from > tag_to: tag_from = tag_to diff --git a/src/UI/Timeline/LayerButton.gd b/src/UI/Timeline/LayerButton.gd index 16d2bf96a..a88075248 100644 --- a/src/UI/Timeline/LayerButton.gd +++ b/src/UI/Timeline/LayerButton.gd @@ -74,5 +74,6 @@ func _on_LockButton_pressed() -> void: func _on_LinkButton_pressed() -> void: Global.layers[i].new_cels_linked = !Global.layers[i].new_cels_linked if Global.layers[i].new_cels_linked && !Global.layers[i].linked_cels: - Global.layers[i].linked_cels.append(Global.canvas) + # If button is pressed and there are no linked cels in the layer + Global.layers[i].linked_cels.append(Global.frames[Global.current_frame]) Global.layers[i].frame_container.get_child(Global.current_frame)._ready()