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

426 lines
14 KiB
GDScript3
Raw Normal View History

2019-08-18 09:28:38 +00:00
extends Control
var opensprite_file_selected := false
var redone := false
var is_quitting_on_save := false
var cursor_image: Texture = preload("res://assets/graphics/cursor.png")
2021-11-22 19:32:39 +00:00
onready var ui := $MenuAndUI/UI/DockableContainer
onready var backup_confirmation: ConfirmationDialog = $Dialogs/BackupConfirmation
onready var quit_dialog: ConfirmationDialog = $Dialogs/QuitDialog
onready var quit_and_save_dialog: ConfirmationDialog = $Dialogs/QuitAndSaveDialog
onready var left_cursor: Sprite = $LeftCursor
onready var right_cursor: Sprite = $RightCursor
2022-03-21 23:48:14 +00:00
func _init() -> void:
Global.shrink = _get_auto_display_scale()
2022-03-21 23:48:14 +00:00
if OS.get_name() == "OSX":
_use_osx_shortcuts()
2019-08-18 09:28:38 +00:00
func _ready() -> void:
randomize()
get_tree().set_auto_accept_quit(false)
_setup_application_window_size()
Global.window_title = tr("untitled") + " - Pixelorama " + Global.current_version
Basic Layer Groups and Timeline Refactor (#698) * Fixed issues with Shading tool Saturation and Value not always being right in Hue Shading mode * Shading tool hue shifting fixes and tweaks * Bringing over changes from layer groups brach, without any changes to layer blending * Some quick fixes to make it work again * Fixed some of the places where GroupLayers cause errors. Cel Buttons are now hidden when groups are collapsed * Layer drag highlighting (need to actually drop them correctly, also need to do cels) * Added more layer hierarchy related functions, organized the function order in the Layer classes a bit * Switched the layer type changing from string to int * Moved layer type enum to Global * Added get_layer_type_name(), currently used for the default layer name * Renamed the layer get_children/is_a_parent_of functions * changed get_layer_type_name() to get_default_name(number) * New layer drag and dropping behavior * Added read/write_image_data_from/to_pxo functions to Cel classes to handle saving/loading the binary image data for each cel type * Fixed warning * Added a line to child layers wich makes it easier to see where they are in the hierarchy * Fixed debugger warning * Fixed all cel types loading as PixelCels * Fixed spacing issue with cels when collapsing groups * Fixed bug when dropping a child layer to the bottom region of its parent group, where it would end up to far down (maybe disappearing) * updated temporary todo comments * Created a base scene for layer buttons and merged layer button script into one * Prevent the case of parenting to itself in layer drag and drop, fixed static reference to LayerButton still being BaseLayerButton * Use a base scene for CelButtons * First bit of the refactoring work * Several bits of refactoring * Fixed moving cels * Cleaned up Project.move_cel function * Fixed project_layer_removed * Updated change_frame_order on FrameButton. Some (not all) work on getting the layer UI updated when pressing buttons such as collapse/visible/lock * Bug fixes. Updating layer button's buttons * Fixed timeline selection issues when creating a new project. Some code cleanup * tweaks * Removed a bunch of commented out code * Removing more commented out code * Fixed bugs with timeline selectio. Fixed cels being placed in the reverse layer order when adding a frame * Changed add/remove_frame to add/remove_frames (multiple support) * Refactored copy_frames in animation timeline * added copy function to cel classes * added layer copy function * simplifed copy_frames a tiny bit * Updated TODO comments to categorize them and remove any that were already done * Turned Project.add/remove_layer into Project.add/remove_layers (multiple support), not yet tested * Seperated the layer cloning functionality in timeline's add_layer to its own function, since they're only used by one button, renamed to _on_Button_pressed naming scheme, added children support to the delete layer button * some TODOs * Added layer swapping * Added priorities to refactor TODOs * Simplified layer swapping code a little * Fixed performance regression on changing project, updated TODOs * Included _on_MergeDownLayer_pressed in timeline refactor * Cleaned up _on_MergeDownLayer_pressed refactor * If all frames are selected, prevent being able to remove all of them * Fixed cel linking when cloning layers/frames. Moved the copy function from cel classes to layer classes, splitting into copy_cel and copy_all_cels * Combined and rewrote the 2 project _toggle_layer_buttons_.. functions into 1 simpler _toggle_layer_buttons function * Simplified _toggle_layer_buttons some more * Added hierarchy support for move up/down layer buttons * Added toggle_frame_buttons method to project (extracted from _frame_changed). Called from main when setting up startup project. Removed _ from start of _toggle_layer_buttons name * Fixed duplicate_layers parent references being to the original layers * cleaned up project.move_layers method a bit * TODOs * moved the transform_content_confirm calls for the layer buttons in AnimationTimeline (Add/remove/clone) to the project layer modification functions * animation first/last_frame tweaks and un-press play buttons when the first/last_frame are the same in _on_AnimationTimer_timeout in AnimationTimeline * Cleaned up project_changed in ANimationTimeline a bit * Cleaned up project_layer_added in AnimationTimeline * Changed Layer classes get_default_name to set_name_to_default * Cleaned up LayerButton.drop_data slightly * Looked at some of my TODOs * cleaned up copying cels * Fixed CelButton linked_indicator not showing up right away when becoming linked * Cleand up link/unlink cel menu option a little. Fixed situatoin where trying to call button_setup on cel_button that doesn't exist anymore due to undo/redo * Fixed regression with copy_cel (linked) in when cloning a frame * Minor cleanup, more detailed comments, updated TODOs * more improved comments * Made focus_mode on Cel/Layer/FrameButton NONE to fix bug where it looks like one is selected after pressing it and adding a new Layer/Frame (but its just in the focus state, not the pressed state * Made AnimationTimeline.change_layer_order work a little more consistantly with LayerButton.drop_data, and fixed a minor bug in it * Updated comments and TODOs * cleanup * removed some code that should no longer be needed * updated comment * removed Project's frames and layers setters _frames_changed and _layers_changed * Made some 'for x in range(array.size())' just 'for x in array.size()' * updated comments/TODOs * Cel content changes intial * Added 'content' methods to Cel classes * Removed image var from PixelCelButton * Reusing PixelCelButton.gd on GroupCelButton scene * Renamed PixelCelButton.gd to CelButton.gd (as it will be used for all Cel Buttons) and deleted GroupCelButton.gd * Hide the TransparentChecker on GroupCelButton.tscn until a preview texture is added for GroupCels * TODOs, prevent memory leak when closing projects * Link/unlink cel cleanup : * Added _project param to _init methods of Layer classes * Added update_texture method to Cel classes (moving part from the update_texture and update_selected_cels_textures methods from Canvas.gd * Removed a temporary check (which also fixed another bug) * Clone child layers when cloning a layer * Added temp dummy get_image method to GroupCel, and use get_image when copying or picking colors * TODOs * Made open_image_as_spritesheet_layer work after the timeline refactor (still doesn't work with groups yet though). TODO comment updates * Added create_new_cel methods to Layer classes * Updated TODOs and comments * Renamed Layer class's create_empty_cel to new_empty_cel to match Project's new_emtpy_frame * Renamed create_layer/cel_button to instantiate_layer/cel_button * updated TODOs * prioritized TODOs * Fixed some warnings * removed commented out code from previous commit * Fixed export * Made open_image_as_new_frame work after timeline refactor * Fixed open_image_as_new_layer after timeline refactor * Some linked cel fixes * More linked cels fixes * cleanup * Optimized importing spreadsheet as new layer * Fixed Scale Image crash with Groups * Fixed onion skin with groups * Removed blend_mode from BaseLayer for now * Mostly fixed image effects * Fixed resize canvas * Fixed drag and drop not working with Cel Buttons on Group Layers * updated TODOs * Renamed Replace Frame (in open image) to Replace Cel * Continued renaming Replace Frame to Replace Cel * Made open_image_at_cels work after timeline refactor * Added get_layer_path method to BaseLayer * Replaced AtLayerSpinbox with AtLayerOption for Open Image as New Frame or Replace Cel * Updated TODOs * updated TODOs * Comments for cel content methods * fixed right clicking group cel button deselecting the button (even though cel is still selected * frame/layer modification methods comments * Removed unneeded size flags * TODO updates * Removed a loop that would never run from open_image_as_spritesheet_tab * TODO update * Combined BaseLayer.get_children_direct and get_children_recursive into a single get_children method with a bool for recursive. Added a get_child_count method * Removed unneeded frame paramaters from _on_DeleteFrame_pressed and _on_CopyFrame_pressed * TODO Updates * Removed unneeded code from delete_frames * Made delete_frames variable names more consistent with my other changes * Continuation * made variable names in copy_frames more consistent with rest of changes * Update TODOs * Removed TODOs for after this PR (moved to my notes) * Fixed crash when pasting image on Group * Fixed layer .visible check to be is_visible_in_hierarchy() * Removed some drag highlight polish code that didn't work * Removed code from Canvas update_texture and update_selected_cels_textures that was redundant * gdformat * gdformat * gdlint fixes * Fixed Cel button not having its linked indicator show when enabling new cels linked on a layer other than the current layer * Fixed crop image and centralize image * Added '# gdlint: ignore=max-public-methods' to the top of Project' * Fixed dragging cels to layer of different type crash * Formatted CelButton.gd Co-authored-by: MrTriPie <MrTriPie>
2022-09-28 18:59:49 +00:00
Global.current_project.layers.append(PixelLayer.new(Global.current_project))
Global.current_project.frames.append(Global.current_project.new_empty_frame())
Global.animation_timeline.project_changed()
Global.current_project.toggle_frame_buttons()
Import.import_brushes(Global.directory_module.get_brushes_search_path_in_order())
Import.import_patterns(Global.directory_module.get_patterns_search_path_in_order())
quit_and_save_dialog.add_button("Exit without saving", false, "ExitWithoutSaving")
quit_and_save_dialog.get_ok().text = "Save & Exit"
Global.open_sprites_dialog.current_dir = Global.config_cache.get_value(
"data", "current_dir", OS.get_system_dir(OS.SYSTEM_DIR_DESKTOP)
)
Global.save_sprites_dialog.current_dir = Global.config_cache.get_value(
"data", "current_dir", OS.get_system_dir(OS.SYSTEM_DIR_DESKTOP)
)
(Port) Port Pixelorama to Ubuntu Touch (#517) * Add support for creating Ubuntu Touch click packages. The clickable directory contains the files necessary to create a click package designed for Ubuntu Touch, a community-driven Linux distro for mobile phones as an alternative to iOS and Android. A new CI script has been added to create the packages, which is copied over from one of my other projects. Please change this to suit your needs. A new custom feature "clickable" has been added to the project settings to allow customizations for the Ubuntu Touch platform. Signed-off-by: Marquis Kurt <software@marquiskurt.net> * Make clickable CI follow more closely to desktop builds * Remove sudo from clickable install step * Install software-properties-common * Comment out docker startups in click install * Change export name for Click version * Change name and export mode to pack only * Change means of copying data to clickable dir * Install sudo to docker * Add -g to docker add user * Remove docker user creation * Remove other chpasswd stuff * Split CI into two jobs * Make build-ubports.sh runnable * Use HiPDI GUI theme on Clickable * Move clickable folder to Misc, add release CI targets * Add mobile to clickable settings * Add pixelorama_data to install data * Create pixelorama_data subdir in click itself * Change default save dir for clickable * Update AppArmor policy * Update clickable version to test AppArmor * Revert changes and use user data dir * Add README pertaining to Ubuntu Touch * Remove GODOT_MAC_VERSION from UT port workflow Co-authored-by: Manolis Papadeas <35376950+OverloadedOrama@users.noreply.github.com>
2021-09-25 10:42:31 +00:00
# FIXME: OS.get_system_dir does not grab the correct directory for Ubuntu Touch.
# Additionally, AppArmor policies prevent the app from writing to the /home
# directory. Until the proper AppArmor policies are determined to write to these
# files accordingly, use the user data folder where cache.ini is stored.
# Ubuntu Touch users can access these files in the File Manager at the directory
# ~/.local/pixelorama.orama-interactive/godot/app_userdata/Pixelorama.
if OS.has_feature("clickable"):
Global.open_sprites_dialog.current_dir = OS.get_user_data_dir()
Global.save_sprites_dialog.current_dir = OS.get_user_data_dir()
2021-11-22 19:32:39 +00:00
var i := 0
for camera in Global.cameras:
camera.index = i
i += 1
var zstd_checkbox := CheckBox.new()
zstd_checkbox.name = "ZSTDCompression"
zstd_checkbox.pressed = true
zstd_checkbox.text = "Use ZSTD Compression"
zstd_checkbox.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
Global.save_sprites_dialog.get_vbox().add_child(zstd_checkbox)
_handle_backup()
_handle_cmdline_arguments()
get_tree().connect("files_dropped", self, "_on_files_dropped")
if OS.get_name() == "Android":
OS.request_permissions()
_show_splash_screen()
func _input(event: InputEvent) -> void:
left_cursor.position = get_global_mouse_position() + Vector2(-32, 32)
right_cursor.position = get_global_mouse_position() + Vector2(32, 32)
if event is InputEventKey and (event.scancode == KEY_ENTER or event.scancode == KEY_KP_ENTER):
if get_focus_owner() is LineEdit:
get_focus_owner().release_focus()
# Taken from https://github.com/godotengine/godot/blob/3.x/editor/editor_settings.cpp#L1474
func _get_auto_display_scale() -> float:
if OS.get_name() == "OSX":
return OS.get_screen_max_scale()
var dpi := OS.get_screen_dpi()
var smallest_dimension: int = min(OS.get_screen_size().x, OS.get_screen_size().y)
if dpi >= 192 && smallest_dimension >= 1400:
return 2.0 # hiDPI display.
elif smallest_dimension >= 1700:
return 1.5 # Likely a hiDPI display, but we aren't certain due to the returned DPI.
return 1.0
func _setup_application_window_size() -> void:
get_tree().set_screen_stretch(
SceneTree.STRETCH_MODE_DISABLED,
SceneTree.STRETCH_ASPECT_IGNORE,
Vector2(1024, 576),
Global.shrink
)
set_custom_cursor()
if OS.get_name() == "HTML5":
return
# Set a minimum window size to prevent UI elements from collapsing on each other.
OS.min_window_size = Vector2(1024, 576)
# Restore the window position/size if values are present in the configuration cache
if Global.config_cache.has_section_key("window", "screen"):
OS.current_screen = Global.config_cache.get_value("window", "screen")
if Global.config_cache.has_section_key("window", "maximized"):
OS.window_maximized = Global.config_cache.get_value("window", "maximized")
if !OS.window_maximized:
if Global.config_cache.has_section_key("window", "position"):
OS.window_position = Global.config_cache.get_value("window", "position")
if Global.config_cache.has_section_key("window", "size"):
OS.window_size = Global.config_cache.get_value("window", "size")
func set_custom_cursor() -> void:
if Global.native_cursors:
return
if Global.shrink == 1.0:
Input.set_custom_mouse_cursor(cursor_image, Input.CURSOR_CROSS, Vector2(15, 15))
else:
var cursor_data := cursor_image.get_data()
cursor_data.resize(
cursor_data.get_width() * Global.shrink, cursor_data.get_height() * Global.shrink, 0
)
var new_cursor_tex := ImageTexture.new()
new_cursor_tex.create_from_image(cursor_data, 0)
Input.set_custom_mouse_cursor(
new_cursor_tex, Input.CURSOR_CROSS, Vector2(15, 15) * Global.shrink
)
func _show_splash_screen() -> void:
if not Global.config_cache.has_section_key("preferences", "startup"):
Global.config_cache.set_value("preferences", "startup", true)
if Global.config_cache.get_value("preferences", "startup"):
# Wait for the window to adjust itself, so the popup is correctly centered
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
$Dialogs/SplashDialog.popup_centered() # Splash screen
modulate = Color(0.5, 0.5, 0.5)
else:
Global.can_draw = true
func _handle_backup() -> void:
2021-11-25 17:10:04 +00:00
# If backup file exists, Pixelorama was not closed properly (probably crashed) - reopen backup
backup_confirmation.add_button("Discard All", false, "discard")
if Global.config_cache.has_section("backups"):
var project_paths = Global.config_cache.get_section_keys("backups")
if project_paths.size() > 0:
# Get backup paths
var backup_paths := []
for p_path in project_paths:
backup_paths.append(Global.config_cache.get_value("backups", p_path))
# Temporatily stop autosave until user confirms backup
OpenSave.autosave_timer.stop()
backup_confirmation.connect(
"confirmed", self, "_on_BackupConfirmation_confirmed", [project_paths, backup_paths]
)
backup_confirmation.connect(
"custom_action",
self,
"_on_BackupConfirmation_custom_action",
[project_paths, backup_paths]
)
backup_confirmation.popup_centered()
Global.can_draw = false
modulate = Color(0.5, 0.5, 0.5)
else:
if Global.open_last_project:
load_last_project()
else:
if Global.open_last_project:
load_last_project()
func _handle_cmdline_arguments() -> void:
var args := OS.get_cmdline_args()
if args.empty():
return
for arg in args:
if arg.begins_with("-") or arg.begins_with("--"):
# TODO: Add code to handle custom command line arguments
continue
else:
OpenSave.handle_loading_file(arg)
func _notification(what: int) -> void:
match what:
MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
show_quit_dialog()
# If the mouse exits the window and another application has the focus,
# pause the application
MainLoop.NOTIFICATION_WM_FOCUS_OUT:
Global.has_focus = false
if Global.pause_when_unfocused:
get_tree().paused = true
MainLoop.NOTIFICATION_WM_MOUSE_EXIT:
if !OS.is_window_focused() and Global.pause_when_unfocused:
get_tree().paused = true
# Unpause it when the mouse enters the window or when it gains focus
MainLoop.NOTIFICATION_WM_MOUSE_ENTER:
get_tree().paused = false
2021-11-04 00:46:12 +00:00
MainLoop.NOTIFICATION_WM_FOCUS_IN:
get_tree().paused = false
2021-11-04 00:46:12 +00:00
var mouse_pos := get_global_mouse_position()
var viewport_rect := Rect2(
Global.main_viewport.rect_global_position, Global.main_viewport.rect_size
)
2021-11-04 00:46:12 +00:00
if viewport_rect.has_point(mouse_pos):
Global.has_focus = true
func _on_files_dropped(files: PoolStringArray, _screen: int) -> void:
for file in files:
OpenSave.handle_loading_file(file)
var splash_dialog = Global.control.get_node("Dialogs/SplashDialog")
if splash_dialog.visible:
splash_dialog.hide()
func load_last_project() -> void:
if OS.get_name() == "HTML5":
return
# Check if any project was saved or opened last time
if Global.config_cache.has_section_key("preferences", "last_project_path"):
# Check if file still exists on disk
var file_path = Global.config_cache.get_value("preferences", "last_project_path")
var file_check := File.new()
if file_check.file_exists(file_path): # If yes then load the file
OpenSave.open_pxo_file(file_path)
# Sync file dialogs
Global.save_sprites_dialog.current_dir = file_path.get_base_dir()
Global.open_sprites_dialog.current_dir = file_path.get_base_dir()
Global.config_cache.set_value("data", "current_dir", file_path.get_base_dir())
else:
# If file doesn't exist on disk then warn user about this
Global.error_dialog.set_text("Cannot find last project file.")
Global.error_dialog.popup_centered()
Global.dialog_open(true)
func load_recent_project_file(path: String) -> void:
if OS.get_name() == "HTML5":
return
# Check if file still exists on disk
var file_check := File.new()
if file_check.file_exists(path): # If yes then load the file
OpenSave.handle_loading_file(path)
# Sync file dialogs
Global.save_sprites_dialog.current_dir = path.get_base_dir()
Global.open_sprites_dialog.current_dir = path.get_base_dir()
Global.config_cache.set_value("data", "current_dir", path.get_base_dir())
else:
# If file doesn't exist on disk then warn user about this
Global.error_dialog.set_text("Cannot find project file.")
Global.error_dialog.popup_centered()
Global.dialog_open(true)
func _on_OpenSprite_files_selected(paths: PoolStringArray) -> void:
for path in paths:
OpenSave.handle_loading_file(path)
Global.save_sprites_dialog.current_dir = paths[0].get_base_dir()
Global.config_cache.set_value("data", "current_dir", paths[0].get_base_dir())
func _on_SaveSprite_file_selected(path: String) -> void:
save_project(path)
func save_project(path: String) -> void:
var zstd: bool = Global.save_sprites_dialog.get_vbox().get_node("ZSTDCompression").pressed
OpenSave.save_pxo_file(path, false, zstd)
Global.open_sprites_dialog.current_dir = path.get_base_dir()
Global.config_cache.set_value("data", "current_dir", path.get_base_dir())
if is_quitting_on_save:
_quit()
func _on_SaveSpriteHTML5_confirmed() -> void:
var file_name = Global.save_sprites_html5_dialog.get_node(
"FileNameContainer/FileNameLineEdit"
).text
file_name += ".pxo"
var path = "user://".plus_file(file_name)
OpenSave.save_pxo_file(path, false, false)
func _on_OpenSprite_popup_hide() -> void:
2019-08-18 09:28:38 +00:00
if !opensprite_file_selected:
_can_draw_true()
2019-08-18 09:28:38 +00:00
2019-08-18 09:28:38 +00:00
func _can_draw_true() -> void:
Global.dialog_open(false)
func show_quit_dialog() -> void:
var changed_project := false
for project in Global.projects:
if project.has_changed:
changed_project = true
break
2021-11-23 00:36:22 +00:00
if !quit_dialog.visible:
if !changed_project:
if Global.quit_confirmation:
quit_dialog.call_deferred("popup_centered")
else:
_quit()
else:
2022-03-28 23:35:32 +00:00
quit_and_save_dialog.call_deferred("popup_centered")
Global.dialog_open(true)
func _on_QuitDialog_confirmed() -> void:
_quit()
func _on_QuitAndSaveDialog_custom_action(action: String) -> void:
if action == "ExitWithoutSaving":
_quit()
func _on_QuitAndSaveDialog_confirmed() -> void:
is_quitting_on_save = true
Global.save_sprites_dialog.popup_centered()
quit_dialog.hide()
Global.dialog_open(true)
func _quit() -> void:
# Darken the UI to denote that the application is currently exiting
# (it won't respond to user input in this state).
modulate = Color(0.5, 0.5, 0.5)
get_tree().quit()
func _on_BackupConfirmation_confirmed(project_paths: Array, backup_paths: Array) -> void:
OpenSave.reload_backup_file(project_paths, backup_paths)
Global.current_project.file_name = OpenSave.current_save_paths[0].get_file().trim_suffix(".pxo")
Global.current_project.directory_path = OpenSave.current_save_paths[0].get_base_dir()
Global.current_project.was_exported = false
Global.top_menu_container.file_menu.set_item_text(
Global.FileMenu.SAVE, tr("Save") + " %s" % OpenSave.current_save_paths[0].get_file()
)
Global.top_menu_container.file_menu.set_item_text(Global.FileMenu.EXPORT, tr("Export"))
func _on_BackupConfirmation_custom_action(
action: String, project_paths: Array, backup_paths: Array
) -> void:
backup_confirmation.hide()
if action != "discard":
return
for i in range(project_paths.size()):
OpenSave.remove_backup_by_path(project_paths[i], backup_paths[i])
# Reopen last project
if Global.open_last_project:
load_last_project()
func _on_BackupConfirmation_popup_hide() -> void:
if Global.enable_autosave:
OpenSave.autosave_timer.start()
func _use_osx_shortcuts() -> void:
2022-07-18 19:12:17 +00:00
for action in InputMap.get_actions():
var action_list: Array = InputMap.get_action_list(action)
2022-06-29 20:41:53 +00:00
if action_list.size() == 0:
continue
var event: InputEvent = action_list[0]
if event.is_action("show_pixel_grid"):
event.shift = true
if event.control:
event.control = false
event.command = true
func _exit_tree() -> void:
2022-03-01 22:41:22 +00:00
Global.config_cache.set_value("window", "layout", Global.top_menu_container.selected_layout)
Global.config_cache.set_value("window", "screen", OS.current_screen)
Global.config_cache.set_value(
"window", "maximized", OS.window_maximized || OS.window_fullscreen
)
Global.config_cache.set_value("window", "position", OS.window_position)
Global.config_cache.set_value("window", "size", OS.window_size)
Global.config_cache.set_value("view_menu", "draw_grid", Global.draw_grid)
Global.config_cache.set_value("view_menu", "draw_pixel_grid", Global.draw_pixel_grid)
Global.config_cache.set_value("view_menu", "show_rulers", Global.show_rulers)
Global.config_cache.set_value("view_menu", "show_guides", Global.show_guides)
Global.config_cache.save("user://cache.ini")
var i := 0
for project in Global.projects:
project.remove()
OpenSave.remove_backup(i)
i += 1