diff --git a/addons/pandora/api.gd b/addons/pandora/api.gd
index a9cb333b..f54e6898 100644
--- a/addons/pandora/api.gd
+++ b/addons/pandora/api.gd
@@ -13,6 +13,7 @@ signal import_failed(reason: String)
signal import_calculation_ended(import_info: Dictionary)
signal import_calculation_failed(reason: String)
signal import_progress
+signal update_fields_settings(type: String)
var _context_manager: PandoraContextManager
var _storage: PandoraDataStorage
diff --git a/addons/pandora/icons/ExtensionsSettings.svg b/addons/pandora/icons/ExtensionsSettings.svg
new file mode 100644
index 00000000..948b6316
--- /dev/null
+++ b/addons/pandora/icons/ExtensionsSettings.svg
@@ -0,0 +1,138 @@
+
+
\ No newline at end of file
diff --git a/addons/pandora/icons/ExtensionsSettings.svg.import b/addons/pandora/icons/ExtensionsSettings.svg.import
new file mode 100644
index 00000000..ff60eb2c
--- /dev/null
+++ b/addons/pandora/icons/ExtensionsSettings.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cqxxv5pilfslw"
+path="res://.godot/imported/ExtensionsSettings.svg-7b09f161a7fd97a3789aaef5788d6005.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/pandora/icons/ExtensionsSettings.svg"
+dest_files=["res://.godot/imported/ExtensionsSettings.svg-7b09f161a7fd97a3789aaef5788d6005.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/addons/pandora/model/entity.gd b/addons/pandora/model/entity.gd
index ca8d1331..c578541b 100644
--- a/addons/pandora/model/entity.gd
+++ b/addons/pandora/model/entity.gd
@@ -111,7 +111,15 @@ class OverridingProperty:
var value = _parent_entity._property_overrides[_property.get_property_name()]
if value is PandoraReference:
return value.get_entity()
- return value
+ # Parse the value through the property type to handle conversions
+ # (e.g., String paths to Resources)
+ var parsed_value = _property.get_property_type().parse_value(value, {})
+ # Duplicate RefCounted objects (custom classes like Pandora+, etc.)
+ # to avoid reference sharing between entities.
+ # Don't duplicate Resources (Texture, AudioStream, etc.) as they are shared assets.
+ if parsed_value != null and parsed_value is RefCounted and parsed_value.has_method("duplicate"):
+ return parsed_value.duplicate()
+ return parsed_value
return _property.get_default_value()
func get_property_id() -> String:
diff --git a/addons/pandora/model/property.gd b/addons/pandora/model/property.gd
index 301e2c85..f4c7c068 100644
--- a/addons/pandora/model/property.gd
+++ b/addons/pandora/model/property.gd
@@ -37,7 +37,7 @@ func _init(id: String, name: String, type_name: String) -> void:
func get_setting(key: String) -> Variant:
if has_setting_override(key):
return _setting_overrides[key]
- elif _type != null:
+ elif _type != null and _type.get_settings().has(key):
return _type.get_settings()[key]["value"]
else:
return null
@@ -95,6 +95,10 @@ func get_property_type() -> PandoraPropertyType:
func get_default_value() -> Variant:
if _default_value is PandoraReference:
return _default_value.get_entity()
+ # If the default value has a duplicate() method, use it to avoid reference sharing. This is important for complex types.
+ # Only Objects have has_method(), so check type first
+ if _default_value != null and _default_value is Object and _default_value.has_method("duplicate"):
+ return _default_value.duplicate()
return _default_value
diff --git a/addons/pandora/model/types/resource.gd b/addons/pandora/model/types/resource.gd
index dc912c27..f25a5933 100644
--- a/addons/pandora/model/types/resource.gd
+++ b/addons/pandora/model/types/resource.gd
@@ -11,15 +11,27 @@ func _init() -> void:
func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
if variant is String:
- return load(variant)
+ # Handle empty strings as null to avoid "res://" loading errors
+ if variant == "":
+ return null
+ # Load the resource and handle potential errors
+ var resource = load(variant)
+ if resource == null:
+ push_warning("Failed to load resource: " + variant)
+ return resource
return variant
func write_value(variant: Variant) -> Variant:
+ if variant == null:
+ return null
if variant is Resource:
return variant.resource_path
return variant
func is_valid(variant: Variant) -> bool:
- return variant is Resource
+ # Allow null as valid value for optional resources
+ # Allow String (resource paths) as they will be converted to Resources
+ # Allow Resource objects directly
+ return variant == null or variant is Resource or variant is String
diff --git a/addons/pandora/plugin.gd b/addons/pandora/plugin.gd
index acd96b1e..b95fc051 100644
--- a/addons/pandora/plugin.gd
+++ b/addons/pandora/plugin.gd
@@ -13,6 +13,12 @@ var _exporter: PandoraExportPlugin
func _init() -> void:
self.name = 'PandoraPlugin'
+func _ready() -> void:
+ if not DirAccess.dir_exists_absolute("res://pandora/extensions/"):
+ DirAccess.make_dir_recursive_absolute("res://pandora/extensions/")
+ if not FileAccess.file_exists("res://pandora/extensions/configuration.json"):
+ var extensionsDir = DirAccess.open("res://pandora/extensions/")
+ extensionsDir.copy("res://addons/pandora/util/configuration_template.json", "res://pandora/extensions/configuration.json")
func _enter_tree() -> void:
Engine.set_meta("PandoraEditorPlugin", self)
@@ -37,7 +43,6 @@ func _enter_tree() -> void:
_make_visible(false)
-
func _apply_changes() -> void:
if Engine.is_editor_hint() and is_instance_valid(editor_view):
if editor_view.has_method("apply_changes"):
diff --git a/addons/pandora/settings/pandora_settings.gd b/addons/pandora/settings/pandora_settings.gd
index 2eae6865..7bc40227 100644
--- a/addons/pandora/settings/pandora_settings.gd
+++ b/addons/pandora/settings/pandora_settings.gd
@@ -25,6 +25,8 @@ const DEFAULT_PANDORA_EXTENSIONS_DIR: Array[StringName] = ["res://pandora/extens
static var extensions_models: Dictionary[String, RefCounted] = {}
static var extensions_types: Dictionary[String, String] = {}
+static var extensions_configurations: Array[Dictionary] = []
+static var extensions_confs_map: Dictionary[String, int] = {}
static func initialize() -> void:
init_setting(
@@ -75,6 +77,7 @@ static func init_setting(
"hint_string": hint_string,
}
ProjectSettings.add_property_info(info)
+ _load_all_extensions_configuration()
_check_new_extensions_models()
static func get_id_type() -> IDType:
@@ -110,10 +113,36 @@ static func get_extensions_dirs() -> Array:
DEFAULT_PANDORA_EXTENSIONS_DIR
)
+static func get_extensions_configurations() -> Array[Dictionary]:
+ return extensions_configurations
+
+static func get_extensions_confs_map() -> Dictionary:
+ return extensions_confs_map
+
static func set_extensions_dir(array: Array) -> void:
ProjectSettings.set_setting(SETTINGS_PANDORA_EXTENSIONS_DIR, array)
+ _load_all_extensions_configuration()
_check_new_extensions_models()
+static func find_extension_configuration_property(type: String) -> Dictionary:
+ for conf in extensions_configurations:
+ for property in conf["properties"]:
+ if property and property.has("dir_name") and property["dir_name"] == type:
+ return property
+ return {}
+
+static func _load_all_extensions_configuration() -> void:
+ var extensions_dirs = PandoraSettings.get_extensions_dirs()
+ for extensions_dir in extensions_dirs:
+ var configuration_file = FileAccess.open(extensions_dir + "/configuration.json", FileAccess.READ)
+ if not configuration_file:
+ push_error("Impossible to load the configuration from " + extensions_dir)
+ else:
+ var configuration_dic = JSON.parse_string(configuration_file.get_as_text())
+ if not extensions_configurations.has(configuration_dic):
+ extensions_configurations.append(configuration_dic)
+ extensions_confs_map[extensions_dir] = extensions_configurations.size() - 1
+
static func _check_new_extensions_models() -> void:
var extensions_dirs = PandoraSettings.get_extensions_dirs()
for extensions_dir in extensions_dirs:
@@ -146,6 +175,30 @@ static func compare_with_extensions_models(value) -> bool:
return true
return false
+static func save_extensions_configurations() -> void:
+ var extensions_dirs = PandoraSettings.get_extensions_dirs()
+ var extensions_confs_map = PandoraSettings.get_extensions_confs_map()
+ var extensions_configurations = PandoraSettings.get_extensions_configurations()
+ for extensions_dir in extensions_dirs:
+ var configuration_file = FileAccess.open(extensions_dir + "/configuration.json", FileAccess.WRITE)
+ var extensions_confs_idx: int = extensions_confs_map[extensions_dir] as int
+ var extensions_configuration = extensions_configurations[extensions_confs_idx]
+ configuration_file.store_string(JSON.stringify(extensions_configuration, "\t"))
+ configuration_file.close()
+
+static func get_property_dependencies_by(current_property: Dictionary) -> Array[Dictionary]:
+ var extensions_configurations = PandoraSettings.get_extensions_configurations()
+ var property_dependencies : Array[Dictionary] = []
+ var current_dependencies := current_property["dependencies"] as Array
+ var current_prop_dependencies = current_dependencies.filter(func(dep: Dictionary): return dep["type"] == "PROPERTY")
+ for current_dependency in current_prop_dependencies:
+ for ext_configuration in extensions_configurations:
+ var ext_conf_properties := ext_configuration["properties"] as Array
+ var property_dependency := ext_conf_properties.filter(func(p: Dictionary): return p["name"] == current_dependency["name"])
+ if property_dependency:
+ property_dependencies.append(property_dependency[0])
+ return property_dependencies
+
static func get_lookup_property_name(value) -> String:
for emodel in extensions_models:
if not value is Dictionary and not value is Color:
diff --git a/addons/pandora/ui/components/properties/property_control.gd b/addons/pandora/ui/components/properties/property_control.gd
index bf09bf6b..e5a659f0 100644
--- a/addons/pandora/ui/components/properties/property_control.gd
+++ b/addons/pandora/ui/components/properties/property_control.gd
@@ -8,11 +8,31 @@ signal unfocused
@export var type: String
var _property: PandoraProperty
+var _fields_settings: Array = []
+func _notification(what: int) -> void:
+ if what == NOTIFICATION_PARENTED:
+ var ext_conf_property := PandoraSettings.find_extension_configuration_property(type)
+ if ext_conf_property.has("enabled") and not ext_conf_property["enabled"]:
+ push_error("You are trying to instantiate/add a scene that is part of a property disabled by Pandora's configurations. Are you sure you want to continue?")
func init(property: PandoraProperty) -> void:
self._property = property
-
+ print("init ", property)
+ _load_fields_settings()
func refresh() -> void:
pass
+
+func update_field_settings(field_settings: Dictionary) -> void:
+ _load_fields_settings()
+ var fs := _fields_settings.filter(func(dic: Dictionary): return dic["name"] == field_settings["name"])[0] as Dictionary
+ var fs_idx := _fields_settings.find(fs)
+ _fields_settings[fs_idx] = field_settings
+ Pandora.update_fields_settings.emit(type)
+
+func _load_fields_settings() -> void:
+ if _fields_settings.is_empty():
+ var extension_configuration := PandoraSettings.find_extension_configuration_property(type)
+ if not extension_configuration.is_empty():
+ _fields_settings = extension_configuration["fields"] as Array
diff --git a/addons/pandora/ui/components/properties/resource/resource_property.gd b/addons/pandora/ui/components/properties/resource/resource_property.gd
index 97074aa9..7bbd1563 100644
--- a/addons/pandora/ui/components/properties/resource/resource_property.gd
+++ b/addons/pandora/ui/components/properties/resource/resource_property.gd
@@ -11,12 +11,29 @@ func _ready() -> void:
resource_picker.focus_entered.connect(func(): focused.emit())
resource_picker.resource_changed.connect(
func(resource_path:String):
- _property.set_default_value(load(resource_path))
+ # Store the path as string, not the loaded resource
+ # The type system will handle conversion via parse_value/write_value
+ _property.set_default_value(resource_path)
+ refresh()
property_value_changed.emit(resource_path))
func refresh() -> void:
if _property != null:
- var default_value = _property.get_default_value() as Resource
- if default_value != null:
- resource_picker.set_resource_path(default_value.resource_path)
+ # Get the raw value from overrides to avoid parse_value conversion
+ var raw_value = null
+ if _property is PandoraEntity.OverridingProperty:
+ var prop_name = _property.get_property_name()
+ if _property._parent_entity._property_overrides.has(prop_name):
+ raw_value = _property._parent_entity._property_overrides[prop_name]
+
+ if raw_value == null:
+ raw_value = _property.get_default_value()
+
+ # Handle both String paths and Resource objects
+ if raw_value is String and raw_value != "":
+ resource_picker.set_resource_path(raw_value)
+ elif raw_value is Resource and raw_value.resource_path != "":
+ resource_picker.set_resource_path(raw_value.resource_path)
+ else:
+ resource_picker.set_resource_path("")
diff --git a/addons/pandora/ui/components/property_bar/property_bar.gd b/addons/pandora/ui/components/property_bar/property_bar.gd
index 57f6de28..04a63cb1 100644
--- a/addons/pandora/ui/components/property_bar/property_bar.gd
+++ b/addons/pandora/ui/components/property_bar/property_bar.gd
@@ -20,13 +20,45 @@ func get_scene_by_type(type: String) -> PackedScene:
return type_to_scene[type]
func add_extensions_button() -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_confs_map := PandoraSettings.get_extensions_confs_map()
var extensions_dirs = PandoraSettings.get_extensions_dirs()
for extensions_dir in extensions_dirs:
+ var extensions_configuration_idx := extensions_confs_map[extensions_dir] as int
+ var extensions_configuration := extensions_configurations[extensions_configuration_idx] as Dictionary
+ var extension_properties := extensions_configuration["properties"] as Array
+
var main_dir = DirAccess.open(extensions_dir)
for ed_path in main_dir.get_directories():
- var extension_dir = DirAccess.open(extensions_dir + "/" + ed_path)
- assert(extension_dir.dir_exists("property_button"))
- var property_button_dir = DirAccess.open(extensions_dir + "/" + ed_path + "/property_button/")
- var scene_path : String = extensions_dir + "/" + ed_path + "/property_button/property_button.tscn"
- var scene = load(scene_path).instantiate()
- add_child(scene)
+ var extension_property = extension_properties.filter(func(property: Dictionary): return property["dir_name"] == ed_path)[0] as Dictionary
+ if extension_property["enabled"]:
+ var extension_dir = DirAccess.open(extensions_dir + "/" + ed_path)
+ assert(extension_dir.dir_exists("property_button"))
+ var property_button_dir = DirAccess.open(extensions_dir + "/" + ed_path + "/property_button/")
+ var scene_path : String = extensions_dir + "/" + ed_path + "/property_button/property_button.tscn"
+ var scene = load(scene_path).instantiate()
+ scene.visible = extension_property["show_on_top"]
+ add_child(scene)
+
+func updates_property_bar_buttons() -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_confs_map := PandoraSettings.get_extensions_confs_map()
+ var extensions_dirs = PandoraSettings.get_extensions_dirs()
+ for extensions_dir in extensions_dirs:
+ var extensions_configuration_idx := extensions_confs_map[extensions_dir] as int
+ var extensions_configuration := extensions_configurations[extensions_configuration_idx] as Dictionary
+ var extension_properties := extensions_configuration["properties"] as Array
+ for extension_property in extension_properties:
+ var btn = get_children().filter(func(node: Node):
+ var node_instance = node.scene.instantiate()
+ var check = node_instance.type == extension_property["dir_name"]
+ node_instance.queue_free()
+ return check)
+ if btn:
+ if extension_property["enabled"]:
+ if extension_property["show_on_top"]:
+ btn[0].show()
+ else:
+ btn[0].hide()
+ else:
+ btn[0].hide()
diff --git a/addons/pandora/ui/components/resource_picker/resource_picker.gd b/addons/pandora/ui/components/resource_picker/resource_picker.gd
index b4a5d702..b33c130d 100644
--- a/addons/pandora/ui/components/resource_picker/resource_picker.gd
+++ b/addons/pandora/ui/components/resource_picker/resource_picker.gd
@@ -17,6 +17,12 @@ func _ready() -> void:
func set_resource_path(path: String) -> void:
+ # Handle empty path - clear the field
+ if path == "":
+ line_edit.text = ""
+ self.resource_path = ""
+ return
+
var resource = load(path) as Resource
if resource != null:
line_edit.text = path
diff --git a/addons/pandora/ui/editor/pandora_editor.gd b/addons/pandora/ui/editor/pandora_editor.gd
index a34e06ae..ebe6d6ab 100644
--- a/addons/pandora/ui/editor/pandora_editor.gd
+++ b/addons/pandora/ui/editor/pandora_editor.gd
@@ -7,6 +7,7 @@ class_name PandoraEditor extends Control
@onready var create_entity_button: Button = %CreateEntityButton
@onready var create_category_button: Button = %CreateCategoryButton
@onready var import_button: Button = %ImportButton
+@onready var settings_button: Button = %SettingsButton
@onready var delete_button = %DeleteButton
@onready var property_editor = %PropertyEditor
@onready var regenerate_id_button: Button = %RegenerateIDButton
@@ -14,6 +15,7 @@ class_name PandoraEditor extends Control
@onready var version = %Version
@onready var save_label = %SaveLabel
@onready var import_dialog = %ImportDialog
+@onready var settings_dialog = %SettingsDialog
@onready var progress_bar = %ProgressBar
@onready var data_content = %DataContent
@@ -22,7 +24,6 @@ class_name PandoraEditor extends Control
var selected_entity: PandoraEntity
var _load_error = false
-
func _ready() -> void:
save_button.pressed.connect(_save)
tree.entity_selected.connect(_entity_selected)
@@ -37,6 +38,7 @@ func _ready() -> void:
reset_button.pressed.connect(_reset_to_saved_file)
delete_button.pressed.connect(func(): tree.queue_delete(selected_entity.get_entity_id()))
import_button.pressed.connect(func(): import_dialog.open())
+ settings_button.pressed.connect(func(): settings_dialog.open())
import_dialog.import_started.connect(func(import_count: int): progress_bar.init(import_count))
import_dialog.import_ended.connect(_on_import_ended)
diff --git a/addons/pandora/ui/editor/pandora_editor.tscn b/addons/pandora/ui/editor/pandora_editor.tscn
index a2c9a1da..f45c2aa9 100644
--- a/addons/pandora/ui/editor/pandora_editor.tscn
+++ b/addons/pandora/ui/editor/pandora_editor.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=17 format=3 uid="uid://0bxxjjroysub"]
+[gd_scene load_steps=19 format=3 uid="uid://0bxxjjroysub"]
[ext_resource type="Script" uid="uid://b4f7fhcompuon" path="res://addons/pandora/ui/editor/pandora_editor.gd" id="1_bowve"]
[ext_resource type="Texture2D" uid="uid://dojpd3ptnta4m" path="res://addons/pandora/icons/Object.svg" id="2_aj8uc"]
@@ -12,10 +12,12 @@
[ext_resource type="Texture2D" uid="uid://bhcep67ihojnd" path="res://addons/pandora/icons/Reload.svg" id="5_qbvn0"]
[ext_resource type="PackedScene" uid="uid://dsqfuyjkcdwvu" path="res://addons/pandora/ui/components/notification_label/notification_label.tscn" id="6_ftkgr"]
[ext_resource type="Texture2D" uid="uid://dp8it1xjb8k2g" path="res://addons/pandora/icons/AssetLib.svg" id="8_wruey"]
+[ext_resource type="Texture2D" uid="uid://cqxxv5pilfslw" path="res://addons/pandora/icons/ExtensionsSettings.svg" id="9_aw1n3"]
[ext_resource type="PackedScene" uid="uid://dibfkp6i5uvgi" path="res://addons/pandora/ui/components/progress_bar/progress_bar.tscn" id="10_xf8wv"]
[ext_resource type="PackedScene" uid="uid://dy4xl20q2nq7q" path="res://addons/pandora/ui/components/update_button/update_button.tscn" id="11_cva2e"]
[ext_resource type="Texture2D" uid="uid://crgjwaubao8pj" path="res://addons/pandora/icons/icon.png" id="15_3jwvj"]
[ext_resource type="PackedScene" uid="uid://ceboo5esbe2ld" path="res://addons/pandora/ui/editor/import_dialog/import_dialog.tscn" id="15_umv0u"]
+[ext_resource type="PackedScene" uid="uid://ctp7xnvi5ep0e" path="res://addons/pandora/ui/editor/settings_dialog/settings_dialog.tscn" id="18_yfrlk"]
[node name="PandoraEditor" type="MarginContainer"]
clip_contents = true
@@ -89,6 +91,12 @@ layout_mode = 2
tooltip_text = "Import Data File"
icon = ExtResource("8_wruey")
+[node name="SettingsButton" type="Button" parent="Contents/HeaderBar/Actions"]
+unique_name_in_owner = true
+layout_mode = 2
+tooltip_text = "Extensions Settings"
+icon = ExtResource("9_aw1n3")
+
[node name="SaveLabel" parent="Contents/HeaderBar/Actions" instance=ExtResource("6_ftkgr")]
unique_name_in_owner = true
visible = false
@@ -130,7 +138,7 @@ unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 1
theme_override_colors/font_color = Color(1, 1, 1, 0.27451)
-text = "Pandora v1.0-alpha4"
+text = "Pandora v1.0-alpha10-dev"
horizontal_alignment = 2
vertical_alignment = 1
justification_flags = 0
@@ -208,3 +216,9 @@ unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 0
+
+[node name="SettingsDialog" parent="." instance=ExtResource("18_yfrlk")]
+unique_name_in_owner = true
+layout_mode = 2
+
+[connection signal="update_extensions_configurations" from="SettingsDialog" to="Contents/DataContent/HSplitContainer/PropertyEditor" method="_on_update_extensions_configurations"]
diff --git a/addons/pandora/ui/editor/property_editor/property_editor.gd b/addons/pandora/ui/editor/property_editor/property_editor.gd
index 715000ac..e7d3219b 100644
--- a/addons/pandora/ui/editor/property_editor/property_editor.gd
+++ b/addons/pandora/ui/editor/property_editor/property_editor.gd
@@ -100,3 +100,7 @@ func _generate_property_name(type: String, entity: PandoraEntity) -> String:
if properties.is_empty() or not entity.has_entity_property(property_name):
return property_name
return property_name + str(properties.size())
+
+
+func _on_update_extensions_configurations() -> void:
+ property_bar.updates_property_bar_buttons()
diff --git a/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd b/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd
index e7098d01..6d687244 100644
--- a/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd
+++ b/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd
@@ -19,6 +19,7 @@ func set_property(property: PandoraProperty) -> void:
self._property = property
if property:
var property_type = property.get_property_type()
+ print(property_type.get_settings())
if property_type.get_type_name() == "array":
self._default_settings = property_type.get_merged_settings(property)
else:
diff --git a/addons/pandora/ui/editor/settings_dialog/dependency.gd b/addons/pandora/ui/editor/settings_dialog/dependency.gd
new file mode 100644
index 00000000..062d74bc
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/dependency.gd
@@ -0,0 +1,16 @@
+@tool
+class_name Dependency
+extends PanelContainer
+
+signal removed(dependency: Dictionary)
+
+@onready var label: Label = $MarginContainer/HBoxContainer/Label
+
+var dependency: Dictionary
+
+func _ready() -> void:
+ label.text = dependency["name"]
+
+func _on_button_pressed() -> void:
+ removed.emit(dependency)
+ queue_free()
diff --git a/addons/pandora/ui/editor/settings_dialog/dependency.gd.uid b/addons/pandora/ui/editor/settings_dialog/dependency.gd.uid
new file mode 100644
index 00000000..3d2abcb3
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/dependency.gd.uid
@@ -0,0 +1 @@
+uid://bo02nc6r2276o
diff --git a/addons/pandora/ui/editor/settings_dialog/dependency.tscn b/addons/pandora/ui/editor/settings_dialog/dependency.tscn
new file mode 100644
index 00000000..ab774e96
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/dependency.tscn
@@ -0,0 +1,29 @@
+[gd_scene load_steps=3 format=3 uid="uid://dn5yxfosec2ta"]
+
+[ext_resource type="Script" uid="uid://bo02nc6r2276o" path="res://addons/pandora/ui/editor/settings_dialog/dependency.gd" id="1_cka5m"]
+[ext_resource type="Texture2D" uid="uid://b2s1ixfakdj1e" path="res://addons/pandora/icons/Remove.svg" id="2_u7abk"]
+
+[node name="Dependency" type="PanelContainer"]
+offset_right = 129.0
+offset_bottom = 28.0
+script = ExtResource("1_cka5m")
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+layout_mode = 2
+theme_override_constants/margin_left = 15
+theme_override_constants/margin_top = 2
+theme_override_constants/margin_bottom = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="Label" type="Label" parent="MarginContainer/HBoxContainer"]
+layout_mode = 2
+text = "Dependency"
+
+[node name="Button" type="Button" parent="MarginContainer/HBoxContainer"]
+layout_mode = 2
+icon = ExtResource("2_u7abk")
+
+[connection signal="pressed" from="MarginContainer/HBoxContainer/Button" to="." method="_on_button_pressed"]
diff --git a/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd b/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd
new file mode 100644
index 00000000..08aa3d8c
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd
@@ -0,0 +1,343 @@
+@tool
+extends Control
+
+signal update_extensions_configurations
+
+const DependencyScene = preload("uid://dn5yxfosec2ta")
+const STRING_FIELD_SETTINGS = preload("uid://bn7da5ljy5mqh")
+const RANGE_FIELD_SETTINGS = preload("uid://cyd24jwivayf5")
+const ARRAY_FIELD_SETTINGS = preload("uid://cgwd2gdv7xeia")
+const REFERENCE_FIELD_SETTINGS = preload("uid://d3a0188wd61px")
+const OPTIONS_FIELD_SETTINGS = preload("uid://7c8j3yx3hnr4")
+const BOOL_FIELD_SETTINGS = preload("uid://bm6rmjycqduyn")
+
+@onready var window: Window = $Window
+@onready var extensions_list: ItemList = $Window/PanelContainer/HBoxContainer/ExtensionsContainer/ItemList
+@onready var extension_label: Label = $Window/PanelContainer/HBoxContainer/VBoxContainer/Label
+@onready var select_extension_label: Label = %SelectExtension
+@onready var no_properties_label: Label = %NoProperties
+@onready var ext_configuration_container: VBoxContainer = %ExtConfigurationContainer
+
+@onready var ext_properties_list: ItemList = %PropertyItemList
+@onready var ext_property_desc: Label = %PropertyDescription
+@onready var ext_property_enable_btn: CheckButton = %EnableButton
+@onready var ext_property_show_on_top_btn: CheckButton = %ShowPropertyOnTop
+@onready var customization_container: FoldableContainer = %CustomizationContainer
+@onready var dependencies_container: FoldableContainer = %DependenciesContainer
+@onready var properties_dependencies: VBoxContainer = %PropertiesDependencies
+@onready var entities_dependencies: VBoxContainer = %EntitiesDependencies
+@onready var properties_dependencies_container: GridContainer = %PropertiesDependencies/GridContainer
+@onready var entities_dependencies_container: GridContainer = %EntitiesDependencies/GridContainer
+@onready var ext_property_details: VBoxContainer = %PropertyContainer
+
+@onready var creation_dialog: ConfirmationDialog = $Window/CreationDialog
+@onready var creation_name_edit: LineEdit = $Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer/LineEdit
+@onready var creation_type_edit: LineEdit = $Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer2/LineEdit2
+@onready var creation_description_edit: TextEdit = $Window/CreationDialog/VBoxContainer/VBoxContainer/TextEdit
+
+@onready var dependency_dialog: ConfirmationDialog = $Window/DependencyDialog
+@onready var extensions_properties_selector: OptionButton = $Window/DependencyDialog/VBoxContainer/OptionButton
+@onready var dependency_type_edit: LineEdit = $Window/DependencyDialog/VBoxContainer/LineEdit
+@onready var enable_dialog: ConfirmationDialog = $Window/EnableDialog
+@onready var dependency_check_alert: AcceptDialog = $Window/DependencyCheckAlert
+
+@onready var property_scene_container: MarginContainer = %PropertySceneContainer
+@onready var fields_settings: VBoxContainer = %FieldsSettings
+
+var _selected_extension_conf_index : int
+var _selected_extension_property_index : int
+var _selected_dependency : Dictionary
+
+func _ready() -> void:
+ window.hide()
+ hide()
+
+func _load_configurations() -> void:
+ extensions_list.clear()
+
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ for extensions_configuration in extensions_configurations:
+ var item_name = extensions_configuration["configuration"]["name"] as String
+ var item_icon = load(extensions_configuration["configuration"]["icon"] as String)
+
+ if item_name == "Pandora":
+ item_name = "Default"
+ extensions_list.add_item(item_name, item_icon)
+ no_properties_label.hide()
+ ext_configuration_container.hide()
+ ext_property_details.hide()
+ select_extension_label.show()
+
+func open():
+ _load_configurations()
+
+ show()
+ window.show()
+
+func _on_close_requested() -> void:
+ _selected_extension_conf_index = -1
+ _selected_extension_property_index = -1
+
+ window.hide()
+ hide()
+
+func _on_item_selected(index: int) -> void:
+ _selected_extension_conf_index = index
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[index]
+ extension_label.text = "%s - Extensions Settings" % extensions_configuration["configuration"]["name"]
+
+ no_properties_label.hide()
+ select_extension_label.hide()
+ ext_configuration_container.hide()
+ if not extensions_configuration["properties"]:
+ no_properties_label.show()
+ else:
+ ext_properties_list.clear()
+
+ for extension_property in extensions_configuration["properties"]:
+ ext_properties_list.add_item(extension_property["name"])
+
+ ext_configuration_container.show()
+
+func _on_property_selected(index: int) -> void:
+ _selected_extension_property_index = index
+ for child in properties_dependencies_container.get_children():
+ child.queue_free()
+ for child in entities_dependencies_container.get_children():
+ child.queue_free()
+ for child in fields_settings.get_children():
+ child.queue_free()
+ if property_scene_container.get_child_count() > 0:
+ property_scene_container.get_child(0).queue_free()
+
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_property = extensions_configurations[_selected_extension_conf_index]["properties"][index] as Dictionary
+
+ ext_property_desc.text = extension_property["description"]
+ ext_property_enable_btn.button_pressed = extension_property["enabled"]
+ ext_property_show_on_top_btn.button_pressed = extension_property["show_on_top"]
+ var dependencies : Array = extension_property["dependencies"]
+ var property_dependencies := dependencies.filter(func(dep: Dictionary): return dep["type"] == "PROPERTY")
+ var model_dependencies := dependencies.filter(func(dep: Dictionary): return dep["type"] == "MODEL")
+ if property_dependencies:
+ for dep in property_dependencies:
+ var dependency_scene : Dependency = DependencyScene.instantiate()
+ dependency_scene.dependency = dep
+ properties_dependencies_container.add_child(dependency_scene)
+ dependency_scene.removed.connect(_on_dependency_removed)
+ if model_dependencies:
+ for dep in model_dependencies:
+ var dependency_scene : Dependency = DependencyScene.instantiate()
+ dependency_scene.dependency = dep
+ entities_dependencies_container.add_child(dependency_scene)
+ dependency_scene.removed.connect(_on_dependency_removed)
+ var extension_dir = PandoraSettings.get_extensions_confs_map().find_key(_selected_extension_conf_index)
+ var property_scene := (load(extension_dir + "/" + extension_property["dir_name"] + "/ui_component/" + extension_property["dir_name"] + ".tscn") as PackedScene).instantiate()
+ property_scene_container.add_child(property_scene)
+
+ if extension_property["fields"]:
+ for property_field in extension_property["fields"]:
+ if property_field["type"] == "STRING":
+ var field_instance := STRING_FIELD_SETTINGS.instantiate() as StringFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+ elif property_field["type"] == "RANGE":
+ var field_instance := RANGE_FIELD_SETTINGS.instantiate() as RangeFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+ elif property_field["type"] == "ARRAY":
+ var field_instance := ARRAY_FIELD_SETTINGS.instantiate() as ArrayFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+ elif property_field["type"] == "REFERENCE":
+ var field_instance := REFERENCE_FIELD_SETTINGS.instantiate() as ReferenceFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+ elif property_field["type"] == "OPTIONS":
+ var field_instance := OPTIONS_FIELD_SETTINGS.instantiate() as OptionsFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+ elif property_field["type"] == "BOOL":
+ var field_instance := BOOL_FIELD_SETTINGS.instantiate() as BoolFieldSettings
+ fields_settings.add_child(field_instance)
+ field_instance.set_property_field(property_field)
+ field_instance.updated.connect(_on_field_settings_update)
+
+ if not extension_property["enabled"]:
+ ext_property_show_on_top_btn.disabled = true
+ dependencies_container.modulate.a = 0.45
+ customization_container.modulate.a = 0.45
+ else:
+ ext_property_show_on_top_btn.disabled = false
+ dependencies_container.modulate.a = 1
+ customization_container.modulate.a = 1
+ ext_property_details.show()
+
+func _on_field_settings_update(property_field: Dictionary) -> void:
+ var property_control = property_scene_container.get_child(0) as PandoraPropertyControl
+ property_control.update_field_settings(property_field)
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+func _on_enabled(toggled_on: bool) -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_property = extensions_configurations[_selected_extension_conf_index]["properties"][_selected_extension_property_index] as Dictionary
+ extension_property["enabled"] = toggled_on
+
+ if not toggled_on:
+ ext_property_show_on_top_btn.disabled = true
+ dependencies_container.modulate.a = 0.45
+ customization_container.modulate.a = 0.45
+ else:
+ ext_property_show_on_top_btn.disabled = false
+ dependencies_container.modulate.a = 1
+ customization_container.modulate.a = 1
+
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+func _on_show_on_top(toggled_on: bool) -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_property = extensions_configurations[_selected_extension_conf_index]["properties"][_selected_extension_property_index] as Dictionary
+ extension_property["show_on_top"] = toggled_on
+
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+func _on_new_property_pressed() -> void:
+ creation_dialog.popup_centered()
+
+func _on_creation_dialog_confirmed() -> void:
+ var property_name = creation_name_edit.text
+ var property_type = creation_type_edit.text
+ var property_description = creation_description_edit.text
+
+ if not property_name:
+ push_error("Property name is mandatory. Please retry.")
+ if not property_type:
+ push_error("Property type is mandatory. Please retry.")
+
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_dirs = PandoraSettings.get_extensions_dirs()
+
+ var extensions_dir = extensions_dirs[_selected_extension_conf_index]
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+
+ var opened_ext_dir = DirAccess.open(extensions_dir)
+ opened_ext_dir.make_dir_recursive(property_type + "/icons")
+ opened_ext_dir.make_dir_recursive(property_type + "/model/types")
+ opened_ext_dir.make_dir_recursive(property_type + "/property_button")
+ opened_ext_dir.make_dir_recursive(property_type + "/ui_component")
+ FileAccess.open(extensions_dir + "/" + property_type + "/model/" + property_type + ".gd", FileAccess.WRITE)
+ FileAccess.open(extensions_dir + "/" + property_type + "/model/types/" + property_type + ".gd", FileAccess.WRITE)
+ FileAccess.open(extensions_dir + "/" + property_type + "/ui_component/" + property_type + ".gd", FileAccess.WRITE)
+
+ var ui_component := PandoraPropertyControl.new()
+ ui_component.type = property_type
+
+ var ui_component_scene := PackedScene.new()
+ var result = ui_component_scene.pack(ui_component)
+ if result == OK:
+ ResourceSaver.save(ui_component_scene, extensions_dir + "/" + property_type + "/ui_component/" + property_type + ".tscn")
+
+ var property_button := PandoraPropertyButton.new()
+ property_button.scene = load(extensions_dir + "/" + property_type + "/ui_component/" + property_type + ".tscn")
+ var property_button_scene := PackedScene.new()
+ result = property_button_scene.pack(property_button)
+ if result == OK:
+ ResourceSaver.save(property_button_scene, extensions_dir + "/" + property_type + "/property_button/property_button.tscn")
+
+ var extension_property : Dictionary = {
+ "name": property_name,
+ "dir_name": property_type,
+ "description": property_description,
+ "enabled": false,
+ "show_on_top": true,
+ "dependencies": []
+ }
+ extensions_configurations[_selected_extension_conf_index]["properties"].append(extension_property)
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+ creation_name_edit.text = ""
+ creation_type_edit.text = ""
+ creation_description_edit.text = ""
+
+ _load_configurations()
+
+func _on_add_prop_dependency_pressed() -> void:
+ dependency_type_edit.editable = true
+ dependency_type_edit.text = "PROPERTY"
+ dependency_type_edit.editable = false
+
+ extensions_properties_selector.clear()
+
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ for ext_conf_prop in extensions_configuration["properties"]:
+ if ext_conf_prop["name"] != extensions_configuration["properties"][_selected_extension_property_index]["name"]:
+ extensions_properties_selector.add_item(ext_conf_prop["name"])
+
+ dependency_dialog.popup_centered()
+
+func _on_add_entity_dependency_pressed() -> void:
+ dependency_type_edit.editable = true
+ dependency_type_edit.text = "ENTITY"
+ dependency_type_edit.editable = false
+ dependency_dialog.popup_centered()
+
+func _on_dependency_dialog_confirmed() -> void:
+ var property_name := extensions_properties_selector.get_item_text(extensions_properties_selector.selected)
+
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_properties = extensions_configurations[_selected_extension_conf_index]["properties"]
+ var selected_dependency = extension_properties.filter(func(property: Dictionary): return property["name"] == property_name)[0] as Dictionary
+ if not selected_dependency["enabled"]:
+ _selected_dependency = selected_dependency
+ enable_dialog.popup_centered()
+ else:
+ extension_properties[_selected_extension_property_index]["dependencies"].append({"name": selected_dependency["name"], "type": "PROPERTY"})
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+func _on_enable_dialog_confirmed() -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_properties = extensions_configurations[_selected_extension_conf_index]["properties"]
+ extension_properties.filter(func(property: Dictionary): return property["name"] == _selected_dependency["name"])[0]["enabled"] = true
+ extension_properties[_selected_extension_property_index]["dependencies"].append({"name": _selected_dependency["name"], "type": "PROPERTY"})
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
+
+func _on_delete_property_pressed() -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var current_property_name = extensions_configuration["properties"][_selected_extension_property_index]["name"]
+ var is_dependency = extensions_configuration["properties"].any(func(property: Dictionary): \
+ return property["dependencies"].any(func(dep: Dictionary): \
+ return dep["name"] == current_property_name))
+
+ if is_dependency:
+ dependency_check_alert.popup_centered()
+ else:
+ pass
+
+func _on_dependency_removed(dep: Dictionary) -> void:
+ var extensions_configurations := PandoraSettings.get_extensions_configurations()
+ var extensions_configuration := extensions_configurations[_selected_extension_conf_index]
+ var extension_properties = extensions_configurations[_selected_extension_conf_index]["properties"]
+ var property_dependencies = extension_properties[_selected_extension_property_index]["dependencies"] as Array
+ property_dependencies.erase(dep)
+
+ PandoraSettings.save_extensions_configurations()
+ update_extensions_configurations.emit()
diff --git a/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd.uid b/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd.uid
new file mode 100644
index 00000000..760e7b98
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/settings_dialog.gd.uid
@@ -0,0 +1 @@
+uid://d4efa7td5f0e0
diff --git a/addons/pandora/ui/editor/settings_dialog/settings_dialog.tscn b/addons/pandora/ui/editor/settings_dialog/settings_dialog.tscn
new file mode 100644
index 00000000..7d1a325a
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/settings_dialog.tscn
@@ -0,0 +1,388 @@
+[gd_scene load_steps=4 format=3 uid="uid://ctp7xnvi5ep0e"]
+
+[ext_resource type="Script" uid="uid://d4efa7td5f0e0" path="res://addons/pandora/ui/editor/settings_dialog/settings_dialog.gd" id="1_4vos3"]
+[ext_resource type="Texture2D" uid="uid://dmh7pik8vjog8" path="res://addons/pandora/icons/pandora-icon.svg" id="2_4vos3"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4vos3"]
+
+[node name="SettingsDialog" type="Control"]
+visible = false
+layout_mode = 3
+anchors_preset = 0
+script = ExtResource("1_4vos3")
+
+[node name="Window" type="Window" parent="."]
+disable_3d = true
+oversampling_override = 1.0
+title = "Extensions Settings"
+initial_position = 2
+size = Vector2i(1152, 648)
+visible = false
+wrap_controls = true
+content_scale_mode = 1
+content_scale_aspect = 4
+
+[node name="PanelContainer" type="PanelContainer" parent="Window"]
+self_modulate = Color(0, 0, 0, 1)
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_4vos3")
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/PanelContainer"]
+layout_mode = 2
+
+[node name="ExtensionsContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="Window/PanelContainer/HBoxContainer/ExtensionsContainer"]
+layout_mode = 2
+theme_override_colors/font_color = Color(1, 1, 0.69411767, 1)
+text = "Extensions list"
+
+[node name="ItemList" type="ItemList" parent="Window/PanelContainer/HBoxContainer/ExtensionsContainer"]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_vertical = 3
+item_count = 1
+item_0/text = "Default"
+item_0/icon = ExtResource("2_4vos3")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Label" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer"]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.7882353, 0.3137255, 0.80784315, 1)
+text = "Pandora - Extensions Settings"
+
+[node name="MarginContainer" type="MarginContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_constants/margin_left = 5
+theme_override_constants/margin_top = 5
+theme_override_constants/margin_right = 5
+theme_override_constants/margin_bottom = 5
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+text = "Here you can enable/disable any properties added by the extension or change their behaviours."
+
+[node name="NoProperties" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_colors/font_color = Color(0.5489626, 0.5489626, 0.54896253, 1)
+text = "This extensions doesn't add custom properties to Pandora."
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="SelectExtension" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_colors/font_color = Color(0.5489626, 0.5489626, 0.54896253, 1)
+text = "Select an extension to check its configuration"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="ExtConfigurationContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="Label" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer"]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.6039216, 0.44313726, 0.4117647, 1)
+text = "All Properties"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="Properties" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer"]
+layout_mode = 2
+
+[node name="PropertyItemList" type="ItemList" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/Properties"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_colors/font_selected_color = Color(0.64705884, 0.25490198, 0.6627451, 1)
+item_count = 1
+item_0/text = "TestProperty"
+
+[node name="Button" type="Button" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/Properties"]
+layout_mode = 2
+text = "New Property"
+
+[node name="ScrollContainer" type="ScrollContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="PropertyContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="PropertyDescription" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Defines the main attributes of an entity (mob, player, NPC, etc.)."
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer"]
+layout_mode = 2
+
+[node name="EnableButton" type="CheckButton" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 0
+text = "Enable property"
+
+[node name="ShowPropertyOnTop" type="CheckButton" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 0
+disabled = true
+text = "Show property on top (inside Property bar)"
+
+[node name="CustomizationContainer" type="FoldableContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer"]
+unique_name_in_owner = true
+modulate = Color(1, 1, 1, 0.47058824)
+layout_mode = 2
+title = "Customize Property"
+
+[node name="PropertyShowcase" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer"]
+layout_mode = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase"]
+layout_mode = 2
+theme_override_constants/margin_left = 10
+theme_override_constants/margin_top = 0
+theme_override_constants/margin_right = 10
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase/MarginContainer"]
+layout_mode = 2
+
+[node name="PanelContainer" type="PanelContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="PropertySceneContainer" type="MarginContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase/MarginContainer/VBoxContainer/PanelContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+mouse_filter = 0
+mouse_behavior_recursive = 1
+mouse_force_pass_scroll_events = false
+mouse_default_cursor_shape = 8
+theme_override_constants/margin_left = 10
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 10
+theme_override_constants/margin_bottom = 10
+
+[node name="MarginContainer" type="MarginContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase/MarginContainer/VBoxContainer"]
+layout_mode = 2
+theme_override_constants/margin_left = 5
+theme_override_constants/margin_top = 5
+theme_override_constants/margin_right = 5
+theme_override_constants/margin_bottom = 5
+
+[node name="FieldsSettings" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/CustomizationContainer/PropertyShowcase/MarginContainer/VBoxContainer/MarginContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="DependenciesContainer" type="FoldableContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer"]
+unique_name_in_owner = true
+modulate = Color(1, 1, 1, 0.47058824)
+layout_mode = 2
+title = "Dependencies"
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer"]
+layout_mode = 2
+
+[node name="PropertiesDependencies" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="HSeparator" type="HSeparator" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies"]
+layout_mode = 2
+
+[node name="Dependecies" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_color = Color(1, 0.23921569, 0.2509804, 1)
+text = "Dependencies (Properties)"
+
+[node name="Button" type="Button" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies/HBoxContainer"]
+layout_mode = 2
+text = "Add dependency"
+
+[node name="GridContainer" type="GridContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies"]
+layout_mode = 2
+theme_override_constants/h_separation = 30
+columns = 5
+
+[node name="EntitiesDependencies" type="VBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+
+[node name="HSeparator" type="HSeparator" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies"]
+layout_mode = 2
+
+[node name="Dependecies" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_color = Color(1, 0.23921569, 0.2509804, 1)
+text = "Dependencies (Entities/Models)"
+
+[node name="Button" type="Button" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies/HBoxContainer"]
+layout_mode = 2
+text = "Add dependency"
+
+[node name="GridContainer" type="GridContainer" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies"]
+layout_mode = 2
+theme_override_constants/h_separation = 30
+columns = 5
+
+[node name="Label" type="Label" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies/GridContainer"]
+layout_mode = 2
+text = "ItemEntity"
+
+[node name="BottomSpace" type="HSeparator" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies"]
+modulate = Color(1, 1, 1, 0)
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="Button" type="Button" parent="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer"]
+custom_minimum_size = Vector2(160, 0)
+layout_mode = 2
+size_flags_horizontal = 8
+size_flags_vertical = 10
+theme_override_colors/font_color = Color(0.8745098, 0.24313726, 0, 1)
+text = "Delete Property"
+
+[node name="CreationDialog" type="ConfirmationDialog" parent="Window"]
+oversampling_override = 1.0
+title = "New Property"
+initial_position = 2
+size = Vector2i(500, 246)
+ok_button_text = "Create"
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/CreationDialog"]
+offset_left = 8.0
+offset_top = 8.0
+offset_right = 492.0
+offset_bottom = 197.0
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Window/CreationDialog/VBoxContainer"]
+layout_mode = 2
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/CreationDialog/VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Label" type="Label" parent="Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer"]
+layout_mode = 2
+text = "Property Name"
+
+[node name="LineEdit" type="LineEdit" parent="Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer"]
+layout_mode = 2
+placeholder_text = "TestProperty"
+
+[node name="VBoxContainer2" type="VBoxContainer" parent="Window/CreationDialog/VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Label2" type="Label" parent="Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer2"]
+layout_mode = 2
+text = "Type"
+
+[node name="LineEdit2" type="LineEdit" parent="Window/CreationDialog/VBoxContainer/HBoxContainer/VBoxContainer2"]
+layout_mode = 2
+placeholder_text = "test_property"
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/CreationDialog/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="Window/CreationDialog/VBoxContainer/VBoxContainer"]
+layout_mode = 2
+text = "Description"
+
+[node name="TextEdit" type="TextEdit" parent="Window/CreationDialog/VBoxContainer/VBoxContainer"]
+custom_minimum_size = Vector2(0, 100)
+layout_mode = 2
+placeholder_text = "Write here a description of your property"
+
+[node name="DependencyDialog" type="ConfirmationDialog" parent="Window"]
+oversampling_override = 1.0
+title = "Add new dependency"
+initial_position = 2
+size = Vector2i(300, 166)
+ok_button_text = "Add"
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window/DependencyDialog"]
+offset_left = 8.0
+offset_top = 8.0
+offset_right = 292.0
+offset_bottom = 117.0
+
+[node name="Label" type="Label" parent="Window/DependencyDialog/VBoxContainer"]
+layout_mode = 2
+text = "Select a property"
+
+[node name="OptionButton" type="OptionButton" parent="Window/DependencyDialog/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label2" type="Label" parent="Window/DependencyDialog/VBoxContainer"]
+layout_mode = 2
+text = "Type of dependency"
+
+[node name="LineEdit" type="LineEdit" parent="Window/DependencyDialog/VBoxContainer"]
+layout_mode = 2
+editable = false
+
+[node name="EnableDialog" type="ConfirmationDialog" parent="Window"]
+oversampling_override = 1.0
+title = "Warning"
+initial_position = 2
+size = Vector2i(275, 106)
+ok_button_text = "Enable"
+dialog_text = "The selected property is disabled.
+Do you want to enable it?"
+
+[node name="DependencyCheckAlert" type="AcceptDialog" parent="Window"]
+oversampling_override = 1.0
+title = "Warning!"
+initial_position = 2
+size = Vector2i(370, 106)
+dialog_text = "You can't delete this property because is used
+by another property."
+
+[connection signal="close_requested" from="Window" to="." method="_on_close_requested"]
+[connection signal="item_selected" from="Window/PanelContainer/HBoxContainer/ExtensionsContainer/ItemList" to="." method="_on_item_selected"]
+[connection signal="item_selected" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/Properties/PropertyItemList" to="." method="_on_property_selected"]
+[connection signal="pressed" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/Properties/Button" to="." method="_on_new_property_pressed"]
+[connection signal="toggled" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/HBoxContainer/EnableButton" to="." method="_on_enabled"]
+[connection signal="toggled" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/HBoxContainer/ShowPropertyOnTop" to="." method="_on_show_on_top"]
+[connection signal="pressed" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/PropertiesDependencies/HBoxContainer/Button" to="." method="_on_add_prop_dependency_pressed"]
+[connection signal="pressed" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/DependenciesContainer/VBoxContainer/EntitiesDependencies/HBoxContainer/Button" to="." method="_on_add_entity_dependency_pressed"]
+[connection signal="pressed" from="Window/PanelContainer/HBoxContainer/VBoxContainer/MarginContainer/VBoxContainer/ExtConfigurationContainer/HBoxContainer/ScrollContainer/PropertyContainer/Button" to="." method="_on_delete_property_pressed"]
+[connection signal="confirmed" from="Window/CreationDialog" to="." method="_on_creation_dialog_confirmed"]
+[connection signal="confirmed" from="Window/DependencyDialog" to="." method="_on_dependency_dialog_confirmed"]
+[connection signal="confirmed" from="Window/EnableDialog" to="." method="_on_enable_dialog_confirmed"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd
new file mode 100644
index 00000000..a5534bd3
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd
@@ -0,0 +1,41 @@
+@tool
+class_name ArrayFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+@onready var option_button: OptionButton = $HBoxContainer/OptionButton
+
+var property_field : Dictionary : set = set_property_field
+var property_types_idx: Dictionary
+
+func _ready() -> void:
+ option_button.clear()
+ var idx = 0
+ for property_type in PandoraPropertyType.get_all_types():
+ if property_type.allow_nesting():
+ option_button.add_icon_item(
+ load(property_type.get_type_icon_path()), property_type.get_type_name(), idx
+ )
+ property_types_idx[idx] = property_type.get_type_name()
+ idx += 1
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+ var idx = property_types_idx.find_key(property_field["settings"]["type"])
+ option_button.select(idx)
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
+
+func _on_option_button_item_selected(index: int) -> void:
+ property_field["settings"]["type"] = property_types_idx[index]
+ updated.emit(property_field)
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd.uid
new file mode 100644
index 00000000..c5687a37
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://gifa0m2v52h7
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.tscn
new file mode 100644
index 00000000..d826a4b3
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.tscn
@@ -0,0 +1,31 @@
+[gd_scene load_steps=2 format=3 uid="uid://cgwd2gdv7xeia"]
+
+[ext_resource type="Script" uid="uid://gifa0m2v52h7" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/array_field_settings.gd" id="1_qtgvu"]
+
+[node name="ArrayFieldSettings" type="VBoxContainer"]
+offset_right = 109.0
+offset_bottom = 23.0
+script = ExtResource("1_qtgvu")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Array Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+button_pressed = true
+text = "Enable field"
+
+[node name="Label" type="Label" parent="HBoxContainer"]
+layout_mode = 2
+text = "Type"
+
+[node name="OptionButton" type="OptionButton" parent="HBoxContainer"]
+layout_mode = 2
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
+[connection signal="item_selected" from="HBoxContainer/OptionButton" to="." method="_on_option_button_item_selected"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd
new file mode 100644
index 00000000..5a3fcdec
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd
@@ -0,0 +1,22 @@
+@tool
+class_name BoolFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+
+var property_field : Dictionary : set = set_property_field
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd.uid
new file mode 100644
index 00000000..9814a5a7
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://ch5nj1y2dxmjk
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.tscn
new file mode 100644
index 00000000..9d9c302d
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.tscn
@@ -0,0 +1,26 @@
+[gd_scene load_steps=2 format=3 uid="uid://bm6rmjycqduyn"]
+
+[ext_resource type="Script" uid="uid://ch5nj1y2dxmjk" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/bool_field_settings.gd" id="1_h648l"]
+
+[node name="BoolFieldSettings" type="VBoxContainer"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_h648l")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Bool Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+button_pressed = true
+text = "Enable field"
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd
new file mode 100644
index 00000000..c54f1195
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd
@@ -0,0 +1,44 @@
+@tool
+class_name OptionsFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+@onready var edit_button: Button = $HBoxContainer/Button
+@onready var options_window: Window = $OptionsWindow
+@onready var line_edit: LineEdit = $HBoxContainer/LineEdit
+
+var property_field : Dictionary : set = set_property_field
+
+func _ready() -> void:
+ edit_button.pressed.connect(func(): options_window.open(property_field["settings"]["options"] as Array))
+
+ options_window.item_added.connect(func(item: Variant):
+ property_field["settings"]["options"].append(item)
+ )
+ options_window.item_removed.connect(func(item: Variant):
+ property_field["settings"]["options"].erase(item)
+ )
+ options_window.item_updated.connect(func(idx: int, item: Variant):
+ property_field["settings"]["options"][idx] = item
+ )
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+ line_edit.text = str(property_field["settings"]["options"].size()) + " Options"
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
+
+func _on_window_close_requested() -> void:
+ _update_field_settings.call_deferred()
+ updated.emit(property_field)
+ options_window.hide()
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd.uid
new file mode 100644
index 00000000..3f4e1f1e
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://qx222rida1tm
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.tscn
new file mode 100644
index 00000000..684a6225
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.tscn
@@ -0,0 +1,114 @@
+[gd_scene load_steps=4 format=3 uid="uid://7c8j3yx3hnr4"]
+
+[ext_resource type="Texture2D" uid="uid://b0mt8ysdc5m4a" path="res://addons/pandora/icons/Edit.svg" id="1_atebi"]
+[ext_resource type="Script" uid="uid://qx222rida1tm" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/options_field_settings.gd" id="1_ceb5e"]
+[ext_resource type="Script" uid="uid://1higomb3gr2t" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd" id="3_xc8d3"]
+
+[node name="OptionsFieldSettings" type="VBoxContainer"]
+script = ExtResource("1_ceb5e")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Options Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 0
+size_flags_vertical = 8
+button_pressed = true
+text = "Enable field"
+
+[node name="LineEdit" type="LineEdit" parent="HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+text = "0 Options"
+alignment = 1
+editable = false
+expand_to_text_length = true
+context_menu_enabled = false
+virtual_keyboard_enabled = false
+shortcut_keys_enabled = false
+selecting_enabled = false
+flat = true
+
+[node name="Button" type="Button" parent="HBoxContainer"]
+layout_mode = 2
+icon = ExtResource("1_atebi")
+
+[node name="OptionsWindow" type="Window" parent="."]
+disable_3d = true
+oversampling_override = 1.0
+title = "Options Manager"
+initial_position = 2
+size = Vector2i(134, 100)
+visible = false
+wrap_controls = true
+content_scale_mode = 1
+content_scale_aspect = 4
+script = ExtResource("3_xc8d3")
+
+[node name="Panel" type="Panel" parent="OptionsWindow"]
+self_modulate = Color(0, 0, 0, 1)
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="OptionsWindow/Panel"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme_override_constants/margin_left = 10
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 10
+theme_override_constants/margin_bottom = 10
+
+[node name="MainContainer" type="VBoxContainer" parent="OptionsWindow/Panel/MarginContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="ScrollContainer" type="ScrollContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="VBoxContainer" type="VBoxContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer/ScrollContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="MarginContainer" type="MarginContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer/ScrollContainer/VBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 8
+theme_override_constants/margin_bottom = 10
+
+[node name="NewItemButton" type="Button" parent="OptionsWindow/Panel/MarginContainer/MainContainer/ScrollContainer/VBoxContainer/MarginContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Add New Item +"
+
+[node name="ArrayItems" type="VBoxContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer/ScrollContainer/VBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="CenterContainer" type="CenterContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer"]
+layout_mode = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="OptionsWindow/Panel/MarginContainer/MainContainer/CenterContainer"]
+layout_mode = 2
+theme_override_constants/separation = 20
+
+[node name="CloseButton" type="Button" parent="OptionsWindow/Panel/MarginContainer/MainContainer/CenterContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Close"
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
+[connection signal="close_requested" from="OptionsWindow" to="." method="_on_window_close_requested"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd
new file mode 100644
index 00000000..ce4d956c
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd
@@ -0,0 +1,84 @@
+@tool
+extends Window
+
+const ArrayItem = preload("res://addons/pandora/ui/components/array_editor/array_item.tscn")
+const PropertyBarScene = "res://addons/pandora/ui/components/property_bar/property_bar.tscn"
+
+signal item_added(item: Variant)
+signal item_removed(item: Variant)
+signal item_updated(idx: int, new_item: Variant)
+
+@onready var close_button: Button = %CloseButton
+@onready var new_item_button: Button = %NewItemButton
+@onready var items_container: VBoxContainer = %ArrayItems
+@onready var main_container: VBoxContainer = %MainContainer
+
+var property_bar: Node
+var _items: Array
+
+func _ready():
+ if owner.get_parent() is SubViewport:
+ return
+
+ close_button.pressed.connect(_on_close_requested)
+ new_item_button.pressed.connect(_add_new_item)
+
+func close():
+ _remove_empty_items()
+ _clear()
+
+func _add_new_item():
+ var scene = property_bar.get_scene_by_type("string")
+ var control = scene.instantiate() as PandoraPropertyControl
+ var item_property = PandoraProperty.new("", "array_item", "string")
+ _items.append(item_property.get_default_value())
+ _add_property_control(control, item_property, _items.size() - 1)
+ item_added.emit(_items[_items.size() - 1])
+
+func _add_property_control(control: PandoraPropertyControl, item_property: PandoraProperty, idx: int):
+ var item = ArrayItem.instantiate()
+ control.init(item_property)
+ control.property_value_changed.connect(func(value: Variant): item_updated.emit(idx, value))
+ item.item_removal_requested.connect(
+ func(): item_removed.emit(control._property.get_default_value())
+ )
+ item.init(item_property, control, Pandora._entity_backend)
+ items_container.add_child(item)
+
+func _clear():
+ _items.clear()
+ for child in items_container.get_children():
+ child.queue_free()
+ items_container.get_children().clear()
+
+func _remove_empty_items():
+ for index in range(_items.size()):
+ if _items[index] == null:
+ _items.erase(index)
+ item_removed.emit(_items[index])
+
+func _load_items():
+ for i in range(_items.size()):
+ var control = (property_bar.get_scene_by_type("string").instantiate() as PandoraPropertyControl)
+ var item_property = PandoraProperty.new("", "array_item", "string")
+ var value = _items[i]
+ item_property.set_default_value(value)
+ _add_property_control(control, item_property, i)
+
+func open(original_items: Array):
+ popup_centered_clamped(Vector2i(800, 1000), 0.5)
+ move_to_foreground()
+ grab_focus()
+
+ var property_bar_scene = load(PropertyBarScene)
+ property_bar = property_bar_scene.instantiate()
+ property_bar._ready()
+
+ _items = original_items.duplicate()
+ _load_items()
+
+func _on_close_requested():
+ close()
+ hide()
+ property_bar.queue_free()
+ close_requested.emit()
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd.uid
new file mode 100644
index 00000000..4ea25cbb
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/options_window.gd.uid
@@ -0,0 +1 @@
+uid://1higomb3gr2t
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd
new file mode 100644
index 00000000..5a6e37aa
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd
@@ -0,0 +1,38 @@
+@tool
+class_name RangeFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+@onready var spin_box: SpinBox = $HBoxContainer/SpinBox
+@onready var spin_box_2: SpinBox = $HBoxContainer/SpinBox2
+
+var property_field : Dictionary : set = set_property_field
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+ spin_box_2.value = property_field["settings"]["max_value"]
+ spin_box_2.max_value = property_field["settings"]["max_value"]
+ spin_box_2.min_value = property_field["settings"]["min_value"]
+ spin_box.value = property_field["settings"]["min_value"]
+ spin_box.min_value = property_field["settings"]["min_value"]
+ spin_box.max_value = property_field["settings"]["max_value"]
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
+
+func _on_spin_box_value_changed(value: float) -> void:
+ property_field["settings"]["min_value"] = value
+ updated.emit(property_field)
+
+func _on_spin_box_2_value_changed(value: float) -> void:
+ property_field["settings"]["max_value"] = value
+ updated.emit(property_field)
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd.uid
new file mode 100644
index 00000000..3c8c9c00
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://ba6xr8b575on3
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.tscn
new file mode 100644
index 00000000..9a55b523
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.tscn
@@ -0,0 +1,45 @@
+[gd_scene load_steps=2 format=3 uid="uid://cyd24jwivayf5"]
+
+[ext_resource type="Script" uid="uid://ba6xr8b575on3" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/range_field_settings.gd" id="1_oe68r"]
+
+[node name="RangeFieldSettings" type="VBoxContainer"]
+script = ExtResource("1_oe68r")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Quantity Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+button_pressed = true
+text = "Enable field"
+
+[node name="Label" type="Label" parent="HBoxContainer"]
+layout_mode = 2
+text = "Min Value"
+
+[node name="SpinBox" type="SpinBox" parent="HBoxContainer"]
+custom_minimum_size = Vector2(120, 0)
+layout_mode = 2
+min_value = -999999999.0
+max_value = 999999999.0
+value = -999999999.0
+
+[node name="Label2" type="Label" parent="HBoxContainer"]
+layout_mode = 2
+text = "Max Value"
+
+[node name="SpinBox2" type="SpinBox" parent="HBoxContainer"]
+custom_minimum_size = Vector2(120, 0)
+layout_mode = 2
+min_value = -999999999.0
+max_value = 999999999.0
+value = 999999999.0
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
+[connection signal="value_changed" from="HBoxContainer/SpinBox" to="." method="_on_spin_box_value_changed"]
+[connection signal="value_changed" from="HBoxContainer/SpinBox2" to="." method="_on_spin_box_2_value_changed"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd
new file mode 100644
index 00000000..56694ec9
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd
@@ -0,0 +1,39 @@
+@tool
+class_name ReferenceFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+@onready var category_only: CheckButton = $HBoxContainer/CategoryOnly
+@onready var entity_picker: HBoxContainer = $HBoxContainer/EntityPicker
+
+var property_field : Dictionary : set = set_property_field
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+ category_only.button_pressed = property_field["settings"]["category_only"]
+ entity_picker.categories_only = property_field["settings"]["category_only"]
+ _pick_entity_or_category.call_deferred(property_field["settings"]["entity_id"])
+
+func _pick_entity_or_category(category_id: String) -> void:
+ var category = Pandora.get_category(category_id)
+ entity_picker.select(category)
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
+
+func _on_category_only_toggled(toggled_on: bool) -> void:
+ property_field["settings"]["category_only"] = toggled_on
+ entity_picker.categories_only = toggled_on
+ updated.emit(property_field)
+
+func _on_entity_picker_entity_selected(entity: PandoraEntity) -> void:
+ property_field["settings"]["entity_id"] = entity.get_entity_id()
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd.uid
new file mode 100644
index 00000000..4a692830
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://nt7wcwqkldyq
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.tscn
new file mode 100644
index 00000000..b2102cb1
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.tscn
@@ -0,0 +1,39 @@
+[gd_scene load_steps=3 format=3 uid="uid://d3a0188wd61px"]
+
+[ext_resource type="Script" uid="uid://nt7wcwqkldyq" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/reference_field_settings.gd" id="1_a0vmf"]
+[ext_resource type="PackedScene" uid="uid://bfhqt0xa4a2fh" path="res://addons/pandora/ui/components/entity_picker/entity_picker.tscn" id="1_hcy81"]
+
+[node name="ReferenceFieldSettings" type="VBoxContainer"]
+script = ExtResource("1_a0vmf")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Reference Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 0
+size_flags_vertical = 8
+button_pressed = true
+text = "Enable field"
+
+[node name="CategoryOnly" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 8
+text = "Category only"
+
+[node name="Label" type="Label" parent="HBoxContainer"]
+layout_mode = 2
+text = "Category Filter"
+
+[node name="EntityPicker" parent="HBoxContainer" instance=ExtResource("1_hcy81")]
+custom_minimum_size = Vector2(190, 0)
+layout_mode = 2
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
+[connection signal="toggled" from="HBoxContainer/CategoryOnly" to="." method="_on_category_only_toggled"]
+[connection signal="entity_selected" from="HBoxContainer/EntityPicker" to="." method="_on_entity_picker_entity_selected"]
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd
new file mode 100644
index 00000000..36854c86
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd
@@ -0,0 +1,22 @@
+@tool
+class_name StringFieldSettings
+extends VBoxContainer
+
+signal updated(property_field: Dictionary)
+
+@onready var label: Label = $Label
+@onready var check_button: CheckButton = $HBoxContainer/CheckButton
+
+var property_field : Dictionary : set = set_property_field
+
+func set_property_field(field: Dictionary) -> void:
+ property_field = field
+ _update_field_settings()
+
+func _update_field_settings() -> void:
+ label.text = property_field["name"] + " Settings"
+ check_button.button_pressed = property_field["enabled"]
+
+func _on_check_button_toggled(toggled_on: bool) -> void:
+ property_field["enabled"] = toggled_on
+ updated.emit(property_field)
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd.uid b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd.uid
new file mode 100644
index 00000000..94fb8338
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd.uid
@@ -0,0 +1 @@
+uid://ds6adhc4rxiyl
diff --git a/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.tscn b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.tscn
new file mode 100644
index 00000000..e0bd0a20
--- /dev/null
+++ b/addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.tscn
@@ -0,0 +1,21 @@
+[gd_scene load_steps=2 format=3 uid="uid://bn7da5ljy5mqh"]
+
+[ext_resource type="Script" uid="uid://ds6adhc4rxiyl" path="res://addons/pandora/ui/editor/settings_dialog/ui_fields/string_field_settings.gd" id="1_1ygog"]
+
+[node name="StringFieldSettings" type="VBoxContainer"]
+script = ExtResource("1_1ygog")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.59607846, 0.43529412, 0.40392157, 1)
+text = "Item Name Settings"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="CheckButton" type="CheckButton" parent="HBoxContainer"]
+layout_mode = 2
+button_pressed = true
+text = "Enable field"
+
+[connection signal="toggled" from="HBoxContainer/CheckButton" to="." method="_on_check_button_toggled"]
diff --git a/addons/pandora/util/configuration_template.json b/addons/pandora/util/configuration_template.json
new file mode 100644
index 00000000..959f9a6a
--- /dev/null
+++ b/addons/pandora/util/configuration_template.json
@@ -0,0 +1,7 @@
+{
+ "configuration": {
+ "name": "Pandora",
+ "icon": "res://addons/pandora/icons/pandora-icon.svg",
+ },
+ "properties": []
+}
diff --git a/data.pandora b/data.pandora
index 88a137ed..703c9279 100644
--- a/data.pandora
+++ b/data.pandora
@@ -428,12 +428,19 @@
"_id": "5",
"_name": "array property",
"_type": "array"
+ },
+ {
+ "_category_id": "1",
+ "_default_value": null,
+ "_id": "17.0",
+ "_name": "test_property property",
+ "_type": "test_property"
}
]
},
"_id_generator": {
"_ids_by_context": {
- "default": 9.0
+ "default": 17.0
}
}
}
\ No newline at end of file
diff --git a/pandora/categories.gd b/pandora/categories.gd
index 3094c8cd..d1c830c2 100644
--- a/pandora/categories.gd
+++ b/pandora/categories.gd
@@ -2,11 +2,22 @@
class_name PandoraCategories
-const ROOT = "F2e9QCtQ6e"
+const ITEMS = "1"
+const RARITY = "16"
+const QUESTS = "27"
+const DIALOGUES = "28"
+const SPELLS = "29"
+const MOCK__REQUIRED_FOR_TESTING__ = "54"
+const NPCS = "2"
-class RootCategories:
- const ITEMS = "_zMxaAiHqU"
- const NPCS = "PXyryU_CUw"
+class ItemsArmoryCategories:
+ const SHIELDS = "8"
+
+
+class ItemsCategories:
+ const ARMORY = "3"
+ const TOOLS = "4"
+ const ORES = "13"
diff --git a/pandora/extensions/configuration.json b/pandora/extensions/configuration.json
new file mode 100644
index 00000000..4ba57a0a
--- /dev/null
+++ b/pandora/extensions/configuration.json
@@ -0,0 +1,83 @@
+{
+ "configuration": {
+ "icon": "res://addons/pandora/icons/pandora-icon.svg",
+ "name": "Pandora"
+ },
+ "properties": [
+ {
+ "dependencies": [
+ {
+ "name": "DependencyProperty",
+ "type": "PROPERTY"
+ }
+ ],
+ "description": "A simple property of test to show how to use new custom extensions.",
+ "dir_name": "test_property",
+ "enabled": true,
+ "fields": [
+ {
+ "enabled": true,
+ "name": "Item Name",
+ "settings": {
+
+ },
+ "type": "STRING"
+ },
+ {
+ "enabled": true,
+ "name": "Quantity",
+ "settings": {
+ "max_value": 100.0,
+ "min_value": 0.0
+ },
+ "type": "RANGE"
+ }
+ ],
+ "name": "PandoraTestProperty",
+ "show_on_top": true
+ },
+ {
+ "dependencies": [],
+ "description": "",
+ "dir_name": "dependency_property",
+ "enabled": true,
+ "fields": [
+ {
+ "enabled": true,
+ "name": "Item Name",
+ "settings": {
+ "options": []
+ },
+ "type": "OPTIONS"
+ },
+ {
+ "enabled": true,
+ "name": "Quantity",
+ "settings": {
+ "max_value": 100.0,
+ "min_value": 0.0
+ },
+ "type": "RANGE"
+ },
+ {
+ "enabled": true,
+ "name": "Test",
+ "settings": {
+ "type": "bool"
+ },
+ "type": "ARRAY"
+ },
+ {
+ "enabled": true,
+ "name": "Item Name",
+ "settings": {
+ "options": []
+ },
+ "type": "OPTIONS"
+ }
+ ],
+ "name": "DependencyProperty",
+ "show_on_top": true
+ }
+ ]
+}
diff --git a/pandora/extensions/dependency_property/model/dependency_property.gd b/pandora/extensions/dependency_property/model/dependency_property.gd
new file mode 100644
index 00000000..d2738aa0
--- /dev/null
+++ b/pandora/extensions/dependency_property/model/dependency_property.gd
@@ -0,0 +1,30 @@
+class_name PandoraDependencyProperty extends RefCounted
+
+var _item_name : String
+var _quantity : int
+
+func _init(item_name: String, quantity: int) -> void:
+ _item_name = item_name
+ _quantity = quantity
+
+func set_item_name(item_name: String) -> void:
+ _item_name = item_name
+
+func set_quantity(quantity: int) -> void:
+ _quantity = quantity
+
+func get_item_name() -> String:
+ return _item_name
+
+func get_quantity() -> int:
+ return _quantity
+
+func load_data(data: Dictionary) -> void:
+ _item_name = data["item_name"]
+ _quantity = data["quantity"]
+
+func save_data() -> Dictionary:
+ return { "item_name": _item_name, "quantity": _quantity }
+
+func _to_string() -> String:
+ return ""
diff --git a/pandora/extensions/dependency_property/model/dependency_property.gd.uid b/pandora/extensions/dependency_property/model/dependency_property.gd.uid
new file mode 100644
index 00000000..aa885aad
--- /dev/null
+++ b/pandora/extensions/dependency_property/model/dependency_property.gd.uid
@@ -0,0 +1 @@
+uid://dooakeh83r2ai
diff --git a/pandora/extensions/dependency_property/model/types/dependency_property.gd b/pandora/extensions/dependency_property/model/types/dependency_property.gd
new file mode 100644
index 00000000..713b24ac
--- /dev/null
+++ b/pandora/extensions/dependency_property/model/types/dependency_property.gd
@@ -0,0 +1,27 @@
+extends PandoraPropertyType
+
+const SETTING_CATEGORY_FILTER = "Category Filter"
+const SETTING_MIN_VALUE = "Min Quantity"
+const SETTING_MAX_VALUE = "Max Quantity"
+const SETTINGS = {
+ SETTING_MIN_VALUE: {"type": "int", "value": -9999999999},
+ SETTING_MAX_VALUE: {"type": "int", "value": 9999999999}
+}
+
+func _init() -> void:
+ super("dependency_property", SETTINGS, null, "res://pandora/extensions/test_property/icons/icon.png")
+
+func parse_value(variant: Variant, _s: Dictionary = {}) -> Variant:
+ if variant is Dictionary:
+ var item_name = variant["item_name"]
+ var quantity = variant["quantity"]
+ return PandoraTestProperty.new(item_name, quantity)
+ return variant
+
+func write_value(variant: Variant) -> Variant:
+ if variant is PandoraTestProperty:
+ return variant.save_data()
+ return variant
+
+func is_valid(variant: Variant) -> bool:
+ return variant is PandoraDependencyProperty
diff --git a/pandora/extensions/dependency_property/model/types/dependency_property.gd.uid b/pandora/extensions/dependency_property/model/types/dependency_property.gd.uid
new file mode 100644
index 00000000..2968dcdf
--- /dev/null
+++ b/pandora/extensions/dependency_property/model/types/dependency_property.gd.uid
@@ -0,0 +1 @@
+uid://bv6atsu450c0j
diff --git a/pandora/extensions/dependency_property/property_button/property_button.tscn b/pandora/extensions/dependency_property/property_button/property_button.tscn
new file mode 100644
index 00000000..20a33f67
--- /dev/null
+++ b/pandora/extensions/dependency_property/property_button/property_button.tscn
@@ -0,0 +1,12 @@
+[gd_scene load_steps=4 format=3 uid="uid://bm08cj4lcvudv"]
+
+[ext_resource type="Texture2D" uid="uid://cvktrbp2le3eb" path="res://addons/gdUnit4/src/update/assets/dot1.png" id="1_2jhnd"]
+[ext_resource type="Script" uid="uid://crr6rlkqtg6we" path="res://addons/pandora/ui/components/property_bar/property_button.gd" id="2_nq2f7"]
+[ext_resource type="PackedScene" uid="uid://byn750powq8to" path="res://pandora/extensions/test_property/ui_component/test_property.tscn" id="3_ovgkr"]
+
+[node name="AddDependencyPropertyButton" type="Button"]
+tooltip_text = "Dependency property"
+icon = ExtResource("1_2jhnd")
+script = ExtResource("2_nq2f7")
+scene = ExtResource("3_ovgkr")
+metadata/_custom_type_script = "uid://crr6rlkqtg6we"
diff --git a/pandora/extensions/dependency_property/ui_component/dependency_property.gd b/pandora/extensions/dependency_property/ui_component/dependency_property.gd
new file mode 100644
index 00000000..18e2a6b6
--- /dev/null
+++ b/pandora/extensions/dependency_property/ui_component/dependency_property.gd
@@ -0,0 +1,44 @@
+@tool
+extends PandoraPropertyControl
+
+const DependencyPropertyType = preload("../model/types/dependency_property.gd")
+
+@onready var text_edit: TextEdit = $HBoxContainer/TextEdit
+@onready var spin_box: SpinBox = $HBoxContainer/SpinBox
+var current_property : PandoraDependencyProperty = PandoraDependencyProperty.new("", 0)
+
+func _ready() -> void:
+ refresh()
+
+ if _property != null:
+ _property.setting_changed.connect(_setting_changed)
+ _property.setting_cleared.connect(_setting_changed)
+ text_edit.focus_exited.connect(func(): unfocused.emit())
+ text_edit.focus_entered.connect(func(): focused.emit())
+ text_edit.text_changed.connect(
+ func():
+ current_property.set_item_name(text_edit.text)
+ _property.set_default_value(current_property)
+ property_value_changed.emit(current_property))
+
+ spin_box.focus_entered.connect(func(): focused.emit())
+ spin_box.focus_exited.connect(func(): unfocused.emit())
+ spin_box.value_changed.connect(
+ func(value: float):
+ current_property.set_quantity(int(value))
+ _property.set_default_value(current_property)
+ property_value_changed.emit(current_property))
+
+func refresh() -> void:
+ if _property != null:
+ spin_box.min_value = _property.get_setting(DependencyPropertyType.SETTING_MIN_VALUE) as int
+ spin_box.max_value = _property.get_setting(DependencyPropertyType.SETTING_MAX_VALUE) as int
+ if _property.get_default_value() != null:
+ current_property = _property.get_default_value() as PandoraDependencyProperty
+ text_edit.text = current_property.get_item_name()
+ text_edit.set_caret_column(text_edit.text.length())
+ spin_box.value = current_property.get_quantity()
+
+func _setting_changed(key:String) -> void:
+ if key == DependencyPropertyType.SETTING_MIN_VALUE || key == DependencyPropertyType.SETTING_MAX_VALUE:
+ refresh()
diff --git a/pandora/extensions/dependency_property/ui_component/dependency_property.gd.uid b/pandora/extensions/dependency_property/ui_component/dependency_property.gd.uid
new file mode 100644
index 00000000..d0ffbce3
--- /dev/null
+++ b/pandora/extensions/dependency_property/ui_component/dependency_property.gd.uid
@@ -0,0 +1 @@
+uid://cmdhm8gi3l3xv
diff --git a/pandora/extensions/dependency_property/ui_component/dependency_property.tscn b/pandora/extensions/dependency_property/ui_component/dependency_property.tscn
new file mode 100644
index 00000000..faa024fc
--- /dev/null
+++ b/pandora/extensions/dependency_property/ui_component/dependency_property.tscn
@@ -0,0 +1,24 @@
+[gd_scene load_steps=2 format=3 uid="uid://sqgw6p1rliv8"]
+
+[ext_resource type="Script" uid="uid://cmdhm8gi3l3xv" path="res://pandora/extensions/dependency_property/ui_component/dependency_property.gd" id="1_ovono"]
+
+[node name="DependencyProperty" type="MarginContainer"]
+script = ExtResource("1_ovono")
+type = "dependency_property"
+metadata/_custom_type_script = "uid://bvl8qiojdoihh"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="TextEdit" type="TextEdit" parent="HBoxContainer"]
+custom_minimum_size = Vector2(0, 31)
+layout_mode = 2
+size_flags_horizontal = 3
+placeholder_text = "Test Name"
+
+[node name="SpinBox" type="SpinBox" parent="HBoxContainer"]
+layout_mode = 2
+focus_mode = 1
+max_value = 99999.0
+rounded = true
+select_all_on_focus = true
diff --git a/pandora/extensions/test_property/model/test_property.gd b/pandora/extensions/test_property/model/test_property.gd
index b7284e76..aa662d64 100644
--- a/pandora/extensions/test_property/model/test_property.gd
+++ b/pandora/extensions/test_property/model/test_property.gd
@@ -20,11 +20,20 @@ func get_quantity() -> int:
return _quantity
func load_data(data: Dictionary) -> void:
- _item_name = data["item_name"]
- _quantity = data["quantity"]
-
-func save_data() -> Dictionary:
- return { "item_name": _item_name, "quantity": _quantity }
+ if data.has("item_name"):
+ _item_name = data["item_name"]
+ if data.has("quantity"):
+ _quantity = data["quantity"]
+
+func save_data(fields_settings: Array[Dictionary]) -> Dictionary:
+ var result := {}
+ var itemNameIdx := fields_settings.find(func(dic: Dictionary): return dic["name"] == "Item Name")
+ var quantityIdx := fields_settings.find(func(dic: Dictionary): return dic["name"] == "Quantity")
+ if fields_settings[itemNameIdx]["enabled"]:
+ result["item_name"] = _item_name
+ if fields_settings[quantityIdx]["enabled"]:
+ result["quantity"] = _quantity
+ return result
func _to_string() -> String:
- return ""
+ return ""
diff --git a/pandora/extensions/test_property/model/types/test_property.gd b/pandora/extensions/test_property/model/types/test_property.gd
index d5b9d93e..ac45079c 100644
--- a/pandora/extensions/test_property/model/types/test_property.gd
+++ b/pandora/extensions/test_property/model/types/test_property.gd
@@ -1,26 +1,47 @@
extends PandoraPropertyType
-const SETTING_CATEGORY_FILTER = "Category Filter"
const SETTING_MIN_VALUE = "Min Quantity"
const SETTING_MAX_VALUE = "Max Quantity"
-const SETTINGS = {
+var SETTINGS = {
SETTING_MIN_VALUE: {"type": "int", "value": -9999999999},
SETTING_MAX_VALUE: {"type": "int", "value": 9999999999}
}
func _init() -> void:
super("test_property", SETTINGS, null, "res://pandora/extensions/test_property/icons/icon.png")
+ Pandora.update_fields_settings.connect(_on_update_fields_settings)
+ _update_fields_settings()
+
+func _on_update_fields_settings(type: String) -> void:
+ if _type_name == type:
+ _update_fields_settings()
+
+func _update_fields_settings() -> void:
+ var extension_configuration := PandoraSettings.find_extension_configuration_property("test_property")
+ var fields_settings := extension_configuration["fields"] as Array
+ for field_settings in fields_settings:
+ if field_settings["name"] == "Quantity":
+ if field_settings["enabled"] == false:
+ SETTINGS.erase(SETTING_MAX_VALUE)
+ SETTINGS.erase(SETTING_MIN_VALUE)
+ else:
+ if !SETTINGS.has(SETTING_MAX_VALUE) or !SETTINGS.has(SETTING_MIN_VALUE):
+ SETTINGS[SETTING_MAX_VALUE] = {"type": "int", "value": field_settings["settings"]["max_value"]}
+ SETTINGS[SETTING_MIN_VALUE] = {"type": "int", "value": field_settings["settings"]["min_value"]}
+ _settings = SETTINGS
func parse_value(variant: Variant, _s: Dictionary = {}) -> Variant:
if variant is Dictionary:
- var item_name = variant["item_name"]
- var quantity = variant["quantity"]
+ var item_name = "" if not variant.has("item_name") else variant["item_name"]
+ var quantity = 0 if not variant.has("quantity") else variant["quantity"]
return PandoraTestProperty.new(item_name, quantity)
return variant
func write_value(variant: Variant) -> Variant:
if variant is PandoraTestProperty:
- return variant.save_data()
+ var extension_configuration := PandoraSettings.find_extension_configuration_property("test_property")
+ var fields_settings := extension_configuration["fields"] as Array
+ return variant.save_data(fields_settings)
return variant
func is_valid(variant: Variant) -> bool:
diff --git a/pandora/extensions/test_property/ui_component/test_property.gd b/pandora/extensions/test_property/ui_component/test_property.gd
index 023e371c..f6223be8 100644
--- a/pandora/extensions/test_property/ui_component/test_property.gd
+++ b/pandora/extensions/test_property/ui_component/test_property.gd
@@ -1,7 +1,7 @@
@tool
extends PandoraPropertyControl
-const ItemRecipeType = preload("../model/types/test_property.gd")
+const TestPropertyType = preload("../model/types/test_property.gd")
@onready var text_edit: TextEdit = $HBoxContainer/TextEdit
@onready var spin_box: SpinBox = $HBoxContainer/SpinBox
@@ -9,6 +9,7 @@ var current_property : PandoraTestProperty = PandoraTestProperty.new("", 0)
func _ready() -> void:
refresh()
+ Pandora.update_fields_settings.connect(_on_update_fields_settings)
if _property != null:
_property.setting_changed.connect(_setting_changed)
@@ -30,9 +31,17 @@ func _ready() -> void:
property_value_changed.emit(current_property))
func refresh() -> void:
+ for field_settings in _fields_settings:
+ if field_settings["name"] == "Quantity":
+ spin_box.visible = field_settings["enabled"]
+ elif field_settings["name"] == "Item Name":
+ spin_box.visible = field_settings["enabled"]
+
if _property != null:
- spin_box.min_value = _property.get_setting(ItemRecipeType.SETTING_MIN_VALUE) as int
- spin_box.max_value = _property.get_setting(ItemRecipeType.SETTING_MAX_VALUE) as int
+ if _property.get_setting(TestPropertyType.SETTING_MIN_VALUE):
+ spin_box.min_value = _property.get_setting(TestPropertyType.SETTING_MIN_VALUE) as int
+ if _property.get_setting(TestPropertyType.SETTING_MAX_VALUE):
+ spin_box.max_value = _property.get_setting(TestPropertyType.SETTING_MAX_VALUE) as int
if _property.get_default_value() != null:
current_property = _property.get_default_value() as PandoraTestProperty
text_edit.text = current_property.get_item_name()
@@ -40,5 +49,9 @@ func refresh() -> void:
spin_box.value = current_property.get_quantity()
func _setting_changed(key:String) -> void:
- if key == ItemRecipeType.SETTING_MIN_VALUE || key == ItemRecipeType.SETTING_MAX_VALUE:
+ if key == TestPropertyType.SETTING_MIN_VALUE || key == TestPropertyType.SETTING_MAX_VALUE:
+ refresh()
+
+func _on_update_fields_settings(property_type: String) -> void:
+ if property_type == type:
refresh()
diff --git a/pandora/extensions/test_property/ui_component/test_property.tscn b/pandora/extensions/test_property/ui_component/test_property.tscn
index 6aeb3adf..d7c7e9e5 100644
--- a/pandora/extensions/test_property/ui_component/test_property.tscn
+++ b/pandora/extensions/test_property/ui_component/test_property.tscn
@@ -11,6 +11,7 @@ metadata/_custom_type_script = "uid://bvl8qiojdoihh"
layout_mode = 2
[node name="TextEdit" type="TextEdit" parent="HBoxContainer"]
+custom_minimum_size = Vector2(0, 31)
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "Item Name"