1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-19 09:39:48 +00:00

Continue with the undo/redo rewrite

Works everywhere except image resizing, replacing cels and merging layers
This commit is contained in:
Emmanouil Papadeas 2024-11-28 23:28:49 +02:00
parent b3a429466d
commit 9e86492bfe
11 changed files with 105 additions and 85 deletions

View file

@ -157,10 +157,11 @@ func display_animate_dialog() -> void:
func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void:
project.update_tilesets(undo_data)
var redo_data := _get_undo_data(project) var redo_data := _get_undo_data(project)
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) project.undo_redo.create_action(action)
Global.undo_redo_compress_images(redo_data, undo_data, project) project.deserialize_cel_undo_data(redo_data, undo_data)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, -1, -1, project)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, -1, -1, project))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, -1, -1, project)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, -1, -1, project))
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -168,24 +169,22 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo
func _get_undo_data(project: Project) -> Dictionary: func _get_undo_data(project: Project) -> Dictionary:
var data := {} var data := {}
var images := _get_selected_draw_images(project) project.serialize_cel_undo_data(_get_selected_draw_cels(project), data)
for image in images:
image.add_data_to_dictionary(data)
return data return data
func _get_selected_draw_images(project: Project) -> Array[ImageExtended]: func _get_selected_draw_cels(project: Project) -> Array[BaseCel]:
var images: Array[ImageExtended] = [] var images: Array[BaseCel] = []
if affect == SELECTED_CELS: if affect == SELECTED_CELS:
for cel_index in project.selected_cels: for cel_index in project.selected_cels:
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]] var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]
if cel is PixelCel: if cel is PixelCel:
images.append(cel.get_image()) images.append(cel)
else: else:
for frame in project.frames: for frame in project.frames:
for cel in frame.cels: for cel in frame.cels:
if cel is PixelCel: if cel is PixelCel:
images.append(cel.get_image()) images.append(cel)
return images return images

View file

@ -651,6 +651,26 @@ func get_all_pixel_cels() -> Array[PixelCel]:
return cels return cels
func serialize_cel_undo_data(cels: Array[BaseCel], data: Dictionary) -> void:
for cel in cels:
if not cel is PixelCel:
continue
var image := (cel as PixelCel).get_image()
image.add_data_to_dictionary(data)
if cel is CelTileMap:
data[cel] = (cel as CelTileMap).serialize_undo_data()
func deserialize_cel_undo_data(redo_data: Dictionary, undo_data: Dictionary) -> void:
Global.undo_redo_compress_images(redo_data, undo_data, self)
for cel in redo_data:
if cel is CelTileMap:
(cel as CelTileMap).deserialize_undo_data(redo_data[cel], undo_redo, false)
for cel in undo_data:
if cel is CelTileMap:
(cel as CelTileMap).deserialize_undo_data(undo_data[cel], undo_redo, true)
## Re-order layers to take each cel's z-index into account. If all z-indexes are 0, ## Re-order layers to take each cel's z-index into account. If all z-indexes are 0,
## then the order of drawing is the same as the order of the layers itself. ## then the order of drawing is the same as the order of the layers itself.
func order_layers(frame_index := current_frame) -> void: func order_layers(frame_index := current_frame) -> void:
@ -954,3 +974,9 @@ func reorder_reference_image(from: int, to: int) -> void:
func add_tileset(tileset: TileSetCustom) -> void: func add_tileset(tileset: TileSetCustom) -> void:
tilesets.append(tileset) tilesets.append(tileset)
func update_tilesets(cel_dictionary: Dictionary) -> void:
for cel in cel_dictionary:
if cel is CelTileMap:
(cel as CelTileMap).update_tileset()

View file

@ -272,11 +272,9 @@ func prepare_undo(action: String) -> void:
func commit_undo() -> void: func commit_undo() -> void:
for cel in _undo_data:
if cel is CelTileMap:
(cel as CelTileMap).update_tileset()
var redo_data := _get_undo_data()
var project := Global.current_project var project := Global.current_project
project.update_tilesets(_undo_data)
var redo_data := _get_undo_data()
var frame := -1 var frame := -1
var layer := -1 var layer := -1
if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1:
@ -284,13 +282,7 @@ func commit_undo() -> void:
layer = project.current_layer layer = project.current_layer
project.undos += 1 project.undos += 1
Global.undo_redo_compress_images(redo_data, _undo_data, project) project.deserialize_cel_undo_data(redo_data, _undo_data)
for cel in redo_data:
if cel is CelTileMap:
(cel as CelTileMap).deserialize_undo_data(redo_data[cel], project.undo_redo, false)
for cel in _undo_data:
if cel is CelTileMap:
(cel as CelTileMap).deserialize_undo_data(_undo_data[cel], project.undo_redo, true)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer))
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -766,13 +758,7 @@ func _get_undo_data() -> Dictionary:
if not cel is PixelCel: if not cel is PixelCel:
continue continue
cels.append(cel) cels.append(cel)
for cel in cels: project.serialize_cel_undo_data(cels, data)
if not cel is PixelCel:
continue
var image := (cel as PixelCel).get_image()
image.add_data_to_dictionary(data)
if cel is CelTileMap:
data[cel] = (cel as CelTileMap).serialize_undo_data()
return data return data

View file

@ -344,6 +344,17 @@ func _get_draw_image() -> ImageExtended:
return Global.current_project.get_current_cel().get_image() return Global.current_project.get_current_cel().get_image()
func _get_selected_draw_cels() -> Array[BaseCel]:
var cels: Array[BaseCel]
var project := Global.current_project
for cel_index in project.selected_cels:
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]
if not cel is PixelCel:
continue
cels.append(cel)
return cels
func _get_selected_draw_images() -> Array[ImageExtended]: func _get_selected_draw_images() -> Array[ImageExtended]:
var images: Array[ImageExtended] = [] var images: Array[ImageExtended] = []
var project := Global.current_project var project := Global.current_project

View file

@ -494,8 +494,9 @@ func _set_pixel_pattern(image: ImageExtended, x: int, y: int, pattern_size: Vect
func commit_undo() -> void: func commit_undo() -> void:
var redo_data := _get_undo_data()
var project := Global.current_project var project := Global.current_project
project.update_tilesets(_undo_data)
var redo_data := _get_undo_data()
var frame := -1 var frame := -1
var layer := -1 var layer := -1
if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1:
@ -504,7 +505,7 @@ func commit_undo() -> void:
project.undos += 1 project.undos += 1
project.undo_redo.create_action("Draw") project.undo_redo.create_action("Draw")
Global.undo_redo_compress_images(redo_data, _undo_data, project) project.deserialize_cel_undo_data(redo_data, _undo_data)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer))
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -514,14 +515,13 @@ func commit_undo() -> void:
func _get_undo_data() -> Dictionary: func _get_undo_data() -> Dictionary:
var data := {} var data := {}
if Global.animation_timeline.animation_timer.is_stopped(): if Global.animation_timeline.animation_timer.is_stopped():
var images := _get_selected_draw_images() Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data)
for image in images:
image.add_data_to_dictionary(data)
else: else:
var cels: Array[BaseCel]
for frame in Global.current_project.frames: for frame in Global.current_project.frames:
var cel := frame.cels[Global.current_project.current_layer] var cel := frame.cels[Global.current_project.current_layer]
if not cel is PixelCel: if not cel is PixelCel:
continue continue
var image := (cel as PixelCel).get_image() cels.append(cel)
image.add_data_to_dictionary(data) Global.current_project.serialize_cel_undo_data(cels, data)
return data return data

View file

@ -130,8 +130,9 @@ func _snap_position(pos: Vector2) -> Vector2:
func _commit_undo(action: String) -> void: func _commit_undo(action: String) -> void:
var redo_data := _get_undo_data()
var project := Global.current_project var project := Global.current_project
project.update_tilesets(_undo_data)
var redo_data := _get_undo_data()
var frame := -1 var frame := -1
var layer := -1 var layer := -1
if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1:
@ -140,7 +141,7 @@ func _commit_undo(action: String) -> void:
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) project.undo_redo.create_action(action)
Global.undo_redo_compress_images(redo_data, _undo_data, project) project.deserialize_cel_undo_data(redo_data, _undo_data)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer))
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -158,9 +159,5 @@ func _get_undo_data() -> Dictionary:
for frame in project.frames: for frame in project.frames:
var cel := frame.cels[project.current_layer] var cel := frame.cels[project.current_layer]
cels.append(cel) cels.append(cel)
for cel in cels: project.serialize_cel_undo_data(cels, data)
if not cel is PixelCel:
continue
var image := (cel as PixelCel).get_image()
image.add_data_to_dictionary(data)
return data return data

View file

@ -161,8 +161,9 @@ func text_to_pixels() -> void:
func commit_undo(action: String, undo_data: Dictionary) -> void: func commit_undo(action: String, undo_data: Dictionary) -> void:
var redo_data := _get_undo_data()
var project := Global.current_project var project := Global.current_project
project.update_tilesets(undo_data)
var redo_data := _get_undo_data()
var frame := -1 var frame := -1
var layer := -1 var layer := -1
if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1: if Global.animation_timeline.animation_timer.is_stopped() and project.selected_cels.size() == 1:
@ -171,7 +172,7 @@ func commit_undo(action: String, undo_data: Dictionary) -> void:
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) project.undo_redo.create_action(action)
Global.undo_redo_compress_images(redo_data, undo_data, project) project.deserialize_cel_undo_data(redo_data, undo_data)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer))
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer))
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -179,9 +180,7 @@ func commit_undo(action: String, undo_data: Dictionary) -> void:
func _get_undo_data() -> Dictionary: func _get_undo_data() -> Dictionary:
var data := {} var data := {}
var images := _get_selected_draw_images() Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data)
for image in images:
image.add_data_to_dictionary(data)
return data return data

View file

@ -568,12 +568,12 @@ func commit_undo(action: String, undo_data_tmp: Dictionary) -> void:
if !undo_data_tmp: if !undo_data_tmp:
print("No undo data found!") print("No undo data found!")
return return
var redo_data := get_undo_data(undo_data_tmp["undo_image"])
var project := Global.current_project var project := Global.current_project
project.update_tilesets(undo_data_tmp)
var redo_data := get_undo_data(undo_data_tmp["undo_image"])
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) project.undo_redo.create_action(action)
Global.undo_redo_compress_images(redo_data, undo_data_tmp, project) project.deserialize_cel_undo_data(redo_data, undo_data_tmp)
project.undo_redo.add_do_property( project.undo_redo.add_do_property(
self, "big_bounding_rectangle", redo_data["big_bounding_rectangle"] self, "big_bounding_rectangle", redo_data["big_bounding_rectangle"]
) )
@ -604,15 +604,14 @@ func get_undo_data(undo_image: bool) -> Dictionary:
data["undo_image"] = undo_image data["undo_image"] = undo_image
if undo_image: if undo_image:
var images := _get_selected_draw_images() Global.current_project.serialize_cel_undo_data(_get_selected_draw_cels(), data)
for image in images:
image.add_data_to_dictionary(data)
return data return data
func _get_selected_draw_cels() -> Array[PixelCel]: # TODO: Change BaseCel to PixelCel if Godot ever fixes issues
var cels: Array[PixelCel] = [] # with typed arrays being cast into other types.
func _get_selected_draw_cels() -> Array[BaseCel]:
var cels: Array[BaseCel] = []
var project := Global.current_project var project := Global.current_project
for cel_index in project.selected_cels: for cel_index in project.selected_cels:
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]] var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]

View file

@ -47,11 +47,11 @@ func _flip_image(cel: Image, affect_selection: bool, project: Project) -> void:
func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void:
_flip_selection(project) _flip_selection(project)
project.update_tilesets(undo_data)
var redo_data := _get_undo_data(project) var redo_data := _get_undo_data(project)
project.undos += 1 project.undos += 1
project.undo_redo.create_action(action) project.undo_redo.create_action(action)
Global.undo_redo_compress_images(redo_data, undo_data, project) project.deserialize_cel_undo_data(redo_data, undo_data)
if redo_data.has("outline_offset"): if redo_data.has("outline_offset"):
project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"]) project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"])
project.undo_redo.add_undo_property( project.undo_redo.add_undo_property(
@ -66,14 +66,10 @@ func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> vo
func _get_undo_data(project: Project) -> Dictionary: func _get_undo_data(project: Project) -> Dictionary:
var affect_selection := selection_checkbox.button_pressed and project.has_selection var affect_selection := selection_checkbox.button_pressed and project.has_selection
var data := {} var data := super._get_undo_data(project)
if affect_selection: if affect_selection:
data[project.selection_map] = project.selection_map.data data[project.selection_map] = project.selection_map.data
data["outline_offset"] = project.selection_offset data["outline_offset"] = project.selection_offset
var images := _get_selected_draw_images(project)
for image in images:
data[image] = image.data
return data return data

View file

@ -149,34 +149,37 @@ func _delete_effect(effect: LayerEffect) -> void:
func _apply_effect(layer: BaseLayer, effect: LayerEffect) -> void: func _apply_effect(layer: BaseLayer, effect: LayerEffect) -> void:
var project := Global.current_project
var index := layer.effects.find(effect) var index := layer.effects.find(effect)
var redo_data := {} var redo_data := {}
var undo_data := {} var undo_data := {}
for frame in Global.current_project.frames: for frame in project.frames:
var cel := frame.cels[layer.index] var cel := frame.cels[layer.index]
var new_image := ImageExtended.new()
var cel_image := cel.get_image() var cel_image := cel.get_image()
if cel is CelTileMap:
undo_data[cel] = (cel as CelTileMap).serialize_undo_data()
if cel_image is ImageExtended: if cel_image is ImageExtended:
new_image.is_indexed = cel_image.is_indexed
new_image.copy_from_custom(cel_image)
var image_size := new_image.get_size()
var shader_image_effect := ShaderImageEffect.new()
shader_image_effect.generate_image(new_image, effect.shader, effect.params, image_size)
if cel_image is ImageExtended:
redo_data[cel_image.indices_image] = new_image.indices_image.data
undo_data[cel_image.indices_image] = cel_image.indices_image.data undo_data[cel_image.indices_image] = cel_image.indices_image.data
redo_data[cel_image] = new_image.data
undo_data[cel_image] = cel_image.data undo_data[cel_image] = cel_image.data
Global.current_project.undos += 1 var image_size := cel_image.get_size()
Global.current_project.undo_redo.create_action("Apply layer effect") var shader_image_effect := ShaderImageEffect.new()
Global.undo_redo_compress_images(redo_data, undo_data) shader_image_effect.generate_image(cel_image, effect.shader, effect.params, image_size)
Global.current_project.undo_redo.add_do_method(func(): layer.effects.erase(effect)) if cel is CelTileMap:
Global.current_project.undo_redo.add_do_method(Global.canvas.queue_redraw) (cel as CelTileMap).update_tileset()
Global.current_project.undo_redo.add_do_method(Global.undo_or_redo.bind(false)) redo_data[cel] = (cel as CelTileMap).serialize_undo_data()
Global.current_project.undo_redo.add_undo_method(func(): layer.effects.insert(index, effect)) if cel_image is ImageExtended:
Global.current_project.undo_redo.add_undo_method(Global.canvas.queue_redraw) redo_data[cel_image.indices_image] = cel_image.indices_image.data
Global.current_project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true)) redo_data[cel_image] = cel_image.data
Global.current_project.undo_redo.commit_action() project.undos += 1
project.undo_redo.create_action("Apply layer effect")
project.deserialize_cel_undo_data(redo_data, undo_data)
project.undo_redo.add_do_method(func(): layer.effects.erase(effect))
project.undo_redo.add_do_method(Global.canvas.queue_redraw)
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))
project.undo_redo.add_undo_method(func(): layer.effects.insert(index, effect))
project.undo_redo.add_undo_method(Global.canvas.queue_redraw)
project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true))
project.undo_redo.commit_action()
effect_container.get_child(index).queue_free() effect_container.get_child(index).queue_free()

View file

@ -722,21 +722,25 @@ func _color_mode_submenu_id_pressed(id: ColorModes) -> void:
var old_color_mode := project.color_mode var old_color_mode := project.color_mode
var redo_data := {} var redo_data := {}
var undo_data := {} var undo_data := {}
var pixel_cels: Array[BaseCel]
# We need to do it this way because Godot
# doesn't like casting typed arrays into other types.
for cel in project.get_all_pixel_cels(): for cel in project.get_all_pixel_cels():
cel.get_image().add_data_to_dictionary(undo_data) pixel_cels.append(cel)
project.serialize_cel_undo_data(pixel_cels, undo_data)
# Change the color mode directly before undo/redo in order to affect the images, # Change the color mode directly before undo/redo in order to affect the images,
# so we can store them as redo data. # so we can store them as redo data.
if id == ColorModes.RGBA: if id == ColorModes.RGBA:
project.color_mode = Image.FORMAT_RGBA8 project.color_mode = Image.FORMAT_RGBA8
else: else:
project.color_mode = Project.INDEXED_MODE project.color_mode = Project.INDEXED_MODE
for cel in project.get_all_pixel_cels(): project.update_tilesets(undo_data)
cel.get_image().add_data_to_dictionary(redo_data) project.serialize_cel_undo_data(pixel_cels, redo_data)
project.undo_redo.create_action("Change color mode") project.undo_redo.create_action("Change color mode")
project.undos += 1 project.undos += 1
project.undo_redo.add_do_property(project, "color_mode", project.color_mode) project.undo_redo.add_do_property(project, "color_mode", project.color_mode)
project.undo_redo.add_undo_property(project, "color_mode", old_color_mode) project.undo_redo.add_undo_property(project, "color_mode", old_color_mode)
Global.undo_redo_compress_images(redo_data, undo_data, project) project.deserialize_cel_undo_data(redo_data, undo_data)
project.undo_redo.add_do_method(_check_color_mode_submenu_item.bind(project)) project.undo_redo.add_do_method(_check_color_mode_submenu_item.bind(project))
project.undo_redo.add_undo_method(_check_color_mode_submenu_item.bind(project)) project.undo_redo.add_undo_method(_check_color_mode_submenu_item.bind(project))
project.undo_redo.add_do_method(Global.undo_or_redo.bind(false)) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false))