From 1d35198a250f39d93fb3cc6aa0c4f1e53a4e1481 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Sun, 29 Oct 2023 16:55:22 +0500 Subject: [PATCH 1/4] Ask user if they wish to delete Extensions permanently or not (#919) * don't delete extensions permanently * some further improvements to the previous commit * add a tab to make log reading easier * move to bin on uninstall * attemp fix formatting * attemp fix formatting * attemp fix formatting * attempt fix formatting * attempt fix formatting * attempt fix formatting * attempt fix formatting * Ask user if they prefer their extensions fried or disintegrated * removed accidental change * formatting * fix uninstall dialog not apearing (missed it due to a small blunder) --- src/Preferences/HandleExtensions.gd | 65 ++++++++++++++++++++------ src/Preferences/PreferencesDialog.tscn | 21 ++++++++- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/Preferences/HandleExtensions.gd b/src/Preferences/HandleExtensions.gd index 6e441f6e4..ea27bb525 100644 --- a/src/Preferences/HandleExtensions.gd +++ b/src/Preferences/HandleExtensions.gd @@ -1,6 +1,10 @@ extends Control +enum UninstallMode { KEEP_FILE, FILE_TO_BIN, REMOVE_PERMANENT } + const EXTENSIONS_PATH := "user://extensions" +const BUG_EXTENSIONS_PATH := "user://give_in_bug_report" +const BIN_ACTION := "trash" var extensions := {} ## Extension name: Extension class var extension_selected := -1 @@ -10,6 +14,7 @@ var damaged_extension: String @onready var enable_button: Button = $HBoxContainer/EnableButton @onready var uninstall_button: Button = $HBoxContainer/UninstallButton @onready var extension_parent: Node = Global.control.get_node("Extensions") +@onready var delete_confirmation: ConfirmationDialog = %DeleteConfirmation class Extension: @@ -40,6 +45,7 @@ class Extension: func _ready() -> void: + delete_confirmation.add_button(tr("Move to Trash"), false, BIN_ACTION) if OS.get_name() == "Web": $HBoxContainer/AddExtensionButton.disabled = true $HBoxContainer/OpenFolderButton.visible = false @@ -74,9 +80,18 @@ func install_extension(path: String) -> void: _add_extension(file_name) -func _uninstall_extension(file_name := "", remove_file := true, item := extension_selected) -> void: - if remove_file: - var err := DirAccess.remove_absolute(EXTENSIONS_PATH.path_join(file_name)) +func _uninstall_extension( + file_name := "", remove_mode := UninstallMode.REMOVE_PERMANENT, item := extension_selected +) -> void: + var err := OK + match remove_mode: + UninstallMode.FILE_TO_BIN: + err = OS.move_to_trash( + ProjectSettings.globalize_path(EXTENSIONS_PATH).path_join(file_name) + ) + UninstallMode.REMOVE_PERMANENT: + err = DirAccess.remove_absolute(EXTENSIONS_PATH.path_join(file_name)) + if remove_mode != UninstallMode.KEEP_FILE: if err != OK: print(err) return @@ -94,16 +109,21 @@ func _uninstall_extension(file_name := "", remove_file := true, item := extensio func _add_extension(file_name: String) -> void: var tester_file: FileAccess # For testing and deleting damaged extensions - var remover_directory := DirAccess.open(EXTENSIONS_PATH) # Remove any extension that was proven guilty before this extension is loaded - if remover_directory.file_exists(EXTENSIONS_PATH.path_join("Faulty.txt")): + if FileAccess.file_exists(EXTENSIONS_PATH.path_join("Faulty.txt")): # This code will only run if pixelorama crashed var faulty_path := EXTENSIONS_PATH.path_join("Faulty.txt") tester_file = FileAccess.open(faulty_path, FileAccess.READ) damaged_extension = tester_file.get_as_text() tester_file.close() - remover_directory.remove(EXTENSIONS_PATH.path_join(damaged_extension)) - remover_directory.remove(EXTENSIONS_PATH.path_join("Faulty.txt")) + # don't delete the extension permanently + # (so that it may be given to the developer in the bug report) + DirAccess.make_dir_recursive_absolute(BUG_EXTENSIONS_PATH) + DirAccess.rename_absolute( + EXTENSIONS_PATH.path_join(damaged_extension), + BUG_EXTENSIONS_PATH.path_join(damaged_extension) + ) + DirAccess.remove_absolute(EXTENSIONS_PATH.path_join("Faulty.txt")) # Don't load a deleted extension if damaged_extension == file_name: @@ -125,7 +145,7 @@ func _add_extension(file_name: String) -> void: if item == -1: print("Failed to find %s" % file_name) return - _uninstall_extension(file_name, false, item) + _uninstall_extension(file_name, UninstallMode.KEEP_FILE, item) # Wait two frames so the previous nodes can get freed await get_tree().process_frame await get_tree().process_frame @@ -134,11 +154,14 @@ func _add_extension(file_name: String) -> void: var file_path := EXTENSIONS_PATH.path_join(file_name) var success := ProjectSettings.load_resource_pack(file_path) if !success: - print("Failed loading resource pack.") - var dir := DirAccess.open(EXTENSIONS_PATH) - dir.remove(file_path) + # Don't delete the extension + # Context: pixelorama deletes v0.11.x extensions when you open v1.0, this will prevent it. +# OS.move_to_trash(file_path) + print("EXTENSION ERROR: Failed loading resource pack %s." % file_name) + print(" There may be errors in extension code or extension is incompatible") + # Delete the faulty.txt, (it's fate has already been decided) + DirAccess.remove_absolute(EXTENSIONS_PATH.path_join("Faulty.txt")) return - var extension_path := "res://src/Extensions/%s/" % file_name_no_ext var extension_config_file_path := extension_path.path_join("extension.json") var extension_config_file := FileAccess.open(extension_config_file_path, FileAccess.READ) @@ -176,7 +199,7 @@ func _add_extension(file_name: String) -> void: Global.dialog_open(true) print("Incompatible API") # Don't put it in faulty, (it's merely incompatible) - remover_directory.remove(EXTENSIONS_PATH.path_join("Faulty.txt")) + DirAccess.remove_absolute(EXTENSIONS_PATH.path_join("Faulty.txt")) return var extension := Extension.new() @@ -192,7 +215,7 @@ func _add_extension(file_name: String) -> void: # If an extension doesn't crash pixelorama then it is proven innocent # And we should now delete its "Faulty.txt" file - remover_directory.remove(EXTENSIONS_PATH.path_join("Faulty.txt")) + DirAccess.remove_absolute(EXTENSIONS_PATH.path_join("Faulty.txt")) func _enable_extension(extension: Extension, save_to_config := true) -> void: @@ -259,7 +282,7 @@ func _on_EnableButton_pressed() -> void: func _on_UninstallButton_pressed() -> void: - _uninstall_extension(extension_list.get_item_metadata(extension_selected)) + delete_confirmation.popup_centered() func _on_OpenFolderButton_pressed() -> void: @@ -269,3 +292,15 @@ func _on_OpenFolderButton_pressed() -> void: func _on_AddExtensionFileDialog_files_selected(paths: PackedStringArray) -> void: for path in paths: install_extension(path) + + +func _on_delete_confirmation_custom_action(action: StringName) -> void: + if action == BIN_ACTION: + _uninstall_extension( + extension_list.get_item_metadata(extension_selected), UninstallMode.FILE_TO_BIN + ) + delete_confirmation.hide() + + +func _on_delete_confirmation_confirmed() -> void: + _uninstall_extension(extension_list.get_item_metadata(extension_selected)) diff --git a/src/Preferences/PreferencesDialog.tscn b/src/Preferences/PreferencesDialog.tscn index 0ea68fdb5..bd35a8e70 100644 --- a/src/Preferences/PreferencesDialog.tscn +++ b/src/Preferences/PreferencesDialog.tscn @@ -23,11 +23,11 @@ anchor_bottom = 1.0 offset_left = 8.0 offset_top = 8.0 offset_right = -8.0 -offset_bottom = -36.0 +offset_bottom = -49.0 size_flags_horizontal = 3 theme_override_constants/separation = 20 theme_override_constants/autohide = 0 -split_offset = 1 +split_offset = 150 [node name="List" type="ItemList" parent="HSplitContainer"] custom_minimum_size = Vector2(85, 0) @@ -1300,6 +1300,21 @@ access = 2 filters = PackedStringArray("*.pck ; Godot Resource Pack File", "*.zip ;") show_hidden_files = true +[node name="DeleteConfirmation" type="ConfirmationDialog" parent="."] +unique_name_in_owner = true +position = Vector2i(0, 36) +size = Vector2i(500, 100) +ok_button_text = "Delete Permanently" + +[node name="Label" type="Label" parent="DeleteConfirmation"] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 492.0 +offset_bottom = 51.0 +text = "Delete Extension?" +horizontal_alignment = 1 +vertical_alignment = 1 + [connection signal="about_to_popup" from="." to="." method="_on_PreferencesDialog_about_to_show"] [connection signal="visibility_changed" from="." to="." method="_on_PreferencesDialog_visibility_changed"] [connection signal="item_selected" from="HSplitContainer/List" to="." method="_on_List_item_selected"] @@ -1312,3 +1327,5 @@ show_hidden_files = true [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/HBoxContainer/UninstallButton" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_UninstallButton_pressed"] [connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/HBoxContainer/OpenFolderButton" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_OpenFolderButton_pressed"] [connection signal="files_selected" from="Popups/AddExtensionFileDialog" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_AddExtensionFileDialog_files_selected"] +[connection signal="confirmed" from="DeleteConfirmation" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_delete_confirmation_confirmed"] +[connection signal="custom_action" from="DeleteConfirmation" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_delete_confirmation_custom_action"] From 72a159aef4203d7e70264dc17e68cf4670f91d2a Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas Date: Mon, 30 Oct 2023 14:33:28 +0200 Subject: [PATCH 2/4] [skip ci] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c772d28..97a83b42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [v1.0] - Unreleased +This update has been brought to you by the contributions of: +Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)) Built using Godot 4.1.2 ### Added +- Support for multiple layer blend modes are finally here! [#911](https://github.com/Orama-Interactive/Pixelorama/pull/911) - Export to webp and jpeg file formats. Webp is currently only for static images and does not support animations. - Added some missing shortcuts for buttons. [#900](https://github.com/Orama-Interactive/Pixelorama/pull/900) - The brush increment/decrement shortcuts can now be changed. [#900](https://github.com/Orama-Interactive/Pixelorama/pull/900) @@ -19,6 +22,7 @@ Built using Godot 4.1.2 ### Changed - The color picker has been vastly improved, thanks to the update to Godot 4. Users can now use the OKHSL color mode, and choose between four different picker shapes: HSV Rectangle (default), HSV Wheel, VHS Circle and OKHSL Circle. - Every shader-based image effect is automatically working without the need to change renderers, and they all work now on the Web version. This comes at the cost of less compatibility, as the desktop version now requires OpenGL 3.3 minimum instead of 2.1, and the Web version requires WebGL 2 instead of WebGL 1. [#900](https://github.com/Orama-Interactive/Pixelorama/pull/900) +- When deleting an extension, a confirmation window now appears that lets users either to delete the palette permanently, move it to trash, or cancel. [#919](https://github.com/Orama-Interactive/Pixelorama/pull/919) ### Fixed - Performance when drawing and doing operations such as bucket area fill should be better now. [#900](https://github.com/Orama-Interactive/Pixelorama/pull/900) @@ -36,6 +40,7 @@ Built using Godot 3.5.2 ### Fixed - Fixed undo/redo history not working when the tool changes. [#916](https://github.com/Orama-Interactive/Pixelorama/pull/916) - Pixelorama no longer closes when the project fails to be saved if "Save & Exit" is selected. [#920](https://github.com/Orama-Interactive/Pixelorama/pull/920) +- Projects with 3D cels saved in 1.x can now be opened in 0.11.3. [#928](https://github.com/Orama-Interactive/Pixelorama/pull/928) ## [v0.11.2] - 2023-08-31 This update has been brought to you by the contributions of: From 76e8dfeaaf56bceeb6cff10c2fa980d0b3a88a45 Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:53:33 +0200 Subject: [PATCH 3/4] [skip ci] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97a83b42c..72a089b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ Built using Godot 4.1.2 - Performance when drawing and doing operations such as bucket area fill should be better now. [#900](https://github.com/Orama-Interactive/Pixelorama/pull/900) - Dividing by zero in value sliders and spinboxes no longer crashes the program. -## [v0.11.3] - Unreleased +## [v0.11.3] - 2023-10-30 This update has been brought to you by the contributions of: Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)) From 58e694abecec7b387fb19f71ced7d66bda468d9b Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas Date: Tue, 31 Oct 2023 14:06:59 +0200 Subject: [PATCH 4/4] Optimize canvas drawing by only calling queue_redraw when the image has changed --- src/Tools/3DShapeEdit.gd | 1 + src/UI/Canvas/Canvas.gd | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Tools/3DShapeEdit.gd b/src/Tools/3DShapeEdit.gd index 4e1871bf7..356ec338d 100644 --- a/src/Tools/3DShapeEdit.gd +++ b/src/Tools/3DShapeEdit.gd @@ -77,6 +77,7 @@ var _object_names := { func sprite_changed_this_frame(): _checker_update_qued = true _old_cel_image = _cel.get_image() + Global.canvas.sprite_changed_this_frame = true func _input(_event: InputEvent) -> void: diff --git a/src/UI/Canvas/Canvas.gd b/src/UI/Canvas/Canvas.gd index c504040fd..0841d4588 100644 --- a/src/UI/Canvas/Canvas.gd +++ b/src/UI/Canvas/Canvas.gd @@ -69,7 +69,7 @@ func _input(event: InputEvent) -> void: ): return - var tmp_position: Vector2 = Global.main_viewport.get_local_mouse_position() + var tmp_position := Global.main_viewport.get_local_mouse_position() if get_velocity: var velocity := Input.get_vector( "move_mouse_left", "move_mouse_right", "move_mouse_up", "move_mouse_down" @@ -82,14 +82,12 @@ func _input(event: InputEvent) -> void: var tmp_transform := get_canvas_transform().affine_inverse() current_pixel = tmp_transform.basis_xform(tmp_position) + tmp_transform.origin - if Global.has_focus: - queue_redraw() - sprite_changed_this_frame = false - Tools.handle_draw(Vector2i(current_pixel.floor()), event) if sprite_changed_this_frame: + if Global.has_focus: + queue_redraw() update_selected_cels_textures() @@ -106,7 +104,7 @@ func update_texture(layer_i: int, frame_i := -1, project := Global.current_proje frame_i = project.current_frame if frame_i < project.frames.size() and layer_i < project.layers.size(): - var current_cel: BaseCel = project.frames[frame_i].cels[layer_i] + var current_cel := project.frames[frame_i].cels[layer_i] current_cel.update_texture() @@ -115,7 +113,7 @@ func update_selected_cels_textures(project := Global.current_project) -> void: var frame_index: int = cel_index[0] var layer_index: int = cel_index[1] if frame_index < project.frames.size() and layer_index < project.layers.size(): - var current_cel: BaseCel = project.frames[frame_index].cels[layer_index] + var current_cel := project.frames[frame_index].cels[layer_index] current_cel.update_texture() @@ -129,7 +127,8 @@ func draw_layers() -> void: for i in Global.current_project.layers.size(): if current_cels[i] is GroupCel: continue - if Global.current_project.layers[i].is_visible_in_hierarchy(): + var layer := Global.current_project.layers[i] + if layer.is_visible_in_hierarchy(): var cel_image := current_cels[i].get_image() textures.append(cel_image) opacities.append(current_cels[i].opacity) @@ -137,7 +136,7 @@ func draw_layers() -> void: origins.append(Vector2(move_preview_location) / Vector2(cel_image.get_size())) else: origins.append(Vector2.ZERO) - blend_modes.append(Global.current_project.layers[i].blend_mode) + blend_modes.append(layer.blend_mode) var texture_array := Texture2DArray.new() texture_array.create_from_images(textures) material.set_shader_parameter("layers", texture_array)