diff --git a/src/Classes/ImageEffect.gd b/src/Classes/ImageEffect.gd index 3dd8e3a1b..1e159d5bd 100644 --- a/src/Classes/ImageEffect.gd +++ b/src/Classes/ImageEffect.gd @@ -47,49 +47,44 @@ func _about_to_show() -> void: func _confirmed() -> void: var project: Project = Global.current_project if affect == CEL: - # No changes if the layer is locked or invisible - if !project.layers[project.current_layer].can_layer_get_drawn(): - return - if project.selected_cels.size() == 1: - Global.canvas.handle_undo("Draw") - commit_action(current_cel) - Global.canvas.handle_redo("Draw") - else: - Global.canvas.handle_undo("Draw", project, -1, -1) - for cel_index in project.selected_cels: - var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]] - var cel_image: Image = cel.image - commit_action(cel_image) - Global.canvas.handle_redo("Draw", project, -1, -1) + var undo_data := _get_undo_data(project) + for cel_index in project.selected_cels: + if !project.layers[cel_index[1]].can_layer_get_drawn(): + continue + var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]] + var cel_image: Image = cel.image + commit_action(cel_image) + _commit_undo("Draw", undo_data, project) + elif affect == FRAME: - Global.canvas.handle_undo("Draw", project, -1) + var undo_data := _get_undo_data(project) var i := 0 for cel in project.frames[project.current_frame].cels: if project.layers[i].can_layer_get_drawn(): commit_action(cel.image) i += 1 - Global.canvas.handle_redo("Draw", project, -1) + _commit_undo("Draw", undo_data, project) elif affect == ALL_FRAMES: - Global.canvas.handle_undo("Draw", project, -1, -1) + var undo_data := _get_undo_data(project) for frame in project.frames: var i := 0 for cel in frame.cels: if project.layers[i].can_layer_get_drawn(): commit_action(cel.image) i += 1 - Global.canvas.handle_redo("Draw", project, -1, -1) + _commit_undo("Draw", undo_data, project) elif affect == ALL_PROJECTS: for _project in Global.projects: - Global.canvas.handle_undo("Draw", _project, -1, -1) + var undo_data := _get_undo_data(_project) for frame in _project.frames: var i := 0 for cel in frame.cels: if _project.layers[i].can_layer_get_drawn(): commit_action(cel.image, _project) i += 1 - Global.canvas.handle_redo("Draw", _project, -1, -1) + _commit_undo("Draw", undo_data, _project) func commit_action(_cel: Image, _project: Project = Global.current_project) -> void: @@ -100,6 +95,42 @@ func set_nodes() -> void: pass +func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: + var redo_data := _get_undo_data(project) + + project.undos += 1 + project.undo_redo.create_action(action) + for image in redo_data: + project.undo_redo.add_do_property(image, "data", redo_data[image]) + for image in undo_data: + project.undo_redo.add_undo_property(image, "data", undo_data[image]) + project.undo_redo.add_do_method(Global, "redo", -1, -1, project) + project.undo_redo.add_undo_method(Global, "undo", -1, -1, project) + project.undo_redo.commit_action() + + +func _get_undo_data(project: Project) -> Dictionary: + var data := {} + var images := _get_selected_draw_images(project) + for image in images: + image.unlock() + data[image] = image.data + return data + + +func _get_selected_draw_images(project: Project) -> Array: # Array of Images + var images := [] + if affect == CEL: + for cel_index in project.selected_cels: + var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]] + images.append(cel.image) + else: + for frame in project.frames: + for cel in frame.cels: + images.append(cel.image) + return images + + func _on_SelectionCheckBox_toggled(_button_pressed: bool) -> void: update_preview() @@ -124,8 +155,8 @@ func update_preview() -> void: func update_transparent_background_size() -> void: if !preview: return - var image_size_y = preview.rect_size.y - var image_size_x = preview.rect_size.x + var image_size_y := preview.rect_size.y + var image_size_x := preview.rect_size.x if preview_image.get_size().x > preview_image.get_size().y: var scale_ratio = preview_image.get_size().x / image_size_x image_size_y = preview_image.get_size().y / scale_ratio diff --git a/src/Classes/ShaderImageEffect.gd b/src/Classes/ShaderImageEffect.gd index 8ed8630a0..2f12408f5 100644 --- a/src/Classes/ShaderImageEffect.gd +++ b/src/Classes/ShaderImageEffect.gd @@ -45,7 +45,5 @@ func generate_image( VisualServer.free_rid(ci_rid) VisualServer.free_rid(mat_rid) viewport_texture.convert(Image.FORMAT_RGBA8) - #Global.canvas.handle_undo("Draw") _img.copy_from(viewport_texture) - #Global.canvas.handle_redo("Draw") emit_signal("done") diff --git a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd index 396e268ba..417f87d0b 100644 --- a/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd +++ b/src/UI/Dialogs/ImageEffects/FlipImageDialog.gd @@ -10,8 +10,8 @@ func set_nodes() -> void: affect_option_button = $VBoxContainer/OptionsContainer/AffectOptionButton -func commit_action(_cel: Image, project: Project = Global.current_project) -> void: - flip_image(_cel, selection_checkbox.pressed, project) +func commit_action(cel: Image, project: Project = Global.current_project) -> void: + _flip_image(cel, selection_checkbox.pressed, project) func _on_FlipHorizontal_toggled(_button_pressed: bool) -> void: @@ -22,35 +22,98 @@ func _on_FlipVertical_toggled(_button_pressed: bool) -> void: update_preview() -func flip_image(img: Image, affect_selection: bool, proj: Project = Global.current_project) -> void: - if !(affect_selection and proj.has_selection): +func _flip_image(cel: Image, affect_selection: bool, project: Project) -> void: + if !(affect_selection and project.has_selection): if flip_h.pressed: - img.flip_x() + cel.flip_x() if flip_v.pressed: - img.flip_y() + cel.flip_y() else: # Create a temporary image that only has the selected pixels in it - var selected_image := Image.new() - selected_image.create(img.get_width(), img.get_height(), false, Image.FORMAT_RGBA8) - selected_image.lock() - img.lock() - for x in img.get_width(): - for y in img.get_width(): + var selected := Image.new() + var rectangle: Rect2 = Global.canvas.selection.big_bounding_rectangle + if project != Global.current_project: + rectangle = project.get_selection_rectangle() + selected = cel.get_rect(rectangle) + selected.lock() + cel.lock() + for x in selected.get_width(): + for y in selected.get_height(): var pos := Vector2(x, y) - if proj.can_pixel_get_drawn(pos): - var color: Color = img.get_pixelv(pos) - selected_image.set_pixelv(pos, color) - img.set_pixelv(pos, Color(0, 0, 0, 0)) + var cel_pos := pos + rectangle.position + if project.can_pixel_get_drawn(cel_pos): + cel.set_pixelv(cel_pos, Color(0, 0, 0, 0)) + else: + selected.set_pixelv(pos, Color(0, 0, 0, 0)) + selected.unlock() + cel.unlock() if flip_h.pressed: - selected_image.flip_x() + selected.flip_x() if flip_v.pressed: - selected_image.flip_y() - selected_image.unlock() - img.blit_rect_mask( - selected_image, - selected_image, - Rect2(Vector2.ZERO, selected_image.get_size()), - Vector2.ZERO - ) - img.unlock() + selected.flip_y() + cel.blend_rect(selected, Rect2(Vector2.ZERO, selected.get_size()), rectangle.position) + + +func _commit_undo(action: String, undo_data: Dictionary, project: Project) -> void: + _flip_selection(project) + + var redo_data := _get_undo_data(project) + project.undos += 1 + project.undo_redo.create_action(action) + project.undo_redo.add_do_property(project, "selection_bitmap", redo_data["selection_bitmap"]) + project.undo_redo.add_do_property(project, "selection_offset", redo_data["outline_offset"]) + project.undo_redo.add_undo_property(project, "selection_bitmap", undo_data["selection_bitmap"]) + project.undo_redo.add_undo_property(project, "selection_offset", undo_data["outline_offset"]) + + for image in redo_data: + if not image is Image: + continue + project.undo_redo.add_do_property(image, "data", redo_data[image]) + image.unlock() + for image in undo_data: + if not image is Image: + continue + project.undo_redo.add_undo_property(image, "data", undo_data[image]) + project.undo_redo.add_do_method(Global, "redo", -1, -1, project) + project.undo_redo.add_do_method(project, "selection_bitmap_changed") + project.undo_redo.add_undo_method(Global, "undo", -1, -1, project) + project.undo_redo.add_undo_method(project, "selection_bitmap_changed") + project.undo_redo.commit_action() + + +func _get_undo_data(project: Project) -> Dictionary: + var data := {} + data["selection_bitmap"] = project.selection_bitmap.duplicate() + data["outline_offset"] = project.selection_offset + + var images := _get_selected_draw_images(project) + for image in images: + image.unlock() + data[image] = image.data + + return data + + +func _flip_selection(project: Project = Global.current_project) -> void: + if !(selection_checkbox.pressed and project.has_selection): + return + + var bitmap_image: Image = project.bitmap_to_image(project.selection_bitmap) + var selection_rect := bitmap_image.get_used_rect() + var smaller_bitmap_image := bitmap_image.get_rect(selection_rect) + + if flip_h.pressed: + smaller_bitmap_image.flip_x() + if flip_v.pressed: + smaller_bitmap_image.flip_y() + + bitmap_image.fill(Color(0, 0, 0, 0)) + bitmap_image.blend_rect( + smaller_bitmap_image, + Rect2(Vector2.ZERO, smaller_bitmap_image.get_size()), + selection_rect.position + ) + var bitmap_copy: BitMap = project.selection_bitmap.duplicate() + bitmap_copy.create_from_image_alpha(bitmap_image) + project.selection_bitmap = bitmap_copy