From 6d7282f5cb4f4fb4ce8dfa6945e10b3bbdbcb97c Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 13 Mar 2025 13:29:13 +0100 Subject: [PATCH] Tabbed inventory --- Resources/Items/Ammo1.tres | 6 +- Resources/Items/Blue_Keycard.tres | 6 +- Resources/Items/Cheat_Gun_Item.tres | 8 +- Resources/Items/Green_Keycard.tres | 6 +- Resources/Items/Green_Points_Pickup.tres | 8 +- Resources/Items/Heart_Pickup.tres | 7 +- Resources/Items/IceShotgun.tres | 8 +- Resources/Items/IcicleGun.tres | 7 +- Resources/Items/IcicleRepeater.tres | 8 +- Resources/Items/Money_Pickup.tres | 10 +- Resources/Items/Points_Pickup.tres | 8 +- Resources/Items/Power_Pickup.tres | 8 +- Resources/Items/Red_Keycard.tres | 6 +- Resources/Items/Shield_Pickup.tres | 8 +- Resources/Items/Spider_Bomb_Pickup.tres | 12 +- Resources/Items/Yin_Yang_Ammo.tres | 6 +- Resources/Items/Yin_Yang_Gun_Pickup.tres | 6 +- Resources/Items/Yin_Yang_Orb.tres | 6 +- Resources/Weapons/Cheat_Gun.tres | 6 +- Resources/Weapons/Ice_Shotgun_Weapon.tres | 6 +- Resources/Weapons/IcicleGun.tres | 6 +- Resources/Weapons/IcicleRepeater.tres | 6 +- Resources/Weapons/Spider_Bomb.tres | 6 +- Resources/Weapons/Yin_Yang_Gun.tres | 6 +- Scenes/HUD/HUD.tscn | 75 ++- Scenes/Interactable.cs | 2 +- Scenes/Maps/PlayerFSMTest.tscn | 2 +- Scenes/test.tscn | 4 +- Scripts/InventoryManager.cs | 8 +- Scripts/Resources/LootItem.cs | 6 +- Scripts/Resources/WeaponResource.cs | 6 +- Scripts/UI/InventoryMenu.cs | 98 +++ Scripts/UI/InventoryMenu.cs.uid | 1 + Scripts/UI/ItemsMenu.cs | 129 ++-- addons/resources_spreadsheet_view/LICENSE.md | 9 + .../editor_color_setter.gd | 6 + .../editor_color_setter.gd.uid | 1 + .../editor_icon_button.gd | 12 + .../editor_icon_button.gd.uid | 1 + .../editor_resource_array_picker.gd | 69 ++ .../editor_resource_array_picker.gd.uid | 1 + .../resources_spreadsheet_view/editor_view.gd | 527 +++++++++++++++ .../editor_view.gd.uid | 1 + .../editor_view.tscn | 606 ++++++++++++++++++ .../import_export/formats_edit/edit_base.gd | 36 ++ .../formats_edit/edit_base.gd.uid | 1 + .../import_export/formats_edit/edit_csv.gd | 88 +++ .../formats_edit/edit_csv.gd.uid | 1 + .../import_export/formats_edit/edit_tres.gd | 119 ++++ .../formats_edit/edit_tres.gd.uid | 1 + .../formats_export/export_csv.gd | 32 + .../formats_export/export_csv.gd.uid | 1 + .../formats_import/import_csv.gd | 57 ++ .../formats_import/import_csv.gd.uid | 1 + .../import_export/import_export_dialog.gd | 241 +++++++ .../import_export/import_export_dialog.gd.uid | 1 + .../import_export/import_export_dialog.tscn | 240 +++++++ .../import_export_enum_format.gd | 30 + .../import_export_enum_format.gd.uid | 1 + .../import_export_enum_format.tscn | 68 ++ .../import_export/property_list_item.gd | 12 + .../import_export/property_list_item.gd.uid | 1 + .../import_export/property_list_item.tscn | 36 ++ .../import_export/spreadsheet_import.gd | 430 +++++++++++++ .../import_export/spreadsheet_import.gd.uid | 1 + .../main_screen/class_filter.gd | 146 +++++ .../main_screen/class_filter.gd.uid | 1 + .../main_screen/column_header_manager.gd | 189 ++++++ .../main_screen/column_header_manager.gd.uid | 1 + .../main_screen/expression_textfield.gd | 173 +++++ .../main_screen/expression_textfield.gd.uid | 1 + .../main_screen/frozen_columns.gd | 60 ++ .../main_screen/frozen_columns.gd.uid | 1 + .../main_screen/input_handler.gd | 148 +++++ .../main_screen/input_handler.gd.uid | 1 + .../main_screen/recent_paths.gd | 54 ++ .../main_screen/recent_paths.gd.uid | 1 + .../main_screen/selection_actions.gd | 191 ++++++ .../main_screen/selection_actions.gd.uid | 1 + .../main_screen/selection_actions.tscn | 191 ++++++ .../main_screen/selection_manager.gd | 303 +++++++++ .../main_screen/selection_manager.gd.uid | 1 + .../main_screen/table_header.gd | 72 +++ .../main_screen/table_header.gd.uid | 1 + .../main_screen/table_header.tscn | 23 + .../main_screen/table_pages.gd | 118 ++++ .../main_screen/table_pages.gd.uid | 1 + addons/resources_spreadsheet_view/plugin.cfg | 9 + addons/resources_spreadsheet_view/plugin.gd | 43 ++ .../resources_spreadsheet_view/plugin.gd.uid | 1 + .../saved_state.json | 57 ++ .../settings_grid.gd | 39 ++ .../settings_grid.gd.uid | 1 + .../settings_grid.tscn | 141 ++++ .../text_editing_utils.gd | 192 ++++++ .../text_editing_utils.gd.uid | 1 + .../typed_cells/array.tscn | 36 ++ .../typed_cells/basic.tscn | 33 + .../typed_cells/cell_editor.gd | 46 ++ .../typed_cells/cell_editor.gd.uid | 1 + .../typed_cells/cell_editor_array.gd | 64 ++ .../typed_cells/cell_editor_array.gd.uid | 1 + .../typed_cells/cell_editor_bool.gd | 34 + .../typed_cells/cell_editor_bool.gd.uid | 1 + .../typed_cells/cell_editor_color.gd | 43 ++ .../typed_cells/cell_editor_color.gd.uid | 1 + .../typed_cells/cell_editor_dict.gd | 51 ++ .../typed_cells/cell_editor_dict.gd.uid | 1 + .../typed_cells/cell_editor_enum.gd | 38 ++ .../typed_cells/cell_editor_enum.gd.uid | 1 + .../typed_cells/cell_editor_enum_array.gd | 39 ++ .../typed_cells/cell_editor_enum_array.gd.uid | 1 + .../typed_cells/cell_editor_number.gd | 13 + .../typed_cells/cell_editor_number.gd.uid | 1 + .../typed_cells/cell_editor_resource.gd | 73 +++ .../typed_cells/cell_editor_resource.gd.uid | 1 + .../typed_cells/cell_editor_string.gd | 13 + .../typed_cells/cell_editor_string.gd.uid | 1 + .../typed_cells/resource.tscn | 45 ++ .../typed_editors/dock_array.gd | 252 ++++++++ .../typed_editors/dock_array.gd.uid | 1 + .../typed_editors/dock_array.tscn | 195 ++++++ .../typed_editors/dock_base.gd | 50 ++ .../typed_editors/dock_base.gd.uid | 1 + .../typed_editors/dock_color.gd | 139 ++++ .../typed_editors/dock_color.gd.uid | 1 + .../typed_editors/dock_color.tscn | 295 +++++++++ .../typed_editors/dock_dict.gd | 201 ++++++ .../typed_editors/dock_dict.gd.uid | 1 + .../typed_editors/dock_dict.tscn | 226 +++++++ .../typed_editors/dock_enum_array.gd | 137 ++++ .../typed_editors/dock_enum_array.gd.uid | 1 + .../typed_editors/dock_enum_array.tscn | 117 ++++ .../typed_editors/dock_number.gd | 188 ++++++ .../typed_editors/dock_number.gd.uid | 1 + .../typed_editors/dock_number.tscn | 265 ++++++++ .../typed_editors/dock_texture.gd | 39 ++ .../typed_editors/dock_texture.gd.uid | 1 + .../typed_editors/dock_texture.tscn | 101 +++ example/Items/item_icons/items.png | 3 + example/Items/item_icons/items.png.import | 34 + example/Items/item_type.gd | 32 + example/Items/item_type.gd.uid | 1 + example/Items/items/arrows.tres | 19 + example/Items/items/belt_1.tres | 28 + example/Items/items/belt_2.tres | 28 + example/Items/items/chestplate_1.tres | 28 + example/Items/items/chestplate_2.tres | 29 + example/Items/items/coin_gold.tres | 19 + example/Items/items/coin_purple.tres | 21 + example/Items/items/feather.tres | 19 + example/Items/items/gem_blue.tres | 19 + example/Items/items/head_helmet.tres | 28 + example/Items/items/head_wizardhat.tres | 28 + example/Items/items/herb.tres | 19 + example/Items/items/leather.tres | 19 + example/Items/items/magic_crystal.tres | 21 + example/Items/items/melee_battleaxe.tres | 29 + example/Items/items/melee_sword.tres | 29 + example/Items/items/metalscrap_copper.tres | 19 + example/Items/items/metalscrap_gold.tres | 24 + example/Items/items/metalscrap_iron.tres | 19 + example/Items/items/metalscrap_wyvernite.tres | 21 + example/Items/items/potion_blue.tres | 24 + example/Items/items/potion_purple.tres | 21 + example/Items/items/potion_red.tres | 21 + example/Items/items/ring_1.tres | 28 + example/Items/items/ring_2.tres | 28 + example/Items/items/scroll_enchant.tres | 21 + example/Items/items/wand_purple.tres | 28 + example/Items/items/wand_red.tres | 28 + example/Items/items/wood.tres | 19 + example/Random Upgrades/icons/all_icons.png | 3 + .../icons/all_icons.png.import | 34 + .../icons/all_icons/all_icons_1.tres | 7 + .../icons/all_icons/all_icons_10.tres | 7 + .../icons/all_icons/all_icons_11.tres | 7 + .../icons/all_icons/all_icons_12.tres | 7 + .../icons/all_icons/all_icons_13.tres | 7 + .../icons/all_icons/all_icons_14.tres | 7 + .../icons/all_icons/all_icons_15.tres | 7 + .../icons/all_icons/all_icons_16.tres | 7 + .../icons/all_icons/all_icons_2.tres | 7 + .../icons/all_icons/all_icons_3.tres | 7 + .../icons/all_icons/all_icons_4.tres | 7 + .../icons/all_icons/all_icons_5.tres | 7 + .../icons/all_icons/all_icons_6.tres | 7 + .../icons/all_icons/all_icons_7.tres | 7 + .../icons/all_icons/all_icons_8.tres | 7 + .../icons/all_icons/all_icons_9.tres | 7 + example/Random Upgrades/new scene.tscn | 31 + example/Random Upgrades/upgrade_data.gd | 30 + example/Random Upgrades/upgrade_data.gd.uid | 1 + .../Random Upgrades/upgrade_data_weapon.gd | 16 + .../upgrade_data_weapon.gd.uid | 1 + .../Random Upgrades/upgrades/elemental.tres | 25 + example/Random Upgrades/upgrades/health.tres | 25 + .../upgrades/mastery_magic.tres | 29 + .../upgrades/mastery_strength.tres | 29 + example/Random Upgrades/upgrades/up_aoe.tres | 26 + .../Random Upgrades/upgrades/up_magic.tres | 25 + .../upgrades/up_movement_speed.tres | 26 + .../Random Upgrades/upgrades/up_strength.tres | 25 + .../upgrades/weapons/weapon_axe.tres | 28 + .../upgrades/weapons/weapon_blizzard.tres | 28 + .../upgrades/weapons/weapon_chaos_blast.tres | 30 + .../upgrades/weapons/weapon_dagger.tres | 28 + .../upgrades/weapons/weapon_fireball.tres | 28 + .../upgrades/weapons/weapon_giga_sword.tres | 30 + .../upgrades/weapons/weapon_lightning.tres | 28 + .../upgrades/weapons/weapon_spear.tres | 28 + .../Random Upgrades/upgrades_csv/upgrades.csv | 33 + .../upgrades_csv/upgrades.csv.import | 3 + project.godot | 15 +- 214 files changed, 9329 insertions(+), 186 deletions(-) create mode 100644 Scripts/UI/InventoryMenu.cs create mode 100644 Scripts/UI/InventoryMenu.cs.uid create mode 100644 addons/resources_spreadsheet_view/LICENSE.md create mode 100644 addons/resources_spreadsheet_view/editor_color_setter.gd create mode 100644 addons/resources_spreadsheet_view/editor_color_setter.gd.uid create mode 100644 addons/resources_spreadsheet_view/editor_icon_button.gd create mode 100644 addons/resources_spreadsheet_view/editor_icon_button.gd.uid create mode 100644 addons/resources_spreadsheet_view/editor_resource_array_picker.gd create mode 100644 addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid create mode 100644 addons/resources_spreadsheet_view/editor_view.gd create mode 100644 addons/resources_spreadsheet_view/editor_view.gd.uid create mode 100644 addons/resources_spreadsheet_view/editor_view.tscn create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd create mode 100644 addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd create mode 100644 addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd create mode 100644 addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_dialog.gd create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn create mode 100644 addons/resources_spreadsheet_view/import_export/property_list_item.gd create mode 100644 addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid create mode 100644 addons/resources_spreadsheet_view/import_export/property_list_item.tscn create mode 100644 addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd create mode 100644 addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/class_filter.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/column_header_manager.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/expression_textfield.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/frozen_columns.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/input_handler.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/recent_paths.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/selection_actions.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/selection_actions.tscn create mode 100644 addons/resources_spreadsheet_view/main_screen/selection_manager.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/table_header.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/table_header.gd.uid create mode 100644 addons/resources_spreadsheet_view/main_screen/table_header.tscn create mode 100644 addons/resources_spreadsheet_view/main_screen/table_pages.gd create mode 100644 addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid create mode 100644 addons/resources_spreadsheet_view/plugin.cfg create mode 100644 addons/resources_spreadsheet_view/plugin.gd create mode 100644 addons/resources_spreadsheet_view/plugin.gd.uid create mode 100644 addons/resources_spreadsheet_view/saved_state.json create mode 100644 addons/resources_spreadsheet_view/settings_grid.gd create mode 100644 addons/resources_spreadsheet_view/settings_grid.gd.uid create mode 100644 addons/resources_spreadsheet_view/settings_grid.tscn create mode 100644 addons/resources_spreadsheet_view/text_editing_utils.gd create mode 100644 addons/resources_spreadsheet_view/text_editing_utils.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/array.tscn create mode 100644 addons/resources_spreadsheet_view/typed_cells/basic.tscn create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd create mode 100644 addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_cells/resource.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_array.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_array.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_base.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_color.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_color.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_dict.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_number.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_number.tscn create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_texture.gd create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid create mode 100644 addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn create mode 100644 example/Items/item_icons/items.png create mode 100644 example/Items/item_icons/items.png.import create mode 100644 example/Items/item_type.gd create mode 100644 example/Items/item_type.gd.uid create mode 100644 example/Items/items/arrows.tres create mode 100644 example/Items/items/belt_1.tres create mode 100644 example/Items/items/belt_2.tres create mode 100644 example/Items/items/chestplate_1.tres create mode 100644 example/Items/items/chestplate_2.tres create mode 100644 example/Items/items/coin_gold.tres create mode 100644 example/Items/items/coin_purple.tres create mode 100644 example/Items/items/feather.tres create mode 100644 example/Items/items/gem_blue.tres create mode 100644 example/Items/items/head_helmet.tres create mode 100644 example/Items/items/head_wizardhat.tres create mode 100644 example/Items/items/herb.tres create mode 100644 example/Items/items/leather.tres create mode 100644 example/Items/items/magic_crystal.tres create mode 100644 example/Items/items/melee_battleaxe.tres create mode 100644 example/Items/items/melee_sword.tres create mode 100644 example/Items/items/metalscrap_copper.tres create mode 100644 example/Items/items/metalscrap_gold.tres create mode 100644 example/Items/items/metalscrap_iron.tres create mode 100644 example/Items/items/metalscrap_wyvernite.tres create mode 100644 example/Items/items/potion_blue.tres create mode 100644 example/Items/items/potion_purple.tres create mode 100644 example/Items/items/potion_red.tres create mode 100644 example/Items/items/ring_1.tres create mode 100644 example/Items/items/ring_2.tres create mode 100644 example/Items/items/scroll_enchant.tres create mode 100644 example/Items/items/wand_purple.tres create mode 100644 example/Items/items/wand_red.tres create mode 100644 example/Items/items/wood.tres create mode 100644 example/Random Upgrades/icons/all_icons.png create mode 100644 example/Random Upgrades/icons/all_icons.png.import create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_1.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_10.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_11.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_12.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_13.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_14.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_15.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_16.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_2.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_3.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_4.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_5.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_6.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_7.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_8.tres create mode 100644 example/Random Upgrades/icons/all_icons/all_icons_9.tres create mode 100644 example/Random Upgrades/new scene.tscn create mode 100644 example/Random Upgrades/upgrade_data.gd create mode 100644 example/Random Upgrades/upgrade_data.gd.uid create mode 100644 example/Random Upgrades/upgrade_data_weapon.gd create mode 100644 example/Random Upgrades/upgrade_data_weapon.gd.uid create mode 100644 example/Random Upgrades/upgrades/elemental.tres create mode 100644 example/Random Upgrades/upgrades/health.tres create mode 100644 example/Random Upgrades/upgrades/mastery_magic.tres create mode 100644 example/Random Upgrades/upgrades/mastery_strength.tres create mode 100644 example/Random Upgrades/upgrades/up_aoe.tres create mode 100644 example/Random Upgrades/upgrades/up_magic.tres create mode 100644 example/Random Upgrades/upgrades/up_movement_speed.tres create mode 100644 example/Random Upgrades/upgrades/up_strength.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_axe.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_dagger.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_fireball.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_lightning.tres create mode 100644 example/Random Upgrades/upgrades/weapons/weapon_spear.tres create mode 100644 example/Random Upgrades/upgrades_csv/upgrades.csv create mode 100644 example/Random Upgrades/upgrades_csv/upgrades.csv.import diff --git a/Resources/Items/Ammo1.tres b/Resources/Items/Ammo1.tres index ebd71caa..ef31f29b 100644 --- a/Resources/Items/Ammo1.tres +++ b/Resources/Items/Ammo1.tres @@ -9,9 +9,9 @@ atlas = ExtResource("1_bpftr") [resource] script = ExtResource("1_31o2l") -ItemName = "Ammo 1" -ItemDescription = "Ammunition" -ItemKey = "Ammo1" +ItemName = &"Ice Ammo" +ItemDescription = &"Ammo for Ice-Based Weapons" +ItemKey = &"ICE_AMMO" Item = 3 Amount = 25 Max = 400 diff --git a/Resources/Items/Blue_Keycard.tres b/Resources/Items/Blue_Keycard.tres index f1be3736..48dc5159 100644 --- a/Resources/Items/Blue_Keycard.tres +++ b/Resources/Items/Blue_Keycard.tres @@ -9,9 +9,9 @@ region = Rect2(0, 0, 16, 16) [resource] script = ExtResource("1_k8cnp") -ItemName = "Blue Keycard" -ItemDescription = "Keycard that opens blue coded readers" -ItemKey = "KeycardBlue" +ItemName = &"Blue Keycard" +ItemDescription = &"Activates Blue KeyPads" +ItemKey = &"BLUE_KEY" Item = 1 Amount = 1 Max = 1 diff --git a/Resources/Items/Cheat_Gun_Item.tres b/Resources/Items/Cheat_Gun_Item.tres index 8cc136c6..2ab4dc17 100644 --- a/Resources/Items/Cheat_Gun_Item.tres +++ b/Resources/Items/Cheat_Gun_Item.tres @@ -7,9 +7,9 @@ [resource] script = ExtResource("3_i0e51") -ItemName = "Cheat Gun" -ItemDescription = "Cheat gun that deals massive damage" -ItemKey = "CheatGun" +ItemName = &"Cheat Gun" +ItemDescription = &"Does massive damage" +ItemKey = &"CHEAT_GUN" Item = 9 WeaponData = ExtResource("2_0na1t") Amount = 1 @@ -20,4 +20,4 @@ UiType = 1 Selectable = true InventorySprite = ExtResource("2_0vddk") HudItemScene = ExtResource("1_i6xgq") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Cheat_Gun_Pickup.tscn" diff --git a/Resources/Items/Green_Keycard.tres b/Resources/Items/Green_Keycard.tres index ef7b578f..d584a8ec 100644 --- a/Resources/Items/Green_Keycard.tres +++ b/Resources/Items/Green_Keycard.tres @@ -9,9 +9,9 @@ region = Rect2(0, 0, 16, 16) [resource] script = ExtResource("1_t0s5w") -ItemName = "Green Keycard" -ItemDescription = "Keycard that opens green coded readers" -ItemKey = "KeycardGreen" +ItemName = &"Green Keycard" +ItemDescription = &"Activates Green KeyPads" +ItemKey = &"GREEN_KEY" Item = 2 Amount = 1 Max = 1 diff --git a/Resources/Items/Green_Points_Pickup.tres b/Resources/Items/Green_Points_Pickup.tres index 68f5d51d..d54af045 100644 --- a/Resources/Items/Green_Points_Pickup.tres +++ b/Resources/Items/Green_Points_Pickup.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("2_fg25e") -ItemName = "Green Points" -ItemDescription = "Use them for upgrades" -ItemKey = "GreenPoints" +ItemName = &"Green Points" +ItemDescription = &"Used for upgrades" +ItemKey = &"GREEN_POINTS" Item = 11 Amount = 1 Max = 100 @@ -16,5 +16,5 @@ ConsumeOnUse = true UiType = 0 Selectable = false InventorySprite = ExtResource("1_b4fj2") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Green_Points_Pickup.tscn" metadata/_custom_type_script = "uid://epnwjptvks3t" diff --git a/Resources/Items/Heart_Pickup.tres b/Resources/Items/Heart_Pickup.tres index 471ec555..1011af94 100644 --- a/Resources/Items/Heart_Pickup.tres +++ b/Resources/Items/Heart_Pickup.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("1_hyh2l") -ItemName = "Extend" -ItemDescription = "Gives back 20 Health on use" -ItemKey = "Heart" +ItemName = &"Health" +ItemDescription = &"Gives back 25% of Max Health on use" +ItemKey = &"HEALTH" Item = 4 Amount = 1 Max = 10 @@ -16,4 +16,5 @@ ConsumeOnUse = true UiType = 0 Selectable = true InventorySprite = ExtResource("1_xg75n") +DropScenePath = &"res://Scenes/Items/Heart_Pickup.tscn" metadata/_custom_type_script = "uid://epnwjptvks3t" diff --git a/Resources/Items/IceShotgun.tres b/Resources/Items/IceShotgun.tres index 6d046143..d08fdf8a 100644 --- a/Resources/Items/IceShotgun.tres +++ b/Resources/Items/IceShotgun.tres @@ -7,9 +7,9 @@ [resource] script = ExtResource("3_cjfxs") -ItemName = "Ice Shotgun" -ItemDescription = "A shotgun transformed by Cirno's magic, requires ammunition to shoot" -ItemKey = "IceShotgun" +ItemName = &"Ice Shotgun" +ItemDescription = &"Shoots ice pellets in a wide spread" +ItemKey = &"ICE_SHOTGUN" Item = 9 WeaponData = ExtResource("2_3le6e") Amount = 1 @@ -20,4 +20,4 @@ UiType = 1 Selectable = true InventorySprite = ExtResource("2_4ibag") HudItemScene = ExtResource("1_13ven") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Ice_Shotgun_Pickup.tscn" diff --git a/Resources/Items/IcicleGun.tres b/Resources/Items/IcicleGun.tres index 73e66d51..863c5349 100644 --- a/Resources/Items/IcicleGun.tres +++ b/Resources/Items/IcicleGun.tres @@ -7,9 +7,9 @@ [resource] script = ExtResource("2_hy2hk") -ItemName = "Icicle Gun" -ItemDescription = "Cirno's basic gun, never runs out of ammo" -ItemKey = "IcicleGun" +ItemName = &"Icicle Gun" +ItemDescription = &"Cirno\'s custom gun, shoots ice pellets and never runs out of ammo" +ItemKey = &"ICICLE_GUN" Item = 9 WeaponData = ExtResource("1_itajb") Amount = 1 @@ -20,3 +20,4 @@ UiType = 1 Selectable = true InventorySprite = ExtResource("2_eaoas") HudItemScene = ExtResource("1_lfbsh") +DropScenePath = "res://Scenes/Items/IcicleGun.tscn" diff --git a/Resources/Items/IcicleRepeater.tres b/Resources/Items/IcicleRepeater.tres index 0c51d894..53947409 100644 --- a/Resources/Items/IcicleRepeater.tres +++ b/Resources/Items/IcicleRepeater.tres @@ -6,9 +6,9 @@ [resource] script = ExtResource("4_k6in2") -ItemName = "Icicle Repeater" -ItemDescription = "Fast shooting weapon" -ItemKey = "IcicleRepeater" +ItemName = &"Icicle Repeater" +ItemDescription = &"Shoots ice pellets at a high rate" +ItemKey = &"ICICLE_REPEATER" Item = 9 WeaponData = ExtResource("3_5vsuk") Amount = 1 @@ -18,4 +18,4 @@ ConsumeOnUse = false UiType = 1 Selectable = true InventorySprite = ExtResource("2_3abss") -DropScenePath = &"res://Scenes/Items/Icicle_Repeater.tscn" +DropScenePath = &"res://Scenes/Items/Icicle_Repeater.tscn" diff --git a/Resources/Items/Money_Pickup.tres b/Resources/Items/Money_Pickup.tres index b6ab3c97..660d247b 100644 --- a/Resources/Items/Money_Pickup.tres +++ b/Resources/Items/Money_Pickup.tres @@ -5,10 +5,10 @@ [resource] script = ExtResource("2_swcup") -ItemName = "Credits" -ItemDescription = "Spend it on stuff" -ItemKey = "Credits" -Item = 4 +ItemName = &"Credits" +ItemDescription = &"Can be used to buy things" +ItemKey = &"CREDITS" +Item = 12 Amount = 1 Max = 10 PickupIfMaxed = false @@ -16,5 +16,5 @@ ConsumeOnUse = true UiType = 0 Selectable = true InventorySprite = ExtResource("1_woor7") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Credits_Pickup.tscn" metadata/_custom_type_script = "uid://epnwjptvks3t" diff --git a/Resources/Items/Points_Pickup.tres b/Resources/Items/Points_Pickup.tres index 1dd96be8..10105573 100644 --- a/Resources/Items/Points_Pickup.tres +++ b/Resources/Items/Points_Pickup.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("2_rxsju") -ItemName = "Points" -ItemDescription = "Use them for upgrades" -ItemKey = "Points" +ItemName = &"Points" +ItemDescription = &"Necessari for upgrades" +ItemKey = &"POINTS" Item = 11 Amount = 1 Max = 100 @@ -16,5 +16,5 @@ ConsumeOnUse = true UiType = 0 Selectable = false InventorySprite = ExtResource("1_nsfmo") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Points_Pickup.tscn" metadata/_custom_type_script = "uid://epnwjptvks3t" diff --git a/Resources/Items/Power_Pickup.tres b/Resources/Items/Power_Pickup.tres index 926ab253..e7ac9675 100644 --- a/Resources/Items/Power_Pickup.tres +++ b/Resources/Items/Power_Pickup.tres @@ -5,10 +5,10 @@ [resource] script = ExtResource("1_vw5ht") -ItemName = "Power" -ItemDescription = "Restores Health when used" -ItemKey = "PowerPickup" -Item = 4 +ItemName = &"Power" +ItemDescription = &"Necessary for upgrades" +ItemKey = &"POWER" +Item = 10 Amount = 1 Max = 100 PickupIfMaxed = false diff --git a/Resources/Items/Red_Keycard.tres b/Resources/Items/Red_Keycard.tres index b6b2cb37..d48cd1b5 100644 --- a/Resources/Items/Red_Keycard.tres +++ b/Resources/Items/Red_Keycard.tres @@ -7,9 +7,9 @@ [resource] script = ExtResource("1_istlt") -ItemName = "Red Keycard" -ItemDescription = "Keycard that opens red coded readers" -ItemKey = "KeycardRed" +ItemName = &"Red Keycard" +ItemDescription = &"Opens Red KeyPads" +ItemKey = &"RED_KEY" Item = 0 Amount = 1 Max = 1 diff --git a/Resources/Items/Shield_Pickup.tres b/Resources/Items/Shield_Pickup.tres index 5fed940e..87d8d74a 100644 --- a/Resources/Items/Shield_Pickup.tres +++ b/Resources/Items/Shield_Pickup.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("2_xsuq5") -ItemName = "Shield" -ItemDescription = "Gives back 20 Shield on use" -ItemKey = "Shield" +ItemName = &"Shield Charge" +ItemDescription = &"Recharges the shield by 25%" +ItemKey = &"SHIELD" Item = 8 Amount = 1 Max = 10 @@ -16,5 +16,5 @@ ConsumeOnUse = true UiType = 0 Selectable = true InventorySprite = ExtResource("1_0hq6q") -DropScenePath = null +DropScenePath = &"res://Scenes/Items/Shield_Pickup.tscn" metadata/_custom_type_script = "uid://epnwjptvks3t" diff --git a/Resources/Items/Spider_Bomb_Pickup.tres b/Resources/Items/Spider_Bomb_Pickup.tres index db71af5b..2913a322 100644 --- a/Resources/Items/Spider_Bomb_Pickup.tres +++ b/Resources/Items/Spider_Bomb_Pickup.tres @@ -11,7 +11,7 @@ region = Rect2(0, 0, 16, 16) [sub_resource type="Resource" id="Resource_v5a4k"] script = ExtResource("1_qd764") -Name = "Snowball Bomb launcher" +Name = null BulletData = ExtResource("2_gpot4") RateOfFire = 1.0 BulletCapacity = 10 @@ -21,16 +21,16 @@ InfiniteAmmo = true BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "SPIDER_BOMB" -AmmoKey = "SPIDER_BOMB" +ItemKey = null +AmmoKey = null _rotationOffset = 0.0 metadata/_custom_type_script = "uid://b6fmrnipv88bk" [resource] script = ExtResource("1_lus3u") -ItemName = "Snowball Bomb" -ItemDescription = "A snowball with a bomb inside" -ItemKey = "SPIDER_BOMB" +ItemName = &"SnowBall Bomb" +ItemDescription = &"A snowball packed of explosive, explodes on contact" +ItemKey = &"SPIDER_BOMB" Item = 5 WeaponData = SubResource("Resource_v5a4k") Amount = 1 diff --git a/Resources/Items/Yin_Yang_Ammo.tres b/Resources/Items/Yin_Yang_Ammo.tres index 112ff915..d941184f 100644 --- a/Resources/Items/Yin_Yang_Ammo.tres +++ b/Resources/Items/Yin_Yang_Ammo.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("3_ajs4l") -ItemName = "Yin Yang Ammo" -ItemDescription = "Ammunition for Ying-Yang based weapons" -ItemKey = "YinYangAmmo" +ItemName = &"Yin-Yang Ammo" +ItemDescription = &"Ammo for Ying-Yang based weapons" +ItemKey = &"YINYANG_AMMO" Item = 3 Amount = 5 Max = 50 diff --git a/Resources/Items/Yin_Yang_Gun_Pickup.tres b/Resources/Items/Yin_Yang_Gun_Pickup.tres index d4dc3894..289291bd 100644 --- a/Resources/Items/Yin_Yang_Gun_Pickup.tres +++ b/Resources/Items/Yin_Yang_Gun_Pickup.tres @@ -6,9 +6,9 @@ [resource] script = ExtResource("2_2w24o") -ItemName = "Yin-Yang Gun" -ItemDescription = "A weapon reverse engineered from Reimu's Yin-Yang orbs, shoots explosive projectiles" -ItemKey = "YinYangGun" +ItemName = &"Yin-Yang Gun" +ItemDescription = &"A weapon that shoots explosive Yin-Yang Orbs" +ItemKey = &"YINYANG_GUN" Item = 9 WeaponData = ExtResource("1_cuxft") Amount = 1 diff --git a/Resources/Items/Yin_Yang_Orb.tres b/Resources/Items/Yin_Yang_Orb.tres index 22364d71..85e30cf2 100644 --- a/Resources/Items/Yin_Yang_Orb.tres +++ b/Resources/Items/Yin_Yang_Orb.tres @@ -5,9 +5,9 @@ [resource] script = ExtResource("2_8wjtq") -ItemName = "Yin Yang Orb" -ItemDescription = "It's an orb of mystical properties" -ItemKey = "YingYangOrb" +ItemName = &"Ying-Yang Orb" +ItemDescription = &"A mysterious orb emitting magical energy" +ItemKey = &"YINYANG_ORB" Item = 13 Amount = 1 Max = 1 diff --git a/Resources/Weapons/Cheat_Gun.tres b/Resources/Weapons/Cheat_Gun.tres index bd01c898..2bd77c3e 100644 --- a/Resources/Weapons/Cheat_Gun.tres +++ b/Resources/Weapons/Cheat_Gun.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("1_d3tbp") -Name = "Cheat Gun" +Name = &"Cheat Gun" BulletData = ExtResource("1_7fekn") RateOfFire = 0.4 BulletCapacity = 200 @@ -15,6 +15,6 @@ InfiniteAmmo = true BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "CheatGun" -AmmoKey = "" +ItemKey = &"CHEAT_GUN" +AmmoKey = null _rotationOffset = 0.0 diff --git a/Resources/Weapons/Ice_Shotgun_Weapon.tres b/Resources/Weapons/Ice_Shotgun_Weapon.tres index fd98d3d9..d3ab1564 100644 --- a/Resources/Weapons/Ice_Shotgun_Weapon.tres +++ b/Resources/Weapons/Ice_Shotgun_Weapon.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("2_utbbo") -Name = "Ice Shotgun" +Name = &"Ice Shotgun" BulletData = ExtResource("1_m44wx") RateOfFire = 0.1 BulletCapacity = 4 @@ -15,6 +15,6 @@ InfiniteAmmo = false BulletsPerShot = 3 SpreadAngle = 15.0 RandomSpread = 0.0 -ItemKey = "IceShotgun" -AmmoKey = "Ammo1" +ItemKey = &"ICE_SHOTGUN" +AmmoKey = &"ICE_AMMO" _rotationOffset = 0.0 diff --git a/Resources/Weapons/IcicleGun.tres b/Resources/Weapons/IcicleGun.tres index cccd8cc3..c0d6cce9 100644 --- a/Resources/Weapons/IcicleGun.tres +++ b/Resources/Weapons/IcicleGun.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("2_m8dps") -Name = "Icicle Gun" +Name = &"Icicle Gun" BulletData = ExtResource("1_85ef1") RateOfFire = 0.2 BulletCapacity = 4 @@ -15,6 +15,6 @@ InfiniteAmmo = true BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "IcicleGun" -AmmoKey = "" +ItemKey = &"ICICLE_GUN" +AmmoKey = null _rotationOffset = 0.0 diff --git a/Resources/Weapons/IcicleRepeater.tres b/Resources/Weapons/IcicleRepeater.tres index 1d6a0a49..fb730333 100644 --- a/Resources/Weapons/IcicleRepeater.tres +++ b/Resources/Weapons/IcicleRepeater.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("2_f4135") -Name = "Icicle Gun" +Name = &"Icicle Repeater" BulletData = ExtResource("1_lg8jo") RateOfFire = 0.1 BulletCapacity = 8 @@ -15,6 +15,6 @@ InfiniteAmmo = false BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "IcicleRepeater" -AmmoKey = "Ammo1" +ItemKey = &"ICICLE_REPEATER" +AmmoKey = &"ICE_AMMO" _rotationOffset = 0.0 diff --git a/Resources/Weapons/Spider_Bomb.tres b/Resources/Weapons/Spider_Bomb.tres index 9198b975..03103a5f 100644 --- a/Resources/Weapons/Spider_Bomb.tres +++ b/Resources/Weapons/Spider_Bomb.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("1_wdsus") -Name = "Spider Bomb" +Name = &"Spider Bomb" BulletData = ExtResource("1_m8p4s") RateOfFire = 0.4 BulletCapacity = 20 @@ -15,7 +15,7 @@ InfiniteAmmo = true BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "SPIDER_BOMB" -AmmoKey = "" +ItemKey = &"SPIDER_BOMB" +AmmoKey = null _rotationOffset = 0.0 metadata/_custom_type_script = "uid://b6fmrnipv88bk" diff --git a/Resources/Weapons/Yin_Yang_Gun.tres b/Resources/Weapons/Yin_Yang_Gun.tres index 638b3890..c8a2bb66 100644 --- a/Resources/Weapons/Yin_Yang_Gun.tres +++ b/Resources/Weapons/Yin_Yang_Gun.tres @@ -5,7 +5,7 @@ [resource] script = ExtResource("2_dbal7") -Name = "Yin-Yang Gun" +Name = &"Yin-Yang Gun" BulletData = ExtResource("1_otehl") RateOfFire = 0.8 BulletCapacity = 3 @@ -15,6 +15,6 @@ InfiniteAmmo = false BulletsPerShot = 1 SpreadAngle = 0.0 RandomSpread = 0.0 -ItemKey = "YinYangGun" -AmmoKey = "YinYangAmmo" +ItemKey = &"YINYAN_GUN" +AmmoKey = &"YINYAN_AMMO" _rotationOffset = 0.0 diff --git a/Scenes/HUD/HUD.tscn b/Scenes/HUD/HUD.tscn index ddaf66a5..2232b952 100644 --- a/Scenes/HUD/HUD.tscn +++ b/Scenes/HUD/HUD.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=23 format=3 uid="uid://dkwi1hu1bixoe"] +[gd_scene load_steps=24 format=3 uid="uid://dkwi1hu1bixoe"] [ext_resource type="Script" uid="uid://baf6pxbvhqmjk" path="res://Scripts/Hud.cs" id="1_m0hb0"] [ext_resource type="FontFile" uid="uid://ccm3u37q1hvux" path="res://fonts/Xolonium-Regular.ttf" id="2_0xmx2"] @@ -13,6 +13,7 @@ [ext_resource type="Theme" uid="uid://dnsadvmunm76k" path="res://Resources/Styles/MainMenuButtons.tres" id="9_sx5r0"] [ext_resource type="StyleBox" uid="uid://ctw2hju32l3rg" path="res://Resources/Styles/PixelStyleBoxRed.tres" id="10_f3h51"] [ext_resource type="Script" uid="uid://bobo5f4ud60qw" path="res://Scripts/UI/ItemsMenu.cs" id="10_oflr6"] +[ext_resource type="Script" uid="uid://com5b4ffsmj7s" path="res://Scripts/UI/InventoryMenu.cs" id="11_7pulb"] [sub_resource type="LabelSettings" id="LabelSettings_a7f6n"] font = ExtResource("2_0xmx2") @@ -190,27 +191,71 @@ offset_top = 26.0 offset_right = 226.0 offset_bottom = 144.0 -[node name="Control" type="Control" parent="."] -layout_mode = 3 -anchors_preset = 0 -offset_left = 41.0 -offset_top = 16.0 -offset_right = 291.0 -offset_bottom = 146.0 +[node name="InventoryMenu" type="TabContainer" parent="."] +offset_left = 16.0 +offset_top = 9.0 +offset_right = 305.0 +offset_bottom = 153.0 mouse_filter = 2 +theme_override_fonts/font = ExtResource("6_sk1eq") +current_tab = 4 +script = ExtResource("11_7pulb") metadata/_edit_group_ = true -[node name="ItemList" type="ItemList" parent="Control"] +[node name="Weapons" type="ItemList" parent="InventoryMenu"] visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 +layout_mode = 2 theme = ExtResource("9_sx5r0") theme_override_styles/panel = ExtResource("10_f3h51") allow_search = false max_columns = 3 same_column_width = true script = ExtResource("10_oflr6") +ItemsFilter = Array[int]([9]) +metadata/_tab_index = 0 + +[node name="Consumables" type="ItemList" parent="InventoryMenu"] +visible = false +layout_mode = 2 +theme = ExtResource("9_sx5r0") +theme_override_styles/panel = ExtResource("10_f3h51") +allow_search = false +max_columns = 3 +same_column_width = true +script = ExtResource("10_oflr6") +ItemsFilter = Array[int]([4, 5, 8, 7, 6]) +metadata/_tab_index = 1 + +[node name="Ammo" type="ItemList" parent="InventoryMenu"] +visible = false +layout_mode = 2 +theme = ExtResource("9_sx5r0") +theme_override_styles/panel = ExtResource("10_f3h51") +allow_search = false +max_columns = 3 +same_column_width = true +script = ExtResource("10_oflr6") +ItemsFilter = Array[int]([3]) +metadata/_tab_index = 2 + +[node name="Key" type="ItemList" parent="InventoryMenu"] +visible = false +layout_mode = 2 +theme = ExtResource("9_sx5r0") +theme_override_styles/panel = ExtResource("10_f3h51") +allow_search = false +max_columns = 3 +same_column_width = true +script = ExtResource("10_oflr6") +ItemsFilter = Array[int]([0, 1, 2, 13, 10, 11, 12]) +metadata/_tab_index = 3 + +[node name="Status" type="PanelContainer" parent="InventoryMenu"] +layout_mode = 2 +metadata/_tab_index = 4 + +[node name="Label" type="Label" parent="InventoryMenu/Status"] +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 0 +text = "Status" diff --git a/Scenes/Interactable.cs b/Scenes/Interactable.cs index e60b002b..61c2c079 100644 --- a/Scenes/Interactable.cs +++ b/Scenes/Interactable.cs @@ -28,7 +28,7 @@ public partial class Interactable : Area2D, IInteractable { if (Requirements.Any()) { - if (InventoryManager.Instance.HasItems(Requirements.Select(x => x.ItemKey).ToList())) + if (InventoryManager.Instance.HasItems(Requirements.Select(x => x.ItemKey.ToString()).ToList())) { GD.Print($"Requirements for activation of {this.Name} successfully met: {string.Join(",", Requirements.Select(x => x.Item))} "); return true; diff --git a/Scenes/Maps/PlayerFSMTest.tscn b/Scenes/Maps/PlayerFSMTest.tscn index be78bd95..6db4d3c5 100644 --- a/Scenes/Maps/PlayerFSMTest.tscn +++ b/Scenes/Maps/PlayerFSMTest.tscn @@ -53,7 +53,7 @@ [sub_resource type="Resource" id="Resource_6wo78"] script = ExtResource("4_u1i8n") EggIndex = 0 -StartingEquipment = Array[ExtResource("5_u1i8n")]([]) +StartingEquipment = [] [sub_resource type="RectangleShape2D" id="RectangleShape2D_rff8l"] size = Vector2(30, 52.5) diff --git a/Scenes/test.tscn b/Scenes/test.tscn index c6f5008e..8e187523 100644 --- a/Scenes/test.tscn +++ b/Scenes/test.tscn @@ -201,7 +201,7 @@ ActivationType = 0 Targets = Array[NodePath]([NodePath("../Rumia")]) WaitForCompletion = true -[sub_resource type="Resource" id="Resource_mah4x"] +[sub_resource type="Resource" id="Resource_qnbhd"] resource_local_to_scene = true script = ExtResource("49_0si7g") Target = NodePath(".") @@ -821,7 +821,7 @@ Events = Array[ExtResource("42_yqnr2")]([SubResource("Resource_068l7"), SubResou [node name="BossBattleStartScript" parent="Parallax2D/Factory Tilemaps/LevelProps" instance=ExtResource("43_kf3qc")] position = Vector2(-1487, -396) -Events = Array[ExtResource("42_yqnr2")]([SubResource("Resource_4f4id"), SubResource("Resource_s2o7m"), SubResource("Resource_b1dht"), SubResource("Resource_xrgpy"), SubResource("Resource_mah4x")]) +Events = Array[ExtResource("42_yqnr2")]([SubResource("Resource_4f4id"), SubResource("Resource_s2o7m"), SubResource("Resource_b1dht"), SubResource("Resource_xrgpy"), SubResource("Resource_qnbhd")]) [node name="Enemy13" parent="Parallax2D/Factory Tilemaps/LevelProps" instance=ExtResource("47_u1ve6")] position = Vector2(-1657, -788) diff --git a/Scripts/InventoryManager.cs b/Scripts/InventoryManager.cs index 7b4047c1..27d49c05 100644 --- a/Scripts/InventoryManager.cs +++ b/Scripts/InventoryManager.cs @@ -10,7 +10,7 @@ public partial class InventoryManager : Node2D public static InventoryManager Instance { get; private set; } public bool RedKeycard { get; set; } - private Dictionary _itemsDict = new Dictionary(); + private Dictionary _itemsDict = new(); public List Items => _itemsDict.Where(x => x.Value.Count > 0).Select(x => x.Value).ToList(); @@ -47,7 +47,7 @@ public partial class InventoryManager : Node2D return _itemsDict.TryGetValue(key, out item); } - public bool HasItems(List itemKeys) + public bool HasItems(IList itemKeys) { return itemKeys.Aggregate(false, (current, item) => current || GetItemCount(item) > 0); } @@ -120,7 +120,7 @@ public partial class InventoryManager : Node2D return true; } - public bool UseItem(string itemKey) + public bool UseItem(StringName itemKey) { if (!_itemsDict.TryGetValue(itemKey, out var itm)) return false; @@ -150,7 +150,7 @@ public partial class InventoryManager : Node2D return true; } - public void NotifyLoadedAmmoChange(string weaponDataItemKey, int loadedAmmo) + public void NotifyLoadedAmmoChange(StringName weaponDataItemKey, int loadedAmmo) { EmitSignal(SignalName.LoadedAmmoChanged, weaponDataItemKey, loadedAmmo); } diff --git a/Scripts/Resources/LootItem.cs b/Scripts/Resources/LootItem.cs index 20cb4cb8..cbab9f52 100644 --- a/Scripts/Resources/LootItem.cs +++ b/Scripts/Resources/LootItem.cs @@ -5,9 +5,9 @@ namespace Cirno.Scripts.Resources; [GlobalClass] public partial class LootItem : Resource { - [Export] public string ItemName { get; set; } - [Export] public string ItemDescription { get; set; } - [Export] public string ItemKey { get; set; } + [Export] public StringName ItemName { get; set; } + [Export] public StringName ItemDescription { get; set; } + [Export] public StringName ItemKey { get; set; } [Export] public ItemTypes Item; [Export] public WeaponResource WeaponData { get; set; } [Export] public int Amount; diff --git a/Scripts/Resources/WeaponResource.cs b/Scripts/Resources/WeaponResource.cs index a696350d..e2ed1b14 100644 --- a/Scripts/Resources/WeaponResource.cs +++ b/Scripts/Resources/WeaponResource.cs @@ -10,7 +10,7 @@ namespace Cirno.Scripts.Resources; public partial class WeaponResource : Resource { [Export] - public string Name { get; set; } + public StringName Name { get; set; } [Export] public BulletResource BulletData { get; private set; } @@ -34,11 +34,11 @@ public partial class WeaponResource : Resource [Export] public float SpreadAngle = 0f; [Export] public float RandomSpread = 0f; - [Export] public string ItemKey; + [Export] public StringName ItemKey; #region Bullet spawn data - [Export] public string AmmoKey; + [Export] public StringName AmmoKey; //[Export] public float BulletSpeed = 100f; //[Export] public float BulletDamage = 1; //[Export] public float LifeTime = 10f; diff --git a/Scripts/UI/InventoryMenu.cs b/Scripts/UI/InventoryMenu.cs new file mode 100644 index 00000000..09b7f4a8 --- /dev/null +++ b/Scripts/UI/InventoryMenu.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Linq; +using Godot; + +namespace Cirno.Scripts.UI; + +public partial class InventoryMenu : TabContainer +{ + private List _itemMenus = []; + + [Export] + public StringName InventoryActionName { get; private set; } = "inventory"; + + [Export] + public StringName PauseActionName { get; private set; } = "pause"; + + [Export] + public StringName CancelActionName { get; private set; } = "ui_cancel"; + + public override void _Ready() + { + CallDeferred(MethodName.DeferredInitialize); + this.Hide(); + } + + public override void _Process(double delta) + { + if (Input.IsActionJustPressed(InventoryActionName) || Input.IsActionJustPressed(PauseActionName)) + { + if (Visible) + { + CallDeferred(MethodName.HideInventory); + } + // else + // { + // ShowInventory(); + // } + } + } + + private void DeferredInitialize() + { + var children = this.GetChildren(); + foreach (var child in children) + { + if (child is ItemsMenu menu) + { + _itemMenus.Add(menu); + menu.Init(this); + } + } + //Clear(); + + //ItemActivated += OnItemSelected; + + GameManager.Instance.GameStateChange += state => + { + switch (state) + { + case GameState.Inventory: + CallDeferred(MethodName.ShowInventory); + break; + default: + CallDeferred(MethodName.HideInventory); + //HideInventory(); + break; + } + }; + } + + private void HideInventory() + { + if (!Visible) return; + GD.Print("Hiding inventory"); + this.Hide(); + foreach (var menu in _itemMenus) + { + menu.Empty(); + } + + //_itemsDic.Clear(); + + //GameManager.Instance.ChangeState(GameState.Playing); + } + + private void ShowInventory() + { + if (Visible) return; + this.Show(); + + foreach (var menu in _itemMenus) + { + menu.Fill(); + } + + _itemMenus.FirstOrDefault()?.GrabFocus(); + } +} \ No newline at end of file diff --git a/Scripts/UI/InventoryMenu.cs.uid b/Scripts/UI/InventoryMenu.cs.uid new file mode 100644 index 00000000..3c54f2f3 --- /dev/null +++ b/Scripts/UI/InventoryMenu.cs.uid @@ -0,0 +1 @@ +uid://com5b4ffsmj7s diff --git a/Scripts/UI/ItemsMenu.cs b/Scripts/UI/ItemsMenu.cs index 9fcde581..28e01eb9 100644 --- a/Scripts/UI/ItemsMenu.cs +++ b/Scripts/UI/ItemsMenu.cs @@ -1,103 +1,88 @@ using Godot; using System; using Cirno.Scripts; +using Cirno.Scripts.UI; using Godot.Collections; public partial class ItemsMenu : ItemList { - private InventoryManager _inventoryManager; private Dictionary _itemsDic = new(); + + [Export] public Array ItemsFilter { get; private set; } = []; + + private InventoryMenu _parent; - private GameManager _gameManager; - [Export] - public string InventoryActionName { get; private set; } = "inventory"; - - [Export] - public string PauseActionName { get; private set; } = "pause"; - - public override void _Ready() + public void Init(InventoryMenu parent) { - CallDeferred(MethodName.DeferredInitialize); - this.Hide(); + _parent = parent; + Empty(); + ItemActivated += OnItemSelected; } - public override void _Process(double delta) + public void Fill() { - if (Input.IsActionJustPressed(InventoryActionName) || Input.IsActionJustPressed(PauseActionName)) + foreach (var item in InventoryManager.Instance.Items) { - if (Visible) - { - CallDeferred(MethodName.HideInventory); - } - // else - // { - // ShowInventory(); - // } + if (item.Count <= 0) continue; + if (!ItemsFilter.Contains(item.Item.Item)) continue; + + var index = this.AddItem($"{item.Item.ItemName} x{item.Count}", item.Item.InventorySprite, + true); + + //this.SetItemTooltip(index, item.Item.ItemDescription); + + _itemsDic.Add(index, item.Item.ItemKey); + } } - private void DeferredInitialize() + public void Empty() { - _gameManager = GameManager.Instance; - _inventoryManager = _gameManager.GetInventoryManager(); - - ItemSelected += OnItemSelected; Clear(); - - ItemActivated += OnItemSelected; - - _gameManager.GameStateChange += state => - { - switch (state) - { - case GameState.Inventory: - CallDeferred(MethodName.ShowInventory); - break; - default: - CallDeferred(MethodName.HideInventory); - //HideInventory(); - break; - } - }; + _itemsDic.Clear(); } private void OnItemSelected(long index) { var item = _itemsDic[index]; GD.Print("Item: " + item); - HideInventory(); - - _inventoryManager.UseItem(item); - } + InventoryManager.Instance.TryGetItem(item, out var lootItem); + if (!lootItem.Item.Selectable) return; - private void HideInventory() - { - if (!Visible) return; - GD.Print("Hiding inventory"); - this.Hide(); - Clear(); - _itemsDic.Clear(); - GameManager.Instance.ChangeState(GameState.Playing); + + InventoryManager.Instance.UseItem(item); } - private void ShowInventory() - { - if (Visible) return; - GD.Print("Showing inventory"); - this.Show(); - foreach (var item in _inventoryManager.Items) - { - if (item.Count <= 0) continue; - - var index = this.AddItem($"{item.Item.ItemName} x{item.Count}", item.Item.InventorySprite, - item.Item.Selectable); - - this.SetItemTooltip(index, item.Item.ItemDescription); - - _itemsDic.Add(index, item.Item.ItemKey); - - } - } + // private void HideInventory() + // { + // if (!Visible) return; + // GD.Print("Hiding inventory"); + // this.Hide(); + // Clear(); + // _itemsDic.Clear(); + // + // GameManager.Instance.ChangeState(GameState.Playing); + // } + + // private void ShowInventory() + // { + // if (Visible) return; + // this.Show(); + // GrabFocus(); + // foreach (var item in _inventoryManager.Items) + // { + // if (item.Count <= 0) continue; + // if (!ItemsFilter.Contains(item.Item.Item)) continue; + // + // var index = this.AddItem($"{item.Item.ItemName} x{item.Count}", item.Item.InventorySprite, + // true); + // + // this.SetItemTooltip(index, item.Item.ItemDescription); + // + // _itemsDic.Add(index, item.Item.ItemKey); + // + // } + // } } diff --git a/addons/resources_spreadsheet_view/LICENSE.md b/addons/resources_spreadsheet_view/LICENSE.md new file mode 100644 index 00000000..0d448fd4 --- /dev/null +++ b/addons/resources_spreadsheet_view/LICENSE.md @@ -0,0 +1,9 @@ +# MIT License + +Copyright 2022 Gennady "Don Tnowe" Krupenyov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/addons/resources_spreadsheet_view/editor_color_setter.gd b/addons/resources_spreadsheet_view/editor_color_setter.gd new file mode 100644 index 00000000..5c35111a --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_color_setter.gd @@ -0,0 +1,6 @@ +@tool +extends Control + + +func _ready(): + modulate = get_theme_color("accent_color", "Editor") diff --git a/addons/resources_spreadsheet_view/editor_color_setter.gd.uid b/addons/resources_spreadsheet_view/editor_color_setter.gd.uid new file mode 100644 index 00000000..91aaedd3 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_color_setter.gd.uid @@ -0,0 +1 @@ +uid://begbojdjn84s0 diff --git a/addons/resources_spreadsheet_view/editor_icon_button.gd b/addons/resources_spreadsheet_view/editor_icon_button.gd new file mode 100644 index 00000000..0259cb08 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_icon_button.gd @@ -0,0 +1,12 @@ +@tool +extends Button + +@export var icon_name := "Node" : + set(v): + icon_name = v + if has_theme_icon(v, "EditorIcons"): + icon = get_theme_icon(v, "EditorIcons") + + +func _ready(): + self.icon_name = (icon_name) diff --git a/addons/resources_spreadsheet_view/editor_icon_button.gd.uid b/addons/resources_spreadsheet_view/editor_icon_button.gd.uid new file mode 100644 index 00000000..81e3092c --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_icon_button.gd.uid @@ -0,0 +1 @@ +uid://dqt5ujookfl06 diff --git a/addons/resources_spreadsheet_view/editor_resource_array_picker.gd b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd new file mode 100644 index 00000000..15be1ef1 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd @@ -0,0 +1,69 @@ +@tool +extends EditorResourcePicker + +signal on_resources_dropped(resources : Array) + +var _prepared_for_drop := false +var _drop_hint_label : Label + + +func _ready(): + resource_changed.connect(_on_resource_changed) + _drop_hint_label = Label.new() + _drop_hint_label.text = "[Drop Here to Add!]" + _drop_hint_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _drop_hint_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + _drop_hint_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + _drop_hint_label.hide() + add_child(_drop_hint_label) + + +func set_prepared_for_drop(state : bool): + for x in get_children(true): + if not x is Popup and (not x is Label): + x.visible = not state + + _drop_hint_label.visible = state + custom_minimum_size = size if state else Vector2.ZERO + _prepared_for_drop = state + + +func _can_drop_data(at_position: Vector2, data: Variant) -> bool: + var data_drop_type : StringName = data.get(&"type", &"") + if data_drop_type != &"files" or data_drop_type != &"resource": + return true + + set_prepared_for_drop(true) + return false + + +func _drop_data(at_position: Vector2, data: Variant): + var data_drop_type : StringName = data.get(&"type", &"") + var new_array : Array[Resource] = [] + if data_drop_type == &"files": + for x in data.files: + new_array.append(load(x)) + + if data_drop_type == &"resource": + new_array.append(data.resource) + + if new_array.size() == 0: + return + + edited_resource = new_array[0] + on_resources_dropped.emit(new_array) + + +func _input(event: InputEvent): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if !event.pressed: + set_prepared_for_drop(false) + + if event is InputEventMouseMotion and not _prepared_for_drop: + # _can_drop_data() is only called when hovering over the picker. Items must be hidden before that. + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not get_global_rect().has_point(event.global_position): + set_prepared_for_drop(true) + + +func _on_resource_changed(new_resource : Resource): + on_resources_dropped.emit([new_resource]) diff --git a/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid new file mode 100644 index 00000000..713340c9 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid @@ -0,0 +1 @@ +uid://c7lqgh2xu0agt diff --git a/addons/resources_spreadsheet_view/editor_view.gd b/addons/resources_spreadsheet_view/editor_view.gd new file mode 100644 index 00000000..88860938 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.gd @@ -0,0 +1,527 @@ +@tool +extends Control + +signal grid_updated() + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var node_folder_path : LineEdit = $"HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path" +@onready var node_recent_paths : OptionButton = $"HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/RecentPaths" +@onready var node_table_root : GridContainer = $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid" +@onready var node_columns : HBoxContainer = $"HeaderContentSplit/VBoxContainer/Columns/Columns" +@onready var node_page_manager : Control = $"HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" +@onready var node_class_filter : Control = $"HeaderContentSplit/VBoxContainer/Search/Search/Class" + +@onready var _on_cell_gui_input : Callable = $"InputHandler"._on_cell_gui_input +@onready var _selection := $"SelectionManager" + +var editor_interface : Object +var editor_plugin : EditorPlugin + +var current_path := "" +var save_data_path : String = get_script().resource_path.get_base_dir() + "/saved_state.json" +var sorting_by := &"" +var sorting_reverse := false + +var columns : Array[StringName] = [] +var column_types : Array[int] = [] +var column_hints : Array[int] = [] +var column_hint_strings : Array[PackedStringArray] = [] +var rows := [] +var remembered_paths := {} +var remembered_paths_total_count := 0 +var table_functions_dict := {} + +var search_cond : Callable +var io : RefCounted + +var first_row := 0 +var last_row := 0 + + +func _ready(): + editor_interface.get_resource_filesystem().filesystem_changed.connect(_on_filesystem_changed) + if FileAccess.file_exists(save_data_path): + var file := FileAccess.open(save_data_path, FileAccess.READ) + var as_text := file.get_as_text() + var as_var := JSON.parse_string(as_text) + + node_recent_paths.load_paths(as_var.get(&"recent_paths", [])) + node_columns.column_properties = as_var.get(&"column_properties", {}) + table_functions_dict = as_var.get(&"table_functions", {}) + for x in $"HeaderContentSplit/VBoxContainer/Search/Search".get_children(): + if x.has_method(&"load_saved_functions"): + x.load_saved_functions(table_functions_dict) + + # Legacy compat: old hidden column format + var legacy_hidden_columns : Dictionary = as_var.get(&"hidden_columns", {}) + for k in legacy_hidden_columns: + for k2 in legacy_hidden_columns[k]: + node_columns.column_properties[k] = node_columns.column_properties.get(k, {}) + node_columns.column_properties[k][k2] = { &"visibility" : 0 } + + if node_recent_paths.recent_paths.size() >= 1: + display_folder(node_recent_paths.recent_paths[-1], &"resource_name", false, true) + + +func save_data(): + if ( + node_recent_paths.recent_paths.is_empty() + and node_columns.column_properties.is_empty() + and table_functions_dict.is_empty() + ): + return + + var file := FileAccess.open(save_data_path, FileAccess.WRITE) + file.store_string(JSON.stringify( + { + &"recent_paths" : node_recent_paths.recent_paths, + &"column_properties" : node_columns.column_properties, + &"table_functions" : table_functions_dict, + } + , " ")) + + +func _on_filesystem_changed(): + if current_path == "": + return + + var file_total_count := _get_file_count_recursive(current_path) + if file_total_count != remembered_paths_total_count: + refresh() + + else: + for k in remembered_paths: + if !is_instance_valid(remembered_paths[k]): + continue + + if remembered_paths[k].resource_path != k: + var res = remembered_paths[k] + remembered_paths.erase(k) + remembered_paths[res.resource_path] = res + refresh() + break + + +func _get_file_count_recursive(path : String) -> int: + var editor_fs : EditorFileSystem = editor_interface.get_resource_filesystem() + var path_dir := editor_fs.get_filesystem_path(path) + if !path_dir: return 0 + + var file_total_count := 0 + var folder_stack : Array[EditorFileSystemDirectory] = [path_dir] + while folder_stack.size() > 0: + path_dir = folder_stack.pop_back() + file_total_count += path_dir.get_file_count() + for i in path_dir.get_subdir_count(): + folder_stack.append(path_dir.get_subdir(i)) + + return file_total_count + + +func display_folder(folderpath : String, sort_by : StringName = "", sort_reverse : bool = false, force_rebuild : bool = false, is_echo : bool = false): + if folderpath == "": + # You wouldn't just wanna edit ALL resources in the project, that's a long time to load! + return + + if sort_by == "": + sort_by = &"resource_path" + + if folderpath.get_extension() == "": + folderpath = folderpath.trim_suffix("/") + "/" + + if (folderpath.ends_with(".tres") or folderpath.ends_with(".res")) and !(load(folderpath) is ResourceTablesImport): + folderpath = folderpath.get_base_dir() + "/" + + node_recent_paths.add_path_to_recent(folderpath) + node_folder_path.text = folderpath + + _load_resources_from_path(folderpath, sort_by, sort_reverse) + _update_visible_rows(force_rebuild or current_path != folderpath) + + current_path = folderpath + remembered_paths_total_count = _get_file_count_recursive(folderpath) + node_columns.update() + grid_updated.emit() + + $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".visible = rows.size() == 0 + $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".text = "No rows visible?\nThis might happen when sorting by a property that isn't here anymore.\nTry clicking a column header to sort again!\n\nIt's also possible that your Filter expression is filtering them out." + + +func display_resources(resource_array : Array): + if sorting_by == "": + sorting_by = &"resource_path" + + current_path = "" + node_recent_paths.select(-1) + rows = [] + for x in resource_array: + insert_row_sorted(x, rows, sorting_by, sorting_reverse) + + fill_property_data_many(rows) + _update_visible_rows() + + node_columns.update() + grid_updated.emit() + + +func refresh(force_rebuild : bool = true): + if current_path == "": + display_resources(rows) + + else: + display_folder(current_path, sorting_by, sorting_reverse, force_rebuild) + + +func _load_resources_from_path(path : String, sort_by : StringName, sort_reverse : bool): + if path.ends_with("/"): + io = ResourceTablesEditFormatTres.new() + + else: + var loaded := load(path) + if loaded is ResourceTablesImport: + io = loaded.view_script.new() + node_class_filter.hide() + + else: + io = ResourceTablesEditFormatTres.new() + + io.editor_view = self + remembered_paths.clear() + rows = io.import_from_path(path, insert_row_sorted, sort_by, sort_reverse) + + +func _update_visible_rows(force_rebuild : bool = true): + node_page_manager.update_page_count(rows) + if columns.size() == 0: + return + + if force_rebuild or columns != node_columns.columns: + for x in node_table_root.get_children(): + x.free() + + node_columns.columns = columns + + var cells_left_to_free : int = node_table_root.get_child_count() - (last_row - first_row) * columns.size() + while cells_left_to_free > 0: + node_table_root.get_child(0).free() + cells_left_to_free -= 1 + + var color_rows : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "color_rows") + for i in last_row - first_row: + _update_row(first_row + i, color_rows) + + +func fill_property_data(res : Resource): + columns.clear() + column_types.clear() + column_hints.clear() + column_hint_strings.clear() + var column_values := [] + var i := -1 + for x in res.get_property_list(): + if x[&"usage"] & PROPERTY_USAGE_EDITOR != 0 and x[&"name"] != "script": + i += 1 + columns.append(x[&"name"]) + column_types.append(x[&"type"]) + column_hints.append(x[&"hint"]) + column_hint_strings.append(x[&"hint_string"].split(",")) + column_values.append(io.get_value(res, columns[i])) + + _selection.initialize_editors(column_values, column_types, column_hints) + + +func fill_property_data_many(resources : Array): + node_class_filter.fill(resources) + + columns.clear() + column_types.clear() + column_hints.clear() + column_hint_strings.clear() + var column_values := [] + var i := -1 + var found_props := {} + for x in resources: + if x == null: continue + i += 1 + if not search_cond.is_null() and not search_cond.call(x, i): + continue + + if not node_class_filter.filter(x): + continue + + for y in x.get_property_list(): + found_props[y[&"name"]] = y + y[&"owner_object"] = x + + i = -1 + for x in found_props.values(): + if x[&"usage"] & PROPERTY_USAGE_EDITOR != 0 and x[&"name"] != "script": + i += 1 + columns.append(x[&"name"]) + column_types.append(x[&"type"]) + column_hints.append(x[&"hint"]) + column_hint_strings.append(x[&"hint_string"].split(",")) + column_values.append(io.get_value(x[&"owner_object"], columns[i])) + + _selection.initialize_editors(column_values, column_types, column_hints) + + +func insert_row_sorted(res : Resource, loaded_rows : Array, sort_by : StringName, sort_reverse : bool): + if not search_cond.is_null() and not search_cond.call(res, loaded_rows.size()): + return + + if not sort_by in res or not node_class_filter.filter(res): + return + + var sort_value = res[sort_by] + for i in loaded_rows.size(): + if sort_reverse == compare_values(sort_value, loaded_rows[i][sort_by]): + loaded_rows.insert(i, res) + return + + remembered_paths[res.resource_path] = res + loaded_rows.append(res) + + +func compare_values(a, b) -> bool: + if a == null or b == null: return b == null + if a is float or a is int: + return a > b + + if a is Color: + return a.h > b.h if a.h != b.h else a.v > b.v + + if a is Resource: + return a.resource_path > b.resource_path + + return str(a) > str(b) + + +func column_can_solo_open(column_index : int) -> bool: + return ( + column_types[column_index] == TYPE_OBJECT + or (column_types[column_index] == TYPE_ARRAY and column_hint_strings[column_index][0].begins_with("24")) + ) + + +func column_solo_open(column_index : int): + display_folder(current_path.trim_suffix("/") + "::" + columns[column_index]) + + +func _set_sorting(sort_by : StringName): + var sort_reverse : bool = !(sorting_by != sort_by or sorting_reverse) + sorting_reverse = sort_reverse + sorting_by = sort_by + refresh() + + +func _update_row(row_index : int, color_rows : bool = true): + var current_node : Control + var next_color := Color.WHITE + var column_editors : Array = _selection.column_editors + var shortened_path : String = rows[row_index].resource_path.substr(current_path.length()).trim_suffix(".tres").trim_suffix(".res") + for i in columns.size(): + if node_table_root.get_child_count() <= (row_index - first_row) * columns.size() + i: + current_node = column_editors[i].create_cell(self) + current_node.gui_input.connect(_on_cell_gui_input.bind(current_node)) + node_table_root.add_child(current_node) + + else: + current_node = node_table_root.get_child((row_index - first_row) * columns.size() + i) + current_node.tooltip_text = ( + columns[i].capitalize() + + "\n---\n" + + "Of " + shortened_path + ) + + if columns[i] in rows[row_index]: + current_node.mouse_filter = MOUSE_FILTER_STOP + current_node.modulate.a = 1.0 + + else: + # Empty cell, can't click, property doesn't exist. + current_node.mouse_filter = MOUSE_FILTER_IGNORE + current_node.modulate.a = 0.0 + continue + + if columns[i] == &"resource_path": + column_editors[i].set_value(current_node, shortened_path) + + else: + var cell_value = io.get_value(rows[row_index], columns[i]) + if cell_value != null or column_types[i] == TYPE_OBJECT: + column_editors[i].set_value(current_node, cell_value) + if color_rows and column_types[i] == TYPE_COLOR: + next_color = cell_value + + column_editors[i].set_color(current_node, next_color) + + +func get_selected_column() -> int: + return _selection.get_cell_column(_selection.edited_cells[0]) + + +func select_column(column_index : int): + _selection.deselect_all_cells() + _selection.select_cell(Vector2i(column_index, 0)) + _selection.select_cells_to(Vector2i(column_index, rows.size() - 1)) + + +func set_edited_cells_values_text(new_cell_values : Array): + var column_editor : Object = _selection.column_editors[get_selected_column()] + + # Duplicated here since if using text editing, edited_cells_text needs to modified + # but here, it would be converted from a String breaking editing + var new_cell_values_converted := new_cell_values.duplicate() + for i in new_cell_values.size(): + new_cell_values_converted[i] = column_editor.from_text(new_cell_values[i]) + + set_edited_cells_values(new_cell_values_converted) + for i in new_cell_values.size(): + var i_pos : Vector2i = _selection.edited_cells[i] + var update_cell : Control = _selection.get_cell_node_from_position(i_pos) + if update_cell == null: + continue + + column_editor.set_value(update_cell, new_cell_values[i]) + + +func set_edited_cells_values(new_cell_values : Array): + var edited_rows : Array = _selection.get_edited_rows() + var column : int = _selection.get_cell_column(_selection.edited_cells[0]) + var edited_cells_resources := _get_row_resources(edited_rows) + + editor_plugin.undo_redo.create_action("Set Cell Values") + editor_plugin.undo_redo.add_undo_method( + self, + &"_update_resources", + edited_cells_resources.duplicate(), + edited_rows.duplicate(), + column, + get_edited_cells_values() + ) + editor_plugin.undo_redo.add_undo_method( + _selection, + &"_update_selected_cells_text" + ) + editor_plugin.undo_redo.add_do_method( + self, + &"_update_resources", + edited_cells_resources.duplicate(), + edited_rows.duplicate(), + column, + new_cell_values.duplicate() + ) + editor_plugin.undo_redo.commit_action(true) + _selection._update_selected_cells_text() + + +func rename_row(row, new_name): + if !has_row_names(): return + + io.rename_row(row, new_name) + refresh() + + +func duplicate_selected_rows(new_name : String): + io.duplicate_rows(_get_row_resources(_selection.get_edited_rows()), new_name) + refresh() + + +func delete_selected_rows(): + io.delete_rows(_get_row_resources(_selection.get_edited_rows())) + refresh() + refresh.call_deferred() + + +func has_row_names(): + return io.has_row_names() + + +func get_last_selected_row(): + return rows[_selection.get_cell_row(_selection.edited_cells[-1])] + + +func get_edited_cells_values() -> Array: + var cells : Array = _selection.edited_cells.duplicate() + var column_index : int = _selection.get_cell_column(cells[0]) + var result := [] + result.resize(cells.size()) + for i in cells.size(): + result[i] = io.get_value(rows[_selection.get_cell_row(cells[i])], columns[column_index]) + + return result + + +func _update_resources(update_rows : Array, update_row_indices : Array[int], update_column : int, values : Array): + var column_editor : Object = _selection.column_editors[update_column] + for i in update_rows.size(): + var row := update_row_indices[i] + io.set_value( + update_rows[i], + columns[update_column], + values[i], + row + ) + var update_cell : Control = _selection.get_cell_node_from_position(Vector2i(update_column, row)) + if update_cell == null: + continue + + column_editor.set_value(update_cell, values[i]) + var row_script : Object = update_rows[i].get_script() + if row_script != null && row_script.is_tool(): + for column_i in columns.size(): + if column_i == update_column: + continue + + var update_cell_c : Control = _selection.get_cell_node_from_position(Vector2i(column_i, row)) + if columns[column_i] != &"resource_path": + _selection.column_editors[column_i].set_value(update_cell_c, update_rows[i].get(columns[column_i])) + + if values[i] == null: + continue + + if column_types[update_column] == TYPE_COLOR: + for j in columns.size() - update_column: + if j != 0 and column_types[j + update_column] == TYPE_COLOR: + break + + _selection.column_editors[j + update_column].set_color( + _selection.get_cell_node_from_position(Vector2i(update_column + j, row)), + values[i] + ) + + node_columns._update_column_sizes() + io.save_entries(rows, update_row_indices) + + +func _on_path_text_submitted(new_text : String = ""): + if new_text != "": + current_path = new_text + display_folder(new_text, "", false, true) + + else: + refresh() + + +func _on_FileDialog_dir_selected(dir : String): + node_folder_path.text = dir + display_folder(dir) + + +func _get_row_resources(row_indices) -> Array: + var arr := [] + arr.resize(row_indices.size()) + for i in arr.size(): + arr[i] = rows[row_indices[i]] + + return arr + + +func _on_File_pressed(): + node_folder_path.get_parent().get_parent().visible = !node_folder_path.get_parent().get_parent().visible + + +func _on_SearchProcess_pressed(): + $"HeaderContentSplit/VBoxContainer/Search".visible = !$"HeaderContentSplit/VBoxContainer/Search".visible diff --git a/addons/resources_spreadsheet_view/editor_view.gd.uid b/addons/resources_spreadsheet_view/editor_view.gd.uid new file mode 100644 index 00000000..14eb6624 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.gd.uid @@ -0,0 +1 @@ +uid://k2am24rkpi2a diff --git a/addons/resources_spreadsheet_view/editor_view.tscn b/addons/resources_spreadsheet_view/editor_view.tscn new file mode 100644 index 00000000..a1026563 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.tscn @@ -0,0 +1,606 @@ +[gd_scene load_steps=33 format=3 uid="uid://5pic6fxx6et3"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_view.gd" id="1_wfx75"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_color_setter.gd" id="2_t2s7k"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="3_7ja2l"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/recent_paths.gd" id="4_umoob"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/expression_textfield.gd" id="5_faq75"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/table_pages.gd" id="5_ka2yn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/class_filter.gd" id="6_2v7d5"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/column_header_manager.gd" id="6_emnmd"] +[ext_resource type="PackedScene" uid="uid://d1s6oihqedvo5" path="res://addons/resources_spreadsheet_view/main_screen/table_header.tscn" id="7_3dx0v"] +[ext_resource type="PackedScene" uid="uid://ddqak780cwwfj" path="res://addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn" id="8_234wn"] +[ext_resource type="PackedScene" uid="uid://c3a2cip8ffccv" path="res://addons/resources_spreadsheet_view/typed_editors/dock_array.tscn" id="9_nts08"] +[ext_resource type="PackedScene" uid="uid://b3a3bo6cfyh5t" path="res://addons/resources_spreadsheet_view/typed_editors/dock_color.tscn" id="10_nsma2"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/frozen_columns.gd" id="10_vb62w"] +[ext_resource type="PackedScene" uid="uid://gtbf7b0wptv" path="res://addons/resources_spreadsheet_view/typed_editors/dock_number.tscn" id="11_q1ao4"] +[ext_resource type="PackedScene" uid="uid://rww3gpl052bn" path="res://addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn" id="12_4kr6q"] +[ext_resource type="PackedScene" uid="uid://dhunxgcae6h1" path="res://addons/resources_spreadsheet_view/settings_grid.tscn" id="13_as1sh"] +[ext_resource type="PackedScene" uid="uid://p6x03dbvhnqw" path="res://addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn" id="13_il556"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/input_handler.gd" id="14_2t57a"] +[ext_resource type="PackedScene" uid="uid://b413igx28kkvb" path="res://addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn" id="14_3p12b"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/selection_manager.gd" id="15_mx6qn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd" id="16_p7n52"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" id="17_sofdw"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd" id="18_oeewr"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd" id="19_7x44x"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd" id="19_oeuko"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd" id="20_swsbn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd" id="21_58wf8"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd" id="22_bni8r"] +[ext_resource type="PackedScene" uid="uid://b51hnttsie7k5" path="res://addons/resources_spreadsheet_view/main_screen/selection_actions.tscn" id="23_m53sx"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd" id="28_a0j2e"] + +[sub_resource type="Gradient" id="Gradient_8kp6w"] +offsets = PackedFloat32Array(0, 0.995413, 1) +colors = PackedColorArray(1, 1, 1, 0.490196, 1, 1, 1, 0.0458716, 1, 1, 1, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_18il8"] +gradient = SubResource("Gradient_8kp6w") + +[node name="Control" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath(".") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath(".") +focus_next = NodePath(".") +focus_previous = NodePath(".") +focus_mode = 2 +theme_override_constants/margin_left = 3 +theme_override_constants/margin_right = 3 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_wfx75") +metadata/_edit_lock_ = true + +[node name="HeaderContentSplit" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HeaderContentSplit"] +layout_mode = 2 + +[node name="MenuStrip" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="File" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +toggle_mode = true +button_pressed = true +text = "File" +flat = true + +[node name="SearchProcess" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +toggle_mode = true +button_pressed = true +text = "Filter/Process" +flat = true + +[node name="VisibleCols" type="MenuButton" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +text = "Shown Columns" + +[node name="VSeparator" type="Control" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Settings" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +text = "Settings" +flat = true + +[node name="VSeparator2" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 + +[node name="Info" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +focus_mode = 0 +text = "About" +flat = true + +[node name="HBoxContainer" type="HSplitContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 +split_offset = -249 + +[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 0 + +[node name="ColorRect4" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/ColorRect4"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="ColorRect3" type="Control" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(2, 0) +layout_mode = 2 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Resource Folder:" + +[node name="Path" type="LineEdit" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +caret_blink = true + +[node name="SelectDir" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Open Folder" +script = ExtResource("3_7ja2l") +icon_name = "Folder" + +[node name="DeletePath" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Remove Path from Recent" +script = ExtResource("3_7ja2l") +icon_name = "Remove" + +[node name="HBoxContainer2" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +layout_mode = 2 +text = "Open Recent:" + +[node name="RecentPaths" type="OptionButton" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +clip_text = true +fit_to_longest_item = false +script = ExtResource("4_umoob") + +[node name="ImportExport" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +layout_mode = 2 +text = "Import/Export CSV..." +script = ExtResource("3_7ja2l") +icon_name = "TextFile" + +[node name="Search" type="VBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search"] +layout_mode = 2 + +[node name="ColorRect4" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +size_flags_vertical = 5 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer/ColorRect4"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +layout_mode = 2 +text = "GDScript Filter and Process" + +[node name="HSeparator" type="HSeparator" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Search" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search"] +layout_mode = 2 + +[node name="ColorRect2" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +size_flags_vertical = 5 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/Search/Search/ColorRect2"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +text = "Condition:" + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +tooltip_text = "Enter an expression. The table only show rows where the expression returns `true`. + +You can use `res.` to get a property, and `index` to get row number. Hit ENTER to run the search. + +Try out these: +- (res.number_property > 0 and res.number_property < 100) +- (res.text_property != \\\"\\\") +- (\\\"a\\\" in res.text_property) +- (index < 5)" +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="Filter" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_faq75") +editor_view_path = NodePath("../../../../..") +title = "func f(res : Resource, index : int):" +default_text = "true" +default_text_ml = "return true" +function_save_key = "filter" + +[node name="VSeparator" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 + +[node name="Class" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +script = ExtResource("6_2v7d5") + +[node name="Label5" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +text = "Class:" + +[node name="Class" type="OptionButton" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +clip_text = true +fit_to_longest_item = false + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +text = "Sub:" + +[node name="Subclasses" type="CheckBox" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +tooltip_text = "Include Subclasses" +button_pressed = true + +[node name="VSeparator2" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 + +[node name="Label3" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +text = "Process:" + +[node name="Label4" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +tooltip_text = "Enter an expression. The values in selected cells will be replaced with calculated new values. + +You can use `value` to get the cell's value, `res.` to get a property, `row_index` to get row number +and `cell_index` to get the cell's selection order. Hit ENTER to run the search. + +These are some valid expressions: +- (res.property1 + res.property2) +- (res.property1.replace(\\\"old_string\\\", \\\"new_string\\\")) +- (load(\\\"res://path/to_resource.tres\\\")) + +Don't forget quotation marks on strings and str() on non-strings." +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="Process" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_faq75") +editor_view_path = NodePath("../../../../..") +mode = 1 +title = "func f(value : Var, res : Resource, all_res : Array[Resource], row_index : int):" +default_text = "value" +default_text_ml = "return value" +function_save_key = "process" + +[node name="HBoxContainer3" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +text = "Grid" + +[node name="Refresh" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +tooltip_text = "Refresh" +script = ExtResource("3_7ja2l") +icon_name = "Loop" + +[node name="Pages" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_ka2yn") + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +text = "Page:" + +[node name="Scroll" type="ScrollContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +vertical_scroll_mode = 0 + +[node name="Pagelist" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages/Scroll"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +text = "Rows per page:" + +[node name="LineEdit" type="SpinBox" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +size_flags_vertical = 4 +min_value = 2.0 +max_value = 300.0 +value = 50.0 + +[node name="Sep" type="Control" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="Columns" type="Control" parent="HeaderContentSplit/VBoxContainer"] +clip_contents = true +layout_mode = 2 + +[node name="Columns" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Columns"] +layout_mode = 0 +theme_override_constants/separation = 0 +script = ExtResource("6_emnmd") +table_header_scene = ExtResource("7_3dx0v") + +[node name="Sep2" type="Control" parent="HeaderContentSplit/VBoxContainer"] +visible = false +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="FooterContentSplit" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Panel" type="MarginContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="Panel" type="Panel" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +layout_mode = 2 + +[node name="Scroll" type="ScrollContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll"] +layout_mode = 2 + +[node name="TableGrid" type="GridContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer"] +layout_mode = 2 +theme_override_constants/h_separation = 0 +theme_override_constants/v_separation = 0 + +[node name="Label" type="Label" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +self_modulate = Color(1, 1, 1, 0.498039) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +text = "No folder selected! +Please select a folder to edit using the text field or Open button above. + +Then, Shift+Click or Ctrl+Click cells to edit them using the keyboard, +Inspector dock or this screen's bottom panels. + +To find out keybindings available, open the \"About\" menu." +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="FrozenColumns" type="Control" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +clip_contents = true +layout_mode = 2 +mouse_filter = 2 + +[node name="FrozenColumns" type="ColorRect" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/FrozenColumns"] +layout_mode = 1 +size_flags_horizontal = 0 +mouse_filter = 2 +script = ExtResource("10_vb62w") + +[node name="Footer" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"] +layout_mode = 2 + +[node name="PropertyEditors" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="EditEnumArray" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("8_234wn")] +visible = false +layout_mode = 2 + +[node name="EditArray" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("9_nts08")] +visible = false +layout_mode = 2 + +[node name="EditDict" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("13_il556")] +visible = false +layout_mode = 2 + +[node name="EditColor" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("10_nsma2")] +visible = false +layout_mode = 2 + +[node name="EditNumber" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("11_q1ao4")] +visible = false +layout_mode = 2 + +[node name="EditTexture" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("12_4kr6q")] +visible = false +layout_mode = 2 + +[node name="Control" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 +metadata/_edit_lock_ = true + +[node name="FileDialog" type="FileDialog" parent="Control"] +title = "Open" +size = Vector2i(800, 500) +min_size = Vector2i(800, 400) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 3 +filters = PackedStringArray("*.tres", "*.res") + +[node name="FileDialogText" type="FileDialog" parent="Control"] +title = "Open or Create Text File" +size = Vector2i(800, 500) +min_size = Vector2i(800, 400) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 3 +filters = PackedStringArray("*.csv") + +[node name="Info" type="AcceptDialog" parent="Control"] +title = "About" +size = Vector2i(800, 500) + +[node name="MarginContainer" type="MarginContainer" parent="Control/Info"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -8.0 +offset_bottom = -49.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Panel" type="Panel" parent="Control/Info/MarginContainer"] +layout_mode = 2 + +[node name="RichTextLabel" type="RichTextLabel" parent="Control/Info/MarginContainer"] +layout_mode = 2 +bbcode_enabled = true +text = "Edit Resources as Table 2 + +\"Welp, it is what it sounds like!\" + +Possible inputs: +- Ctrl + Click / Cmd + Click - Select multiple cells in one column +- Shift + Click - Select all cells between A and B in one column +- Up / Down / Shift+Tab / Tab - move cell selection up/down/left/right + +- Left/Right - Move cursor along cell text +- Backspace/Delete - Erase text Left / Right from cursor +- Home/End - Move cursor to start/end of cell +- Ctrl + / Cmd + - Move through / Erase whole word + +- Ctrl/Cmd + C/V - Copy cells / Paste text into cells +- Ctrl/Cmd + (Shift) + Z - The Savior +If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell. + +Made by Don Tnowe. 2022. +https://twitter.com/don_tnowe +Issues and contribution: +https://github.com/don-tnowe/godot-resources-as-sheets-plugin" + +[node name="Settings" type="AcceptDialog" parent="Control"] +title = "Settings" +size = Vector2i(500, 300) +min_size = Vector2i(500, 300) + +[node name="Settings" parent="Control/Settings" instance=ExtResource("13_as1sh")] + +[node name="ImportExport" type="Window" parent="Control"] +process_mode = 3 +initial_position = 4 +size = Vector2i(600, 400) +visible = false +transient = true +exclusive = true +min_size = Vector2i(600, 400) + +[node name="ImportExport" parent="Control/ImportExport" instance=ExtResource("14_3p12b")] + +[node name="SelectionActions" parent="Control" instance=ExtResource("23_m53sx")] +visible = false +layout_mode = 2 +offset_left = -506.0 +offset_top = 65.0 +offset_right = -426.0 +offset_bottom = 117.0 + +[node name="InputHandler" type="Node" parent="."] +script = ExtResource("14_2t57a") + +[node name="SelectionManager" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 +script = ExtResource("15_mx6qn") +cell_editor_classes = Array[Script]([ExtResource("16_p7n52"), ExtResource("19_oeuko"), ExtResource("17_sofdw"), ExtResource("18_oeewr"), ExtResource("19_7x44x"), ExtResource("20_swsbn"), ExtResource("21_58wf8"), ExtResource("28_a0j2e"), ExtResource("22_bni8r")]) +metadata/_edit_lock_ = true + +[connection signal="grid_updated" from="." to="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" method="_on_grid_updated"] +[connection signal="grid_updated" from="." to="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/FrozenColumns/FrozenColumns" method="_on_grid_updated"] +[connection signal="gui_input" from="." to="InputHandler" method="_gui_input"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/File" to="." method="_on_File_pressed"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/SearchProcess" to="." method="_on_SearchProcess_pressed"] +[connection signal="about_to_popup" from="HeaderContentSplit/VBoxContainer/MenuStrip/VisibleCols" to="HeaderContentSplit/VBoxContainer/Columns/Columns" method="_on_visible_cols_about_to_popup"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/Settings" to="Control/Settings" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/Info" to="Control/Info" method="popup_centered"] +[connection signal="text_submitted" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path" to="." method="_on_path_text_submitted"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/SelectDir" to="Control/FileDialog" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/DeletePath" to="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/RecentPaths" method="remove_selected_path_from_recent"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/ImportExport" to="Control/FileDialogText" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer3/Refresh" to="." method="_on_path_text_submitted"] +[connection signal="value_changed" from="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages/LineEdit" to="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" method="_on_LineEdit_value_changed"] +[connection signal="dir_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] +[connection signal="file_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] +[connection signal="dir_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_file_selected"] +[connection signal="file_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_file_selected"] +[connection signal="files_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_files_selected"] +[connection signal="close_requested" from="Control/ImportExport" to="Control/ImportExport" method="hide"] +[connection signal="cells_rightclicked" from="SelectionManager" to="Control/SelectionActions" method="_on_grid_cells_rightclicked"] +[connection signal="cells_selected" from="SelectionManager" to="Control/SelectionActions" method="_on_grid_cells_selected"] diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd new file mode 100644 index 00000000..ff18907f --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd @@ -0,0 +1,36 @@ +class_name ResourceTablesEditFormat +extends RefCounted + +var editor_view : Control + +## Override to define reading behaviour. +func get_value(entry, key : String): + pass + +## Override to define writing behaviour. This is NOT supposed to save - use `save_entries`. +func set_value(entry, key : String, value, index : int): + pass + +## Override to define how the data gets saved. +func save_entries(all_entries : Array, indices : Array): + pass + +## Override to allow editing rows from the Inspector. +func create_resource(entry) -> Resource: + return Resource.new() + +## Override to define duplication behaviour. `name_input` should be a suffix if multiple entries, and full name if one. +func duplicate_rows(rows : Array, name_input : String): + pass + +## Override to define removal behaviour. +func delete_rows(rows : Array): + pass + +## Override with `return true` if `resource_path` is defined and the Rename butoon should show. +func has_row_names(): + return false + +## Override to define import behaviour. Must return the `rows` value for the editor view. +func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + return [] diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid new file mode 100644 index 00000000..d469515a --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid @@ -0,0 +1 @@ +uid://c3ck0jsff86i0 diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd new file mode 100644 index 00000000..96fb2f52 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd @@ -0,0 +1,88 @@ +class_name ResourceTablesEditFormatCsv +extends ResourceTablesEditFormatTres + +var import_data : ResourceTablesImport +var csv_rows := [] +var resource_original_positions := {} + + +func get_value(entry, key : String): + return entry.get(key) + + +func set_value(entry, key : String, value, index : int): + entry.set(key, value) + csv_rows[resource_original_positions[entry]] = import_data.resource_to_strings(entry) + + +func save_entries(all_entries : Array, indices : Array, repeat : bool = true): + if timer == null or timer.time_left <= 0.0: + var space_after_delimiter := import_data.delimeter.ends_with(" ") + var file := FileAccess.open(import_data.edited_path, FileAccess.WRITE) + for x in csv_rows: + if space_after_delimiter: + for i in x.size(): + if i == 0: continue + x[i] = " " + x[i] + + file.store_csv_line(x, import_data.delimeter[0]) + + if repeat: + timer = editor_view.get_tree().create_timer(3.0) + timer.timeout.connect(save_entries.bind(all_entries, indices, false)) + + +func create_resource(entry) -> Resource: + return entry + + +func duplicate_rows(rows : Array, name_input : String): + for x in rows: + var new_res = x.duplicate() + var index : int = resource_original_positions[x] + csv_rows.insert(index, import_data.resource_to_strings(new_res)) + _bump_row_indices(index + 1, 1) + resource_original_positions[new_res] = index + 1 + + save_entries([], []) + + +func delete_rows(rows): + for x in rows: + var index : int = resource_original_positions[x] + csv_rows.remove_at(index) + _bump_row_indices(index, -1) + resource_original_positions.erase(x) + + save_entries([], []) + + +func has_row_names(): + return false + + +func _bump_row_indices(from : int, increment : int = 1): + for k in resource_original_positions: + if resource_original_positions[k] >= from: + resource_original_positions[k] += increment + + +func import_from_path(path : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + import_data = load(path) + var file := FileAccess.open(import_data.edited_path, FileAccess.READ) + csv_rows = ResourceTablesImportFormatCsv.import_as_arrays(import_data) + + var rows := [] + var res : Resource + resource_original_positions.clear() + for i in csv_rows.size(): + if import_data.remove_first_row and i == 0: + continue + + res = import_data.strings_to_resource(csv_rows[i], "") + res.resource_path = "" + insert_func.call(res, rows, sort_by, sort_reverse) + resource_original_positions[res] = i + + editor_view.fill_property_data(rows[0]) + return rows \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid new file mode 100644 index 00000000..3eecdcc4 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid @@ -0,0 +1 @@ +uid://b1ksuhdokhkd3 diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd new file mode 100644 index 00000000..116adc50 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd @@ -0,0 +1,119 @@ +class_name ResourceTablesEditFormatTres +extends ResourceTablesEditFormat + +var timer : SceneTreeTimer + + +func get_value(entry, key : String): + return entry[key] + + +func set_value(entry, key : String, value, index : int): + entry[key] = value + + +func save_entries(all_entries : Array, indices : Array, repeat : bool = true): + # No need to save. Resources are saved with Ctrl+S + # (likely because plugin.edit_resource is called to show inspector) + return + + +func create_resource(entry) -> Resource: + return entry + + +func duplicate_rows(rows : Array, name_input : String): + if rows.size() == 1: + var new_row = rows[0].duplicate() + var res_extension := ".res" if rows[0].resource_path.ends_with(".res") else ".tres" + new_row.resource_path = rows[0].resource_path.get_base_dir() + "/" + name_input + res_extension + ResourceSaver.save(new_row) + return + + var new_row + for x in rows: + new_row = x.duplicate() + var res_extension := ".res" if x.resource_path.ends_with(".res") else ".tres" + new_row.resource_path = x.resource_path.get_basename() + name_input + res_extension + ResourceSaver.save(new_row) + + +func rename_row(row, new_name : String): + var new_row = row + DirAccess.open("res://").remove(row.resource_path) + var res_extension := ".res" if row.resource_path.ends_with(".res") else ".tres" + new_row.resource_path = row.resource_path.get_base_dir() + "/" + new_name + res_extension + ResourceSaver.save(new_row) + + +func delete_rows(rows): + for x in rows: + DirAccess.open("res://").remove(x.resource_path) + + +func has_row_names(): + return true + + +func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + var solo_property := "" + var solo_property_split : Array[String] = [] + if folderpath.contains("::"): + var found_at := folderpath.find("::") + solo_property = folderpath.substr(found_at + "::".length()).trim_suffix("/") + folderpath = folderpath.left(found_at) + for x in solo_property.split("::"): + solo_property_split.append(x) + + var rows := [] + var dir := DirAccess.open(folderpath) + if dir == null: return [] + + var file_stack : Array[String] = [] + var folder_stack : Array[String] = [folderpath] + + while folder_stack.size() > 0: + folderpath = folder_stack.pop_back() + + for x in DirAccess.get_files_at(folderpath): + file_stack.append(folderpath.path_join(x)) + + for x in DirAccess.get_directories_at(folderpath): + folder_stack.append(folderpath.path_join(x)) + + var loaded_res_unique := {} + for x in file_stack: + if !x.ends_with(".tres") and !x.ends_with(".res"): + continue + + if solo_property.is_empty(): + loaded_res_unique[load(x)] = true + + else: + _append_soloed_property(load(x), loaded_res_unique, solo_property_split) + + for x in loaded_res_unique.keys(): + if x == null: continue + insert_func.call(x, rows, sort_by, sort_reverse) + + editor_view.fill_property_data_many(loaded_res_unique.keys()) + return rows + + +func _append_soloed_property(current_res : Resource, result : Dictionary, solo_property_split : Array[String], solo_property_split_idx : int = -solo_property_split.size()): + var soloed_value = current_res[solo_property_split[solo_property_split_idx]] + if solo_property_split_idx == -1: + if soloed_value is Resource: + result[soloed_value] = true + + elif soloed_value is Array: + for x in soloed_value: + result[x] = true + + else: + if soloed_value is Resource: + _append_soloed_property(soloed_value, result, solo_property_split, solo_property_split_idx + 1) + + elif soloed_value is Array: + for x in soloed_value: + _append_soloed_property(x, result, solo_property_split, solo_property_split_idx + 1) \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid new file mode 100644 index 00000000..fdd7a8da --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid @@ -0,0 +1 @@ +uid://begfw34lcjlmk diff --git a/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd new file mode 100644 index 00000000..b407a55c --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd @@ -0,0 +1,32 @@ +class_name ResourceTablesExportFormatCsv +extends RefCounted + + +static func can_edit_path(path : String): + return path.ends_with(".csv") + + +static func export_to_file(entries_array : Array, column_names : Array, into_path : String, import_data : ResourceTablesImport): + var file := FileAccess.open(into_path, FileAccess.WRITE) + + var line := PackedStringArray() + var space_after_delimiter := import_data.delimeter.ends_with(" ") + import_data.prop_names = column_names + import_data.prop_types = import_data.get_resource_property_types(entries_array[0], column_names) + import_data.resource_path = "" + line.resize(column_names.size()) + if import_data.remove_first_row: + for j in column_names.size(): + line[j] = String(column_names[j]) + if space_after_delimiter and j != 0: + line[j] = " " + line[j] + + file.store_csv_line(line, import_data.delimeter[0]) + + for i in entries_array.size(): + for j in column_names.size(): + line[j] = import_data.property_to_string((entries_array[i].get(column_names[j])), j) + if space_after_delimiter and j != 0: + line[j] = " " + line[j] + + file.store_csv_line(line, import_data.delimeter[0]) \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid new file mode 100644 index 00000000..26107ca4 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid @@ -0,0 +1 @@ +uid://wj6qqlduil8l diff --git a/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd new file mode 100644 index 00000000..6a3ad2f5 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd @@ -0,0 +1,57 @@ +class_name ResourceTablesImportFormatCsv +extends RefCounted + + +static func can_edit_path(path : String): + return path.ends_with(".csv") + + +static func get_properties(entries, import_data): + return Array(entries[0]) + + +static func import_as_arrays(import_data) -> Array: + var file := FileAccess.open(import_data.edited_path, FileAccess.READ) + + import_data.delimeter = ";" + var text_lines : Array[PackedStringArray] = [file.get_line().split(import_data.delimeter)] + var space_after_delimeter := false + var line := text_lines[0] + if line.size() == 0: + return [] + + if line.size() == 1: + import_data.delimeter = "," + line = line[0].split(import_data.delimeter) + text_lines[0] = line + if line.size() <= 1: + return [] + + if line[1].begins_with(" "): + for i in line.size(): + line[i] = line[i].trim_prefix(" ") + + text_lines[0] = line + space_after_delimeter = true + import_data.delimeter += " " + + while !file.eof_reached(): + line = file.get_csv_line(import_data.delimeter[0]) + if space_after_delimeter: + for i in line.size(): + line[i] = line[i].trim_prefix(" ") + + if line.size() == text_lines[0].size(): + text_lines.append(line) + + elif line.size() != 1: + line.resize(text_lines[0].size()) + text_lines.append(line) + + var entries := [] + entries.resize(text_lines.size()) + + for i in entries.size(): + entries[i] = text_lines[i] + + return entries diff --git a/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid new file mode 100644 index 00000000..cd4eda46 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid @@ -0,0 +1 @@ +uid://bxs8u1hqwxnlf diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd new file mode 100644 index 00000000..66884310 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd @@ -0,0 +1,241 @@ +@tool +extends Control + +@export var prop_list_item_scene : PackedScene +@export var formats_export : Array[Script] +@export var formats_import : Array[Script] + +@onready var editor_view := $"../../.." +@onready var filename_options := $"Import/Margins/Scroll/Box/Grid/UseAsFilename" +@onready var classname_field := $"Import/Margins/Scroll/Box/Grid/Classname" +@onready var script_path_field := $"Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" +@onready var prop_list := $"Import/Margins/Scroll/Box" +@onready var format_settings := $"Import/Margins/Scroll/Box/StyleSettingsI" +@onready var file_dialog_use_script: FileDialog = $"Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" + +var format_extension := ".csv" +var entries := [] + +var import_data : ResourceTablesImport + + +func _ready(): + hide() + show() + if get_parent().get("size"): + get_parent().size = Vector2(600, 400) + + file_dialog_use_script.file_selected.connect(_on_file_dialog_file_selected) + + +func _on_file_selected(path : String): + if !FileAccess.file_exists(path): + if path.get_extension() != "": + # Path is a file path: replace extension + path = path.get_basename() + ".csv" + + else: + # Path is a directory: add filename, add extension + path = path.path_join(editor_view.current_path.trim_suffix("/").get_file()) + ".csv" + + FileAccess.open(path, FileAccess.WRITE) + + import_data = null + for x in DirAccess.get_files_at(path.get_base_dir()): + if !x.ends_with(".tres") and !x.ends_with(".res"): + continue + + var found_res := load(path.get_base_dir().path_join(x)) + if !(found_res is ResourceTablesImport): + continue + + _import_settings_from_settings_file(found_res, path) + break + + if import_data == null: + _create_new_settings_file(path) + + _create_prop_editors() + $"Import/Margins/Scroll/Box/StyleSettingsI"._send_signal() + + if editor_view.rows.size() > 0: + var using_script = editor_view.rows[0].get_script() + if using_script != null: + script_path_field.text = using_script.resource_path + + await get_tree().process_frame + get_parent().popup_centered() + await get_tree().process_frame + get_parent().min_size = get_combined_minimum_size() + position = Vector2.ZERO + size = get_parent().size + + +func _on_files_selected(paths : PackedStringArray): + _on_file_selected(paths[0]) + + +func _import_settings_from_settings_file(settings_file : ResourceTablesImport, textfile_path : String): + import_data = settings_file + + filename_options.clear() + for i in import_data.prop_names.size(): + filename_options.add_item(import_data.prop_names[i], i) + + if import_data.new_script != null: + classname_field.text = import_data.new_script.get_global_name() + script_path_field.text = settings_file.new_script.resource_path + + format_settings.set_format_array(import_data.enum_format) + for format_x in formats_import: + var new_importer = format_x.new() + if new_importer.can_edit_path(textfile_path): + entries = format_x.new().import_as_arrays(import_data) + break + + +func _create_new_settings_file(textfile_path : String): + import_data = ResourceTablesImport.new() + import_data.initialize(textfile_path) + + for format_x in formats_import: + var new_importer = format_x.new() + if new_importer.can_edit_path(textfile_path): + entries = new_importer.import_as_arrays(import_data) + import_data.prop_names = new_importer.get_properties(entries, import_data) + break + + classname_field.text = import_data.edited_path.get_file().get_basename()\ + .capitalize().replace(" ", "") + import_data.script_classname = classname_field.text + if script_path_field.text: + var existing_resource : Resource = load(script_path_field.text).new() + import_data.prop_types = ResourceTablesImport.get_resource_property_types(existing_resource, import_data.prop_names) + + else: + import_data.load_property_names_from_textfile(textfile_path, entries) + + filename_options.clear() + for i in import_data.prop_names.size(): + filename_options.add_item(import_data.prop_names[i], i) + + +func _create_prop_editors(): + for x in prop_list.get_children(): + if !x is GridContainer: x.free() + + await get_tree().process_frame + for i in import_data.prop_names.size(): + var new_node := prop_list_item_scene.instantiate() + prop_list.add_child(new_node) + var prop_type = import_data.prop_types[i] + new_node.display(import_data.prop_names[i], prop_type if !(prop_type is PackedStringArray) else ResourceTablesImport.PropType.ENUM) + new_node.connect_all_signals(self, i) + + +func _generate_class(save_script = true): + save_script = true # Built-ins didn't work in 3.x, won't change because dont wanna test rn + import_data.new_script = import_data.generate_script(entries, save_script) + if save_script: + import_data.new_script.resource_path = import_data.edited_path.get_basename() + ".gd" + ResourceSaver.save(import_data.new_script) + # Because when instanced, objects have a copy of the script + import_data.new_script = load(import_data.edited_path.get_basename() + ".gd") + + +func _on_import_to_tres_pressed(): + if script_path_field.text != "": + import_data.load_external_script(load(script_path_field.text)) + + if import_data.new_script == null: + _generate_class() + + DirAccess.open("res://").make_dir_recursive(import_data.edited_path.get_basename()) + + import_data.prop_used_as_filename = import_data.prop_names[filename_options.selected] + var new_res : Resource + for i in entries.size(): + if import_data.remove_first_row and i == 0: + continue + + new_res = import_data.strings_to_resource(entries[i], editor_view.current_path) + ResourceSaver.save(new_res) + + await get_tree().process_frame + await get_tree().process_frame + editor_view.refresh() + close() + + +func _on_import_edit_pressed(): + if import_data.new_script == null: + _generate_class(false) + + import_data.prop_used_as_filename = "" + import_data.save() + await get_tree().process_frame + editor_view.display_folder(import_data.resource_path) + editor_view.node_columns.hidden_columns[editor_view.current_path] = { + "resource_path" : true, + "resource_local_to_scene" : true, + } + editor_view.save_data() + await get_tree().process_frame + editor_view.refresh() + close() + + +func _on_export_csv_pressed(): + var exported_cols : Array = editor_view.columns.duplicate() + exported_cols.erase(&"resource_local_to_scene") + for x in editor_view.node_columns.hidden_columns[editor_view.current_path].keys(): + exported_cols.erase(x) + + ResourceTablesExportFormatCsv.export_to_file(editor_view.rows, exported_cols, import_data.edited_path, import_data) + await get_tree().process_frame + editor_view.refresh() + close() + +# Input controls +func _on_classname_field_text_changed(new_text : String): + import_data.script_classname = new_text.replace(" ", "") + + +func _on_remove_first_row_toggled(button_pressed : bool): + import_data.remove_first_row = button_pressed +# $"Export/Box2/Button".button_pressed = true + $"Export/Box3/CheckBox".button_pressed = button_pressed + + +func _on_list_item_type_selected(type : int, index : int): + import_data.prop_types[index] = type + + +func _on_list_item_name_changed(name : String, index : int): + import_data.prop_names[index] = name.replace(" ", "") + + +func _on_export_delimiter_pressed(del : String): + import_data.delimeter = del + import_data.delimeter.substr(1) + + +func _on_export_space_toggled(button_pressed : bool): + import_data.delimeter = ( + import_data.delimeter[0] + if !button_pressed else + import_data.delimeter + " " + ) + + +func _on_enum_format_changed(case, delimiter, bool_yes, bool_no): + import_data.enum_format = [case, delimiter, bool_yes, bool_no] + + +func close(): + get_parent().hide() + + +# Handles reloading the import hint editor if a Resource script is chosen +func _on_file_dialog_file_selected(path: String) -> void: + script_path_field.text = path + _on_file_selected(import_data.edited_path) diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid new file mode 100644 index 00000000..bc3b923c --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid @@ -0,0 +1 @@ +uid://dn5vbpm4foj0a diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn b/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn new file mode 100644 index 00000000..d067c844 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn @@ -0,0 +1,240 @@ +[gd_scene load_steps=8 format=3 uid="uid://b413igx28kkvb"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/import_export_dialog.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd" id="2_33c6s"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd" id="2_fxayt"] +[ext_resource type="PackedScene" uid="uid://b8llymigbprh6" path="res://addons/resources_spreadsheet_view/import_export/property_list_item.tscn" id="2_xfhmf"] +[ext_resource type="PackedScene" uid="uid://ckhf3bqy2rqjr" path="res://addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn" id="4"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="5_k5rhi"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_080hd"] + +[node name="TabContainer" type="TabContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +current_tab = 1 +script = ExtResource("1") +prop_list_item_scene = ExtResource("2_xfhmf") +formats_export = Array[Script]([ExtResource("2_33c6s")]) +formats_import = Array[Script]([ExtResource("2_fxayt")]) + +[node name="Import" type="VBoxContainer" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +metadata/_tab_index = 0 + +[node name="Margins" type="MarginContainer" parent="Import"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Scroll" type="ScrollContainer" parent="Import/Margins"] +layout_mode = 2 +horizontal_scroll_mode = 0 + +[node name="Box" type="VBoxContainer" parent="Import/Margins/Scroll"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Grid" type="GridContainer" parent="Import/Margins/Scroll/Box"] +layout_mode = 2 +columns = 2 + +[node name="Label" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Column Used as Filename:" + +[node name="UseAsFilename" type="OptionButton" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label4" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Use Script:" + +[node name="HBoxContainer" type="HBoxContainer" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "(create new GDScript)" +editable = false + +[node name="Button2" type="Button" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +script = ExtResource("5_k5rhi") +icon_name = "Clear" + +[node name="Button" type="Button" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +script = ExtResource("5_k5rhi") +icon_name = "Folder" + +[node name="FileDialog" type="FileDialog" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +title = "Choose Script..." +initial_position = 4 +size = Vector2i(800, 500) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 0 +filters = PackedStringArray("*.gd", "*.cs") + +[node name="Control" type="Control" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="Label5" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +self_modulate = Color(1, 0.84375, 0, 1) +layout_mode = 2 +text = "WARNING: Importing with a pre-existing Script will not import datatypes not selectible below." +horizontal_alignment = 1 +autowrap_mode = 3 + +[node name="Label2" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +visible = false +layout_mode = 2 +text = "Class Name" + +[node name="Classname" type="LineEdit" parent="Import/Margins/Scroll/Box/Grid"] +visible = false +layout_mode = 2 +caret_blink = true +caret_blink_interval = 0.5 + +[node name="Label3" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Flags:" + +[node name="Flags" type="VBoxContainer" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="RemoveFirstRow" type="CheckBox" parent="Import/Margins/Scroll/Box/Grid/Flags"] +layout_mode = 2 +text = "First row contains property names" + +[node name="HSeparator" type="HSeparator" parent="Import/Margins/Scroll/Box"] +layout_mode = 2 + +[node name="StyleSettingsI" parent="Import/Margins/Scroll/Box" instance=ExtResource("4")] +layout_mode = 2 + +[node name="Box" type="HBoxContainer" parent="Import"] +layout_mode = 2 +mouse_filter = 2 +alignment = 1 + +[node name="Ok2" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Confirm and edit" + +[node name="Ok" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Convert to Resources and edit" + +[node name="Cancel" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Cancel" + +[node name="Control" type="Control" parent="Import"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Export" type="VBoxContainer" parent="."] +layout_mode = 2 +metadata/_tab_index = 1 + +[node name="Info" type="Label" parent="Export"] +layout_mode = 2 +size_flags_vertical = 0 +text = "The currently edited folder will be exported into the selected file. + +Rows hidden by the filter will NOT be exported, and order follows the current sorting key. Rows on non-selected pages will not be removed. + +Hidden columns will NOT be exported." +autowrap_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="Export"] +layout_mode = 2 + +[node name="Box" type="HBoxContainer" parent="Export"] +layout_mode = 2 +alignment = 1 + +[node name="Label2" type="Label" parent="Export/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Delimiter:" + +[node name="Button" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_pressed = true +button_group = SubResource("ButtonGroup_080hd") +text = "Comma (,)" + +[node name="Button2" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_080hd") +text = "Semicolon (;)" + +[node name="Button3" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_080hd") +text = "Tab" + +[node name="CheckBox" type="CheckBox" parent="Export/Box"] +layout_mode = 2 +text = "With space after" + +[node name="Box3" type="HBoxContainer" parent="Export"] +layout_mode = 2 + +[node name="CheckBox" type="CheckBox" parent="Export/Box3"] +layout_mode = 2 +text = "First row contains property names (CSV)" + +[node name="StyleSettingsE" parent="Export" instance=ExtResource("4")] +layout_mode = 2 + +[node name="Control" type="Control" parent="Export"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Box2" type="HBoxContainer" parent="Export"] +layout_mode = 2 +alignment = 1 + +[node name="Button" type="Button" parent="Export/Box2"] +layout_mode = 2 +text = "Export to CSV" + +[node name="Cancel" type="Button" parent="Export/Box2"] +layout_mode = 2 +text = "Cancel" + +[node name="Control2" type="Control" parent="Export"] +layout_mode = 2 + +[connection signal="pressed" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/Button2" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" method="set_text" binds= [""]] +[connection signal="pressed" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/Button" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" method="popup_centered"] +[connection signal="file_selected" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" method="set_text"] +[connection signal="text_changed" from="Import/Margins/Scroll/Box/Grid/Classname" to="." method="_on_classname_field_text_changed"] +[connection signal="toggled" from="Import/Margins/Scroll/Box/Grid/Flags/RemoveFirstRow" to="." method="_on_remove_first_row_toggled"] +[connection signal="format_changed" from="Import/Margins/Scroll/Box/StyleSettingsI" to="." method="_on_enum_format_changed"] +[connection signal="format_changed" from="Import/Margins/Scroll/Box/StyleSettingsI" to="Export/StyleSettingsE" method="_on_format_changed"] +[connection signal="pressed" from="Import/Box/Ok2" to="." method="_on_import_edit_pressed"] +[connection signal="pressed" from="Import/Box/Ok" to="." method="_on_import_to_tres_pressed"] +[connection signal="pressed" from="Import/Box/Cancel" to="." method="close"] +[connection signal="pressed" from="Export/Box/Button" to="." method="_on_export_delimiter_pressed" binds= [","]] +[connection signal="pressed" from="Export/Box/Button2" to="." method="_on_export_delimiter_pressed" binds= [";"]] +[connection signal="pressed" from="Export/Box/Button3" to="." method="_on_export_delimiter_pressed" binds= [" "]] +[connection signal="toggled" from="Export/Box/CheckBox" to="." method="_on_export_space_toggled"] +[connection signal="toggled" from="Export/Box3/CheckBox" to="." method="_on_remove_first_row_toggled"] +[connection signal="format_changed" from="Export/StyleSettingsE" to="." method="_on_enum_format_changed"] +[connection signal="pressed" from="Export/Box2/Button" to="." method="_on_export_csv_pressed"] +[connection signal="pressed" from="Export/Box2/Cancel" to="." method="close"] diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd new file mode 100644 index 00000000..4c5e404b --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd @@ -0,0 +1,30 @@ +@tool +extends GridContainer + +signal format_changed(case : int, delimiter : String, bool_yes : String, bool_no: String) + + +func set_format_array(format : Array): + _on_format_changed(format[0], format[1], format[2], format[3]) + format_changed.emit(format[0], format[1], format[2], format[3]) + + +func set_format(case : int, delimiter : String, bool_yes : String, bool_no: String): + _on_format_changed(case, delimiter, bool_yes, bool_no) + format_changed.emit(case, delimiter, bool_yes, bool_no) + + +func _send_signal(arg1 = null): + format_changed.emit( + $"HBoxContainer/Case".selected, + [" ", "_", "-"][$"HBoxContainer/Separator".selected], + $"HBoxContainer2/True".text, + $"HBoxContainer2/False".text + ) + + +func _on_format_changed(case : int, delimiter : String, bool_yes : String, bool_no: String): + $"HBoxContainer/Case".selected = case + $"HBoxContainer/Separator".selected = [" ", "_", "-"].find(delimiter) + $"HBoxContainer2/True".text = bool_yes + $"HBoxContainer2/False".text = bool_no diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid new file mode 100644 index 00000000..5cf8e757 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid @@ -0,0 +1 @@ +uid://bwx4j0loexx47 diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn new file mode 100644 index 00000000..e2ae4402 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=2 format=3 uid="uid://ckhf3bqy2rqjr"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd" id="1"] + +[node name="EnumFormat" type="GridContainer"] +columns = 2 +script = ExtResource("1") + +[node name="Label3" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Enum word case/separator" + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Case" type="OptionButton" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +clip_text = true +selected = 2 +item_count = 4 +popup/item_0/text = "all lower" +popup/item_1/text = "caps Except First" +popup/item_1/id = 1 +popup/item_2/text = "Caps Every Word" +popup/item_2/id = 2 +popup/item_3/text = "ALL CAPS" +popup/item_3/id = 3 + +[node name="Separator" type="OptionButton" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.5 +clip_text = true +selected = 0 +item_count = 3 +popup/item_0/text = "Space \" \"" +popup/item_1/text = "Underscore \"_\"" +popup/item_1/id = 1 +popup/item_2/text = "Kebab \"-\"" +popup/item_2/id = 2 + +[node name="Label4" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Boolean True/False" + +[node name="HBoxContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="True" type="LineEdit" parent="HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Yes" + +[node name="False" type="LineEdit" parent="HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "No" + +[connection signal="mouse_entered" from="Label3" to="." method="_on_Label3_mouse_entered"] +[connection signal="item_selected" from="HBoxContainer/Case" to="." method="_send_signal"] +[connection signal="item_selected" from="HBoxContainer/Separator" to="." method="_send_signal"] +[connection signal="text_changed" from="HBoxContainer2/True" to="." method="_send_signal"] +[connection signal="text_changed" from="HBoxContainer2/False" to="." method="_send_signal"] diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.gd b/addons/resources_spreadsheet_view/import_export/property_list_item.gd new file mode 100644 index 00000000..ecae6609 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.gd @@ -0,0 +1,12 @@ +@tool +extends HBoxContainer + + +func display(name : String, type : int): + $"LineEdit".text = name + $"OptionButton".selected = type + + +func connect_all_signals(to : Object, index : int, prefix : String = "_on_list_item_"): + $"LineEdit".text_changed.connect(Callable(to, prefix + "name_changed").bind(index)) + $"OptionButton".item_selected.connect(Callable(to, prefix + "type_selected").bind(index)) diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid b/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid new file mode 100644 index 00000000..ead1b51b --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid @@ -0,0 +1 @@ +uid://myerw3pilvgk diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.tscn b/addons/resources_spreadsheet_view/import_export/property_list_item.tscn new file mode 100644 index 00000000..a0732f75 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=2 format=3 uid="uid://b8llymigbprh6"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/property_list_item.gd" id="1"] + +[node name="Entry" type="HBoxContainer"] +script = ExtResource("1") + +[node name="LineEdit" type="LineEdit" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.5 +text = "1" + +[node name="OptionButton" type="OptionButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 5 +size_flags_stretch_ratio = 0.25 +fit_to_longest_item = false +item_count = 8 +popup/item_0/text = "Bool" +popup/item_0/id = 1 +popup/item_1/text = "Integer Number" +popup/item_1/id = 2 +popup/item_2/text = "Floating Point Number" +popup/item_2/id = 3 +popup/item_3/text = "String/Other" +popup/item_3/id = 4 +popup/item_4/text = "Color" +popup/item_4/id = 14 +popup/item_5/text = "Resource Path" +popup/item_5/id = 17 +popup/item_6/text = "Enumeration" +popup/item_6/id = 101 +popup/item_7/text = "Array" +popup/item_7/id = 102 diff --git a/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd new file mode 100644 index 00000000..e0a6e381 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd @@ -0,0 +1,430 @@ +@tool +class_name ResourceTablesImport +extends Resource + +enum PropType { + BOOL, + INT, + FLOAT, + STRING, + COLOR, + OBJECT, + ENUM, + COLLECTION, + MAX, +} + +enum NameCasing { + ALL_LOWER, + CAPS_WORD_EXCEPT_FIRST, + CAPS_WORD, + ALL_CAPS, +} + +const SUFFIX := "_table_import.tres" +const TYPE_MAP := { + TYPE_STRING : PropType.STRING, + TYPE_FLOAT : PropType.FLOAT, + TYPE_BOOL : PropType.BOOL, + TYPE_INT : PropType.INT, + TYPE_OBJECT : PropType.OBJECT, + TYPE_COLOR : PropType.COLOR, + TYPE_ARRAY : PropType.COLLECTION, + TYPE_DICTIONARY : PropType.COLLECTION, +} + +@export var prop_types : Array +@export var prop_names : Array + +@export var edited_path := "res://" +@export var prop_used_as_filename := "" +@export var script_classname := "" +@export var remove_first_row := true + +@export var new_script : Script +@export var view_script : Script = ResourceTablesEditFormatCsv +@export var delimeter := ";" +@export var enum_format : Array = [NameCasing.CAPS_WORD, " ", "Yes", "No"] + +@export var uniques : Dictionary + + +func initialize(path): + edited_path = path + prop_types = [] + prop_names = [] + + +func save(): + resource_path = edited_path.get_basename() + SUFFIX + ResourceSaver.save.call_deferred(self) + + +func string_to_property(string : String, col_index : int): + match prop_types[col_index]: + PropType.STRING: + return string + + PropType.BOOL: + string = string.to_lower() + if string == enum_format[2].to_lower(): return true + if string == enum_format[3].to_lower(): return false + return !string in ["no", "disabled", "-", "false", "absent", "wrong", "off", "0", ""] + + PropType.FLOAT: + return string.to_float() + + PropType.INT: + return string.to_int() + + PropType.COLOR: + return Color(string) + + PropType.OBJECT: + return null if string == "" else load(string) + + PropType.ENUM: + if string == "": + return int(uniques[col_index]["N_A"]) + + else: + return int(uniques[col_index][string.capitalize().replace(" ", "_").to_upper()]) + # if string.is_valid_int(): + # return int(uniques[col_index][string.capitalize().replace(" ", "_").to_upper()]) + # else: + # # If the enum is a string, we actually just want the key not the value + # var enum_keys : Dictionary = uniques[col_index] + # return int(enum_keys.find_key(string)) + + PropType.COLLECTION: + var result = str_to_var(string) + if result is Array: + for i in result.size(): + if result[i] is String && result[i].begins_with("res://"): + result[i] = load(result[i]) + + if result is Dictionary: + for k in result: + if result[k] is String && result[k].begins_with("res://"): + result[k] = load(result[k]) + + if result == null: + result = [] + + return result + + +func property_to_string(value, col_index : int) -> String: + if value == null: return "" + if prop_types[col_index] is PackedStringArray: + return prop_types[col_index][value].capitalize() + + match prop_types[col_index]: + PropType.STRING: + return str(value) + + PropType.BOOL: + return enum_format[2] if value else enum_format[3] + + PropType.FLOAT, PropType.INT: + return str(value) + + PropType.COLOR: + return value.to_html() + + PropType.OBJECT: + return value.resource_path + + PropType.COLLECTION: + value = value.duplicate() + if value is Array: + for i in value.size(): + if value[i] is Resource: + value[i] = value[i].resource_path + + if value is Dictionary: + for k in value: + if value[k] is Resource: + value[k] = value[k].resource_path + + return str(value) + + PropType.ENUM: + var dict = uniques[col_index] + for k in dict: + if dict[k] == value: + return change_name_to_format(k, enum_format[0], enum_format[1]) + + return str(value) + + +func create_property_line_for_prop(col_index : int) -> String: + var result : String = "@export var " + prop_names[col_index] + " :" + match prop_types[col_index]: + PropType.STRING: + return result + "= \"\"\r\n" + + PropType.BOOL: + return result + "= false\r\n" + + PropType.FLOAT: + return result + "= 0.0\r\n" + + PropType.INT: + return result + "= 0\r\n" + + PropType.COLOR: + return result + "= Color.WHITE\r\n" + + PropType.OBJECT: + return result + " Resource\r\n" + + PropType.COLLECTION: + return result + "= []\r\n" + + PropType.ENUM: + return result + " %s\r\n" % _escape_forbidden_enum_names(prop_names[col_index].capitalize().replace(" ", "")) + # return result.replace( + # "@export var", + # "@export_enum(" + _escape_forbidden_enum_names( + # prop_names[col_index].capitalize()\ + # .replace(" ", "") + # ) + ") var" + # ) + "= 0\r\n" + + return "" + + +func _escape_forbidden_enum_names(string : String) -> String: + if ClassDB.class_exists(string): + return string + "_" + + # Not in ClassDB, but are engine types and can be property names + if string in [ + "Color", "String", "Plane", "Projection", + "Basis", "Transform", "Variant", + ]: + return string + "_" + + return string + + +func create_enum_for_prop(col_index) -> String: + var result := ( + "enum " + + _escape_forbidden_enum_names( + prop_names[col_index].capitalize().replace(" ", "") + ) + " {\r\n" + ) + for k in uniques[col_index]: + result += ( + "\t" + + k # Enum Entry + + " = " + + str(uniques[col_index][k]) # Value + + ",\r\n" + ) + result += "\tMAX,\r\n}\r\n\r\n" + + return result + + +func generate_script(entries, has_classname = true) -> GDScript: + var source := "" +# if has_classname and script_classname != "": +# source = "class_name " + script_classname + " \r\nextends Resource\r\n\r\n" +# +# else: + source = "extends Resource\r\n\r\n" + + # Enums + uniques = get_uniques(entries) + for i in prop_types.size(): + if prop_types[i] == PropType.ENUM: + source += create_enum_for_prop(i) + + # Properties + for i in prop_names.size(): + if (prop_names[i] != "resource_path") and (prop_names[i] != "resource_name"): + source += create_property_line_for_prop(i) + + var created_script : GDScript = GDScript.new() + created_script.source_code = source + created_script.reload() + return created_script + + +func load_property_names_from_textfile(path : String, loaded_entries : Array): + prop_types.resize(prop_names.size()) + prop_types.fill(4) + for i in prop_names.size(): + prop_names[i] = loaded_entries[0][i]\ + .replace("\"", "")\ + .replace(" ", "_")\ + .replace("-", "_")\ + .replace(".", "_")\ + .replace(",", "_")\ + .replace("\t", "_")\ + .replace("/", "_")\ + .replace("\\", "_")\ + .to_lower() + + var value = loaded_entries[1][i] + var value_cast = str_to_var(value) + # Don't guess Ints automatically - further rows might have floats + if value_cast is Array or value_cast is Dictionary: + prop_types[i] = ResourceTablesImport.PropType.COLLECTION + elif value.is_valid_float(): + prop_types[i] = ResourceTablesImport.PropType.FLOAT + elif value.begins_with("res://") && prop_names[i] != "resource_path": + prop_types[i] = ResourceTablesImport.PropType.OBJECT + elif value.length() == 6 or value.length() == 8 or (value.length() > 0 and value[0] == "#"): + prop_types[i] = ResourceTablesImport.PropType.COLOR + else: + prop_types[i] = ResourceTablesImport.PropType.STRING + + +func load_external_script(script_res : Script): + new_script = script_res + var result := {} + for x in script_res.get_script_property_list(): + + if x.hint != PROPERTY_HINT_ENUM or x.type != TYPE_INT: + continue + + var cur_value := "" + var result_for_prop := {} + result[prop_names.find(x.name)] = result_for_prop + var hint_arr : Array = x.hint_string.split(",") + for current_hint in hint_arr.size(): + var colon_found : int = hint_arr[current_hint].rfind(":") + cur_value = hint_arr[current_hint] + if cur_value == "": + cur_value = "N_A" + + if colon_found != -1: + var value_split := cur_value.split(":") + result_for_prop[value_split[1].to_upper()] = value_split[0] + + else: + result_for_prop[cur_value.to_upper()] = result_for_prop.size() + + uniques = result + + +func strings_to_resource(strings : Array, destination_path : String) -> Resource: + if destination_path == "": + destination_path = edited_path.get_base_dir().path_join("import/") + DirAccess.make_dir_recursive_absolute(destination_path) + + # If a full path is provided this catches that case + var new_path : String = strings[prop_names.find(prop_used_as_filename)] + + if !FileAccess.file_exists(new_path): + new_path = destination_path.path_join(new_path).trim_suffix(".tres") + ".tres" + + if !FileAccess.file_exists(new_path): + new_path = (strings[prop_names.find(prop_used_as_filename)] + .trim_prefix(destination_path) + .trim_suffix(".tres") + ".tres" + ) + if !new_path.begins_with("res://"): + new_path = destination_path.path_join(new_path) + + DirAccess.make_dir_recursive_absolute(new_path.get_base_dir()) + + var new_res : Resource + if FileAccess.file_exists(new_path): + new_res = load(new_path) + + else: + new_res = new_script.new() + new_res.resource_path = new_path + + for i in mini(prop_names.size(), strings.size()): + var skip_next := false + var cast_array := false + + # This is awful, but the workaround for typed casting + # https://github.com/godotengine/godot/issues/72620 + var property_value = string_to_property(strings[i], i) + if property_value is Array: + var property_value_as_typed := new_res.get(prop_names[i]) + property_value_as_typed.assign(property_value) + new_res.set(prop_names[i], property_value_as_typed) + + else: + new_res.set(prop_names[i], property_value) + + if prop_used_as_filename != "": + new_res.resource_path = new_path + + return new_res + + +func resource_to_strings(res : Resource): + var strings := [] + strings.resize(prop_names.size()) + for i in prop_names.size(): + strings[i] = property_to_string(res.get(prop_names[i]), i) + + return PackedStringArray(strings) + + +func get_uniques(entries : Array) -> Dictionary: + var result := {} + for i in prop_types.size(): + if prop_types[i] == PropType.ENUM: + var cur_value := "" + result[i] = {} + for j in entries.size(): + if j == 0 and remove_first_row: continue + + cur_value = entries[j][i].capitalize().to_upper().replace(" ", "_") + if cur_value == "": + cur_value = "N_A" + + if !result[i].has(cur_value): + result[i][cur_value] = result[i].size() + + return result + + +static func change_name_to_format(name : String, case : int, delim : String): + var string := name.capitalize().replace(" ", delim) + if case == NameCasing.ALL_LOWER: + return string.to_lower() + + if case == NameCasing.CAPS_WORD_EXCEPT_FIRST: + return string[0].to_lower() + string.substr(1) + + if case == NameCasing.CAPS_WORD: + return string + + if case == NameCasing.ALL_CAPS: + return string.to_upper() + + +static func get_resource_property_types(res : Resource, properties : Array) -> Array: + var result := [] + result.resize(properties.size()) + result.fill(PropType.STRING) + var cur_type := 0 + for x in res.get_property_list(): + var found := properties.find(x["name"]) + if found == -1: continue + if x["usage"] & PROPERTY_USAGE_EDITOR != 0: + if x["hint"] == PROPERTY_HINT_ENUM: + + var enum_values : PackedStringArray = x["hint_string"].split(",") + for i in enum_values.size(): + var index_found : int = enum_values[i].find(":") + if index_found == -1: continue + enum_values[i] = enum_values[i].left(index_found) + + result[found] = enum_values + + else: + result[found] = TYPE_MAP.get(x["type"], PropType.STRING) + + return result diff --git a/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid new file mode 100644 index 00000000..46a4d6a6 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid @@ -0,0 +1 @@ +uid://drkldkxc5lgdr diff --git a/addons/resources_spreadsheet_view/main_screen/class_filter.gd b/addons/resources_spreadsheet_view/main_screen/class_filter.gd new file mode 100644 index 00000000..f952c77e --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/class_filter.gd @@ -0,0 +1,146 @@ +@tool +extends Control + +@onready var editor_view := $"../../../../.." +@onready var node_options := $"Class" +@onready var node_subclasses_check := $"Subclasses" + +var found_builtins : Array[String] = [] +var found_scripts : Array[Script] = [] +var selected_builtin := &"" +var selected_script : Script +var selected_is_valid := false +var include_subclasses := true + + +func _ready(): + node_options.item_selected.connect(_on_item_selected) + node_subclasses_check.toggled.connect(_on_subclasses_toggled) + + +func fill(resources : Array): + node_options.clear() + found_scripts.clear() + found_builtins.clear() + var class_set := {} + for x in resources: + class_set[x.get_script()] = true + class_set[StringName(x.get_class())] = true + var current_s : Script = x.get_script() + while current_s != null: + current_s = current_s.get_base_script() + if class_set.has(current_s): + break + + class_set[current_s] = true + + var current_c : StringName = x.get_class() + while true: + if current_c == &"Resource": + break + + current_c = ClassDB.get_parent_class(current_c) + if class_set.has(current_c): + break + + class_set[current_c] = true + + class_set.erase(null) + class_set.erase("Resource") + + for k in class_set: + if k is StringName: + found_builtins.append(k) + + if k is Script: + found_scripts.append(k) + + # Add builtins, then script classes, in order. + node_options.add_item("") + for x in found_builtins: + node_options.add_item(x) + if has_theme_icon(x, &"EditorIcons"): + node_options.set_item_icon(-1, get_theme_icon(x, &"EditorIcons")) + + else: + node_options.set_item_icon(-1, get_theme_icon(&"Object", &"EditorIcons")) + + for x in found_scripts: + node_options.add_item(x.resource_path.get_file().get_basename().to_pascal_case()) + node_options.set_item_icon(-1, get_theme_icon(&"Script", &"EditorIcons")) + + node_options.add_item("") + + # Filter is disabled if the already selected class is not in the set. + if not class_set.has(selected_script) and not class_set.has(selected_builtin): + selected_is_valid = false + + # When the list is cleared, text and icon are cleared too. Setting to -1 explicitly allows changing icon and label + node_options.selected = -1 + if not selected_is_valid: + node_options.set_item_icon(-1, null) + + elif selected_builtin == &"" or selected_builtin == &"Resource": + node_options.set_item_icon(-1, get_theme_icon("Script", "EditorIcons")) + + else: + node_options.set_item_icon(-1, get_theme_icon(selected_builtin, "EditorIcons")) + + show() + + +func clear(): + selected_is_valid = false + + +func filter(resource : Resource) -> bool: + if not selected_is_valid: + return true + + if resource.get_class() != selected_builtin: + if include_subclasses and selected_script == null: + var cur_class := StringName(resource.get_class()) + while cur_class != &"Object": + cur_class = ClassDB.get_parent_class(cur_class) + if cur_class == selected_builtin: + return true + + return false + + if selected_script != null and resource.get_script() != selected_script: + if include_subclasses: + var cur_class : Script = resource.get_script() + while cur_class != null: + cur_class = cur_class.get_base_script() + if cur_class == selected_script: + return true + + return false + + + return true + + +func _on_item_selected(index : int): + if index == 0: + selected_builtin = &"" + selected_script = null + selected_is_valid = false + + elif index <= found_builtins.size(): + selected_builtin = found_builtins[index - 1] + selected_script = null + selected_is_valid = true + + elif index <= found_builtins.size() + found_scripts.size(): + selected_script = found_scripts[index - found_builtins.size() - 1] + selected_builtin = selected_script.get_instance_base_type() + selected_is_valid = true + + node_options.tooltip_text = "Selected: %s" % node_options.get_item_text(index) + editor_view.refresh() + + +func _on_subclasses_toggled(state : bool): + include_subclasses = state + editor_view.refresh() diff --git a/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid b/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid new file mode 100644 index 00000000..d9c90f31 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid @@ -0,0 +1 @@ +uid://bw8bams3j0086 diff --git a/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd new file mode 100644 index 00000000..02e1473d --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd @@ -0,0 +1,189 @@ +@tool +extends Control + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@export var table_header_scene : PackedScene + +@onready var editor_view : Control = $"../../../.." +@onready var hide_columns_button : MenuButton = $"../../MenuStrip/VisibleCols" +@onready var grid : GridContainer = $"../../../MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid" + + +var hidden_columns := {}: + get: + var result := {} + for k_path in column_properties: + var result_one_path := {} + result[k_path] = result_one_path + for k_column in column_properties[k_path]: + for k_property in column_properties[k_path][k_column]: + if k_property == &"visibility" && [k_property]: + result[k_column] = true + + return result +var column_properties := {} +var columns := []: + set(v): + columns = v + for x in get_children(): + remove_child(x) + x.queue_free() + + var new_node : Control + for x in v: + new_node = table_header_scene.instantiate() + new_node.manager = self + add_child(new_node) + new_node.set_label(x) + new_node.get_node("Button").pressed.connect(editor_view._set_sorting.bind(x)) + + +func _ready(): + hide_columns_button\ + .get_popup()\ + .id_pressed\ + .connect(_on_visible_cols_id_pressed) + $"../../../MarginContainer/FooterContentSplit/Panel/Scroll"\ + .get_h_scroll_bar()\ + .value_changed\ + .connect(_on_h_scroll_changed) + + +func update(): + _update_hidden_columns() + _update_column_sizes() + + +func hide_column(column_index : int): + set_column_property(column_index, &"visibility", 0) + editor_view.save_data() + update() + + +func set_column_property(column_index : int, property_key : StringName, property_value): + var dict := column_properties + if !dict.has(editor_view.current_path): + dict[editor_view.current_path] = {} + + dict = dict[editor_view.current_path] + if !dict.has(columns[column_index]): + dict[columns[column_index]] = {} + + dict = dict[columns[column_index]] + dict[property_key] = property_value + + +func get_column_property(column_index : int, property_key : StringName, property_default = null): + var dict := column_properties + if !dict.has(editor_view.current_path): + return property_default + + dict = dict[editor_view.current_path] + if !dict.has(columns[column_index]): + return property_default + + dict = dict[columns[column_index]] + return dict.get(property_key, property_default) + + +func select_column(column_index : int): + editor_view.select_column(column_index) + + +func _update_column_sizes(): + if grid.get_child_count() == 0: + return + + await get_tree().process_frame + var column_headers := get_children() + + if grid.get_child_count() < column_headers.size(): return + if column_headers.size() != columns.size(): + editor_view.refresh() + return + + var clip_text : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "clip_headers") + var min_width := 0 + var cell : Control + + for i in column_headers.size(): + var header = column_headers[i] + cell = grid.get_child(i) + + header.get_child(0).clip_text = clip_text + header.custom_minimum_size.x = 0 + cell.custom_minimum_size.x = 0 + header.size.x = 0 + + min_width = max(header.size.x, cell.size.x) + header.custom_minimum_size.x = min_width + cell.custom_minimum_size.x = header.get_minimum_size().x + header.size.x = min_width + + grid.hide() + grid.show() + hide() + show() + await get_tree().process_frame + + # Abort if the node has been deleted since. + if !is_instance_valid(column_headers[0]): + return + + get_parent().custom_minimum_size.y = column_headers[0].size.y + for i in column_headers.size(): + column_headers[i].position.x = grid.get_child(i).position.x + column_headers[i].size.x = grid.get_child(i).size.x + + +func _update_hidden_columns(): + var current_path : String = editor_view.current_path + var rows_shown : int = editor_view.last_row - editor_view.first_row + + if !column_properties.has(current_path): + column_properties[current_path] = { + "resource_local_to_scene" : { &"visibility" : 0 }, + "resource_name" : { &"visibility" : 0 }, + "metadata/_custom_type_script" : { &"visibility" : 0 }, + } + editor_view.save_data() + + var visible_column_count := 0 + for i in columns.size(): + var column_visible : bool = get_column_property(i, &"visibility", 1) != 0 + get_child(i).visible = column_visible + for j in rows_shown: + grid.get_child(j * columns.size() + i).visible = column_visible + + if column_visible: + visible_column_count += 1 + + grid.columns = maxi(visible_column_count, 1) + + +func _on_h_scroll_changed(value): + position.x = -value + + +func _on_visible_cols_about_to_popup(): + var popup := hide_columns_button.get_popup() + popup.clear() + popup.hide_on_checkable_item_selection = false + for i in columns.size(): + popup.add_check_item(columns[i].capitalize(), i) + popup.set_item_checked(i, get_column_property(i, &"visibility", 1) != 0) + + +func _on_visible_cols_id_pressed(id : int): + var popup := hide_columns_button.get_popup() + if popup.is_item_checked(id): + popup.set_item_checked(id, false) + set_column_property(id, &"visibility", 0) + + else: + popup.set_item_checked(id, true) + set_column_property(id, &"visibility", 1) + + editor_view.save_data() + update() diff --git a/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid new file mode 100644 index 00000000..9ae5f255 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid @@ -0,0 +1 @@ +uid://ch8piyjv53gtd diff --git a/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd new file mode 100644 index 00000000..71ef67fd --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd @@ -0,0 +1,173 @@ +@tool +extends Control + +@export var editor_view_path : NodePath + +@export_enum("Filter", "Process", "Sort") var mode := 0 +@export var title := "" +@export var default_text := "": + set(v): + default_text = v + if _textfield == null: + await ready + + _textfield.text = v +@export_multiline var default_text_ml := "": + set(v): + default_text_ml = v + if _textfield_ml == null: + await ready + + _textfield_ml.text = v +@export var function_save_key := "" + +var _textfield : LineEdit +var _textfield_ml : TextEdit +var _togglable_popup : PopupPanel +var _saved_function_index_label : Label + +var _saved_functions : Array = [] +var _saved_function_selected := -1 + + +func load_saved_functions(func_dict : Dictionary): + if !func_dict.has(function_save_key): + func_dict[function_save_key] = [default_text_ml] + + _saved_functions = func_dict[function_save_key] + _on_saved_function_selected(0) + + +func _ready(): + var toggle_button := Button.new() + var popup_box := VBoxContainer.new() + var popup_buttons_box := HBoxContainer.new() + var title_label := Label.new() + var submit_button := Button.new() + var move_label := Label.new() + var move_button_l := Button.new() + var move_button_r := Button.new() + _textfield = LineEdit.new() + _togglable_popup = PopupPanel.new() + _textfield_ml = TextEdit.new() + _saved_function_index_label = Label.new() + + add_child(_textfield) + add_child(toggle_button) + _textfield.add_child(_togglable_popup) + _togglable_popup.add_child(popup_box) + popup_box.add_child(title_label) + popup_box.add_child(_textfield_ml) + popup_box.add_child(popup_buttons_box) + popup_buttons_box.add_child(submit_button) + popup_buttons_box.add_child(move_label) + popup_buttons_box.add_child(move_button_l) + popup_buttons_box.add_child(_saved_function_index_label) + popup_buttons_box.add_child(move_button_r) + + title_label.text = title + + toggle_button.icon = get_theme_icon("Collapse", "EditorIcons") + toggle_button.pressed.connect(_on_expand_pressed) + + _textfield.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _textfield.text_submitted.connect(_on_text_submitted.unbind(1)) + + _textfield_ml.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _textfield_ml.size_flags_vertical = Control.SIZE_EXPAND_FILL + + submit_button.text = "Run multiline!" + submit_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + submit_button.pressed.connect(_on_text_submitted) + + move_label.text = "Choose saved:" + move_button_l.icon = get_theme_icon("PagePrevious", "EditorIcons") + move_button_l.pressed.connect(_on_saved_function_bumped.bind(-1)) + _on_saved_function_selected(0) + move_button_r.icon = get_theme_icon("PageNext", "EditorIcons") + move_button_r.pressed.connect(_on_saved_function_bumped.bind(+1)) + + + +func _on_expand_pressed(): + _togglable_popup.popup(Rect2i(_textfield.get_screen_position(), Vector2(size.x, 256.0))) + + +func _on_text_submitted(): + [_table_filter, _table_process][mode].call() + _saved_functions[_saved_function_selected] = _textfield_ml.text + get_node(editor_view_path).save_data.call_deferred() + + +func _get_script_source_code(first_line : String): + var new_text := "" + if !_togglable_popup.visible: + new_text = _textfield.text + if new_text == "": + new_text = default_text + + return first_line + "\treturn " + new_text + + else: + new_text = _textfield_ml.text + if new_text == "": + new_text = default_text_ml + + var text_split := new_text.split("\n") + for i in text_split.size(): + text_split[i] = "\t" + text_split[i] + + return first_line + "\n".join(text_split) + + +func _table_filter(): + var new_script := GDScript.new() + new_script.source_code = _get_script_source_code("static func can_show(res, index):\n") + new_script.reload() + + var editor_view := get_node(editor_view_path) + editor_view.search_cond = new_script.can_show + editor_view.refresh() + + +func _table_process(): + var new_script := GDScript.new() + new_script.source_code = _get_script_source_code("static func get_result(value, res, all_res, row_index):\n") + new_script.reload() + + var editor_view := get_node(editor_view_path) + var new_script_instance := new_script.new() + var values : Array = editor_view.get_edited_cells_values() + + var edited_rows : Array[int] = editor_view._selection.get_edited_rows() + var edited_resources := edited_rows.map(func(x): return editor_view.rows[x]) + for i in values.size(): + values[i] = new_script_instance.get_result(values[i], editor_view.rows[edited_rows[i]], edited_resources, i) + + editor_view.set_edited_cells_values(values) + + +func _on_saved_function_selected(new_index : int): + if new_index < 0: + new_index = 0 + + if _saved_function_selected == _saved_functions.size() - 1 and _textfield_ml.text == default_text_ml: + _saved_functions.resize(_saved_functions.size() - 1) + + elif _saved_function_selected >= 0: + _saved_functions[_saved_function_selected] = _textfield_ml.text + + _saved_function_selected = new_index + if new_index >= _saved_functions.size(): + _saved_functions.resize(new_index + 1) + for i in _saved_functions.size(): + if _saved_functions[i] == null: + _saved_functions[i] = default_text_ml + + _textfield_ml.text = _saved_functions[new_index] + _saved_function_index_label.text = "%d/%d" % [new_index + 1, _saved_functions.size()] + get_node(editor_view_path).save_data.call_deferred() + + +func _on_saved_function_bumped(increment : int): + _on_saved_function_selected(_saved_function_selected + increment) diff --git a/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid new file mode 100644 index 00000000..2f956100 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid @@ -0,0 +1 @@ +uid://co5vnlvytmq55 diff --git a/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd new file mode 100644 index 00000000..b722523d --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd @@ -0,0 +1,60 @@ +@tool +extends ColorRect + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var editor_view : Control = $"../../../../../.." +@onready var grid_scroll : ScrollContainer = $"../../Scroll" +@onready var grid : GridContainer = $"../../Scroll/MarginContainer/TableGrid" + +var children : Array[Control] = [] +var children_copy_cells : Array[Control] = [] + + +func _ready() -> void: + grid_scroll.get_h_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED) + grid_scroll.get_v_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED) + + +func _on_grid_updated() -> void: + if editor_view.rows.size() == 0: + hide() + return + + visible = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "freeze_first_column") + for x in get_children(): + x.queue_free() + + children.clear() + children_copy_cells.clear() + size.x = 0.0 + + await get_tree().process_frame + + var first_visible_column := 0 + for i in grid.columns: + if grid.get_child(i).visible: + first_visible_column = i + break + + var total_column_count : int = editor_view.columns.size() + children.resize(grid.get_child_count() / total_column_count) + children_copy_cells.resize(children.size()) + for i in children.size(): + children_copy_cells[i] = grid.get_child(total_column_count * i + first_visible_column) + children[i] = children_copy_cells[i].duplicate() + children[i].mouse_filter = Control.MOUSE_FILTER_IGNORE + add_child(children[i]) + size.x = maxf(size.x, children_copy_cells[i].size.x) + + size.y = grid.size.y + color = get_theme_color(&"background", &"Editor") + color.a *= 0.9 + _on_scroll_updated(0.0) + + +func _on_scroll_updated(_new_value : float): + position = Vector2(0.0, -grid_scroll.scroll_vertical) + for i in children.size(): + children[i].size = children_copy_cells[i].size + children[i].position = children_copy_cells[i].position diff --git a/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid new file mode 100644 index 00000000..daf27b97 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid @@ -0,0 +1 @@ +uid://1i0r2v3qyiqy diff --git a/addons/resources_spreadsheet_view/main_screen/input_handler.gd b/addons/resources_spreadsheet_view/main_screen/input_handler.gd new file mode 100644 index 00000000..0778e7d2 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/input_handler.gd @@ -0,0 +1,148 @@ +@tool +extends Node + +const TablesPluginEditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd") +const TablesPluginSelectionManagerClass := preload("res://addons/resources_spreadsheet_view/main_screen/selection_manager.gd") +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +@onready var editor_view : TablesPluginEditorViewClass = get_parent() +@onready var selection : TablesPluginSelectionManagerClass = get_node("../SelectionManager") + + +func _on_cell_gui_input(event : InputEvent, cell_node : Control): + var cell := selection.get_cell_node_position(cell_node) + if event is InputEventMouseButton: + editor_view.grab_focus() + if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + if !cell in selection.edited_cells: + selection.deselect_all_cells() + selection.select_cell(cell) + + selection.rightclick_cells() + + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + if event.is_command_or_control_pressed(): + if cell in selection.edited_cells: + selection.deselect_cell(cell) + + else: + selection.select_cell(cell) + + elif Input.is_key_pressed(KEY_SHIFT): + selection.select_cells_to(cell) + + else: + selection.deselect_all_cells() + selection.select_cell(cell) + + +func _gui_input(event : InputEvent): + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed(): + selection.rightclick_cells() + + if event.button_index == MOUSE_BUTTON_LEFT: + editor_view.grab_focus() + if !event.pressed: + selection.deselect_all_cells() + + +func _input(event : InputEvent): + if !event is InputEventKey or !event.pressed: + return + + if !editor_view.has_focus() or selection.edited_cells.size() == 0: + return + + if event.keycode == KEY_CTRL or event.keycode == KEY_SHIFT or event.keycode == KEY_META: + # Modifier keys do not get processed. + return + + # Ctrl + Z (before, and instead of, committing the action!) + if event.is_command_or_control_pressed(): + if event.keycode == KEY_Z or event.keycode == KEY_Y: + return + + _key_specific_action(event) + editor_view.grab_focus() + editor_view.editor_interface.get_resource_filesystem().scan() + + +func _key_specific_action(event : InputEvent): + var column := selection.get_cell_column(selection.edited_cells[0]) + var ctrl_pressed : bool = event.is_command_or_control_pressed() + + # BETWEEN-CELL NAVIGATION + var grid_move_offset := (10 if ctrl_pressed else 1) + if event.keycode == KEY_UP: + _move_selection_on_grid(0, -grid_move_offset) + + elif event.keycode == KEY_DOWN: + _move_selection_on_grid(0, +grid_move_offset) + + elif Input.is_key_pressed(KEY_SHIFT) and event.keycode == KEY_TAB: + _move_selection_on_grid(-grid_move_offset, 0) + + elif event.keycode == KEY_TAB: + _move_selection_on_grid(+grid_move_offset, 0) + + elif ctrl_pressed and event.keycode == KEY_C: + TextEditingUtilsClass.multi_copy(selection.edited_cells_text) + get_viewport().set_input_as_handled() + + # Ctrl + V + elif ctrl_pressed and event.keycode == KEY_V and editor_view.columns[column] != "resource_path": + selection.clipboard_paste() + get_viewport().set_input_as_handled() + + # TEXT CARET MOVEMENT + var caret_move_offset := TextEditingUtilsClass.get_caret_movement_from_key(event.keycode) + if TextEditingUtilsClass.multi_move_caret(caret_move_offset, selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed): + selection.queue_redraw() + return + + # The following actions do not work on non-editable cells. + if !selection.column_editors[column].is_text() or editor_view.columns[column] == "resource_path": + return + + # ERASING + elif event.keycode == KEY_BACKSPACE: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_left( + selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed + )) + + elif event.keycode == KEY_DELETE: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_right( + selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed + )) + get_viewport().set_input_as_handled() + + # And finally, text typing. + elif event.keycode == KEY_ENTER: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input( + "\n", selection.edited_cells_text, selection.edit_cursor_positions + )) + + elif event.unicode != 0 and event.unicode != 127: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input( + char(event.unicode), selection.edited_cells_text, selection.edit_cursor_positions + )) + + selection.queue_redraw() + + +func _move_selection_on_grid(move_h : int, move_v : int): + var selected_cells := selection.edited_cells.duplicate() + var num_columns := editor_view.columns.size() + var num_rows := editor_view.rows.size() + var new_child_pos := Vector2i(0, 0) + for i in selected_cells.size(): + new_child_pos = Vector2i( + clamp(selected_cells[i].x + move_h, 0, num_columns - 1), + clamp(selected_cells[i].y + move_v, 0, num_rows - 1), + ) + selected_cells[i] = new_child_pos + + editor_view.grab_focus() + selection.deselect_all_cells() + selection.select_cells(selected_cells) diff --git a/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid b/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid new file mode 100644 index 00000000..116f5c8b --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid @@ -0,0 +1 @@ +uid://dwvxs8j1xs7fc diff --git a/addons/resources_spreadsheet_view/main_screen/recent_paths.gd b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd new file mode 100644 index 00000000..bb9f3ecb --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd @@ -0,0 +1,54 @@ +@tool +extends OptionButton + +@onready var editor_view := $"../../../../.." + +var recent_paths := [] + + +func _ready(): + item_selected.connect(_on_item_selected) + + +func load_paths(paths): + clear() + for x in paths: + add_path_to_recent(x, true) + + selected = 0 + + +func add_path_to_recent(path : String, is_loading : bool = false): + if path in recent_paths: return + + var idx_in_array := recent_paths.find(path) + if idx_in_array != -1: + remove_item(idx_in_array) + recent_paths.remove_at(idx_in_array) + + recent_paths.append(path) + add_item(path) + select(get_item_count() - 1) + + if !is_loading: + editor_view.save_data() + + +func remove_selected_path_from_recent(): + if get_item_count() == 0: + return + + var idx_in_array := selected + recent_paths.remove_at(idx_in_array) + remove_item(idx_in_array) + + if get_item_count() != 0: + select(0) + editor_view.display_folder(recent_paths[0]) + editor_view.save_data() + + +func _on_item_selected(index : int): + editor_view.current_path = recent_paths[index] + editor_view.node_folder_path.text = recent_paths[index] + editor_view.refresh() diff --git a/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid new file mode 100644 index 00000000..d40fbb91 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid @@ -0,0 +1 @@ +uid://jmjijgbfgwti diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.gd b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd new file mode 100644 index 00000000..4e4682e1 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd @@ -0,0 +1,191 @@ +@tool +extends MarginContainer + +enum { + EDITBOX_DUPLICATE = 1, + EDITBOX_RENAME, + EDITBOX_DELETE, +} + +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var editor_view := $"../.." +@onready var selection := $"../../SelectionManager" + +@onready var editbox_node := $"Control/ColorRect/Popup" +@onready var editbox_label : Label = editbox_node.get_node("Panel/VBoxContainer/Label") +@onready var editbox_input : LineEdit = editbox_node.get_node("Panel/VBoxContainer/LineEdit") + +var cell : Control +var editbox_action : int + + +func _ready(): + editbox_input.get_node("../..").add_theme_stylebox_override( + "panel", + get_theme_stylebox(&"Content", &"EditorStyles") + ) + editbox_input.text_submitted.connect(func(_new_text): _on_editbox_accepted()) + close() + + +func _on_grid_cells_rightclicked(cells): + open(cells) + + +func _on_grid_cells_selected(cells): + open(cells, true, true) + + +func open(cells : Array, pin_to_cell : bool = false, from_leftclick : bool = false): + if cells.size() == 0 or (from_leftclick and !ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "context_menu_on_leftclick")): + hide() + cell = null + return + + if pin_to_cell: + cell = selection.get_cell_node_from_position(cells[-1]) + set_deferred(&"global_position", Vector2( + cell.global_position.x + cell.size.x, + cell.global_position.y + )) + + else: + cell = null + set_deferred(&"global_position", get_global_mouse_position() + Vector2.ONE) + + show() + size = Vector2.ZERO + top_level = true + $"Control2/Label".text = str(cells.size()) + (" Cells" if cells.size() % 10 != 1 else " Cell") + $"GridContainer/Rename".visible = editor_view.has_row_names() + $"GridContainer/SoloOpen".visible = editor_view.column_can_solo_open(editor_view.get_selected_column()) + + +func close(): + pass + + +func _input(event : InputEvent): + if !editor_view.is_visible_in_tree(): + close() + return + + if event is InputEventMouseButton and event.is_pressed(): + close() + return + + if event is InputEventKey: + if event.is_pressed() and event.is_command_or_control_pressed(): + global_position = get_global_mouse_position() + Vector2.ONE + if cell != null: + global_position = Vector2( + cell.global_position.x + cell.size.x, + cell.global_position.y + ) + + # Dupe + if event.keycode == KEY_D: + _on_Duplicate_pressed() + return + + # Rename + if event.keycode == KEY_R: + _on_Rename_pressed() + return + + +func _on_Duplicate_pressed(): + _show_editbox(EDITBOX_DUPLICATE) + + +func _on_CbCopy_pressed(): + TextEditingUtilsClass.multi_copy(selection.edited_cells_text) + + +func _on_CbPaste_pressed(): + selection.clipboard_paste() + + +func _on_Rename_pressed(): + _show_editbox(EDITBOX_RENAME) + + +func _on_Delete_pressed(): + _show_editbox(EDITBOX_DELETE) + + +func _on_SoloOpen_pressed(): + var resources_to_open_unique := {} + for x in editor_view.get_edited_cells_values(): + if x is Array: + for y in x: + resources_to_open_unique[y] = true + + if x is Resource: + resources_to_open_unique[x] = true + + if resources_to_open_unique.size() > 0: + editor_view.display_resources(resources_to_open_unique.keys()) + + +func _show_editbox(action): + editbox_action = action + match action: + EDITBOX_DUPLICATE: + if !editor_view.has_row_names(): + _on_editbox_accepted() + return + + if selection.edited_cells.size() == 1: + editbox_label.text = "Input new row's name..." + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + else: + editbox_label.text = "Input suffix to append to names..." + editbox_input.text = "" + + EDITBOX_RENAME: + editbox_label.text = "Input new name for row..." + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + EDITBOX_DELETE: + editbox_label.text = "Really delete selected rows? (Irreversible!!!)" + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + show() + editbox_input.grab_focus() + editbox_input.caret_column = 999999999 + editbox_node.size = Vector2.ZERO + editbox_node.show() + $"Control/ColorRect".show() + $"Control/ColorRect".top_level = true + $"Control/ColorRect".size = get_viewport_rect().size * 4.0 + editbox_node.global_position = ( + global_position + + size * 0.5 + - editbox_node.get_child(0).size * 0.5 + ) + + +func _on_editbox_closed(): + editbox_node.hide() + $"Control/ColorRect".hide() + + +func _on_editbox_accepted(): + match(editbox_action): + EDITBOX_DUPLICATE: + editor_view.duplicate_selected_rows(editbox_input.text) + + EDITBOX_RENAME: + editor_view.rename_row(editor_view.get_last_selected_row(), editbox_input.text) + + EDITBOX_DELETE: + editor_view.delete_selected_rows() + + _on_editbox_closed() diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid new file mode 100644 index 00000000..22ffd760 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid @@ -0,0 +1 @@ +uid://o4dvq3uo8p43 diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn b/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn new file mode 100644 index 00000000..a051f6a1 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn @@ -0,0 +1,191 @@ +[gd_scene load_steps=7 format=3 uid="uid://b51hnttsie7k5"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/selection_actions.gd" id="1_qv6ov"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_color_setter.gd" id="2_a4ihj"] + +[sub_resource type="Image" id="Image_pjk43"] +data = { +"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +"format": "LumAlpha8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="2"] +image = SubResource("Image_pjk43") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r2l2b"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(1, 0.365, 0.365, 1) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_detail = 1 + +[node name="SelectionActions" type="MarginContainer"] +offset_right = 80.0 +offset_bottom = 52.0 +size_flags_horizontal = 9 +mouse_filter = 2 +script = ExtResource("1_qv6ov") + +[node name="Control2" type="Panel" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Control2"] +show_behind_parent = true +layout_mode = 0 +mouse_filter = 2 + +[node name="ColorRect2" type="ColorRect" parent="Control2"] +modulate = Color(0, 0, 0, 1) +show_behind_parent = true +layout_mode = 1 +anchors_preset = 9 +anchor_bottom = 1.0 +offset_left = -2.0 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("2_a4ihj") + +[node name="Label" type="Label" parent="Control2"] +layout_mode = 0 +offset_top = -26.0 +offset_right = 57.0 +text = "Actions" +vertical_alignment = 2 + +[node name="ColorRect3" type="Panel" parent="Control2/Label"] +show_behind_parent = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -2.0 +offset_top = 2.0 +offset_right = 2.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 + +[node name="GridContainer" type="GridContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 9 +size_flags_vertical = 9 +mouse_filter = 2 +columns = 3 + +[node name="Duplicate" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Duplicate Selected Rows (Ctrl+D)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Duplicate" + +[node name="CbCopy" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Copy to Clipboard (Ctrl+C)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "ActionCopy" + +[node name="CbPaste" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Paste Clipboard (Ctrl+V)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "ActionPaste" + +[node name="Rename" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Rename Selected Rows (Ctrl+R)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Edit" + +[node name="Delete" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "DELETE Selected Rows" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Remove" + +[node name="SoloOpen" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Open selected cells as new table" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Object" + +[node name="Control" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Control"] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -80.0 +offset_bottom = -52.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 0.498039) + +[node name="Popup" type="MarginContainer" parent="Control/ColorRect"] +layout_mode = 0 +offset_top = 100.0 +offset_right = 140.0 +offset_bottom = 196.0 + +[node name="Panel" type="PanelContainer" parent="Control/ColorRect/Popup"] +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_r2l2b") + +[node name="VBoxContainer" type="VBoxContainer" parent="Control/ColorRect/Popup/Panel"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 +text = "Input new name..." + +[node name="LineEdit" type="LineEdit" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="Button" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "OK" + +[node name="Button2" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Cancel" + +[connection signal="pressed" from="GridContainer/Duplicate" to="." method="_on_Duplicate_pressed"] +[connection signal="pressed" from="GridContainer/CbCopy" to="." method="_on_CbCopy_pressed"] +[connection signal="pressed" from="GridContainer/CbPaste" to="." method="_on_CbPaste_pressed"] +[connection signal="pressed" from="GridContainer/Rename" to="." method="_on_Rename_pressed"] +[connection signal="pressed" from="GridContainer/Delete" to="." method="_on_Delete_pressed"] +[connection signal="pressed" from="GridContainer/SoloOpen" to="." method="_on_SoloOpen_pressed"] +[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button" to="." method="_on_editbox_accepted"] +[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button2" to="." method="_on_editbox_closed"] diff --git a/addons/resources_spreadsheet_view/main_screen/selection_manager.gd b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd new file mode 100644 index 00000000..8fa25cea --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd @@ -0,0 +1,303 @@ +@tool +extends Control + +signal cells_selected(cells_positions) +signal cells_rightclicked(cells_positions) + +const EditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd") +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +@export var cell_editor_classes : Array[Script] = [] + +@onready var node_property_editors : VBoxContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" +@onready var scrollbar : ScrollContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll" + +@onready var editor_view : EditorViewClass = get_parent() + +var edited_cells : Array = [] +var edited_cells_text : Array = [] +var edit_cursor_positions : Array[int] = [] + +var all_cell_editors : Array = [] +var column_editors : Array[Object] = [] +var inspector_resource : Resource + + +func _ready(): + # Load cell editors and instantiate them + for x in cell_editor_classes: + all_cell_editors.append(x.new()) + all_cell_editors[all_cell_editors.size() - 1].hint_strings_array = editor_view.column_hint_strings + + get_parent()\ + .editor_interface\ + .get_inspector()\ + .property_edited\ + .connect(_on_inspector_property_edited) + + scrollbar.get_h_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED) + scrollbar.get_v_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED) + + if ProjectSettings.get_setting(editor_view.TablesPluginSettingsClass.PREFIX + "fold_docks", false): + for x in node_property_editors.get_children(): + x.resize_set_hidden(true) + + +func _draw(): + if edited_cells.size() == 0 or edit_cursor_positions.size() != edited_cells.size() or !column_editors[edited_cells[0].x].is_text(): + return + + var font := get_theme_font(&"font", &"Label") + var font_size := get_theme_font_size(&"font", &"Label") + var caret_color := get_theme_color(&"caret_color", &"LineEdit") + var label_padding_left := 2.0 + var newline_char := 10 + for i in edited_cells.size(): + var cell : Control = get_cell_node_from_position(edited_cells[i]) + var caret_rect := TextEditingUtilsClass.get_caret_rect(edited_cells_text[i], edit_cursor_positions[i], font, font_size, label_padding_left, 1.0) + caret_rect.position += cell.global_position - global_position + draw_rect(caret_rect, caret_color) + + +func initialize_editors(column_values, column_types, column_hints): + _set_visible_selected(false) + column_editors.clear() + for i in column_values.size(): + for x in all_cell_editors: + if x.can_edit_value(column_values[i], column_types[i], column_hints[i], i): + column_editors.append(x) + break + + +func deselect_all_cells(): + _set_visible_selected(false) + edited_cells.clear() + edited_cells_text.clear() + edit_cursor_positions.clear() + _selection_changed() + + +func deselect_cell(cell : Vector2i): + var idx := edited_cells.find(cell) + if idx == -1: return + + edited_cells.remove_at(idx) + if edited_cells_text.size() != 0: + edited_cells_text.remove_at(idx) + edit_cursor_positions.remove_at(idx) + + var cell_node := get_cell_node_from_position(cell) + if cell_node != null: + column_editors[get_cell_column(cell)].set_selected(cell_node, false) + + _selection_changed() + + +func select_cell(cell : Vector2i): + var column_index := get_cell_column(cell) + if edited_cells.size() == 0 or edited_cells[0].x == cell.x: + _add_cell_to_selection(cell) + _try_open_docks(cell) + inspector_resource = editor_view.rows[get_cell_row(cell)] + editor_view.editor_plugin.get_editor_interface().edit_resource(inspector_resource) + + _selection_changed() + + +func select_cells(cells : Array): + var last_selectible := Vector2i(-1, -1) + var started_empty := edited_cells.size() == 0 + for x in cells: + if started_empty or edited_cells[0].x != x.x: + _add_cell_to_selection(x) + if get_cell_node_from_position(x) != null: + last_selectible = x + + if last_selectible != Vector2i(-1, -1): + select_cell(last_selectible) + + +func select_cells_to(cell : Vector2i): + var column_index := get_cell_column(cell) + if edited_cells.size() == 0 or column_index != get_cell_column(edited_cells[-1]): + return + + var row_start := get_cell_row(edited_cells[-1]) + var row_end := get_cell_row(cell) + var edge_shift := -1 if row_start > row_end else 1 + row_start += edge_shift + row_end += edge_shift + + var column_editor := column_editors[column_index] + for i in range(row_start, row_end, edge_shift): + var cur_cell := Vector2i(column_index, i) + var cur_cell_node := get_cell_node_from_position(cur_cell) + if cur_cell not in edited_cells: + edited_cells.append(cur_cell) + + var cur_cell_value = editor_view.io.get_value(editor_view.rows[cur_cell.y], editor_view.columns[cur_cell.x]) + var cur_cell_text : String = column_editor.to_text(cur_cell_value) + edited_cells_text.append(cur_cell_text) + edit_cursor_positions.append(cur_cell_text.length()) + + if cur_cell_node == null or !cur_cell_node.visible or cur_cell_node.mouse_filter == MOUSE_FILTER_IGNORE: + # When showing several classes, empty cells will be non-selectable. + continue + + column_editors[column_index].set_selected(cur_cell_node, true) + + _selection_changed() + + +func rightclick_cells(): + cells_rightclicked.emit(edited_cells) + + +func is_cell_node_selected(cell : Control) -> bool: + return get_cell_node_position(cell) in edited_cells + + +func is_cell_selected(cell : Vector2i) -> bool: + return cell in edited_cells + + +func can_select_cell(cell : Vector2i) -> bool: + if edited_cells.size() == 0: + return true + + if ( + get_cell_column(cell) + != get_cell_column(edited_cells[0]) + ): + return false + + return !cell in edited_cells + + +func get_cell_node_from_position(cell_pos : Vector2i) -> Control: + var cell_index := (cell_pos.y - editor_view.first_row) * editor_view.columns.size() + cell_pos.x + if cell_index < 0 or cell_index >= editor_view.node_table_root.get_child_count(): + return null + + return editor_view.node_table_root.get_child(cell_index) + + +func get_cell_node_position(cell : Control) -> Vector2i: + var col_count := editor_view.columns.size() + var cell_index := cell.get_index() + return Vector2i(cell_index % col_count, cell_index / col_count + editor_view.first_row) + + +func get_cell_column(cell : Vector2i) -> int: + return cell.x + + +func get_cell_row(cell : Vector2i) -> int: + return cell.y + + +func get_edited_rows() -> Array[int]: + var rows : Array[int] = [] + rows.resize(edited_cells.size()) + for i in rows.size(): + rows[i] = get_cell_row(edited_cells[i]) + + return rows + + +func clipboard_paste(): + if column_editors[edited_cells[0].x].is_text(): + editor_view.set_edited_cells_values( + TextEditingUtilsClass.multi_paste( + edited_cells_text, + edit_cursor_positions, + ) + ) + + elif DisplayServer.clipboard_has(): + var values := [] + values.resize(edited_cells.size()) + var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n") + var paste_each_line := pasted_lines.size() == values.size() + + for i in values.size(): + values[i] = str_to_var( + pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get() + ) + + editor_view.set_edited_cells_values(values) + + +func _selection_changed(): + queue_redraw() + cells_selected.emit(edited_cells) + + +func _set_visible_selected(state : bool): + for x in edited_cells: + var cell_node := get_cell_node_from_position(x) + if cell_node != null: + column_editors[get_cell_column(x)].set_selected(cell_node, state) + + +func _add_cell_to_selection(cell : Vector2i): + edited_cells.append(cell) + + var column_editor := column_editors[get_cell_column(cell)] + var cell_node := get_cell_node_from_position(cell) + if cell_node != null: + column_editor.set_selected(cell_node, true) + + var cell_value = editor_view.io.get_value(editor_view.rows[cell.y], editor_view.columns[cell.x]) + var text_value : String = column_editor.to_text(cell_value) + edited_cells_text.append(text_value) + edit_cursor_positions.append(text_value.length()) + + +func _update_selected_cells_text(): + if edited_cells_text.size() == 0: + return + + var column_editor := column_editors[get_cell_column(edited_cells[0])] + if !column_editor.text_update_on_edit(): + return + + for i in edited_cells.size(): + edited_cells_text[i] = column_editor.to_text(editor_view.io.get_value( + editor_view.rows[edited_cells[i].y], + editor_view.columns[edited_cells[i].x], + )) + edit_cursor_positions[i] = edited_cells_text[i].length() + + +func _try_open_docks(cell : Vector2i): + var column_index := get_cell_column(cell) + var row = editor_view.rows[get_cell_row(cell)] + var column := editor_view.columns[column_index] + var type := editor_view.column_types[column_index] + var hints := editor_view.column_hints[column_index] + + for x in node_property_editors.get_children(): + x.visible = x.try_edit_value(editor_view.io.get_value(row, column), type, hints) + x.get_node(x.path_property_name).text = column + + +func _on_inspector_property_edited(property : String): + if !editor_view.is_visible_in_tree(): return + if inspector_resource != editor_view.editor_plugin.get_editor_interface().get_inspector().get_edited_object(): + return + + if editor_view.columns[get_cell_column(edited_cells[0])] != property: + var columns := editor_view.columns + var previously_edited := edited_cells.duplicate() + var new_column := columns.find(property) + deselect_all_cells() + for i in previously_edited.size(): + _add_cell_to_selection(Vector2i(new_column, previously_edited[i].y)) + + var values := [] + values.resize(edited_cells.size()) + values.fill(inspector_resource[property]) + + editor_view.set_edited_cells_values.call_deferred(values) + _try_open_docks(edited_cells[0]) diff --git a/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid new file mode 100644 index 00000000..86f42145 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid @@ -0,0 +1 @@ +uid://biwt446cmre7d diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.gd b/addons/resources_spreadsheet_view/main_screen/table_header.gd new file mode 100644 index 00000000..7a8c56f9 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.gd @@ -0,0 +1,72 @@ +@tool +extends HBoxContainer + +var manager : Control + + +func set_label(label : String): + $"Button".text = label.capitalize() + $"Button".tooltip_text = label + "\nClick to sort." + + +func _ready(): + $"Button".gui_input.connect(_on_main_gui_input) + $"Button2".about_to_popup.connect(_on_about_to_popup) + $"Button2".get_popup().id_pressed.connect(_on_list_id_pressed) + + +func _on_about_to_popup(): + var menu_popup : PopupMenu = $"Button2".get_popup() + menu_popup.clear() + menu_popup.add_item("Select All", 0) + menu_popup.add_item("Hide", 1) + + if !manager.editor_view.column_can_solo_open(get_index()): + menu_popup.add_item("(not a Resource property)", 2) + menu_popup.set_item_disabled(2, true) + menu_popup.add_separator("", 3) + + else: + menu_popup.add_item("Open Sub-Resources of Column", 2) + + if manager.editor_view.get_edited_cells_values().size() == 0 or manager.editor_view.get_selected_column() != get_index(): + menu_popup.add_item("(none selected)", 3) + menu_popup.set_item_disabled(3, true) + + else: + menu_popup.add_item("Open Sub-Resources in Selection", 3) + + +func _on_main_gui_input(event : InputEvent): + if event is InputEventMouseButton and event.pressed: + var popup : Popup = $"Button2".get_popup() + if event.button_index == MOUSE_BUTTON_RIGHT: + _on_about_to_popup() + popup.visible = !popup.visible + popup.size = Vector2.ZERO + popup.position = Vector2i(get_global_mouse_position()) + get_viewport().position + + else: + popup.visible = false + + +func _on_list_id_pressed(id : int): + match id: + 0: + manager.select_column(get_index()) + 1: + manager.hide_column(get_index()) + 2: + manager.editor_view.column_solo_open(get_index()) + 3: + var resources_to_open_unique := {} + for x in manager.editor_view.get_edited_cells_values(): + if x is Array: + for y in x: + resources_to_open_unique[y] = true + + if x is Resource: + resources_to_open_unique[x] = true + + if resources_to_open_unique.size() > 0: + manager.editor_view.display_resources(resources_to_open_unique.keys()) diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid b/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid new file mode 100644 index 00000000..f0bb484e --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid @@ -0,0 +1 @@ +uid://wk4vmvrq5wum diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.tscn b/addons/resources_spreadsheet_view/main_screen/table_header.tscn new file mode 100644 index 00000000..c287a34c --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=3 format=3 uid="uid://d1s6oihqedvo5"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/table_header.gd" id="1_5fd1m"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_0ymob"] + +[node name="Header" type="HBoxContainer"] +offset_right = 179.0 +offset_bottom = 31.0 +size_flags_horizontal = 3 +script = ExtResource("1_5fd1m") + +[node name="Button" type="Button" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "resource_name" +clip_text = true + +[node name="Button2" type="MenuButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 9 +script = ExtResource("2_0ymob") +icon_name = "ArrowDown" diff --git a/addons/resources_spreadsheet_view/main_screen/table_pages.gd b/addons/resources_spreadsheet_view/main_screen/table_pages.gd new file mode 100644 index 00000000..3cfb0e47 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_pages.gd @@ -0,0 +1,118 @@ +@tool +extends HBoxContainer + +@onready var node_editor_view_root : Control = $"../../../.." + +var rows_per_page := 50 +var current_page := 0 + + +func update_page_count(array : Array) -> int: + var page_count : int = (node_editor_view_root.rows.size() - 1) / rows_per_page + 1 + node_editor_view_root.first_row = min(current_page, page_count) * rows_per_page + node_editor_view_root.last_row = min(node_editor_view_root.first_row + rows_per_page, array.size()) + return page_count + + +func _on_grid_updated(): + if node_editor_view_root.rows.size() == 0: + return + + visible = true + var page_count := update_page_count(node_editor_view_root.rows) + var pagelist_node := $"Scroll/Pagelist" + for x in pagelist_node.get_children(): + x.queue_free() + + var button_group := ButtonGroup.new() + var btns := [] + btns.resize(page_count) + for i in page_count: + var btn := Button.new() + btns[i] = btn + btn.toggle_mode = true + btn.button_group = button_group + btn.text = str(i + 1) + btn.pressed.connect(_on_button_pressed.bind(btn)) + btn.size_flags_vertical = SIZE_SHRINK_CENTER + pagelist_node.add_child(btn) + + var pagelist_line := HSeparator.new() + pagelist_line.size_flags_horizontal = SIZE_EXPAND_FILL + pagelist_node.add_child(pagelist_line) + btns[current_page].button_pressed = true + + var sort_property : StringName = node_editor_view_root.sorting_by + if sort_property == "": sort_property = "resource_path" + var sort_type : int = node_editor_view_root.column_types[node_editor_view_root.columns.find(sort_property)] + var property_values := [] + property_values.resize(page_count) + if(node_editor_view_root.rows.size() == 0): + return + + for i in page_count: + property_values[i] = node_editor_view_root.rows[i * rows_per_page].get(sort_property) + + if sort_type == TYPE_FLOAT or sort_type == TYPE_INT: + for i in page_count: + btns[i].text = str(property_values[i]) + + elif sort_type == TYPE_COLOR: + for i in page_count: + btns[i].self_modulate = property_values[i] * 0.75 + Color(0.25, 0.25, 0.25, 1.0) + + elif sort_type == TYPE_STRING: + var strings := [] + strings.resize(page_count) + for i in page_count: + strings[i] = property_values[i].get_file() + if strings[i] == "": + strings[i] = str(i) + + _fill_buttons_with_prefixes(btns, strings, page_count) + + elif sort_type == TYPE_OBJECT: + var strings := [] + strings.resize(page_count + 1) + for i in page_count: + if is_instance_valid(property_values[i]): + strings[i] = property_values[i].resource_path.get_file() + + _fill_buttons_with_prefixes(btns, strings, page_count) + + +func _fill_buttons_with_prefixes(btns : Array, strings : Array, page_count : int): + for i in page_count: + if strings[i] == null: + continue + + if i == 0: + btns[0].text = strings[0][0] + continue + + for j in strings[i].length(): + if strings[i].unicode_at(j) != strings[i - 1].unicode_at(j): + btns[i].text = strings[i].left(j + 1) + btns[i - 1].text = strings[i - 1].left(max(j + 1, btns[i - 1].text.length())) + break + + for i in page_count - 1: + btns[i].text = btns[i].text + "-" + btns[i + 1].text + + btns[page_count - 1].text += "-[End]" + + +func _on_button_pressed(button): + button.button_pressed = true + current_page = button.get_index() + _update_view() + + +func _on_LineEdit_value_changed(value): + rows_per_page = value + current_page = 0 + _update_view() + + +func _update_view(): + node_editor_view_root.refresh(false) diff --git a/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid b/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid new file mode 100644 index 00000000..7598388a --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid @@ -0,0 +1 @@ +uid://bdyxtghkp55ko diff --git a/addons/resources_spreadsheet_view/plugin.cfg b/addons/resources_spreadsheet_view/plugin.cfg new file mode 100644 index 00000000..ec06e330 --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.cfg @@ -0,0 +1,9 @@ +[plugin] + +name="Edit Resources as Table" +description="Edit Many Resources from one Folder as a table. + +Heavily inspired by Multi-Cursor-Editing in text editors, so after selecting multiple cells (in the same column!) using Ctrl+Click or Shift+Click, most Basic-to-Intermediate movements should be available." +author="Don Tnowe" +version="2.7" +script="plugin.gd" diff --git a/addons/resources_spreadsheet_view/plugin.gd b/addons/resources_spreadsheet_view/plugin.gd new file mode 100644 index 00000000..70549bef --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.gd @@ -0,0 +1,43 @@ +@tool +extends EditorPlugin + +var editor_view : Control +var undo_redo : EditorUndoRedoManager + + +func _enter_tree() -> void: + editor_view = load(get_script().resource_path.get_base_dir() + "/editor_view.tscn").instantiate() + editor_view.editor_interface = get_editor_interface() + if editor_view.editor_interface == null: + # 4.2: now a singleton + editor_view.editor_interface = Engine.get_singleton("EditorInterface") + + editor_view.editor_plugin = self + undo_redo = get_undo_redo() + get_editor_interface().get_editor_main_screen().add_child(editor_view) + _make_visible(false) + + +func _exit_tree() -> void: + if is_instance_valid(editor_view): + editor_view.queue_free() + + +func _get_plugin_name(): + return "ResourceTables" + + +func _make_visible(visible): + if is_instance_valid(editor_view): + editor_view.visible = visible + if visible: + editor_view.display_folder(editor_view.current_path) + + +func _has_main_screen(): + return true + + +func _get_plugin_icon(): + # Until I add an actual icon, this'll do. + return get_editor_interface().get_base_control().get_theme_icon("VisualShaderNodeComment", "EditorIcons") diff --git a/addons/resources_spreadsheet_view/plugin.gd.uid b/addons/resources_spreadsheet_view/plugin.gd.uid new file mode 100644 index 00000000..23798317 --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.gd.uid @@ -0,0 +1 @@ +uid://dxe2u46hch26 diff --git a/addons/resources_spreadsheet_view/saved_state.json b/addons/resources_spreadsheet_view/saved_state.json new file mode 100644 index 00000000..ecb41783 --- /dev/null +++ b/addons/resources_spreadsheet_view/saved_state.json @@ -0,0 +1,57 @@ +{ + "column_properties": { + "res://Resources/": { + "metadata/_custom_type_script": { + "visibility": 0 + }, + "resource_local_to_scene": { + "visibility": 0 + }, + "resource_name": { + "visibility": 0 + } + }, + "res://Resources/Bullets/": { + "metadata/_custom_type_script": { + "visibility": 0 + }, + "resource_local_to_scene": { + "visibility": 0 + }, + "resource_name": { + "visibility": 0 + } + }, + "res://Resources/Items/": { + "metadata/_custom_type_script": { + "visibility": 0 + }, + "resource_local_to_scene": { + "visibility": 0 + }, + "resource_name": { + "visibility": 0 + } + }, + "res://Resources/Weapons/": { + "metadata/_custom_type_script": { + "visibility": 0 + }, + "resource_local_to_scene": { + "visibility": 0 + }, + "resource_name": { + "visibility": 0 + } + } + }, + "recent_paths": [ + "res://Resources/", + "res://Resources/Items/", + "res://Resources/Weapons/", + "res://Resources/Bullets/" + ], + "table_functions": { + + } +} \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/settings_grid.gd b/addons/resources_spreadsheet_view/settings_grid.gd new file mode 100644 index 00000000..ba242a9e --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.gd @@ -0,0 +1,39 @@ +@tool +extends GridContainer + +const PREFIX := "addons/resources_spreadsheet_view/" + + +func _ready(): + ProjectSettings.set_setting(PREFIX + "array_color_tint", 100.0 if ProjectSettings.get_setting(PREFIX + "color_arrays", true) else 0.0) + ProjectSettings.set_setting(PREFIX + "color_arrays", null) + + for x in get_children(): + var setting : String = PREFIX + x.name.to_snake_case() + if x is CheckBox: + x.toggled.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.button_pressed, setting) + + else: + x.button_pressed = ProjectSettings.get_setting(setting) + + elif x is OptionButton: + x.item_selected.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.selected, setting) + + else: + x.selected = ProjectSettings.get_setting(setting) + + elif x is Range: + x.value_changed.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.value, setting) + + else: + x.value = ProjectSettings.get_setting(setting) + + +func _set_setting(new_value, setting : String): + ProjectSettings.set_setting(setting, new_value) diff --git a/addons/resources_spreadsheet_view/settings_grid.gd.uid b/addons/resources_spreadsheet_view/settings_grid.gd.uid new file mode 100644 index 00000000..a2466afd --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.gd.uid @@ -0,0 +1 @@ +uid://dq4urh7lb5mb2 diff --git a/addons/resources_spreadsheet_view/settings_grid.tscn b/addons/resources_spreadsheet_view/settings_grid.tscn new file mode 100644 index 00000000..860aa9ef --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.tscn @@ -0,0 +1,141 @@ +[gd_scene load_steps=2 format=3 uid="uid://dhunxgcae6h1"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/settings_grid.gd" id="1_s8s2f"] + +[node name="Settings" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -622.0 +offset_bottom = -322.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="RichTextLabel" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="GridContainer" type="GridContainer" parent="RichTextLabel"] +layout_mode = 2 +columns = 2 +script = ExtResource("1_s8s2f") + +[node name="Label" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Color-type cells style rows" +autowrap_mode = 2 + +[node name="ColorRows" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label2" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Collection item color tint" +autowrap_mode = 2 + +[node name="ArrayColorTint" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +value = 100.0 + +[node name="Label3" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Array cell min width" +autowrap_mode = 2 + +[node name="ArrayMinWidth" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +min_value = 32.0 +max_value = 512.0 +value = 128.0 + +[node name="Label8" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Resource preview size (Including Textures)" +autowrap_mode = 2 + +[node name="ResourcePreviewSize" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +min_value = 8.0 +max_value = 1024.0 +value = 32.0 + +[node name="Label7" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Clip header text (makes columns smaller)" +autowrap_mode = 2 + +[node name="ClipHeaders" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +text = "Enable" + +[node name="Label5" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Duplicate arrays on edit (slower, but can be undone)" +autowrap_mode = 2 + +[node name="DupeArrays" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label6" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show context menu on left-click (and not just rightclick)" +autowrap_mode = 2 + +[node name="ContextMenuOnLeftclick" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +text = "Enable" + +[node name="Label9" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Fold bottom docks on startup (drag their top bar to resize)" +autowrap_mode = 2 + +[node name="FoldDocks" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label10" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Resources in cells (allow viewing _to_string() override's result)" +autowrap_mode = 2 + +[node name="ResourceCellLabelMode" type="OptionButton" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +toggle_mode = false +selected = 1 +allow_reselect = true +item_count = 3 +popup/item_0/text = "Name + ToString()" +popup/item_0/id = 3 +popup/item_1/text = "ToString()" +popup/item_1/id = 1 +popup/item_2/text = "Name Only" +popup/item_2/id = 2 + +[node name="Label11" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Freeze/Lock First Column" +autowrap_mode = 2 + +[node name="FreezeFirstColumn" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" diff --git a/addons/resources_spreadsheet_view/text_editing_utils.gd b/addons/resources_spreadsheet_view/text_editing_utils.gd new file mode 100644 index 00000000..f81027c1 --- /dev/null +++ b/addons/resources_spreadsheet_view/text_editing_utils.gd @@ -0,0 +1,192 @@ +extends RefCounted + +const non_typing_paragraph := "¶" +const non_typing_space := "●" +const whitespace_chars := [ + 32, # " " + 44, # "," + 58, # ":" + 45, # "-" + 59, # ";" + 40, # "(" + 41, # ")" + 46, # "." + 182, # "¶" Linefeed + 10, # "\n" Actual Linefeed + 967, # "●" Whitespace +] + + +static func is_character_whitespace(text : String, idx : int) -> bool: + if idx <= 0: return true # Stop at the edges. + if idx >= text.length(): return true + return text.unicode_at(idx) in whitespace_chars + + +static func show_non_typing(text : String) -> String: + text = text\ + .replace(non_typing_paragraph, "\n")\ + .replace(non_typing_space, " ") + + if text.ends_with("\n"): + text = text.left(text.length() - 1) + non_typing_paragraph + + elif text.ends_with(" "): + text = text.left(text.length() - 1) + non_typing_space + + return text + + +static func revert_non_typing(text : String) -> String: + if text.ends_with(non_typing_paragraph): + text = text.left(text.length() - 1) + "\n" + + elif text.ends_with(non_typing_space): + text = text.left(text.length() - 1) + " " + + return text + + +static func get_caret_movement_from_key(keycode : int) -> int: + match keycode: + KEY_LEFT: + return -1 + KEY_RIGHT: + return +1 + KEY_HOME: + return -2 + KEY_END: + return +2 + + return 0 + + +static func multi_move_caret(offset : int, edited_cells_text : Array, edit_caret_positions : Array, whole_word : bool) -> bool: + if offset == -1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = _step_cursor(edited_cells_text[i], edit_caret_positions[i], -1, whole_word) + + elif offset == +1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = _step_cursor(edited_cells_text[i], edit_caret_positions[i], +1, whole_word) + + elif offset < -1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = 0 + + elif offset > +1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = edited_cells_text[i].length() + + return offset != 0 + + +static func multi_erase_right(values : Array, cursor_positions : Array, whole_word : bool): + for i in values.size(): + var start_pos : int = cursor_positions[i] + cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, whole_word) + + cursor_positions[i] = min( + cursor_positions[i], + values[i].length() + ) + values[i] = ( + values[i].left(start_pos) + + values[i].substr(cursor_positions[i]) + ) + cursor_positions[i] = start_pos + + return values + + +static func multi_erase_left(values : Array, cursor_positions : Array, whole_word : bool): + for i in values.size(): + var start_pos : int = cursor_positions[i] + + cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, whole_word) + values[i] = ( + values[i].substr(0, cursor_positions[i]) + + values[i].substr(start_pos) + ) + + return values + + +static func multi_paste(values : Array, cursor_positions : Array): + var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n") + var paste_each_line := pasted_lines.size() == values.size() + + for i in values.size(): + if paste_each_line: + cursor_positions[i] += pasted_lines[i].length() + + else: + cursor_positions[i] += DisplayServer.clipboard_get().length() + + values[i] = ( + values[i].left(cursor_positions[i]) + + (pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get()) + + values[i].substr(cursor_positions[i]) + ) + + return values + + +static func multi_copy(values : Array): + DisplayServer.clipboard_set("\n".join(values)) + + +static func multi_input(input_char : String, values : Array, cursor_positions : Array): + for i in values.size(): + values[i] = ( + values[i].left(cursor_positions[i]) + + input_char + + values[i].substr(cursor_positions[i]) + ) + cursor_positions[i] = min(cursor_positions[i] + 1, values[i].length()) + + return values + + +static func get_caret_rect(cell_text : String, caret_position : int, font : Font, font_size : int, label_padding_left : float, caret_width : float = 2.0) -> Rect2: + var font_height := font.get_height(font_size) + var char_size := Vector2(0, font_height) + var result_pos := Vector2(label_padding_left, 0) + for j in max(caret_position, 0) + 1: + if j == 0: continue + if cell_text.unicode_at(j - 1) == 10: + # If "\n" found, next line. + # The 2.0 is ACTUALLY not 2.0 and varies per character. + # Since get_char_size() does not return the correct size, this will cause problems with non-Latin characters + result_pos.x = label_padding_left + result_pos.y += font_height - 2.0 + font_height = 0.0 + continue + + char_size = font.get_char_size(cell_text.unicode_at(j - 1), font_size) + font_height = maxf(char_size.y, font_height) + result_pos.x += char_size.x + + return Rect2(result_pos + Vector2(1.0, 0.0), Vector2(caret_width, char_size.y)) + + +static func _step_cursor(text : String, start : int, step : int = 1, whole_word : bool = false) -> int: + var cur := start + if whole_word and is_character_whitespace(text, cur + step): + cur += step + + while true: + cur += step + if !whole_word or is_character_whitespace(text, cur): + if cur > text.length(): + return text.length() + + if cur <= 0: + return 0 + + if whole_word and step < 0: + return cur + 1 + + return cur + + return 0 diff --git a/addons/resources_spreadsheet_view/text_editing_utils.gd.uid b/addons/resources_spreadsheet_view/text_editing_utils.gd.uid new file mode 100644 index 00000000..026d678c --- /dev/null +++ b/addons/resources_spreadsheet_view/text_editing_utils.gd.uid @@ -0,0 +1 @@ +uid://b52jvnmp6vf1n diff --git a/addons/resources_spreadsheet_view/typed_cells/array.tscn b/addons/resources_spreadsheet_view/typed_cells/array.tscn new file mode 100644 index 00000000..61062ace --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/array.tscn @@ -0,0 +1,36 @@ +[gd_scene format=3 uid="uid://ydrs54md3knl"] + +[node name="Label" type="MarginContainer"] +offset_right = 16.0 +offset_bottom = 16.0 +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Box" type="HFlowContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="Back" type="Control" parent="."] +show_behind_parent = true +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Back"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -1.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) diff --git a/addons/resources_spreadsheet_view/typed_cells/basic.tscn b/addons/resources_spreadsheet_view/typed_cells/basic.tscn new file mode 100644 index 00000000..541f1bac --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/basic.tscn @@ -0,0 +1,33 @@ +[gd_scene format=3 uid="uid://cghfjg6qt3rb1"] + +[node name="Label" type="Label"] +offset_right = 20.0 +offset_bottom = 23.0 +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Back" type="ColorRect" parent="."] +show_behind_parent = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -1.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd new file mode 100644 index 00000000..c8a03f1b --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd @@ -0,0 +1,46 @@ +class_name ResourceTablesCellEditor +extends RefCounted + +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +const CELL_SCENE_DIR := "res://addons/resources_spreadsheet_view/typed_cells/" + +var hint_strings_array := [] + + +## Override to define where the cell should be shown. +func can_edit_value(value, type, property_hint, column_index) -> bool: + return value != null + +## Override to change how the cell is created; preload a scene or create nodes from code. +## Caller is an instance of [code]editor_view.tscn[/code]. +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "basic.tscn").instantiate() + +## Override to change behaviour when the cell is clicked to be selected. +func set_selected(node : Control, selected : bool): + node.get_node("Selected").visible = selected + +## Override to change how the value is displayed. +func set_value(node : Control, value): + node.text = TextEditingUtilsClass.show_non_typing(str(value)) + +## Override to prevent the cell from being edited as text. +func is_text(): + return true + +## Override to refresh internal text values when edited using keyboard. +func text_update_on_edit(): + return false + +## Override to define custom behaviour for converting the value into text for editing and copy/paste. +func to_text(value) -> String: + return var_to_str(value) + +## Override to define custom behaviour for converting the value from text for editing and copy/paste. +func from_text(text : String): + return str_to_var(text) + +## Override to change behaviour when there are color cells to the left of this cell. +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 1.0 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid new file mode 100644 index 00000000..83c66797 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid @@ -0,0 +1 @@ +uid://d7ir8dgaeibm diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd new file mode 100644 index 00000000..1ddd9399 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd @@ -0,0 +1,64 @@ +extends ResourceTablesCellEditor + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_PACKED_STRING_ARRAY or type == TYPE_ARRAY + + +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "array.tscn").instantiate() + + +func set_value(node : Control, value): + var children := node.get_node("Box").get_children() + node.custom_minimum_size.x = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_min_width") + var color_tint : float = 0.01 * ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_color_tint", 100.0) + var cell_label_mode : int = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0) + while children.size() < value.size(): + children.append(Label.new()) + node.get_node("Box").add_child(children[children.size() - 1]) + + var column_hints = hint_strings_array[node.get_index() % hint_strings_array.size()] + for i in children.size(): + if i >= value.size(): + children[i].visible = false + + else: + children[i].visible = true + _write_value_to_child(value[i], value[i], column_hints, children[i], color_tint, cell_label_mode) + + +func _write_value_to_child(value, key, hint_arr : PackedStringArray, child : Label, color_tint : float, cell_label_mode : int): + if value is Resource: + value = _resource_to_string(value, cell_label_mode) + + if key is Resource: + key = _resource_to_string(key, cell_label_mode) + + child.text = str(value) + child.self_modulate = ( + Color.WHITE * (1.0 - color_tint) + + + (Color(str(key).hash()) + Color(0.2, 0.2, 0.2, 1.0)) * color_tint + ) + + +static func _resource_to_string(res : Resource, cell_label_mode : int): + var prefix := "" + if cell_label_mode != 2: + if res.has_method(&"_to_string"): + prefix = res._to_string() + "\n" + + elif res.has_method(&"ToString"): + prefix = res.ToString() + "\n" + + if cell_label_mode == 1 && !prefix.is_empty(): + return prefix.trim_suffix("\n") + + return prefix + (res.resource_name if res.resource_name != "" else "[%s]" % res.resource_path.get_file()) + + +func is_text(): + return false diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid new file mode 100644 index 00000000..344f1ecf --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid @@ -0,0 +1 @@ +uid://b42jhwbimgaor diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd new file mode 100644 index 00000000..4848b715 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd @@ -0,0 +1,34 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_BOOL + + +func set_value(node : Control, value): + if value is bool: + _set_value_internal(node, value) + + else: + _set_value_internal(node, node.text.begins_with("O")) + + +func _set_value_internal(node, value): + node.text = "ON" if value else "off" + node.self_modulate.a = 1.0 if value else 0.2 + + +func text_update_on_edit(): + return true + + +func to_text(value) -> String: + return "ON" if value else "off" + + +func from_text(text : String): + if text.begins_with("O"): + return text == "ON" + + else: + return text != "off" diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid new file mode 100644 index 00000000..b1546b8b --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid @@ -0,0 +1 @@ +uid://c5xp6d8r5dm5h diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd new file mode 100644 index 00000000..019a1f27 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd @@ -0,0 +1,43 @@ +extends ResourceTablesCellEditor + +var _cached_color := Color.WHITE + + +func create_cell(caller : Control) -> Control: + var node : Label = load(CELL_SCENE_DIR + "basic.tscn").instantiate() + var color := ColorRect.new() + node.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + node.custom_minimum_size.x = 56 + node.add_child(color) + color.name = "Color" + _resize_color_rect.call_deferred(color) + return node + + +func _resize_color_rect(rect): + if !is_instance_valid(rect): return # Table refreshed twice, probably? Either way, this fix is easier + rect.size = Vector2(8, 0) + rect.set_anchors_and_offsets_preset(Control.PRESET_LEFT_WIDE, Control.PRESET_MODE_KEEP_WIDTH) + + +func can_edit_value(value, type, property_hint, property_hint_string) -> bool: + return type == TYPE_COLOR + + +func set_value(node : Control, value): + if value is String: + node.text = TextEditingUtilsClass.show_non_typing(str(value)) + + else: + node.text = value.to_html(true) + _cached_color = value + + node.get_node("Color").color = value + + +func to_text(value) -> String: + return value.to_html() + + +func from_text(text : String): + return Color.from_string(text, Color.BLACK) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid new file mode 100644 index 00000000..9d333955 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid @@ -0,0 +1 @@ +uid://fkojswcshsu7 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd new file mode 100644 index 00000000..cec47024 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd @@ -0,0 +1,51 @@ +extends "res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_DICTIONARY + + +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "array.tscn").instantiate() + + +func set_value(node : Control, value): + var children := node.get_node("Box").get_children() + node.custom_minimum_size.x = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_min_width") + var color_tint : float = 0.01 * ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_color_tint", 100.0) + var cell_label_mode : int = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0) + while children.size() < value.size(): + children.append(Label.new()) + node.get_node("Box").add_child(children[children.size() - 1]) + + var column_hints : PackedStringArray = hint_strings_array[node.get_index() % hint_strings_array.size()] + var values : Array = value.values() + var keys : Array = value.keys() + + for i in children.size(): + if i >= values.size(): + children[i].visible = false + + else: + children[i].visible = true + var current_value = values[i] + var current_key = keys[i] + if current_value is Resource: + current_value = _resource_to_string(current_value, cell_label_mode) + + if current_key is Resource: + current_key = _resource_to_string(current_key, cell_label_mode) + + _write_value_to_child("%s ◆ %s" % [current_key, current_value], current_key, column_hints, children[i], color_tint, cell_label_mode) + + +func is_text(): + return false + + +func to_text(value) -> String: + return var_to_str(value).replace("\n", " ") + + +func from_text(text : String): + return str_to_var(text) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid new file mode 100644 index 00000000..a5731ac3 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid @@ -0,0 +1 @@ +uid://cbxk1q40v5wc5 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd new file mode 100644 index 00000000..e05f5ced --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd @@ -0,0 +1,38 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_INT and property_hint == PROPERTY_HINT_ENUM + + +func set_value(node : Control, value): + if value == null: + # Sometimes, when creating new property, becomes null + value = 0 + + var value_str : String + var key_found := -1 + var hint_arr : Array = hint_strings_array[node.get_index() % hint_strings_array.size()] + for i in hint_arr.size(): + var colon_found : int = hint_arr[i].rfind(":") + if colon_found == -1: + key_found = value + break + + if hint_arr[i].substr(colon_found + 1).to_int() == value: + key_found = i + break + + if key_found != -1 and key_found < hint_arr.size(): + value_str = hint_arr[key_found] + + else: + value_str = "?:%s" % value + + node.text = value_str + node.self_modulate = Color(node.text.hash()) + Color(0.25, 0.25, 0.25, 1.0) + node.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + +func is_text(): + return false diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid new file mode 100644 index 00000000..da99ffc1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid @@ -0,0 +1 @@ +uid://prde4jp5vqja diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd new file mode 100644 index 00000000..c9d19fb2 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd @@ -0,0 +1,39 @@ +extends "res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + if ( + type != TYPE_PACKED_INT32_ARRAY + and type != TYPE_PACKED_INT64_ARRAY + and type != TYPE_ARRAY + ) or property_hint != PROPERTY_HINT_TYPE_STRING: + return false + + return hint_strings_array[column_index][0].begins_with("2/2:") + + +func _write_value_to_child(value, key, hint_arr : PackedStringArray, child : Label, color_tint : float, cell_label_mode : int): + var value_str : String + var key_found := -1 + for i in hint_arr.size(): + var colon_found := hint_arr[i].rfind(":") + if colon_found == -1: + key_found = value + break + + if hint_arr[i].substr(colon_found + 1).to_int() == value: + key_found = i + break + + if key_found == 0: + # Enum array hints have "2/3:" before list. + var found := hint_arr[0].find(":") + 1 + value_str = hint_arr[0].substr(hint_arr[0].find(":") + 1) + + elif key_found != -1: + value_str = hint_arr[key_found] + + else: + value_str = "?:%s" % value + + super(value_str, value_str, hint_arr, child, color_tint, cell_label_mode) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid new file mode 100644 index 00000000..d49522c6 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid @@ -0,0 +1 @@ +uid://tawbbu20kith diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd new file mode 100644 index 00000000..4f008339 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd @@ -0,0 +1,13 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_FLOAT or type == TYPE_INT + + +func to_text(value) -> String: + return str(value) + + +func from_text(text : String): + return text.to_float() diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid new file mode 100644 index 00000000..ce411a08 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid @@ -0,0 +1 @@ +uid://cl3h0tvulww5e diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd new file mode 100644 index 00000000..e2a170f6 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd @@ -0,0 +1,73 @@ +extends ResourceTablesCellEditor + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +var previewer : EditorResourcePreview + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_OBJECT + + +func create_cell(caller : Control) -> Control: + if previewer == null: + previewer = caller.editor_plugin.get_editor_interface().get_resource_previewer() + + var node = load(CELL_SCENE_DIR + "resource.tscn").instantiate() + return node + + +func set_value(node : Control, value): + var preview_node := node.get_node("Box/Tex") + var label_node := node.get_node("Box/Label") + if value == null: + preview_node.visible = false + label_node.text = "[empty]" + node.editor_description = "" + + if !value is Resource: return + + node.editor_description = value.resource_path + label_node.text = _resource_to_string(value, ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0)) + + if value is Texture: + preview_node.visible = true + preview_node.texture = value + + else: + preview_node.visible = false + previewer.queue_resource_preview(value.resource_path, self, &"_on_preview_loaded", node) + + preview_node.custom_minimum_size = Vector2.ONE * ProjectSettings.get_setting( + TablesPluginSettingsClass.PREFIX + "resource_preview_size" + ) + + +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 0.6 if node.editor_description == "" else color + + +func is_text(): + return false + + +func _on_preview_loaded(path : String, preview : Texture, thumbnail_preview : Texture, node): + # Abort if the node has been deleted since. + if is_instance_valid(node): + node.get_node("Box/Tex").visible = true + node.get_node("Box/Tex").texture = preview + + +static func _resource_to_string(res : Resource, cell_label_mode : int): + var prefix := "" + if cell_label_mode != 2: + if res.has_method(&"_to_string"): + prefix = res._to_string() + "\n" + + elif res.has_method(&"ToString"): + prefix = res.ToString() + "\n" + + if cell_label_mode == 1 && !prefix.is_empty(): + return prefix.trim_suffix("\n") + + return prefix + (res.resource_name if res.resource_name != "" else "[%s]" % res.resource_path.get_file()) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid new file mode 100644 index 00000000..a97c8a72 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid @@ -0,0 +1 @@ +uid://0vmq5jtk4m6p diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd new file mode 100644 index 00000000..5a565013 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd @@ -0,0 +1,13 @@ +extends ResourceTablesCellEditor + + +func to_text(value) -> String: + return str(value) + + +func from_text(text : String): + return text + + +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 0.6 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid new file mode 100644 index 00000000..87e77895 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid @@ -0,0 +1 @@ +uid://4ojdojn2ehky diff --git a/addons/resources_spreadsheet_view/typed_cells/resource.tscn b/addons/resources_spreadsheet_view/typed_cells/resource.tscn new file mode 100644 index 00000000..1372d023 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/resource.tscn @@ -0,0 +1,45 @@ +[gd_scene format=3 uid="uid://clcndgxaty503"] + +[node name="Label" type="MarginContainer"] +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Back" type="Control" parent="."] +show_behind_parent = true +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Back"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -2.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) + +[node name="Box" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="Tex" type="TextureRect" parent="Box"] +layout_mode = 2 +mouse_filter = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="Label" type="Label" parent="Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "res.tres" diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.gd b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd new file mode 100644 index 00000000..bd5270b1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd @@ -0,0 +1,252 @@ +@tool +extends ResourceTablesDockEditor + +@onready var recent_container := $"HBoxContainer/Control2/HBoxContainer/HFlowContainer" +@onready var contents_label := $"HBoxContainer/HBoxContainer/Panel/Label" +@onready var button_box := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer" +@onready var value_input := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/LineEdit" + +var _stored_value +var _stored_type := 0 + + +func _ready(): + super() + contents_label.text_changed.connect(_on_contents_edit_text_changed) + + +func try_edit_value(value, type, property_hint) -> bool: + if ( + type != TYPE_ARRAY and type != TYPE_PACKED_STRING_ARRAY + and type != TYPE_PACKED_INT32_ARRAY and type != TYPE_PACKED_FLOAT32_ARRAY + and type != TYPE_PACKED_INT64_ARRAY and type != TYPE_PACKED_FLOAT64_ARRAY + ): + return false + + if sheet.column_hint_strings[sheet.get_selected_column()][0].begins_with("2/2:"): + # For enums, prefer the specialized dock. + return false + + _stored_type = type + _stored_value = value.duplicate() # Generic arrays are passed by reference + contents_label.text = str(value) + + var is_generic_array : bool = _stored_type == TYPE_ARRAY and !value.is_typed() + button_box.get_child(1).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_STRING or value.get_typed_builtin() == TYPE_STRING_NAME + or _stored_type == TYPE_PACKED_STRING_ARRAY + ) + button_box.get_child(2).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_INT + or _stored_type == TYPE_PACKED_INT32_ARRAY or _stored_type == TYPE_PACKED_INT64_ARRAY + ) + button_box.get_child(3).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_FLOAT + or _stored_type == TYPE_PACKED_FLOAT32_ARRAY or _stored_type == TYPE_PACKED_FLOAT64_ARRAY + ) + button_box.get_child(5).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_OBJECT + ) + + if value.get_typed_builtin() == TYPE_OBJECT: + if !value_input is EditorResourcePicker: + var new_input : EditorResourcePicker = load("res://addons/resources_spreadsheet_view/editor_resource_array_picker.gd").new() + new_input.size_flags_horizontal = SIZE_EXPAND_FILL + new_input.base_type = value.get_typed_class_name() + new_input.on_resources_dropped.connect(func(p): + _add_values(p) + for x in p: + _add_recent(x) + ) + new_input.resource_selected.connect(func(p1, p2): EditorInterface.edit_resource(p1)) + + value_input.replace_by(new_input) + value_input.free() + value_input = new_input + + else: + if !value_input is LineEdit: + var new_input := LineEdit.new() + new_input.size_flags_horizontal = SIZE_EXPAND_FILL + + value_input.replace_by(new_input) + value_input.free() + value_input = new_input + + return true + + +func _add_value(value): + _stored_value.append(value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append(value) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_values(added_values : Array): + _stored_value.append_array(added_values) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append_array(added_values) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _remove_value(value): + _stored_value.remove_at(_stored_value.find(value)) + var values : Array = sheet.get_edited_cells_values() + var cur_value : Array + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + if cur_value.has(value): # erase() not defined in PoolArrays + cur_value.remove_at(cur_value.find(value)) + + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_recent(value): + for x in recent_container.get_children(): + if x.text == str(value): + return + + if value is Resource and x.tooltip_text == value.resource_path: + return + + var node := Button.new() + var value_str : String = str(value) + if value is Resource: + value_str = value.resource_path.get_file() if value.resource_name == "" else value.resource_name + node.tooltip_text = value.resource_path + + node.text = value_str + node.self_modulate = Color(value_str.hash()) + Color(0.25, 0.25, 0.25, 1.0) + node.pressed.connect(_on_recent_clicked.bind(node, value)) + recent_container.add_child(node) + + +func _on_recent_clicked(button : Button, value): + var recent_mode : int = recent_container.get_child(1).selected + if value_input is EditorResourcePicker: + value_input.edited_resource = value + + else: + value_input.text = str(value) + + if recent_mode == 0: + _add_value(value) + + if recent_mode == 1: + _remove_value(value) + + if recent_mode == 2: + button.queue_free() + + +func _on_Remove_pressed(): + if value_input is EditorResourcePicker: + _remove_value(value_input.edited_resource) + + elif str_to_var(value_input.text) != null: + _remove_value(str_to_var(value_input.text)) + + else: + _remove_value(value_input.text) + + +func _on_RemoveLast_pressed(): + _stored_value.pop_back() + var values : Array = sheet.get_edited_cells_values() + var cur_value : Array + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.pop_back() + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_ClearRecent_pressed(): + for i in recent_container.get_child_count(): + if i == 0: continue + recent_container.get_child(i).free() + + +func _on_Float_pressed(): + _add_value(value_input.text.to_float()) + + +func _on_Int_pressed(): + _add_value(value_input.text.to_int()) + + +func _on_String_pressed(): + _add_value(value_input.text) + _add_recent(value_input.text) + + +func _on_Variant_pressed(): + if value_input is EditorResourcePicker: + _add_value(value_input.edited_resource) + + else: + _add_value(str_to_var(value_input.text)) + + +func _on_Resource_pressed(): + var new_value + if value_input is LineEdit: + new_value = load(value_input.text) + + elif value_input is EditorResourcePicker: + new_value = value_input.edited_resource + + _add_value(new_value) + _add_recent(new_value) + + +func _on_AddRecentFromSel_pressed(): + for x in sheet.get_edited_cells_values(): + for y in x: + _add_recent(y) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Array: + return + + var values : Array = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = values[i].duplicate() + values[i].resize(value.size()) + for j in value.size(): + values[i][j] = value[j] + + _stored_value = value + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid new file mode 100644 index 00000000..f9e58da1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid @@ -0,0 +1 @@ +uid://ctvrj6pm2sxdr diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn new file mode 100644 index 00000000..0fd2cbf1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn @@ -0,0 +1,195 @@ +[gd_scene load_steps=5 format=3 uid="uid://c3a2cip8ffccv"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_array.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2"] + +[sub_resource type="Image" id="Image_3slrg"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_3slrg") + +[node name="EditArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Array" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 380 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +placeholder_text = "Input value to add/erase..." +clear_button_enabled = true + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Add:" + +[node name="String" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add string" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "String" + +[node name="Int" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add integer" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "int" + +[node name="Float" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add float" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "float" + +[node name="Variant" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Guess type and add" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Variant" + +[node name="Object" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add resource (by path if string)" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Object" + +[node name="Label2" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Erase:" + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Find and erase value in textbox" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Remove" + +[node name="Remove2" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Remove last value" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "MoveLeft" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="ScrollContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +horizontal_scroll_mode = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Recent:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 3 +popup/item_0/text = "Add" +popup/item_1/text = "Erase" +popup/item_1/id = 1 +popup/item_2/text = "Remove From Recent" +popup/item_2/id = 2 + +[node name="AddRecentFromSel" type="Button" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +tooltip_text = "Add from selected cells" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "ListSelect" + +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/String" to="." method="_on_String_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Int" to="." method="_on_Int_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Float" to="." method="_on_Float_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Variant" to="." method="_on_Variant_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Object" to="." method="_on_Resource_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove" to="." method="_on_Remove_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove2" to="." method="_on_RemoveLast_pressed"] +[connection signal="pressed" from="HBoxContainer/Control2/HBoxContainer/HFlowContainer/AddRecentFromSel" to="." method="_on_AddRecentFromSel_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_base.gd b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd new file mode 100644 index 00000000..79d42298 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd @@ -0,0 +1,50 @@ +@tool +class_name ResourceTablesDockEditor +extends Control + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@export var path_property_name := NodePath("Header/Label") + +var sheet : Control +var selection : Array + +var _resize_target_height := 0.0 +var _resize_pressed := false + + +func _ready(): + var parent := get_parent() + while parent != null and !parent.has_method(&"display_folder"): + parent = parent.get_parent() + + sheet = parent + get_node(path_property_name).add_theme_font_override(&"normal", get_theme_font(&"bold", &"EditorFonts")) + + $"Header".gui_input.connect(_on_header_gui_input) + $"Header".mouse_filter = MOUSE_FILTER_STOP + $"Header".mouse_default_cursor_shape = CURSOR_VSIZE + +## Override to define when to show the dock and, if it can edit the value, how to handle it. +func try_edit_value(value, type : int, property_hint : String) -> bool: + return true + +## Override to define behaviour when stretching the header to change size. +func resize_drag(to_height : float): + return + + +func resize_set_hidden(state : bool): + get_child(1).visible = !state + + +func _on_header_gui_input(event : InputEvent): + if event is InputEventMouseMotion and _resize_pressed: + _resize_target_height -= event.relative.y + custom_minimum_size.y = clamp(_resize_target_height, 0.0, get_viewport().size.y * 0.75) + resize_drag(_resize_target_height) + resize_set_hidden(_resize_target_height <= $"Header".size.y) + + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + _resize_pressed = event.pressed + _resize_target_height = custom_minimum_size.y diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid new file mode 100644 index 00000000..15407a81 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid @@ -0,0 +1 @@ +uid://b5r8fnpa1q172 diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.gd b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd new file mode 100644 index 00000000..6529cebd --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd @@ -0,0 +1,139 @@ +@tool +extends ResourceTablesDockEditor + +@onready var _value_rect := $"EditColor/ColorProper/ColorRect" +@onready var _color_picker_panel := $"EditColor/VSeparator6/Panel" +@onready var _color_picker := $"EditColor/VSeparator6/Panel/MarginContainer/ColorPicker" +@onready var _custom_value_edit := $"EditColor/CustomX/Box/LineEdit" + +var _stored_value := Color.WHITE +var _resize_height_small := 0.0 +var _resize_expanded := true + + +func _ready(): + super._ready() + _connect_buttons($"EditColor/RGBGrid", 0, 0) + _connect_buttons($"EditColor/RGBGrid", 5, 1) + _connect_buttons($"EditColor/RGBGrid", 10, 2) + _connect_buttons($"EditColor/HSVGrid", 0, 3) + _connect_buttons($"EditColor/HSVGrid", 5, 4) + _connect_buttons($"EditColor/HSVGrid", 10, 5) + + _resize_height_small = get_child(1).get_minimum_size().y + + +func _connect_buttons(grid, start_index, property_bind): + grid.get_child(start_index + 0).pressed.connect(_increment_values_custom.bind(-1.0, property_bind)) + grid.get_child(start_index + 1).pressed.connect(_increment_values.bind(-10.0, property_bind)) + grid.get_child(start_index + 3).pressed.connect(_increment_values.bind(10.0, property_bind)) + grid.get_child(start_index + 4).pressed.connect(_increment_values_custom.bind(1.0, property_bind)) + + +func try_edit_value(value, type, property_hint) -> bool: + _color_picker_panel.top_level = false + if type != TYPE_COLOR: + return false + + _set_stored_value(value) + _color_picker_panel.visible = false + return true + + +func resize_drag(to_height : float): + var expanded := to_height > _resize_height_small + if _resize_expanded == expanded: + return + + _resize_expanded = expanded + $"EditColor/RGBGrid".visible = expanded + $"EditColor/ColorProper".visible = expanded + $"EditColor/HSVGrid".columns = 5 if expanded else 15 + $"EditColor/CustomX/Label".visible = expanded + + +func _set_stored_value(v): + _stored_value = v + _color_picker.color = v + _value_rect.color = v + + +func _increment_values(by : float, property : int): + var cell_values : Array = sheet.get_edited_cells_values() + match property: + 0: + _stored_value.r += by / 255.0 + for i in cell_values.size(): + cell_values[i].r += by / 255.0 + + 1: + _stored_value.g += by / 255.0 + for i in cell_values.size(): + cell_values[i].g += by / 255.0 + + 2: + _stored_value.b += by / 255.0 + for i in cell_values.size(): + cell_values[i].b += by / 255.0 + + 3: + # Hue has 360 degrees and loops + _stored_value.h += by / 360.0 + for i in cell_values.size(): + cell_values[i].h = fposmod(cell_values[i].h + by / 360.0, 1.0) + + 4: + _stored_value.s += by * 0.005 + for i in cell_values.size(): + cell_values[i].s += by * 0.005 + + 5: + _stored_value.v += by * 0.005 + for i in cell_values.size(): + cell_values[i].v += by * 0.005 + + _set_stored_value(_stored_value) + sheet.set_edited_cells_values(cell_values) + + +func _increment_values_custom(multiplier : float, property : int): + if property == 4 or property == 5: + # Numbered buttons increment by 5 for Sat and Value, so hue is x0.5 effect. Negate it here + multiplier *= 2.0 + + _increment_values(_custom_value_edit.text.to_float() * multiplier, property) + + +func _on_Button_pressed(): + _color_picker_panel.visible = !_color_picker_panel.visible + if _color_picker_panel.visible: + _color_picker_panel.top_level = true + _color_picker_panel.global_position = ( + sheet.global_position + + Vector2(0, sheet.size.y - _color_picker_panel.size.y) + + Vector2(16, -16) + ) + _color_picker_panel.global_position.y = clamp( + _color_picker_panel.global_position.y, + 0, + sheet.editor_plugin.get_editor_interface().get_base_control().size.y + ) + _color_picker.color = _stored_value + + elif _color_picker.color != _stored_value: + _set_stored_value(_color_picker.color) + update_cell_values() + + +func _on_ColorPicker_gui_input(event : InputEvent): + if event is InputEventMouseButton and !event.pressed: + _set_stored_value(_color_picker.color) + update_cell_values() + + +func update_cell_values(): + var values = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = _stored_value + + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid new file mode 100644 index 00000000..26451072 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid @@ -0,0 +1 @@ +uid://bkgtf5p3ii8l1 diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn new file mode 100644 index 00000000..d7774e16 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn @@ -0,0 +1,295 @@ +[gd_scene load_steps=2 format=3 uid="uid://b3a3bo6cfyh5t"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_color.gd" id="1"] + +[node name="EditColor" type="VBoxContainer"] +offset_bottom = 131.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Color" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="EditColor" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="VSeparator7" type="Control" parent="EditColor"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VSeparator3" type="Control" parent="EditColor"] +visible = false +layout_mode = 2 + +[node name="ButtonRowTemplate" type="Control" parent="EditColor"] +visible = false +layout_mode = 2 + +[node name="Button3" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "-5" + +[node name="Label" type="Label" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "Red" + +[node name="Button5" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "+5" + +[node name="Button6" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "+X" + +[node name="RGBGrid" type="GridContainer" parent="EditColor"] +layout_mode = 2 +columns = 5 + +[node name="Button3" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "-10" + +[node name="Label" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Red" +horizontal_alignment = 1 + +[node name="Button5" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "+10" + +[node name="Button6" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "+X" + +[node name="Button7" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "-X" + +[node name="Button8" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "-10" + +[node name="Label2" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Green" +horizontal_alignment = 1 + +[node name="Button11" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "+10" + +[node name="Button12" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "+X" + +[node name="Button13" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "-X" + +[node name="Button14" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "-10" + +[node name="Label3" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Blue" +horizontal_alignment = 1 + +[node name="Button17" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "+10" + +[node name="Button18" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "+X" + +[node name="VSeparator" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="ColorProper" type="VBoxContainer" parent="EditColor"] +layout_mode = 2 + +[node name="ColorRect" type="ColorRect" parent="EditColor/ColorProper"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Button" type="Button" parent="EditColor/ColorProper"] +layout_mode = 2 +text = "Choose Color" + +[node name="VSeparator2" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="HSVGrid" type="GridContainer" parent="EditColor"] +layout_mode = 2 +columns = 5 + +[node name="Button3" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(1, 0.913725, 0.776471, 1) +layout_mode = 2 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.898039, 1, 0.698039, 1) +layout_mode = 2 +text = "-10" + +[node name="Label" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Hue" +horizontal_alignment = 1 + +[node name="Button5" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.717647, 1, 0.980392, 1) +layout_mode = 2 +text = "+10" + +[node name="Button6" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.74902, 0.729412, 1, 1) +layout_mode = 2 +text = "+X" + +[node name="Button7" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-X" + +[node name="Button8" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-5" + +[node name="Label2" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Sat" +horizontal_alignment = 1 + +[node name="Button11" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+5" + +[node name="Button12" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+X" + +[node name="Button13" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-X" + +[node name="Button14" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-5" + +[node name="Label3" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Value" +horizontal_alignment = 1 + +[node name="Button17" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+5" + +[node name="Button18" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+X" + +[node name="VSeparator4" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="CustomX" type="VBoxContainer" parent="EditColor"] +layout_mode = 2 + +[node name="Label" type="Label" parent="EditColor/CustomX"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Custom Value" +horizontal_alignment = 1 + +[node name="Box" type="HBoxContainer" parent="EditColor/CustomX"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="EditColor/CustomX/Box"] +layout_mode = 2 +size_flags_vertical = 6 +text = "X =" + +[node name="LineEdit" type="LineEdit" parent="EditColor/CustomX/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "20" + +[node name="VSeparator6" type="Control" parent="EditColor"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Panel" type="PanelContainer" parent="EditColor/VSeparator6"] +visible = false +layout_mode = 1 +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +grow_vertical = 0 + +[node name="Panel2" type="Panel" parent="EditColor/VSeparator6/Panel"] +self_modulate = Color(1.5, 1.5, 1.5, 1) +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="EditColor/VSeparator6/Panel"] +layout_mode = 2 + +[node name="ColorPicker" type="ColorPicker" parent="EditColor/VSeparator6/Panel/MarginContainer"] +layout_mode = 2 + +[node name="Button" type="Button" parent="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker"] +layout_mode = 2 +text = "OK" + +[connection signal="pressed" from="EditColor/ColorProper/Button" to="." method="_on_Button_pressed"] +[connection signal="gui_input" from="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker" to="." method="_on_ColorPicker_gui_input"] +[connection signal="pressed" from="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker/Button" to="." method="_on_Button_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd new file mode 100644 index 00000000..f64eff4e --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd @@ -0,0 +1,201 @@ +@tool +extends "res://addons/resources_spreadsheet_view/typed_editors/dock_array.gd" + +enum { + KEY_TYPE_STRINGNAME = 0, + KEY_TYPE_INT, + KEY_TYPE_FLOAT, + KEY_TYPE_OBJECT, + KEY_TYPE_VARIANT, +} + +@onready var key_input := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyEdit" +@onready var key_type := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyType" + +var _key_type_selected := 0 + + +func try_edit_value(value, type, property_hint) -> bool: + if type != TYPE_DICTIONARY and type != TYPE_OBJECT: + return false + + if value is Texture2D: + # For textures, prefer the specialized dock. + return false + + key_type.visible = type != TYPE_OBJECT + + _stored_type = type + if type == TYPE_DICTIONARY: + _stored_value = value.duplicate() + + contents_label.text = var_to_str_no_sort(value) + + return true + + +func _add_value(value): + var key = _get_key_from_box() + _stored_value[key] = value + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value[key] = value + values[i] = cur_value + + sheet.set_edited_cells_values(values) + super._add_recent(key) + + +func _add_values(added_values : Array): + for x in added_values: + _add_value(x) + + +func _remove_value(_value): + var key = _get_key_from_box() + _stored_value.erase(key) + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value.erase(key) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _get_key_from_box(): + if _stored_type == TYPE_OBJECT: + return StringName(key_input.text) + + return _to_key(key_input.text, _key_type_selected) + + +func _to_key(from : String, key_type : int): + match key_type: + KEY_TYPE_STRINGNAME: + return StringName(from) + + KEY_TYPE_INT: + return from.to_int() + + KEY_TYPE_FLOAT: + return from.to_float() + + KEY_TYPE_OBJECT: + return load(from) + + KEY_TYPE_VARIANT: + return str_to_var(from) + + +func _on_Replace_pressed(): + var old_key = _to_key(key_input.text, _key_type_selected) + var new_key = _to_key(value_input.text, _key_type_selected) + _stored_value[new_key] = _stored_value[old_key] + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value[new_key] = cur_value[old_key] + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_recent(_value): + pass + + +func _on_recent_clicked(button, value): + var val : int = recent_container.get_child(1).selected + key_input.text = str(value) + if val == 0: + # Do nothing! What if the value for the key doesn't match? + pass + + if val == 1: + _remove_value(value) + + if val == 2: + button.queue_free() + + +func _on_key_type_selected(index : int): + _key_type_selected = index + + +func _on_AddRecentFromSel_pressed(): + for x in sheet.get_edited_cells_values(): + if _stored_type == TYPE_OBJECT: + for y in x.get_property_list(): + if y[&"usage"] & PROPERTY_USAGE_EDITOR != 0: + super._add_recent(y[&"name"]) + + else: + for y in x: + super._add_recent(y) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Dictionary: + return + + var values : Array = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = value.duplicate() + + _stored_value = value + sheet.set_edited_cells_values(values) + + +func var_to_str_no_sort(value, indent = " ", cur_indent = ""): + var lines : Array[String] = [] + + if value is Array: + cur_indent += indent + lines.resize(value.size()) + for i in lines.size(): + if value[i] is Array or value[i] is Dictionary: + lines[i] = "%s%s" % [cur_indent, var_to_str_no_sort(value[i])] + + else: + lines[i] = "%s%s" % [cur_indent, var_to_str(value[i])] + + cur_indent = cur_indent.substr(0, cur_indent.length() - indent.length()) + return "[\n" + ",\n".join(lines) + "\n]" + + if value is Dictionary: + var keys : Array = value.keys() + var values : Array = value.values() + cur_indent += indent + lines.resize(keys.size()) + for i in lines.size(): + if values[i] is Array or values[i] is Dictionary: + lines[i] = "%s%s : %s" % [cur_indent, var_to_str(keys[i]), var_to_str_no_sort(values[i])] + + else: + lines[i] = "%s%s : %s" % [cur_indent, var_to_str(keys[i]), var_to_str(values[i])] + + cur_indent = cur_indent.substr(0, cur_indent.length() - indent.length()) + return "{\n" + ",\n".join(lines) + "\n}" + + return ",\n".join(lines) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid new file mode 100644 index 00000000..07458619 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid @@ -0,0 +1 @@ +uid://cdv4upby5ffxx diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn new file mode 100644 index 00000000..44981ce8 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn @@ -0,0 +1,226 @@ +[gd_scene load_steps=5 format=3 uid="uid://p6x03dbvhnqw"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_dict.gd" id="1_2yivi"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_yck0k"] + +[sub_resource type="Image" id="Image_bq2wd"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_bq2wd") + +[node name="EditArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1_2yivi") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Dict/Object" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 520 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="HBoxContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="KeyEdit" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="KeyEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Input key to add/change/erase..." +clear_button_enabled = true + +[node name="KeyType" type="OptionButton" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 5 +popup/item_0/text = "Stringname" +popup/item_1/text = "Int" +popup/item_1/id = 1 +popup/item_2/text = "Float" +popup/item_2/id = 2 +popup/item_3/text = "Resource path" +popup/item_3/id = 4 +popup/item_4/text = "Guess type" +popup/item_4/id = 3 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Input value..." +clear_button_enabled = true + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Set value with type:" + +[node name="String" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to string" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "String" + +[node name="Int" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to integer" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "int" + +[node name="Float" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to float" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "float" + +[node name="Variant" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Guess type and set" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Variant" + +[node name="Object" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to resource (by path if string)" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Object" + +[node name="Label2" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Key:" + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Erase keys in Key textbox" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Remove" + +[node name="Replace" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Copy Key's value to new key +Example: +- key box = \"thing\" +- value box = \"thing two\" +- old dict = {\"thing\" : 12} +- resulting dict = {\"thing\" : 12, \"thing two\" : 12}" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Override" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="ScrollContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +horizontal_scroll_mode = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Recent:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 3 +popup/item_0/text = "Add" +popup/item_1/text = "Erase" +popup/item_1/id = 1 +popup/item_2/text = "Remove From Recent" +popup/item_2/id = 2 + +[node name="AddRecentFromSel" type="Button" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +tooltip_text = "Add from selected cells" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "ListSelect" + +[connection signal="item_selected" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyType" to="." method="_on_key_type_selected"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/String" to="." method="_on_String_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Int" to="." method="_on_Int_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Float" to="." method="_on_Float_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Variant" to="." method="_on_Variant_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Object" to="." method="_on_Resource_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove" to="." method="_on_Remove_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Replace" to="." method="_on_Replace_pressed"] +[connection signal="pressed" from="HBoxContainer/Control2/HBoxContainer/HFlowContainer/AddRecentFromSel" to="." method="_on_AddRecentFromSel_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd new file mode 100644 index 00000000..1398a248 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd @@ -0,0 +1,137 @@ +@tool +extends ResourceTablesDockEditor + +@onready var options_container := $"HBoxContainer/Control2/HBoxContainer/HFlowContainer" +@onready var contents_label := $"HBoxContainer/HBoxContainer/Panel/Label" + +@onready var _init_nodes_in_options_container := options_container.get_child_count() + +var _stored_value +var _last_column := -1 + + +func _ready(): + super() + contents_label.text_changed.connect(_on_contents_edit_text_changed) + + +func try_edit_value(value, type, property_hint) -> bool: + if !sheet.column_hint_strings[sheet.get_selected_column()][0].begins_with("2/2:"): + return false + + _stored_value = value.duplicate() # Generic arrays are passed by reference + if _last_column != sheet.get_selected_column(): + _last_column = sheet.get_selected_column() + for x in options_container.get_children(): + x.visible = x.get_index() < _init_nodes_in_options_container + + for i in sheet.column_hint_strings[sheet.get_selected_column()].size(): + _create_option_button(i) + + contents_label.text = str(value) + return true + + +func _create_option_button(index : int): + var value = sheet.column_hint_strings[sheet.get_selected_column()][index] + if index == 0: + # Enum array hints have "2/3:" before list. + value = value.substr(value.find(":") + 1) + + var node + if index >= options_container.get_child_count() - _init_nodes_in_options_container: + node = Button.new() + options_container.add_child(node) + var colon_found : int = value.rfind(":") + if colon_found == -1: + node.pressed.connect(_on_option_clicked.bind(index)) + + else: + node.pressed.connect(_on_option_clicked.bind(value.substr(colon_found + 1).to_int())) + + else: + node = options_container.get_child(index + _init_nodes_in_options_container) + node.visible = true + + node.text = str(value) + node.self_modulate = Color(value.hash()) + Color(0.25, 0.25, 0.25, 1.0) + return node + + +func _add_value(option_value : int): + _stored_value.append(option_value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append(option_value) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _remove_value(option_value : int): + _stored_value.append(option_value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + if cur_value.has(option_value): + cur_value.remove_at(cur_value.find(option_value)) + + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_option_clicked(value : int): + var val = options_container.get_child(1).selected + if val == 0: + _add_value(value) + + if val == 1: + _remove_value(value) + + +func _on_Remove_pressed(): + _stored_value.remove_at(_stored_value.size() - 1) + var values = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.remove_at(cur_value.size() - 1) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Array: + return + + for x in value: + if !x is int: + return + + var values = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = values[i].duplicate() + values[i].resize(value.size()) + for j in value.size(): + values[i][j] = value[j] + + _stored_value = value + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid new file mode 100644 index 00000000..2e447e04 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid @@ -0,0 +1 @@ +uid://mrydsp3bnps5 diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn new file mode 100644 index 00000000..c1540d53 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn @@ -0,0 +1,117 @@ +[gd_scene load_steps=5 format=3 uid="uid://ddqak780cwwfj"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd" id="1_n3flg"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_mda1e"] + +[sub_resource type="Image" id="Image_5ktp6"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_5ktp6") + +[node name="EditEnumArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +mouse_filter = 0 +script = ExtResource("1_n3flg") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Enum Array" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 250 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +text = "Remove Last Value" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_mda1e") +icon_name = "Remove" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Options:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +item_count = 2 +selected = 0 +fit_to_longest_item = false +popup/item_0/text = "Add" +popup/item_0/id = 0 +popup/item_1/text = "Erase" +popup/item_1/id = 1 + +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/Remove" to="." method="_on_Remove_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.gd b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd new file mode 100644 index 00000000..591f7ffc --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd @@ -0,0 +1,188 @@ +@tool +extends ResourceTablesDockEditor + +@onready var _value_label := $"HBoxContainer/HBoxContainer/NumberPanel/Label" +@onready var _button_grid := $"HBoxContainer/HBoxContainer/GridContainer" +@onready var _button_grid_small := $"HBoxContainer/HBoxContainer/GridContainerSmall" +@onready var _sequence_gen_inputs := $"HBoxContainer/CustomX2/HBoxContainer" +@onready var _custom_value_edit := $"HBoxContainer/CustomX/Box/LineEdit" + +var _stored_value = 0 +var _stored_value_is_int := false + +var _mouse_drag_increment := 0.0 +var _mouse_down := false + +var _resize_height_small := 0.0 +var _resize_expanded := true + + +func _ready(): + super._ready() + _button_grid.get_child(0).pressed.connect(_increment_values.bind(+0.1)) + _button_grid.get_child(1).pressed.connect(_increment_values.bind(+1)) + _button_grid.get_child(2).pressed.connect(_increment_values.bind(+10)) + _button_grid.get_child(3).pressed.connect(_increment_values.bind(+100)) + _button_grid.get_child(4).pressed.connect(_increment_values_custom.bind(true, false)) + _button_grid.get_child(5).pressed.connect(_increment_values_custom.bind(true, true)) + + _button_grid.get_child(6).pressed.connect(_increment_values.bind(-0.1)) + _button_grid.get_child(7).pressed.connect(_increment_values.bind(-1)) + _button_grid.get_child(8).pressed.connect(_increment_values.bind(-10)) + _button_grid.get_child(9).pressed.connect(_increment_values.bind(-100)) + _button_grid.get_child(10).pressed.connect(_increment_values_custom.bind(false, false)) + _button_grid.get_child(11).pressed.connect(_increment_values_custom.bind(false, true)) + + _button_grid_small.get_child(1).pressed.connect(_increment_values_custom.bind(false, true)) + _button_grid_small.get_child(2).pressed.connect(_increment_values_custom.bind(false, false)) + _button_grid_small.get_child(3).pressed.connect(_increment_values.bind(-1)) + _button_grid_small.get_child(4).pressed.connect(_increment_values.bind(+1)) + _button_grid_small.get_child(5).pressed.connect(_increment_values_custom.bind(true, false)) + _button_grid_small.get_child(6).pressed.connect(_increment_values_custom.bind(true, true)) + + _resize_height_small = get_child(1).get_minimum_size().y + + +func try_edit_value(value, type, property_hint) -> bool: + if type != TYPE_FLOAT and type != TYPE_INT: + return false + + _stored_value = value + _value_label.text = str(value) + + _stored_value_is_int = type != TYPE_FLOAT + _button_grid.columns = 5 if _stored_value_is_int else 6 + _button_grid.get_child(0).visible = !_stored_value_is_int + _button_grid.get_child(6).visible = !_stored_value_is_int + + return true + + +func resize_drag(to_height : float): + var expanded : bool = to_height >= _resize_height_small + if _resize_expanded == expanded: + return + + _resize_expanded = expanded + _button_grid.visible = expanded + _button_grid_small.visible = !expanded + $"HBoxContainer/CustomX2/HBoxContainer/Label2".visible = !expanded + $"HBoxContainer/CustomX2/HBoxContainer3".visible = expanded + $"HBoxContainer/HBoxContainer/NumberPanel".visible = expanded + $"HBoxContainer/CustomX2/HBoxContainer2".visible = expanded + $"HBoxContainer/CustomX2/HBoxContainer/Box".visible = !expanded + $"HBoxContainer/CustomX/Label".visible = expanded + + +func _increment_values(by : float): + var cell_values : Array = sheet.get_edited_cells_values() + if _stored_value_is_int: + _stored_value += int(by) + for i in cell_values.size(): + cell_values[i] += int(by) + + else: + _stored_value += by + for i in cell_values.size(): + cell_values[i] += by + + sheet.set_edited_cells_values(cell_values) + _value_label.text = str(_stored_value) + + +func _increment_values_custom(positive : bool, multiplier : bool): + var value := float(_custom_value_edit.text) + if !multiplier: + _increment_values(value if positive else -value) + + else: + if !positive: value = 1 / value + var cell_values : Array = sheet.get_edited_cells_values() + _stored_value *= value + for i in cell_values.size(): + cell_values[i] *= value + if _stored_value_is_int: + cell_values[i] = int(cell_values[i]) + + sheet.set_edited_cells_values(cell_values) + _value_label.text = str(_stored_value) + + +func _on_NumberPanel_gui_input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if event.pressed: + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + _mouse_drag_increment = 0.0 + _mouse_down = true + + else: + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + if _mouse_down: + Input.warp_mouse(_value_label.global_position + _value_label.size * 0.5) + + _increment_values(_mouse_drag_increment) + _mouse_down = false + + if _mouse_down and event is InputEventMouseMotion: + if _stored_value_is_int: + _mouse_drag_increment += event.relative.x * 0.25 + _value_label.text = str(_stored_value + int(_mouse_drag_increment)) + + else: + _mouse_drag_increment += event.relative.x * 0.01 + _value_label.text = str(_stored_value + _mouse_drag_increment) + + +func _on_SequenceFill_pressed(add : bool = false): + sheet.set_edited_cells_values(_fill_sequence(sheet.get_edited_cells_values(), add)) + + +func _fill_sequence(arr : Array, add : bool = false) -> Array: + if !_sequence_gen_inputs.get_node("Start").text.is_valid_float(): + return arr + + var start := float(_sequence_gen_inputs.get_child(0).text) + var end = null + var step = null + + if _sequence_gen_inputs.get_node("Step").text.is_valid_float(): + step = float(_sequence_gen_inputs.get_node("Step").text) + + if _sequence_gen_inputs.get_node("End").text.is_valid_float(): + end = float(_sequence_gen_inputs.get_node("End").text) + + if end == null: + end = INF if step == null or step >= 0 else -INF + + var end_is_higher = end > start + if step == null: + if end == null or end == INF or end == -INF: + step = 0.0 + + else: + step = (end - start) / arr.size() + + if _stored_value_is_int: + if start != null: + start = int(start) + + if step != null: + step = int(step) + + if end != INF and end != -INF: + end = int(end) + + + var cur = start + if !add: + for i in arr.size(): + arr[i] = 0 + + # The range() global function can also be used, but does not work with floats. + for i in arr.size(): + arr[i] = arr[i] + cur + cur += step + if (end_is_higher and cur >= end) or (!end_is_higher and cur <= end): + cur += (start - end) + + return arr diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid new file mode 100644 index 00000000..85eb8a5e --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid @@ -0,0 +1 @@ +uid://c6421qorx0nf diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn new file mode 100644 index 00000000..86eea132 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn @@ -0,0 +1,265 @@ +[gd_scene load_steps=2 format=3 uid="uid://gtbf7b0wptv"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_number.gd" id="1"] + +[node name="EditNumber" type="VBoxContainer"] +offset_right = 1141.0 +offset_bottom = 126.0 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Number" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="CustomX2" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer3" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer3"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Fill with Sequence" + +[node name="Label2" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer3"] +layout_mode = 2 +size_flags_vertical = 6 +tooltip_text = "Fill selected cells with a number sequence. Order is the same as the cells were selected. +- You must specify Start. +- If all values specified, selected cells will have a repeating sequence +of numbers from Start to End, with increment of Step, not including End. +- If both End AND Step are empty, cells are filled with Start. +- If End is omitted, selected cells will have values from Start to (Step x CellCount). +- If Step is omitted, selected cells will have values from Start to End inclusive, +step based on cell count." +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer"] +visible = false +layout_mode = 2 +text = "Sequence" + +[node name="Start" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Start (must not be blank)" +placeholder_text = "Start *" + +[node name="End" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "End" +placeholder_text = "End" + +[node name="Step" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "End" +placeholder_text = "Step" + +[node name="Box" type="HBoxContainer" parent="HBoxContainer/CustomX2/HBoxContainer"] +visible = false +layout_mode = 2 + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 + +[node name="SequenceFill3" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Set" +text = "=" + +[node name="SequenceFill4" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Add to each value" +text = "+" + +[node name="HBoxContainer2" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 + +[node name="SequenceFill" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Set" + +[node name="SequenceFill2" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Add" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="NumberPanel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_default_cursor_shape = 10 + +[node name="Panel" type="Panel" parent="HBoxContainer/HBoxContainer/NumberPanel"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/NumberPanel"] +layout_mode = 2 +text = "1" +clip_text = true + +[node name="GridContainer" type="GridContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +columns = 6 + +[node name="Button15" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+0.1" + +[node name="Button12" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+1" + +[node name="Button8" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+10" + +[node name="Button13" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+100" + +[node name="Button9" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+X" + +[node name="Button16" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "*X" + +[node name="Button14" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-0.1" + +[node name="Button11" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-1" + +[node name="Button7" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-10" + +[node name="Button10" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-100" + +[node name="Button4" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-X" + +[node name="Button5" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "/X" + +[node name="GridContainerSmall" type="HBoxContainer" parent="HBoxContainer/HBoxContainer"] +visible = false +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +text = "Value" + +[node name="Button1" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "/X" + +[node name="Button2" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "-X" + +[node name="Button3" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "-1" + +[node name="Button4" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "+1" + +[node name="Button5" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "+X" + +[node name="Button6" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "*X" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="CustomX" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Custom Value" +horizontal_alignment = 1 + +[node name="Box" type="HBoxContainer" parent="HBoxContainer/CustomX"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX/Box"] +layout_mode = 2 +text = "X =" + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/CustomX/Box"] +custom_minimum_size = Vector2(96, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "1000" + +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer/Box/SequenceFill3" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer/Box/SequenceFill4" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer2/SequenceFill" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer2/SequenceFill2" to="." method="_on_SequenceFill_pressed" binds= [true]] +[connection signal="gui_input" from="HBoxContainer/HBoxContainer/NumberPanel" to="." method="_on_NumberPanel_gui_input"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd new file mode 100644 index 00000000..c163bbb6 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd @@ -0,0 +1,39 @@ +@tool +extends ResourceTablesDockEditor + +var _stored_value : Texture2D + + +func try_edit_value(value, type, _property_hint) -> bool: + if type != TYPE_OBJECT or !value is Texture: + return false + + _stored_value = value + $"HBoxContainer/TextureRect".texture = value + return true + + +func _on_Button_pressed(): + var h_count : int = $"HBoxContainer/VBoxContainer/HBoxContainer/LineEdit".text.to_int() + var v_count : int = $"HBoxContainer/VBoxContainer/HBoxContainer/LineEdit2".text.to_int() + # No, Scene Unique Names can not be used in-editor (last time i checked) + + var folder_name := _stored_value.resource_path.get_basename() + DirAccess.make_dir_recursive_absolute(folder_name) + + var tex_size := _stored_value.get_size() + var tile_size := Vector2(tex_size.x / h_count, tex_size.y / v_count) + var tile_array := [] + for j in v_count: + for i in h_count: + var tile := AtlasTexture.new() + tile.region = Rect2(tile_size * Vector2(i, j), tile_size) + tile.atlas = _stored_value + tile_array.append(tile) + tile.take_over_path(folder_name + "/" + folder_name.get_file() + "_" + str(j * h_count + i + 1) + ".tres") + ResourceSaver.save(tile) + + tile_array.resize(sheet.get_edited_cells_values().size()) + sheet.set_edited_cells_values(tile_array) + sheet.editor_plugin.get_editor_interface().get_resource_filesystem().scan() + diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid new file mode 100644 index 00000000..125c8340 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid @@ -0,0 +1 @@ +uid://12yut6fr2d8y diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn new file mode 100644 index 00000000..fc2f411f --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=3 format=3 uid="uid://rww3gpl052bn"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_texture.gd" id="1"] + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_h3mns"] + +[node name="EditTexture" type="VBoxContainer"] +anchors_preset = -1 +anchor_right = 1.0 +anchor_bottom = 0.25463 +offset_bottom = 126.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") +metadata/_edit_use_anchors_ = true + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Texture" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="Control2" type="Control" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +texture = SubResource("PlaceholderTexture2D_h3mns") +expand_mode = 1 +stretch_mode = 5 + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +auto_translate = false + +[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +text = "Atlas Chopper" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "H Count" + +[node name="LineEdit2" type="LineEdit" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "V Count" + +[node name="Button" type="Button" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 +text = "Chop chop chop!!!" + +[node name="Control" type="Control" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[connection signal="pressed" from="HBoxContainer/VBoxContainer/Button" to="." method="_on_Button_pressed"] diff --git a/example/Items/item_icons/items.png b/example/Items/item_icons/items.png new file mode 100644 index 00000000..91616bd2 --- /dev/null +++ b/example/Items/item_icons/items.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c5a2ad52977372e020e6d4aab0fe5d90c509b9e1fe59d4871012402997db3a0 +size 2918 diff --git a/example/Items/item_icons/items.png.import b/example/Items/item_icons/items.png.import new file mode 100644 index 00000000..d94184ab --- /dev/null +++ b/example/Items/item_icons/items.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwi4ioxeauoc4" +path="res://.godot/imported/items.png-d10b6b2feac7b3334582afee422be338.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://example/Items/item_icons/items.png" +dest_files=["res://.godot/imported/items.png-d10b6b2feac7b3334582afee422be338.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/example/Items/item_type.gd b/example/Items/item_type.gd new file mode 100644 index 00000000..c436d633 --- /dev/null +++ b/example/Items/item_type.gd @@ -0,0 +1,32 @@ +extends Resource + +enum SlotType { + SMALL, + LARGE, + EQUIPMENT, + QUEST, + POTION, + AMMO, + CURRENCY, + FUEL, + CRAFTING, + E_MAINHAND, + E_OFFHAND, + E_HELM, + E_CHEST, + E_BELT, + E_HANDS, + E_FEET, + E_RING, + E_NECK, +} +@export var name := "" +@export_multiline var description := "" +@export var max_stack_count := 1 +@export var in_inventory_width := 1 +@export var in_inventory_height := 1 +@export var texture : Texture +@export var mesh : Mesh + +@export var slot_flags : SlotType = SlotType.SMALL +@export var default_properties : Dictionary diff --git a/example/Items/item_type.gd.uid b/example/Items/item_type.gd.uid new file mode 100644 index 00000000..96be92fb --- /dev/null +++ b/example/Items/item_type.gd.uid @@ -0,0 +1 @@ +uid://s68txxg6mqnj diff --git a/example/Items/items/arrows.tres b/example/Items/items/arrows.tres new file mode 100644 index 00000000..b5558a3c --- /dev/null +++ b/example/Items/items/arrows.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://c65l1w3756rlu"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_npnns"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_npnns") +region = Rect2(12, 24, 24, 12) + +[resource] +script = ExtResource("2") +name = "arrows" +description = "desc_arrows" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 5 +default_properties = {} diff --git a/example/Items/items/belt_1.tres b/example/Items/items/belt_1.tres new file mode 100644 index 00000000..f797bab8 --- /dev/null +++ b/example/Items/items/belt_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d2gb438d6vtlg"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_4rd1p"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_4rd1p") +region = Rect2(0, 156, 24, 12) + +[resource] +script = ExtResource("1") +name = "belt_1" +description = "desc_belt_1" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 13 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"dodgerate": 12.0 +} +} diff --git a/example/Items/items/belt_2.tres b/example/Items/items/belt_2.tres new file mode 100644 index 00000000..631da086 --- /dev/null +++ b/example/Items/items/belt_2.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://c158a1idjr28m"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_laq2t"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_laq2t") +region = Rect2(24, 156, 24, 12) + +[resource] +script = ExtResource("1") +name = "belt_2" +description = "desc_belt_2" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 13 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"health_regen": 2.0 +} +} diff --git a/example/Items/items/chestplate_1.tres b/example/Items/items/chestplate_1.tres new file mode 100644 index 00000000..c3c64954 --- /dev/null +++ b/example/Items/items/chestplate_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ubapirchpsp"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_cwgb2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_cwgb2") +region = Rect2(0, 120, 24, 36) + +[resource] +script = ExtResource("1") +name = "chestplate_1" +description = "desc_chestplate_1" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 12 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 24.0 +} +} diff --git a/example/Items/items/chestplate_2.tres b/example/Items/items/chestplate_2.tres new file mode 100644 index 00000000..516b0ab4 --- /dev/null +++ b/example/Items/items/chestplate_2.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://nquj8y70tdy1"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_fdlcg"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_fdlcg") +region = Rect2(24, 120, 24, 36) + +[resource] +script = ExtResource("1") +name = "chestplate_2" +description = "desc_chestplate_2" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 12 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 16.0, +"dodgerate": 16.0 +} +} diff --git a/example/Items/items/coin_gold.tres b/example/Items/items/coin_gold.tres new file mode 100644 index 00000000..b4d0ff8a --- /dev/null +++ b/example/Items/items/coin_gold.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cqbrojgnmjvil"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_lbcs7"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_lbcs7") +region = Rect2(0, 0, 12, 12) + +[resource] +script = ExtResource("2") +name = "coin_gold" +description = "desc_coin_gold" +max_stack_count = 100 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 6 +default_properties = {} diff --git a/example/Items/items/coin_purple.tres b/example/Items/items/coin_purple.tres new file mode 100644 index 00000000..624c2040 --- /dev/null +++ b/example/Items/items/coin_purple.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://4amkkv73m0lc"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_gphlp"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_gphlp") +region = Rect2(0, 12, 12, 12) + +[resource] +script = ExtResource("2") +name = "coin_purple" +description = "desc_coin_purple" +max_stack_count = 100 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 6 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/feather.tres b/example/Items/items/feather.tres new file mode 100644 index 00000000..29cd487b --- /dev/null +++ b/example/Items/items/feather.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://csj85mouew67r"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_vvaq3"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_vvaq3") +region = Rect2(84, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "feather" +description = "desc_feather" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/gem_blue.tres b/example/Items/items/gem_blue.tres new file mode 100644 index 00000000..77e330df --- /dev/null +++ b/example/Items/items/gem_blue.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ghiwkmadh0i"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_io53q"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_io53q") +region = Rect2(84, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "gem_blue" +description = "desc_gem_blue" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/head_helmet.tres b/example/Items/items/head_helmet.tres new file mode 100644 index 00000000..5e2e4703 --- /dev/null +++ b/example/Items/items/head_helmet.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dmgt12il41ul7"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_1ooxf"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_1ooxf") +region = Rect2(0, 168, 24, 24) + +[resource] +script = ExtResource("1") +name = "head_helmet" +description = "desc_head_helmet" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 11 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 8.0 +} +} diff --git a/example/Items/items/head_wizardhat.tres b/example/Items/items/head_wizardhat.tres new file mode 100644 index 00000000..b6911509 --- /dev/null +++ b/example/Items/items/head_wizardhat.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://bwtgji4rkgc5"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_6ygl4"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_6ygl4") +region = Rect2(24, 168, 24, 24) + +[resource] +script = ExtResource("1") +name = "head_wizardhat" +description = "desc_head_wizardhat" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 11 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"magic_regen": 2.0 +} +} diff --git a/example/Items/items/herb.tres b/example/Items/items/herb.tres new file mode 100644 index 00000000..c042731a --- /dev/null +++ b/example/Items/items/herb.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://v7imonnsq6xx"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_awqqy"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_awqqy") +region = Rect2(12, 36, 24, 12) + +[resource] +script = ExtResource("2") +name = "herb" +description = "desc_herb" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/leather.tres b/example/Items/items/leather.tres new file mode 100644 index 00000000..c2027315 --- /dev/null +++ b/example/Items/items/leather.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://okiwvbkwltf2"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_v5nv2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_v5nv2") +region = Rect2(60, 24, 24, 12) + +[resource] +script = ExtResource("2") +name = "leather" +description = "desc_leather" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/magic_crystal.tres b/example/Items/items/magic_crystal.tres new file mode 100644 index 00000000..d06faa71 --- /dev/null +++ b/example/Items/items/magic_crystal.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d4eo3up2esgao"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_l77qe"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_l77qe") +region = Rect2(0, 24, 12, 24) + +[resource] +script = ExtResource("2") +name = "magic_crystal" +description = "desc_magic_crystal" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/melee_battleaxe.tres b/example/Items/items/melee_battleaxe.tres new file mode 100644 index 00000000..9a1f21ba --- /dev/null +++ b/example/Items/items/melee_battleaxe.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://vi43b1o26w60"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_glg1x"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_glg1x") +region = Rect2(12, 72, 12, 48) + +[resource] +script = ExtResource("2") +name = "melee_battleaxe" +description = "desc_melee_battleaxe" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 4 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"weapon_damage": 8.0, +"weapon_speed": 0.8 +} +} diff --git a/example/Items/items/melee_sword.tres b/example/Items/items/melee_sword.tres new file mode 100644 index 00000000..f10f91dc --- /dev/null +++ b/example/Items/items/melee_sword.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cidvqmpxobgv7"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_qyy4c"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_qyy4c") +region = Rect2(0, 72, 12, 36) + +[resource] +script = ExtResource("2") +name = "melee_sword" +description = "desc_melee_sword" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"weapon_damage": 4.0, +"weapon_speed": 1.5 +} +} diff --git a/example/Items/items/metalscrap_copper.tres b/example/Items/items/metalscrap_copper.tres new file mode 100644 index 00000000..c2679267 --- /dev/null +++ b/example/Items/items/metalscrap_copper.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d2vm3srqwars"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_w6v7m"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_w6v7m") +region = Rect2(48, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_copper" +description = "desc_metalscrap_copper" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/metalscrap_gold.tres b/example/Items/items/metalscrap_gold.tres new file mode 100644 index 00000000..b20a5acf --- /dev/null +++ b/example/Items/items/metalscrap_gold.tres @@ -0,0 +1,24 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b45up1xg1qnlo"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_eoswi"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_eoswi") +region = Rect2(36, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_gold" +description = "desc_metalscrap_gold" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 10.0 +} +} diff --git a/example/Items/items/metalscrap_iron.tres b/example/Items/items/metalscrap_iron.tres new file mode 100644 index 00000000..5c4064f0 --- /dev/null +++ b/example/Items/items/metalscrap_iron.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dyb3w176j3sco"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_61lme"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_61lme") +region = Rect2(36, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_iron" +description = "desc_metalscrap_iron" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/metalscrap_wyvernite.tres b/example/Items/items/metalscrap_wyvernite.tres new file mode 100644 index 00000000..d7f76cd0 --- /dev/null +++ b/example/Items/items/metalscrap_wyvernite.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://desvy1h36yy1s"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_bon0y"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_bon0y") +region = Rect2(48, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_wyvernite" +description = "desc_metalscrap_wyvernite" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/potion_blue.tres b/example/Items/items/potion_blue.tres new file mode 100644 index 00000000..fc40f4f4 --- /dev/null +++ b/example/Items/items/potion_blue.tres @@ -0,0 +1,24 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b0l5g2tgwvm3b"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(36, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_blue" +description = "desc_potion_blue" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 5 +} +} diff --git a/example/Items/items/potion_purple.tres b/example/Items/items/potion_purple.tres new file mode 100644 index 00000000..f4170f60 --- /dev/null +++ b/example/Items/items/potion_purple.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cbrsfa22sudf5"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(24, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_purple" +description = "desc_potion_purple" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/potion_red.tres b/example/Items/items/potion_red.tres new file mode 100644 index 00000000..4ee5e9e6 --- /dev/null +++ b/example/Items/items/potion_red.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://crq178t8cp2g7"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(12, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_red" +description = "desc_potion_red" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/ring_1.tres b/example/Items/items/ring_1.tres new file mode 100644 index 00000000..552bd223 --- /dev/null +++ b/example/Items/items/ring_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d1sgj2djflire"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_7y5px"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_7y5px") +region = Rect2(0, 192, 12, 12) + +[resource] +script = ExtResource("1") +name = "ring_1" +description = "desc_ring_1" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 16 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"dodgerate": 8.0 +} +} diff --git a/example/Items/items/ring_2.tres b/example/Items/items/ring_2.tres new file mode 100644 index 00000000..38dfa417 --- /dev/null +++ b/example/Items/items/ring_2.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dwsqjeolbi2j6"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_a2wrg"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_a2wrg") +region = Rect2(12, 192, 12, 12) + +[resource] +script = ExtResource("1") +name = "ring_2" +description = "desc_ring_2" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 16 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"health": 8.0 +} +} diff --git a/example/Items/items/scroll_enchant.tres b/example/Items/items/scroll_enchant.tres new file mode 100644 index 00000000..e67fea9b --- /dev/null +++ b/example/Items/items/scroll_enchant.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://7vy4rqrqnt4q"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_oismr"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_oismr") +region = Rect2(96, 24, 12, 24) + +[resource] +script = ExtResource("2") +name = "scroll_enchant" +description = "desc_scroll_enchant" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 6 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/wand_purple.tres b/example/Items/items/wand_purple.tres new file mode 100644 index 00000000..f711f79e --- /dev/null +++ b/example/Items/items/wand_purple.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ckgvaqimbvnv8"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_8lhvp"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_8lhvp") +region = Rect2(0, 48, 12, 24) + +[resource] +script = ExtResource("2") +name = "wand_purple" +description = "desc_wand_purple" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"magic": 16.0 +} +} diff --git a/example/Items/items/wand_red.tres b/example/Items/items/wand_red.tres new file mode 100644 index 00000000..8274f25d --- /dev/null +++ b/example/Items/items/wand_red.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://napa4vmvmphs"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_cihvk"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_cihvk") +region = Rect2(12, 48, 12, 24) + +[resource] +script = ExtResource("2") +name = "wand_red" +description = "desc_wand_red" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"spell_damage": 8.0 +} +} diff --git a/example/Items/items/wood.tres b/example/Items/items/wood.tres new file mode 100644 index 00000000..423b4789 --- /dev/null +++ b/example/Items/items/wood.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://uge4rk0vtwxs"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_7ia04"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_7ia04") +region = Rect2(60, 36, 24, 12) + +[resource] +script = ExtResource("2") +name = "wood" +description = "desc_wood" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Random Upgrades/icons/all_icons.png b/example/Random Upgrades/icons/all_icons.png new file mode 100644 index 00000000..bced5786 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c1c5e80d345574e1ec217408add53066743b7c145261cfaa0efee6840d8cdab +size 2072 diff --git a/example/Random Upgrades/icons/all_icons.png.import b/example/Random Upgrades/icons/all_icons.png.import new file mode 100644 index 00000000..40d9e972 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7e3wp7i33ye5" +path="res://.godot/imported/all_icons.png-28909f8bd099d79f5d095eb93a9167e6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://example/Random Upgrades/icons/all_icons.png" +dest_files=["res://.godot/imported/all_icons.png-28909f8bd099d79f5d095eb93a9167e6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/example/Random Upgrades/icons/all_icons/all_icons_1.tres b/example/Random Upgrades/icons/all_icons/all_icons_1.tres new file mode 100644 index 00000000..d3a38a3f --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_1.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://c3bx6kf7frbwk"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(0, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_10.tres b/example/Random Upgrades/icons/all_icons/all_icons_10.tres new file mode 100644 index 00000000..4131f8c5 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_10.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cak6lra5ej68c"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_6pmrx"] + +[resource] +atlas = ExtResource("1_6pmrx") +region = Rect2(64, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_11.tres b/example/Random Upgrades/icons/all_icons/all_icons_11.tres new file mode 100644 index 00000000..5ae6a284 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_11.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dkc8d2p0xbl1n"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_lk0lg"] + +[resource] +atlas = ExtResource("1_lk0lg") +region = Rect2(128, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_12.tres b/example/Random Upgrades/icons/all_icons/all_icons_12.tres new file mode 100644 index 00000000..13979090 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_12.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://ciiykhulvckp7"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_fd56b"] + +[resource] +atlas = ExtResource("1_fd56b") +region = Rect2(192, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_13.tres b/example/Random Upgrades/icons/all_icons/all_icons_13.tres new file mode 100644 index 00000000..cbabc984 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_13.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dki1d3uksoyfj"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_ds6ve"] + +[resource] +atlas = ExtResource("1_ds6ve") +region = Rect2(0, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_14.tres b/example/Random Upgrades/icons/all_icons/all_icons_14.tres new file mode 100644 index 00000000..303ee647 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_14.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cpenn4qsfhx28"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_icesd"] + +[resource] +atlas = ExtResource("1_icesd") +region = Rect2(64, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_15.tres b/example/Random Upgrades/icons/all_icons/all_icons_15.tres new file mode 100644 index 00000000..3de416c2 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_15.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cm6cb8uou75x0"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_mlqxi"] + +[resource] +atlas = ExtResource("1_mlqxi") +region = Rect2(128, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_16.tres b/example/Random Upgrades/icons/all_icons/all_icons_16.tres new file mode 100644 index 00000000..fe9075e5 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_16.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://0c7ngrkwn42u"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_jk82p"] + +[resource] +atlas = ExtResource("1_jk82p") +region = Rect2(192, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_2.tres b/example/Random Upgrades/icons/all_icons/all_icons_2.tres new file mode 100644 index 00000000..405fe322 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_2.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dfpwu4ra3fxgx"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(64, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_3.tres b/example/Random Upgrades/icons/all_icons/all_icons_3.tres new file mode 100644 index 00000000..8bc87b01 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_3.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://d38giyxvkhl6g"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(128, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_4.tres b/example/Random Upgrades/icons/all_icons/all_icons_4.tres new file mode 100644 index 00000000..517e84f2 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_4.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cluvoehgeqmcu"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(192, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_5.tres b/example/Random Upgrades/icons/all_icons/all_icons_5.tres new file mode 100644 index 00000000..8363f7ba --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_5.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://djjpa8lluue1g"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(0, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_6.tres b/example/Random Upgrades/icons/all_icons/all_icons_6.tres new file mode 100644 index 00000000..df97e796 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_6.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://butx3l1jdcgcc"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_em1jn"] + +[resource] +atlas = ExtResource("1_em1jn") +region = Rect2(64, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_7.tres b/example/Random Upgrades/icons/all_icons/all_icons_7.tres new file mode 100644 index 00000000..bfe8fdbb --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_7.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dfhgifwrrigrw"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_bpiay"] + +[resource] +atlas = ExtResource("1_bpiay") +region = Rect2(128, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_8.tres b/example/Random Upgrades/icons/all_icons/all_icons_8.tres new file mode 100644 index 00000000..640155a1 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_8.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dacww8ptt8uyo"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_mbxiu"] + +[resource] +atlas = ExtResource("1_mbxiu") +region = Rect2(192, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_9.tres b/example/Random Upgrades/icons/all_icons/all_icons_9.tres new file mode 100644 index 00000000..0c973417 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_9.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dbbgxcs806sy8"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_bw3gq"] + +[resource] +atlas = ExtResource("1_bw3gq") +region = Rect2(0, 128, 64, 64) diff --git a/example/Random Upgrades/new scene.tscn b/example/Random Upgrades/new scene.tscn new file mode 100644 index 00000000..cf94da51 --- /dev/null +++ b/example/Random Upgrades/new scene.tscn @@ -0,0 +1,31 @@ +[gd_scene format=3 uid="uid://b4cix5ebtpdbf"] + +[node name="Node2D" type="Node2D"] + +[node name="ColorRect" type="ColorRect" parent="."] +offset_left = 363.0 +offset_top = 83.0 +offset_right = 718.0 +offset_bottom = 632.0 +color = Color(0, 1, 0.0156863, 1) + +[node name="ColorRect2" type="ColorRect" parent="."] +offset_left = 833.0 +offset_top = 304.0 +offset_right = 1095.0 +offset_bottom = 653.0 +color = Color(0, 0.905882, 1, 1) + +[node name="ColorRect3" type="ColorRect" parent="."] +offset_left = 553.0 +offset_top = 491.0 +offset_right = 929.0 +offset_bottom = 770.0 +color = Color(0, 0.0156863, 1, 1) + +[node name="ColorRect4" type="ColorRect" parent="."] +offset_left = 746.0 +offset_top = 397.0 +offset_right = 1077.0 +offset_bottom = 632.0 +color = Color(0.686275, 0, 1, 1) diff --git a/example/Random Upgrades/upgrade_data.gd b/example/Random Upgrades/upgrade_data.gd new file mode 100644 index 00000000..915857c0 --- /dev/null +++ b/example/Random Upgrades/upgrade_data.gd @@ -0,0 +1,30 @@ +@tool +class_name UpgradeData +extends Resource + +enum Attributes { + Strength = 0, + Magic, + Endurance, + Agility, + Luck, + Mastery = 128, +} + +@export var color1 := Color.WHITE +@export var max_duplicates := 0 +@export var tags : Array[String] +@export_enum("Weapon", "Passive", "Mastery") var type := 0 +@export var attributes : Array[Attributes] +@export var icon : Texture +@export var custom_scene : PackedScene +@export var prerequisites : Array[UpgradeData] +@export var color2 := Color.WHITE +@export var base_weight := 10.0 +@export var is_notable := false +@export_multiline var multiplier_per_tag := "" +@export_multiline var multiplier_if_tag_present := "" +@export_multiline var multiplier_if_tag_not_present := "" +@export_multiline var max_tags_present := "" +@export var list_item_delimeter := " " +@export var list_row_delimeter := ";" diff --git a/example/Random Upgrades/upgrade_data.gd.uid b/example/Random Upgrades/upgrade_data.gd.uid new file mode 100644 index 00000000..514b6fa0 --- /dev/null +++ b/example/Random Upgrades/upgrade_data.gd.uid @@ -0,0 +1 @@ +uid://ms7o8ggbekuv diff --git a/example/Random Upgrades/upgrade_data_weapon.gd b/example/Random Upgrades/upgrade_data_weapon.gd new file mode 100644 index 00000000..51b6420a --- /dev/null +++ b/example/Random Upgrades/upgrade_data_weapon.gd @@ -0,0 +1,16 @@ +@tool +extends "res://example/Random Upgrades/upgrade_data.gd" + +@export var weapon_damage := 0.0 +@export var weapon_cooldown := 0.0 +@export var weapon_dps := 0.0: + set(v): + weapon_damage = v * weapon_cooldown + get: + return weapon_damage / weapon_cooldown if weapon_cooldown != 0.0 else 0.0 + + +func _validate_property(property: Dictionary) -> void: + if property.name == &"weapon_dps": + # Show in inspector, but don't save into resource file. + property.usage = PROPERTY_USAGE_EDITOR diff --git a/example/Random Upgrades/upgrade_data_weapon.gd.uid b/example/Random Upgrades/upgrade_data_weapon.gd.uid new file mode 100644 index 00000000..8a19bdea --- /dev/null +++ b/example/Random Upgrades/upgrade_data_weapon.gd.uid @@ -0,0 +1 @@ +uid://b5be6nrjdxaxh diff --git a/example/Random Upgrades/upgrades/elemental.tres b/example/Random Upgrades/upgrades/elemental.tres new file mode 100644 index 00000000..b0a6db61 --- /dev/null +++ b/example/Random Upgrades/upgrades/elemental.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://8m6y2o6tbmpn"] + +[ext_resource type="Texture2D" uid="uid://butx3l1jdcgcc" path="res://example/Random Upgrades/icons/all_icons/all_icons_6.tres" id="1_utkae"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Elemental Damage" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["elemental"]) +type = 1 +attributes = Array[int]([1]) +icon = ExtResource("1_utkae") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.964706, 0.298039, 0.298039, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "elemental 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/health.tres b/example/Random Upgrades/upgrades/health.tres new file mode 100644 index 00000000..3cce2ba8 --- /dev/null +++ b/example/Random Upgrades/upgrades/health.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://dys7hpijn82t0"] + +[ext_resource type="Texture2D" uid="uid://c3bx6kf7frbwk" path="res://example/Random Upgrades/icons/all_icons/all_icons_1.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Health" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["health", "melee"]) +type = 1 +attributes = Array[int]([2]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.129412, 1, 0.243137, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 1.5 melee 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/mastery_magic.tres b/example/Random Upgrades/upgrades/mastery_magic.tres new file mode 100644 index 00000000..e975c5ed --- /dev/null +++ b/example/Random Upgrades/upgrades/mastery_magic.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=7 format=3 uid="uid://2totlbwc40e8"] + +[ext_resource type="Texture2D" uid="uid://djjpa8lluue1g" path="res://example/Random Upgrades/icons/all_icons/all_icons_5.tres" id="1_ardng"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://rjxr4qtfc6qd" path="res://example/Random Upgrades/upgrades/weapons/weapon_fireball.tres" id="2_485ad"] +[ext_resource type="Resource" uid="uid://djqq1lqaevth5" path="res://example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres" id="3_xnxxn"] +[ext_resource type="Resource" uid="uid://b0kdw067vtgvn" path="res://example/Random Upgrades/upgrades/weapons/weapon_lightning.tres" id="4_kn0kg"] +[ext_resource type="Resource" uid="uid://8m6y2o6tbmpn" path="res://example/Random Upgrades/upgrades/elemental.tres" id="6_shqeu"] + +[resource] +resource_name = "Mastery: Magic" +script = ExtResource("2") +color1 = Color(1, 0.847059, 0.160784, 1) +max_duplicates = 9 +tags = Array[String](["magic", "mastery"]) +type = 2 +attributes = Array[int]([1, 1, 4, 128]) +icon = ExtResource("1_ardng") +prerequisites = Array[ExtResource("2")]([ExtResource("2_485ad"), ExtResource("3_xnxxn"), ExtResource("4_kn0kg"), ExtResource("6_shqeu")]) +color2 = Color(0.407843, 0.192157, 0.827451, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "magic 1.2" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "magic 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/mastery_strength.tres b/example/Random Upgrades/upgrades/mastery_strength.tres new file mode 100644 index 00000000..8e8ec832 --- /dev/null +++ b/example/Random Upgrades/upgrades/mastery_strength.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=7 format=3 uid="uid://d1suh8iai43st"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1_442ey"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://cux4x0qopwiqk" path="res://example/Random Upgrades/upgrades/weapons/weapon_dagger.tres" id="2_kb33p"] +[ext_resource type="Resource" uid="uid://b78jqcpgef2ud" path="res://example/Random Upgrades/upgrades/weapons/weapon_axe.tres" id="3_tt25f"] +[ext_resource type="Resource" uid="uid://xl0yx8uq6bfp" path="res://example/Random Upgrades/upgrades/weapons/weapon_spear.tres" id="4_kpsn8"] +[ext_resource type="Resource" uid="uid://c6hsg3j74vm56" path="res://example/Random Upgrades/upgrades/up_strength.tres" id="6_gpjyk"] + +[resource] +resource_name = "Mastery: Strength" +script = ExtResource("2") +color1 = Color(1, 0.847059, 0.160784, 1) +max_duplicates = 9 +tags = Array[String](["strength", "mastery"]) +type = 2 +attributes = Array[int]([0, 0, 4, 128]) +icon = ExtResource("1_442ey") +prerequisites = Array[ExtResource("2")]([ExtResource("2_kb33p"), ExtResource("3_tt25f"), ExtResource("4_kpsn8"), ExtResource("6_gpjyk")]) +color2 = Color(0.992157, 0.941176, 0.2, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "strength 1.2" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_aoe.tres b/example/Random Upgrades/upgrades/up_aoe.tres new file mode 100644 index 00000000..85d2d6cd --- /dev/null +++ b/example/Random Upgrades/upgrades/up_aoe.tres @@ -0,0 +1,26 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=4 format=3 uid="uid://2y7extlq12d5"] + +[ext_resource type="Texture2D" uid="uid://butx3l1jdcgcc" path="res://example/Random Upgrades/icons/all_icons/all_icons_6.tres" id="1_prpsx"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://8m6y2o6tbmpn" path="res://example/Random Upgrades/upgrades/elemental.tres" id="3_xu25t"] + +[resource] +resource_name = "Upgrade: Area of Effect" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 4 +tags = Array[String](["aoe"]) +type = 1 +attributes = Array[int]([3]) +icon = ExtResource("1_prpsx") +prerequisites = Array[ExtResource("2")]([ExtResource("3_xu25t")]) +color2 = Color(0.964706, 0.298039, 0.298039, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "aoe 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_magic.tres b/example/Random Upgrades/upgrades/up_magic.tres new file mode 100644 index 00000000..aabe7348 --- /dev/null +++ b/example/Random Upgrades/upgrades/up_magic.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://ce2kulhm7amkp"] + +[ext_resource type="Texture2D" uid="uid://djjpa8lluue1g" path="res://example/Random Upgrades/icons/all_icons/all_icons_5.tres" id="1_we1lq"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Magic" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["magic"]) +type = 1 +attributes = Array[int]([1]) +icon = ExtResource("1_we1lq") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.188235, 0.45098, 0.901961, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "magic 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_movement_speed.tres b/example/Random Upgrades/upgrades/up_movement_speed.tres new file mode 100644 index 00000000..a1d61878 --- /dev/null +++ b/example/Random Upgrades/upgrades/up_movement_speed.tres @@ -0,0 +1,26 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=4 format=3 uid="uid://bn0r0bvk8fylt"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1_fy5ui"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_gfl7s"] +[ext_resource type="Resource" uid="uid://c6hsg3j74vm56" path="res://example/Random Upgrades/upgrades/up_strength.tres" id="3_5v8xn"] + +[resource] +resource_name = "Upgrade: Strength" +script = ExtResource("2_gfl7s") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["strength"]) +type = 1 +attributes = Array[int]([0]) +icon = ExtResource("1_fy5ui") +prerequisites = Array[ExtResource("2_gfl7s")]([ExtResource("3_5v8xn")]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_strength.tres b/example/Random Upgrades/upgrades/up_strength.tres new file mode 100644 index 00000000..85c443cf --- /dev/null +++ b/example/Random Upgrades/upgrades/up_strength.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://c6hsg3j74vm56"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Strength" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["strength"]) +type = 1 +attributes = Array[int]([0]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_axe.tres b/example/Random Upgrades/upgrades/weapons/weapon_axe.tres new file mode 100644 index 00000000..5ba6e464 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_axe.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b78jqcpgef2ud"] + +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_1nxl6"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_646el"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_w4j2j"] + +[resource] +resource_name = "Weapon: Axe" +script = ExtResource("1_646el") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["strength", "melee", "weapon"]) +type = 0 +attributes = Array[int]([0, 2]) +icon = ExtResource("1_1nxl6") +prerequisites = Array[ExtResource("2_w4j2j")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres b/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres new file mode 100644 index 00000000..b4619a87 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://djqq1lqaevth5"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_pewbv"] +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_sr0ui"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_yatbe"] + +[resource] +resource_name = "Weapon: Blizzard" +script = ExtResource("1_pewbv") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "elemental"]) +type = 0 +attributes = Array[int]([1, 2]) +icon = ExtResource("1_sr0ui") +prerequisites = Array[ExtResource("2_yatbe")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres b/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres new file mode 100644 index 00000000..8c3bf36f --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres @@ -0,0 +1,30 @@ +[gd_resource type="Resource" load_steps=5 format=3 uid="uid://60buw33oe30f"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_02in4"] +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_6lnsr"] +[ext_resource type="PackedScene" uid="uid://b4cix5ebtpdbf" path="res://example/Random Upgrades/new scene.tscn" id="1_xh6ym"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="3_o4xc8"] + +[resource] +resource_name = "Weapon: Chaos Blast" +script = ExtResource("1_02in4") +weapon_damage = 12.0 +weapon_cooldown = 8.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "projectile", "legendary"]) +type = 0 +attributes = Array[int]([1, 1, 1, 3]) +icon = ExtResource("1_6lnsr") +custom_scene = ExtResource("1_xh6ym") +prerequisites = Array[ExtResource("3_o4xc8")]([]) +color2 = Color(0.407843, 0.192157, 0.827451, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres b/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres new file mode 100644 index 00000000..fa5abb34 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cux4x0qopwiqk"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_birsa"] +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_sx5xe"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_po4ym"] + +[resource] +resource_name = "Weapon: Daggers" +script = ExtResource("1_birsa") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "projectile"]) +type = 0 +attributes = Array[int]([0, 3]) +icon = ExtResource("1_sx5xe") +prerequisites = Array[ExtResource("2_po4ym")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres b/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres new file mode 100644 index 00000000..5f83bfa1 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://rjxr4qtfc6qd"] + +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_5uqil"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_mehe7"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_1ne1s"] + +[resource] +resource_name = "Weapon: Fireball" +script = ExtResource("1_mehe7") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "projectile", "elemental"]) +type = 0 +attributes = Array[int]([1, 2]) +icon = ExtResource("1_5uqil") +prerequisites = Array[ExtResource("2_1ne1s")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres b/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres new file mode 100644 index 00000000..2d541970 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres @@ -0,0 +1,30 @@ +[gd_resource type="Resource" load_steps=5 format=3 uid="uid://c1mrcevxrm5kv"] + +[ext_resource type="PackedScene" uid="uid://b4cix5ebtpdbf" path="res://example/Random Upgrades/new scene.tscn" id="1_gppwv"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_ldwst"] +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_lir0x"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="3_8w1k7"] + +[resource] +resource_name = "Weapon: Giga Sword" +script = ExtResource("1_ldwst") +weapon_damage = 12.0 +weapon_cooldown = 8.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "melee", "legendary"]) +type = 0 +attributes = Array[int]([0, 0, 0, 2]) +icon = ExtResource("1_lir0x") +custom_scene = ExtResource("1_gppwv") +prerequisites = Array[ExtResource("3_8w1k7")]([]) +color2 = Color(0.992157, 0.941176, 0.2, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres b/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres new file mode 100644 index 00000000..0c6a534a --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b0kdw067vtgvn"] + +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_jsyxk"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_yjf8q"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_dskpw"] + +[resource] +resource_name = "Weapon: Lightning" +script = ExtResource("1_yjf8q") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "elemental"]) +type = 0 +attributes = Array[int]([1, 3]) +icon = ExtResource("1_jsyxk") +prerequisites = Array[ExtResource("2_dskpw")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_spear.tres b/example/Random Upgrades/upgrades/weapons/weapon_spear.tres new file mode 100644 index 00000000..a77ba271 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_spear.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://xl0yx8uq6bfp"] + +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_rw2g6"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_sqli1"] + +[resource] +resource_name = "Weapon: Spear" +script = ExtResource("1_rw2g6") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "melee"]) +type = 0 +attributes = Array[int]([0, 3]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2_sqli1")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades_csv/upgrades.csv b/example/Random Upgrades/upgrades_csv/upgrades.csv new file mode 100644 index 00000000..e5b477ad --- /dev/null +++ b/example/Random Upgrades/upgrades_csv/upgrades.csv @@ -0,0 +1,33 @@ +resource_path;resource_name;color1;max_duplicates;tags;type;attributes;icon;custom_scene;prerequisites;color2;base_weight;is_notable;multiplier_per_tag;multiplier_if_tag_present;multiplier_if_tag_not_present;max_tags_present;list_item_delimeter;list_row_delimeter;weapon_damage;weapon_cooldown;weapon_dps +res://example/Random Upgrades/upgrades/elemental.tres;Upgrade: Elemental Damage;ffffffff;9;"[""elemental""]";Passive;[1];res://example/Random Upgrades/icons/all_icons/all_icons_6.tres;;[];f64c4cff;10;No;;;elemental 0;; ;" +";;; +res://example/Random Upgrades/upgrades/health.tres;Upgrade: Health;ffffffff;9;"[""health"", ""melee""]";Passive;[2];res://example/Random Upgrades/icons/all_icons/all_icons_1.tres;;[];21ff3eff;10;No;strength 1.5 melee 2.0;;;; ;" +";;; +res://example/Random Upgrades/upgrades/mastery_magic.tres;Mastery: Magic;ffd829ff;9;"[""magic"", ""mastery""]";Mastery;[1, 1, 4, 128];res://example/Random Upgrades/icons/all_icons/all_icons_5.tres;;[, , , ];6831d3ff;1;Yes;magic 1.2;;magic 0;; ;" +";;; +res://example/Random Upgrades/upgrades/mastery_strength.tres;Mastery: Strength;ffd829ff;9;"[""strength"", ""mastery""]";Mastery;[0, 0, 4, 128];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[, , , ];fdf033ff;1;Yes;strength 1.2;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_aoe.tres;Upgrade: Area of Effect;ffffffff;4;"[""aoe""]";Passive;[3];res://example/Random Upgrades/icons/all_icons/all_icons_6.tres;;[];f64c4cff;10;No;;;aoe 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_magic.tres;Upgrade: Magic;ffffffff;9;"[""magic""]";Passive;[1];res://example/Random Upgrades/icons/all_icons/all_icons_5.tres;;[];3073e6ff;10;No;;;magic 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_movement_speed.tres;Upgrade: Strength;ffffffff;9;"[""strength""]";Passive;[0];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[];fa9534ff;10;No;;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_strength.tres;Upgrade: Strength;ffffffff;9;"[""strength""]";Passive;[0];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[];fa9534ff;10;No;;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/weapons/weapon_axe.tres;Weapon: Axe;a2c2ffff;1;"[""strength"", ""melee"", ""weapon""]";Weapon;[0, 2];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres;Weapon: Blizzard;a2c2ffff;1;"[""weapon"", ""magic"", ""elemental""]";Weapon;[1, 2];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres;Weapon: Chaos Blast;a2c2ffff;1;"[""weapon"", ""magic"", ""projectile"", ""legendary""]";Weapon;[1, 1, 1, 3];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;res://example/Random Upgrades/new scene.tscn;[];6831d3ff;1;Yes;magic 2.0;;;weapon 4; ;" +";12;8;1.5 +res://example/Random Upgrades/upgrades/weapons/weapon_dagger.tres;Weapon: Daggers;a2c2ffff;1;"[""weapon"", ""strength"", ""projectile""]";Weapon;[0, 3];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_fireball.tres;Weapon: Fireball;a2c2ffff;1;"[""weapon"", ""magic"", ""projectile"", ""elemental""]";Weapon;[1, 2];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres;Weapon: Giga Sword;a2c2ffff;1;"[""weapon"", ""strength"", ""melee"", ""legendary""]";Weapon;[0, 0, 0, 2];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;res://example/Random Upgrades/new scene.tscn;[];fdf033ff;1;Yes;strength 2.0;;;weapon 4; ;" +";12;8;1.5 +res://example/Random Upgrades/upgrades/weapons/weapon_lightning.tres;Weapon: Lightning;a2c2ffff;1;"[""weapon"", ""magic"", ""elemental""]";Weapon;[1, 3];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_spear.tres;Weapon: Spear;a2c2ffff;1;"[""weapon"", ""strength"", ""melee""]";Weapon;[0, 3];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 diff --git a/example/Random Upgrades/upgrades_csv/upgrades.csv.import b/example/Random Upgrades/upgrades_csv/upgrades.csv.import new file mode 100644 index 00000000..8dd0c09d --- /dev/null +++ b/example/Random Upgrades/upgrades_csv/upgrades.csv.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/project.godot b/project.godot index 75904112..019ce19e 100644 --- a/project.godot +++ b/project.godot @@ -18,6 +18,19 @@ Settings/graphWidth=300 Settings/graphHeight=100 Settings/temporaryLogLifetime=5.0 +[addons] + +resources_spreadsheet_view/array_color_tint=100.0 +resources_spreadsheet_view/color_rows=true +resources_spreadsheet_view/array_min_width=128.0 +resources_spreadsheet_view/resource_preview_size=32.0 +resources_spreadsheet_view/clip_headers=false +resources_spreadsheet_view/dupe_arrays=true +resources_spreadsheet_view/context_menu_on_leftclick=false +resources_spreadsheet_view/fold_docks=true +resources_spreadsheet_view/resource_cell_label_mode=1 +resources_spreadsheet_view/freeze_first_column=true + [application] config/name="Cirno" @@ -108,7 +121,7 @@ movie_writer/movie_file="D:/Maddo/Recordings/Capture.avi" [editor_plugins] -enabled=PackedStringArray("res://addons/dialogic/plugin.cfg", "res://addons/scene_palette/plugin.cfg", "res://addons/smoothing/plugin.cfg") +enabled=PackedStringArray("res://addons/dialogic/plugin.cfg", "res://addons/resources_spreadsheet_view/plugin.cfg", "res://addons/scene_palette/plugin.cfg", "res://addons/smoothing/plugin.cfg") [global_group]