└── addons
└── pandora
├── api.gd
├── api.gd.uid
├── backend
├── entity_backend.gd
└── entity_backend.gd.uid
├── context
├── context_manager.gd
└── context_manager.gd.uid
├── icons
├── Array.svg
├── Array.svg.import
├── AssetLib.svg
├── AssetLib.svg.import
├── AtlasTexture.svg
├── AtlasTexture.svg.import
├── Clear.svg
├── Clear.svg.import
├── Color.svg
├── Color.svg.import
├── Edit.svg
├── Edit.svg.import
├── Folder.svg
├── Folder.svg.import
├── Font.svg.import
├── KeyValue.svg
├── KeyValue.svg.import
├── Object.svg
├── Object.svg.import
├── Reload.svg
├── Reload.svg.import
├── Remove.svg
├── Remove.svg.import
├── Save.svg
├── Save.svg.import
├── Search.svg
├── Search.svg.import
├── String.svg
├── String.svg.import
├── Vector2.svg
├── Vector2.svg.import
├── Vector2i.svg
├── Vector2i.svg.import
├── Vector3.svg
├── Vector3.svg.import
├── Vector3i.svg
├── Vector3i.svg.import
├── bool.svg
├── bool.svg.import
├── float.svg
├── float.svg.import
├── icon.png
├── icon.png.import
├── int.svg
├── int.svg.import
├── nanoid.svg
├── nanoid.svg.import
├── pandora-icon.svg
├── pandora-icon.svg.import
├── pandora-json-icon.svg
└── pandora-json-icon.svg.import
├── model
├── category.gd
├── category.gd.uid
├── entity.gd
├── entity.gd.uid
├── property.gd
├── property.gd.uid
├── property_instance.gd
├── property_instance.gd.uid
├── reference.gd
├── reference.gd.uid
├── type.gd
├── type.gd.uid
└── types
│ ├── array.gd
│ ├── array.gd.uid
│ ├── bool.gd
│ ├── bool.gd.uid
│ ├── color.gd
│ ├── color.gd.uid
│ ├── float.gd
│ ├── float.gd.uid
│ ├── int.gd
│ ├── int.gd.uid
│ ├── reference.gd
│ ├── reference.gd.uid
│ ├── resource.gd
│ ├── resource.gd.uid
│ ├── string.gd
│ ├── string.gd.uid
│ ├── vector2.gd
│ ├── vector2.gd.uid
│ ├── vector2i.gd
│ ├── vector2i.gd.uid
│ ├── vector3.gd
│ ├── vector3.gd.uid
│ ├── vector3i.gd
│ └── vector3i.gd.uid
├── plugin.cfg
├── plugin.gd
├── plugin.gd.uid
├── settings
├── pandora_settings.gd
└── pandora_settings.gd.uid
├── storage
├── data_storage.gd
├── data_storage.gd.uid
└── json
│ ├── json_data_storage.gd
│ └── json_data_storage.gd.uid
├── ui
├── components
│ ├── array_editor
│ │ ├── array_editor.gd
│ │ ├── array_editor.gd.uid
│ │ ├── array_editor.tscn
│ │ ├── array_item.gd
│ │ ├── array_item.gd.uid
│ │ ├── array_item.tscn
│ │ ├── array_manager.gd
│ │ ├── array_manager.gd.uid
│ │ ├── array_manager.tscn
│ │ ├── array_window.gd
│ │ └── array_window.gd.uid
│ ├── color_picker
│ │ ├── color_picker.gd
│ │ ├── color_picker.gd.uid
│ │ └── color_picker.tscn
│ ├── entity_attributes
│ │ ├── entity_attributes.gd
│ │ ├── entity_attributes.gd.uid
│ │ └── entity_attributes.tscn
│ ├── entity_picker
│ │ ├── entity_picker.gd
│ │ ├── entity_picker.gd.uid
│ │ └── entity_picker.tscn
│ ├── entity_tree
│ │ ├── entity_tree.gd
│ │ ├── entity_tree.gd.uid
│ │ └── entity_tree.tscn
│ ├── loading_spinner
│ │ ├── LoadingSpinner.tscn
│ │ ├── loading_spinner.gd
│ │ └── loading_spinner.gd.uid
│ ├── notification_label
│ │ ├── notification_label.gd
│ │ ├── notification_label.gd.uid
│ │ └── notification_label.tscn
│ ├── progress_bar
│ │ ├── progress_bar.gd
│ │ ├── progress_bar.gd.uid
│ │ └── progress_bar.tscn
│ ├── properties
│ │ ├── array
│ │ │ ├── array_property.gd
│ │ │ ├── array_property.gd.uid
│ │ │ └── array_property.tscn
│ │ ├── bool
│ │ │ ├── bool_property.gd
│ │ │ ├── bool_property.gd.uid
│ │ │ └── bool_property.tscn
│ │ ├── color
│ │ │ ├── color_property.gd
│ │ │ ├── color_property.gd.uid
│ │ │ └── color_property.tscn
│ │ ├── float
│ │ │ ├── float_property.gd
│ │ │ ├── float_property.gd.uid
│ │ │ └── float_property.tscn
│ │ ├── integer
│ │ │ ├── integer_property.gd
│ │ │ ├── integer_property.gd.uid
│ │ │ └── integer_property.tscn
│ │ ├── property_control.gd
│ │ ├── property_control.gd.uid
│ │ ├── property_control_kvp.gd
│ │ ├── property_control_kvp.gd.uid
│ │ ├── property_control_kvp.tscn
│ │ ├── reference
│ │ │ ├── reference_property.gd
│ │ │ ├── reference_property.gd.uid
│ │ │ └── reference_property.tscn
│ │ ├── resource
│ │ │ ├── resource_property.gd
│ │ │ ├── resource_property.gd.uid
│ │ │ └── resource_property.tscn
│ │ ├── string
│ │ │ ├── string_property.gd
│ │ │ ├── string_property.gd.uid
│ │ │ └── string_property.tscn
│ │ └── vector
│ │ │ ├── vector2
│ │ │ └── vector2_property.tscn
│ │ │ ├── vector2i
│ │ │ └── vector2i_property.tscn
│ │ │ ├── vector3
│ │ │ └── vector3_property.tscn
│ │ │ ├── vector3i
│ │ │ └── vector3i_property.tscn
│ │ │ ├── vector_property.gd
│ │ │ └── vector_property.gd.uid
│ ├── property_bar
│ │ ├── property_bar.gd
│ │ ├── property_bar.gd.uid
│ │ ├── property_bar.tscn
│ │ ├── property_button.gd
│ │ └── property_button.gd.uid
│ ├── property_type_picker
│ │ ├── property_type_picker.gd
│ │ ├── property_type_picker.gd.uid
│ │ └── property_type_picker.tscn
│ ├── resource_picker
│ │ ├── resource_picker.gd
│ │ ├── resource_picker.gd.uid
│ │ └── resource_picker.tscn
│ ├── script_picker
│ │ ├── script_picker.gd
│ │ ├── script_picker.gd.uid
│ │ └── script_picker.tscn
│ ├── texture_picker
│ │ ├── texture_picker.gd
│ │ ├── texture_picker.gd.uid
│ │ └── texture_picker.tscn
│ ├── update_button
│ │ ├── update_button.gd
│ │ ├── update_button.gd.uid
│ │ └── update_button.tscn
│ └── updater
│ │ ├── updater.gd
│ │ ├── updater.gd.uid
│ │ └── updater.tscn
└── editor
│ ├── import_dialog
│ ├── import_dialog.gd
│ ├── import_dialog.gd.uid
│ └── import_dialog.tscn
│ ├── inspector
│ ├── entity_category_browser_property.gd
│ ├── entity_category_browser_property.gd.uid
│ ├── entity_instance_browser_property.gd
│ ├── entity_instance_browser_property.gd.uid
│ ├── entity_instance_inspector.gd
│ └── entity_instance_inspector.gd.uid
│ ├── pandora_editor.gd
│ ├── pandora_editor.gd.uid
│ ├── pandora_editor.tscn
│ ├── property_editor
│ ├── property_editor.gd
│ ├── property_editor.gd.uid
│ └── property_editor.tscn
│ └── property_settings_editor
│ ├── property_settings_editor.gd
│ ├── property_settings_editor.gd.uid
│ └── property_settings_editor.tscn
└── util
├── category_id_file_generator.gd
├── category_id_file_generator.gd.uid
├── compression.gd
├── compression.gd.uid
├── entity_id_file_generator.gd
├── entity_id_file_generator.gd.uid
├── id_generator.gd
├── id_generator.gd.uid
├── nanoid_generator.gd
├── nanoid_generator.gd.uid
├── script_util.gd
├── script_util.gd.uid
├── sequential_id_generator.gd
├── sequential_id_generator.gd.uid
├── tokenizer.gd
└── tokenizer.gd.uid
/addons/pandora/api.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bqv713p4thrli
2 |
--------------------------------------------------------------------------------
/addons/pandora/backend/entity_backend.gd.uid:
--------------------------------------------------------------------------------
1 | uid://hd7urlwrtgyk
2 |
--------------------------------------------------------------------------------
/addons/pandora/context/context_manager.gd:
--------------------------------------------------------------------------------
1 | ## Stores the pandora context. The context influences
2 | ## where user data will be stored. Change the context id
3 | ## to ensure custom save games for example.
4 | @tool
5 | class_name PandoraContextManager extends RefCounted
6 |
7 | # Notifies if the context has changed.
8 | # This can happen if someone changes save games.
9 | signal context_changed
10 |
11 | var _context_id: String = ""
12 |
13 |
14 | func set_context_id(new_context_id: String) -> void:
15 | _context_id = new_context_id
16 |
17 |
18 | func get_context_id() -> String:
19 | return _context_id
20 |
--------------------------------------------------------------------------------
/addons/pandora/context/context_manager.gd.uid:
--------------------------------------------------------------------------------
1 | uid://wy0hx3e0e8rf
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Array.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Array.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://66qnm42libnj"
6 | path="res://.godot/imported/Array.svg-a46ab8298ee257f5a16f285b9bfb722e.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Array.svg"
15 | dest_files=["res://.godot/imported/Array.svg-a46ab8298ee257f5a16f285b9bfb722e.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/AssetLib.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/AssetLib.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dp8it1xjb8k2g"
6 | path="res://.godot/imported/AssetLib.svg-da7edefaec4f5631f9f4bbb2bb7ae4d1.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/AssetLib.svg"
15 | dest_files=["res://.godot/imported/AssetLib.svg-da7edefaec4f5631f9f4bbb2bb7ae4d1.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/AtlasTexture.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/AtlasTexture.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://rwodit05tms7"
6 | path="res://.godot/imported/AtlasTexture.svg-5056fe4707ffa264301261f449c31722.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/AtlasTexture.svg"
15 | dest_files=["res://.godot/imported/AtlasTexture.svg-5056fe4707ffa264301261f449c31722.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Clear.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Clear.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c8r1klbs37r1b"
6 | path="res://.godot/imported/Clear.svg-0b2da895d5f89295ced9a0d8c6f7878a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Clear.svg"
15 | dest_files=["res://.godot/imported/Clear.svg-0b2da895d5f89295ced9a0d8c6f7878a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Color.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Color.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c2738ylh13lsi"
6 | path="res://.godot/imported/Color.svg-79c67f8866a25395b767b76e5b6ff9b9.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Color.svg"
15 | dest_files=["res://.godot/imported/Color.svg-79c67f8866a25395b767b76e5b6ff9b9.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Edit.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Edit.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b0mt8ysdc5m4a"
6 | path="res://.godot/imported/Edit.svg-b452cfd6b4320d4a03672cd65cb72329.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Edit.svg"
15 | dest_files=["res://.godot/imported/Edit.svg-b452cfd6b4320d4a03672cd65cb72329.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Folder.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Folder.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dimpswbv6s8t2"
6 | path="res://.godot/imported/Folder.svg-1bac157773346222a10a5988ba2390e6.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Folder.svg"
15 | dest_files=["res://.godot/imported/Folder.svg-1bac157773346222a10a5988ba2390e6.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Font.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cjib8mo772gfh"
6 | path="res://.godot/imported/Font.svg-af5511d99ea1f05b3118bee68790c21f.ctex"
7 | metadata={
8 | "editor_dark_theme": true,
9 | "editor_scale": 2.0,
10 | "has_editor_variant": true,
11 | "vram_texture": false
12 | }
13 |
14 | [deps]
15 |
16 | source_file="res://addons/pandora/icons/Font.svg"
17 | dest_files=["res://.godot/imported/Font.svg-af5511d99ea1f05b3118bee68790c21f.ctex"]
18 |
19 | [params]
20 |
21 | compress/mode=0
22 | compress/high_quality=false
23 | compress/lossy_quality=0.7
24 | compress/hdr_compression=1
25 | compress/normal_map=0
26 | compress/channel_pack=0
27 | mipmaps/generate=false
28 | mipmaps/limit=-1
29 | roughness/mode=0
30 | roughness/src_normal=""
31 | process/fix_alpha_border=true
32 | process/premult_alpha=false
33 | process/normal_map_invert_y=false
34 | process/hdr_as_srgb=false
35 | process/hdr_clamp_exposure=false
36 | process/size_limit=0
37 | detect_3d/compress_to=1
38 | svg/scale=1.0
39 | editor/scale_with_editor_scale=true
40 | editor/convert_colors_with_editor_theme=true
41 |
--------------------------------------------------------------------------------
/addons/pandora/icons/KeyValue.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/KeyValue.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cb6str3hxrsdi"
6 | path="res://.godot/imported/KeyValue.svg-2822461d639d1a30d7677dfb5a40c9b5.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/KeyValue.svg"
15 | dest_files=["res://.godot/imported/KeyValue.svg-2822461d639d1a30d7677dfb5a40c9b5.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Object.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Object.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dojpd3ptnta4m"
6 | path="res://.godot/imported/Object.svg-cc61fbab643ed4cbb8bfe8ae40e25621.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Object.svg"
15 | dest_files=["res://.godot/imported/Object.svg-cc61fbab643ed4cbb8bfe8ae40e25621.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Reload.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Reload.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bhcep67ihojnd"
6 | path="res://.godot/imported/Reload.svg-8d99b6e330288432ea0139869560d96f.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Reload.svg"
15 | dest_files=["res://.godot/imported/Reload.svg-8d99b6e330288432ea0139869560d96f.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=false
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Remove.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Remove.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b2s1ixfakdj1e"
6 | path="res://.godot/imported/Remove.svg-304a522644e37fda7b1d0215ad410adc.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/pandora/icons/Remove.svg"
14 | dest_files=["res://.godot/imported/Remove.svg-304a522644e37fda7b1d0215ad410adc.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Save.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Save.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b8sd2702bmm7h"
6 | path="res://.godot/imported/Save.svg-14d8c562c46cec9ff174ae539c06d191.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Save.svg"
15 | dest_files=["res://.godot/imported/Save.svg-14d8c562c46cec9ff174ae539c06d191.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Search.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Search.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bv43ytfd0mlq1"
6 | path="res://.godot/imported/Search.svg-a90a8090ed63d36963e355a62f2bc45a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Search.svg"
15 | dest_files=["res://.godot/imported/Search.svg-a90a8090ed63d36963e355a62f2bc45a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/String.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/String.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://do5tkodyvid10"
6 | path="res://.godot/imported/String.svg-3b9e9f01cea93110daa936c3cf4f9623.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/String.svg"
15 | dest_files=["res://.godot/imported/String.svg-3b9e9f01cea93110daa936c3cf4f9623.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector2.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector2.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dcqltisjej0lu"
6 | path="res://.godot/imported/Vector2.svg-f2f9dce954f37bf7fb37a4d1ec1f0f9a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Vector2.svg"
15 | dest_files=["res://.godot/imported/Vector2.svg-f2f9dce954f37bf7fb37a4d1ec1f0f9a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector2i.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector2i.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bk7a4jkyif178"
6 | path="res://.godot/imported/Vector2i.svg-eeccc3f61eae845ad95d8e0ca54c343f.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Vector2i.svg"
15 | dest_files=["res://.godot/imported/Vector2i.svg-eeccc3f61eae845ad95d8e0ca54c343f.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector3.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector3.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bdxvds1pxhqv6"
6 | path="res://.godot/imported/Vector3.svg-28214985aa7422f5a8cd639de0a26885.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Vector3.svg"
15 | dest_files=["res://.godot/imported/Vector3.svg-28214985aa7422f5a8cd639de0a26885.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector3i.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/Vector3i.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c6kohe0abjrrs"
6 | path="res://.godot/imported/Vector3i.svg-fd64811289ff8c1fe119369f99b57b5c.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/Vector3i.svg"
15 | dest_files=["res://.godot/imported/Vector3i.svg-fd64811289ff8c1fe119369f99b57b5c.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/bool.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/bool.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://mmkaghs6sbx4"
6 | path="res://.godot/imported/bool.svg-43fb3fae2bb7e39a7a051a979b8ac2d3.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/bool.svg"
15 | dest_files=["res://.godot/imported/bool.svg-43fb3fae2bb7e39a7a051a979b8ac2d3.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/float.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/float.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cgupnims1vk7r"
6 | path="res://.godot/imported/float.svg-e237fdb12d4b5cee467fb0900459d2a1.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/float.svg"
15 | dest_files=["res://.godot/imported/float.svg-e237fdb12d4b5cee467fb0900459d2a1.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bitbrain/pandora/48ec6e4c38cb92ef9d8b2be9a1fb77302ceadab4/addons/pandora/icons/icon.png
--------------------------------------------------------------------------------
/addons/pandora/icons/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://crgjwaubao8pj"
6 | path="res://.godot/imported/icon.png-c66b8d90e029ace486d4c4b5320f5855.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/pandora/icons/icon.png"
14 | dest_files=["res://.godot/imported/icon.png-c66b8d90e029ace486d4c4b5320f5855.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/pandora/icons/int.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/pandora/icons/int.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://blvy22tu53qxy"
6 | path="res://.godot/imported/int.svg-afe9a260ccab507b1ae9c13850b1afc8.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/int.svg"
15 | dest_files=["res://.godot/imported/int.svg-afe9a260ccab507b1ae9c13850b1afc8.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/nanoid.svg:
--------------------------------------------------------------------------------
1 |
2 |
52 |
--------------------------------------------------------------------------------
/addons/pandora/icons/nanoid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bfs83ic84umkv"
6 | path="res://.godot/imported/nanoid.svg-3c980c901e5edd8de536968665f465a0.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/nanoid.svg"
15 | dest_files=["res://.godot/imported/nanoid.svg-3c980c901e5edd8de536968665f465a0.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/pandora-icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dmh7pik8vjog8"
6 | path="res://.godot/imported/pandora-icon.svg-32440ea7d526187438f368f7b3906fad.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/pandora/icons/pandora-icon.svg"
15 | dest_files=["res://.godot/imported/pandora-icon.svg-32440ea7d526187438f368f7b3906fad.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/pandora/icons/pandora-json-icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://0aj3pk4ubvl7"
6 | path="res://.godot/imported/pandora-json-icon.svg-cbce8b7cbd8bcce6f1b57ba39adfd148.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/pandora/icons/pandora-json-icon.svg"
14 | dest_files=["res://.godot/imported/pandora-json-icon.svg-cbce8b7cbd8bcce6f1b57ba39adfd148.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/pandora/model/category.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PandoraCategory extends PandoraEntity
3 |
4 | # not persisted but computed at runtime
5 | var _children: Array[PandoraEntity] = []
6 |
7 |
8 | func get_child(entity_id: String) -> PandoraEntity:
9 | for child in _children:
10 | if child.get_entity_id() == entity_id:
11 | return child
12 | return null
13 |
14 |
15 | func get_icon_path() -> String:
16 | if _icon_path != "":
17 | return _icon_path
18 | if _category_id != "" and get_category() != null and get_category()._icon_path != "":
19 | return get_category().get_icon_path()
20 | return "res://addons/pandora/icons/Folder.svg"
21 |
22 |
23 | func _delete_property(name: String) -> void:
24 | super._delete_property(name)
25 | for child in _children:
26 | child._delete_property(name)
27 |
28 |
29 | func _to_string() -> String:
30 | return ""
31 |
--------------------------------------------------------------------------------
/addons/pandora/model/category.gd.uid:
--------------------------------------------------------------------------------
1 | uid://ddi7nbxu0sys3
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/entity.gd.uid:
--------------------------------------------------------------------------------
1 | uid://8q73873xik7s
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/property.gd:
--------------------------------------------------------------------------------
1 | ## A property contains a Variant that can be accessed
2 | ## across Pandora by id. Properties can be shared between
3 | ## different entities (depending on the way they get inherited).
4 | ## This ensures that changing the original property will automatically
5 | ## apply to any other entity that is using it.
6 | class_name PandoraProperty extends RefCounted
7 |
8 | ## Emitted when the name of this property changed.
9 | signal name_changed(old_name: String, new_name: String)
10 | signal setting_changed(key: String)
11 | signal setting_cleared(key: String)
12 |
13 | var _id: String
14 | var _name: String:
15 | set(n):
16 | var old = _name
17 | _name = n
18 | if _name != old:
19 | name_changed.emit(old, _name)
20 | var _type: PandoraPropertyType
21 | var _default_value: Variant
22 | var _category_id: String
23 | # setting name -> Variant
24 | var _setting_overrides: Dictionary = {}
25 |
26 |
27 | func _init(id: String, name: String, type_name: String) -> void:
28 | self._id = id
29 | self._name = name
30 | self._type = PandoraPropertyType.lookup(type_name)
31 | self._default_value = _type.get_default_value()
32 |
33 |
34 | func get_setting(key: String) -> Variant:
35 | if has_setting_override(key):
36 | return _setting_overrides[key]
37 | elif _type != null:
38 | return _type.get_settings()[key]["value"]
39 | else:
40 | return null
41 |
42 |
43 | func get_setting_override(name: String) -> Variant:
44 | if _setting_overrides.has(name):
45 | return _setting_overrides[name]
46 | return null
47 |
48 |
49 | func has_setting_override(name: String) -> bool:
50 | return _setting_overrides.has(name)
51 |
52 |
53 | func set_setting_override(name: String, override: Variant) -> void:
54 | _setting_overrides[name] = override
55 | setting_changed.emit(name)
56 |
57 |
58 | func clear_setting_override(name: String) -> void:
59 | _setting_overrides.erase(name)
60 | setting_cleared.emit(name)
61 |
62 |
63 | func set_default_value(value: Variant) -> void:
64 | if not _type.is_valid(value):
65 | print("Pandora error: value " + str(value) + " is incompatible with type ", _type)
66 | return
67 | # ensure that a supported type is assigned.
68 | if value is PandoraEntity:
69 | value = PandoraReference.new(
70 | value.get_entity_id(),
71 | (
72 | PandoraReference.Type.CATEGORY
73 | if value is PandoraCategory
74 | else PandoraReference.Type.ENTITY
75 | )
76 | )
77 | _default_value = value
78 |
79 |
80 | func get_property_id() -> String:
81 | return _id
82 |
83 |
84 | func get_property_name() -> String:
85 | return _name
86 |
87 |
88 | func get_property_type() -> PandoraPropertyType:
89 | return _type
90 |
91 |
92 | func get_default_value() -> Variant:
93 | if _default_value is PandoraReference:
94 | return _default_value.get_entity()
95 | return _default_value
96 |
97 |
98 | func get_category_id() -> String:
99 | return _category_id
100 |
101 |
102 | ## the original category id specifies
103 | ## the category where this property has
104 | ## been originally defined (and inherited down)
105 | func get_original_category_id() -> String:
106 | return _category_id
107 |
108 |
109 | ## resets this property to its original
110 | ## default value in case it was overridden
111 | func reset_to_default() -> void:
112 | pass
113 |
114 |
115 | ## true in case this property is the original definition
116 | ## of a property. (not inherited)
117 | func is_original() -> bool:
118 | return true
119 |
120 |
121 | ## returns true when this property is currently overridden
122 | func is_overridden() -> bool:
123 | return false
124 |
125 |
126 | func load_data(data: Dictionary) -> void:
127 | _id = data["_id"]
128 | _name = data["_name"]
129 | _type = PandoraPropertyType.lookup(data["_type"])
130 | _category_id = data["_category_id"]
131 | if data.has("_setting_overrides"):
132 | _setting_overrides = data["_setting_overrides"]
133 | _default_value = _type.parse_value(data["_default_value"], data["_setting_overrides"])
134 | else:
135 | _default_value = _type.parse_value(data["_default_value"])
136 |
137 |
138 | func save_data() -> Dictionary:
139 | var data = {
140 | "_id": _id,
141 | "_name": _name,
142 | "_type": _type.get_type_name(),
143 | "_default_value": _type.write_value(_default_value),
144 | "_category_id": _category_id,
145 | }
146 | if not _setting_overrides.is_empty():
147 | data["_setting_overrides"] = _setting_overrides
148 | return data
149 |
150 |
151 | func equals(other: PandoraProperty) -> bool:
152 | return (
153 | get_property_id() == other.get_property_id()
154 | and get_property_name() == other.get_property_name()
155 | and get_property_type() == other.get_property_type()
156 | )
157 |
158 |
159 | func _to_string() -> String:
160 | return (
161 | ""
166 | )
167 |
--------------------------------------------------------------------------------
/addons/pandora/model/property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cu448of86n1i3
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/property_instance.gd:
--------------------------------------------------------------------------------
1 | class_name PandoraPropertyInstance extends Resource
2 |
3 | var _property_id: String
4 | var _value: Variant
5 | # not persisted -> set at runtime
6 | var _property: PandoraProperty
7 |
8 |
9 | func _init(_property: PandoraProperty, value: Variant) -> void:
10 | if _property != null:
11 | self._property_id = _property.get_property_id()
12 | self._value = value
13 | self._property = _property
14 |
15 |
16 | func duplicate_instance() -> PandoraPropertyInstance:
17 | return PandoraPropertyInstance.new(_property, _value)
18 |
19 |
20 | func get_property_name() -> String:
21 | if _property != null:
22 | return _property.get_property_name()
23 | return ""
24 |
25 |
26 | func get_property_id() -> String:
27 | return _property_id
28 |
29 |
30 | func get_property_value() -> Variant:
31 | return _value
32 |
33 |
34 | func set_property_value(value: Variant) -> void:
35 | self._value = value
36 |
37 |
38 | func load_data(data: Dictionary) -> void:
39 | _property_id = data["_property_id"]
40 | _property = Pandora.get_property(_property_id) as PandoraProperty
41 | var type = _property.get_property_type() as PandoraPropertyType
42 | _value = type.parse_value(data["_value"])
43 |
44 |
45 | func save_data() -> Dictionary:
46 | var type = _property.get_property_type() as PandoraPropertyType
47 | return {"_value": type.write_value(_value), "_property_id": _property_id}
48 |
49 |
50 | func _to_string() -> String:
51 | return ""
52 |
--------------------------------------------------------------------------------
/addons/pandora/model/property_instance.gd.uid:
--------------------------------------------------------------------------------
1 | uid://kxm5rqslpngs
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/reference.gd:
--------------------------------------------------------------------------------
1 | class_name PandoraReference extends RefCounted
2 |
3 | enum Type { ENTITY, CATEGORY }
4 |
5 | var _entity_id: String
6 | var _type: Type
7 |
8 |
9 | func _init(entity_id: String, type: Type) -> void:
10 | _entity_id = entity_id
11 | _type = type
12 |
13 |
14 | func get_entity() -> PandoraEntity:
15 | if _type == Type.ENTITY:
16 | return Pandora.get_entity(_entity_id)
17 | else:
18 | return Pandora.get_category(_entity_id)
19 |
20 |
21 | func load_data(data: Dictionary) -> void:
22 | _entity_id = data["_entity_id"]
23 | if data.has("_type"):
24 | _type = data["_type"]
25 | else:
26 | _type = Type.ENTITY
27 |
28 |
29 | func save_data() -> Dictionary:
30 | return {"_entity_id": _entity_id, "_type": _type}
31 |
32 |
33 | func _to_string() -> String:
34 | return ""
35 |
--------------------------------------------------------------------------------
/addons/pandora/model/reference.gd.uid:
--------------------------------------------------------------------------------
1 | uid://kq36ufctf202
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/type.gd:
--------------------------------------------------------------------------------
1 | ## This class allows us to make it easier
2 | ## to specify new types, e.g. by adding a new file
3 | ## which then internally specifies everything Pandora needs to know,
4 | ## including serialization, property settings and validation.
5 | class_name PandoraPropertyType extends RefCounted
6 |
7 |
8 | class UndefinedType:
9 | extends PandoraPropertyType
10 |
11 | func _init():
12 | super("undefined", {}, null, "")
13 |
14 |
15 | var _type_name: String
16 | var _settings: Dictionary
17 | var _default_value: Variant
18 | var _type_icon_path: String
19 |
20 |
21 | func _init(
22 | type_name: String, settings: Dictionary, default_value: Variant, type_icon_path: String
23 | ) -> void:
24 | self._type_name = type_name
25 | self._settings = settings
26 | self._default_value = default_value
27 | self._type_icon_path = type_icon_path
28 |
29 |
30 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
31 | return variant
32 |
33 |
34 | func write_value(variant: Variant) -> Variant:
35 | return variant
36 |
37 |
38 | func get_type_name() -> String:
39 | return _type_name
40 |
41 |
42 | func get_settings() -> Dictionary:
43 | return _settings
44 |
45 |
46 | func has_settings() -> bool:
47 | return _settings.is_empty() == false
48 |
49 |
50 | func get_default_value() -> Variant:
51 | return _default_value
52 |
53 |
54 | func get_type_icon_path() -> String:
55 | return _type_icon_path
56 |
57 |
58 | func is_valid(variant: Variant) -> bool:
59 | return false
60 |
61 |
62 | func allow_nesting() -> bool:
63 | return true
64 |
65 |
66 | static func lookup(name: String) -> PandoraPropertyType:
67 | if name == "":
68 | return UndefinedType.new()
69 |
70 | var klass = PandoraPropertyType
71 | var types_dir = klass.resource_path.get_base_dir()
72 | var type_path = types_dir + "/types/" + name + ".gd"
73 |
74 | if ResourceLoader.exists(type_path):
75 | var ScriptType = load(type_path)
76 | if ScriptType != null:
77 | if ScriptType.has_source_code() or ScriptType.can_instantiate():
78 | return ScriptType.new()
79 |
80 | return UndefinedType.new()
81 |
82 |
83 | static func get_all_types() -> Array[PandoraPropertyType]:
84 | var types: Array[PandoraPropertyType] = []
85 | var dir = DirAccess.open("res://addons/pandora/model/types")
86 | dir.list_dir_begin()
87 | var file_name: String = dir.get_next()
88 | while file_name != "":
89 | if file_name.ends_with(".gd"):
90 | var type_name = file_name.left(file_name.length() - 3)
91 | var type = lookup(type_name)
92 | if type != null:
93 | types.append(type)
94 | file_name = dir.get_next()
95 | dir.list_dir_end()
96 | return types
97 |
--------------------------------------------------------------------------------
/addons/pandora/model/type.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dn82xgmfu5q7t
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/array.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Array.svg"
4 |
5 | const SETTING_ARRAY_TYPE = "Array Type"
6 |
7 | const SETTINGS = {
8 | SETTING_ARRAY_TYPE:
9 | {
10 | "type": "property_type",
11 | "value": "string",
12 | }
13 | }
14 |
15 |
16 | func _init() -> void:
17 | super("array", SETTINGS, [], ICON_PATH)
18 |
19 |
20 | func is_valid(variant: Variant) -> bool:
21 | return variant is Array
22 |
23 |
24 | func get_merged_settings(property: PandoraProperty) -> Dictionary:
25 | var merged_settings: Dictionary = _settings.duplicate()
26 | var array_type = PandoraPropertyType.lookup(property.get_setting(SETTING_ARRAY_TYPE))
27 | var array_type_settings: Dictionary = array_type.get_settings().duplicate()
28 | merged_settings.merge(array_type_settings)
29 | return merged_settings
30 |
31 |
32 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
33 | if variant is Dictionary:
34 | var array = []
35 | var dict = variant as Dictionary
36 | for i in range(dict.size()):
37 | var value = dict[str(i)]
38 | if not settings.is_empty():
39 | if settings[SETTING_ARRAY_TYPE] == "reference" and "_entity_id" in value:
40 | value = PandoraReference.new(value["_entity_id"], value["_type"]).get_entity()
41 | if settings[SETTING_ARRAY_TYPE] == "resource":
42 | value = load(value)
43 | if settings[SETTING_ARRAY_TYPE] == "color":
44 | value = Color.from_string(value, Color.WHITE)
45 | else:
46 | if value is Dictionary and value.has("type") and value.has("value"):
47 | var value_type = value["type"]
48 | var dict_value = value["value"]
49 |
50 | var type = PandoraPropertyType.lookup(value_type)
51 | if type != null:
52 | value = type.parse_value(dict_value)
53 |
54 | array.append(value)
55 | return array
56 | return variant
57 |
58 |
59 | func write_value(variant: Variant) -> Variant:
60 | var array = variant as Array
61 | var dict = {}
62 | if not array.is_empty():
63 | var types = PandoraPropertyType.get_all_types()
64 | var value_type
65 |
66 | for i in range(array.size()):
67 | var value = array[i]
68 | if value is PandoraEntity:
69 | value_type = PandoraPropertyType.lookup("reference")
70 | value = (
71 | PandoraReference
72 | . new(
73 | value.get_entity_id(),
74 | (
75 | PandoraReference.Type.CATEGORY
76 | if value is PandoraCategory
77 | else PandoraReference.Type.ENTITY
78 | )
79 | )
80 | . save_data()
81 | )
82 | elif value is PandoraReference:
83 | value_type = PandoraPropertyType.lookup("reference")
84 | value = value.save_data()
85 | else:
86 | for type in types:
87 | if type.is_valid(value):
88 | value_type = type
89 | value = type.write_value(value)
90 | break
91 |
92 | if value != null:
93 | if value_type == null:
94 | dict[str(i)] = value
95 | else:
96 | dict[str(i)] = {"type": value_type.get_type_name(), "value": value}
97 |
98 | return dict
99 |
100 |
101 | func allow_nesting() -> bool:
102 | return false
103 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/array.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b0b632vedutjw
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/bool.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/bool.svg"
4 |
5 | const SETTINGS = {}
6 |
7 |
8 | func _init() -> void:
9 | super("bool", SETTINGS, false, ICON_PATH)
10 |
11 |
12 | func is_valid(variant: Variant) -> bool:
13 | return variant is bool
14 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/bool.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cbc5oo6r7ghbj
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/color.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Color.svg"
4 |
5 | const SETTINGS = {}
6 |
7 |
8 | func _init() -> void:
9 | super("color", SETTINGS, Color.WHITE, ICON_PATH)
10 |
11 |
12 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
13 | if variant is String:
14 | return Color.from_string(variant, Color.WHITE)
15 | return variant
16 |
17 |
18 | func write_value(variant: Variant) -> Variant:
19 | var color = variant as Color
20 | return color.to_html()
21 |
22 |
23 | func is_valid(variant: Variant) -> bool:
24 | return variant is Color or variant is String
25 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/color.gd.uid:
--------------------------------------------------------------------------------
1 | uid://d2xr4whsmpnnw
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/float.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/float.svg"
4 |
5 | const SETTING_MIN_VALUE = "Min Value"
6 | const SETTING_MAX_VALUE = "Max Value"
7 | const SETTING_STEPS = "Steps"
8 |
9 | const SETTINGS = {
10 | SETTING_STEPS: {"type": "float", "value": 0.01},
11 | SETTING_MIN_VALUE: {"type": "int", "value": -9999999999},
12 | SETTING_MAX_VALUE: {"type": "int", "value": 9999999999}
13 | }
14 |
15 |
16 | func _init() -> void:
17 | super("float", SETTINGS, 0.0, ICON_PATH)
18 |
19 |
20 | func is_valid(variant: Variant) -> bool:
21 | return variant is float
22 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/float.gd.uid:
--------------------------------------------------------------------------------
1 | uid://by7c2yf0lqsg7
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/int.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/int.svg"
4 |
5 | const SETTING_MIN_VALUE = "Min Value"
6 | const SETTING_MAX_VALUE = "Max Value"
7 |
8 | const SETTINGS = {
9 | SETTING_MIN_VALUE: {"type": "int", "value": -9999999999},
10 | SETTING_MAX_VALUE: {"type": "int", "value": 9999999999}
11 | }
12 |
13 |
14 | func _init() -> void:
15 | super("int", SETTINGS, 0, ICON_PATH)
16 |
17 |
18 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
19 | if variant is float:
20 | return int(variant)
21 | return variant
22 |
23 |
24 | func is_valid(variant: Variant) -> bool:
25 | return variant is int
26 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/int.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cn8krkhtccirc
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/reference.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Object.svg"
4 |
5 | const SETTING_CATEGORIES_ONLY = "Categories Only"
6 | const SETTING_CATEGORY_FILTER = "Category Filter"
7 | const SETTING_SORT_LIST = "Sort List"
8 | const SORT_ALPHABETICALLY = "Alphabetically"
9 | const SORT_AS_IS = "As-Is"
10 |
11 | const SETTINGS = {
12 | SETTING_CATEGORIES_ONLY: {"type": "bool", "value": false},
13 | SETTING_CATEGORY_FILTER: {"type": "reference", "value": ""},
14 | SETTING_SORT_LIST:
15 | {"type": "string", "options": [SORT_ALPHABETICALLY, SORT_AS_IS], "value": SORT_ALPHABETICALLY}
16 | }
17 |
18 |
19 | func _init() -> void:
20 | super("reference", SETTINGS, null, ICON_PATH)
21 |
22 |
23 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
24 | if variant is Dictionary:
25 | var reference = PandoraReference.new("", 0)
26 | reference.load_data(variant)
27 | return reference
28 | return variant
29 |
30 |
31 | func write_value(variant: Variant) -> Variant:
32 | if variant is PandoraReference:
33 | return variant.save_data()
34 | return variant
35 |
36 |
37 | func is_valid(variant: Variant) -> bool:
38 | return variant is PandoraEntity
39 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/reference.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bs8pju4quv8m3
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/resource.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/AtlasTexture.svg"
4 |
5 | const SETTINGS = {}
6 |
7 |
8 | func _init() -> void:
9 | super("resource", SETTINGS, null, ICON_PATH)
10 |
11 |
12 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
13 | if variant is String:
14 | return load(variant)
15 | return variant
16 |
17 |
18 | func write_value(variant: Variant) -> Variant:
19 | if variant is Resource:
20 | return variant.resource_path
21 | return variant
22 |
23 |
24 | func is_valid(variant: Variant) -> bool:
25 | return variant is Resource
26 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/resource.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cy0nw76c56kl7
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/string.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/String.svg"
4 |
5 | const SETTINGS = {}
6 |
7 |
8 | func _init() -> void:
9 | super("string", SETTINGS, "", ICON_PATH)
10 |
11 |
12 | func is_valid(variant: Variant) -> bool:
13 | return variant is String
14 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/string.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bmmbuipddr40v
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector2.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Vector2.svg"
4 |
5 | const SETTING_MIN_COMPONENT_VALUE = "Min Component Value"
6 | const SETTING_MAX_COMPONENT_VALUE = "Max Component Value"
7 | const SETTING_STEPS = "Steps"
8 |
9 | const SETTINGS = {
10 | SETTING_STEPS: {"type": "float", "value": 0.01},
11 | SETTING_MIN_COMPONENT_VALUE: {"type": "int", "value": -9999999999},
12 | SETTING_MAX_COMPONENT_VALUE: {"type": "int", "value": 9999999999}
13 | }
14 |
15 |
16 | func _init() -> void:
17 | super("vector2", SETTINGS, Vector2.ZERO, ICON_PATH)
18 |
19 |
20 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
21 | if variant is String:
22 | var values = variant.trim_prefix("(").trim_suffix(")").split(",", false, 1)
23 | return Vector2(values[0].to_float(), values[1].to_float())
24 | return variant
25 |
26 |
27 | func write_value(variant: Variant) -> Variant:
28 | var vector = variant as Vector2
29 | return "(%s,%s)" % [vector.x, vector.y]
30 |
31 |
32 | func is_valid(variant: Variant) -> bool:
33 | return variant is Vector2
34 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector2.gd.uid:
--------------------------------------------------------------------------------
1 | uid://rbxug87suaxl
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector2i.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Vector2i.svg"
4 |
5 | const SETTING_MIN_COMPONENT_VALUE = "Min Component Value"
6 | const SETTING_MAX_COMPONENT_VALUE = "Max Component Value"
7 |
8 | const SETTINGS = {
9 | SETTING_MIN_COMPONENT_VALUE: {"type": "int", "value": -9999999999},
10 | SETTING_MAX_COMPONENT_VALUE: {"type": "int", "value": 9999999999}
11 | }
12 |
13 |
14 | func _init() -> void:
15 | super("vector2i", SETTINGS, Vector2i.ZERO, ICON_PATH)
16 |
17 |
18 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
19 | if variant is String:
20 | var values = variant.trim_prefix("(").trim_suffix(")").split(",", false, 1)
21 | return Vector2i(values[0].to_int(), values[1].to_int())
22 | return variant
23 |
24 |
25 | func write_value(variant: Variant) -> Variant:
26 | var vector = variant as Vector2i
27 | return "(%s,%s)" % [vector.x, vector.y]
28 |
29 |
30 | func is_valid(variant: Variant) -> bool:
31 | return variant is Vector2i
32 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector2i.gd.uid:
--------------------------------------------------------------------------------
1 | uid://0fhypi3gtmud
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector3.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Vector3.svg"
4 |
5 | const SETTING_MIN_COMPONENT_VALUE = "Min Component Value"
6 | const SETTING_MAX_COMPONENT_VALUE = "Max Component Value"
7 | const SETTING_STEPS = "Steps"
8 |
9 | const SETTINGS = {
10 | SETTING_STEPS: {"type": "float", "value": 0.01},
11 | SETTING_MIN_COMPONENT_VALUE: {"type": "int", "value": -9999999999},
12 | SETTING_MAX_COMPONENT_VALUE: {"type": "int", "value": 9999999999}
13 | }
14 |
15 |
16 | func _init() -> void:
17 | super("vector3", SETTINGS, Vector3.ZERO, ICON_PATH)
18 |
19 |
20 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
21 | if variant is String:
22 | var values = variant.trim_prefix("(").trim_suffix(")").split(",", false, 2)
23 | return Vector3(values[0].to_float(), values[1].to_float(), values[2].to_float())
24 | return variant
25 |
26 |
27 | func write_value(variant: Variant) -> Variant:
28 | var vector = variant as Vector3
29 | return "(%s,%s,%s)" % [vector.x, vector.y, vector.z]
30 |
31 |
32 | func is_valid(variant: Variant) -> bool:
33 | return variant is Vector3
34 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector3.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bfot6pj52pnnv
2 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector3i.gd:
--------------------------------------------------------------------------------
1 | extends PandoraPropertyType
2 |
3 | const ICON_PATH = "res://addons/pandora/icons/Vector3i.svg"
4 |
5 | const SETTING_MIN_COMPONENT_VALUE = "Min Component Value"
6 | const SETTING_MAX_COMPONENT_VALUE = "Max Component Value"
7 |
8 | const SETTINGS = {
9 | SETTING_MIN_COMPONENT_VALUE: {"type": "int", "value": -9999999999},
10 | SETTING_MAX_COMPONENT_VALUE: {"type": "int", "value": 9999999999}
11 | }
12 |
13 |
14 | func _init() -> void:
15 | super("vector3i", SETTINGS, Vector3i.ZERO, ICON_PATH)
16 |
17 |
18 | func parse_value(variant: Variant, settings: Dictionary = {}) -> Variant:
19 | if variant is String:
20 | var values = variant.trim_prefix("(").trim_suffix(")").split(",", false, 2)
21 | return Vector3i(values[0].to_int(), values[1].to_int(), values[2].to_int())
22 | return variant
23 |
24 |
25 | func write_value(variant: Variant) -> Variant:
26 | var vector = variant as Vector3i
27 | return "(%s,%s,%s)" % [vector.x, vector.y, vector.z]
28 |
29 |
30 | func is_valid(variant: Variant) -> bool:
31 | return variant is Vector3i
32 |
--------------------------------------------------------------------------------
/addons/pandora/model/types/vector3i.gd.uid:
--------------------------------------------------------------------------------
1 | uid://ckafq5g2cg7dq
2 |
--------------------------------------------------------------------------------
/addons/pandora/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Pandora"
4 | description="📦 Store items, inventories, spells, mobs and more."
5 | author="bitbrain"
6 | version="1.0-alpha10-dev"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/pandora/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 | const PandoraEditor := preload("res://addons/pandora/ui/editor/pandora_editor.tscn")
5 | const PandoraIcon := preload("res://addons/pandora/icons/pandora-icon.svg")
6 | const PandoraEntityInspector = preload("res://addons/pandora/ui/editor/inspector/entity_instance_inspector.gd")
7 | const Compression = preload("res://addons/pandora/util/compression.gd")
8 |
9 | var editor_view
10 | var entity_inspector
11 | var _exporter: PandoraExportPlugin
12 |
13 | func _init() -> void:
14 | self.name = 'PandoraPlugin'
15 |
16 |
17 | func _enter_tree() -> void:
18 | Engine.set_meta("PandoraEditorPlugin", self)
19 | _exporter = PandoraExportPlugin.new()
20 | add_autoload_singleton("Pandora", "res://addons/pandora/api.gd")
21 | add_export_plugin(_exporter)
22 | PandoraSettings.initialize()
23 |
24 | if Engine.is_editor_hint():
25 | editor_view = PandoraEditor.instantiate()
26 | editor_view.hide()
27 | get_editor_interface().get_editor_main_screen().add_child(editor_view)
28 |
29 | # connect signals for error handling
30 | get_editor_interface().get_resource_filesystem().resources_reimported.connect(func(res): if editor_view.has_method("reattempt_load_on_error"): editor_view.reattempt_load_on_error())
31 | get_editor_interface().get_resource_filesystem().sources_changed.connect(func(res): if editor_view.has_method("reattempt_load_on_error"): editor_view.reattempt_load_on_error())
32 | get_editor_interface().get_resource_filesystem().resources_reload.connect(func(exists): if editor_view.has_method("reattempt_load_on_error"): editor_view.reattempt_load_on_error())
33 | get_editor_interface().get_resource_filesystem().script_classes_updated.connect(func(): if editor_view.has_method("reattempt_load_on_error"): editor_view.reattempt_load_on_error())
34 |
35 | entity_inspector = PandoraEntityInspector.new()
36 | add_inspector_plugin(entity_inspector)
37 |
38 | _make_visible(false)
39 |
40 |
41 | func _apply_changes() -> void:
42 | if Engine.is_editor_hint() and is_instance_valid(editor_view):
43 | if editor_view.has_method("apply_changes"):
44 | editor_view.apply_changes()
45 |
46 |
47 | func _exit_tree() -> void:
48 | if Engine.is_editor_hint() and is_instance_valid(editor_view):
49 | remove_control_from_bottom_panel(editor_view)
50 | editor_view.queue_free()
51 | remove_inspector_plugin(entity_inspector)
52 |
53 | Engine.remove_meta("PandoraEditorPlugin")
54 |
55 | remove_export_plugin(_exporter)
56 | remove_autoload_singleton("Pandora")
57 |
58 |
59 | func _make_visible(visible:bool) -> void:
60 | if Engine.is_editor_hint() and is_instance_valid(editor_view):
61 | editor_view.visible = visible
62 |
63 |
64 | func _has_main_screen() -> bool:
65 | return Engine.is_editor_hint()
66 |
67 |
68 | func _get_plugin_name() -> String:
69 | return "Pandora"
70 |
71 |
72 | func _get_plugin_icon() -> Texture2D:
73 | return PandoraIcon
74 |
75 | class PandoraExportPlugin extends EditorExportPlugin:
76 | # Override the _export_begin method to add the data.pandora file during export
77 | func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int):
78 | var pandora_path = "res://data.pandora"
79 | var file = FileAccess.open(pandora_path, FileAccess.READ)
80 | if not file:
81 | printerr("Unable to export Pandora data: ", FileAccess.get_open_error())
82 | return
83 | var data:PackedByteArray = file.get_buffer(file.get_length())
84 | if not is_debug:
85 | var text = file.get_as_text()
86 | data = Compression.compress(text)
87 | add_file(pandora_path, data, false)
88 |
89 | func _get_name() -> String:
90 | return "PandoraExporter"
91 |
--------------------------------------------------------------------------------
/addons/pandora/plugin.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b65tct4x0yii8
2 |
--------------------------------------------------------------------------------
/addons/pandora/settings/pandora_settings.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PandoraSettings
3 | extends RefCounted
4 |
5 | enum IDType {
6 | SEQUENTIAL,
7 | NANOID,
8 | }
9 |
10 | const CATEGORY_MAIN: StringName = "pandora"
11 | const CATEGORY_CONFIG: StringName = CATEGORY_MAIN + "/config"
12 |
13 | const SETTING_ID_TYPE: StringName = CATEGORY_CONFIG + "/id_type"
14 |
15 | const DEFAULT_ID_TYPE: IDType = IDType.SEQUENTIAL
16 |
17 |
18 | static func initialize() -> void:
19 | init_setting(
20 | SETTING_ID_TYPE,
21 | IDType.keys()[DEFAULT_ID_TYPE],
22 | TYPE_STRING,
23 | PROPERTY_HINT_ENUM,
24 | "%s,%s" % IDType.keys()
25 | )
26 |
27 |
28 | static func init_setting(
29 | name: String,
30 | default: Variant,
31 | type := typeof(default),
32 | hint := PROPERTY_HINT_NONE,
33 | hint_string := ""
34 | ) -> void:
35 | if not ProjectSettings.has_setting(name):
36 | ProjectSettings.set_setting(name, default)
37 |
38 | ProjectSettings.set_initial_value(name, default)
39 |
40 | var info = {
41 | "name": name,
42 | "type": type,
43 | "hint": hint,
44 | "hint_string": hint_string,
45 | }
46 | ProjectSettings.add_property_info(info)
47 |
48 |
49 | static func get_id_type() -> IDType:
50 | var default: StringName = IDType.keys()[DEFAULT_ID_TYPE]
51 | var key := ProjectSettings.get_setting(SETTING_ID_TYPE, default)
52 | return IDType[key]
53 |
54 |
55 | static func set_id_type(id_type: IDType) -> void:
56 | ProjectSettings.set_setting(SETTING_ID_TYPE, IDType.keys()[id_type])
57 |
--------------------------------------------------------------------------------
/addons/pandora/settings/pandora_settings.gd.uid:
--------------------------------------------------------------------------------
1 | uid://d2higq0hv04lf
2 |
--------------------------------------------------------------------------------
/addons/pandora/storage/data_storage.gd:
--------------------------------------------------------------------------------
1 | ## Generic definition of a Pandora storage.
2 | ## Provides a generic way to persist and load
3 | ## data required for this addon.
4 | class_name PandoraDataStorage extends RefCounted
5 |
6 | var DEFAULT_ICON = preload("res://addons/pandora/icons/pandora-icon.svg")
7 |
8 |
9 | func get_storage_name() -> String:
10 | return "missing storage name"
11 |
12 |
13 | func get_storage_description() -> String:
14 | return "missing description"
15 |
16 |
17 | func get_storage_icon() -> Texture:
18 | return DEFAULT_ICON
19 |
20 |
21 | func store_all_data(data: Dictionary, context_id: String) -> Dictionary:
22 | return {}
23 |
24 |
25 | func get_all_data(context_id: String) -> Dictionary:
26 | return {}
27 |
28 |
29 | func load_from_file(file_path: String) -> Dictionary:
30 | return {}
31 |
--------------------------------------------------------------------------------
/addons/pandora/storage/data_storage.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cofymmkr5biwu
2 |
--------------------------------------------------------------------------------
/addons/pandora/storage/json/json_data_storage.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PandoraJsonDataStorage extends PandoraDataStorage
3 |
4 | const ICON = preload("res://addons/pandora/icons/pandora-json-icon.svg")
5 |
6 | var data_directory: String = "user://pandora"
7 |
8 |
9 | func get_backend_name() -> String:
10 | return "Pandora JSON"
11 |
12 |
13 | func get_backend_description() -> String:
14 | return "Stores data via json at the data_directory provided."
15 |
16 |
17 | func get_backend_icon() -> Texture:
18 | return ICON
19 |
20 |
21 | func _init(data_dir: String):
22 | data_directory = data_dir
23 |
24 |
25 | func store_all_data(data: Dictionary, context_id: String) -> Dictionary:
26 | var file_path = _get_file_path(context_id)
27 | var file: FileAccess
28 | if _should_use_compression():
29 | file = FileAccess.open_compressed(file_path, FileAccess.WRITE)
30 | file.store_string(JSON.stringify(data))
31 | else:
32 | file = FileAccess.open(file_path, FileAccess.WRITE)
33 | file.store_string(JSON.stringify(data, "\t"))
34 | file.close()
35 | return data
36 |
37 |
38 | func get_all_data(context_id: String) -> Dictionary:
39 | var file_path = _get_file_path(context_id)
40 | var file: FileAccess
41 | if _should_use_compression():
42 | file = FileAccess.open_compressed(file_path, FileAccess.READ)
43 | else:
44 | file = FileAccess.open(file_path, FileAccess.READ)
45 | var json: JSON = JSON.new()
46 | if file != null:
47 | var text = file.get_as_text()
48 | json.parse(text)
49 | file.close()
50 | # Backwards compatibility for already compressed files
51 | if json.get_data() == null and OS.is_debug_build():
52 | print("Compressed file detected in debug mode, decompressing...")
53 | return get_decompressed_data(file_path)
54 | return json.get_data() as Dictionary
55 | else:
56 | return {}
57 |
58 |
59 | func get_decompressed_data(file_path: String) -> Dictionary:
60 | var file: FileAccess = FileAccess.open_compressed(file_path, FileAccess.READ)
61 | if file != null:
62 | var text = file.get_as_text()
63 | file.close()
64 | var json: JSON = JSON.new()
65 | json.parse(text)
66 | return json.get_data() as Dictionary
67 | else:
68 | return {}
69 |
70 |
71 | func load_from_file(file_path: String) -> Dictionary:
72 | var file: FileAccess
73 | if _should_use_compression():
74 | file = FileAccess.open_compressed(file_path, FileAccess.READ)
75 | else:
76 | file = FileAccess.open(file_path, FileAccess.READ)
77 | if FileAccess.file_exists(file_path) and file != null:
78 | var content = file.get_as_text()
79 | file.close()
80 | var json = JSON.new()
81 | json.parse(content)
82 | return json.get_data()
83 | else:
84 | return {}
85 |
86 |
87 | func _get_directory_path(context_id: String) -> String:
88 | var directory_path = ""
89 | if data_directory.ends_with("//"):
90 | directory_path = (
91 | "%s%s" % [data_directory, context_id] if context_id != "" else data_directory
92 | )
93 | else:
94 | directory_path = (
95 | "%s/%s" % [data_directory, context_id] if context_id != "" else data_directory
96 | )
97 | if not DirAccess.dir_exists_absolute(directory_path):
98 | DirAccess.make_dir_recursive_absolute(directory_path)
99 | return "%s" % [directory_path]
100 |
101 |
102 | func _get_file_path(context_id: String) -> String:
103 | return "%s/data.pandora" % [_get_directory_path(context_id)]
104 |
105 |
106 | func _should_use_compression() -> bool:
107 | # Ensure within the Godot Engine editor Pandora remains uncompressed
108 | return not Engine.is_editor_hint() and not OS.is_debug_build()
109 |
--------------------------------------------------------------------------------
/addons/pandora/storage/json/json_data_storage.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bk527fxef7usp
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_editor.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
4 | signal item_added(item: Variant)
5 | signal item_removed(item: Variant)
6 | signal item_updated(idx: int, new_item: Variant)
7 | signal about_to_popup
8 |
9 | @onready var edit_button: Button = $EditArrayButton
10 | @onready var array_info: LineEdit = $ArrayInfo
11 | @onready var array_window: Window = $ArrayWindow
12 |
13 | var _property: PandoraProperty
14 |
15 | func _ready():
16 | _refresh()
17 | edit_button.pressed.connect(func(): array_window.open(_property))
18 | array_window.about_to_popup.connect(func(): about_to_popup.emit())
19 | array_window.item_added.connect(func(item: Variant):
20 | item_added.emit(item)
21 | _refresh.call_deferred()
22 | )
23 | array_window.item_removed.connect(func(item: Variant):
24 | item_removed.emit(item)
25 | _refresh.call_deferred()
26 | )
27 | array_window.item_updated.connect(func(idx: int, item: Variant):
28 | item_updated.emit(idx, item)
29 | _refresh.call_deferred()
30 | )
31 |
32 | func set_property(property: PandoraProperty):
33 | if property.get_original_category_id() != property._id:
34 | var original_category = Pandora.get_category(property.get_original_category_id())
35 | var original_array_property = original_category.get_entity_property(property.get_property_name())
36 | property._setting_overrides = original_array_property._setting_overrides
37 | _property = property
38 | _refresh()
39 |
40 | func _refresh():
41 | if _property:
42 | var value = _property.get_default_value() as Array
43 | array_info.text = str(value.size()) + " Entries"
44 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_editor.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dinmptyyimoey
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_editor.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://cikbl461v071j"]
2 |
3 | [ext_resource type="Script" uid="uid://dinmptyyimoey" path="res://addons/pandora/ui/components/array_editor/array_editor.gd" id="1_yrssj"]
4 | [ext_resource type="Texture2D" uid="uid://b0mt8ysdc5m4a" path="res://addons/pandora/icons/Edit.svg" id="2_rmn70"]
5 | [ext_resource type="Script" uid="uid://b83eebnfe6lis" path="res://addons/pandora/ui/components/array_editor/array_window.gd" id="3_evj6f"]
6 | [ext_resource type="PackedScene" uid="uid://d15ldap7ubifc" path="res://addons/pandora/ui/components/array_editor/array_manager.tscn" id="4_5yyg5"]
7 |
8 | [node name="ArrayEditor" type="HBoxContainer"]
9 | size_flags_horizontal = 3
10 | size_flags_vertical = 3
11 | script = ExtResource("1_yrssj")
12 |
13 | [node name="ArrayInfo" type="LineEdit" parent="."]
14 | layout_mode = 2
15 | size_flags_horizontal = 3
16 | text = "0 Entries"
17 | editable = false
18 | context_menu_enabled = false
19 | virtual_keyboard_enabled = false
20 | shortcut_keys_enabled = false
21 | selecting_enabled = false
22 | flat = true
23 |
24 | [node name="EditArrayButton" type="Button" parent="."]
25 | layout_mode = 2
26 | icon = ExtResource("2_rmn70")
27 |
28 | [node name="ArrayWindow" type="Window" parent="."]
29 | disable_3d = true
30 | title = "Array Manager"
31 | initial_position = 2
32 | size = Vector2i(134, 100)
33 | visible = false
34 | wrap_controls = true
35 | content_scale_mode = 1
36 | content_scale_aspect = 4
37 | script = ExtResource("3_evj6f")
38 |
39 | [node name="ArrayManager" parent="ArrayWindow" instance=ExtResource("4_5yyg5")]
40 |
41 | [connection signal="close_requested" from="ArrayWindow" to="ArrayWindow" method="_on_close_requested"]
42 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_item.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PanelContainer
3 |
4 | signal item_removal_requested
5 |
6 | var _property: PandoraProperty
7 | var _control: PandoraPropertyControl:
8 | set(c):
9 | _control = c
10 | _refresh_value.call_deferred()
11 | var _backend: PandoraEntityBackend
12 |
13 | @onready var item_value: MarginContainer = %ItemValue
14 | @onready var delete_item_button: Button = %DeleteItemButton
15 | @onready var confirmation_dialog: ConfirmationDialog = %ConfirmationDialog
16 |
17 |
18 | func init(
19 | property: PandoraProperty, control: PandoraPropertyControl, backend: PandoraEntityBackend
20 | ) -> void:
21 | if self._control != null:
22 | _control.queue_free()
23 | self._property = property
24 | self._control = control
25 | self._backend = backend
26 |
27 |
28 | func _ready():
29 | delete_item_button.pressed.connect(func(): confirmation_dialog.popup())
30 | confirmation_dialog.confirmed.connect(_delete_item)
31 | _refresh.call_deferred()
32 | if _control != null:
33 | _control.property_value_changed.connect(_refresh)
34 |
35 |
36 | func _refresh_value() -> void:
37 | for child in item_value.get_children():
38 | child.queue_free()
39 | item_value.get_children().clear()
40 | item_value.add_child(_control)
41 |
42 |
43 | func _refresh(_value: Variant = null):
44 | if _control == null or _property == null:
45 | return
46 | _control.refresh()
47 |
48 |
49 | func _delete_item():
50 | item_removal_requested.emit()
51 | queue_free()
52 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_item.gd.uid:
--------------------------------------------------------------------------------
1 | uid://csaisqucgg6bx
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_item.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://crcu03fp7fkyd"]
2 |
3 | [ext_resource type="Script" uid="uid://csaisqucgg6bx" path="res://addons/pandora/ui/components/array_editor/array_item.gd" id="1_3q6kl"]
4 | [ext_resource type="Texture2D" uid="uid://b2s1ixfakdj1e" path="res://addons/pandora/icons/Remove.svg" id="2_rgeed"]
5 |
6 | [node name="ArrayItem" type="PanelContainer"]
7 | size_flags_horizontal = 3
8 | size_flags_vertical = 3
9 | script = ExtResource("1_3q6kl")
10 |
11 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
12 | layout_mode = 2
13 |
14 | [node name="ItemValue" type="MarginContainer" parent="HBoxContainer"]
15 | unique_name_in_owner = true
16 | layout_mode = 2
17 | size_flags_horizontal = 3
18 |
19 | [node name="DeleteItemButton" type="Button" parent="HBoxContainer"]
20 | unique_name_in_owner = true
21 | layout_mode = 2
22 | icon = ExtResource("2_rgeed")
23 |
24 | [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
25 | unique_name_in_owner = true
26 | initial_position = 2
27 | size = Vector2i(400, 200)
28 | dialog_text = "Are you sure you want to remove this item?"
29 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_manager.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PanelContainer
3 |
4 | const ArrayType = preload("res://addons/pandora/model/types/array.gd")
5 | const ArrayItem = preload("res://addons/pandora/ui/components/array_editor/array_item.tscn")
6 | const PropertyBarScene = "res://addons/pandora/ui/components/property_bar/property_bar.tscn"
7 |
8 | signal item_added(item: Variant)
9 | signal item_removed(item: Variant)
10 | signal item_updated(idx: int, new_item: Variant)
11 | signal close_requested
12 |
13 | @onready var close_button: Button = %CloseButton
14 | @onready var new_item_button: Button = %NewItemButton
15 | @onready var items_container: VBoxContainer = %ArrayItems
16 | @onready var main_container: VBoxContainer = %MainContainer
17 | var property_bar: Node
18 |
19 | var _items: Array
20 | var _property: PandoraProperty
21 |
22 |
23 | func _ready():
24 | close_button.pressed.connect(func(): close_requested.emit())
25 | new_item_button.pressed.connect(_add_new_item)
26 |
27 |
28 | func open(property: PandoraProperty):
29 | _property = property
30 | var property_bar_scene = load(PropertyBarScene)
31 | property_bar = property_bar_scene.instantiate()
32 | property_bar._ready()
33 | _load_items.call_deferred()
34 |
35 |
36 | func close():
37 | _remove_empty_items()
38 | _clear()
39 | property_bar.queue_free()
40 |
41 |
42 | func is_empty(item: Variant):
43 | var array_type = _property.get_setting(ArrayType.SETTING_ARRAY_TYPE)
44 | if array_type == "reference":
45 | return item == null
46 | if array_type == "resource":
47 | return is_instance_valid(item) == false
48 | elif array_type == "string":
49 | return item == ""
50 | else:
51 | return false
52 |
53 |
54 | func _remove_empty_items():
55 | for index in range(_items.size()):
56 | if is_empty(_items[index]):
57 | _items.erase(index)
58 | item_removed.emit(_items[index])
59 |
60 |
61 | func _clear():
62 | _items.clear()
63 | for child in items_container.get_children():
64 | child.queue_free()
65 | items_container.get_children().clear()
66 |
67 |
68 | func _load_items():
69 | _clear()
70 | _items = _property.get_default_value().duplicate()
71 | var array_type = _property.get_setting(ArrayType.SETTING_ARRAY_TYPE)
72 | for i in range(_items.size()):
73 | var control = (
74 | property_bar.get_scene_by_type(array_type).instantiate() as PandoraPropertyControl
75 | )
76 | var item_property = PandoraProperty.new("", "array_item", array_type)
77 | item_property._setting_overrides = _property._setting_overrides
78 | var value = _items[i]
79 | if array_type == "resource":
80 | value = load(value)
81 | elif array_type == "reference":
82 | if value is Dictionary:
83 | value = Pandora.get_entity(value["_entity_id"])
84 | elif value is PandoraReference:
85 | value = value.get_entity()
86 | item_property.set_default_value(value)
87 | _add_property_control(control, item_property, i)
88 |
89 |
90 | func _add_new_item():
91 | var array_type = _property.get_setting(ArrayType.SETTING_ARRAY_TYPE)
92 | var scene = property_bar.get_scene_by_type(array_type)
93 | var control = scene.instantiate() as PandoraPropertyControl
94 | var item_property = PandoraProperty.new(
95 | "", "array_item", _property.get_setting(ArrayType.SETTING_ARRAY_TYPE)
96 | )
97 | item_property._setting_overrides = _property._setting_overrides
98 | _items.append(item_property.get_default_value())
99 | _add_property_control(control, item_property, _items.size() - 1)
100 | item_added.emit(_items[_items.size() - 1])
101 |
102 |
103 | func _add_property_control(
104 | control: PandoraPropertyControl, item_property: PandoraProperty, idx: int
105 | ):
106 | var item = ArrayItem.instantiate()
107 |
108 | control.init(item_property)
109 |
110 | control.property_value_changed.connect(func(value: Variant): item_updated.emit(idx, value))
111 |
112 | item.item_removal_requested.connect(
113 | func(): item_removed.emit(control._property.get_default_value())
114 | )
115 | item.init(_property, control, Pandora._entity_backend)
116 | items_container.add_child(item)
117 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_manager.gd.uid:
--------------------------------------------------------------------------------
1 | uid://db4alrrhmduii
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_manager.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://d15ldap7ubifc"]
2 |
3 | [ext_resource type="Script" uid="uid://db4alrrhmduii" path="res://addons/pandora/ui/components/array_editor/array_manager.gd" id="1_f23k5"]
4 |
5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1xsek"]
6 |
7 | [node name="ArrayManager" type="PanelContainer"]
8 | self_modulate = Color(0, 0, 0, 1)
9 | anchors_preset = 15
10 | anchor_right = 1.0
11 | anchor_bottom = 1.0
12 | grow_horizontal = 2
13 | grow_vertical = 2
14 | theme_override_styles/panel = SubResource("StyleBoxFlat_1xsek")
15 | script = ExtResource("1_f23k5")
16 |
17 | [node name="MarginContainer" type="MarginContainer" parent="."]
18 | layout_mode = 2
19 | theme_override_constants/margin_left = 10
20 | theme_override_constants/margin_top = 10
21 | theme_override_constants/margin_right = 10
22 | theme_override_constants/margin_bottom = 10
23 |
24 | [node name="MainContainer" type="VBoxContainer" parent="MarginContainer"]
25 | unique_name_in_owner = true
26 | layout_mode = 2
27 |
28 | [node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/MainContainer"]
29 | layout_mode = 2
30 | size_flags_vertical = 3
31 |
32 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/MainContainer/ScrollContainer"]
33 | layout_mode = 2
34 | size_flags_horizontal = 3
35 | size_flags_vertical = 3
36 |
37 | [node name="HeaderContainer" type="MarginContainer" parent="MarginContainer/MainContainer/ScrollContainer/VBoxContainer"]
38 | layout_mode = 2
39 | size_flags_horizontal = 8
40 | theme_override_constants/margin_bottom = 10
41 |
42 | [node name="NewItemButton" type="Button" parent="MarginContainer/MainContainer/ScrollContainer/VBoxContainer/HeaderContainer"]
43 | unique_name_in_owner = true
44 | layout_mode = 2
45 | text = "Add New Item +"
46 |
47 | [node name="ArrayItems" type="VBoxContainer" parent="MarginContainer/MainContainer/ScrollContainer/VBoxContainer"]
48 | unique_name_in_owner = true
49 | layout_mode = 2
50 |
51 | [node name="CenterContainer" type="CenterContainer" parent="MarginContainer/MainContainer"]
52 | layout_mode = 2
53 |
54 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MainContainer/CenterContainer"]
55 | layout_mode = 2
56 | theme_override_constants/separation = 20
57 |
58 | [node name="CloseButton" type="Button" parent="MarginContainer/MainContainer/CenterContainer/HBoxContainer"]
59 | unique_name_in_owner = true
60 | layout_mode = 2
61 | text = "Close"
62 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_window.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Window
3 |
4 | signal item_added(item: Variant)
5 | signal item_removed(item: Variant)
6 | signal item_updated(idx: int, new_item: Variant)
7 |
8 | @onready var array_manager = $ArrayManager
9 |
10 |
11 | func _ready():
12 | if owner.get_parent() is SubViewport:
13 | return
14 | array_manager.close_requested.connect(_on_close_requested)
15 | array_manager.item_added.connect(func(item: Variant): item_added.emit(item))
16 | array_manager.item_removed.connect(func(item: Variant): item_removed.emit(item))
17 | array_manager.item_updated.connect(func(idx: int, item: Variant): item_updated.emit(idx, item))
18 |
19 |
20 | func open(property: PandoraProperty):
21 | popup_centered_clamped(Vector2i(800, 1000), 0.5)
22 | move_to_foreground()
23 | grab_focus()
24 | array_manager.open(property)
25 |
26 |
27 | func _on_close_requested():
28 | hide()
29 | array_manager.close()
30 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/array_editor/array_window.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b83eebnfe6lis
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/color_picker/color_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends MarginContainer
3 |
4 | @onready var color_picker_button: ColorPickerButton = $ColorPickerButton
5 |
6 | signal color_selected(color: Color)
7 |
8 |
9 | func _ready():
10 | color_picker_button.color_changed.connect(func(color): color_selected.emit(color))
11 |
12 |
13 | func set_color(color: Color) -> void:
14 | color_picker_button.color = color
15 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/color_picker/color_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://wnr5jjkir4j2
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/color_picker/color_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cex30s5jawlql"]
2 |
3 | [ext_resource type="Script" uid="uid://wnr5jjkir4j2" path="res://addons/pandora/ui/components/color_picker/color_picker.gd" id="1_eeppq"]
4 |
5 | [node name="ColorPicker" type="MarginContainer"]
6 | offset_right = 8.0
7 | offset_bottom = 55.0
8 | size_flags_horizontal = 3
9 | size_flags_vertical = 3
10 | script = ExtResource("1_eeppq")
11 |
12 | [node name="ColorPickerButton" type="ColorPickerButton" parent="."]
13 | layout_mode = 2
14 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_attributes/entity_attributes.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends VBoxContainer
3 |
4 | @onready var texture_picker = %TexturePicker
5 | @onready var script_picker = %ScriptPicker
6 | @onready var id_generation_enabled = %IdGenerationEnabled
7 | @onready var class_name_edit = %ClassNameEdit
8 | @onready var color_picker = %ColorPicker
9 |
10 | @onready var script_attribute = $ScriptAttribute
11 | @onready var h_separator_2 = $HSeparator2
12 | @onready var id_generation_attribute = $IdGenerationAttribute
13 | @onready var id_class_name_attribute = %IdClassNameAttribute
14 |
15 | var _entity: PandoraEntity
16 |
17 |
18 | func init(entity: PandoraEntity) -> void:
19 | self._entity = entity
20 | texture_picker.set_texture_path(entity.get_icon_path())
21 | script_picker.set_script_path(entity.get_script_path())
22 | color_picker.set_color(entity.get_icon_color())
23 | # ensure selected script extends PandoraEntity!
24 | script_picker.set_filter(_is_entity)
25 | class_name_edit.text = entity.get_id_generation_class()
26 | id_generation_enabled.button_pressed = entity._generate_ids
27 | class_name_edit.editable = entity._generate_ids
28 |
29 | # only show script & id generation on categories
30 | script_attribute.visible = entity is PandoraCategory
31 | h_separator_2.visible = entity is PandoraCategory
32 | id_generation_attribute.visible = entity is PandoraCategory
33 | id_class_name_attribute.visible = entity is PandoraCategory
34 |
35 |
36 | func _ready() -> void:
37 | texture_picker.texture_changed.connect(_set_icon_path)
38 | script_picker.script_path_changed.connect(_set_script_path)
39 | id_generation_enabled.toggled.connect(_set_id_generation)
40 | class_name_edit.text_changed.connect(_set_class_name)
41 | color_picker.color_selected.connect(_set_icon_color)
42 |
43 |
44 | func _set_icon_path(path: String) -> void:
45 | _entity.set_icon_path(path)
46 |
47 |
48 | func _set_icon_color(color: Color) -> void:
49 | _entity.set_icon_color(color)
50 |
51 |
52 | func _set_script_path(path: String) -> void:
53 | _entity.set_script_path(path)
54 |
55 |
56 | func _set_id_generation(toggled: bool) -> void:
57 | _entity.set_generate_ids(toggled)
58 | class_name_edit.editable = toggled
59 |
60 |
61 | func _set_class_name(name: String) -> void:
62 | _entity.set_id_generation_class(name.to_pascal_case())
63 |
64 |
65 | func _is_entity(path: String) -> bool:
66 | var EntityClass = load(path)
67 | if not EntityClass:
68 | return false
69 | var entity = EntityClass.new("", "", "", "")
70 | return (entity as PandoraEntity) != null
71 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_attributes/entity_attributes.gd.uid:
--------------------------------------------------------------------------------
1 | uid://d3wqprwajfpi3
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_attributes/entity_attributes.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://ceqq28yvnhs2e"]
2 |
3 | [ext_resource type="Script" uid="uid://d3wqprwajfpi3" path="res://addons/pandora/ui/components/entity_attributes/entity_attributes.gd" id="1_hnn1r"]
4 | [ext_resource type="PackedScene" uid="uid://dvoxop0o2mlfi" path="res://addons/pandora/ui/components/texture_picker/texture_picker.tscn" id="2_tv6yu"]
5 | [ext_resource type="PackedScene" uid="uid://bp0gaqyb10bns" path="res://addons/pandora/ui/components/script_picker/script_picker.tscn" id="3_e2peg"]
6 | [ext_resource type="PackedScene" uid="uid://cex30s5jawlql" path="res://addons/pandora/ui/components/color_picker/color_picker.tscn" id="3_o3ybf"]
7 |
8 | [node name="EntityAttributes" type="VBoxContainer"]
9 | anchors_preset = 15
10 | anchor_right = 1.0
11 | anchor_bottom = 1.0
12 | grow_horizontal = 2
13 | grow_vertical = 2
14 | size_flags_horizontal = 3
15 | size_flags_vertical = 3
16 | script = ExtResource("1_hnn1r")
17 |
18 | [node name="HSeparator" type="HSeparator" parent="."]
19 | layout_mode = 2
20 | theme_override_constants/separation = 20
21 |
22 | [node name="IconAttribute" type="HBoxContainer" parent="."]
23 | layout_mode = 2
24 |
25 | [node name="IconLabel" type="Label" parent="IconAttribute"]
26 | layout_mode = 2
27 | size_flags_horizontal = 3
28 | text = "Icon"
29 |
30 | [node name="TexturePicker" parent="IconAttribute" instance=ExtResource("2_tv6yu")]
31 | unique_name_in_owner = true
32 | layout_mode = 2
33 |
34 | [node name="ColorAttribute" type="HBoxContainer" parent="."]
35 | layout_mode = 2
36 |
37 | [node name="ColorLabel" type="Label" parent="ColorAttribute"]
38 | layout_mode = 2
39 | size_flags_horizontal = 3
40 | text = "Color"
41 |
42 | [node name="ColorPicker" parent="ColorAttribute" instance=ExtResource("3_o3ybf")]
43 | unique_name_in_owner = true
44 | layout_mode = 2
45 |
46 | [node name="ScriptAttribute" type="HBoxContainer" parent="."]
47 | layout_mode = 2
48 |
49 | [node name="Label" type="Label" parent="ScriptAttribute"]
50 | layout_mode = 2
51 | size_flags_horizontal = 3
52 | text = "Script"
53 |
54 | [node name="ScriptPicker" parent="ScriptAttribute" instance=ExtResource("3_e2peg")]
55 | unique_name_in_owner = true
56 | layout_mode = 2
57 |
58 | [node name="HSeparator2" type="HSeparator" parent="."]
59 | layout_mode = 2
60 | theme_override_constants/separation = 20
61 |
62 | [node name="IdGenerationAttribute" type="HBoxContainer" parent="."]
63 | layout_mode = 2
64 |
65 | [node name="Label" type="Label" parent="IdGenerationAttribute"]
66 | layout_mode = 2
67 | size_flags_horizontal = 3
68 | text = "Generate ID Class"
69 |
70 | [node name="IdGenerationEnabled" type="CheckButton" parent="IdGenerationAttribute"]
71 | unique_name_in_owner = true
72 | layout_mode = 2
73 |
74 | [node name="IdClassNameAttribute" type="HBoxContainer" parent="."]
75 | unique_name_in_owner = true
76 | layout_mode = 2
77 |
78 | [node name="IdClassNameLabel" type="Label" parent="IdClassNameAttribute"]
79 | layout_mode = 2
80 | size_flags_horizontal = 3
81 | text = "ID Class Name"
82 |
83 | [node name="ClassNameEdit" type="LineEdit" parent="IdClassNameAttribute"]
84 | unique_name_in_owner = true
85 | layout_mode = 2
86 | size_flags_horizontal = 3
87 | placeholder_text = "SomeClassName"
88 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_picker/entity_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
4 | signal entity_selected(entity: PandoraEntity)
5 |
6 | @onready var option_button = $OptionButton
7 |
8 | var hint_string: String
9 | var categories_only: bool:
10 | set(v):
11 | var old_value = categories_only
12 | categories_only = v
13 | if old_value != categories_only:
14 | _invalidate.call_deferred()
15 |
16 | var _ids_to_entities = {}
17 | var _entity_ids_to_ids = {}
18 | var _entities: Array[PandoraEntity]
19 | var _category_id_filter: String:
20 | set(v):
21 | var old_value = _category_id_filter
22 | _category_id_filter = v
23 | if old_value != _category_id_filter:
24 | _invalidate.call_deferred()
25 | var _sort: Callable = func(a, b): return false
26 |
27 |
28 | func _ready() -> void:
29 | option_button.get_popup().id_pressed.connect(_on_id_selected)
30 | _invalidate()
31 |
32 |
33 | func set_sort(sort: Callable) -> void:
34 | self._sort = sort
35 | _invalidate()
36 |
37 |
38 | func set_filter(category_id: String) -> void:
39 | self._category_id_filter = category_id
40 | _invalidate()
41 |
42 |
43 | func set_data(entities: Array[PandoraEntity]) -> void:
44 | self._entities = entities
45 | _ids_to_entities.clear()
46 | _entity_ids_to_ids.clear()
47 | var id_counter = 0
48 | option_button.get_popup().clear()
49 | for entity in _entities:
50 | option_button.get_popup().add_icon_item(
51 | load(entity.get_icon_path()), entity.get_entity_name(), id_counter
52 | )
53 |
54 | var editor_plugin: EditorPlugin = (
55 | Engine.get_meta("PandoraEditorPlugin")
56 | if Engine.has_meta("PandoraEditorPlugin")
57 | else null
58 | )
59 | if editor_plugin:
60 | option_button.get_popup().set_item_icon_max_width(
61 | id_counter, editor_plugin.get_editor_interface().get_editor_scale() * 16
62 | )
63 | # Godot 4.1+
64 | if option_button.get_popup().has_method("set_item_icon_modulate"):
65 | option_button.get_popup().set_item_icon_modulate(id_counter, entity.get_icon_color())
66 | _ids_to_entities[id_counter] = entity
67 | _entity_ids_to_ids[entity.get_entity_id()] = id_counter
68 | id_counter += 1
69 |
70 |
71 | func select(entity: PandoraEntity) -> void:
72 | var id = _entity_ids_to_ids[entity.get_entity_id()]
73 | option_button.select(id)
74 | option_button.modulate = entity.get_icon_color()
75 |
76 |
77 | func _on_id_selected(id: int) -> void:
78 | entity_selected.emit(_ids_to_entities[id])
79 |
80 |
81 | func _invalidate() -> void:
82 | var filter = Pandora.get_category(_category_id_filter) if _category_id_filter else null
83 | if categories_only:
84 | set_data(Pandora.get_all_categories(filter, _sort))
85 | else:
86 | set_data(Pandora.get_all_entities(filter, _sort))
87 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_picker/entity_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://tv7m68jxrun4
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_picker/entity_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://bfhqt0xa4a2fh"]
2 |
3 | [ext_resource type="Script" uid="uid://tv7m68jxrun4" path="res://addons/pandora/ui/components/entity_picker/entity_picker.gd" id="1_cjsnj"]
4 |
5 | [node name="EntityPicker" type="HBoxContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_cjsnj")
12 |
13 | [node name="OptionButton" type="OptionButton" parent="."]
14 | layout_mode = 2
15 | size_flags_horizontal = 3
16 | size_flags_vertical = 1
17 | expand_icon = true
18 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_tree/entity_tree.gd.uid:
--------------------------------------------------------------------------------
1 | uid://nrk4g58k31is
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/entity_tree/entity_tree.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://ctmsh7eg6wypu"]
2 |
3 | [ext_resource type="Script" uid="uid://nrk4g58k31is" path="res://addons/pandora/ui/components/entity_tree/entity_tree.gd" id="1_0uafu"]
4 | [ext_resource type="PackedScene" uid="uid://piqbfrsn5bi1" path="res://addons/pandora/ui/components/loading_spinner/LoadingSpinner.tscn" id="2_dokdi"]
5 |
6 | [node name="EntityTree" type="Tree"]
7 | anchors_preset = 15
8 | anchor_right = 1.0
9 | anchor_bottom = 1.0
10 | grow_horizontal = 2
11 | grow_vertical = 2
12 | focus_mode = 1
13 | mouse_filter = 1
14 | hide_root = true
15 | script = ExtResource("1_0uafu")
16 |
17 | [node name="LoadingSpinner" parent="." instance=ExtResource("2_dokdi")]
18 | layout_mode = 1
19 |
20 | [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
21 | initial_position = 2
22 | size = Vector2i(303, 80)
23 | dialog_text = "Are you sure you want to delete '%s'?"
24 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/loading_spinner/LoadingSpinner.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://piqbfrsn5bi1"]
2 |
3 | [ext_resource type="Script" uid="uid://pdchat0hnc06" path="res://addons/pandora/ui/components/loading_spinner/loading_spinner.gd" id="1_waqf6"]
4 | [ext_resource type="Texture2D" uid="uid://dmh7pik8vjog8" path="res://addons/pandora/icons/pandora-icon.svg" id="2_0ad3g"]
5 |
6 | [node name="LoadingSpinner" type="CenterContainer"]
7 | anchors_preset = 15
8 | anchor_right = 1.0
9 | anchor_bottom = 1.0
10 | grow_horizontal = 2
11 | grow_vertical = 2
12 | script = ExtResource("1_waqf6")
13 |
14 | [node name="Control" type="Control" parent="."]
15 | custom_minimum_size = Vector2(64, 64)
16 | layout_mode = 2
17 |
18 | [node name="RotationSprite" type="Sprite2D" parent="Control"]
19 | position = Vector2(32, 32)
20 | rotation = -6.27916
21 | scale = Vector2(2, 2)
22 | texture = ExtResource("2_0ad3g")
23 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/loading_spinner/loading_spinner.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends CenterContainer
3 |
4 | @onready var rotation_sprite = $Control/RotationSprite
5 |
6 |
7 | func _ready() -> void:
8 | _tween()
9 |
10 |
11 | func _tween() -> void:
12 | var tween = create_tween()
13 | rotation_sprite.rotation_degrees = -360
14 | (
15 | tween
16 | . tween_property(rotation_sprite, "rotation_degrees", 360, 1.5)
17 | . set_ease(Tween.EASE_IN_OUT)
18 | . set_trans(Tween.TRANS_CUBIC)
19 | . finished
20 | . connect(_tween)
21 | )
22 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/loading_spinner/loading_spinner.gd.uid:
--------------------------------------------------------------------------------
1 | uid://pdchat0hnc06
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/notification_label/notification_label.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Label
3 |
4 | var tween: Tween
5 |
6 |
7 | func _ready() -> void:
8 | self_modulate.a = 0.0
9 |
10 |
11 | func popup() -> void:
12 | visible = true
13 | if tween and tween.is_running():
14 | tween.stop()
15 | self_modulate.a = 1.0
16 | tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CUBIC)
17 | tween.finished.connect(func(): visible = false)
18 | tween.tween_property(self, "self_modulate:a", 0.0, 1.5).set_delay(2.0)
19 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/notification_label/notification_label.gd.uid:
--------------------------------------------------------------------------------
1 | uid://busm38g2lymg4
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/notification_label/notification_label.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://dsqfuyjkcdwvu"]
2 |
3 | [ext_resource type="Script" uid="uid://busm38g2lymg4" path="res://addons/pandora/ui/components/notification_label/notification_label.gd" id="1_vp8r6"]
4 |
5 | [sub_resource type="LabelSettings" id="LabelSettings_ue3du"]
6 | line_spacing = 0.0
7 | font_color = Color(0.537255, 0.952941, 0, 1)
8 | outline_size = 2
9 | outline_color = Color(0, 0.866667, 0.541176, 1)
10 | shadow_size = 10
11 | shadow_color = Color(0, 0.627451, 0.772549, 0.14902)
12 | shadow_offset = Vector2(0, 0)
13 |
14 | [node name="SaveLabel" type="Label"]
15 | self_modulate = Color(1, 1, 1, 0)
16 | theme_override_colors/font_color = Color(0.564706, 0.92549, 0, 1)
17 | text = "Data saved!"
18 | label_settings = SubResource("LabelSettings_ue3du")
19 | script = ExtResource("1_vp8r6")
20 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/progress_bar/progress_bar.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name ImportProgressBar
3 | extends MarginContainer
4 |
5 | @onready var progress_bar = $ProgressBar
6 |
7 | var total_steps: int = 100
8 |
9 |
10 | # Called when the node enters the scene tree for the first time.
11 | func _ready():
12 | visible = false
13 |
14 |
15 | func init(total_steps: int):
16 | total_steps = total_steps
17 | progress_bar.step = progress_bar.max_value / total_steps
18 | visible = true
19 |
20 |
21 | func advance():
22 | progress_bar.value += progress_bar.step
23 |
24 |
25 | func finish():
26 | total_steps = 100
27 | progress_bar.step = 0.01
28 | visible = false
29 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/progress_bar/progress_bar.gd.uid:
--------------------------------------------------------------------------------
1 | uid://sjpp7qx4vbjd
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/progress_bar/progress_bar.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://dibfkp6i5uvgi"]
2 |
3 | [ext_resource type="Script" uid="uid://sjpp7qx4vbjd" path="res://addons/pandora/ui/components/progress_bar/progress_bar.gd" id="1_ifnan"]
4 |
5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uy0ts"]
6 | bg_color = Color(0.278431, 0.701961, 0.360784, 1)
7 |
8 | [node name="ProgressContainer" type="MarginContainer"]
9 | visible = false
10 | offset_right = 100.0
11 | offset_bottom = 37.0
12 | theme_override_constants/margin_left = 5
13 | theme_override_constants/margin_top = 5
14 | theme_override_constants/margin_right = 5
15 | theme_override_constants/margin_bottom = 5
16 | script = ExtResource("1_ifnan")
17 |
18 | [node name="ProgressBar" type="ProgressBar" parent="."]
19 | layout_mode = 2
20 | theme_override_styles/fill = SubResource("StyleBoxFlat_uy0ts")
21 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/array/array_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 | const ArrayType = preload("res://addons/pandora/model/types/array.gd")
5 |
6 | @onready var array_editor = $ArrayEditor
7 | var _items: Array = []
8 |
9 |
10 | func _ready() -> void:
11 | refresh()
12 | _property.setting_changed.connect(_setting_changed)
13 | array_editor.item_added.connect(_on_item_added)
14 | array_editor.item_removed.connect(_on_item_removed)
15 | array_editor.item_updated.connect(_on_item_updated)
16 |
17 |
18 | func refresh() -> void:
19 | if _property != null:
20 | array_editor.set_property(_property)
21 | _items = _property.get_default_value().duplicate()
22 |
23 |
24 | func _on_item_added(item: Variant):
25 | _items.append(item)
26 | save_array()
27 |
28 |
29 | func _on_item_updated(idx: int, item: Variant):
30 | if range(_items.size()).has(idx):
31 | _items[idx] = item
32 | save_array()
33 | else:
34 | _on_item_added(item)
35 |
36 |
37 | func _on_item_removed(item: Variant):
38 | _items.erase(item)
39 | save_array()
40 |
41 |
42 | func save_array():
43 | _property.set_default_value(_items)
44 | property_value_changed.emit(_items)
45 |
46 |
47 | func _setting_changed(key: String):
48 | if key == ArrayType.SETTING_ARRAY_TYPE:
49 | _items.clear()
50 | save_array()
51 | refresh()
52 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/array/array_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://btmowi7f4ffar
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/array/array_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://ckdfcxfes51ia"]
2 |
3 | [ext_resource type="Script" uid="uid://btmowi7f4ffar" path="res://addons/pandora/ui/components/properties/array/array_property.gd" id="1_ku3y1"]
4 | [ext_resource type="PackedScene" uid="uid://cikbl461v071j" path="res://addons/pandora/ui/components/array_editor/array_editor.tscn" id="2_j8x1r"]
5 |
6 | [node name="ArrayProperty" type="MarginContainer"]
7 | script = ExtResource("1_ku3y1")
8 | type = "array"
9 |
10 | [node name="ArrayEditor" parent="." instance=ExtResource("2_j8x1r")]
11 | layout_mode = 2
12 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/bool/bool_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | @onready var check_button: CheckButton = $CheckButton
6 |
7 |
8 | func _ready() -> void:
9 | refresh()
10 | check_button.focus_exited.connect(func(): unfocused.emit())
11 | check_button.focus_entered.connect(func(): focused.emit())
12 | check_button.toggled.connect(
13 | func(toggled:bool):
14 | _property.set_default_value(toggled)
15 | property_value_changed.emit(toggled))
16 |
17 |
18 | func refresh() -> void:
19 | check_button.set_pressed(_property.get_default_value() as bool)
20 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/bool/bool_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://yfs0hurvmhd1
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/bool/bool_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://brp6oodbm37gk"]
2 |
3 | [ext_resource type="Script" uid="uid://yfs0hurvmhd1" path="res://addons/pandora/ui/components/properties/bool/bool_property.gd" id="1_aee5b"]
4 |
5 | [node name="BoolProperty" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | size_flags_horizontal = 3
12 | size_flags_vertical = 3
13 | script = ExtResource("1_aee5b")
14 | type = "bool"
15 |
16 | [node name="CheckButton" type="CheckButton" parent="."]
17 | layout_mode = 2
18 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/color/color_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | @onready var color_picker_button: ColorPickerButton = $ColorPickerButton
6 |
7 |
8 | func _ready() -> void:
9 | refresh()
10 | color_picker_button.focus_exited.connect(func(): unfocused.emit())
11 | color_picker_button.focus_entered.connect(func(): focused.emit())
12 | color_picker_button.color_changed.connect(
13 | func(color:Color):
14 | _property.set_default_value(color)
15 | property_value_changed.emit(color))
16 |
17 |
18 | func refresh() -> void:
19 | color_picker_button.color = _property.get_default_value() as Color
20 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/color/color_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cjpnsuvvhqlfc
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/color/color_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://chj1ateikyk5"]
2 |
3 | [ext_resource type="Script" uid="uid://cjpnsuvvhqlfc" path="res://addons/pandora/ui/components/properties/color/color_property.gd" id="1_tgtmt"]
4 |
5 | [node name="ColorProperty" type="MarginContainer"]
6 | offset_right = 8.0
7 | offset_bottom = 8.0
8 | size_flags_horizontal = 3
9 | size_flags_vertical = 3
10 | theme_override_constants/margin_left = 0
11 | theme_override_constants/margin_top = 0
12 | theme_override_constants/margin_right = 0
13 | theme_override_constants/margin_bottom = 0
14 | script = ExtResource("1_tgtmt")
15 | type = "color"
16 |
17 | [node name="ColorPickerButton" type="ColorPickerButton" parent="."]
18 | custom_minimum_size = Vector2(0, 55)
19 | layout_mode = 2
20 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/float/float_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | const FloatType = preload("res://addons/pandora/model/types/float.gd")
6 |
7 |
8 | @onready var spin_box: SpinBox = $SpinBox
9 |
10 |
11 | func _ready() -> void:
12 | if _property != null:
13 | _property.setting_changed.connect(_setting_changed)
14 | _property.setting_cleared.connect(_setting_changed)
15 | refresh()
16 | spin_box.focus_exited.connect(func(): unfocused.emit())
17 | spin_box.focus_entered.connect(func(): focused.emit())
18 | spin_box.value_changed.connect(
19 | func(value:float):
20 | _property.set_default_value(value)
21 | property_value_changed.emit(value))
22 |
23 |
24 | func refresh() -> void:
25 | spin_box.rounded = false
26 | spin_box.value = _property.get_default_value() as float
27 | spin_box.min_value = _property.get_setting(FloatType.SETTING_MIN_VALUE) as int
28 | spin_box.max_value = _property.get_setting(FloatType.SETTING_MAX_VALUE) as int
29 | spin_box.step = _property.get_setting(FloatType.SETTING_STEPS) as float
30 |
31 |
32 | func _setting_changed(key:String) -> void:
33 | if key == FloatType.SETTING_MIN_VALUE || key == FloatType.SETTING_MAX_VALUE || key == FloatType.SETTING_STEPS:
34 | refresh()
35 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/float/float_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cmyen1e0ae0xx
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/float/float_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://75nkqyavb3aj"]
2 |
3 | [ext_resource type="Script" uid="uid://cmyen1e0ae0xx" path="res://addons/pandora/ui/components/properties/float/float_property.gd" id="1_1npi1"]
4 |
5 | [node name="FloatProperty" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | size_flags_horizontal = 3
12 | size_flags_vertical = 3
13 | script = ExtResource("1_1npi1")
14 | type = "float"
15 |
16 | [node name="SpinBox" type="SpinBox" parent="."]
17 | layout_mode = 2
18 | min_value = -1e+08
19 | max_value = 1e+08
20 | step = 0.01
21 | custom_arrow_step = 0.01
22 | select_all_on_focus = true
23 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/integer/integer_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | const IntType = preload("res://addons/pandora/model/types/int.gd")
6 |
7 |
8 | @onready var spin_box: SpinBox = $SpinBox
9 |
10 |
11 | func _ready() -> void:
12 | if _property != null:
13 | _property.setting_changed.connect(_setting_changed)
14 | _property.setting_cleared.connect(_setting_changed)
15 | refresh()
16 | spin_box.focus_entered.connect(func(): focused.emit())
17 | spin_box.focus_exited.connect(func(): unfocused.emit())
18 | spin_box.value_changed.connect(
19 | func(value:float):
20 | _property.set_default_value(int(value))
21 | property_value_changed.emit(value))
22 |
23 |
24 | func refresh() -> void:
25 | if _property != null:
26 | spin_box.value = _property.get_default_value() as int
27 | spin_box.min_value = _property.get_setting(IntType.SETTING_MIN_VALUE) as int
28 | spin_box.max_value = _property.get_setting(IntType.SETTING_MAX_VALUE) as int
29 |
30 |
31 | func _setting_changed(key:String) -> void:
32 | if key == IntType.SETTING_MIN_VALUE || key == IntType.SETTING_MAX_VALUE:
33 | refresh()
34 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/integer/integer_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://3dvks83yldd3
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/integer/integer_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://kgit41uva08d"]
2 |
3 | [ext_resource type="Script" uid="uid://3dvks83yldd3" path="res://addons/pandora/ui/components/properties/integer/integer_property.gd" id="1_82ywy"]
4 |
5 | [node name="IntegerProperty" type="MarginContainer"]
6 | size_flags_horizontal = 3
7 | size_flags_vertical = 3
8 | script = ExtResource("1_82ywy")
9 | type = "int"
10 |
11 | [node name="SpinBox" type="SpinBox" parent="."]
12 | layout_mode = 2
13 | focus_mode = 1
14 | max_value = 99999.0
15 | rounded = true
16 | select_all_on_focus = true
17 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/property_control.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PandoraPropertyControl extends MarginContainer
3 |
4 | signal property_value_changed(value: Variant)
5 | signal focused
6 | signal unfocused
7 |
8 | @export var type: String
9 |
10 | var _property: PandoraProperty
11 |
12 |
13 | func init(property: PandoraProperty) -> void:
14 | self._property = property
15 |
16 |
17 | func refresh() -> void:
18 | pass
19 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/property_control.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bvl8qiojdoihh
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/property_control_kvp.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PanelContainer
3 |
4 | ## invoked when a property was selected that is inherited.
5 | signal inherited_property_selected(category_id: String, property_name: String)
6 |
7 | ## called when an original property was selected
8 | signal original_property_selected(property: PandoraProperty)
9 |
10 | var _property: PandoraProperty:
11 | set(p):
12 | _property = p
13 | _refresh_key.call_deferred()
14 | var _control: PandoraPropertyControl:
15 | set(c):
16 | _control = c
17 | _refresh_value.call_deferred()
18 | var _backend: PandoraEntityBackend
19 |
20 | @onready var property_key: LinkButton = %PropertyKey
21 | @onready var property_key_edit: LineEdit = %PropertyKeyEdit
22 | @onready var property_value: MarginContainer = %PropertyValue
23 | @onready var reset_button: Button = %ResetButton
24 | @onready var regenerate_id_button: Button = %RegenerateIDButton
25 | @onready var delete_property_button: Button = %DeletePropertyButton
26 | @onready var confirmation_dialog = %ConfirmationDialog
27 |
28 |
29 | func init(
30 | property: PandoraProperty, control: PandoraPropertyControl, backend: PandoraEntityBackend
31 | ) -> void:
32 | if self._control != null:
33 | _control.queue_free()
34 | self._property = property
35 | self._control = control
36 | self._backend = backend
37 |
38 |
39 | func _ready() -> void:
40 | property_key_edit.focus_entered.connect(_property_key_focused)
41 | property_key_edit.text_changed.connect(_property_name_changed)
42 | reset_button.pressed.connect(_property_reset_to_default)
43 | regenerate_id_button.pressed.connect(func(): Pandora.regenerate_property_id(_property))
44 | delete_property_button.pressed.connect(func(): confirmation_dialog.popup())
45 | confirmation_dialog.confirmed.connect(_delete_property)
46 | _refresh.call_deferred()
47 | if _property != null:
48 | _set_edit_name_mode(_property.is_original())
49 | property_key.pressed.connect(
50 | func(): inherited_property_selected.emit(
51 | _property.get_original_category_id(), _property.get_property_name()
52 | )
53 | )
54 | if _control != null:
55 | _control.property_value_changed.connect(_refresh)
56 |
57 |
58 | func edit_key():
59 | if property_key_edit.visible:
60 | property_key_edit.grab_focus()
61 |
62 |
63 | func _refresh_key() -> void:
64 | property_key.text = _property.get_property_name()
65 | property_key_edit.text = _property.get_property_name()
66 |
67 |
68 | func _refresh_value() -> void:
69 | for child in property_value.get_children():
70 | child.queue_free()
71 | property_value.get_children().clear()
72 | property_value.add_child(_control)
73 |
74 |
75 | func _set_edit_name_mode(edit_mode: bool) -> void:
76 | property_key.visible = not edit_mode
77 | property_key_edit.visible = edit_mode
78 |
79 |
80 | func _property_name_changed(new_name: String) -> void:
81 | # FIXME avoid key duplication issue
82 | _property._name = new_name
83 |
84 |
85 | func _property_reset_to_default() -> void:
86 | _property.reset_to_default()
87 | _refresh()
88 |
89 |
90 | func _refresh(_value: Variant = null) -> void:
91 | if _control == null or _property == null:
92 | return
93 | # FIXME: focused & unfocused signals don't quite work!
94 | if not _control.unfocused.is_connected(_control_value_unfocused):
95 | _control.unfocused.connect(_control_value_unfocused)
96 | if not _control.focused.is_connected(_control_value_focused):
97 | _control.focused.connect(_control_value_focused)
98 | _control.refresh()
99 | reset_button.visible = not _property.is_original() and _property.is_overridden()
100 | regenerate_id_button.disabled = not _property.is_original()
101 | regenerate_id_button.visible = _property.is_original()
102 | if regenerate_id_button.disabled:
103 | regenerate_id_button.tooltip_text = "Inherited property id cannot be regenerated"
104 | else:
105 | regenerate_id_button.tooltip_text = "Regenerate property id"
106 | delete_property_button.disabled = not _property.is_original()
107 | delete_property_button.visible = _property.is_original()
108 | if delete_property_button.disabled:
109 | delete_property_button.tooltip_text = "Inherited property cannot be deleted"
110 | else:
111 | delete_property_button.tooltip_text = "Delete property"
112 |
113 |
114 | func _delete_property() -> void:
115 | _backend.delete_property(_property)
116 | queue_free()
117 |
118 |
119 | func _property_key_focused() -> void:
120 | original_property_selected.emit(_property)
121 |
122 |
123 | func _property_key_unfocused() -> void:
124 | pass
125 |
126 |
127 | func _control_value_focused() -> void:
128 | if property_key_edit.visible:
129 | original_property_selected.emit(_property)
130 |
131 |
132 | func _control_value_unfocused() -> void:
133 | pass
134 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/property_control_kvp.gd.uid:
--------------------------------------------------------------------------------
1 | uid://ba0d3chmbcm8i
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/property_control_kvp.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://tgaigoiiqvmc"]
2 |
3 | [ext_resource type="Script" uid="uid://ba0d3chmbcm8i" path="res://addons/pandora/ui/components/properties/property_control_kvp.gd" id="1_1h35p"]
4 | [ext_resource type="Texture2D" uid="uid://bhcep67ihojnd" path="res://addons/pandora/icons/Reload.svg" id="2_718d2"]
5 | [ext_resource type="Texture2D" uid="uid://bfs83ic84umkv" path="res://addons/pandora/icons/nanoid.svg" id="3_1psa3"]
6 | [ext_resource type="Texture2D" uid="uid://b2s1ixfakdj1e" path="res://addons/pandora/icons/Remove.svg" id="4_2n76s"]
7 |
8 | [node name="PropertyControlKVP" type="PanelContainer"]
9 | size_flags_horizontal = 3
10 | size_flags_vertical = 3
11 | script = ExtResource("1_1h35p")
12 |
13 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
14 | layout_mode = 2
15 |
16 | [node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"]
17 | layout_mode = 2
18 | size_flags_horizontal = 3
19 |
20 | [node name="Container" type="HBoxContainer" parent="HBoxContainer/HBoxContainer"]
21 | layout_mode = 2
22 | size_flags_horizontal = 3
23 | size_flags_stretch_ratio = 2.0
24 |
25 | [node name="PropertyKey" type="LinkButton" parent="HBoxContainer/HBoxContainer/Container"]
26 | unique_name_in_owner = true
27 | visible = false
28 | layout_mode = 2
29 | size_flags_horizontal = 3
30 |
31 | [node name="PropertyKeyEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Container"]
32 | unique_name_in_owner = true
33 | visible = false
34 | layout_mode = 2
35 | size_flags_horizontal = 3
36 |
37 | [node name="MarginContainer" type="MarginContainer" parent="HBoxContainer/HBoxContainer"]
38 | layout_mode = 2
39 | theme_override_constants/margin_right = -2
40 |
41 | [node name="ResetButton" type="Button" parent="HBoxContainer/HBoxContainer/MarginContainer"]
42 | unique_name_in_owner = true
43 | visible = false
44 | layout_mode = 2
45 | icon = ExtResource("2_718d2")
46 |
47 | [node name="PropertyValue" type="MarginContainer" parent="HBoxContainer"]
48 | unique_name_in_owner = true
49 | layout_mode = 2
50 | size_flags_horizontal = 3
51 |
52 | [node name="RegenerateIDButton" type="Button" parent="HBoxContainer"]
53 | unique_name_in_owner = true
54 | layout_mode = 2
55 | disabled = true
56 | icon = ExtResource("3_1psa3")
57 |
58 | [node name="DeletePropertyButton" type="Button" parent="HBoxContainer"]
59 | unique_name_in_owner = true
60 | layout_mode = 2
61 | disabled = true
62 | icon = ExtResource("4_2n76s")
63 |
64 | [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
65 | unique_name_in_owner = true
66 | title = "Delete confirmation"
67 | initial_position = 4
68 | size = Vector2i(400, 200)
69 | dialog_text = "Confirm deletion? This can have impact on children!"
70 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/reference/reference_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | const ReferenceType = preload("res://addons/pandora/model/types/reference.gd")
6 |
7 |
8 | @onready var entity_picker = $EntityPicker
9 |
10 |
11 | func _ready() -> void:
12 | refresh()
13 | _property.setting_changed.connect(_setting_changed)
14 | _property.setting_cleared.connect(_setting_changed)
15 | entity_picker.focus_exited.connect(func(): unfocused.emit())
16 | entity_picker.focus_entered.connect(func(): focused.emit())
17 | entity_picker.entity_selected.connect(
18 | func(entity:PandoraEntity):
19 | _property.set_default_value(entity)
20 | property_value_changed.emit(entity))
21 |
22 |
23 | func refresh() -> void:
24 | if _property != null:
25 | entity_picker.set_filter(_property.get_setting(ReferenceType.SETTING_CATEGORY_FILTER) as String)
26 | entity_picker.categories_only = _property.get_setting(ReferenceType.SETTING_CATEGORIES_ONLY) as bool
27 | match _property.get_setting(ReferenceType.SETTING_SORT_LIST) as String:
28 | ReferenceType.SORT_ALPHABETICALLY:
29 | entity_picker.set_sort(func(a,b): return a.get_entity_name() < b.get_entity_name())
30 | ReferenceType.SORT_AS_IS:
31 | entity_picker.set_sort(func(a,b): return false)
32 | var entity = _property.get_default_value() as PandoraEntity
33 | if entity != null:
34 | entity_picker.select.call_deferred(entity)
35 |
36 |
37 | func _setting_changed(key:String) -> void:
38 | if key == ReferenceType.SETTING_CATEGORIES_ONLY || key == ReferenceType.SETTING_CATEGORY_FILTER || key == ReferenceType.SETTING_SORT_LIST:
39 | refresh()
40 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/reference/reference_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dnk1kd1cqhqqs
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/reference/reference_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://b22vuf1tui0q3"]
2 |
3 | [ext_resource type="Script" uid="uid://dnk1kd1cqhqqs" path="res://addons/pandora/ui/components/properties/reference/reference_property.gd" id="1_euup8"]
4 | [ext_resource type="PackedScene" uid="uid://bfhqt0xa4a2fh" path="res://addons/pandora/ui/components/entity_picker/entity_picker.tscn" id="2_kp4gb"]
5 |
6 | [node name="ReferenceProperty" type="MarginContainer"]
7 | script = ExtResource("1_euup8")
8 | type = "reference"
9 |
10 | [node name="EntityPicker" parent="." instance=ExtResource("2_kp4gb")]
11 | layout_mode = 2
12 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/resource/resource_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | @onready var resource_picker = $ResourcePicker
6 |
7 |
8 | func _ready() -> void:
9 | refresh()
10 | resource_picker.focus_exited.connect(func(): unfocused.emit())
11 | resource_picker.focus_entered.connect(func(): focused.emit())
12 | resource_picker.resource_changed.connect(
13 | func(resource_path:String):
14 | _property.set_default_value(load(resource_path))
15 | property_value_changed.emit(resource_path))
16 |
17 |
18 | func refresh() -> void:
19 | if _property != null:
20 | var default_value = _property.get_default_value() as Resource
21 | if default_value != null:
22 | resource_picker.set_resource_path(default_value.resource_path)
23 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/resource/resource_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cx2h6mbdbc1h8
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/resource/resource_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://yhwimtiw711n"]
2 |
3 | [ext_resource type="Script" uid="uid://cx2h6mbdbc1h8" path="res://addons/pandora/ui/components/properties/resource/resource_property.gd" id="1_j84fe"]
4 | [ext_resource type="PackedScene" uid="uid://bvg3w88lp8uuc" path="res://addons/pandora/ui/components/resource_picker/resource_picker.tscn" id="2_5l2jx"]
5 |
6 | [node name="ResourceProperty" type="MarginContainer"]
7 | script = ExtResource("1_j84fe")
8 | type = "resource"
9 |
10 | [node name="ResourcePicker" parent="." instance=ExtResource("2_5l2jx")]
11 | layout_mode = 2
12 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/string/string_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | @onready var line_edit: LineEdit = $LineEdit
6 |
7 |
8 | func _ready() -> void:
9 | refresh()
10 | line_edit.focus_exited.connect(func(): unfocused.emit())
11 | line_edit.focus_entered.connect(func(): focused.emit())
12 | line_edit.text_changed.connect(
13 | func(text:String):
14 | _property.set_default_value(text)
15 | property_value_changed.emit(text))
16 |
17 |
18 | func refresh() -> void:
19 | if _property != null:
20 | var value = _property.get_default_value() as String
21 | if value != line_edit.text:
22 | line_edit.text = value
23 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/string/string_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://by1xtep440y1d
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/string/string_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://d02rt6sxqqha6"]
2 |
3 | [ext_resource type="Script" uid="uid://by1xtep440y1d" path="res://addons/pandora/ui/components/properties/string/string_property.gd" id="1_d17kv"]
4 |
5 | [node name="StringProperty" type="MarginContainer"]
6 | size_flags_horizontal = 3
7 | size_flags_vertical = 3
8 | script = ExtResource("1_d17kv")
9 | type = "string"
10 |
11 | [node name="LineEdit" type="LineEdit" parent="."]
12 | layout_mode = 2
13 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector2/vector2_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cmewrvvrbssm0"]
2 |
3 | [ext_resource type="Script" uid="uid://d31s8isfsqird" path="res://addons/pandora/ui/components/properties/vector/vector_property.gd" id="1_bd0jg"]
4 |
5 | [node name="Vector2Property" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_bd0jg")
12 | type = "vector2"
13 |
14 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
15 | layout_mode = 2
16 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector2i/vector2i_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://18iy7nw2r8gv"]
2 |
3 | [ext_resource type="Script" uid="uid://d31s8isfsqird" path="res://addons/pandora/ui/components/properties/vector/vector_property.gd" id="1_ticyw"]
4 |
5 | [node name="Vector2iProperty" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_ticyw")
12 | vector_type = 1
13 | type = "vector2i"
14 |
15 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
16 | layout_mode = 2
17 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector3/vector3_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cckh8r5sngw1m"]
2 |
3 | [ext_resource type="Script" uid="uid://d31s8isfsqird" path="res://addons/pandora/ui/components/properties/vector/vector_property.gd" id="1_jmmow"]
4 |
5 | [node name="Vector3Property" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_jmmow")
12 | vector_type = 2
13 | type = "vector3"
14 |
15 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
16 | layout_mode = 2
17 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector3i/vector3i_property.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://csevjm1e6lhlp"]
2 |
3 | [ext_resource type="Script" uid="uid://d31s8isfsqird" path="res://addons/pandora/ui/components/properties/vector/vector_property.gd" id="1_3onub"]
4 |
5 | [node name="Vector3iProperty" type="MarginContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_3onub")
12 | vector_type = 3
13 | type = "vector3i"
14 |
15 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
16 | layout_mode = 2
17 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector_property.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PandoraPropertyControl
3 |
4 |
5 | enum VectorType { VECTOR_2, VECTOR_2I, VECTOR_3, VECTOR_3I }
6 |
7 |
8 | const Vector2Type = preload("res://addons/pandora/model/types/vector2.gd")
9 | const Vector2iType = preload("res://addons/pandora/model/types/vector2i.gd")
10 | const Vector3Type = preload("res://addons/pandora/model/types/vector3.gd")
11 | const Vector3iType = preload("res://addons/pandora/model/types/vector3i.gd")
12 |
13 |
14 | @export var vector_type : VectorType
15 |
16 |
17 | @onready var hbox : HBoxContainer = $HBoxContainer
18 |
19 |
20 | var inputs : Array[SpinBox] = []
21 |
22 |
23 | func _ready() -> void:
24 | var components : int
25 | match vector_type:
26 | VectorType.VECTOR_2, VectorType.VECTOR_2I:
27 | components = 2
28 | VectorType.VECTOR_3, VectorType.VECTOR_3I:
29 | components = 3
30 | for i in components:
31 | var input := _create_editor_spin_slider(i)
32 | inputs.append(input)
33 | hbox.add_child(input)
34 | if _property != null:
35 | _property.setting_changed.connect(_setting_changed)
36 | _property.setting_cleared.connect(_setting_changed)
37 | refresh()
38 |
39 |
40 | func refresh() -> void:
41 | if _property != null:
42 | var min_value : int
43 | var max_value : int
44 | var step := 1.0
45 | var value = _property.get_default_value()
46 | match vector_type:
47 | VectorType.VECTOR_2:
48 | min_value = _property.get_setting(Vector2Type.SETTING_MIN_COMPONENT_VALUE) as int
49 | max_value = _property.get_setting(Vector2Type.SETTING_MAX_COMPONENT_VALUE) as int
50 | step = _property.get_setting(Vector2Type.SETTING_STEPS) as float
51 | VectorType.VECTOR_2I:
52 | min_value = _property.get_setting(Vector2iType.SETTING_MIN_COMPONENT_VALUE) as int
53 | max_value = _property.get_setting(Vector2iType.SETTING_MAX_COMPONENT_VALUE) as int
54 | VectorType.VECTOR_3:
55 | min_value = _property.get_setting(Vector3Type.SETTING_MIN_COMPONENT_VALUE) as int
56 | max_value = _property.get_setting(Vector3Type.SETTING_MAX_COMPONENT_VALUE) as int
57 | step = _property.get_setting(Vector3Type.SETTING_STEPS) as float
58 | VectorType.VECTOR_3I:
59 | min_value = _property.get_setting(Vector3iType.SETTING_MIN_COMPONENT_VALUE) as int
60 | max_value = _property.get_setting(Vector3iType.SETTING_MAX_COMPONENT_VALUE) as int
61 | for i in inputs.size():
62 | var input = inputs[i]
63 | input.min_value = min_value
64 | input.max_value = max_value
65 | input.step = step
66 | if value[i] != input.value:
67 | input.set_value_no_signal(value[i])
68 |
69 |
70 |
71 | func _setting_changed(key:String) -> void:
72 | if (vector_type == VectorType.VECTOR_2 and
73 | (key == Vector2Type.SETTING_MIN_COMPONENT_VALUE or
74 | key == Vector2Type.SETTING_MAX_COMPONENT_VALUE or
75 | key == Vector2Type.SETTING_STEPS)) \
76 | or \
77 | (vector_type == VectorType.VECTOR_2I and
78 | (key == Vector2iType.SETTING_MIN_COMPONENT_VALUE or
79 | key == Vector2iType.SETTING_MAX_COMPONENT_VALUE)) \
80 | or \
81 | (vector_type == VectorType.VECTOR_3 and
82 | (key == Vector3Type.SETTING_MIN_COMPONENT_VALUE or
83 | key == Vector3Type.SETTING_MAX_COMPONENT_VALUE or
84 | key == Vector3Type.SETTING_STEPS)) \
85 | or \
86 | (vector_type == VectorType.VECTOR_3I and
87 | (key == Vector3iType.SETTING_MIN_COMPONENT_VALUE or
88 | key == Vector3iType.SETTING_MAX_COMPONENT_VALUE)):
89 | refresh()
90 |
91 |
92 | func _create_editor_spin_slider(axis:int) -> SpinBox:
93 | var node := SpinBox.new()
94 | var label = ["x", "y", "z"][axis]
95 | node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
96 | node.prefix = label
97 | if vector_type == VectorType.VECTOR_2 or vector_type == VectorType.VECTOR_3:
98 | node.step = 0.01
99 | node.focus_entered.connect(func(): focused.emit())
100 | node.focus_exited.connect(func(): unfocused.emit())
101 | node.value_changed.connect(
102 | func(v):
103 | var value = _property.get_default_value()
104 | value[axis] = v
105 | _property.set_default_value(value)
106 | property_value_changed.emit(value))
107 | return node
108 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/properties/vector/vector_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://d31s8isfsqird
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_bar/property_bar.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PandoraPropertyBar extends HBoxContainer
3 |
4 | signal property_added(scene: PackedScene)
5 |
6 | @onready var _buttons = get_children()
7 |
8 | var type_to_scene = {}
9 |
10 |
11 | func _ready() -> void:
12 | for button in _buttons:
13 | button.pressed.connect(_pressed.bind(button as PandoraPropertyButton))
14 | var scene_instance = button.scene.instantiate()
15 | type_to_scene[scene_instance.type] = button.scene
16 | scene_instance.queue_free()
17 |
18 |
19 | func _pressed(button: PandoraPropertyButton) -> void:
20 | property_added.emit(button.scene)
21 |
22 |
23 | func get_scene_by_type(type: String) -> PackedScene:
24 | return type_to_scene[type]
25 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_bar/property_bar.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bxesr1w5ukygv
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_bar/property_bar.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=27 format=3 uid="uid://8namx0kxhw0"]
2 |
3 | [ext_resource type="Script" uid="uid://bxesr1w5ukygv" path="res://addons/pandora/ui/components/property_bar/property_bar.gd" id="1_0r2cp"]
4 | [ext_resource type="Texture2D" uid="uid://do5tkodyvid10" path="res://addons/pandora/icons/String.svg" id="1_4esni"]
5 | [ext_resource type="Texture2D" uid="uid://blvy22tu53qxy" path="res://addons/pandora/icons/int.svg" id="2_vpyx8"]
6 | [ext_resource type="Texture2D" uid="uid://cgupnims1vk7r" path="res://addons/pandora/icons/float.svg" id="3_d0hjc"]
7 | [ext_resource type="Script" uid="uid://crr6rlkqtg6we" path="res://addons/pandora/ui/components/property_bar/property_button.gd" id="3_kwfh5"]
8 | [ext_resource type="PackedScene" uid="uid://d02rt6sxqqha6" path="res://addons/pandora/ui/components/properties/string/string_property.tscn" id="4_noo0c"]
9 | [ext_resource type="Texture2D" uid="uid://mmkaghs6sbx4" path="res://addons/pandora/icons/bool.svg" id="4_wkogm"]
10 | [ext_resource type="Texture2D" uid="uid://c2738ylh13lsi" path="res://addons/pandora/icons/Color.svg" id="5_m2x7s"]
11 | [ext_resource type="PackedScene" uid="uid://kgit41uva08d" path="res://addons/pandora/ui/components/properties/integer/integer_property.tscn" id="6_bgkni"]
12 | [ext_resource type="PackedScene" uid="uid://75nkqyavb3aj" path="res://addons/pandora/ui/components/properties/float/float_property.tscn" id="8_7fghm"]
13 | [ext_resource type="PackedScene" uid="uid://brp6oodbm37gk" path="res://addons/pandora/ui/components/properties/bool/bool_property.tscn" id="10_jsvgc"]
14 | [ext_resource type="Texture2D" uid="uid://bk7a4jkyif178" path="res://addons/pandora/icons/Vector2i.svg" id="11_2g827"]
15 | [ext_resource type="PackedScene" uid="uid://18iy7nw2r8gv" path="res://addons/pandora/ui/components/properties/vector/vector2i/vector2i_property.tscn" id="11_wu1l4"]
16 | [ext_resource type="PackedScene" uid="uid://csevjm1e6lhlp" path="res://addons/pandora/ui/components/properties/vector/vector3i/vector3i_property.tscn" id="12_6vngj"]
17 | [ext_resource type="PackedScene" uid="uid://chj1ateikyk5" path="res://addons/pandora/ui/components/properties/color/color_property.tscn" id="12_xjj7h"]
18 | [ext_resource type="Texture2D" uid="uid://c6kohe0abjrrs" path="res://addons/pandora/icons/Vector3i.svg" id="13_26qay"]
19 | [ext_resource type="Texture2D" uid="uid://dcqltisjej0lu" path="res://addons/pandora/icons/Vector2.svg" id="13_c5fps"]
20 | [ext_resource type="PackedScene" uid="uid://b22vuf1tui0q3" path="res://addons/pandora/ui/components/properties/reference/reference_property.tscn" id="13_suig5"]
21 | [ext_resource type="Texture2D" uid="uid://dojpd3ptnta4m" path="res://addons/pandora/icons/Object.svg" id="13_y2aqa"]
22 | [ext_resource type="PackedScene" uid="uid://cmewrvvrbssm0" path="res://addons/pandora/ui/components/properties/vector/vector2/vector2_property.tscn" id="14_oowe1"]
23 | [ext_resource type="Texture2D" uid="uid://rwodit05tms7" path="res://addons/pandora/icons/AtlasTexture.svg" id="15_dus4l"]
24 | [ext_resource type="PackedScene" uid="uid://yhwimtiw711n" path="res://addons/pandora/ui/components/properties/resource/resource_property.tscn" id="16_qe711"]
25 | [ext_resource type="Texture2D" uid="uid://bdxvds1pxhqv6" path="res://addons/pandora/icons/Vector3.svg" id="17_bx0em"]
26 | [ext_resource type="Texture2D" uid="uid://66qnm42libnj" path="res://addons/pandora/icons/Array.svg" id="17_ebxvo"]
27 | [ext_resource type="PackedScene" uid="uid://cckh8r5sngw1m" path="res://addons/pandora/ui/components/properties/vector/vector3/vector3_property.tscn" id="18_oxp4m"]
28 | [ext_resource type="PackedScene" uid="uid://ckdfcxfes51ia" path="res://addons/pandora/ui/components/properties/array/array_property.tscn" id="18_sjnhs"]
29 |
30 | [node name="PropertyBar" type="HBoxContainer"]
31 | offset_right = 35.0
32 | offset_bottom = 33.0
33 | theme_override_constants/separation = 10
34 | script = ExtResource("1_0r2cp")
35 |
36 | [node name="AddTextPropertyButton" type="Button" parent="."]
37 | layout_mode = 2
38 | size_flags_horizontal = 0
39 | tooltip_text = "String property"
40 | icon = ExtResource("1_4esni")
41 | script = ExtResource("3_kwfh5")
42 | scene = ExtResource("4_noo0c")
43 |
44 | [node name="AddIntegerPropertyButton" type="Button" parent="."]
45 | layout_mode = 2
46 | size_flags_horizontal = 0
47 | tooltip_text = "Integer property"
48 | icon = ExtResource("2_vpyx8")
49 | script = ExtResource("3_kwfh5")
50 | scene = ExtResource("6_bgkni")
51 |
52 | [node name="AddFloatPropertyButton" type="Button" parent="."]
53 | layout_mode = 2
54 | size_flags_horizontal = 0
55 | tooltip_text = "Float property"
56 | icon = ExtResource("3_d0hjc")
57 | script = ExtResource("3_kwfh5")
58 | scene = ExtResource("8_7fghm")
59 |
60 | [node name="AddBoolPropertyButton" type="Button" parent="."]
61 | layout_mode = 2
62 | size_flags_horizontal = 0
63 | tooltip_text = "Bool property"
64 | icon = ExtResource("4_wkogm")
65 | script = ExtResource("3_kwfh5")
66 | scene = ExtResource("10_jsvgc")
67 |
68 | [node name="AddVector2iPropertyButton" type="Button" parent="."]
69 | layout_mode = 2
70 | tooltip_text = "Vector2i property"
71 | icon = ExtResource("11_2g827")
72 | script = ExtResource("3_kwfh5")
73 | scene = ExtResource("11_wu1l4")
74 |
75 | [node name="AddVector2PropertyButton" type="Button" parent="."]
76 | layout_mode = 2
77 | tooltip_text = "Vector2 property"
78 | icon = ExtResource("13_c5fps")
79 | script = ExtResource("3_kwfh5")
80 | scene = ExtResource("14_oowe1")
81 |
82 | [node name="AddVector3iPropertyButton" type="Button" parent="."]
83 | layout_mode = 2
84 | tooltip_text = "Vector3i property"
85 | icon = ExtResource("13_26qay")
86 | script = ExtResource("3_kwfh5")
87 | scene = ExtResource("12_6vngj")
88 |
89 | [node name="AddVector3PropertyButton" type="Button" parent="."]
90 | layout_mode = 2
91 | tooltip_text = "Vector3 property"
92 | icon = ExtResource("17_bx0em")
93 | script = ExtResource("3_kwfh5")
94 | scene = ExtResource("18_oxp4m")
95 |
96 | [node name="AddColorPropertyButton" type="Button" parent="."]
97 | layout_mode = 2
98 | size_flags_horizontal = 0
99 | tooltip_text = "Color property"
100 | icon = ExtResource("5_m2x7s")
101 | script = ExtResource("3_kwfh5")
102 | scene = ExtResource("12_xjj7h")
103 |
104 | [node name="AddReferencePropertyButton" type="Button" parent="."]
105 | layout_mode = 2
106 | size_flags_horizontal = 0
107 | tooltip_text = "Reference property"
108 | icon = ExtResource("13_y2aqa")
109 | script = ExtResource("3_kwfh5")
110 | scene = ExtResource("13_suig5")
111 |
112 | [node name="AddResourcePropertyButton" type="Button" parent="."]
113 | layout_mode = 2
114 | tooltip_text = "Resource property"
115 | icon = ExtResource("15_dus4l")
116 | script = ExtResource("3_kwfh5")
117 | scene = ExtResource("16_qe711")
118 |
119 | [node name="AddArrayPropertyButton" type="Button" parent="."]
120 | layout_mode = 2
121 | tooltip_text = "Array property"
122 | icon = ExtResource("17_ebxvo")
123 | script = ExtResource("3_kwfh5")
124 | scene = ExtResource("18_sjnhs")
125 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_bar/property_button.gd:
--------------------------------------------------------------------------------
1 | class_name PandoraPropertyButton extends Button
2 |
3 | @export var scene: PackedScene
4 |
5 |
6 | func _ready():
7 | if scene:
8 | var scene_instance = scene.instantiate()
9 | var property_type = PandoraPropertyType.lookup(scene_instance.type)
10 | icon = load(property_type.get_type_icon_path())
11 | scene_instance.queue_free()
12 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_bar/property_button.gd.uid:
--------------------------------------------------------------------------------
1 | uid://crr6rlkqtg6we
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_type_picker/property_type_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_type_picker/property_type_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://clt62qk6a21q4
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/property_type_picker/property_type_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://xbns62fkvuc7"]
2 |
3 | [ext_resource type="Script" uid="uid://clt62qk6a21q4" path="res://addons/pandora/ui/components/property_type_picker/property_type_picker.gd" id="1_7kqcl"]
4 |
5 | [node name="PropertyTypePicker" type="HBoxContainer"]
6 | anchors_preset = 15
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | grow_horizontal = 2
10 | grow_vertical = 2
11 | script = ExtResource("1_7kqcl")
12 |
13 | [node name="OptionButton" type="OptionButton" parent="."]
14 | layout_mode = 2
15 | size_flags_horizontal = 3
16 | size_flags_vertical = 0
17 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/resource_picker/resource_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
4 | signal resource_changed(resource_path: String)
5 |
6 | @onready var line_edit = $LineEdit
7 | @onready var load_file_button = $LoadFileButton
8 | @onready var file_dialog: FileDialog = $FileDialog
9 |
10 | var resource_path: String
11 |
12 |
13 | func _ready() -> void:
14 | line_edit.text_submitted.connect(_path_changed)
15 | load_file_button.pressed.connect(file_dialog.popup)
16 | file_dialog.file_selected.connect(_path_changed)
17 |
18 |
19 | func set_resource_path(path: String) -> void:
20 | var resource = load(path) as Resource
21 | if resource != null:
22 | line_edit.text = path
23 | self.resource_path = path
24 |
25 |
26 | func _path_changed(new_path: String) -> void:
27 | if new_path.begins_with("res://"):
28 | var resource = load(new_path) as Resource
29 | if resource != null and resource_path != new_path:
30 | resource_path = new_path
31 | resource_changed.emit(new_path)
32 | else:
33 | line_edit.text = resource_path
34 |
35 |
36 | func _can_drop_data(_pos, data):
37 | if data.type == "files":
38 | return true
39 | return false
40 |
41 |
42 | func _drop_data(_pos, data):
43 | if data.type == "files":
44 | var path = data.files[0]
45 | _path_changed(path)
46 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/resource_picker/resource_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://do7o7akn03aw3
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/resource_picker/resource_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bvg3w88lp8uuc"]
2 |
3 | [ext_resource type="Script" uid="uid://do7o7akn03aw3" path="res://addons/pandora/ui/components/resource_picker/resource_picker.gd" id="1_hjkiw"]
4 | [ext_resource type="Texture2D" uid="uid://dimpswbv6s8t2" path="res://addons/pandora/icons/Folder.svg" id="3_51u7n"]
5 |
6 | [node name="ResourcePicker" type="HBoxContainer"]
7 | size_flags_horizontal = 3
8 | size_flags_vertical = 3
9 | script = ExtResource("1_hjkiw")
10 |
11 | [node name="LineEdit" type="LineEdit" parent="."]
12 | layout_mode = 2
13 | size_flags_horizontal = 3
14 | mouse_filter = 1
15 |
16 | [node name="LoadFileButton" type="Button" parent="."]
17 | layout_mode = 2
18 | icon = ExtResource("3_51u7n")
19 |
20 | [node name="FileDialog" type="FileDialog" parent="."]
21 | title = "Open a File"
22 | initial_position = 2
23 | size = Vector2i(784, 324)
24 | ok_button_text = "Open"
25 | file_mode = 0
26 | filters = PackedStringArray("*.tres", "*.jpg", "*.png", "*.jpeg", "*.wav", "*.mp3", "*.ogg", "*.tscn", "*.mp4", "*.gif", "*.gd")
27 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/script_picker/script_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
4 | signal script_path_changed(script_path: String)
5 |
6 | @onready var line_edit = $LineEdit
7 | @onready var button = $Button
8 | @onready var file_dialog = $FileDialog
9 |
10 | var _filter: Callable
11 |
12 |
13 | func _ready() -> void:
14 | line_edit.text_submitted.connect(_path_changed)
15 | button.pressed.connect(file_dialog.popup)
16 | file_dialog.file_selected.connect(_path_changed)
17 |
18 |
19 | func set_filter(filter: Callable) -> void:
20 | self._filter = filter
21 |
22 |
23 | func set_script_path(script_path: String) -> void:
24 | if line_edit.text != script_path:
25 | line_edit.text = script_path
26 |
27 |
28 | func _path_changed(new_path: String) -> void:
29 | if new_path.begins_with("res://"):
30 | if _filter == null or _filter.call(new_path):
31 | set_script_path(new_path)
32 | script_path_changed.emit(new_path)
33 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/script_picker/script_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cc3lh861dwdq3
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/script_picker/script_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bp0gaqyb10bns"]
2 |
3 | [ext_resource type="Script" uid="uid://cc3lh861dwdq3" path="res://addons/pandora/ui/components/script_picker/script_picker.gd" id="1_7xx4n"]
4 | [ext_resource type="Texture2D" uid="uid://dimpswbv6s8t2" path="res://addons/pandora/icons/Folder.svg" id="2_gmucu"]
5 |
6 | [node name="ScriptPicker" type="HBoxContainer"]
7 | size_flags_horizontal = 3
8 | script = ExtResource("1_7xx4n")
9 |
10 | [node name="LineEdit" type="LineEdit" parent="."]
11 | layout_mode = 2
12 | size_flags_horizontal = 3
13 |
14 | [node name="Button" type="Button" parent="."]
15 | layout_mode = 2
16 | icon = ExtResource("2_gmucu")
17 |
18 | [node name="FileDialog" type="FileDialog" parent="."]
19 | title = "Open a File"
20 | initial_position = 2
21 | size = Vector2i(400, 324)
22 | ok_button_text = "Open"
23 | file_mode = 0
24 | filters = PackedStringArray("*.gd")
25 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/texture_picker/texture_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HBoxContainer
3 |
4 | signal texture_changed(texture_path: String)
5 |
6 | @onready var texture_rect = $TextureRect
7 | @onready var line_edit = $LineEdit
8 | @onready var load_file_button = $LoadFileButton
9 | @onready var file_dialog: FileDialog = $FileDialog
10 |
11 | var texture_path: String
12 |
13 |
14 | func _ready() -> void:
15 | line_edit.text_submitted.connect(_path_changed)
16 | load_file_button.pressed.connect(file_dialog.popup)
17 | file_dialog.file_selected.connect(_path_changed)
18 |
19 |
20 | func set_texture_path(path: String) -> void:
21 | var resource = load(path) as Texture2D
22 | if resource != null:
23 | texture_rect.texture = resource
24 | line_edit.text = path
25 | self.texture_path = path
26 |
27 |
28 | func _path_changed(new_path: String) -> void:
29 | if new_path.begins_with("res://"):
30 | var resource = load(new_path) as Texture2D
31 | if resource != null and texture_path != new_path:
32 | texture_path = new_path
33 | texture_rect.texture = resource
34 | texture_changed.emit(new_path)
35 | else:
36 | line_edit.text = texture_path
37 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/texture_picker/texture_picker.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bb0m1hfpcrgr8
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/texture_picker/texture_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://dvoxop0o2mlfi"]
2 |
3 | [ext_resource type="Script" uid="uid://bb0m1hfpcrgr8" path="res://addons/pandora/ui/components/texture_picker/texture_picker.gd" id="1_dilp1"]
4 | [ext_resource type="Texture2D" uid="uid://dimpswbv6s8t2" path="res://addons/pandora/icons/Folder.svg" id="3_0esgd"]
5 |
6 | [node name="TexturePicker" type="HBoxContainer"]
7 | size_flags_horizontal = 3
8 | size_flags_vertical = 3
9 | script = ExtResource("1_dilp1")
10 |
11 | [node name="TextureRect" type="TextureRect" parent="."]
12 | layout_mode = 2
13 | expand_mode = 2
14 |
15 | [node name="LineEdit" type="LineEdit" parent="."]
16 | layout_mode = 2
17 | size_flags_horizontal = 3
18 |
19 | [node name="LoadFileButton" type="Button" parent="."]
20 | layout_mode = 2
21 | icon = ExtResource("3_0esgd")
22 |
23 | [node name="FileDialog" type="FileDialog" parent="."]
24 | title = "Open a File"
25 | initial_position = 2
26 | size = Vector2i(784, 324)
27 | ok_button_text = "Open"
28 | file_mode = 0
29 | filters = PackedStringArray("*.svg", "*.jpg", "*.png", "*.jpeg")
30 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/update_button/update_button.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Button
3 |
4 | const RELEASE_URL: String = "https://api.github.com/repos/bitbrain/pandora/releases"
5 |
6 | @onready var http_request: HTTPRequest = %HTTPRequest
7 | @onready var updater_window: AcceptDialog = $UpdaterWindow
8 | @onready var updater: Control = $UpdaterWindow/UpdaterControl
9 | @onready var post_update_window: ConfirmationDialog = $PostUpdateWindow
10 |
11 |
12 | func _ready() -> void:
13 | self.hide()
14 | check_for_updates()
15 |
16 |
17 | func get_version() -> String:
18 | var plugin_config: ConfigFile = ConfigFile.new()
19 | plugin_config.load("res://addons/pandora/plugin.cfg")
20 | return plugin_config.get_value("plugin", "version")
21 |
22 |
23 | func check_for_updates() -> void:
24 | http_request.request(RELEASE_URL)
25 |
26 |
27 | func version_to_number(ver: String) -> int:
28 | ver = ver.lstrip("v")
29 | ver = ver.split("+")[0]
30 |
31 | var parts = ver.split("-")
32 | var release_ver = parts[0]
33 | parts.remove_at(0)
34 |
35 | var phase = null
36 | if parts.size() > 0:
37 | phase = "-".join(parts)
38 |
39 | var nums = release_ver.split(".")
40 | var size = nums.size()
41 | var offset = 0 if phase == null else 1
42 | var value = 0
43 |
44 | for idx in range(size):
45 | var item = nums[idx]
46 | if item.is_valid_int():
47 | value += item.to_int() * (100 ** (size + offset - idx))
48 |
49 | # If the release is stable, add 75 to be greater than alpha, beta & rc
50 | if phase == null && idx == size - 1:
51 | value += 75
52 |
53 | # The lstrip is done seperately so it works even if the "." is not present
54 | if phase != null:
55 | if phase.begins_with("alpha"):
56 | value += phase.lstrip("alpha").lstrip(".").to_int()
57 | elif phase.begins_with("beta"):
58 | value += 25 + phase.lstrip("beta").lstrip(".").to_int()
59 | elif phase.begins_with("rc"):
60 | value += 50 + phase.lstrip("rc").lstrip(".").to_int()
61 |
62 | return value
63 |
64 |
65 | func _on_http_request_completed(
66 | result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray
67 | ) -> void:
68 | if result != HTTPRequest.RESULT_SUCCESS:
69 | return
70 |
71 | var res = JSON.parse_string(body.get_string_from_utf8())
72 | if typeof(res) != TYPE_ARRAY:
73 | return
74 |
75 | var curr_version_num = version_to_number(get_version())
76 |
77 | var new_versions: Array = (res as Array).filter(
78 | func(release): return version_to_number(release.tag_name) > curr_version_num
79 | )
80 |
81 | if new_versions.size() > 0:
82 | self.show()
83 | updater.releases = new_versions
84 |
85 |
86 | func _on_update_button_pressed() -> void:
87 | updater_window.show()
88 |
89 |
90 | func _on_updater_update_done(success: bool) -> void:
91 | if success:
92 | post_update_window.set_text("Updated Pandora successfully!\nRestart editor?")
93 | else:
94 | post_update_window.set_text("Could not update Pandora!\nRestart editor?")
95 |
96 | post_update_window.show()
97 |
98 |
99 | func _on_post_update_window_confirmed() -> void:
100 | var plugin: EditorPlugin = Engine.get_meta("PandoraEditorPlugin")
101 | plugin.get_editor_interface().restart_editor(true)
102 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/update_button/update_button.gd.uid:
--------------------------------------------------------------------------------
1 | uid://sn8ptmm6u17a
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/update_button/update_button.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://dy4xl20q2nq7q"]
2 |
3 | [ext_resource type="Script" uid="uid://sn8ptmm6u17a" path="res://addons/pandora/ui/components/update_button/update_button.gd" id="1_0iteh"]
4 | [ext_resource type="PackedScene" uid="uid://dtwiql0cpn5hu" path="res://addons/pandora/ui/components/updater/updater.tscn" id="2_lifbu"]
5 |
6 | [node name="UpdateButton" type="Button"]
7 | visible = false
8 | text = "Update"
9 | script = ExtResource("1_0iteh")
10 |
11 | [node name="HTTPRequest" type="HTTPRequest" parent="."]
12 | unique_name_in_owner = true
13 |
14 | [node name="UpdaterWindow" type="AcceptDialog" parent="."]
15 | title = "Update Pandora"
16 | initial_position = 2
17 | size = Vector2i(600, 450)
18 | unresizable = true
19 | ok_button_text = "Close"
20 |
21 | [node name="UpdaterControl" parent="UpdaterWindow" instance=ExtResource("2_lifbu")]
22 |
23 | [node name="PostUpdateWindow" type="ConfirmationDialog" parent="."]
24 | title = "Pandora Updater"
25 | initial_position = 2
26 | size = Vector2i(343, 109)
27 | ok_button_text = "Restart"
28 | dialog_text = "Updated Pandora successfully!
29 | Restart editor?"
30 |
31 | [connection signal="pressed" from="." to="." method="_on_update_button_pressed"]
32 | [connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_completed"]
33 | [connection signal="update_done" from="UpdaterWindow/UpdaterControl" to="." method="_on_updater_update_done"]
34 | [connection signal="confirmed" from="PostUpdateWindow" to="." method="_on_post_update_window_confirmed"]
35 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/updater/updater.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | signal update_done(success: bool)
5 |
6 | const TEMP_FILE_NAME: String = "user://temp.zip"
7 |
8 | @onready var http_request: HTTPRequest = $HTTPRequest
9 | @onready var release_text: TextEdit = $VBoxContainer/ReleaseText
10 | @onready var release_link: LinkButton = $VBoxContainer/CenterContainer2/LinkButton
11 | @onready var download_btn: Button = $VBoxContainer/CenterContainer/DownloadButton
12 | @onready var version_text: Label = $VBoxContainer/VersionText
13 |
14 | var releases: Array = []:
15 | set(value):
16 | releases = value
17 | _update_ui()
18 | get:
19 | return releases
20 |
21 |
22 | func _update_ui() -> void:
23 | if releases.is_empty():
24 | return
25 |
26 | var release_notes_text = ""
27 | for release in releases:
28 | release_notes_text += "Release " + release.tag_name + "\n" + release.body + "\n\n"
29 | release_notes_text = release_notes_text.rstrip("\n")
30 | release_text.set_text(release_notes_text)
31 |
32 | version_text.set_text("Latest version: " + releases[0].tag_name)
33 | release_link.set_uri(releases[0].html_url)
34 |
35 |
36 | func _on_download_button_pressed() -> void:
37 | if releases.is_empty():
38 | self.update_done.emit(false)
39 | self.hide()
40 | return
41 |
42 | if FileAccess.file_exists("res://examples/inventory/inventory_example.gd"):
43 | prints("You can't update the addon from within itself.")
44 | return
45 |
46 | http_request.request(releases[0].zipball_url)
47 | download_btn.disabled = true
48 | download_btn.set_text("Downloading")
49 |
50 |
51 | func _on_http_request_request_completed(
52 | result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray
53 | ) -> void:
54 | if result != HTTPRequest.RESULT_SUCCESS:
55 | self.update_done.emit(false)
56 | self.hide()
57 | return
58 |
59 | var zip_file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE)
60 | zip_file.store_buffer(body)
61 | zip_file.close()
62 |
63 | OS.move_to_trash(ProjectSettings.globalize_path("res://addons/pandora"))
64 |
65 | var zip_reader: ZIPReader = ZIPReader.new()
66 | zip_reader.open(TEMP_FILE_NAME)
67 | var files: PackedStringArray = zip_reader.get_files()
68 |
69 | var base_path = files[1]
70 |
71 | for path in files:
72 | var new_file_path: String = path.replace(base_path, "")
73 | if path.ends_with("/"):
74 | DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path)
75 | else:
76 | var file: FileAccess = FileAccess.open(
77 | "res://addons/%s" % new_file_path, FileAccess.WRITE
78 | )
79 | file.store_buffer(zip_reader.read_file(path))
80 |
81 | zip_reader.close()
82 | DirAccess.remove_absolute(TEMP_FILE_NAME)
83 |
84 | self.update_done.emit(true)
85 | self.hide()
86 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/updater/updater.gd.uid:
--------------------------------------------------------------------------------
1 | uid://df16diqheefu8
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/components/updater/updater.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://dtwiql0cpn5hu"]
2 |
3 | [ext_resource type="Script" uid="uid://df16diqheefu8" path="res://addons/pandora/ui/components/updater/updater.gd" id="1_e18b4"]
4 | [ext_resource type="Texture2D" uid="uid://crgjwaubao8pj" path="res://addons/pandora/icons/icon.png" id="1_jpf8m"]
5 |
6 | [node name="UpdaterControl" type="Control"]
7 | layout_mode = 3
8 | anchors_preset = 15
9 | anchor_right = 1.0
10 | anchor_bottom = 1.0
11 | offset_left = 8.0
12 | offset_top = 8.0
13 | offset_right = -8.0
14 | offset_bottom = -49.0
15 | grow_horizontal = 2
16 | grow_vertical = 2
17 | script = ExtResource("1_e18b4")
18 |
19 | [node name="HTTPRequest" type="HTTPRequest" parent="."]
20 |
21 | [node name="VBoxContainer" type="VBoxContainer" parent="."]
22 | layout_mode = 1
23 | anchors_preset = 15
24 | anchor_right = 1.0
25 | anchor_bottom = 1.0
26 | grow_horizontal = 2
27 | grow_vertical = 2
28 | theme_override_constants/separation = 8
29 |
30 | [node name="ReleaseNotesText" type="Label" parent="VBoxContainer"]
31 | layout_mode = 2
32 | text = "Release Notes"
33 |
34 | [node name="ReleaseText" type="TextEdit" parent="VBoxContainer"]
35 | custom_minimum_size = Vector2(256, 256)
36 | layout_mode = 2
37 | editable = false
38 | context_menu_enabled = false
39 | shortcut_keys_enabled = false
40 | deselect_on_focus_loss_enabled = false
41 | drag_and_drop_selection_enabled = false
42 | virtual_keyboard_enabled = false
43 | middle_mouse_paste_enabled = false
44 |
45 | [node name="TextureRect" type="TextureRect" parent="VBoxContainer"]
46 | visible = false
47 | custom_minimum_size = Vector2(128, 128)
48 | layout_mode = 2
49 | texture = ExtResource("1_jpf8m")
50 | expand_mode = 1
51 | stretch_mode = 5
52 |
53 | [node name="VersionText" type="Label" parent="VBoxContainer"]
54 | layout_mode = 2
55 | text = "Latest version: vx.y.-alphaZ"
56 | horizontal_alignment = 1
57 |
58 | [node name="CenterContainer" type="CenterContainer" parent="VBoxContainer"]
59 | layout_mode = 2
60 |
61 | [node name="DownloadButton" type="Button" parent="VBoxContainer/CenterContainer"]
62 | layout_mode = 2
63 | text = "Download and install"
64 |
65 | [node name="CenterContainer2" type="CenterContainer" parent="VBoxContainer"]
66 | layout_mode = 2
67 |
68 | [node name="LinkButton" type="LinkButton" parent="VBoxContainer/CenterContainer2"]
69 | layout_mode = 2
70 | text = "Release Notes"
71 |
72 | [connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"]
73 | [connection signal="pressed" from="VBoxContainer/CenterContainer/DownloadButton" to="." method="_on_download_button_pressed"]
74 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/import_dialog/import_dialog.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | signal import_started(import_count: int)
5 | signal import_ended(data: Array[PandoraEntity])
6 |
7 | @onready var notification_dialog = %NotificationDialog
8 | @onready var confirmation_dialog = %ConfirmationDialog
9 | @onready var file_dialog = %FileDialog
10 |
11 |
12 | func _ready():
13 | file_dialog.file_selected.connect(_import_file)
14 | Pandora.import_success.connect(self._on_import_success)
15 | Pandora.import_failed.connect(self._on_import_failed)
16 | Pandora.import_calculation_ended.connect(self._on_import_calculation_ended)
17 | Pandora.import_calculation_failed.connect(self._on_import_calculation_failed)
18 |
19 |
20 | func open():
21 | file_dialog.popup_centered()
22 |
23 |
24 | func _import_file(path: String) -> void:
25 | Pandora.calculate_import_data(path)
26 |
27 |
28 | func _on_import_calculation_failed(reason: String) -> void:
29 | notification_dialog.title = "Import Failed!"
30 | notification_dialog.dialog_text = reason
31 | notification_dialog.popup_centered()
32 |
33 |
34 | func _on_import_calculation_ended(import_info: Dictionary) -> void:
35 | confirmation_dialog.title = "Confirm Import"
36 | confirmation_dialog.dialog_text = (
37 | "Found "
38 | + str(import_info["total_categories"])
39 | + " Categories with "
40 | + str(import_info["total_entities"])
41 | + " Entities. Would you like to proceed?"
42 | )
43 | confirmation_dialog.confirmed.connect(func(): self._start_import(import_info))
44 | confirmation_dialog.popup_centered()
45 |
46 |
47 | func _start_import(import_info: Dictionary) -> void:
48 | import_started.emit(
49 | (
50 | int(import_info["total_categories"])
51 | + int(import_info["total_entities"])
52 | + int(import_info["total_properties"])
53 | )
54 | )
55 | Pandora.import_data(import_info["path"])
56 |
57 |
58 | func _on_import_success(imported_count: int = 0) -> void:
59 | var data: Array[PandoraEntity] = []
60 | data.assign(Pandora.get_all_roots())
61 | notification_dialog.title = "Import Finished!"
62 | notification_dialog.dialog_text = str(imported_count) + " records imported successfully!"
63 | notification_dialog.popup_centered()
64 | import_ended.emit(data)
65 |
66 |
67 | func _on_import_failed(reason: String) -> void:
68 | notification_dialog.title = "Import Failed!"
69 | notification_dialog.dialog_text = reason
70 | notification_dialog.popup_centered()
71 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/import_dialog/import_dialog.gd.uid:
--------------------------------------------------------------------------------
1 | uid://4hj8geca1kqp
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/import_dialog/import_dialog.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://ceboo5esbe2ld"]
2 |
3 | [ext_resource type="Script" uid="uid://4hj8geca1kqp" path="res://addons/pandora/ui/editor/import_dialog/import_dialog.gd" id="1_4evpu"]
4 |
5 | [node name="ImportDialog" type="Control"]
6 | layout_mode = 3
7 | anchors_preset = 0
8 | offset_right = 40.0
9 | offset_bottom = 40.0
10 | script = ExtResource("1_4evpu")
11 |
12 | [node name="FileDialog" type="FileDialog" parent="."]
13 | unique_name_in_owner = true
14 | title = "Open a File"
15 | initial_position = 1
16 | size = Vector2i(800, 600)
17 | transient = false
18 | ok_button_text = "Open"
19 | file_mode = 0
20 | access = 2
21 | filters = PackedStringArray("*.pandora")
22 |
23 | [node name="NotificationDialog" type="AcceptDialog" parent="."]
24 | unique_name_in_owner = true
25 | title = "Import Finished!"
26 | initial_position = 1
27 | size = Vector2i(274, 100)
28 | transient = false
29 | dialog_text = "0 records imported successfully!"
30 |
31 | [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
32 | unique_name_in_owner = true
33 | title = "Confirm Import"
34 | initial_position = 1
35 | size = Vector2i(504, 100)
36 | dialog_text = "Found 10 Categories with 4 Entities. Would you like to proceed?"
37 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_category_browser_property.gd:
--------------------------------------------------------------------------------
1 | extends EditorProperty
2 |
3 | # The main control for editing the property.
4 | var property_control := OptionButton.new()
5 | var ids_to_categories = {}
6 |
7 |
8 | func _init(class_data: Dictionary) -> void:
9 | # Add the control as a direct child of EditorProperty node.
10 | add_child.call_deferred(property_control)
11 | # Make sure the control is able to retain the focus.
12 | add_focusable(property_control)
13 | property_control.get_popup().id_pressed.connect(_on_id_selected)
14 |
15 | var id_counter = 0
16 | var all_categories = _find_all_categories(class_data["path"])
17 | var editor_plugin: EditorPlugin = Engine.get_meta("PandoraEditorPlugin", null)
18 | # Prevent button from expanding to selected icon size.
19 | property_control.set_expand_icon(true)
20 |
21 | for category in all_categories:
22 | property_control.get_popup().add_icon_item(
23 | load(category.get_icon_path()), category.get_entity_name(), id_counter
24 | )
25 | if editor_plugin:
26 | property_control.get_popup().set_item_icon_max_width(id_counter, editor_plugin.get_editor_interface().get_editor_scale() * 16)
27 | # Godot 4.1+
28 | if property_control.get_popup().has_method("set_item_icon_modulate"):
29 | property_control.get_popup().set_item_icon_modulate(id_counter, category.get_icon_color())
30 | ids_to_categories[id_counter] = category
31 | id_counter += 1
32 |
33 |
34 | func _on_id_selected(id: int) -> void:
35 | var category = ids_to_categories[id] as PandoraEntity
36 | var current_category = get_edited_object()[get_edited_property()] as PandoraEntity
37 |
38 | property_control.modulate = (
39 | current_category.get_icon_color() if current_category != null else Color.WHITE
40 | )
41 | if current_category != null and category.get_entity_id() == current_category.get_entity_id():
42 | # skip current entities
43 | return
44 |
45 | emit_changed(get_edited_property(), category)
46 |
47 |
48 | func _update_property() -> void:
49 | _update_deferred()
50 |
51 |
52 | func _update_deferred() -> void:
53 | var current_category = get_edited_object()[get_edited_property()] as PandoraEntity
54 | if current_category == null:
55 | property_control.select(-1)
56 | return
57 | for id in ids_to_categories.keys():
58 | if ids_to_categories[id].get_entity_id() == current_category.get_entity_id():
59 | property_control.select(id)
60 | property_control.modulate = current_category.get_icon_color()
61 | break
62 |
63 |
64 | ## Looks up all categories who are eligible for the given script path
65 | func _find_all_categories(script_path: String) -> Array[PandoraEntity]:
66 | # lookup entity data
67 | var categories = Pandora.get_all_categories()
68 | var all_categories: Array[PandoraEntity] = []
69 | for category in categories:
70 | if category._script_path == script_path:
71 | all_categories.append(category)
72 | if all_categories.is_empty():
73 | all_categories = Pandora.get_all_categories()
74 | return all_categories
75 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_category_browser_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://pfvrw0lbudp5
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_instance_browser_property.gd:
--------------------------------------------------------------------------------
1 | extends EditorProperty
2 |
3 | # The main control for editing the property.
4 | var property_control := OptionButton.new()
5 | var ids_to_entities = {}
6 |
7 |
8 | func _init(class_data: Dictionary) -> void:
9 | # Add the control as a direct child of EditorProperty node.
10 | add_child.call_deferred(property_control)
11 | # Make sure the control is able to retain the focus.
12 | add_focusable(property_control)
13 | property_control.get_popup().id_pressed.connect(_on_id_selected)
14 |
15 | var id_counter = 0
16 | var all_entities = _find_all_entities(class_data["path"])
17 | var editor_plugin: EditorPlugin = Engine.get_meta("PandoraEditorPlugin", null)
18 | # Prevent button from expanding to selected icon size.
19 | property_control.set_expand_icon(true)
20 |
21 | for entity in all_entities:
22 | property_control.get_popup().add_icon_item(
23 | load(entity.get_icon_path()), entity.get_entity_name(), id_counter
24 | )
25 | if editor_plugin:
26 | property_control.get_popup().set_item_icon_max_width(id_counter, editor_plugin.get_editor_interface().get_editor_scale() * 16)
27 | # Godot 4.1+
28 | if property_control.get_popup().has_method("set_item_icon_modulate"):
29 | property_control.get_popup().set_item_icon_modulate(id_counter, entity.get_icon_color())
30 | ids_to_entities[id_counter] = entity
31 | id_counter += 1
32 |
33 |
34 | func _on_id_selected(id: int) -> void:
35 | var entity = ids_to_entities[id] as PandoraEntity
36 | var current_entity = get_edited_object()[get_edited_property()] as PandoraEntity
37 |
38 | property_control.modulate = (
39 | current_entity.get_icon_color() if current_entity != null else Color.WHITE
40 | )
41 | if current_entity != null and entity.get_entity_id() == current_entity.get_entity_id():
42 | # skip current entities
43 | return
44 |
45 | emit_changed(get_edited_property(), entity)
46 |
47 |
48 | func _update_property() -> void:
49 | _update_deferred.call_deferred()
50 |
51 |
52 | func _update_deferred() -> void:
53 | var current_entity = get_edited_object()[get_edited_property()] as PandoraEntity
54 | if current_entity == null:
55 | property_control.select(-1)
56 | return
57 | for id in ids_to_entities.keys():
58 | if ids_to_entities[id].get_entity_id() == current_entity.get_entity_id():
59 | property_control.select(id)
60 | property_control.modulate = current_entity.get_icon_color()
61 | break
62 |
63 |
64 | ## Looks up all entities who are eligible for the given script path
65 | func _find_all_entities(script_path: String) -> Array[PandoraEntity]:
66 | # lookup entity data
67 | var categories = Pandora.get_all_categories()
68 | var all_entities: Array[PandoraEntity] = []
69 | for category in categories:
70 | if category._script_path == script_path:
71 | var entities = Pandora.get_all_entities(category)
72 | for entity in entities:
73 | if entity in all_entities: continue
74 | all_entities.append(entity)
75 | if all_entities.is_empty():
76 | all_entities = Pandora.get_all_entities()
77 | return all_entities
78 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_instance_browser_property.gd.uid:
--------------------------------------------------------------------------------
1 | uid://52wm80hygfi8
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_instance_inspector.gd:
--------------------------------------------------------------------------------
1 | extends EditorInspectorPlugin
2 |
3 | const EntityBrowserProperty = preload("./entity_instance_browser_property.gd")
4 | const CategoryBrowserProperty = preload("./entity_category_browser_property.gd")
5 |
6 | const PANDORA_ENTITY_CLASS = &"PandoraEntity"
7 | const PANDORA_CATEGORY_CLASS = &"PandoraCategory"
8 |
9 | # ClassName -> Dictionary
10 | var _global_class_cache = {}
11 |
12 |
13 | func _can_handle(object):
14 | return object != null
15 |
16 |
17 | func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):
18 | if _global_class_cache.is_empty():
19 | for global_class in ProjectSettings.get_global_class_list():
20 | _global_class_cache[global_class["class"]] = global_class
21 | if type == TYPE_OBJECT:
22 | if _is_pandora_category(hint_string):
23 | var inspector_property := CategoryBrowserProperty.new(_global_class_cache[hint_string])
24 | add_property_editor(name, inspector_property)
25 | return true
26 | elif _is_pandora_entity(hint_string):
27 | var inspector_property := EntityBrowserProperty.new(_global_class_cache[hint_string])
28 | add_property_editor(name, inspector_property)
29 | return true
30 | return false
31 | return false
32 |
33 |
34 | func _is_pandora_entity(clazz: String) -> bool:
35 | if clazz == PANDORA_ENTITY_CLASS:
36 | return true
37 | if clazz == "":
38 | return false
39 | var parent = _get_parent_class(clazz)
40 | if parent == null:
41 | return false
42 | if parent == PANDORA_ENTITY_CLASS:
43 | return true
44 | return _is_pandora_entity(parent)
45 |
46 |
47 | func _is_pandora_category(clazz: String) -> bool:
48 | if clazz == PANDORA_CATEGORY_CLASS:
49 | return true
50 | if clazz == "":
51 | return false
52 | var parent = _get_parent_class(clazz)
53 | if parent == null:
54 | return false
55 | if parent == PANDORA_CATEGORY_CLASS:
56 | return true
57 | return _is_pandora_category(parent)
58 |
59 |
60 | func _get_parent_class(clazz_name: String) -> String:
61 | if not _global_class_cache.has(clazz_name):
62 | return ""
63 | var clazz = _global_class_cache[clazz_name]
64 | if not _global_class_cache.has(clazz["base"]):
65 | return ""
66 | return _global_class_cache[clazz["base"]]["class"]
67 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/inspector/entity_instance_inspector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://wifxwa5oif5s
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/pandora_editor.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b4f7fhcompuon
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_editor/property_editor.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HSplitContainer
3 |
4 | ## called when the user intends to navigate to the
5 | ## original property of an inherited property.
6 | signal inherited_property_selected(category_id: String, property_name: String)
7 |
8 | const PropertyControlKvp = preload(
9 | "res://addons/pandora/ui/components/properties/property_control_kvp.tscn"
10 | )
11 | const PROPERTY_DEFAULT_NAME = "property"
12 |
13 | @onready var property_bar: PandoraPropertyBar = %PropertyBar
14 | @onready var property_list = %PropertyList
15 | @onready var unselected_container = %UnselectedContainer
16 | @onready var entity_attributes = %EntityAttributes
17 | @onready var property_settings_container = %PropertySettingsContainer
18 | @onready var scroll_container: ScrollContainer = %ScrollContainer
19 |
20 | var current_entity: PandoraEntity
21 |
22 |
23 | func _ready() -> void:
24 | property_bar.property_added.connect(_add_property)
25 | set_entity(null)
26 |
27 |
28 | ## if possible, attempt to edit the given property key.
29 | func edit_key(property_name: String) -> void:
30 | for property_control in property_list.get_children():
31 | var property = property_control._property
32 | if (
33 | property != null
34 | and property_name == property.get_property_name()
35 | and property.is_original()
36 | ):
37 | property_control.edit_key()
38 |
39 |
40 | func set_entity(entity: PandoraEntity) -> void:
41 | property_settings_container.visible = entity is PandoraCategory
42 | property_settings_container.set_property(null)
43 | for child in property_list.get_children():
44 | child.queue_free()
45 | self.current_entity = entity
46 | property_bar.visible = entity != null and entity is PandoraCategory
47 | property_list.visible = entity != null
48 | unselected_container.visible = entity == null
49 | entity_attributes.visible = entity != null
50 |
51 | if entity != null:
52 | entity_attributes.init(entity)
53 | var properties = entity.get_entity_properties()
54 |
55 | for property in properties:
56 | var scene = property_bar.get_scene_by_type(property.get_property_type().get_type_name())
57 | var control = scene.instantiate() as PandoraPropertyControl
58 | _add_property_control(control, property)
59 |
60 |
61 | func _add_property(scene: PackedScene) -> void:
62 | if not current_entity is PandoraCategory:
63 | print("Cannot add custom properties to non-categories!")
64 | return
65 | var control = scene.instantiate() as PandoraPropertyControl
66 | var property = Pandora.create_property(
67 | current_entity as PandoraCategory,
68 | _generate_property_name(control.type, current_entity),
69 | control.type
70 | )
71 | if property != null:
72 | _add_property_control(control, property)
73 |
74 |
75 | func _add_property_control(control: PandoraPropertyControl, property: PandoraProperty) -> void:
76 | var control_kvp = PropertyControlKvp.instantiate()
77 | control.init(property)
78 | control_kvp.init(property, control, Pandora._entity_backend)
79 | control_kvp.inherited_property_selected.connect(
80 | func(category_id: String, property_name: String): inherited_property_selected.emit(
81 | category_id, property_name
82 | )
83 | )
84 | property_list.add_child(control_kvp)
85 | control_kvp.property_key_edit.grab_focus()
86 | control_kvp.original_property_selected.connect(property_settings_container.set_property)
87 | await get_tree().process_frame
88 | # First scroll to the control node and then apply an offset.
89 | # It's important to wait a frame before scrolling as for the documentation.
90 | scroll_container.ensure_control_visible(control_kvp)
91 | scroll_container.scroll_vertical = scroll_container.scroll_vertical + 100
92 |
93 |
94 | func _generate_property_name(type: String, entity: PandoraEntity) -> String:
95 | var properties = entity.get_entity_properties()
96 | var property_name = type + " " + PROPERTY_DEFAULT_NAME
97 | if properties.is_empty() or not entity.has_entity_property(property_name):
98 | return property_name
99 | return property_name + str(properties.size())
100 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_editor/property_editor.gd.uid:
--------------------------------------------------------------------------------
1 | uid://df4b8473mfmny
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_editor/property_editor.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://clsxp8wg4ctet"]
2 |
3 | [ext_resource type="Script" uid="uid://df4b8473mfmny" path="res://addons/pandora/ui/editor/property_editor/property_editor.gd" id="1_r06w1"]
4 | [ext_resource type="PackedScene" uid="uid://8namx0kxhw0" path="res://addons/pandora/ui/components/property_bar/property_bar.tscn" id="1_vndtp"]
5 | [ext_resource type="PackedScene" uid="uid://ceqq28yvnhs2e" path="res://addons/pandora/ui/components/entity_attributes/entity_attributes.tscn" id="3_tosw7"]
6 | [ext_resource type="Texture2D" uid="uid://crgjwaubao8pj" path="res://addons/pandora/icons/icon.png" id="4_y2k2p"]
7 | [ext_resource type="PackedScene" uid="uid://c34sacps74dk3" path="res://addons/pandora/ui/editor/property_settings_editor/property_settings_editor.tscn" id="5_u6s37"]
8 |
9 | [node name="PropertyEditor" type="HSplitContainer"]
10 | offset_right = 519.0
11 | offset_bottom = 647.0
12 | size_flags_horizontal = 3
13 | size_flags_vertical = 3
14 | size_flags_stretch_ratio = 2.0
15 | script = ExtResource("1_r06w1")
16 |
17 | [node name="PropertyContainer" type="VBoxContainer" parent="."]
18 | layout_mode = 2
19 | size_flags_horizontal = 3
20 | size_flags_vertical = 3
21 |
22 | [node name="CaptionLabel" type="Label" parent="PropertyContainer"]
23 | layout_mode = 2
24 | theme_type_variation = &"HeaderSmall"
25 | text = "Properties"
26 |
27 | [node name="PanelContainer" type="PanelContainer" parent="PropertyContainer"]
28 | layout_mode = 2
29 |
30 | [node name="MarginContainer" type="MarginContainer" parent="PropertyContainer/PanelContainer"]
31 | layout_mode = 2
32 | theme_override_constants/margin_left = 5
33 | theme_override_constants/margin_top = 5
34 | theme_override_constants/margin_right = 5
35 | theme_override_constants/margin_bottom = 5
36 |
37 | [node name="HBoxContainer" type="HBoxContainer" parent="PropertyContainer/PanelContainer/MarginContainer"]
38 | layout_mode = 2
39 |
40 | [node name="PropertyBar" parent="PropertyContainer/PanelContainer/MarginContainer/HBoxContainer" instance=ExtResource("1_vndtp")]
41 | unique_name_in_owner = true
42 | visible = false
43 | layout_mode = 2
44 |
45 | [node name="ScrollContainer" type="ScrollContainer" parent="PropertyContainer"]
46 | unique_name_in_owner = true
47 | layout_mode = 2
48 | size_flags_vertical = 3
49 | follow_focus = true
50 |
51 | [node name="VBoxContainer" type="VBoxContainer" parent="PropertyContainer/ScrollContainer"]
52 | layout_mode = 2
53 | size_flags_horizontal = 3
54 | size_flags_vertical = 3
55 |
56 | [node name="PropertyList" type="VBoxContainer" parent="PropertyContainer/ScrollContainer/VBoxContainer"]
57 | unique_name_in_owner = true
58 | visible = false
59 | layout_mode = 2
60 | size_flags_horizontal = 3
61 | size_flags_vertical = 0
62 |
63 | [node name="UnselectedContainer" type="CenterContainer" parent="PropertyContainer/ScrollContainer/VBoxContainer"]
64 | unique_name_in_owner = true
65 | layout_mode = 2
66 | size_flags_horizontal = 3
67 | size_flags_vertical = 3
68 |
69 | [node name="VBoxContainer" type="VBoxContainer" parent="PropertyContainer/ScrollContainer/VBoxContainer/UnselectedContainer"]
70 | layout_mode = 2
71 | theme_override_constants/separation = 0
72 | alignment = 1
73 |
74 | [node name="TextureRect" type="TextureRect" parent="PropertyContainer/ScrollContainer/VBoxContainer/UnselectedContainer/VBoxContainer"]
75 | custom_minimum_size = Vector2(250, 250)
76 | layout_mode = 2
77 | size_flags_horizontal = 4
78 | size_flags_vertical = 0
79 | texture = ExtResource("4_y2k2p")
80 | expand_mode = 2
81 | stretch_mode = 5
82 |
83 | [node name="SpecialLabel" type="Label" parent="PropertyContainer/ScrollContainer/VBoxContainer/UnselectedContainer/VBoxContainer"]
84 | layout_mode = 2
85 | text = "Create or select a category or item to see its properties here."
86 | horizontal_alignment = 1
87 | vertical_alignment = 1
88 |
89 | [node name="EntityAttributes" parent="PropertyContainer/ScrollContainer/VBoxContainer" instance=ExtResource("3_tosw7")]
90 | unique_name_in_owner = true
91 | visible = false
92 | layout_mode = 2
93 | theme_override_constants/separation = 10
94 |
95 | [node name="PropertySettingsContainer" parent="." instance=ExtResource("5_u6s37")]
96 | unique_name_in_owner = true
97 | visible = false
98 | layout_mode = 2
99 | size_flags_stretch_ratio = 0.5
100 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends VBoxContainer
3 |
4 | const EntityPicker = preload("res://addons/pandora/ui/components/entity_picker/entity_picker.tscn")
5 |
6 | @onready var info_label = $InfoLabel
7 | @onready var header_label = $HeaderLabel
8 | @onready var properties_settings = $PropertiesSettings
9 |
10 | var _property: PandoraProperty
11 | var _default_settings: Dictionary
12 | var property_types_idx: Dictionary
13 |
14 |
15 | func set_property(property: PandoraProperty) -> void:
16 | for child in properties_settings.get_children():
17 | child.queue_free()
18 | properties_settings.get_children().clear()
19 | self._property = property
20 | if property:
21 | var property_type = property.get_property_type()
22 | if property_type.get_type_name() == "array":
23 | self._default_settings = property_type.get_merged_settings(property)
24 | else:
25 | self._default_settings = property_type.get_settings()
26 | else:
27 | self._default_settings = {}
28 | info_label.visible = property == null or not property.is_original()
29 | header_label.visible = not info_label.visible
30 |
31 | for default_setting_name in _default_settings:
32 | var setting = HBoxContainer.new()
33 | setting.size_flags_horizontal = Control.SIZE_EXPAND_FILL
34 | var label = Label.new()
35 | label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
36 | label.text = default_setting_name
37 | setting.add_child(label)
38 | var default_setting = _default_settings[default_setting_name]
39 | var current_value = (
40 | _property.get_setting_override(default_setting_name)
41 | if _property.has_setting_override(default_setting_name)
42 | else default_setting.value
43 | )
44 | var options: Array[Variant] = []
45 | options.assign(default_setting["options"] if default_setting.has("options") else [])
46 | var control = _new_control_for_type(
47 | default_setting_name,
48 | default_setting.type,
49 | options,
50 | default_setting.value,
51 | current_value
52 | )
53 | if control != null:
54 | control.size_flags_horizontal = Control.SIZE_EXPAND_FILL
55 | setting.add_child(control)
56 | properties_settings.add_child(setting)
57 | else:
58 | setting.queue_free()
59 | push_warning("Unsupported property setting type for " + str(default_setting_name))
60 |
61 |
62 | func _new_control_for_type(
63 | key: String,
64 | type: String,
65 | options: Array[Variant],
66 | default_value: Variant,
67 | current_value: Variant
68 | ) -> Control:
69 | if options.size() > 0:
70 | var option_button = OptionButton.new()
71 | var popup = option_button.get_popup()
72 | var options_to_index = {}
73 | var index = 0
74 | for option in options:
75 | popup.add_radio_check_item(str(option), index)
76 | options_to_index[option] = index
77 | index = index + 1
78 | option_button.select(options_to_index[current_value])
79 | popup.index_pressed.connect(func(index): _change_value(key, options[index], default_value))
80 | return option_button
81 | elif type == "string":
82 | var edit = LineEdit.new()
83 | edit.text = current_value as String
84 | edit.text_changed.connect(func(new): _change_value(key, new, default_value))
85 | return edit
86 | elif type == "color":
87 | var color_picker = ColorPickerButton.new()
88 | color_picker.color = current_value as Color
89 | color_picker.color_changed.connect(func(new): _change_value(key, new, default_value))
90 | return color_picker
91 | elif type == "int" or type == "float":
92 | var spin_box = SpinBox.new()
93 | spin_box.min_value = -999999999
94 | spin_box.max_value = 999999999
95 | spin_box.step = 0.01 if type == "float" else 1
96 | spin_box.custom_arrow_step = spin_box.step
97 | spin_box.rounded = type == "int"
98 | spin_box.value = current_value
99 | spin_box.value_changed.connect(func(new): _change_value(key, new, default_value))
100 | return spin_box
101 | elif type == "bool":
102 | var check_button = CheckButton.new()
103 | check_button.set_pressed(current_value as bool)
104 | check_button.toggled.connect(func(new): _change_value(key, new, default_value))
105 | return check_button
106 | elif type == "reference":
107 | var entity_picker = EntityPicker.instantiate()
108 | entity_picker.categories_only = true
109 | # pre-select category deferred since
110 | # data may not be available right now
111 | if current_value != "":
112 | _select_category_on_picker.call_deferred(entity_picker, current_value)
113 | entity_picker.entity_selected.connect(
114 | func(new): _change_value(key, new.get_entity_id(), default_value)
115 | )
116 | return entity_picker
117 | # pre-select category deferred since
118 | # data may not be available right now
119 | if current_value != "":
120 | _select_category_on_picker.call_deferred(entity_picker, current_value)
121 | entity_picker.entity_selected.connect(
122 | func(new): _change_value(key, new.get_entity_id(), default_value)
123 | )
124 | return entity_picker
125 | elif type == "property_type":
126 | var property_type_picker: OptionButton = OptionButton.new()
127 | var idx = 0
128 | for property_type in PandoraPropertyType.get_all_types():
129 | if property_type.allow_nesting():
130 | property_type_picker.add_icon_item(
131 | load(property_type.get_type_icon_path()), property_type.get_type_name(), idx
132 | )
133 | property_types_idx[idx] = property_type.get_type_name()
134 | idx += 1
135 | if current_value != "":
136 | _select_prop_type.call_deferred(property_type_picker, current_value)
137 | property_type_picker.item_selected.connect(
138 | func(idx): _change_value(key, property_types_idx[idx], default_value)
139 | )
140 | return property_type_picker
141 | return null
142 |
143 |
144 | func _change_value(key: String, new_value: Variant, default_value: Variant) -> void:
145 | if new_value == default_value and _property.has_setting_override(key):
146 | _property.clear_setting_override(key)
147 | elif new_value != default_value:
148 | _property.set_setting_override(key, new_value)
149 | _refresh()
150 |
151 |
152 | func _select_category_on_picker(picker, category_id: String) -> void:
153 | var category = Pandora.get_category(category_id)
154 | picker.select(category)
155 |
156 |
157 | func _select_prop_type(picker, prop_type: String) -> void:
158 | picker.select(property_types_idx.find_key(prop_type))
159 |
160 |
161 | func _refresh():
162 | set_property(_property)
163 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bp70tavbds3k8
2 |
--------------------------------------------------------------------------------
/addons/pandora/ui/editor/property_settings_editor/property_settings_editor.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://c34sacps74dk3"]
2 |
3 | [ext_resource type="Script" uid="uid://bp70tavbds3k8" path="res://addons/pandora/ui/editor/property_settings_editor/property_settings_editor.gd" id="1_drmqk"]
4 |
5 | [node name="PropertySettingsContainer" type="VBoxContainer"]
6 | size_flags_horizontal = 3
7 | size_flags_vertical = 3
8 | script = ExtResource("1_drmqk")
9 |
10 | [node name="InfoLabel" type="Label" parent="."]
11 | layout_mode = 2
12 | size_flags_vertical = 3
13 | text = "Select an editable property
14 | to see its configuration!"
15 | horizontal_alignment = 1
16 | vertical_alignment = 1
17 |
18 | [node name="HeaderLabel" type="Label" parent="."]
19 | layout_mode = 2
20 | theme_type_variation = &"HeaderSmall"
21 | text = "Property Settings"
22 |
23 | [node name="PropertiesSettings" type="VBoxContainer" parent="."]
24 | layout_mode = 2
25 |
--------------------------------------------------------------------------------
/addons/pandora/util/category_id_file_generator.gd:
--------------------------------------------------------------------------------
1 | const Tokenizer = preload("tokenizer.gd")
2 |
3 |
4 | class CategoryTuple:
5 | var category_name: String
6 | var category_id: String
7 |
8 | func _init(category_name: String, category_id: String) -> void:
9 | self.category_name = category_name
10 | self.category_id = category_id
11 |
12 |
13 | ## Generates a .gd file that allows for easier access
14 | ## of categories and subcategories of the data
15 | static func regenerate_category_id_file(root_categories: Array[PandoraCategory]) -> void:
16 | var root_category_tuples: Array[CategoryTuple] = generate_parent_category_tuples(root_categories)
17 | var subcategory_tuples: Dictionary = generate_sub_category_tuples(root_categories)
18 | generate_category_id_file(root_category_tuples, subcategory_tuples)
19 |
20 |
21 | static func generate_parent_category_tuples(root_categories: Array[PandoraCategory]) -> Array[CategoryTuple]:
22 | var root_category_tuples: Array[CategoryTuple] = []
23 | for category in root_categories:
24 | root_category_tuples.append(CategoryTuple.new(category.get_entity_name(), category.get_entity_id()))
25 | return root_category_tuples
26 |
27 |
28 | static func generate_sub_category_tuples(root_categories: Array[PandoraCategory]) -> Dictionary:
29 | var subcategory_tuples = {}
30 | for category in root_categories:
31 | _process_sub_category_tuples(category.get_entity_name(), category._children, subcategory_tuples)
32 | return subcategory_tuples
33 |
34 |
35 | static func _process_sub_category_tuples(
36 | parent_category: String, entities: Array[PandoraEntity], subcategory_tuples: Dictionary) -> void:
37 | var local_subcategories = []
38 |
39 | for entity in entities:
40 | if entity is PandoraCategory:
41 | var entity_name = entity.get_entity_name()
42 | var entity_id = entity.get_entity_id()
43 | var category_tuple = CategoryTuple.new(entity_name, entity_id)
44 | var new_key = parent_category + "_" + entity_name
45 |
46 | _process_sub_category_tuples(new_key, entity._children, subcategory_tuples)
47 |
48 | # Add current category to the local list if it's a leaf or has children
49 | if not subcategory_tuples.has(new_key) or subcategory_tuples[new_key].size() == 0:
50 | subcategory_tuples.erase(new_key) # Remove if empty
51 | local_subcategories.append(category_tuple)
52 |
53 | if local_subcategories.size() > 0:
54 | subcategory_tuples[parent_category] = local_subcategories
55 |
56 |
57 |
58 | static func generate_category_id_file(
59 | root_category_tuples: Array[CategoryTuple], subcategory_tuples: Dictionary) -> void:
60 | var file_path = "res://pandora/categories.gd"
61 | if not DirAccess.dir_exists_absolute("res://pandora"):
62 | DirAccess.make_dir_absolute("res://pandora")
63 |
64 | var file_access = FileAccess.open(file_path, FileAccess.WRITE)
65 | file_access.store_line("# Do not modify! Auto-generated file.")
66 | file_access.store_line("class_name PandoraCategories\n\n")
67 |
68 | for category_tuple in root_category_tuples:
69 | var line = 'const %s = "%s"' % [Tokenizer.tokenize(category_tuple.category_name), category_tuple.category_id]
70 | file_access.store_line(line)
71 |
72 | file_access.store_line("\n")
73 | for parent_category in subcategory_tuples:
74 | if subcategory_tuples[parent_category].size() == 0:
75 | continue
76 | var line = "class %sCategories:" % parent_category.to_pascal_case()
77 | file_access.store_line(line)
78 | for category_tuple in subcategory_tuples[parent_category]:
79 | line = ' const %s = "%s"' % [Tokenizer.tokenize(category_tuple.category_name), category_tuple.category_id]
80 | file_access.store_line(line)
81 | file_access.store_line("\n")
82 | file_access.close()
83 |
--------------------------------------------------------------------------------
/addons/pandora/util/category_id_file_generator.gd.uid:
--------------------------------------------------------------------------------
1 | uid://wti0o7u6m7l7
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/compression.gd:
--------------------------------------------------------------------------------
1 | const BLOCK_SIZE = 4096
2 | const MAGIC = "GCPF"
3 |
4 |
5 | ## magic
6 | ## char[4] "GCPF"
7 | ##
8 | ## header
9 | ## uint32_t compression_mode (Compression::MODE_ZSTD by default)
10 | ## uint32_t block_size (4096 by default)
11 | ## uint32_t uncompressed_size
12 | ##
13 | ## block compressed sizes, number of blocks = (uncompressed_size / block_size) + 1
14 | ## uint32_t block_sizes[]
15 | ##
16 | ## followed by compressed block data, same as calling `compress` for each source `block_size`
17 | static func compress(text: String, compression_mode:FileAccess.CompressionMode = FileAccess.COMPRESSION_FASTLZ) -> PackedByteArray:
18 | var data = _encode_string(text)
19 | var uncompressed_size = data.size()
20 |
21 | var num_blocks = int(ceil(float(uncompressed_size) / BLOCK_SIZE))
22 |
23 | var buffer = PackedByteArray()
24 |
25 | buffer.append_array(_encode_string(MAGIC))
26 |
27 | buffer.append_array(_encode_uint32(compression_mode))
28 | buffer.append_array(_encode_uint32(BLOCK_SIZE))
29 | buffer.append_array(_encode_uint32(uncompressed_size))
30 |
31 | var block_sizes = PackedByteArray()
32 | var compressed_blocks = []
33 |
34 | for i in range(num_blocks):
35 | var start = i * BLOCK_SIZE
36 | var end = min((i + 1) * BLOCK_SIZE, uncompressed_size)
37 | var block_data = PackedByteArray()
38 | var block_index = start
39 | while block_index < end:
40 | block_data.append(data[block_index])
41 | block_index += 1
42 |
43 | var compressed_block = block_data.compress(compression_mode)
44 | block_sizes.append_array(_encode_uint32(compressed_block.size()))
45 | compressed_blocks.append(compressed_block)
46 |
47 | buffer.append_array(block_sizes)
48 |
49 | for block in compressed_blocks:
50 | buffer.append_array(block)
51 |
52 | return buffer
53 |
54 |
55 | static func _encode_uint32(value: int) -> PackedByteArray:
56 | var arr = PackedByteArray()
57 | arr.append(value & 0xFF)
58 | arr.append((value >> 8) & 0xFF)
59 | arr.append((value >> 16) & 0xFF)
60 | arr.append((value >> 24) & 0xFF)
61 | return arr
62 |
63 |
64 | static func _encode_string(value: String) -> PackedByteArray:
65 | var arr = PackedByteArray()
66 | for char in value:
67 | arr.append_array(char.to_ascii_buffer())
68 | return arr
69 |
--------------------------------------------------------------------------------
/addons/pandora/util/compression.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bwxfd2vjspwsh
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/entity_id_file_generator.gd:
--------------------------------------------------------------------------------
1 | const Tokenizer = preload("tokenizer.gd")
2 |
3 | static func regenerate_id_files(root_categories: Array[PandoraCategory]) -> void:
4 | var class_to_entity_map = generate_class_to_entity_map(root_categories)
5 | for entity_class in class_to_entity_map:
6 | var file_content = generate_entity_id_file(entity_class, class_to_entity_map[entity_class])
7 | if not file_content.is_empty():
8 | _write_to_file(entity_class, file_content)
9 |
10 | static func generate_class_to_entity_map(root_categories: Array[PandoraCategory]) -> Dictionary:
11 | var class_to_entity_map = {}
12 | for category in root_categories:
13 | _process_category_for_id_files(category, class_to_entity_map)
14 |
15 | # Remove empty entries from the map
16 | var keys_to_remove = []
17 | for key in class_to_entity_map.keys():
18 | if class_to_entity_map[key].size() == 0:
19 | keys_to_remove.append(key)
20 | for key in keys_to_remove:
21 | class_to_entity_map.erase(key)
22 |
23 | return class_to_entity_map
24 |
25 | static func generate_entity_id_file(entity_class_name: String, entities: Array[PandoraEntity]) -> Array[String]:
26 | if entities.is_empty():
27 | return []
28 | var lines:Array[String] = ["# Do not modify! Auto-generated file.", "class_name " + entity_class_name + "\n\n"]
29 | var name_usages = {}
30 | for entity in entities:
31 | var entity_name = entity.get_entity_name()
32 | if not name_usages.has(entity_name):
33 | name_usages[entity_name] = 0
34 | else:
35 | name_usages[entity_name] += 1
36 | entity_name += str(name_usages[entity_name])
37 | lines.append("const " + Tokenizer.tokenize(entity_name) + ' = "' + entity.get_entity_id() + '"')
38 | return lines
39 |
40 | static func _process_category_for_id_files(category: PandoraCategory, class_to_entity_map: Dictionary) -> void:
41 | var classname = category.get_id_generation_class()
42 | if not class_to_entity_map.has(classname):
43 | var empty:Array[PandoraEntity] = []
44 | class_to_entity_map[classname] = empty
45 |
46 | if category.is_generate_ids():
47 | for child in category._children:
48 | if not child is PandoraCategory:
49 | if not _entity_exists_in_map(class_to_entity_map[classname], child):
50 | class_to_entity_map[classname].append(child)
51 | else:
52 | _process_category_for_id_files(child as PandoraCategory, class_to_entity_map)
53 |
54 | for child in category._children:
55 | if child is PandoraCategory:
56 | var child_classname = child.get_id_generation_class()
57 | if class_to_entity_map.has(child_classname):
58 | for sub_entity in class_to_entity_map[child_classname]:
59 | if not _entity_exists_in_map(class_to_entity_map[classname], sub_entity):
60 | class_to_entity_map[classname].append(sub_entity)
61 |
62 | static func _entity_exists_in_map(entity_list: Array[PandoraEntity], entity: PandoraEntity) -> bool:
63 | for e in entity_list:
64 | if e.get_entity_id() == entity.get_entity_id():
65 | return true
66 | return false
67 |
68 | static func _write_to_file(entity_class_name: String, lines: Array[String]) -> void:
69 | var file_path = "res://pandora/" + entity_class_name.to_snake_case() + ".gd"
70 | if not DirAccess.dir_exists_absolute("res://pandora"):
71 | DirAccess.make_dir_absolute("res://pandora")
72 |
73 | var file = FileAccess.open(file_path, FileAccess.WRITE)
74 | if FileAccess.get_open_error() == OK:
75 | for line in lines:
76 | file.store_line(line)
77 | file.close()
78 | else:
79 | print("Failed to open file for writing: " + file_path)
80 |
--------------------------------------------------------------------------------
/addons/pandora/util/entity_id_file_generator.gd.uid:
--------------------------------------------------------------------------------
1 | uid://ra4xv74fia7e
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/id_generator.gd:
--------------------------------------------------------------------------------
1 | class_name PandoraIDGenerator
2 | extends RefCounted
3 |
4 | var _nanoid := PandoraNanoIDGenerator.new(10)
5 | var _sequential := PandoraSequentialIDGenerator.new()
6 |
7 |
8 | func generate() -> String:
9 | var id_type := PandoraSettings.get_id_type()
10 | match id_type:
11 | PandoraSettings.IDType.SEQUENTIAL:
12 | return _sequential.generate()
13 | PandoraSettings.IDType.NANOID:
14 | return _nanoid.generate()
15 | push_error("unknown id type: %s" % id_type)
16 | return _sequential.generate()
17 |
18 |
19 | func clear() -> void:
20 | _sequential.clear()
21 |
22 |
23 | func save_data() -> Dictionary:
24 | return _sequential.save_data()
25 |
26 |
27 | func load_data(data: Dictionary) -> void:
28 | _sequential.load_data(data)
29 |
--------------------------------------------------------------------------------
/addons/pandora/util/id_generator.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dr36cdy1l3e1d
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/nanoid_generator.gd:
--------------------------------------------------------------------------------
1 | # inspired by github.com/eth0net/nanoid-godot (MIT) v0.2.0
2 | class_name PandoraNanoIDGenerator
3 | extends RefCounted
4 |
5 | const ALPHABET := "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"
6 | const DEFAULT_LENGTH := 21
7 |
8 | var default_length := DEFAULT_LENGTH
9 |
10 |
11 | func _init(length := DEFAULT_LENGTH) -> void:
12 | default_length = length
13 |
14 |
15 | func generate(length := default_length) -> String:
16 | var id: String
17 | for i in range(length):
18 | id += ALPHABET[randi() % ALPHABET.length()]
19 | return id
20 |
--------------------------------------------------------------------------------
/addons/pandora/util/nanoid_generator.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dnafvia3jdolr
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/script_util.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | const PandoraEntityScript = preload("res://addons/pandora/model/entity.gd")
4 |
5 |
6 | static func create_entity_from_script(
7 | path: String, id: String, name: String, icon_path: String, category_id: String
8 | ):
9 | var clazz = _get_entity_class(path)
10 | var new_method = _find_first_method_of_script(clazz, "init_entity")
11 | if not new_method.has("args"):
12 | push_warning("ERROR - Pandora is unable to correctly resolve new() method.")
13 | var entity = PandoraEntityScript.new()
14 | entity.init_entity(id, name, icon_path, category_id)
15 | return entity
16 | var expected_method = _find_first_method_of_script(PandoraEntityScript, "init_entity")
17 | if new_method["args"].size() != expected_method["args"].size():
18 | push_warning(
19 | (
20 | "init_entity() method has incorrect signature! Requires "
21 | + str(expected_method["args"].size())
22 | + " arguments - defaulting to PandoraEntity instead."
23 | )
24 | )
25 | var entity = PandoraEntityScript.new()
26 | entity.init_entity(id, name, icon_path, category_id)
27 | return entity
28 |
29 | var entity = clazz.new()
30 | if not entity is PandoraEntity:
31 | push_warning(
32 | "Script '" + path + "' must extend PandoraEntity - defaulting to PandoraEntity instead."
33 | )
34 | entity = PandoraEntityScript.new()
35 |
36 | entity.init_entity(id, name, icon_path, category_id)
37 | return entity
38 |
39 |
40 | static func _get_entity_class(path: String) -> GDScript:
41 | var EntityClass = load(path)
42 | if EntityClass == null or not EntityClass.can_instantiate():
43 | push_warning("Unable to find " + path + " - defaulting to PandoraEntity instead.")
44 | EntityClass = PandoraEntityScript
45 | return EntityClass
46 |
47 |
48 | ## searches for the first occurence of the method.
49 | ## methods can occur multiple times in the order of inheritance.
50 | static func _find_first_method_of_script(script: GDScript, method_name: String) -> Dictionary:
51 | for method in script.get_script_method_list():
52 | if method.name == method_name:
53 | return method
54 | return {}
55 |
--------------------------------------------------------------------------------
/addons/pandora/util/script_util.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cmv0h32r644wp
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/sequential_id_generator.gd:
--------------------------------------------------------------------------------
1 | class_name PandoraSequentialIDGenerator
2 | extends RefCounted
3 |
4 | const DEFAULT_CONTEXT: String = "default"
5 |
6 | var _ids_by_context: Dictionary = {}
7 |
8 |
9 | func generate(context: String = DEFAULT_CONTEXT) -> String:
10 | if not _ids_by_context.has(context):
11 | _ids_by_context[context] = 0
12 | _ids_by_context[context] += 1
13 | return str(_ids_by_context[context])
14 |
15 |
16 | func clear() -> void:
17 | _ids_by_context.clear()
18 |
19 |
20 | func save_data() -> Dictionary:
21 | return {"_ids_by_context": _ids_by_context}
22 |
23 |
24 | func load_data(data: Dictionary) -> void:
25 | _ids_by_context = data["_ids_by_context"]
26 |
--------------------------------------------------------------------------------
/addons/pandora/util/sequential_id_generator.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgb1rend0hi7r
2 |
--------------------------------------------------------------------------------
/addons/pandora/util/tokenizer.gd:
--------------------------------------------------------------------------------
1 | static var regex:RegEx
2 |
3 | ## Converts any string into a GDScript-valid token (cannot contain special characters)
4 | static func tokenize(value:String) -> String:
5 | if regex == null:
6 | regex = RegEx.new()
7 | regex.compile("(^[^A-Z_\u4e00-\u9fa5])|([^A-Z0-9_\u4e00-\u9fa5])")
8 | var token = value.to_upper()
9 |
10 | var regex_matches = regex.search_all(token)
11 | var offset = 0
12 | for regex_match in regex_matches:
13 | var start = regex_match.get_start()
14 | var end = regex_match.get_end()
15 | var length = end - start
16 | var text = token.substr(start + offset, length)
17 | var replacement = "_"
18 | token = token.substr(0, start + offset) + replacement + token.substr(end + offset)
19 | offset += replacement.length() - text.length()
20 |
21 | return token
22 |
--------------------------------------------------------------------------------
/addons/pandora/util/tokenizer.gd.uid:
--------------------------------------------------------------------------------
1 | uid://diww4ex65mx8k
2 |
--------------------------------------------------------------------------------