From da3693ac45180732ff79442f61c764d6843c09e1 Mon Sep 17 00:00:00 2001
From: Mew Pur Pur <85438892+MewPurPur@users.noreply.github.com>
Date: Tue, 9 Apr 2024 02:33:52 +0300
Subject: [PATCH] Improve the fallback file dialog (#641)
---
src/GlobalSettings.gd | 11 +-
src/HandlerGUI.gd | 2 +-
src/SVG.gd | 52 +++-
src/ThemeGenerator.gd | 37 ++-
src/data_classes/SaveData.gd | 1 +
src/ui_parts/alert_dialog.tscn | 20 +-
src/ui_parts/export_dialog.gd | 33 +--
src/ui_parts/export_dialog.tscn | 3 +-
src/ui_parts/good_file_dialog.gd | 289 +++++++++++++++++++
src/ui_parts/good_file_dialog.tscn | 205 +++++++++++++
src/ui_parts/import_warning_dialog.tscn | 34 +--
src/ui_parts/settings_menu.gd | 18 +-
src/ui_parts/settings_menu.tscn | 32 +-
src/ui_parts/svg_file_dialog.gd | 10 -
src/ui_parts/svg_file_dialog.tscn | 19 --
translations/GodSVG.pot | 30 ++
translations/bg.po | 32 ++
translations/de.po | 37 +++
translations/en.po | 32 ++
translations/ru.po | 37 +++
translations/uk.po | 37 +++
visual/icon.svg | 2 +-
visual/icons/DirDesktop.svg | 1 +
visual/icons/DirDesktop.svg.import | 37 +++
visual/icons/DirDocuments.svg | 1 +
visual/icons/DirDocuments.svg.import | 37 +++
visual/icons/DirDownloads.svg | 1 +
visual/icons/DirDownloads.svg.import | 37 +++
visual/icons/DirMovies.svg | 1 +
visual/icons/DirMovies.svg.import | 37 +++
visual/icons/DirMusic.svg | 1 +
visual/icons/DirMusic.svg.import | 37 +++
visual/icons/DirPictures.svg | 1 +
visual/icons/DirPictures.svg.import | 37 +++
visual/icons/Folder.svg | 1 +
visual/icons/Folder.svg.import | 37 +++
visual/icons/{theme => }/FolderUp.svg | 0
visual/icons/{theme => }/FolderUp.svg.import | 6 +-
visual/icons/Search.svg | 1 +
visual/icons/Search.svg.import | 37 +++
visual/icons/tag/polyline.svg | 2 +-
41 files changed, 1161 insertions(+), 124 deletions(-)
create mode 100644 src/ui_parts/good_file_dialog.gd
create mode 100644 src/ui_parts/good_file_dialog.tscn
delete mode 100644 src/ui_parts/svg_file_dialog.gd
delete mode 100644 src/ui_parts/svg_file_dialog.tscn
create mode 100644 visual/icons/DirDesktop.svg
create mode 100644 visual/icons/DirDesktop.svg.import
create mode 100644 visual/icons/DirDocuments.svg
create mode 100644 visual/icons/DirDocuments.svg.import
create mode 100644 visual/icons/DirDownloads.svg
create mode 100644 visual/icons/DirDownloads.svg.import
create mode 100644 visual/icons/DirMovies.svg
create mode 100644 visual/icons/DirMovies.svg.import
create mode 100644 visual/icons/DirMusic.svg
create mode 100644 visual/icons/DirMusic.svg.import
create mode 100644 visual/icons/DirPictures.svg
create mode 100644 visual/icons/DirPictures.svg.import
create mode 100644 visual/icons/Folder.svg
create mode 100644 visual/icons/Folder.svg.import
rename visual/icons/{theme => }/FolderUp.svg (100%)
rename visual/icons/{theme => }/FolderUp.svg.import (74%)
create mode 100644 visual/icons/Search.svg
create mode 100644 visual/icons/Search.svg.import
diff --git a/src/GlobalSettings.gd b/src/GlobalSettings.gd
index f294ee5f..9756728d 100644
--- a/src/GlobalSettings.gd
+++ b/src/GlobalSettings.gd
@@ -56,6 +56,7 @@ const default_config = {
"invert_zoom": false,
"wrap_mouse": false,
"use_ctrl_for_zoom": true,
+ "use_native_file_dialog": true,
},
}
@@ -73,10 +74,6 @@ var language: String:
var palettes: Array[ColorPalette] = []
-# Input
-var invert_zoom := false
-var wrap_mouse := false
-var use_ctrl_for_zoom := true
# Autoformat
var general_number_precision := 3
@@ -118,6 +115,12 @@ var basic_color_valid := Color("9f9")
var basic_color_error := Color("f99")
var basic_color_warning := Color("ff9")
+# Other
+var invert_zoom := false
+var wrap_mouse := false
+var use_ctrl_for_zoom := true
+var use_native_file_dialog := true
+
func toggle_bool_setting(section: String, setting: String) -> void:
set(setting, !get(setting))
diff --git a/src/HandlerGUI.gd b/src/HandlerGUI.gd
index ab922378..951f1af6 100644
--- a/src/HandlerGUI.gd
+++ b/src/HandlerGUI.gd
@@ -40,9 +40,9 @@ func add_overlay(overlay_menu: Node) -> void:
overlay_ref = OverlayRect.new()
get_tree().get_root().add_child(overlay_ref)
overlay_ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
+ overlay_ref.add_child(overlay_menu)
if overlay_menu is Control:
overlay_menu.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
- overlay_ref.add_child(overlay_menu)
overlay_menu.tree_exiting.connect(remove_overlay)
has_overlay = true
get_tree().paused = true
diff --git a/src/SVG.gd b/src/SVG.gd
index 25160eae..1e1246fb 100644
--- a/src/SVG.gd
+++ b/src/SVG.gd
@@ -2,9 +2,11 @@
## The SVG text, and the native [TagSVG] representation.
extends Node
+const GoodFileDialogType = preload("res://src/ui_parts/good_file_dialog.gd")
+
const AlertDialog := preload("res://src/ui_parts/alert_dialog.tscn")
const ImportWarningDialog = preload("res://src/ui_parts/import_warning_dialog.tscn")
-const SVGFileDialog = preload("res://src/ui_parts/svg_file_dialog.tscn")
+const GoodFileDialog = preload("res://src/ui_parts/good_file_dialog.tscn")
const ExportDialog = preload("res://src/ui_parts/export_dialog.tscn")
const default = ''
@@ -78,16 +80,22 @@ func _on_undo_redo() -> void:
func refresh() -> void:
SVG.root_tag.replace_self(SVG.root_tag.create_duplicate())
+
+func is_native_preferred() -> bool:
+ return DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG) and\
+ GlobalSettings.use_native_file_dialog
+
func open_import_dialog() -> void:
# Open it inside a native file dialog, or our custom one if it's not available.
- if DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG):
+ if is_native_preferred():
DisplayServer.file_dialog_show("Import a .svg file", Utils.get_last_dir(), "", false,
DisplayServer.FILE_DIALOG_MODE_OPEN_FILE, ["*.svg"], native_file_import)
elif OS.has_feature("web"):
HandlerGUI.web_load_svg()
else:
- var svg_import_dialog := SVGFileDialog.instantiate()
- svg_import_dialog.current_dir = Utils.get_last_dir()
+ var svg_import_dialog := GoodFileDialog.instantiate()
+ svg_import_dialog.setup(Utils.get_last_dir(), "",
+ GoodFileDialogType.FileMode.SELECT, "svg")
HandlerGUI.add_overlay(svg_import_dialog)
svg_import_dialog.file_selected.connect(apply_svg_from_path)
@@ -103,7 +111,7 @@ func open_export_dialog() -> void:
func open_save_dialog(extension: String, native_callable: Callable,
non_native_callable: Callable) -> void:
# Open it inside a native file dialog, or our custom one if it's not available.
- if DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG):
+ if is_native_preferred():
DisplayServer.file_dialog_show("Save the .%s file" % extension,
Utils.get_last_dir(),
Utils.get_file_name(GlobalSettings.save_data.current_file_path) + "." + extension,
@@ -112,9 +120,10 @@ non_native_callable: Callable) -> void:
elif OS.has_feature("web"):
HandlerGUI.web_save_svg()
else:
- var svg_export_dialog := SVGFileDialog.instantiate()
- svg_export_dialog.current_dir = Utils.get_last_dir()
- svg_export_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
+ var svg_export_dialog := GoodFileDialog.instantiate()
+ svg_export_dialog.setup(Utils.get_last_dir(),
+ Utils.get_file_name(GlobalSettings.save_data.current_file_path),
+ GoodFileDialogType.FileMode.SAVE, extension)
HandlerGUI.add_overlay(svg_export_dialog)
svg_export_dialog.file_selected.connect(non_native_callable)
@@ -155,10 +164,37 @@ func apply_svg_from_path(path: String) -> int:
HandlerGUI.add_overlay(warning_panel)
return OK
+func generate_image_from_tags(upscale_amount := 1.0) -> Image:
+ var export_svg := SVG.root_tag.create_duplicate()
+ if export_svg.attributes.viewBox.get_list().is_empty():
+ export_svg.attributes.viewBox.set_list([0, 0, export_svg.width, export_svg.height])
+ export_svg.attributes.width.set_num(export_svg.width * upscale_amount)
+ export_svg.attributes.height.set_num(export_svg.height * upscale_amount)
+ var img := Image.new()
+ img.load_svg_from_string(SVGParser.svg_to_text(export_svg))
+ img.fix_alpha_edges() # See godot issue 82579.
+ return img
+
+
func finish_import(svg_text: String, file_path: String) -> void:
GlobalSettings.modify_save_data("current_file_path", file_path)
apply_svg_text(svg_text)
+func finish_export(file_path: String, extension: String, upscale_amount := 1.0) -> void:
+ if file_path.get_extension().is_empty():
+ file_path += "." + extension
+
+ GlobalSettings.modify_save_data("last_used_dir", file_path.get_base_dir())
+
+ match extension:
+ "png":
+ generate_image_from_tags(upscale_amount).save_png(file_path)
+ _:
+ # SVG / fallback.
+ GlobalSettings.modify_save_data("current_file_path", file_path)
+ save_svg_to_file(file_path)
+ HandlerGUI.remove_overlay()
+
func save_svg_to_file(path: String) -> void:
var FA := FileAccess.open(path, FileAccess.WRITE)
diff --git a/src/ThemeGenerator.gd b/src/ThemeGenerator.gd
index 96c4673c..12c0460c 100644
--- a/src/ThemeGenerator.gd
+++ b/src/ThemeGenerator.gd
@@ -76,7 +76,7 @@ static func generate_theme() -> void:
setup_button(theme)
setup_checkbox(theme)
setup_checkbutton(theme)
- setup_filedialog(theme)
+ setup_itemlist(theme)
setup_lineedit(theme)
setup_scrollbar(theme)
setup_separator(theme)
@@ -132,7 +132,7 @@ static func setup_panelcontainer(theme: Theme) -> void:
overlay_stylebox.set_border_width_all(2)
overlay_stylebox.content_margin_left = 8.0
overlay_stylebox.content_margin_right = 10.0
- overlay_stylebox.content_margin_top = 8.0
+ overlay_stylebox.content_margin_top = 6.0
overlay_stylebox.content_margin_bottom = 10.0
overlay_stylebox.bg_color = overlay_panel_inner_color
overlay_stylebox.border_color = overlay_panel_border_color
@@ -511,11 +511,34 @@ static func setup_checkbutton(theme: Theme) -> void:
theme.set_icon("checked", "CheckButton", icon("GuiToggleChecked"))
theme.set_icon("unchecked", "CheckButton", icon("GuiToggleUnchecked"))
-static func setup_filedialog(theme: Theme) -> void:
- theme.add_type("FileDialog")
- theme.set_icon("parent_folder", "CheckButton", icon("FolderUp"))
- theme.set_icon("reload", "CheckButton", icon("../Reload"))
- theme.set_icon("toggle_hidden", "CheckButton", icon("../Visuals"))
+static func setup_itemlist(theme: Theme) -> void:
+ theme.add_type("ItemList")
+ theme.set_color("font_color", "ItemList", Color(0.9, 0.9, 0.9))
+ theme.set_color("font_hovered", "ItemList", Color.WHITE)
+ theme.set_color("font_selected", "ItemList", Color.WHITE)
+ theme.set_color("guide_color", "ItemList", Color.TRANSPARENT)
+ #theme.set_constant("v_separation", "ItemList", 0)
+ theme.set_constant("icon_margin", "ItemList", 4)
+
+ var empty_stylebox := StyleBoxEmpty.new()
+ empty_stylebox.set_content_margin_all(1)
+ theme.set_stylebox("panel", "ItemList", empty_stylebox)
+ theme.set_stylebox("focus", "ItemList", empty_stylebox)
+ theme.set_stylebox("cursor", "ItemList", empty_stylebox)
+ theme.set_stylebox("cursor_unfocused", "ItemList", empty_stylebox)
+
+ var item_stylebox := StyleBoxFlat.new()
+ item_stylebox.set_corner_radius_all(3)
+ item_stylebox.set_content_margin_all(2)
+
+ var hover_item_stylebox := item_stylebox.duplicate()
+ hover_item_stylebox.bg_color = flat_button_color_hover
+ theme.set_stylebox("hovered", "ItemList", hover_item_stylebox)
+
+ var selected_item_stylebox := item_stylebox.duplicate()
+ selected_item_stylebox.bg_color = flat_button_color_pressed
+ theme.set_stylebox("selected", "ItemList", selected_item_stylebox)
+ theme.set_stylebox("selected_focus", "ItemList", selected_item_stylebox)
static func setup_lineedit(theme: Theme) -> void:
theme.add_type("LineEdit")
diff --git a/src/data_classes/SaveData.gd b/src/data_classes/SaveData.gd
index ae45b03c..3f437ab5 100644
--- a/src/data_classes/SaveData.gd
+++ b/src/data_classes/SaveData.gd
@@ -10,6 +10,7 @@ const GoodColorPicker = preload("res://src/ui_elements/good_color_picker.gd")
@export var color_picker_slider_mode := GoodColorPicker.SliderMode.RGB
@export var path_command_relative := false
@export var last_used_dir := ""
+@export var file_dialog_show_hidden := false
signal current_file_path_changed
@export var current_file_path := "":
diff --git a/src/ui_parts/alert_dialog.tscn b/src/ui_parts/alert_dialog.tscn
index 02b6d04e..9e08d5f0 100644
--- a/src/ui_parts/alert_dialog.tscn
+++ b/src/ui_parts/alert_dialog.tscn
@@ -15,40 +15,34 @@ offset_right = 2.0
offset_bottom = 2.0
grow_horizontal = 2
grow_vertical = 2
+theme_type_variation = &"OverlayPanel"
script = ExtResource("1_qntyo")
-[node name="MarginContainer" type="MarginContainer" parent="."]
-layout_mode = 2
-theme_override_constants/margin_left = 8
-theme_override_constants/margin_top = 6
-theme_override_constants/margin_right = 8
-theme_override_constants/margin_bottom = 8
-
-[node name="MainContainer" type="VBoxContainer" parent="MarginContainer"]
+[node name="MainContainer" type="VBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
theme_override_constants/separation = 10
-[node name="TextContainer" type="VBoxContainer" parent="MarginContainer/MainContainer"]
+[node name="TextContainer" type="VBoxContainer" parent="MainContainer"]
layout_mode = 2
-[node name="Title" type="Label" parent="MarginContainer/MainContainer/TextContainer"]
+[node name="Title" type="Label" parent="MainContainer/TextContainer"]
layout_mode = 2
theme_override_fonts/font = ExtResource("1_3yrpq")
theme_override_font_sizes/font_size = 16
text = "Alert!"
horizontal_alignment = 1
-[node name="Label" type="RichTextLabel" parent="MarginContainer/MainContainer/TextContainer"]
+[node name="Label" type="RichTextLabel" parent="MainContainer/TextContainer"]
custom_minimum_size = Vector2(180, 0)
layout_mode = 2
theme_override_font_sizes/normal_font_size = 12
fit_content = true
-[node name="OKButton" type="Button" parent="MarginContainer/MainContainer"]
+[node name="OKButton" type="Button" parent="MainContainer"]
layout_mode = 2
size_flags_horizontal = 4
mouse_default_cursor_shape = 2
text = "OK"
-[connection signal="pressed" from="MarginContainer/MainContainer/OKButton" to="." method="_on_ok_button_pressed"]
+[connection signal="pressed" from="MainContainer/OKButton" to="." method="_on_ok_button_pressed"]
diff --git a/src/ui_parts/export_dialog.gd b/src/ui_parts/export_dialog.gd
index 83263fdc..90f56652 100644
--- a/src/ui_parts/export_dialog.gd
+++ b/src/ui_parts/export_dialog.gd
@@ -1,7 +1,6 @@
extends PanelContainer
const NumberEditType = preload("res://src/ui_elements/number_edit.gd")
-const SVGFileDialog = preload("res://src/ui_parts/svg_file_dialog.tscn")
var upscale_amount := -1.0
var extension := ""
@@ -52,32 +51,17 @@ func _on_dropdown_value_changed(new_value: String) -> void:
func native_file_export(has_selected: bool, files: PackedStringArray,
_filter_idx: int) -> void:
if has_selected:
- export(files[0])
+ SVG.finish_export(files[0], extension, upscale_amount)
func _on_ok_button_pressed() -> void:
if OS.has_feature("web"):
match extension:
"png":
- HandlerGUI.web_save_png(create_image())
+ HandlerGUI.web_save_png(SVG.generate_image_from_tags())
_:
HandlerGUI.web_save_svg()
else:
- SVG.open_save_dialog(extension, native_file_export, export)
-
-func export(path: String) -> void:
- if path.get_extension().is_empty():
- path += "." + extension
-
- GlobalSettings.modify_save_data("last_used_dir", path.get_base_dir())
-
- match extension:
- "png":
- create_image().save_png(path)
- _:
- # SVG / fallback.
- GlobalSettings.modify_save_data("current_file_path", path)
- SVG.save_svg_to_file(path)
- HandlerGUI.remove_overlay()
+ SVG.open_save_dialog(extension, native_file_export, SVG.finish_export.bind(extension))
func _on_cancel_button_pressed() -> void:
HandlerGUI.remove_overlay()
@@ -94,14 +78,3 @@ func update_final_scale() -> void:
func update_extension_configuration() -> void:
scale_container.visible = (extension == "png")
-
-func create_image() -> Image:
- var export_svg := SVG.root_tag.create_duplicate()
- if export_svg.attributes.viewBox.get_list().is_empty():
- export_svg.attributes.viewBox.set_list([0, 0, export_svg.width, export_svg.height])
- export_svg.attributes.width.set_num(export_svg.width * upscale_amount)
- export_svg.attributes.height.set_num(export_svg.height * upscale_amount)
- var img := Image.new()
- img.load_svg_from_string(SVGParser.svg_to_text(export_svg))
- img.fix_alpha_edges() # See godot issue 82579.
- return img
diff --git a/src/ui_parts/export_dialog.tscn b/src/ui_parts/export_dialog.tscn
index dde213df..96ed80db 100644
--- a/src/ui_parts/export_dialog.tscn
+++ b/src/ui_parts/export_dialog.tscn
@@ -108,17 +108,18 @@ theme_override_font_sizes/font_size = 10
[node name="ButtonContainer" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
-theme_override_constants/separation = 12
alignment = 1
[node name="CancelButton" type="Button" parent="VBoxContainer/ButtonContainer"]
layout_mode = 2
+size_flags_horizontal = 6
focus_mode = 0
mouse_default_cursor_shape = 2
text = "Cancel"
[node name="OKButton" type="Button" parent="VBoxContainer/ButtonContainer"]
layout_mode = 2
+size_flags_horizontal = 6
focus_mode = 0
mouse_default_cursor_shape = 2
text = "Export"
diff --git a/src/ui_parts/good_file_dialog.gd b/src/ui_parts/good_file_dialog.gd
new file mode 100644
index 00000000..b03faf0f
--- /dev/null
+++ b/src/ui_parts/good_file_dialog.gd
@@ -0,0 +1,289 @@
+## A fallback file dialog for if the native file dialog is not available.
+extends PanelContainer
+
+const AlertDialog = preload("res://src/ui_parts/alert_dialog.tscn")
+
+signal file_selected(path: String)
+
+const folder_icon = preload("res://visual/icons/Folder.svg")
+const system_dir_icons = {
+ OS.SYSTEM_DIR_DESKTOP: preload("res://visual/icons/DirDesktop.svg"),
+ OS.SYSTEM_DIR_DOCUMENTS: preload("res://visual/icons/DirDocuments.svg"),
+ OS.SYSTEM_DIR_DOWNLOADS: preload("res://visual/icons/DirDownloads.svg"),
+ OS.SYSTEM_DIR_MOVIES: preload("res://visual/icons/DirMovies.svg"),
+ OS.SYSTEM_DIR_MUSIC: preload("res://visual/icons/DirMusic.svg"),
+ OS.SYSTEM_DIR_PICTURES: preload("res://visual/icons/DirPictures.svg"),
+}
+
+var item_height := 16
+
+enum FileMode {SELECT, SAVE}
+var mode: FileMode
+
+var current_dir: String
+var current_file := ""
+var default_file := ""
+var extension := ""
+
+var search_text := ""
+
+@onready var close_button: Button = %CloseButton
+@onready var special_button: Button = %SpecialButton
+@onready var path_label: Label = %PathLabel
+@onready var title_label: Label = $VBoxContainer/TitleLabel
+@onready var search_field: BetterLineEdit = %SearchField
+@onready var path_field: BetterLineEdit = %PathField
+@onready var file_container: HBoxContainer = %FileContainer
+@onready var file_field: BetterLineEdit = %FileField
+@onready var extension_panel: PanelContainer = %ExtensionPanel
+@onready var extension_label: Label = %ExtensionLabel
+@onready var system_dir_list: ItemList = %SystemDirList
+@onready var file_list: ItemList = %FileList
+@onready var folder_up_button: Button = %FolderUpButton
+@onready var refresh_button: Button = %RefreshButton
+@onready var show_hidden_button: Button = %ShowHiddenButton
+@onready var search_button: Button = %SearchButton
+
+@onready var center_container: CenterContainer = $CenterContainer
+@onready var alert_title_label: Label = %AlertTitleLabel
+@onready var alert_label: RichTextLabel = %AlertLabel
+@onready var alert_cancel_button: Button = %AlertCancelButton
+@onready var alert_replace_button: Button = %AlertReplaceButton
+
+
+class Actions:
+ var activation_action: Callable
+ var selection_action: Callable
+
+ func _init(on_activation := Callable(), on_selection := Callable()) -> void:
+ activation_action = on_activation
+ selection_action = on_selection
+
+func call_activation_action(actions: Actions) -> void:
+ if actions != null and not actions.activation_action.is_null():
+ actions.activation_action.call()
+
+func call_selection_action(actions: Actions) -> void:
+ if actions != null and not actions.selection_action.is_null():
+ actions.selection_action.call()
+
+
+func setup(new_dir: String, new_file: String, new_mode: FileMode,
+new_extension: String) -> void:
+ current_dir = new_dir
+ current_file = new_file
+ if new_mode == FileMode.SAVE:
+ default_file = new_file
+ mode = new_mode
+ extension = new_extension
+
+func _ready() -> void:
+ if mode == FileMode.SELECT:
+ file_container.hide()
+ if mode == FileMode.SAVE:
+ alert_title_label.text = tr("Alert!")
+ alert_cancel_button.text = tr("Cancel")
+ alert_replace_button.text = tr("Replace")
+ var extension_panel_stylebox := extension_panel.get_theme_stylebox("panel")
+ extension_panel_stylebox.content_margin_top -= 4
+ extension_panel.add_theme_stylebox_override("panel", extension_panel_stylebox)
+ if GlobalSettings.save_data.file_dialog_show_hidden:
+ show_hidden_button.set_pressed_no_signal(true)
+ folder_up_button.tooltip_text = tr("Go to parent folder")
+ refresh_button.tooltip_text = tr("Refresh files")
+ show_hidden_button.tooltip_text = tr("Toggle the visibility of hidden files")
+ search_button.tooltip_text = tr("Search files")
+
+ title_label.text = tr("Select an SVG") if mode == FileMode.SELECT else tr("Save SVG")
+ close_button.text = tr("Close")
+ special_button.text = tr("Select") if mode == FileMode.SELECT else tr("Save")
+ path_label.text = tr("Path") + ":"
+ extension_label.text = "." + extension
+ for dir in [OS.SYSTEM_DIR_DESKTOP, OS.SYSTEM_DIR_DOCUMENTS, OS.SYSTEM_DIR_DOWNLOADS,
+ OS.SYSTEM_DIR_MOVIES, OS.SYSTEM_DIR_MUSIC, OS.SYSTEM_DIR_PICTURES]:
+ var dir_string := OS.get_system_dir(dir)
+ if dir_string.is_empty():
+ continue
+
+ var item_idx := system_dir_list.add_item(dir_string.get_file(),
+ system_dir_icons[dir] if dir in system_dir_icons else folder_icon)
+ system_dir_list.set_item_metadata(item_idx,
+ Actions.new(Callable(), enter_dir.bind(dir_string)))
+ # If you start off in a system dir, highlight it in the list to make it clear.
+ if current_dir == dir_string:
+ system_dir_list.select(item_idx)
+
+ # Should always be safe.
+ set_dir(current_dir)
+ if mode == FileMode.SAVE:
+ set_file(current_file)
+ file_field.grab_focus()
+ else:
+ special_button.disabled = true
+ special_button.mouse_default_cursor_shape = Control.CURSOR_ARROW
+
+
+func enter_dir(dir: String) -> void:
+ if search_button.button_pressed:
+ search_button.button_pressed = false
+ set_dir(dir)
+
+func file_sort(file1: String, file2: String) -> bool:
+ return file1.naturalnocasecmp_to(file2) == -1
+
+# This function requires a safe input.
+func set_dir(dir: String) -> void:
+ file_list.clear()
+ # Basic setup.
+ current_dir = dir
+ path_field.text = current_dir
+ # Create the DirAccess object.
+ var DA := DirAccess.open(dir)
+ DA.include_hidden = GlobalSettings.save_data.file_dialog_show_hidden
+ # Gather the files and directories.
+ var directories: Array[String] = []
+ var files: Array[String] = []
+ for directory in DA.get_directories():
+ directories.append(directory)
+ for file in DA.get_files():
+ files.append(file)
+ directories.sort_custom(file_sort)
+ files.sort_custom(file_sort)
+ # Populate the ItemList.
+ for directory in directories:
+ if not search_text.is_empty() and not search_text.is_subsequence_ofn(directory):
+ continue
+ var item_idx := file_list.add_item(directory, folder_icon)
+ file_list.set_item_metadata(item_idx,
+ Actions.new(enter_dir.bind(current_dir.path_join(directory)), unfocus_file))
+
+ for file in files:
+ if file.get_extension() != extension or\
+ (not search_text.is_empty() and not search_text.is_subsequence_ofn(file)):
+ continue
+
+ match extension:
+ "svg":
+ # Setup a clean SVG graphic by using the scaling parameter.
+ var svg_text := FileAccess.open(current_dir.path_join(file),
+ FileAccess.READ).get_as_text()
+ var img := Image.new()
+ img.load_svg_from_string(svg_text)
+ img.load_svg_from_string(svg_text,
+ item_height / maxf(img.get_width(), img.get_height()))
+ var item_idx := file_list.add_item(file, ImageTexture.create_from_image(img))
+ file_list.set_item_metadata(item_idx,
+ Actions.new(select_file, focus_file.bind(file)))
+ "png":
+ var item_idx := file_list.add_item(file, ImageTexture.create_from_image(
+ Image.load_from_file(current_dir.path_join(file))))
+ file_list.set_item_metadata(item_idx,
+ Actions.new(select_file, focus_file.bind(file)))
+ file = DA.get_next()
+
+func set_file(file: String) -> void:
+ if mode == FileMode.SELECT:
+ if file.is_empty():
+ special_button.disabled = true
+ special_button.mouse_default_cursor_shape = Control.CURSOR_ARROW
+ else:
+ special_button.disabled = false
+ special_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
+ if not file.is_empty():
+ if file.get_extension() != extension:
+ file += "." + extension
+ current_file = file
+ file_field.text = current_file
+
+
+func select_file() -> void:
+ if mode == FileMode.SAVE and current_file in DirAccess.get_files_at(current_dir):
+ alert_label.text = tr("A file named \"{file_name}\" already exists. Replacing will overwrite its contents!").format({"file_name": current_file})
+ center_container.show()
+ alert_replace_button.grab_focus()
+ else:
+ file_selected.emit(current_dir.path_join(current_file))
+
+func focus_file(path: String) -> void:
+ set_file(path.get_file())
+
+func unfocus_file() -> void:
+ set_file(default_file)
+
+func _on_folder_up_button_pressed() -> void:
+ set_dir(current_dir.get_base_dir())
+
+func _on_file_list_empty_clicked(_at_position: Vector2, _mouse_button_index: int) -> void:
+ file_list.deselect_all()
+ unfocus_file()
+
+func _on_system_dir_list_empty_clicked(_at_position: Vector2,
+_mouse_button_index: int) -> void:
+ system_dir_list.deselect_all()
+
+func _on_file_list_item_activated(index: int) -> void:
+ call_activation_action(file_list.get_item_metadata(index))
+
+func _on_file_list_item_selected(index: int) -> void:
+ call_selection_action(file_list.get_item_metadata(index))
+
+func _on_system_dir_list_item_selected(index: int) -> void:
+ call_selection_action(system_dir_list.get_item_metadata(index))
+
+func _on_refresh_button_pressed() -> void:
+ set_dir(current_dir)
+
+func _on_show_hidden_button_toggled(toggled_on: bool) -> void:
+ GlobalSettings.modify_save_data("file_dialog_show_hidden", toggled_on)
+ set_dir(current_dir)
+
+func _on_search_button_toggled(toggled_on: bool) -> void:
+ if toggled_on:
+ search_field.show()
+ search_field.grab_focus()
+ else:
+ search_field.hide()
+ search_text = ""
+ set_dir(current_dir)
+
+
+func _on_close_button_pressed() -> void:
+ queue_free()
+
+func _on_file_selected(_path: String) -> void:
+ queue_free()
+
+func _on_special_button_pressed() -> void:
+ select_file()
+
+func _on_file_field_text_submitted(new_text: String) -> void:
+ file_field.remove_theme_color_override("font_color")
+ if new_text.is_valid_filename():
+ current_file = new_text
+ else:
+ file_field.text = current_file
+
+func _on_path_field_text_submitted(new_text: String) -> void:
+ var DA := DirAccess.open(new_text)
+ if DA != null:
+ set_dir(new_text)
+ else:
+ path_field.text = current_dir
+
+func _on_search_field_text_changed(new_text: String) -> void:
+ search_text = new_text
+ set_dir(current_dir)
+
+func _on_search_field_text_change_canceled() -> void:
+ search_field.text = search_text
+
+func _on_file_field_text_changed(new_text: String) -> void:
+ file_field.add_theme_color_override("font_color",
+ GlobalSettings.get_validity_color(!new_text.is_valid_filename()))
+
+
+func _on_alert_cancel_button_pressed() -> void:
+ center_container.hide()
+
+func _on_alert_replace_button_pressed() -> void:
+ file_selected.emit(current_dir.path_join(current_file))
diff --git a/src/ui_parts/good_file_dialog.tscn b/src/ui_parts/good_file_dialog.tscn
new file mode 100644
index 00000000..840f2464
--- /dev/null
+++ b/src/ui_parts/good_file_dialog.tscn
@@ -0,0 +1,205 @@
+[gd_scene load_steps=8 format=3 uid="uid://bndmdmjlwqxfh"]
+
+[ext_resource type="Script" path="res://src/ui_parts/good_file_dialog.gd" id="1_awdto"]
+[ext_resource type="Script" path="res://src/ui_elements/BetterLineEdit.gd" id="2_52puw"]
+[ext_resource type="Texture2D" uid="uid://rrhdja8l17cn" path="res://visual/icons/FolderUp.svg" id="2_jjo15"]
+[ext_resource type="Texture2D" uid="uid://cvh3kwbucf2n1" path="res://visual/icons/Reload.svg" id="4_udwbh"]
+[ext_resource type="Texture2D" uid="uid://kkxyv1gyrjgj" path="res://visual/icons/Visuals.svg" id="5_2ggtv"]
+[ext_resource type="Texture2D" uid="uid://d4c7haflm8evm" path="res://visual/icons/Search.svg" id="6_otods"]
+[ext_resource type="FontFile" uid="uid://dc0w4sx0h0fui" path="res://visual/fonts/FontBold.ttf" id="7_br1c0"]
+
+[node name="NonNativeFileDialog" type="PanelContainer"]
+offset_right = 684.0
+offset_bottom = 386.0
+theme_type_variation = &"OverlayPanel"
+script = ExtResource("1_awdto")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 2
+theme_override_constants/separation = 8
+
+[node name="TitleLabel" type="Label" parent="VBoxContainer"]
+layout_mode = 2
+horizontal_alignment = 1
+
+[node name="TopBar" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+theme_override_constants/separation = 6
+
+[node name="FolderUpButton" type="Button" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+mouse_default_cursor_shape = 2
+theme_type_variation = &"IconButton"
+icon = ExtResource("2_jjo15")
+
+[node name="PathLabel" type="Label" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="PathField" type="LineEdit" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+script = ExtResource("2_52puw")
+
+[node name="RefreshButton" type="Button" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+mouse_default_cursor_shape = 2
+theme_type_variation = &"IconButton"
+icon = ExtResource("4_udwbh")
+
+[node name="ShowHiddenButton" type="Button" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+mouse_default_cursor_shape = 2
+theme_type_variation = &"IconButton"
+toggle_mode = true
+icon = ExtResource("5_2ggtv")
+
+[node name="SearchButton" type="Button" parent="VBoxContainer/TopBar"]
+unique_name_in_owner = true
+layout_mode = 2
+mouse_default_cursor_shape = 2
+theme_type_variation = &"IconButton"
+toggle_mode = true
+icon = ExtResource("6_otods")
+
+[node name="MainContainer" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+
+[node name="SystemDirContainer" type="PanelContainer" parent="VBoxContainer/MainContainer"]
+custom_minimum_size = Vector2(120, 0)
+layout_mode = 2
+
+[node name="SystemDirList" type="ItemList" parent="VBoxContainer/MainContainer/SystemDirContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+fixed_icon_size = Vector2i(16, 16)
+
+[node name="FilePicker" type="VBoxContainer" parent="VBoxContainer/MainContainer"]
+custom_minimum_size = Vector2(0, 300)
+layout_mode = 2
+
+[node name="SearchField" type="LineEdit" parent="VBoxContainer/MainContainer/FilePicker"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+script = ExtResource("2_52puw")
+
+[node name="VisualPicker" type="PanelContainer" parent="VBoxContainer/MainContainer/FilePicker"]
+custom_minimum_size = Vector2(450, 0)
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="FileList" type="ItemList" parent="VBoxContainer/MainContainer/FilePicker/VisualPicker"]
+unique_name_in_owner = true
+layout_mode = 2
+fixed_icon_size = Vector2i(16, 16)
+
+[node name="FileContainer" type="HBoxContainer" parent="VBoxContainer/MainContainer/FilePicker"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="FileField" type="LineEdit" parent="VBoxContainer/MainContainer/FilePicker/FileContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+script = ExtResource("2_52puw")
+
+[node name="ExtensionPanel" type="PanelContainer" parent="VBoxContainer/MainContainer/FilePicker/FileContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_type_variation = &"DarkPanel"
+
+[node name="ExtensionLabel" type="Label" parent="VBoxContainer/MainContainer/FilePicker/FileContainer/ExtensionPanel"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_override_colors/font_color = Color(0.866667, 0.933333, 1, 0.533333)
+
+[node name="ButtonsContainer" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+theme_override_constants/separation = 12
+alignment = 1
+
+[node name="CloseButton" type="Button" parent="VBoxContainer/ButtonsContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 6
+focus_mode = 0
+mouse_default_cursor_shape = 2
+
+[node name="SpecialButton" type="Button" parent="VBoxContainer/ButtonsContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 6
+focus_mode = 0
+mouse_default_cursor_shape = 2
+
+[node name="CenterContainer" type="CenterContainer" parent="."]
+visible = false
+layout_mode = 2
+
+[node name="AlertDialog" type="PanelContainer" parent="CenterContainer"]
+custom_minimum_size = Vector2(280, 0)
+layout_mode = 2
+theme_type_variation = &"OverlayPanel"
+
+[node name="MainContainer" type="VBoxContainer" parent="CenterContainer/AlertDialog"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="TextContainer" type="VBoxContainer" parent="CenterContainer/AlertDialog/MainContainer"]
+layout_mode = 2
+
+[node name="AlertTitleLabel" type="Label" parent="CenterContainer/AlertDialog/MainContainer/TextContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_override_fonts/font = ExtResource("7_br1c0")
+theme_override_font_sizes/font_size = 16
+horizontal_alignment = 1
+
+[node name="AlertLabel" type="RichTextLabel" parent="CenterContainer/AlertDialog/MainContainer/TextContainer"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(180, 0)
+layout_mode = 2
+theme_override_font_sizes/normal_font_size = 12
+fit_content = true
+
+[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/AlertDialog/MainContainer"]
+layout_mode = 2
+alignment = 1
+
+[node name="AlertCancelButton" type="Button" parent="CenterContainer/AlertDialog/MainContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 6
+mouse_default_cursor_shape = 2
+
+[node name="AlertReplaceButton" type="Button" parent="CenterContainer/AlertDialog/MainContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 6
+mouse_default_cursor_shape = 2
+
+[connection signal="file_selected" from="." to="." method="_on_file_selected"]
+[connection signal="pressed" from="VBoxContainer/TopBar/FolderUpButton" to="." method="_on_folder_up_button_pressed"]
+[connection signal="text_submitted" from="VBoxContainer/TopBar/PathField" to="." method="_on_path_field_text_submitted"]
+[connection signal="pressed" from="VBoxContainer/TopBar/RefreshButton" to="." method="_on_refresh_button_pressed"]
+[connection signal="toggled" from="VBoxContainer/TopBar/ShowHiddenButton" to="." method="_on_show_hidden_button_toggled"]
+[connection signal="toggled" from="VBoxContainer/TopBar/SearchButton" to="." method="_on_search_button_toggled"]
+[connection signal="empty_clicked" from="VBoxContainer/MainContainer/SystemDirContainer/SystemDirList" to="." method="_on_system_dir_list_empty_clicked"]
+[connection signal="item_selected" from="VBoxContainer/MainContainer/SystemDirContainer/SystemDirList" to="." method="_on_system_dir_list_item_selected"]
+[connection signal="text_change_canceled" from="VBoxContainer/MainContainer/FilePicker/SearchField" to="." method="_on_search_field_text_change_canceled"]
+[connection signal="text_changed" from="VBoxContainer/MainContainer/FilePicker/SearchField" to="." method="_on_search_field_text_changed"]
+[connection signal="empty_clicked" from="VBoxContainer/MainContainer/FilePicker/VisualPicker/FileList" to="." method="_on_file_list_empty_clicked"]
+[connection signal="item_activated" from="VBoxContainer/MainContainer/FilePicker/VisualPicker/FileList" to="." method="_on_file_list_item_activated"]
+[connection signal="item_selected" from="VBoxContainer/MainContainer/FilePicker/VisualPicker/FileList" to="." method="_on_file_list_item_selected"]
+[connection signal="text_changed" from="VBoxContainer/MainContainer/FilePicker/FileContainer/FileField" to="." method="_on_file_field_text_changed"]
+[connection signal="text_submitted" from="VBoxContainer/MainContainer/FilePicker/FileContainer/FileField" to="." method="_on_file_field_text_submitted"]
+[connection signal="pressed" from="VBoxContainer/ButtonsContainer/CloseButton" to="." method="_on_close_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/ButtonsContainer/SpecialButton" to="." method="_on_special_button_pressed"]
+[connection signal="pressed" from="CenterContainer/AlertDialog/MainContainer/HBoxContainer/AlertCancelButton" to="." method="_on_alert_cancel_button_pressed"]
+[connection signal="pressed" from="CenterContainer/AlertDialog/MainContainer/HBoxContainer/AlertReplaceButton" to="." method="_on_alert_replace_button_pressed"]
diff --git a/src/ui_parts/import_warning_dialog.tscn b/src/ui_parts/import_warning_dialog.tscn
index 8c6a10be..f8a69754 100644
--- a/src/ui_parts/import_warning_dialog.tscn
+++ b/src/ui_parts/import_warning_dialog.tscn
@@ -16,33 +16,27 @@ offset_right = 206.0
offset_bottom = 111.0
grow_horizontal = 2
grow_vertical = 2
+theme_type_variation = &"OverlayPanel"
script = ExtResource("1_1rv5w")
-[node name="MarginContainer" type="MarginContainer" parent="."]
-layout_mode = 2
-theme_override_constants/margin_left = 8
-theme_override_constants/margin_top = 8
-theme_override_constants/margin_right = 8
-theme_override_constants/margin_bottom = 8
-
-[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
theme_override_constants/separation = 12
-[node name="Title" type="Label" parent="MarginContainer/VBoxContainer"]
+[node name="Title" type="Label" parent="VBoxContainer"]
layout_mode = 2
text = "Import Problems"
horizontal_alignment = 1
-[node name="TextureContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+[node name="TextureContainer" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 12
-[node name="TexturePreview" parent="MarginContainer/VBoxContainer/TextureContainer" instance=ExtResource("2_j1v8v")]
+[node name="TexturePreview" parent="VBoxContainer/TextureContainer" instance=ExtResource("2_j1v8v")]
unique_name_in_owner = true
layout_mode = 2
-[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/TextureContainer"]
+[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/TextureContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(256, 128)
layout_mode = 2
@@ -53,10 +47,10 @@ theme_override_constants/margin_top = 6
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 6
-[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer/TextureContainer/MarginContainer"]
+[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/TextureContainer/MarginContainer"]
layout_mode = 2
-[node name="WarningsLabel" type="RichTextLabel" parent="MarginContainer/VBoxContainer/TextureContainer/MarginContainer/ScrollContainer"]
+[node name="WarningsLabel" type="RichTextLabel" parent="VBoxContainer/TextureContainer/MarginContainer/ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -67,22 +61,24 @@ fit_content = true
scroll_active = false
autowrap_mode = 0
-[node name="ButtonContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+[node name="ButtonContainer" type="HBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_constants/separation = 12
alignment = 1
-[node name="CancelButton" type="Button" parent="MarginContainer/VBoxContainer/ButtonContainer"]
+[node name="CancelButton" type="Button" parent="VBoxContainer/ButtonContainer"]
layout_mode = 2
+size_flags_horizontal = 6
mouse_default_cursor_shape = 2
text = "Cancel"
-[node name="OKButton" type="Button" parent="MarginContainer/VBoxContainer/ButtonContainer"]
+[node name="OKButton" type="Button" parent="VBoxContainer/ButtonContainer"]
layout_mode = 2
+size_flags_horizontal = 6
mouse_default_cursor_shape = 2
text = "Import"
[connection signal="imported" from="." to="." method="_on_imported"]
-[connection signal="pressed" from="MarginContainer/VBoxContainer/ButtonContainer/CancelButton" to="." method="_on_cancel_button_pressed"]
-[connection signal="pressed" from="MarginContainer/VBoxContainer/ButtonContainer/OKButton" to="." method="_on_ok_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/ButtonContainer/CancelButton" to="." method="_on_cancel_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/ButtonContainer/OKButton" to="." method="_on_ok_button_pressed"]
diff --git a/src/ui_parts/settings_menu.gd b/src/ui_parts/settings_menu.gd
index 4a1abdce..9a9e36ff 100644
--- a/src/ui_parts/settings_menu.gd
+++ b/src/ui_parts/settings_menu.gd
@@ -14,7 +14,10 @@ const SettingColor = preload("res://src/ui_elements/setting_color.gd")
@onready var shortcut_container: VBoxContainer = %ShortcutContainer
@onready var content_container: MarginContainer = %ContentContainer
@onready var tabs: VBoxContainer = %Tabs
+
@onready var wrap_mouse: HBoxContainer = %WrapMouse
+@onready var use_native_file_dialog: HBoxContainer = %UseNativeFileDialog
+
@onready var configurable_shortcuts: VBoxContainer = %ConfigurableShortcuts
@onready var non_configurable_shortcuts: VBoxContainer = %NonConfigurableShortcuts
@@ -61,14 +64,17 @@ func setup_setting_labels() -> void:
tabs.get_node(^"ThemeTab").text = tr("Theme")
tabs.get_node(^"OtherTab").text = tr("Other")
- var invert_zoom := %ContentContainer/Other/Input/InvertZoom
+ var invert_zoom := %ContentContainer/Other/OtherSettings/Input/InvertZoom
invert_zoom.label.text = tr("Invert zoom direction")
invert_zoom.label.tooltip_text = tr("Swaps zoom in and zoom out with the mouse wheel.")
wrap_mouse.label.text = tr("Wrap mouse")
wrap_mouse.label.tooltip_text = tr("Wraps the mouse cursor around when panning the viewport.")
- var ctrl_for_zoom := %ContentContainer/Other/Input/UseCtrlForZoom
+ var ctrl_for_zoom := %ContentContainer/Other/OtherSettings/Input/UseCtrlForZoom
ctrl_for_zoom.label.text = tr("Use CTRL for zooming")
ctrl_for_zoom.label.tooltip_text = tr("If turned on, scrolling will pan the view. To zoom, hold CTRL while scrolling.")
+ use_native_file_dialog.label.text = tr("Use native file dialog")
+ use_native_file_dialog.label.tooltip_text = tr("If turned on, uses your operating system's native file dialog. If turned off, uses GodSVG's built-in file dialog.")
+
%GeneralVBox/NumberPrecision.label.text = tr("Number precision digits")
%GeneralVBox/AnglePrecision.label.text = tr("Angle precision digits")
%XMLVBox/AddTrailingNewline.label.text = tr("Add trailing newline")
@@ -284,7 +290,15 @@ func _on_theme_tab_toggled(toggled_on: bool) -> void:
func _on_other_tab_toggled(toggled_on: bool) -> void:
if toggled_on and not generated_content.other:
+ # Disable mouse wrap if not available.
if not DisplayServer.has_feature(DisplayServer.FEATURE_MOUSE_WARP):
wrap_mouse.checkbox.set_pressed_no_signal(false)
wrap_mouse.set_checkbox_enabled(false)
+ # Disable fallback file dialog on web, and native file dialog if not available.
+ if OS.has_feature("web"):
+ use_native_file_dialog.checkbox.set_pressed_no_signal(true)
+ use_native_file_dialog.set_checkbox_enabled(false)
+ if not DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG):
+ use_native_file_dialog.checkbox.set_pressed_no_signal(false)
+ use_native_file_dialog.set_checkbox_enabled(false)
generated_content.other = true
diff --git a/src/ui_parts/settings_menu.tscn b/src/ui_parts/settings_menu.tscn
index 34b21147..72d0b11f 100644
--- a/src/ui_parts/settings_menu.tscn
+++ b/src/ui_parts/settings_menu.tscn
@@ -480,35 +480,57 @@ visible = false
layout_mode = 2
horizontal_scroll_mode = 0
-[node name="Input" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other"]
+[node name="OtherSettings" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_constants/separation = 8
+
+[node name="Input" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/separation = 3
-[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/Input"]
+[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/Input"]
layout_mode = 2
text = "Input"
-[node name="InvertZoom" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/Input" instance=ExtResource("4_2qeh2")]
+[node name="InvertZoom" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/Input" instance=ExtResource("4_2qeh2")]
layout_mode = 2
tooltip_text = "Swaps zoom in and zoom out with the mouse wheel."
section_name = "other"
setting_name = "invert_zoom"
-[node name="WrapMouse" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/Input" instance=ExtResource("4_2qeh2")]
+[node name="WrapMouse" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/Input" instance=ExtResource("4_2qeh2")]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Wraps the mouse cursor around when panning the viewport."
section_name = "other"
setting_name = "wrap_mouse"
-[node name="UseCtrlForZoom" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/Input" instance=ExtResource("4_2qeh2")]
+[node name="UseCtrlForZoom" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/Input" instance=ExtResource("4_2qeh2")]
layout_mode = 2
tooltip_text = "If turned on, scrolling will pan the view. To zoom, hold CTRL while scrolling."
section_name = "other"
setting_name = "use_ctrl_for_zoom"
+[node name="FileDialog" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+theme_override_constants/separation = 3
+
+[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/FileDialog"]
+layout_mode = 2
+text = "Miscellaneous"
+
+[node name="UseNativeFileDialog" parent="VBoxContainer/HBoxContainer/MainPanel/ContentContainer/Other/OtherSettings/FileDialog" instance=ExtResource("4_2qeh2")]
+unique_name_in_owner = true
+layout_mode = 2
+tooltip_text = "Swaps zoom in and zoom out with the mouse wheel."
+section_name = "other"
+setting_name = "use_native_file_dialog"
+
[node name="Close" type="Button" parent="VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 4
diff --git a/src/ui_parts/svg_file_dialog.gd b/src/ui_parts/svg_file_dialog.gd
deleted file mode 100644
index 311ce27c..00000000
--- a/src/ui_parts/svg_file_dialog.gd
+++ /dev/null
@@ -1,10 +0,0 @@
-extends FileDialog
-
-func _on_file_selected(_path: String) -> void:
- queue_free()
-
-func _on_canceled() -> void:
- queue_free()
-
-func _on_confirmed() -> void:
- queue_free()
diff --git a/src/ui_parts/svg_file_dialog.tscn b/src/ui_parts/svg_file_dialog.tscn
deleted file mode 100644
index 31457a00..00000000
--- a/src/ui_parts/svg_file_dialog.tscn
+++ /dev/null
@@ -1,19 +0,0 @@
-[gd_scene load_steps=2 format=3 uid="uid://bndmdmjlwqxfh"]
-
-[ext_resource type="Script" path="res://src/ui_parts/svg_file_dialog.gd" id="1_nw1bg"]
-
-[node name="SVGFileDialog" type="FileDialog"]
-title = "Open a File"
-position = Vector2i(160, 135)
-size = Vector2i(700, 400)
-visible = true
-ok_button_text = "Open"
-cancel_button_text = "Cancel"
-file_mode = 0
-access = 2
-filters = PackedStringArray("*.svg ; Scalable vector graphics")
-script = ExtResource("1_nw1bg")
-
-[connection signal="canceled" from="." to="." method="_on_canceled"]
-[connection signal="confirmed" from="." to="." method="_on_confirmed"]
-[connection signal="file_selected" from="." to="." method="_on_file_selected"]
diff --git a/translations/GodSVG.pot b/translations/GodSVG.pot
index d03296e5..9c1460a4 100644
--- a/translations/GodSVG.pot
+++ b/translations/GodSVG.pot
@@ -325,6 +325,36 @@ msgstr ""
msgid "Disable the color"
msgstr ""
+msgid "Path"
+msgstr ""
+
+msgid "Replace"
+msgstr ""
+
+msgid "Go to parent folder"
+msgstr ""
+
+msgid "Refresh files"
+msgstr ""
+
+msgid "Toggle the visibility of hidden files"
+msgstr ""
+
+msgid "Search files"
+msgstr ""
+
+msgid "Select an SVG"
+msgstr ""
+
+msgid "Save SVG"
+msgstr ""
+
+msgid "Select"
+msgstr ""
+
+msgid "A file named \"{file_name}\" already exists. Replacing will overwrite its contents!"
+msgstr ""
+
msgid "Godot third-party components"
msgstr ""
diff --git a/translations/bg.po b/translations/bg.po
index 45ca1240..5babb104 100644
--- a/translations/bg.po
+++ b/translations/bg.po
@@ -328,6 +328,38 @@ msgstr "Включи цвета"
msgid "Disable the color"
msgstr "Изключи цвета"
+msgid "Path"
+msgstr "Пътека"
+
+msgid "Replace"
+msgstr "Замени"
+
+msgid "Go to parent folder"
+msgstr "Отиди в родителската папка"
+
+msgid "Refresh files"
+msgstr "Обнови файловете"
+
+msgid "Toggle the visibility of hidden files"
+msgstr "Превключи видимостта на скритите файлове"
+
+msgid "Search files"
+msgstr "Търсене из файловете"
+
+msgid "Select an SVG"
+msgstr "Избери SVG"
+
+msgid "Save SVG"
+msgstr "Запиши SVG"
+
+msgid "Select"
+msgstr "Избери"
+
+msgid ""
+"A file named \"{file_name}\" already exists. Replacing will overwrite its "
+"contents!"
+msgstr "Файл кръстен \"{file_name}\" вече съществува. Заместването ще пренапише неговото съдържание!"
+
msgid "Godot third-party components"
msgstr "Компоненти в Godot от трети лица"
diff --git a/translations/de.po b/translations/de.po
index 20dd01ac..9d174828 100644
--- a/translations/de.po
+++ b/translations/de.po
@@ -339,6 +339,43 @@ msgstr "Farbe aktivieren"
msgid "Disable the color"
msgstr "Farbe deaktivieren"
+#, fuzzy
+msgid "Path"
+msgstr "Pfade"
+
+msgid "Replace"
+msgstr ""
+
+msgid "Go to parent folder"
+msgstr ""
+
+msgid "Refresh files"
+msgstr ""
+
+msgid "Toggle the visibility of hidden files"
+msgstr ""
+
+#, fuzzy
+msgid "Search files"
+msgstr "Farbe suchen"
+
+#, fuzzy
+msgid "Select an SVG"
+msgstr "Alle Tags auswählen"
+
+#, fuzzy
+msgid "Save SVG"
+msgstr "Speichern"
+
+#, fuzzy
+msgid "Select"
+msgstr "Farbe löschen"
+
+msgid ""
+"A file named \"{file_name}\" already exists. Replacing will overwrite its "
+"contents!"
+msgstr ""
+
msgid "Godot third-party components"
msgstr "Godot Drittanbieter-Komponente"
diff --git a/translations/en.po b/translations/en.po
index 5dd32484..f2842b3c 100644
--- a/translations/en.po
+++ b/translations/en.po
@@ -326,6 +326,38 @@ msgstr ""
msgid "Disable the color"
msgstr ""
+msgid "Path"
+msgstr ""
+
+msgid "Replace"
+msgstr ""
+
+msgid "Go to parent folder"
+msgstr ""
+
+msgid "Refresh files"
+msgstr ""
+
+msgid "Toggle the visibility of hidden files"
+msgstr ""
+
+msgid "Search files"
+msgstr ""
+
+msgid "Select an SVG"
+msgstr ""
+
+msgid "Save SVG"
+msgstr ""
+
+msgid "Select"
+msgstr ""
+
+msgid ""
+"A file named \"{file_name}\" already exists. Replacing will overwrite its "
+"contents!"
+msgstr ""
+
msgid "Godot third-party components"
msgstr ""
diff --git a/translations/ru.po b/translations/ru.po
index 56e2b9ef..c3208d68 100644
--- a/translations/ru.po
+++ b/translations/ru.po
@@ -335,6 +335,43 @@ msgstr "Активировать цвет"
msgid "Disable the color"
msgstr "Деактивировать цвет"
+#, fuzzy
+msgid "Path"
+msgstr "Пути"
+
+msgid "Replace"
+msgstr ""
+
+msgid "Go to parent folder"
+msgstr ""
+
+msgid "Refresh files"
+msgstr ""
+
+msgid "Toggle the visibility of hidden files"
+msgstr ""
+
+#, fuzzy
+msgid "Search files"
+msgstr "Искать цвет"
+
+#, fuzzy
+msgid "Select an SVG"
+msgstr "Выбрать все теги"
+
+#, fuzzy
+msgid "Save SVG"
+msgstr "Сохранить"
+
+#, fuzzy
+msgid "Select"
+msgstr "Цвет выбранного"
+
+msgid ""
+"A file named \"{file_name}\" already exists. Replacing will overwrite its "
+"contents!"
+msgstr ""
+
msgid "Godot third-party components"
msgstr "Компоненты Godot от третьих лиц"
diff --git a/translations/uk.po b/translations/uk.po
index d765c042..8db21718 100644
--- a/translations/uk.po
+++ b/translations/uk.po
@@ -336,6 +336,43 @@ msgstr "Активувати колір"
msgid "Disable the color"
msgstr "Деактивувати колір"
+#, fuzzy
+msgid "Path"
+msgstr "Шляхи"
+
+msgid "Replace"
+msgstr ""
+
+msgid "Go to parent folder"
+msgstr ""
+
+msgid "Refresh files"
+msgstr ""
+
+msgid "Toggle the visibility of hidden files"
+msgstr ""
+
+#, fuzzy
+msgid "Search files"
+msgstr "Шукати колір"
+
+#, fuzzy
+msgid "Select an SVG"
+msgstr "Обрати усі теги"
+
+#, fuzzy
+msgid "Save SVG"
+msgstr "Зберегти"
+
+#, fuzzy
+msgid "Select"
+msgstr "Колір обраного"
+
+msgid ""
+"A file named \"{file_name}\" already exists. Replacing will overwrite its "
+"contents!"
+msgstr ""
+
msgid "Godot third-party components"
msgstr "Компоненти Godot від третіх сторін"
diff --git a/visual/icon.svg b/visual/icon.svg
index 564abd4e..317263a3 100644
--- a/visual/icon.svg
+++ b/visual/icon.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/visual/icons/DirDesktop.svg b/visual/icons/DirDesktop.svg
new file mode 100644
index 00000000..bee51115
--- /dev/null
+++ b/visual/icons/DirDesktop.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirDesktop.svg.import b/visual/icons/DirDesktop.svg.import
new file mode 100644
index 00000000..bf6712a9
--- /dev/null
+++ b/visual/icons/DirDesktop.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://7tukdjdfcrwg"
+path="res://.godot/imported/DirDesktop.svg-acb7dad19a064fd6b7cbb149a66be88c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirDesktop.svg"
+dest_files=["res://.godot/imported/DirDesktop.svg-acb7dad19a064fd6b7cbb149a66be88c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/DirDocuments.svg b/visual/icons/DirDocuments.svg
new file mode 100644
index 00000000..539e47c1
--- /dev/null
+++ b/visual/icons/DirDocuments.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirDocuments.svg.import b/visual/icons/DirDocuments.svg.import
new file mode 100644
index 00000000..a79b9978
--- /dev/null
+++ b/visual/icons/DirDocuments.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bpmks3pbl18rl"
+path="res://.godot/imported/DirDocuments.svg-b1ef55a3e2fd0b6809986fa07c707238.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirDocuments.svg"
+dest_files=["res://.godot/imported/DirDocuments.svg-b1ef55a3e2fd0b6809986fa07c707238.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/DirDownloads.svg b/visual/icons/DirDownloads.svg
new file mode 100644
index 00000000..35b4e588
--- /dev/null
+++ b/visual/icons/DirDownloads.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirDownloads.svg.import b/visual/icons/DirDownloads.svg.import
new file mode 100644
index 00000000..ea620f90
--- /dev/null
+++ b/visual/icons/DirDownloads.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://biq08throgeuw"
+path="res://.godot/imported/DirDownloads.svg-749be2df5e3e8e86654497d33aaef37a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirDownloads.svg"
+dest_files=["res://.godot/imported/DirDownloads.svg-749be2df5e3e8e86654497d33aaef37a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/DirMovies.svg b/visual/icons/DirMovies.svg
new file mode 100644
index 00000000..0a43fb26
--- /dev/null
+++ b/visual/icons/DirMovies.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirMovies.svg.import b/visual/icons/DirMovies.svg.import
new file mode 100644
index 00000000..9cf6229c
--- /dev/null
+++ b/visual/icons/DirMovies.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bix0itrhquk43"
+path="res://.godot/imported/DirMovies.svg-6502b6ed30bc262e78e211e2590f4935.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirMovies.svg"
+dest_files=["res://.godot/imported/DirMovies.svg-6502b6ed30bc262e78e211e2590f4935.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/DirMusic.svg b/visual/icons/DirMusic.svg
new file mode 100644
index 00000000..f5cfcd19
--- /dev/null
+++ b/visual/icons/DirMusic.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirMusic.svg.import b/visual/icons/DirMusic.svg.import
new file mode 100644
index 00000000..5cb39154
--- /dev/null
+++ b/visual/icons/DirMusic.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://yspvgvx4p5i7"
+path="res://.godot/imported/DirMusic.svg-1579bce19495d8501e24ddf74840513b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirMusic.svg"
+dest_files=["res://.godot/imported/DirMusic.svg-1579bce19495d8501e24ddf74840513b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/DirPictures.svg b/visual/icons/DirPictures.svg
new file mode 100644
index 00000000..86153c63
--- /dev/null
+++ b/visual/icons/DirPictures.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/DirPictures.svg.import b/visual/icons/DirPictures.svg.import
new file mode 100644
index 00000000..2e8e2773
--- /dev/null
+++ b/visual/icons/DirPictures.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ctulth0ybk2l7"
+path="res://.godot/imported/DirPictures.svg-031ed7212e88372d0a1bdba18111386e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/DirPictures.svg"
+dest_files=["res://.godot/imported/DirPictures.svg-031ed7212e88372d0a1bdba18111386e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/Folder.svg b/visual/icons/Folder.svg
new file mode 100644
index 00000000..53891da2
--- /dev/null
+++ b/visual/icons/Folder.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/Folder.svg.import b/visual/icons/Folder.svg.import
new file mode 100644
index 00000000..74a588f4
--- /dev/null
+++ b/visual/icons/Folder.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cba8p7b8tjiv3"
+path="res://.godot/imported/Folder.svg-82fa99ce41a31c247dc49e3ac68cce3f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/Folder.svg"
+dest_files=["res://.godot/imported/Folder.svg-82fa99ce41a31c247dc49e3ac68cce3f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/theme/FolderUp.svg b/visual/icons/FolderUp.svg
similarity index 100%
rename from visual/icons/theme/FolderUp.svg
rename to visual/icons/FolderUp.svg
diff --git a/visual/icons/theme/FolderUp.svg.import b/visual/icons/FolderUp.svg.import
similarity index 74%
rename from visual/icons/theme/FolderUp.svg.import
rename to visual/icons/FolderUp.svg.import
index 8f80bf9d..abe92ee2 100644
--- a/visual/icons/theme/FolderUp.svg.import
+++ b/visual/icons/FolderUp.svg.import
@@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://rrhdja8l17cn"
-path="res://.godot/imported/FolderUp.svg-b4eb7c260434a037353caaa49dc2e4f8.ctex"
+path="res://.godot/imported/FolderUp.svg-ea80ed3af2557e3c1b26b83ba445e18e.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://visual/icons/theme/FolderUp.svg"
-dest_files=["res://.godot/imported/FolderUp.svg-b4eb7c260434a037353caaa49dc2e4f8.ctex"]
+source_file="res://visual/icons/FolderUp.svg"
+dest_files=["res://.godot/imported/FolderUp.svg-ea80ed3af2557e3c1b26b83ba445e18e.ctex"]
[params]
diff --git a/visual/icons/Search.svg b/visual/icons/Search.svg
new file mode 100644
index 00000000..73a40c91
--- /dev/null
+++ b/visual/icons/Search.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/visual/icons/Search.svg.import b/visual/icons/Search.svg.import
new file mode 100644
index 00000000..1b2c30ec
--- /dev/null
+++ b/visual/icons/Search.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d4c7haflm8evm"
+path="res://.godot/imported/Search.svg-2dd99ab889ce67e689ca0f3320130c17.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://visual/icons/Search.svg"
+dest_files=["res://.godot/imported/Search.svg-2dd99ab889ce67e689ca0f3320130c17.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/visual/icons/tag/polyline.svg b/visual/icons/tag/polyline.svg
index c973db42..b33495f8 100644
--- a/visual/icons/tag/polyline.svg
+++ b/visual/icons/tag/polyline.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file