From dc846f95caab369725a306d5a5775b7df4f52420 Mon Sep 17 00:00:00 2001
From: Mew Pur Pur <85438892+MewPurPur@users.noreply.github.com>
Date: Wed, 10 Apr 2024 17:15:40 +0300
Subject: [PATCH] Ensure decent performance of GoodFileDialog (#647)
---
src/Indications.gd | 2 +-
src/SVG.gd | 2 +-
src/data_classes/Attribute.gd | 2 +-
src/data_classes/AttributeColor.gd | 2 +-
src/data_classes/AttributeEnum.gd | 2 +-
src/data_classes/AttributeList.gd | 2 +-
src/data_classes/AttributeNumeric.gd | 2 +-
src/data_classes/AttributePath.gd | 2 +-
src/data_classes/AttributeTransform.gd | 2 +-
src/data_classes/AttributeUnknown.gd | 2 +-
src/data_classes/ColorPalette.gd | 6 ++++
src/data_classes/Tag.gd | 2 +-
src/data_classes/TagEllipse.gd | 2 +-
src/data_classes/TagLine.gd | 2 +-
src/data_classes/TagPath.gd | 2 +-
src/data_classes/TagRect.gd | 2 +-
src/data_classes/TagSVG.gd | 2 +-
src/data_classes/TagStop.gd | 2 +-
src/data_classes/TagUnknown.gd | 2 +-
src/ui_elements/palette_config.gd | 4 ++-
src/ui_parts/good_file_dialog.gd | 48 ++++++++++++++++----------
21 files changed, 57 insertions(+), 37 deletions(-)
diff --git a/src/Indications.gd b/src/Indications.gd
index 5acc5071..89726204 100644
--- a/src/Indications.gd
+++ b/src/Indications.gd
@@ -1,5 +1,5 @@
-## This singleton handles editor information like zoom level and selections.
extends Node
+## This singleton handles editor information like zoom level and selections.
const ContextPopup = preload("res://src/ui_elements/context_popup.tscn")
const PathCommandPopup = preload("res://src/ui_elements/path_popup.tscn")
diff --git a/src/SVG.gd b/src/SVG.gd
index 1bffae45..839c2792 100644
--- a/src/SVG.gd
+++ b/src/SVG.gd
@@ -1,6 +1,6 @@
+extends Node
## This singleton handles the two representations of the SVG:
## The SVG text, and the native [TagSVG] representation.
-extends Node
signal parsing_finished(error_id: SVGParser.ParseError)
diff --git a/src/data_classes/Attribute.gd b/src/data_classes/Attribute.gd
index 9c7dc95a..5fc2d992 100644
--- a/src/data_classes/Attribute.gd
+++ b/src/data_classes/Attribute.gd
@@ -1,5 +1,5 @@
-## Abstract class for an attribute inside a [Tag], i.e.
class_name Attribute extends RefCounted
+## Abstract class for an attribute inside a [Tag], i.e.
signal value_changed(new_value: String)
signal propagate_value_changed(undo_redo: bool)
diff --git a/src/data_classes/AttributeColor.gd b/src/data_classes/AttributeColor.gd
index be11a01c..fa61d9fd 100644
--- a/src/data_classes/AttributeColor.gd
+++ b/src/data_classes/AttributeColor.gd
@@ -1,5 +1,5 @@
-## An attribute representing a color string, or an url to an ID.
class_name AttributeColor extends Attribute
+## An attribute representing a color string, or an url to an ID.
# No direct color representation for this attribute type. There are too many quirks.
diff --git a/src/data_classes/AttributeEnum.gd b/src/data_classes/AttributeEnum.gd
index 38fd0716..23b35676 100644
--- a/src/data_classes/AttributeEnum.gd
+++ b/src/data_classes/AttributeEnum.gd
@@ -1,5 +1,5 @@
-## An attribute with only a set of meaningful values.
class_name AttributeEnum extends Attribute
+## An attribute with only a set of meaningful values.
var possible_values: Array[String]
diff --git a/src/data_classes/AttributeList.gd b/src/data_classes/AttributeList.gd
index 5df3d54f..a61f2a52 100644
--- a/src/data_classes/AttributeList.gd
+++ b/src/data_classes/AttributeList.gd
@@ -1,5 +1,5 @@
-## An attribute representing a list of numbers.
class_name AttributeList extends Attribute
+## An attribute representing a list of numbers.
var _list: PackedFloat32Array
diff --git a/src/data_classes/AttributeNumeric.gd b/src/data_classes/AttributeNumeric.gd
index dfb07fde..8917ffb0 100644
--- a/src/data_classes/AttributeNumeric.gd
+++ b/src/data_classes/AttributeNumeric.gd
@@ -1,5 +1,5 @@
-## An attribute representing a number.
class_name AttributeNumeric extends Attribute
+## An attribute representing a number.
var _number := NAN
enum Mode {FLOAT, UFLOAT, NFLOAT} # UFLOAT is positive-only, NFLOAT is in [0, 1].
diff --git a/src/data_classes/AttributePath.gd b/src/data_classes/AttributePath.gd
index 35d33885..36cf0ad2 100644
--- a/src/data_classes/AttributePath.gd
+++ b/src/data_classes/AttributePath.gd
@@ -1,5 +1,5 @@
-## The "d" attribute of [TagPath].
class_name AttributePath extends Attribute
+## The "d" attribute of [TagPath].
var _commands: Array[PathCommand]
diff --git a/src/data_classes/AttributeTransform.gd b/src/data_classes/AttributeTransform.gd
index 59776d7c..f2bc2013 100644
--- a/src/data_classes/AttributeTransform.gd
+++ b/src/data_classes/AttributeTransform.gd
@@ -1,5 +1,5 @@
-## An attribute representing a list of transforms.
class_name AttributeTransform extends Attribute
+## An attribute representing a list of transforms.
class Transform extends RefCounted:
func compute_transform() -> Transform2D:
diff --git a/src/data_classes/AttributeUnknown.gd b/src/data_classes/AttributeUnknown.gd
index d99b0282..5f3a2c2c 100644
--- a/src/data_classes/AttributeUnknown.gd
+++ b/src/data_classes/AttributeUnknown.gd
@@ -1,5 +1,5 @@
-## An attribute not recognized by GodSVG.
class_name AttributeUnknown extends Attribute
+## An attribute not recognized by GodSVG.
var name := ""
diff --git a/src/data_classes/ColorPalette.gd b/src/data_classes/ColorPalette.gd
index 04f07990..2d9cf3e5 100644
--- a/src/data_classes/ColorPalette.gd
+++ b/src/data_classes/ColorPalette.gd
@@ -1,4 +1,7 @@
class_name ColorPalette extends Resource
+## A resource for the color palettes that are listed in the color picker.
+
+signal layout_changed
@export var title: String # Color palettes must be uniquely named.
@export var colors: Array[String] # Colors must be unique within a palette.
@@ -16,11 +19,13 @@ func add_color() -> void:
colors.append("none")
color_names.append("")
emit_changed()
+ layout_changed.emit()
func remove_color(idx: int) -> void:
colors.remove_at(idx)
color_names.remove_at(idx)
emit_changed()
+ layout_changed.emit()
func move_color(old_idx: int, new_idx: int) -> void:
if old_idx == new_idx:
@@ -32,6 +37,7 @@ func move_color(old_idx: int, new_idx: int) -> void:
colors.insert(new_idx, colors.pop_at(old_idx))
color_names.insert(new_idx, color_names.pop_at(old_idx))
emit_changed()
+ layout_changed.emit()
func modify_title(new_title: String) -> void:
title = new_title
diff --git a/src/data_classes/Tag.gd b/src/data_classes/Tag.gd
index 3fd0fc08..808a3ad9 100644
--- a/src/data_classes/Tag.gd
+++ b/src/data_classes/Tag.gd
@@ -1,5 +1,5 @@
-## A SVG tag, standalone ([code][/code]) or container ([code][/code]).
class_name Tag extends RefCounted
+## A SVG tag, standalone ([code][/code]) or container ([code][/code]).
var child_tags: Array[Tag]
diff --git a/src/data_classes/TagEllipse.gd b/src/data_classes/TagEllipse.gd
index cb8135bf..35ad806f 100644
--- a/src/data_classes/TagEllipse.gd
+++ b/src/data_classes/TagEllipse.gd
@@ -1,5 +1,5 @@
-## An tag.
class_name TagEllipse extends Tag
+## An tag.
const name = "ellipse"
const possible_conversions = ["circle", "rect", "path"]
diff --git a/src/data_classes/TagLine.gd b/src/data_classes/TagLine.gd
index 54831c29..ac4d4cd6 100644
--- a/src/data_classes/TagLine.gd
+++ b/src/data_classes/TagLine.gd
@@ -1,5 +1,5 @@
-## A tag.
class_name TagLine extends Tag
+## A tag.
const name = "line"
const possible_conversions = ["path"]
diff --git a/src/data_classes/TagPath.gd b/src/data_classes/TagPath.gd
index 8f3ee23d..6fe775a9 100644
--- a/src/data_classes/TagPath.gd
+++ b/src/data_classes/TagPath.gd
@@ -1,5 +1,5 @@
-## A tag.
class_name TagPath extends Tag
+## A tag.
const name = "path"
const possible_conversions = []
diff --git a/src/data_classes/TagRect.gd b/src/data_classes/TagRect.gd
index f3ea8eba..12fdb111 100644
--- a/src/data_classes/TagRect.gd
+++ b/src/data_classes/TagRect.gd
@@ -1,5 +1,5 @@
-## A tag.
class_name TagRect extends Tag
+## A tag.
const name = "rect"
const possible_conversions = ["circle", "ellipse", "path"]
diff --git a/src/data_classes/TagSVG.gd b/src/data_classes/TagSVG.gd
index b3dc610d..3934c15b 100644
--- a/src/data_classes/TagSVG.gd
+++ b/src/data_classes/TagSVG.gd
@@ -1,5 +1,5 @@
-## A tag.
class_name TagSVG extends Tag
+## A tag.
var width: float
var height: float
diff --git a/src/data_classes/TagStop.gd b/src/data_classes/TagStop.gd
index a8d7c899..2793bb79 100644
--- a/src/data_classes/TagStop.gd
+++ b/src/data_classes/TagStop.gd
@@ -1,5 +1,5 @@
-## A tag.
class_name TagStop extends Tag
+## A tag.
const name = "stop"
const possible_conversions = []
diff --git a/src/data_classes/TagUnknown.gd b/src/data_classes/TagUnknown.gd
index abc4e1ca..fea637a4 100644
--- a/src/data_classes/TagUnknown.gd
+++ b/src/data_classes/TagUnknown.gd
@@ -1,5 +1,5 @@
-## A tag not recognized by GodSVG.
class_name TagUnknown extends Tag
+## A tag not recognized by GodSVG.
var name: String
const possible_conversions = []
diff --git a/src/ui_elements/palette_config.gd b/src/ui_elements/palette_config.gd
index 6aca02b3..18149a80 100644
--- a/src/ui_elements/palette_config.gd
+++ b/src/ui_elements/palette_config.gd
@@ -20,7 +20,7 @@ var currently_edited_idx := -1
# Used to setup a palette for this element.
func assign_palette(palette: ColorPalette) -> void:
current_palette = palette
- current_palette.changed.connect(rebuild_colors)
+ current_palette.layout_changed.connect(rebuild_colors)
rebuild_colors()
# Rebuilds the content of the colors container.
@@ -232,8 +232,10 @@ func _drop_data(_at_position: Vector2, data: Variant) -> void:
return
if data[0] == current_palette:
+ currently_edited_idx = -1
current_palette.move_color(data[1], proposed_drop_idx)
else:
+ currently_edited_idx = -1
current_palette.colors.insert(proposed_drop_idx, data[0].colors[data[1]])
current_palette.color_names.insert(proposed_drop_idx, data[0].color_names[data[1]])
current_palette.emit_changed()
diff --git a/src/ui_parts/good_file_dialog.gd b/src/ui_parts/good_file_dialog.gd
index 031cf937..1d96079e 100644
--- a/src/ui_parts/good_file_dialog.gd
+++ b/src/ui_parts/good_file_dialog.gd
@@ -78,6 +78,7 @@ new_extension: String) -> void:
extension = new_extension
func _ready() -> void:
+ file_list.get_v_scroll_bar().value_changed.connect(_setup_file_images.unbind(1))
if mode == FileMode.SELECT:
file_container.hide()
if mode == FileMode.SAVE:
@@ -163,24 +164,11 @@ func set_dir(dir: String) -> void:
(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()
+ var item_idx := file_list.add_item(file, null)
+ file_list.set_item_metadata(item_idx,
+ Actions.new(select_file, focus_file.bind(file)))
+ await get_tree().process_frame
+ _setup_file_images()
func set_file(file: String) -> void:
if mode == FileMode.SELECT:
@@ -193,9 +181,33 @@ func set_file(file: String) -> void:
if not file.is_empty():
if file.get_extension() != extension:
file += "." + extension
+ file_list.ensure_current_is_visible()
current_file = file
file_field.text = current_file
+# For optimization, only generate the visible files' images.
+func _setup_file_images() -> void:
+ var visible_start := file_list.position.y + file_list.get_v_scroll_bar().value
+ var visible_end := visible_start + file_list.size.y
+ for item_idx in file_list.item_count:
+ var file_rect := file_list.get_item_rect(item_idx)
+ if file_list.get_item_icon(item_idx) == null and\
+ file_rect.end.y > visible_start and file_rect.position.y < visible_end:
+ var file := file_list.get_item_text(item_idx)
+ match file.get_extension():
+ "png":
+ file_list.set_item_icon(item_idx, ImageTexture.create_from_image(
+ Image.load_from_file(current_dir.path_join(file))))
+ "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()))
+ file_list.set_item_icon(item_idx, ImageTexture.create_from_image(img))
+
func select_file() -> void:
if mode == FileMode.SAVE and current_file in DirAccess.get_files_at(current_dir):