Small Godot Wild Jam game
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add script-ide plugin

+2130 -8
-4
.gitignore
··· 16 16 # OSX 17 17 .DS_Store 18 18 19 - # User plugins 20 - addons/autoscreenshot/ 21 - addons/script-ide/ 22 - 23 19 Movies/
+21
addons/script-ide/LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2023 Marius Hanl 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+62
addons/script-ide/README.md
··· 1 + # Script IDE 2 + 3 + Transforms the Script UI into an IDE like UI. 4 + Tabs are used for navigating between scripts. 5 + The default Outline got an overhaul and now shows all members of the script (not just methods) with unique icons for faster navigation. 6 + Enhanced keyboard navigation for Scripts and Outline. 7 + Fast quick search functionality. 8 + 9 + Features: 10 + - Scripts are now shown as Tabs inside a TabContainer 11 + - The Outline got an overhaul and shows more than just the methods of the script. It includes the following members with a unique icon: 12 + - Classes (Red Square) 13 + - Constants (Red Circle) 14 + - Signals (Yellow) 15 + - Export variables (Orange) 16 + - (Static) Variables (Red) 17 + - Engine callback functions (Blue) 18 + - (Static) Functions (Green) 19 + - Setter functions (Green circle, with an arrow inside it pointing to the right) 20 + - Getter functions (Green circle, with an arrow inside it pointing to the left) 21 + - All the different members of the script can be hidden or made visible again by the outline filter. This allows fine control what should be visible (e.g. only signals, (Godot) functions, ...) 22 + - A `Right Click` enables only the clicked filter, another `Right Click` will enable all filters again 23 + - The Outline can be opened in a Popup with a defined shortcut for quick navigation between methods 24 + - You can navigate through the Outline with the `Arrow` keys (or `Page up/Page down`) and scroll to the selected item by pressing `ENTER` 25 + - Scripts can be opened in a Popup with a defined shortcut or when clicking the three dots on the top right of the TabContainer for quick navigation between scripts 26 + - The currently edited script is automatically selected in the Filesystem Dock 27 + - Files can be quickly searched by the Quick Search Popup with `Shift`+`Shift` 28 + - The plugin is written with performance in mind, everything is very fast and works without any lags or stuttering 29 + 30 + Customization: 31 + - The Outline is on the right side (can be changed to be on the left side again) 32 + - The Outline can be toggled via `File -> Toggle Scripts Panel`. This will hide or show it 33 + - The order in the Outline can be changed 34 + - There is also the possibility to hide private members, this is all members starting with a `_` 35 + - The Script ItemList is not visible by default, but can be made visible again 36 + 37 + All settings can be changed in the `Editor Settings` under `Plugin` -> `Script Ide`: 38 + - `Open Outline Popup` = Shortcut to control how the Outline Popup should be triggered (default=CTRL+O or META+O) 39 + - `Outline Position Right` = Flag to control whether the outline should be on the right or on the left side of the script editor (default=true) 40 + - `Outline Order` = List which specifies the order of all different types in the Outline 41 + - `Hide Private Members` = Flag to control whether private members (methods/variables/constants starting with '_') should be hidden in the Outline or not (default=false) 42 + - `Open Script Popup` = Shortcut to control how the Script Popup should be triggered (default=CTRL+U or META+U) 43 + - `Script List Visible` = Flag to control whether the script list should still be visible or not (above the outline) (default=false) 44 + - `Script Tabs Visible` = Flag to control whether the script tabs should be visible or not (default=true) 45 + - `Script Tabs Position Top` = Flag to control whether the script tabs should be on the top or on the bottom (default=true) 46 + - `Auto Navigate in FileSystem Dock` = Flag to control whether the script that is currently edited should be automatically selected in the Filesystem Dock (default=true) 47 + - `Open Quick Search Popup` = Shortcut to control how the Quick Search Popup should be triggered (default=Shift+Shift, double press behavior is hardcoded for now) 48 + - `Cycle Tab forward` = Shortcut to cycle the script tabs in the forward direction (only works in the 'Script' Editor Tab) (default=CTRL+TAB) 49 + - `Cycle Tab backward` = Shortcut to cycle the script tabs in the backward direction (only works in the 'Script' Editor Tab) (default=CTRL+SHIFT+TAB) 50 + - All outline visibility settings 51 + 52 + ![Example of the Outline](https://github.com/user-attachments/assets/1729cb2b-01ae-4365-b77a-45edcb94b978) 53 + 54 + ![Example of the Outline Popup](https://github.com/user-attachments/assets/995c721f-9708-40d9-a4e8-57b1a99e9c29) 55 + 56 + ![Example of the TabContainer Script ItemList Popup](https://github.com/user-attachments/assets/484d498c-bd1c-4c77-a693-ac31a8500fbe) 57 + 58 + ![Example of the Script ItemList Popup](https://github.com/user-attachments/assets/bb976604-6049-4ce1-a28e-377fc62899f6) 59 + 60 + ![Example of the Quick Search Popup](https://github.com/user-attachments/assets/01141f05-e07c-4059-8d6f-e4c7490cbd40) 61 + 62 + ![Example of the Plugin Editor Settings](https://github.com/user-attachments/assets/0450e423-bc49-4076-862b-c95a62190df1)
+1
addons/script-ide/icon/class.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" width="14" height="14" fill="#ff7085"/></svg>
+38
addons/script-ide/icon/class.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://csik7oxvt7tq3" 6 + path="res://.godot/imported/class.svg-e6f2816a1f06041fb421c2af52817a4a.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/class.svg" 15 + dest_files=["res://.godot/imported/class.svg-e6f2816a1f06041fb421c2af52817a4a.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/constant.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7s7-3.134 7-7c0-3.866-3.134-7-7-7zm0 2c2.7614 0 5 2.2386 5 5 0 2.7614-2.2386 5-5 5-2.7614 0-5-2.2386-5-5 0-2.7614 2.2386-5 5-5z" fill="#ff7085"/></svg>
+38
addons/script-ide/icon/constant.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://cawc456ja8vf5" 6 + path="res://.godot/imported/constant.svg-f6e857276565573c7540f3c32801842a.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/constant.svg" 15 + dest_files=["res://.godot/imported/constant.svg-f6e857276565573c7540f3c32801842a.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/engine_func.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-3.866-3.134-7-7-7z" fill="#57b3ff"/></svg>
+38
addons/script-ide/icon/engine_func.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://cupb0polhqrwj" 6 + path="res://.godot/imported/engine_func.svg-91320e42f9cc7bdd7576002e82fa6ab8.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/engine_func.svg" 15 + dest_files=["res://.godot/imported/engine_func.svg-91320e42f9cc7bdd7576002e82fa6ab8.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/export.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-3.866-3.134-7-7-7z" fill="#ffb273"/></svg>
+38
addons/script-ide/icon/export.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://bvu2gnj8fv2kw" 6 + path="res://.godot/imported/export.svg-d2d18132258a7a219ec1af1f0316c91c.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/export.svg" 15 + dest_files=["res://.godot/imported/export.svg-d2d18132258a7a219ec1af1f0316c91c.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/func.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-3.866-3.134-7-7-7z" fill="#8eef97"/></svg>
+38
addons/script-ide/icon/func.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://rni04cl446ov" 6 + path="res://.godot/imported/func.svg-139842caa5b4b7e4839711b6c756d0f7.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/func.svg" 15 + dest_files=["res://.godot/imported/func.svg-139842caa5b4b7e4839711b6c756d0f7.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/func_get.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 15c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm0.5-2a1 1 0 0 1-0.70703-0.29297l-4-4a1 1 0 0 1-0.25977-0.62695 1.0001 1.0001 0 0 1 0-0.16016 1 1 0 0 1 0.25977-0.62695l4-4a1 1 0 0 1 1.4141 0 1 1 0 0 1 0 1.4141l-2.293 2.293h4.5859a1 1 0 0 1 1 1 1 1 0 0 1-1 1h-4.5859l2.293 2.293a1 1 0 0 1 0 1.4141 1 1 0 0 1-0.70703 0.29297z" fill="#8eef97"/></svg>
+38
addons/script-ide/icon/func_get.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://c2a3aowyhxj5x" 6 + path="res://.godot/imported/func_get.svg-093f0ce02889d1f102ff9cc3e7f72654.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/func_get.svg" 15 + dest_files=["res://.godot/imported/func_get.svg-093f0ce02889d1f102ff9cc3e7f72654.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/func_set.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7s7-3.134 7-7c0-3.866-3.134-7-7-7zm-0.5 2a1 1 0 0 1 0.70703 0.29297l4 4a1 1 0 0 1 0.25977 0.62695 1.0001 1.0001 0 0 1 0 0.16016 1 1 0 0 1-0.25977 0.62695l-4 4a1 1 0 0 1-1.4141 0 1 1 0 0 1 0-1.4141l2.293-2.293h-4.5859a1 1 0 0 1-1-1 1 1 0 0 1 1-1h4.5859l-2.293-2.293a1 1 0 0 1 0-1.4141 1 1 0 0 1 0.70703-0.29297z" fill="#8eef97"/></svg>
+38
addons/script-ide/icon/func_set.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://bvjkrti6kj6o2" 6 + path="res://.godot/imported/func_set.svg-c31168d90866ff1707ad9834754bd2c9.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/func_set.svg" 15 + dest_files=["res://.godot/imported/func_set.svg-c31168d90866ff1707ad9834754bd2c9.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/property.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-3.866-3.134-7-7-7z" fill="#ff7085"/></svg>
+38
addons/script-ide/icon/property.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://dbwlgnwv5e8kl" 6 + path="res://.godot/imported/property.svg-9e228499f30651faad74aa99e4499d7e.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/property.svg" 15 + dest_files=["res://.godot/imported/property.svg-9e228499f30651faad74aa99e4499d7e.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+1
addons/script-ide/icon/signal.svg
··· 1 + <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-3.866-3.134-7-7-7z" fill="#ffdd65"/></svg>
+38
addons/script-ide/icon/signal.svg.import
··· 1 + [remap] 2 + 3 + importer="texture" 4 + type="CompressedTexture2D" 5 + uid="uid://bnccvnaloqnte" 6 + path="res://.godot/imported/signal.svg-97182e1498b520a1ff5b8b9017c3b480.ctex" 7 + metadata={ 8 + "has_editor_variant": true, 9 + "vram_texture": false 10 + } 11 + 12 + [deps] 13 + 14 + source_file="res://addons/script-ide/icon/signal.svg" 15 + dest_files=["res://.godot/imported/signal.svg-97182e1498b520a1ff5b8b9017c3b480.ctex"] 16 + 17 + [params] 18 + 19 + compress/mode=0 20 + compress/high_quality=false 21 + compress/lossy_quality=0.7 22 + compress/hdr_compression=1 23 + compress/normal_map=0 24 + compress/channel_pack=0 25 + mipmaps/generate=false 26 + mipmaps/limit=-1 27 + roughness/mode=0 28 + roughness/src_normal="" 29 + process/fix_alpha_border=true 30 + process/premult_alpha=false 31 + process/normal_map_invert_y=false 32 + process/hdr_as_srgb=false 33 + process/hdr_clamp_exposure=false 34 + process/size_limit=0 35 + detect_3d/compress_to=1 36 + svg/scale=1.0 37 + editor/scale_with_editor_scale=true 38 + editor/convert_colors_with_editor_theme=false
+7
addons/script-ide/plugin.cfg
··· 1 + [plugin] 2 + 3 + name="Script-IDE" 4 + description="Transforms the Script UI into an IDE like UI. Tabs are used for navigating between scripts. The default Outline got an overhaul and now shows all members of the script (not just methods) with unique icons for faster navigation. Enhanced keyboard navigation for Scripts and Outline. Fast quick search functionality." 5 + author="Marius Hanl" 6 + version="1.7.2" 7 + script="plugin.gd"
+1304
addons/script-ide/plugin.gd
··· 1 + ## Copyright (c) 2023-present Marius Hanl under the MIT License. 2 + ## The editor plugin entrypoint for Script-IDE. 3 + ## 4 + ## The Script Tabs and Outline modifies the code that is inside 'script_editor_plugin.cpp'. 5 + ## That is, the structure is changed a little bit. 6 + ## The internals of then native C++ code are therefore important in order to make this plugin work 7 + ## without interfering with the Engine. 8 + ## All the other functionality does not modify anything Engine related. 9 + ## 10 + ## Script-IDE does not use global class_name's in order to not clutter projects using it. 11 + ## Especially since this is an editor only plugin, we do not want this plugin in the final game. 12 + ## Therefore, code that references other code inside this plugin is untyped. 13 + @tool 14 + extends EditorPlugin 15 + 16 + const GETTER: StringName = &"get" 17 + const SETTER: StringName = &"set" 18 + const UNDERSCORE: StringName = &"_" 19 + const INLINE: StringName = &"@" 20 + 21 + const BUILT_IN_SCRIPT: StringName = &"::GDScript" 22 + 23 + #region Settings and Shortcuts 24 + ## Editor setting path 25 + const SCRIPT_IDE: StringName = &"plugin/script_ide/" 26 + ## Editor setting for the outline position 27 + const OUTLINE_POSITION_RIGHT: StringName = SCRIPT_IDE + &"outline_position_right" 28 + ## Editor setting to control the order of the outline 29 + const OUTLINE_ORDER: StringName = SCRIPT_IDE + &"outline_order" 30 + ## Editor setting to control whether private members (annotated with '_' should be hidden or not) 31 + const HIDE_PRIVATE_MEMBERS: StringName = SCRIPT_IDE + &"hide_private_members" 32 + ## Editor setting to control whether we want to auto navigate to the script 33 + ## in the filesystem (dock) when selected 34 + const AUTO_NAVIGATE_IN_FS: StringName = SCRIPT_IDE + &"auto_navigate_in_filesystem_dock" 35 + ## Editor setting to control whether the script list should be visible or not 36 + const SCRIPT_LIST_VISIBLE: StringName = SCRIPT_IDE + &"script_list_visible" 37 + ## Editor setting to control whether the script tabs should be visible or not. 38 + const SCRIPT_TABS_VISIBLE: StringName = SCRIPT_IDE + &"script_tabs_visible" 39 + ## Editor setting to control where the script tabs should be. 40 + const SCRIPT_TAB_POSITION_TOP: StringName = SCRIPT_IDE + &"script_tab_position_top" 41 + 42 + ## Editor setting for the 'Open Outline Popup' shortcut 43 + const OPEN_OUTLINE_POPUP: StringName = SCRIPT_IDE + &"open_outline_popup" 44 + ## Editor setting for the 'Open Scripts Popup' shortcut 45 + const OPEN_SCRIPTS_POPUP: StringName = SCRIPT_IDE + &"open_scripts_popup" 46 + ## Editor setting for the 'Open Scripts Popup' shortcut 47 + const OPEN_QUICK_SEARCH_POPUP: StringName = SCRIPT_IDE + &"open_quick_search_popup" 48 + ## Editor setting for the 'Tab cycle forward' shortcut 49 + const TAB_CYCLE_FORWARD: StringName = SCRIPT_IDE + &"tab_cycle_forward" 50 + ## Editor setting for the 'Tab cycle backward' shortcut 51 + const TAB_CYCLE_BACKWARD: StringName = SCRIPT_IDE + &"tab_cycle_backward" 52 + #endregion 53 + 54 + #region Outline type name and icon 55 + const ENGINE_FUNCS: StringName = &"Engine Callbacks" 56 + const FUNCS: StringName = &"Functions" 57 + const SIGNALS: StringName = &"Signals" 58 + const EXPORTED: StringName = &"Exported Properties" 59 + const PROPERTIES: StringName = &"Properties" 60 + const CLASSES: StringName = &"Classes" 61 + const CONSTANTS: StringName = &"Constants" 62 + 63 + var engine_func_icon: Texture2D 64 + var func_icon: Texture2D 65 + var func_get_icon: Texture2D 66 + var func_set_icon: Texture2D 67 + var property_icon: Texture2D 68 + var export_icon: Texture2D 69 + var signal_icon: Texture2D 70 + var constant_icon: Texture2D 71 + var class_icon: Texture2D 72 + #endregion 73 + 74 + #region Editor settings 75 + var is_outline_right: bool = true 76 + var is_script_list_visible: bool = false 77 + var hide_private_members: bool = false 78 + var is_auto_navigate_in_fs: bool = true 79 + var is_script_tabs_visible: bool = true 80 + var is_script_tabs_top: bool = true 81 + var outline_order: PackedStringArray 82 + 83 + var open_outline_popup_shc: Shortcut 84 + var open_scripts_popup_shc: Shortcut 85 + var open_quick_search_popup_shc: Shortcut 86 + var tab_cycle_forward_shc: Shortcut 87 + var tab_cycle_backward_shc: Shortcut 88 + #endregion 89 + 90 + #region Existing controls we modify 91 + var outline_container: Control 92 + var outline_parent: Control 93 + var scripts_tab_container: TabContainer 94 + var scripts_tab_bar: TabBar 95 + var script_filter_txt: LineEdit 96 + var scripts_item_list: ItemList 97 + var panel_container: VSplitContainer 98 + 99 + var split_container: HSplitContainer 100 + var old_outline: ItemList 101 + var outline_filter_txt: LineEdit 102 + var sort_btn: Button 103 + #endregion 104 + 105 + #region Own controls we add 106 + var outline: ItemList 107 + var outline_popup: PopupPanel 108 + var filter_box: HBoxContainer 109 + 110 + var scripts_popup: PopupPanel 111 + var quick_open_popup: PopupPanel 112 + 113 + var class_btn: Button 114 + var constant_btn: Button 115 + var signal_btn: Button 116 + var property_btn: Button 117 + var export_btn: Button 118 + var func_btn: Button 119 + var engine_func_btn: Button 120 + #endregion 121 + 122 + #region Plugin variables 123 + var keywords: Dictionary = {} # [String, int = 0] # Used as Set. 124 + var outline_type_order: Array[OutlineType] = [] 125 + var outline_cache: OutlineCache 126 + var tab_state: TabStateCache 127 + 128 + var old_script_editor_base: ScriptEditorBase 129 + var old_script_type: StringName 130 + 131 + var selected_tab: int = -1 132 + var last_tab_hovered: int = -1 133 + var sync_script_list: bool = false 134 + var file_to_navigate: String = &"" 135 + var suppress_settings_sync: bool = false 136 + 137 + const QUICK_OPEN_INTERVAL: int = 400 138 + var quick_open_tween: Tween 139 + #endregion 140 + 141 + #region Plugin Enter / Exit setup 142 + ## Change the Godot script UI and transform into an IDE like UI 143 + func _enter_tree() -> void: 144 + init_icons() 145 + init_settings() 146 + init_shortcuts() 147 + 148 + # Update on filesystem changed (e.g. save operation). 149 + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() 150 + file_system.filesystem_changed.connect(schedule_update) 151 + 152 + # Sync settings changes for this plugin. 153 + get_editor_settings().settings_changed.connect(sync_settings) 154 + 155 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 156 + 157 + # Change script item list visibility (based on settings). 158 + scripts_item_list = find_or_null(script_editor.find_children("*", "ItemList", true, false)) 159 + scripts_item_list.allow_reselect = true 160 + scripts_item_list.item_selected.connect(hide_scripts_popup.unbind(1)) 161 + update_script_list_visibility() 162 + 163 + # Add script filter navigation. 164 + script_filter_txt = find_or_null(scripts_item_list.get_parent().find_children("*", "LineEdit", true, false)) 165 + script_filter_txt.gui_input.connect(navigate_on_list.bind(scripts_item_list, select_script)) 166 + 167 + # Make tab container visible. 168 + scripts_tab_container = find_or_null(script_editor.find_children("*", "TabContainer", true, false)) 169 + scripts_tab_bar = scripts_tab_container.get_tab_bar() 170 + 171 + # Save old tab state to restore later. 172 + tab_state = TabStateCache.new() 173 + tab_state.save(scripts_tab_container, scripts_tab_bar) 174 + 175 + # Create and set script popup. 176 + create_set_scripts_popup() 177 + 178 + # Configure tab container and bar. 179 + scripts_tab_container.tabs_visible = is_script_tabs_visible 180 + scripts_tab_container.drag_to_rearrange_enabled = true 181 + scripts_tab_container.auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED 182 + update_tabs_position() 183 + 184 + scripts_tab_bar.tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ACTIVE_ONLY 185 + scripts_tab_bar.drag_to_rearrange_enabled = true 186 + scripts_tab_bar.select_with_rmb = true 187 + scripts_tab_bar.tab_close_pressed.connect(on_tab_close) 188 + scripts_tab_bar.tab_rmb_clicked.connect(on_tab_rmb) 189 + scripts_tab_bar.tab_hovered.connect(on_tab_hovered) 190 + scripts_tab_bar.mouse_exited.connect(on_tab_bar_mouse_exited) 191 + scripts_tab_bar.active_tab_rearranged.connect(on_active_tab_rearranged) 192 + scripts_tab_bar.gui_input.connect(on_tab_bar_gui_input) 193 + 194 + scripts_tab_bar.tab_changed.connect(on_tab_changed) 195 + 196 + # Remove existing outline and add own outline. 197 + split_container = find_or_null(script_editor.find_children("*", "HSplitContainer", true, false)) 198 + outline_container = split_container.get_child(0) 199 + 200 + if (is_outline_right): 201 + update_outline_position() 202 + 203 + old_outline = find_or_null(outline_container.find_children("*", "ItemList", true, false), 1) 204 + outline_parent = old_outline.get_parent() 205 + outline_parent.remove_child(old_outline) 206 + 207 + outline = ItemList.new() 208 + outline.allow_reselect = true 209 + outline.size_flags_vertical = Control.SIZE_EXPAND_FILL 210 + outline_parent.add_child(outline) 211 + 212 + outline.item_selected.connect(scroll_outline) 213 + 214 + # Add a filter box for all kind of members 215 + filter_box = HBoxContainer.new() 216 + 217 + engine_func_btn = create_filter_btn(engine_func_icon, ENGINE_FUNCS) 218 + func_btn = create_filter_btn(func_icon, FUNCS) 219 + signal_btn = create_filter_btn(signal_icon, SIGNALS) 220 + export_btn = create_filter_btn(export_icon, EXPORTED) 221 + property_btn = create_filter_btn(property_icon, PROPERTIES) 222 + class_btn = create_filter_btn(class_icon, CLASSES) 223 + constant_btn = create_filter_btn(constant_icon, CONSTANTS) 224 + update_outline_button_order() 225 + 226 + outline.get_parent().add_child(filter_box) 227 + outline.get_parent().move_child(filter_box, outline.get_index()) 228 + 229 + # Add navigation to the filter and text filtering. 230 + outline_filter_txt = find_or_null(outline_container.find_children("*", "LineEdit", true, false), 1) 231 + outline_filter_txt.gui_input.connect(navigate_on_list.bind(outline, scroll_outline)) 232 + outline_filter_txt.text_changed.connect(update_outline.unbind(1)) 233 + 234 + # Add callback when the sorting changed. 235 + sort_btn = find_or_null(outline_container.find_children("*", "Button", true, false)) 236 + sort_btn.pressed.connect(update_outline) 237 + 238 + on_tab_changed(scripts_tab_bar.current_tab) 239 + 240 + ## Restore the old Godot script UI and free everything we created 241 + func _exit_tree() -> void: 242 + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() 243 + file_system.filesystem_changed.disconnect(schedule_update) 244 + 245 + if (old_script_editor_base != null): 246 + old_script_editor_base.edited_script_changed.disconnect(update_selected_tab) 247 + 248 + if (split_container != null): 249 + if (split_container != outline_container.get_parent()): 250 + split_container.add_child(outline_container) 251 + 252 + # Try to restore the previous split offset. 253 + if (is_outline_right): 254 + var split_offset: float = split_container.get_child(1).size.x 255 + split_container.split_offset = split_offset 256 + 257 + split_container.move_child(outline_container, 0) 258 + 259 + outline_filter_txt.gui_input.disconnect(navigate_on_list) 260 + outline_filter_txt.text_changed.disconnect(update_outline) 261 + sort_btn.pressed.disconnect(update_outline) 262 + 263 + outline.item_selected.disconnect(scroll_outline) 264 + 265 + outline_parent.remove_child(filter_box) 266 + outline_parent.remove_child(outline) 267 + outline_parent.add_child(old_outline) 268 + outline_parent.move_child(old_outline, 2) 269 + 270 + filter_box.free() 271 + outline.free() 272 + 273 + if (scripts_tab_container != null): 274 + tab_state.restore(scripts_tab_container, scripts_tab_bar) 275 + 276 + scripts_tab_container.pre_popup_pressed.disconnect(prepare_scripts_popup) 277 + scripts_tab_container.set_popup(null) 278 + scripts_popup.free() 279 + 280 + if (scripts_tab_bar != null): 281 + scripts_tab_bar.mouse_exited.disconnect(on_tab_bar_mouse_exited) 282 + scripts_tab_bar.gui_input.disconnect(on_tab_bar_gui_input) 283 + scripts_tab_bar.tab_close_pressed.disconnect(on_tab_close) 284 + scripts_tab_bar.tab_rmb_clicked.disconnect(on_tab_rmb) 285 + scripts_tab_bar.tab_hovered.disconnect(on_tab_hovered) 286 + scripts_tab_bar.active_tab_rearranged.disconnect(on_active_tab_rearranged) 287 + 288 + scripts_tab_bar.tab_changed.disconnect(on_tab_changed) 289 + 290 + if (scripts_item_list != null): 291 + scripts_item_list.allow_reselect = false 292 + scripts_item_list.item_selected.disconnect(hide_scripts_popup) 293 + scripts_item_list.get_parent().visible = true 294 + 295 + if (script_filter_txt != null): 296 + script_filter_txt.gui_input.disconnect(navigate_on_list) 297 + 298 + if (outline_popup != null): 299 + outline_popup.free() 300 + 301 + if (quick_open_popup != null): 302 + quick_open_popup.free() 303 + 304 + get_editor_settings().settings_changed.disconnect(sync_settings) 305 + #endregion 306 + 307 + #region Plugin and Shortcut processing 308 + ## Lazy pattern to update the editor only once per frame 309 + func _process(delta: float) -> void: 310 + update_editor() 311 + set_process(false) 312 + 313 + ## Process the user defined shortcuts 314 + func _shortcut_input(event: InputEvent) -> void: 315 + if (!event.is_pressed() || event.is_echo()): 316 + return 317 + 318 + if (open_outline_popup_shc.matches_event(event)): 319 + get_viewport().set_input_as_handled() 320 + open_outline_popup() 321 + elif (open_scripts_popup_shc.matches_event(event)): 322 + get_viewport().set_input_as_handled() 323 + open_scripts_popup() 324 + elif (open_quick_search_popup_shc.matches_event(event)): 325 + if (quick_open_tween != null && quick_open_tween.is_running()): 326 + get_viewport().set_input_as_handled() 327 + if (quick_open_tween != null): 328 + quick_open_tween.kill() 329 + 330 + quick_open_tween = create_tween() 331 + quick_open_tween.tween_interval(0.1) 332 + quick_open_tween.tween_callback(open_quick_search_popup) 333 + quick_open_tween.tween_callback(func(): quick_open_tween = null) 334 + else: 335 + quick_open_tween = create_tween() 336 + quick_open_tween.tween_interval(QUICK_OPEN_INTERVAL / 1000.0) 337 + quick_open_tween.tween_callback(func(): quick_open_tween = null) 338 + elif (EditorInterface.get_script_editor().is_visible_in_tree()): 339 + if (tab_cycle_forward_shc.matches_event(event)): 340 + get_viewport().set_input_as_handled() 341 + 342 + var new_tab: int = scripts_tab_container.current_tab + 1 343 + if (new_tab == scripts_tab_container.get_tab_count()): 344 + new_tab = 0 345 + scripts_tab_container.current_tab = new_tab 346 + elif (tab_cycle_backward_shc.matches_event(event)): 347 + get_viewport().set_input_as_handled() 348 + 349 + var new_tab: int = scripts_tab_container.current_tab - 1 350 + if (new_tab == -1): 351 + new_tab = scripts_tab_container.get_tab_count() - 1 352 + scripts_tab_container.current_tab = new_tab 353 + 354 + ## May cancels the quick search shortcut timer. 355 + func _input(event: InputEvent) -> void: 356 + if (event is InputEventKey): 357 + if (!open_quick_search_popup_shc.matches_event(event)): 358 + if (quick_open_tween != null): 359 + quick_open_tween.kill() 360 + quick_open_tween = null 361 + #endregion 362 + 363 + #region Icon, Settings, Shortcut initialization 364 + ## Initializes all plugin icons, while respecting the editor settings. 365 + func init_icons(): 366 + engine_func_icon = create_editor_texture(load_rel("icon/engine_func.svg")) 367 + func_icon = create_editor_texture(load_rel("icon/func.svg")) 368 + func_get_icon = create_editor_texture(load_rel("icon/func_get.svg")) 369 + func_set_icon = create_editor_texture(load_rel("icon/func_set.svg")) 370 + property_icon = create_editor_texture(load_rel("icon/property.svg")) 371 + export_icon = create_editor_texture(load_rel("icon/export.svg")) 372 + signal_icon = create_editor_texture(load_rel("icon/signal.svg")) 373 + constant_icon = create_editor_texture(load_rel("icon/constant.svg")) 374 + class_icon = create_editor_texture(load_rel("icon/class.svg")) 375 + 376 + ## Initializes all settings. 377 + ## Every setting can be changed while this plugin is active, which will override them. 378 + func init_settings(): 379 + is_outline_right = get_setting(OUTLINE_POSITION_RIGHT, is_outline_right) 380 + hide_private_members = get_setting(HIDE_PRIVATE_MEMBERS, hide_private_members) 381 + is_script_list_visible = get_setting(SCRIPT_LIST_VISIBLE, is_script_list_visible) 382 + is_auto_navigate_in_fs = get_setting(AUTO_NAVIGATE_IN_FS, is_auto_navigate_in_fs) 383 + is_script_tabs_visible = get_setting(SCRIPT_TABS_VISIBLE, is_script_tabs_visible) 384 + is_script_tabs_top = get_setting(SCRIPT_TAB_POSITION_TOP, is_script_tabs_top) 385 + 386 + init_outline_order() 387 + 388 + ## Initializes the outline type structure and sorts it based off the outline order. 389 + func init_outline_order(): 390 + var outline_type: OutlineType = OutlineType.new() 391 + outline_type.type_name = ENGINE_FUNCS 392 + outline_type.add_to_outline = func(): add_to_outline_if_selected(engine_func_btn, 393 + func(): add_to_outline(outline_cache.engine_funcs, engine_func_icon, &"func")) 394 + outline_type_order.append(outline_type) 395 + 396 + outline_type = OutlineType.new() 397 + outline_type.type_name = FUNCS 398 + outline_type.add_to_outline = func(): add_to_outline_if_selected(func_btn, 399 + func(): add_to_outline_ext(outline_cache.funcs, get_func_icon, &"func", &"static")) 400 + outline_type_order.append(outline_type) 401 + 402 + outline_type = OutlineType.new() 403 + outline_type.type_name = SIGNALS 404 + outline_type.add_to_outline = func(): add_to_outline_if_selected(signal_btn, 405 + func(): add_to_outline(outline_cache.signals, signal_icon, &"signal")) 406 + outline_type_order.append(outline_type) 407 + 408 + outline_type = OutlineType.new() 409 + outline_type.type_name = EXPORTED 410 + outline_type.add_to_outline = func(): add_to_outline_if_selected(export_btn, 411 + func(): add_to_outline(outline_cache.exports, export_icon, &"var", &"@export")) 412 + outline_type_order.append(outline_type) 413 + 414 + outline_type = OutlineType.new() 415 + outline_type.type_name = PROPERTIES 416 + outline_type.add_to_outline = func(): add_to_outline_if_selected(property_btn, 417 + func(): add_to_outline(outline_cache.properties, property_icon, &"var")) 418 + outline_type_order.append(outline_type) 419 + 420 + outline_type = OutlineType.new() 421 + outline_type.type_name = CLASSES 422 + outline_type.add_to_outline = func(): add_to_outline_if_selected(class_btn, 423 + func(): add_to_outline(outline_cache.classes, class_icon, &"class")) 424 + outline_type_order.append(outline_type) 425 + 426 + outline_type = OutlineType.new() 427 + outline_type.type_name = CONSTANTS 428 + outline_type.add_to_outline = func(): add_to_outline_if_selected(constant_btn, 429 + func(): add_to_outline(outline_cache.constants, constant_icon, &"const", &"enum")) 430 + outline_type_order.append(outline_type) 431 + 432 + update_outline_order() 433 + 434 + func update_outline_button_order(): 435 + var all_buttons: Array[Button] = [engine_func_btn, func_btn, signal_btn, export_btn, property_btn, class_btn, constant_btn] 436 + all_buttons.sort_custom(sort_buttons_by_outline_order) 437 + 438 + for btn: Button in all_buttons: 439 + if (btn.get_parent() != null): 440 + filter_box.remove_child(btn) 441 + 442 + for btn: Button in all_buttons: 443 + filter_box.add_child(btn) 444 + 445 + func update_outline_order(): 446 + var editor_settings: EditorSettings = get_editor_settings() 447 + if (editor_settings.has_setting(OUTLINE_ORDER)): 448 + outline_order = editor_settings.get_setting(OUTLINE_ORDER) 449 + else: 450 + outline_order = [ENGINE_FUNCS, FUNCS, SIGNALS, EXPORTED, PROPERTIES, CONSTANTS, CLASSES] 451 + editor_settings.set_setting(OUTLINE_ORDER, outline_order) 452 + 453 + outline_type_order.sort_custom(sort_types_by_outline_order) 454 + 455 + func sort_buttons_by_outline_order(btn1: Button, btn2: Button) -> bool: 456 + return sort_by_outline_order(btn1.tooltip_text, btn2.tooltip_text) 457 + 458 + func sort_types_by_outline_order(type1: OutlineType, type2: OutlineType) -> bool: 459 + return sort_by_outline_order(type1.type_name, type2.type_name) 460 + 461 + func sort_by_outline_order(outline_type1: StringName, outline_type2: StringName) -> bool: 462 + return outline_order.find(outline_type1) < outline_order.find(outline_type2) 463 + 464 + ## Initializes all shortcuts. 465 + ## Every shortcut can be changed while this plugin is active, which will override them. 466 + func init_shortcuts(): 467 + var editor_settings: EditorSettings = get_editor_settings() 468 + if (!editor_settings.has_setting(OPEN_OUTLINE_POPUP)): 469 + var shortcut: Shortcut = Shortcut.new() 470 + var event: InputEventKey = InputEventKey.new() 471 + event.device = -1 472 + event.command_or_control_autoremap = true 473 + event.keycode = KEY_O 474 + 475 + shortcut.events = [ event ] 476 + editor_settings.set_setting(OPEN_OUTLINE_POPUP, shortcut) 477 + 478 + if (!editor_settings.has_setting(OPEN_SCRIPTS_POPUP)): 479 + var shortcut: Shortcut = Shortcut.new() 480 + var event: InputEventKey = InputEventKey.new() 481 + event.device = -1 482 + event.command_or_control_autoremap = true 483 + event.keycode = KEY_U 484 + 485 + shortcut.events = [ event ] 486 + editor_settings.set_setting(OPEN_SCRIPTS_POPUP, shortcut) 487 + 488 + if (!editor_settings.has_setting(OPEN_QUICK_SEARCH_POPUP)): 489 + var shortcut: Shortcut = Shortcut.new() 490 + var event: InputEventKey = InputEventKey.new() 491 + event.device = -1 492 + event.keycode = KEY_SHIFT 493 + 494 + shortcut.events = [ event ] 495 + editor_settings.set_setting(OPEN_QUICK_SEARCH_POPUP, shortcut) 496 + 497 + if (!editor_settings.has_setting(TAB_CYCLE_FORWARD)): 498 + var shortcut: Shortcut = Shortcut.new() 499 + var event: InputEventKey = InputEventKey.new() 500 + event.device = -1 501 + event.keycode = KEY_TAB 502 + event.ctrl_pressed = true 503 + 504 + shortcut.events = [ event ] 505 + editor_settings.set_setting(TAB_CYCLE_FORWARD, shortcut) 506 + 507 + if (!editor_settings.has_setting(TAB_CYCLE_BACKWARD)): 508 + var shortcut: Shortcut = Shortcut.new() 509 + var event: InputEventKey = InputEventKey.new() 510 + event.device = -1 511 + event.keycode = KEY_TAB 512 + event.shift_pressed = true 513 + event.ctrl_pressed = true 514 + 515 + shortcut.events = [ event ] 516 + editor_settings.set_setting(TAB_CYCLE_BACKWARD, shortcut) 517 + 518 + open_outline_popup_shc = editor_settings.get_setting(OPEN_OUTLINE_POPUP) 519 + open_scripts_popup_shc = editor_settings.get_setting(OPEN_SCRIPTS_POPUP) 520 + open_quick_search_popup_shc = editor_settings.get_setting(OPEN_QUICK_SEARCH_POPUP) 521 + tab_cycle_forward_shc = editor_settings.get_setting(TAB_CYCLE_FORWARD) 522 + tab_cycle_backward_shc = editor_settings.get_setting(TAB_CYCLE_BACKWARD) 523 + #endregion 524 + 525 + ## Schedules an update on the next frame 526 + func schedule_update(): 527 + set_process(true) 528 + 529 + ## Updates all parts of the editor that are needed to be synchronized with the file system change. 530 + func update_editor(): 531 + update_script_text_filter() 532 + 533 + if (sync_script_list): 534 + if (file_to_navigate != &""): 535 + EditorInterface.get_file_system_dock().navigate_to_path(file_to_navigate) 536 + EditorInterface.get_script_editor().get_current_editor().get_base_editor().grab_focus() 537 + file_to_navigate = &"" 538 + 539 + sync_tab_with_script_list() 540 + sync_script_list = false 541 + 542 + update_tabs() 543 + update_outline_cache() 544 + update_outline() 545 + 546 + func add_to_outline_if_selected(btn: Button, action: Callable): 547 + if (btn.button_pressed): 548 + action.call() 549 + 550 + func open_quick_search_popup(): 551 + if (quick_open_popup == null): 552 + quick_open_popup = load_rel("quickopen/quick_open_panel.tscn").instantiate() 553 + quick_open_popup.plugin = self 554 + 555 + if (quick_open_popup.get_parent() != null): 556 + quick_open_popup.get_parent().remove_child(quick_open_popup) 557 + quick_open_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) 558 + 559 + func hide_scripts_popup(): 560 + if (scripts_popup != null && scripts_popup.visible): 561 + scripts_popup.hide.call_deferred() 562 + 563 + func create_set_scripts_popup(): 564 + panel_container = scripts_item_list.get_parent().get_parent() 565 + 566 + scripts_popup = PopupPanel.new() 567 + scripts_popup.popup_hide.connect(restore_scripts_list) 568 + 569 + # Need to be inside the tree, so it can be shown as popup for the tab container. 570 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 571 + script_editor.add_child(scripts_popup) 572 + 573 + scripts_tab_container.pre_popup_pressed.connect(prepare_scripts_popup) 574 + scripts_tab_container.set_popup(scripts_popup) 575 + 576 + func prepare_scripts_popup(): 577 + scripts_popup.size.x = outline.size.x 578 + scripts_popup.size.y = panel_container.size.y - scripts_tab_bar.size.y 579 + 580 + scripts_item_list.get_parent().reparent(scripts_popup) 581 + scripts_item_list.get_parent().visible = true 582 + 583 + script_filter_txt.grab_focus() 584 + 585 + func restore_scripts_list(): 586 + script_filter_txt.text = &"" 587 + 588 + update_script_list_visibility() 589 + 590 + scripts_item_list.get_parent().reparent(panel_container) 591 + panel_container.move_child(scripts_item_list.get_parent(), 0) 592 + 593 + func navigate_on_list(event: InputEvent, list: ItemList, submit: Callable): 594 + if (event.is_action_pressed(&"ui_text_submit")): 595 + var index: int = get_list_index(list) 596 + if (index == -1): 597 + return 598 + 599 + submit.call(index) 600 + elif (event.is_action_pressed(&"ui_down", true)): 601 + var index: int = get_list_index(list) 602 + if (index == list.item_count - 1): 603 + return 604 + 605 + navigate_list(list, index, 1) 606 + elif (event.is_action_pressed(&"ui_up", true)): 607 + var index: int = get_list_index(list) 608 + if (index <= 0): 609 + return 610 + 611 + navigate_list(list, index, -1) 612 + elif (event.is_action_pressed(&"ui_page_down", true)): 613 + var index: int = get_list_index(list) 614 + if (index == list.item_count - 1): 615 + return 616 + 617 + navigate_list(list, index, 5) 618 + elif (event.is_action_pressed(&"ui_page_up", true)): 619 + var index: int = get_list_index(list) 620 + if (index <= 0): 621 + return 622 + 623 + navigate_list(list, index, -5) 624 + elif (event is InputEventKey && list.item_count > 0 && !list.is_anything_selected()): 625 + list.select(0) 626 + 627 + func get_list_index(list: ItemList) -> int: 628 + var items: PackedInt32Array = list.get_selected_items() 629 + 630 + if (items.is_empty()): 631 + return -1 632 + 633 + return items[0] 634 + 635 + func navigate_list(list: ItemList, index: int, amount: int): 636 + index = clamp(index + amount, 0, list.item_count - 1) 637 + 638 + list.select(index) 639 + list.ensure_current_is_visible() 640 + list.accept_event() 641 + 642 + func get_center_editor_rect() -> Rect2i: 643 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 644 + 645 + var size: Vector2i = Vector2i(400, 500) 646 + var x: int 647 + var y: int 648 + 649 + if (script_editor.get_parent().get_parent() is Window): 650 + # Floating editor. 651 + var window: Window = script_editor.get_parent().get_parent() 652 + var window_rect: Rect2 = window.get_visible_rect() 653 + 654 + x = window_rect.size.x / 2 - size.x / 2 655 + y = window_rect.size.y / 2 - size.y / 2 656 + else: 657 + x = script_editor.global_position.x + script_editor.size.x / 2 - size.x / 2 658 + y = script_editor.global_position.y + script_editor.size.y / 2 - size.y / 2 659 + 660 + return Rect2i(Vector2i(x, y), size) 661 + 662 + func open_outline_popup(): 663 + var button_flags: Array[bool] = [] 664 + for child: Node in filter_box.get_children(): 665 + var btn: Button = child 666 + button_flags.append(btn.button_pressed) 667 + 668 + btn.set_pressed_no_signal(true) 669 + 670 + var old_text: String = outline_filter_txt.text 671 + outline_filter_txt.text = &"" 672 + 673 + if (outline_popup == null): 674 + outline_popup = PopupPanel.new() 675 + 676 + var outline_initially_closed: bool = !outline_container.visible 677 + if (outline_initially_closed): 678 + outline_container.visible = true 679 + 680 + outline_container.reparent(outline_popup) 681 + 682 + outline_popup.popup_hide.connect(on_outline_popup_hidden.bind(outline_initially_closed, old_text, button_flags)) 683 + 684 + if (outline_popup.get_parent() != null): 685 + outline_popup.get_parent().remove_child(outline_popup) 686 + outline_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) 687 + 688 + update_outline() 689 + outline_filter_txt.grab_focus() 690 + 691 + func on_outline_popup_hidden(outline_initially_closed: bool, old_text: String, button_flags: Array[bool]): 692 + outline_popup.popup_hide.disconnect(on_outline_popup_hidden) 693 + 694 + if outline_initially_closed: 695 + outline_container.visible = false 696 + 697 + outline_container.reparent(split_container) 698 + if (!is_outline_right): 699 + split_container.move_child(outline_container, 0) 700 + 701 + outline_filter_txt.text = old_text 702 + 703 + var index: int = 0 704 + for flag: bool in button_flags: 705 + var btn: Button = filter_box.get_child(index) 706 + btn.set_pressed_no_signal(flag) 707 + index += 1 708 + 709 + update_outline() 710 + 711 + func open_scripts_popup(): 712 + scripts_item_list.get_parent().reparent(scripts_popup) 713 + scripts_item_list.get_parent().visible = true 714 + 715 + if (scripts_popup.get_parent() != null): 716 + scripts_popup.get_parent().remove_child(scripts_popup) 717 + scripts_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) 718 + 719 + script_filter_txt.grab_focus() 720 + 721 + ## Removes the script filter text and emits the signal so that the tabs stay 722 + ## and we do not break anything there. 723 + func update_script_text_filter(): 724 + if (script_filter_txt.text != &""): 725 + script_filter_txt.text = &"" 726 + script_filter_txt.text_changed.emit(&"") 727 + 728 + func get_current_script() -> Script: 729 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 730 + return script_editor.get_current_script() 731 + 732 + func select_script(selected_idx: int): 733 + hide_scripts_popup() 734 + 735 + scripts_item_list.item_selected.emit(selected_idx) 736 + 737 + func scroll_outline(selected_idx: int): 738 + if (outline_popup != null && outline_popup.visible): 739 + outline_popup.hide.call_deferred() 740 + 741 + var script: Script = get_current_script() 742 + if (!script): 743 + return 744 + 745 + var text: String = outline.get_item_text(selected_idx) 746 + var metadata: Dictionary = outline.get_item_metadata(selected_idx) 747 + var modifier: StringName = metadata[&"modifier"] 748 + var type: StringName = metadata[&"type"] 749 + 750 + var type_with_text: String = type + " " + text 751 + if (type == &"func"): 752 + type_with_text = type_with_text + "(" 753 + 754 + var source_code: String = script.get_source_code() 755 + var lines: PackedStringArray = source_code.split("\n") 756 + 757 + var index: int = 0 758 + for line: String in lines: 759 + # Easy case, like 'var abc' 760 + if (line.begins_with(type_with_text)): 761 + goto_line(index) 762 + return 763 + 764 + # We have an modifier, e.g. 'static' 765 + if (modifier != &"" && line.begins_with(modifier)): 766 + if (line.begins_with(modifier + " " + type_with_text)): 767 + goto_line(index) 768 + return 769 + # Special case: An 'enum' is treated different. 770 + elif (modifier == &"enum" && line.contains("enum " + text)): 771 + goto_line(index) 772 + return 773 + 774 + # Hard case, probably something like '@onready var abc' 775 + if (type == &"var" && line.contains(type_with_text)): 776 + goto_line(index) 777 + return 778 + 779 + index += 1 780 + 781 + push_error(type_with_text + " or " + modifier + " not found in source code") 782 + 783 + func goto_line(index: int): 784 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 785 + script_editor.goto_line(index) 786 + 787 + var code_edit: CodeEdit = script_editor.get_current_editor().get_base_editor() 788 + code_edit.set_caret_line(index) 789 + code_edit.set_v_scroll(index) 790 + code_edit.set_caret_column(code_edit.get_line(index).length()) 791 + code_edit.set_h_scroll(0) 792 + 793 + code_edit.grab_focus() 794 + 795 + func create_filter_btn(icon: Texture2D, title: StringName) -> Button: 796 + var btn: Button = Button.new() 797 + btn.toggle_mode = true 798 + btn.icon = icon 799 + btn.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER 800 + btn.tooltip_text = title 801 + 802 + var property: StringName = SCRIPT_IDE + title.to_lower().replace(" ", "_") 803 + btn.set_meta(&"property", property) 804 + btn.button_pressed = get_setting(property, true) 805 + 806 + btn.toggled.connect(on_filter_button_pressed.bind(btn)) 807 + btn.gui_input.connect(on_right_click.bind(btn)) 808 + 809 + btn.add_theme_color_override(&"icon_pressed_color", Color.WHITE) 810 + btn.add_theme_color_override(&"icon_hover_color", Color.WHITE) 811 + btn.add_theme_color_override(&"icon_hover_pressed_color", Color.WHITE) 812 + btn.add_theme_color_override(&"icon_focus_color", Color.WHITE) 813 + 814 + var style_box_empty: StyleBoxEmpty = StyleBoxEmpty.new() 815 + btn.add_theme_stylebox_override(&"normal", style_box_empty) 816 + 817 + var style_box: StyleBoxFlat = StyleBoxFlat.new() 818 + style_box.draw_center = false 819 + style_box.border_color = get_editor_accent_color() 820 + style_box.set_border_width_all(1 * get_editor_scale()) 821 + style_box.set_corner_radius_all(get_editor_corner_radius() * get_editor_scale()) 822 + btn.add_theme_stylebox_override(&"focus", style_box) 823 + 824 + return btn 825 + 826 + func on_right_click(event: InputEvent, btn: Button): 827 + if !(event is InputEventMouseButton): 828 + return 829 + 830 + var mouse_event: InputEventMouseButton = event 831 + 832 + if (!mouse_event.is_pressed() || mouse_event.button_index != MOUSE_BUTTON_RIGHT): 833 + return 834 + 835 + btn.button_pressed = true 836 + 837 + var pressed_state: bool = false 838 + for child: Node in filter_box.get_children(): 839 + var other_btn: Button = child 840 + 841 + if (btn != other_btn): 842 + pressed_state = pressed_state || other_btn.button_pressed 843 + 844 + for child: Node in filter_box.get_children(): 845 + var other_btn: Button = child 846 + 847 + if (btn != other_btn): 848 + other_btn.button_pressed = !pressed_state 849 + 850 + outline_filter_txt.grab_focus() 851 + 852 + func on_filter_button_pressed(pressed: bool, btn: Button): 853 + set_setting(btn.get_meta(&"property"), pressed) 854 + 855 + update_outline() 856 + outline_filter_txt.grab_focus() 857 + 858 + func update_outline_position(): 859 + if (is_outline_right): 860 + # Try to restore the previous split offset. 861 + var split_offset: float = split_container.get_child(1).size.x 862 + split_container.split_offset = split_offset 863 + split_container.move_child(outline_container, 1) 864 + else: 865 + split_container.move_child(outline_container, 0) 866 + 867 + func update_script_list_visibility(): 868 + scripts_item_list.get_parent().visible = is_script_list_visible 869 + 870 + func create_editor_texture(texture: Texture2D) -> Texture2D: 871 + var image: Image = texture.get_image().duplicate() 872 + image.adjust_bcs(1.0, 1.0, get_editor_icon_saturation()) 873 + 874 + return ImageTexture.create_from_image(image) 875 + 876 + func sync_settings(): 877 + if (suppress_settings_sync): 878 + return 879 + 880 + var changed_settings: PackedStringArray = get_editor_settings().get_changed_settings() 881 + for setting: String in changed_settings: 882 + if (setting == "interface/theme/icon_saturation"): 883 + init_icons() 884 + engine_func_btn.icon = engine_func_icon 885 + func_btn.icon = func_icon 886 + signal_btn.icon = signal_icon 887 + export_btn.icon = export_icon 888 + property_btn.icon = property_icon 889 + class_btn.icon = class_icon 890 + constant_btn.icon = constant_icon 891 + update_outline() 892 + continue 893 + 894 + if (!setting.begins_with(SCRIPT_IDE)): 895 + continue 896 + 897 + if (setting == OUTLINE_POSITION_RIGHT): 898 + var new_outline_right: bool = get_setting(OUTLINE_POSITION_RIGHT, is_outline_right) 899 + if (new_outline_right != is_outline_right): 900 + is_outline_right = new_outline_right 901 + 902 + update_outline_position() 903 + elif (setting == OUTLINE_ORDER): 904 + update_outline_order() 905 + update_outline_button_order() 906 + update_outline() 907 + elif (setting == HIDE_PRIVATE_MEMBERS): 908 + var new_hide_private_members: bool = get_setting(HIDE_PRIVATE_MEMBERS, hide_private_members) 909 + if (new_hide_private_members != hide_private_members): 910 + hide_private_members = new_hide_private_members 911 + 912 + update_outline_cache() 913 + update_outline() 914 + elif (setting == SCRIPT_LIST_VISIBLE): 915 + var new_script_list_visible: bool = get_setting(SCRIPT_LIST_VISIBLE, is_script_list_visible) 916 + if (new_script_list_visible != is_script_list_visible): 917 + is_script_list_visible = new_script_list_visible 918 + 919 + update_script_list_visibility() 920 + elif (setting == SCRIPT_TABS_VISIBLE): 921 + var new_script_tabs_visible: bool = get_setting(SCRIPT_TABS_VISIBLE, is_script_tabs_visible) 922 + if (new_script_tabs_visible != is_script_tabs_visible): 923 + is_script_tabs_visible = new_script_tabs_visible 924 + 925 + scripts_tab_container.tabs_visible = is_script_tabs_visible 926 + elif (setting == SCRIPT_TAB_POSITION_TOP): 927 + var new_script_tabs_top: bool = get_setting(SCRIPT_TAB_POSITION_TOP, is_script_tabs_top) 928 + if (new_script_tabs_top != is_script_tabs_top): 929 + is_script_tabs_top = new_script_tabs_top 930 + 931 + update_tabs_position() 932 + elif (setting == AUTO_NAVIGATE_IN_FS): 933 + is_auto_navigate_in_fs = get_setting(AUTO_NAVIGATE_IN_FS, is_auto_navigate_in_fs) 934 + elif (setting == OPEN_OUTLINE_POPUP): 935 + open_outline_popup_shc = get_shortcut(OPEN_OUTLINE_POPUP) 936 + elif (setting == OPEN_SCRIPTS_POPUP): 937 + open_scripts_popup_shc = get_shortcut(OPEN_SCRIPTS_POPUP) 938 + elif (setting == TAB_CYCLE_FORWARD): 939 + tab_cycle_forward_shc = get_shortcut(TAB_CYCLE_FORWARD) 940 + elif (setting == TAB_CYCLE_BACKWARD): 941 + tab_cycle_backward_shc = get_shortcut(TAB_CYCLE_BACKWARD) 942 + else: 943 + # Update filter buttons. 944 + for btn_node: Node in filter_box.get_children(): 945 + var btn: Button = btn_node 946 + var property: StringName = btn.get_meta(&"property") 947 + 948 + btn.button_pressed = get_setting(property, btn.button_pressed) 949 + 950 + func get_setting(property: StringName, alt: bool) -> bool: 951 + var editor_settings: EditorSettings = get_editor_settings() 952 + if (editor_settings.has_setting(property)): 953 + return editor_settings.get_setting(property) 954 + else: 955 + editor_settings.set_setting(property, alt) 956 + return alt 957 + 958 + func set_setting(property: StringName, value: bool): 959 + var editor_settings: EditorSettings = get_editor_settings() 960 + 961 + suppress_settings_sync = true 962 + editor_settings.set_setting(property, value) 963 + suppress_settings_sync = false 964 + 965 + func get_shortcut(property: StringName) -> Shortcut: 966 + return get_editor_settings().get_setting(property) 967 + 968 + func on_tab_changed(index: int): 969 + selected_tab = index; 970 + 971 + if (old_script_editor_base != null): 972 + old_script_editor_base.edited_script_changed.disconnect(update_selected_tab) 973 + old_script_editor_base = null 974 + 975 + var script_editor: ScriptEditor = EditorInterface.get_script_editor() 976 + var script_editor_base: ScriptEditorBase = script_editor.get_current_editor() 977 + 978 + if (script_editor_base != null): 979 + script_editor_base.edited_script_changed.connect(update_selected_tab) 980 + 981 + old_script_editor_base = script_editor_base 982 + 983 + sync_script_list = true 984 + 985 + if (is_auto_navigate_in_fs && script_editor.get_current_script() != null): 986 + var file: String = script_editor.get_current_script().get_path() 987 + 988 + if (file.contains(BUILT_IN_SCRIPT)): 989 + # We navigate to the scene in case of a built-in script. 990 + file = file.get_slice(BUILT_IN_SCRIPT, 0) 991 + 992 + file_to_navigate = file 993 + else: 994 + file_to_navigate = &"" 995 + 996 + schedule_update() 997 + 998 + func update_selected_tab(): 999 + if (selected_tab == -1): 1000 + return 1001 + 1002 + if (scripts_item_list.item_count == 0): 1003 + return 1004 + 1005 + update_tab(selected_tab) 1006 + 1007 + func update_tabs(): 1008 + for index: int in scripts_tab_container.get_tab_count(): 1009 + update_tab(index) 1010 + 1011 + func update_tab(index: int): 1012 + scripts_tab_container.set_tab_title(index, scripts_item_list.get_item_text(index)) 1013 + scripts_tab_container.set_tab_icon(index, scripts_item_list.get_item_icon(index)) 1014 + scripts_tab_container.set_tab_tooltip(index, scripts_item_list.get_item_tooltip(index)) 1015 + 1016 + func update_tabs_position(): 1017 + if (is_script_tabs_top): 1018 + scripts_tab_container.tabs_position = TabContainer.POSITION_TOP 1019 + else: 1020 + scripts_tab_container.tabs_position = TabContainer.POSITION_BOTTOM 1021 + 1022 + func update_keywords(script: Script): 1023 + if (script == null): 1024 + return 1025 + 1026 + var new_script_type: StringName = script.get_instance_base_type() 1027 + if (old_script_type != new_script_type): 1028 + old_script_type = new_script_type 1029 + 1030 + keywords.clear() 1031 + keywords["_static_init"] = 0 1032 + register_virtual_methods(new_script_type) 1033 + 1034 + func register_virtual_methods(clazz: String): 1035 + for method: Dictionary in ClassDB.class_get_method_list(clazz): 1036 + if method.flags & METHOD_FLAG_VIRTUAL > 0: 1037 + keywords[method.name] = 0 1038 + 1039 + func update_outline_cache(): 1040 + outline_cache = null 1041 + 1042 + var script: Script = get_current_script() 1043 + if (!script): 1044 + return 1045 + 1046 + update_keywords(script) 1047 + 1048 + # Check if built-in script. In this case we need to duplicate it for whatever reason. 1049 + if (script.get_path().contains(BUILT_IN_SCRIPT)): 1050 + script = script.duplicate() 1051 + 1052 + outline_cache = OutlineCache.new() 1053 + 1054 + # Collect all script members. 1055 + for_each_script_member(script, func(array: Array[String], item: String): array.append(item)) 1056 + 1057 + # Remove script members that only exist in the base script (which includes the base of the base etc.). 1058 + # Note: The method that only collects script members without including the base script(s) 1059 + # is not exposed to GDScript. 1060 + var base_script: Script = script.get_base_script() 1061 + if (base_script != null): 1062 + for_each_script_member(base_script, func(array: Array[String], item: String): array.erase(item)) 1063 + 1064 + func for_each_script_member(script: Script, consumer: Callable): 1065 + # Functions / Methods 1066 + for dict: Dictionary in script.get_script_method_list(): 1067 + var func_name: String = dict[&"name"] 1068 + 1069 + if (keywords.has(func_name)): 1070 + consumer.call(outline_cache.engine_funcs, func_name) 1071 + else: 1072 + if hide_private_members && func_name.begins_with(UNDERSCORE): 1073 + continue 1074 + 1075 + # Inline getter/setter will normally be shown as '@...getter', '@...setter'. 1076 + # Since we already show the variable itself, we will skip those. 1077 + if (func_name.begins_with(INLINE)): 1078 + continue 1079 + 1080 + consumer.call(outline_cache.funcs, func_name) 1081 + 1082 + # Properties / Exported variables 1083 + for dict: Dictionary in script.get_script_property_list(): 1084 + var property: String = dict[&"name"] 1085 + if hide_private_members && property.begins_with(UNDERSCORE): 1086 + continue 1087 + 1088 + var usage: int = dict[&"usage"] 1089 + 1090 + if (usage & PROPERTY_USAGE_SCRIPT_VARIABLE): 1091 + if (usage & PROPERTY_USAGE_STORAGE && usage & PROPERTY_USAGE_EDITOR): 1092 + consumer.call(outline_cache.exports, property) 1093 + else: 1094 + consumer.call(outline_cache.properties, property) 1095 + 1096 + # Static variables (are separated for whatever reason) 1097 + for dict: Dictionary in script.get_property_list(): 1098 + var property: String = dict[&"name"] 1099 + if hide_private_members && property.begins_with(UNDERSCORE): 1100 + continue 1101 + 1102 + var usage: int = dict[&"usage"] 1103 + 1104 + if (usage & PROPERTY_USAGE_SCRIPT_VARIABLE): 1105 + consumer.call(outline_cache.properties, property) 1106 + 1107 + # Signals 1108 + for dict: Dictionary in script.get_script_signal_list(): 1109 + var signal_name: String = dict[&"name"] 1110 + 1111 + consumer.call(outline_cache.signals, signal_name) 1112 + 1113 + # Constants / Classes 1114 + for name_key: String in script.get_script_constant_map(): 1115 + if hide_private_members && name_key.begins_with(UNDERSCORE): 1116 + continue 1117 + 1118 + var object: Variant = script.get_script_constant_map().get(name_key) 1119 + # Inner classes have no source code, while a const of type GDScript has. 1120 + if (object is GDScript && !object.has_source_code()): 1121 + consumer.call(outline_cache.classes, name_key) 1122 + else: 1123 + consumer.call(outline_cache.constants, name_key) 1124 + 1125 + func update_outline(): 1126 + outline.clear() 1127 + 1128 + if (outline_cache == null): 1129 + return 1130 + 1131 + for outline_type: OutlineType in outline_type_order: 1132 + outline_type.add_to_outline.call() 1133 + 1134 + func add_to_outline(items: Array[String], icon: Texture2D, type: String, modifier: StringName = &""): 1135 + add_to_outline_ext(items, func(str: String): return icon, type, modifier) 1136 + 1137 + func add_to_outline_ext(items: Array[String], icon_callable: Callable, type: String, modifier: StringName = &""): 1138 + var text: String = outline_filter_txt.get_text() 1139 + 1140 + if (is_sorted()): 1141 + items = items.duplicate() 1142 + items.sort_custom(func(str1: String, str2: String): return str1.naturalnocasecmp_to(str2) < 0) 1143 + 1144 + for item: String in items: 1145 + if (text.is_empty() || text.is_subsequence_ofn(item)): 1146 + var icon: Texture2D = icon_callable.call(item) 1147 + outline.add_item(item, icon, true) 1148 + 1149 + var dict: Dictionary = { 1150 + &"type": type, 1151 + &"modifier": modifier 1152 + } 1153 + outline.set_item_metadata(outline.item_count - 1, dict) 1154 + 1155 + func get_func_icon(func_name: String) -> Texture2D: 1156 + var icon: Texture2D = func_icon 1157 + if (func_name.begins_with(GETTER)): 1158 + icon = func_get_icon 1159 + elif (func_name.begins_with(SETTER)): 1160 + icon = func_set_icon 1161 + 1162 + return icon 1163 + 1164 + func sync_tab_with_script_list(): 1165 + # For some reason the selected tab is wrong. Looks like a Godot bug. 1166 + if (selected_tab >= scripts_item_list.item_count): 1167 + selected_tab = scripts_tab_bar.current_tab 1168 + 1169 + # Hide filter and outline for non .gd scripts. 1170 + var is_script: bool = get_current_script() != null 1171 + filter_box.visible = is_script 1172 + outline.visible = is_script 1173 + 1174 + # Sync with script item list. 1175 + if (selected_tab != -1 && scripts_item_list.item_count > 0 && !scripts_item_list.is_selected(selected_tab)): 1176 + scripts_item_list.select(selected_tab) 1177 + scripts_item_list.item_selected.emit(selected_tab) 1178 + 1179 + scripts_item_list.ensure_current_is_visible() 1180 + 1181 + func on_tab_bar_mouse_exited(): 1182 + last_tab_hovered = -1 1183 + 1184 + func on_tab_hovered(idx: int): 1185 + last_tab_hovered = idx 1186 + 1187 + func on_tab_bar_gui_input(event: InputEvent): 1188 + if (last_tab_hovered == -1): 1189 + return 1190 + 1191 + if (event is InputEventMouseButton): 1192 + if event.is_pressed() and event.button_index == MOUSE_BUTTON_MIDDLE: 1193 + update_script_text_filter() 1194 + simulate_item_clicked(last_tab_hovered, MOUSE_BUTTON_MIDDLE) 1195 + 1196 + if (last_tab_hovered >= scripts_tab_bar.tab_count - 1): 1197 + last_tab_hovered = -1 1198 + 1199 + func on_active_tab_rearranged(idx_to: int): 1200 + var control: Control = scripts_tab_container.get_tab_control(selected_tab) 1201 + if (!control): 1202 + return 1203 + 1204 + scripts_tab_container.move_child(control, idx_to) 1205 + scripts_tab_container.current_tab = scripts_tab_container.current_tab 1206 + selected_tab = scripts_tab_container.current_tab 1207 + 1208 + func get_res_path(idx: int) -> String: 1209 + var tab_control: Control = scripts_tab_container.get_tab_control(idx) 1210 + if (tab_control == null): 1211 + return '' 1212 + 1213 + var path_var: Variant = tab_control.get(&"metadata/_edit_res_path") 1214 + if (path_var == null): 1215 + return '' 1216 + 1217 + return path_var 1218 + 1219 + func on_tab_rmb(tab_idx: int): 1220 + update_script_text_filter() 1221 + simulate_item_clicked(tab_idx, MOUSE_BUTTON_RIGHT) 1222 + 1223 + func on_tab_close(tab_idx: int): 1224 + update_script_text_filter() 1225 + simulate_item_clicked(tab_idx, MOUSE_BUTTON_MIDDLE) 1226 + 1227 + func simulate_item_clicked(tab_idx: int, mouse_idx: int): 1228 + scripts_item_list.item_clicked.emit(tab_idx, scripts_item_list.get_local_mouse_position(), mouse_idx) 1229 + 1230 + func get_editor_scale() -> float: 1231 + return EditorInterface.get_editor_scale() 1232 + 1233 + func get_editor_corner_radius() -> int: 1234 + return EditorInterface.get_editor_settings().get_setting("interface/theme/corner_radius") 1235 + 1236 + func get_editor_accent_color() -> Color: 1237 + return EditorInterface.get_editor_settings().get_setting("interface/theme/accent_color") 1238 + 1239 + func get_editor_icon_saturation() -> float: 1240 + return EditorInterface.get_editor_settings().get_setting("interface/theme/icon_saturation") 1241 + 1242 + func is_sorted() -> bool: 1243 + return get_editor_settings().get_setting("text_editor/script_list/sort_members_outline_alphabetically") 1244 + 1245 + func get_editor_settings() -> EditorSettings: 1246 + return EditorInterface.get_editor_settings() 1247 + 1248 + func load_rel(path: String) -> Variant: 1249 + var script_path: String = get_script().get_path().get_base_dir() 1250 + return load(script_path.path_join(path)) 1251 + 1252 + static func find_or_null(arr: Array[Node], index: int = 0) -> Node: 1253 + if (arr.is_empty()): 1254 + push_error("""Node that is needed for Script-IDE not found. 1255 + Plugin will not work correctly. 1256 + This might be due to some other plugins or changes in the Engine. 1257 + Please report this to Script-IDE, so we can figure out a fix.""") 1258 + return null 1259 + return arr[index] 1260 + 1261 + ## Cache for everything inside we collected to show in the Outline. 1262 + class OutlineCache: 1263 + var classes: Array[String] = [] 1264 + var constants: Array[String] = [] 1265 + var signals: Array[String] = [] 1266 + var exports: Array[String] = [] 1267 + var properties: Array[String] = [] 1268 + var funcs: Array[String] = [] 1269 + var engine_funcs: Array[String] = [] 1270 + 1271 + ## Outline type for a concrete button with their items in the Outline. 1272 + class OutlineType: 1273 + var type_name: StringName 1274 + var add_to_outline: Callable 1275 + 1276 + ## Contains everything we modify on the Tab Control. Used to save and restore the behaviour 1277 + ## to keep the Engine in a clean state when the plugin is disabled. 1278 + class TabStateCache: 1279 + var tabs_visible: bool 1280 + var drag_to_rearrange_enabled: bool 1281 + var auto_translate_mode_state: Node.AutoTranslateMode 1282 + var tab_bar_drag_to_rearrange_enabled: bool 1283 + var tab_close_display_policy: TabBar.CloseButtonDisplayPolicy 1284 + var select_with_rmb: bool 1285 + 1286 + func save(tab_container: TabContainer, tab_bar: TabBar): 1287 + if (tab_container != null): 1288 + tabs_visible = tab_container.tabs_visible 1289 + drag_to_rearrange_enabled = tab_container.drag_to_rearrange_enabled 1290 + auto_translate_mode_state = tab_container.auto_translate_mode 1291 + if (tab_bar != null): 1292 + tab_bar_drag_to_rearrange_enabled = tab_bar.drag_to_rearrange_enabled 1293 + tab_close_display_policy = tab_bar.tab_close_display_policy 1294 + select_with_rmb = tab_bar.select_with_rmb 1295 + 1296 + func restore(tab_container: TabContainer, tab_bar: TabBar): 1297 + if (tab_container != null): 1298 + tab_container.tabs_visible = tabs_visible 1299 + tab_container.drag_to_rearrange_enabled = drag_to_rearrange_enabled 1300 + tab_container.auto_translate_mode = auto_translate_mode_state 1301 + if (tab_bar != null): 1302 + tab_bar.drag_to_rearrange_enabled = drag_to_rearrange_enabled 1303 + tab_bar.tab_close_display_policy = tab_close_display_policy 1304 + tab_bar.select_with_rmb = select_with_rmb
+1
addons/script-ide/plugin.gd.uid
··· 1 + uid://d3yufqs7scyb5
+232
addons/script-ide/quickopen/quick_open_panel.gd
··· 1 + ## Quick open panel to quickly access all resources that are in the project. 2 + ## Initially shows all resources, but can be changed to more specific resources 3 + ## or filtered down with text. 4 + @tool 5 + extends PopupPanel 6 + 7 + const ADDONS: StringName = &"res://addons" 8 + const SEPARATOR: StringName = &" - " 9 + const STRUCTURE_START: StringName = &"(" 10 + const STRUCTURE_END: StringName = &")" 11 + 12 + #region UI 13 + @onready var filter_bar: TabBar = %FilterBar 14 + @onready var search_option_btn: OptionButton = %SearchOptionBtn 15 + @onready var filter_txt: LineEdit = %FilterTxt 16 + @onready var files_list: ItemList = %FilesList 17 + #endregion 18 + 19 + var plugin: EditorPlugin 20 + 21 + var scenes: Array[FileData] 22 + var scripts: Array[FileData] 23 + var resources: Array[FileData] 24 + var others: Array[FileData] 25 + 26 + # For performance and memory considerations, we add all files into one reusable array. 27 + var all_files: Array[FileData] 28 + 29 + var is_rebuild_cache: bool = true 30 + 31 + #region Plugin and Shortcut processing 32 + func _ready() -> void: 33 + files_list.item_selected.connect(open_file) 34 + search_option_btn.item_selected.connect(rebuild_cache_and_ui.unbind(1)) 35 + filter_txt.text_changed.connect(fill_files_list.unbind(1)) 36 + 37 + filter_bar.tab_changed.connect(change_fill_files_list.unbind(1)) 38 + 39 + about_to_popup.connect(on_show) 40 + 41 + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() 42 + file_system.filesystem_changed.connect(schedule_rebuild) 43 + 44 + if (plugin != null): 45 + filter_txt.gui_input.connect(plugin.navigate_on_list.bind(files_list, open_file)) 46 + 47 + func _shortcut_input(event: InputEvent) -> void: 48 + if (!event.is_pressed() || event.is_echo()): 49 + return 50 + 51 + if (plugin == null): 52 + return 53 + 54 + if (plugin.tab_cycle_forward_shc.matches_event(event)): 55 + get_viewport().set_input_as_handled() 56 + 57 + var new_tab: int = filter_bar.current_tab + 1 58 + if (new_tab == filter_bar.get_tab_count()): 59 + new_tab = 0 60 + filter_bar.current_tab = new_tab 61 + elif (plugin.tab_cycle_backward_shc.matches_event(event)): 62 + get_viewport().set_input_as_handled() 63 + 64 + var new_tab: int = filter_bar.current_tab - 1 65 + if (new_tab == -1): 66 + new_tab = filter_bar.get_tab_count() - 1 67 + filter_bar.current_tab = new_tab 68 + #endregion 69 + 70 + func open_file(index: int): 71 + hide() 72 + 73 + var file: String = files_list.get_item_metadata(index) 74 + 75 + if (ResourceLoader.exists(file)): 76 + var res: Resource = load(file) 77 + EditorInterface.edit_resource(res) 78 + 79 + if (res is PackedScene): 80 + EditorInterface.open_scene_from_path(file) 81 + 82 + func schedule_rebuild(): 83 + is_rebuild_cache = true 84 + 85 + func on_show(): 86 + if (search_option_btn.selected != 0): 87 + search_option_btn.selected = 0 88 + 89 + is_rebuild_cache = true 90 + 91 + var rebuild_ui: bool = false 92 + var all_tab_not_pressed: bool = filter_bar.current_tab != 0 93 + rebuild_ui = is_rebuild_cache || all_tab_not_pressed 94 + 95 + if (is_rebuild_cache): 96 + rebuild_cache() 97 + 98 + if (rebuild_ui): 99 + if (all_tab_not_pressed): 100 + # Triggers the ui update. 101 + filter_bar.current_tab = 0 102 + else: 103 + fill_files_list() 104 + 105 + filter_txt.select_all() 106 + focus_and_select_first() 107 + 108 + func rebuild_cache(): 109 + is_rebuild_cache = false 110 + 111 + all_files.clear() 112 + scenes.clear() 113 + scripts.clear() 114 + resources.clear() 115 + others.clear() 116 + 117 + build_file_cache() 118 + 119 + func rebuild_cache_and_ui(): 120 + rebuild_cache() 121 + fill_files_list() 122 + 123 + focus_and_select_first() 124 + 125 + func focus_and_select_first(): 126 + filter_txt.grab_focus() 127 + 128 + if (files_list.item_count > 0): 129 + files_list.select(0) 130 + 131 + func build_file_cache(): 132 + var dir: EditorFileSystemDirectory = EditorInterface.get_resource_filesystem().get_filesystem() 133 + build_file_cache_dir(dir) 134 + 135 + all_files.append_array(scenes) 136 + all_files.append_array(scripts) 137 + all_files.append_array(resources) 138 + all_files.append_array(others) 139 + 140 + func build_file_cache_dir(dir: EditorFileSystemDirectory): 141 + for index: int in dir.get_subdir_count(): 142 + build_file_cache_dir(dir.get_subdir(index)) 143 + 144 + for index: int in dir.get_file_count(): 145 + var file: String = dir.get_file_path(index) 146 + if (search_option_btn.get_selected_id() == 0 && file.begins_with(ADDONS)): 147 + continue 148 + 149 + var last_delimiter: int = file.rfind(&"/") 150 + 151 + var file_name: String = file.substr(last_delimiter + 1) 152 + var file_structure: String = &"" 153 + if (file_name.length() + 6 != file.length()): 154 + file_structure = SEPARATOR + STRUCTURE_START + file.substr(6, last_delimiter - 6) + STRUCTURE_END 155 + 156 + var file_data: FileData = FileData.new() 157 + file_data.file = file 158 + file_data.file_name = file_name 159 + file_data.file_name_structure = file_name + file_structure 160 + file_data.file_type = dir.get_file_type(index) 161 + 162 + # Needed, as otherwise we have no icon. 163 + if (file_data.file_type == &"Resource"): 164 + file_data.file_type = &"Object" 165 + 166 + match (file.get_extension()): 167 + &"tscn": scenes.append(file_data) 168 + &"gd": scripts.append(file_data) 169 + &"tres": resources.append(file_data) 170 + &"gdshader": resources.append(file_data) 171 + _: others.append(file_data) 172 + 173 + func change_fill_files_list(): 174 + fill_files_list() 175 + 176 + focus_and_select_first() 177 + 178 + func fill_files_list(): 179 + files_list.clear() 180 + 181 + if (filter_bar.current_tab == 0): 182 + fill_files_list_with(all_files) 183 + elif (filter_bar.current_tab == 1): 184 + fill_files_list_with(scenes) 185 + elif (filter_bar.current_tab == 2): 186 + fill_files_list_with(scripts) 187 + elif (filter_bar.current_tab == 3): 188 + fill_files_list_with(resources) 189 + elif (filter_bar.current_tab == 4): 190 + fill_files_list_with(others) 191 + 192 + func fill_files_list_with(files: Array[FileData]): 193 + var filter_text: String = filter_txt.text 194 + files.sort_custom(sort_by_filter) 195 + 196 + for file_data: FileData in files: 197 + var file: String = file_data.file 198 + if (filter_text.is_empty() || filter_text.is_subsequence_ofn(file)): 199 + var icon: Texture2D = EditorInterface.get_base_control().get_theme_icon(file_data.file_type, &"EditorIcons") 200 + 201 + files_list.add_item(file_data.file_name_structure, icon) 202 + files_list.set_item_metadata(files_list.item_count - 1, file) 203 + files_list.set_item_tooltip(files_list.item_count - 1, file) 204 + 205 + func sort_by_filter(a: FileData, b: FileData) -> bool: 206 + var filter_text: String = filter_txt.text 207 + var a_name: String = a.file_name 208 + var b_name: String = b.file_name 209 + 210 + for index: int in filter_text.length(): 211 + if (index >= a_name.length()): 212 + return true 213 + if (index >= b_name.length()): 214 + return false 215 + 216 + var char: String = filter_text[index] 217 + var a_match: bool = char== a_name[index] 218 + var b_match: bool = char == b_name[index] 219 + 220 + if (a_match && !b_match): 221 + return true 222 + 223 + if (b_match && !a_match): 224 + return false 225 + 226 + return a_name < b_name 227 + 228 + class FileData: 229 + var file: String 230 + var file_name: String 231 + var file_name_structure: String 232 + var file_type: StringName
+1
addons/script-ide/quickopen/quick_open_panel.gd.uid
··· 1 + uid://bw2hcwsfw1ynl
+148
addons/script-ide/quickopen/quick_open_panel.tscn
··· 1 + [gd_scene load_steps=14 format=3 uid="uid://d2pttchmj3n7q"] 2 + 3 + [ext_resource type="Script" path="res://addons/script-ide/quickopen/quick_open_panel.gd" id="1_3tl1s"] 4 + 5 + [sub_resource type="Image" id="Image_dfysb"] 6 + data = { 7 + "data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 16, 225, 225, 225, 134, 224, 224, 224, 209, 224, 224, 224, 245, 224, 224, 224, 245, 224, 224, 224, 208, 224, 224, 224, 131, 236, 236, 236, 13, 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, 224, 224, 224, 73, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 225, 225, 225, 68, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 73, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 183, 224, 224, 224, 198, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 198, 224, 224, 224, 189, 224, 224, 224, 255, 224, 224, 224, 254, 224, 224, 224, 65, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 16, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 120, 226, 226, 226, 60, 224, 224, 224, 255, 225, 225, 225, 109, 225, 225, 225, 110, 224, 224, 224, 255, 226, 226, 226, 60, 224, 224, 224, 128, 224, 224, 224, 255, 225, 225, 225, 223, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 134, 224, 224, 224, 255, 225, 225, 225, 183, 255, 255, 255, 0, 224, 224, 224, 153, 224, 224, 224, 243, 255, 255, 255, 4, 255, 255, 255, 4, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 1, 225, 225, 225, 191, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 209, 224, 224, 224, 255, 224, 224, 224, 72, 255, 255, 255, 0, 224, 224, 224, 216, 224, 224, 224, 198, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 199, 224, 224, 224, 214, 255, 255, 255, 0, 226, 226, 226, 78, 224, 224, 224, 255, 224, 224, 224, 206, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 243, 224, 224, 224, 255, 226, 226, 226, 78, 255, 255, 255, 0, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 152, 224, 224, 224, 242, 255, 255, 255, 1, 227, 227, 227, 81, 224, 224, 224, 255, 224, 224, 224, 241, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 245, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 229, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 147, 225, 225, 225, 149, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 230, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 244, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 208, 224, 224, 224, 255, 224, 224, 224, 147, 224, 224, 224, 161, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 235, 224, 224, 224, 235, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 160, 225, 225, 225, 150, 224, 224, 224, 255, 224, 224, 224, 205, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 189, 255, 255, 255, 1, 224, 224, 224, 152, 224, 224, 224, 243, 255, 255, 255, 4, 255, 255, 255, 4, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 2, 225, 225, 225, 199, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 236, 236, 236, 13, 224, 224, 224, 225, 224, 224, 224, 255, 224, 224, 224, 128, 225, 225, 225, 67, 224, 224, 224, 255, 225, 225, 225, 110, 226, 226, 226, 111, 224, 224, 224, 255, 225, 225, 225, 67, 225, 225, 225, 135, 224, 224, 224, 255, 224, 224, 224, 221, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 68, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 194, 224, 224, 224, 220, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 219, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 253, 227, 227, 227, 62, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 66, 224, 224, 224, 225, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 226, 226, 226, 61, 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, 237, 237, 237, 14, 224, 224, 224, 130, 224, 224, 224, 206, 224, 224, 224, 244, 224, 224, 224, 244, 224, 224, 224, 205, 225, 225, 225, 124, 230, 230, 230, 10, 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, 255, 255, 255, 0, 255, 255, 255, 0), 8 + "format": "RGBA8", 9 + "height": 16, 10 + "mipmaps": false, 11 + "width": 16 12 + } 13 + 14 + [sub_resource type="ImageTexture" id="ImageTexture_p6ab8"] 15 + image = SubResource("Image_dfysb") 16 + 17 + [sub_resource type="Image" id="Image_blafy"] 18 + data = { 19 + "data": PackedByteArray(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, 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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 25, 226, 226, 226, 70, 229, 229, 229, 39, 255, 255, 255, 0, 226, 226, 226, 103, 224, 224, 224, 219, 224, 224, 224, 156, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 25, 255, 255, 255, 0, 224, 224, 224, 74, 224, 224, 224, 177, 226, 226, 226, 111, 255, 255, 255, 0, 224, 224, 224, 98, 224, 224, 224, 255, 225, 225, 225, 182, 255, 255, 255, 0, 228, 228, 228, 46, 224, 224, 224, 255, 224, 224, 224, 197, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 255, 224, 224, 224, 187, 255, 255, 255, 0, 225, 225, 225, 42, 224, 224, 224, 255, 224, 224, 224, 232, 255, 255, 255, 6, 224, 224, 224, 8, 225, 225, 225, 182, 224, 224, 224, 153, 255, 255, 255, 7, 255, 255, 255, 0, 228, 228, 228, 37, 255, 255, 255, 7, 255, 255, 255, 0, 229, 229, 229, 19, 224, 224, 224, 237, 224, 224, 224, 198, 225, 225, 225, 17, 255, 255, 255, 0, 227, 227, 227, 71, 224, 224, 224, 48, 255, 255, 255, 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, 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, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 73, 224, 224, 224, 226, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 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), 20 + "format": "RGBA8", 21 + "height": 16, 22 + "mipmaps": false, 23 + "width": 16 24 + } 25 + 26 + [sub_resource type="ImageTexture" id="ImageTexture_bbwjp"] 27 + image = SubResource("Image_blafy") 28 + 29 + [sub_resource type="Image" id="Image_4wc14"] 30 + data = { 31 + "data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 33, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 31, 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, 226, 226, 226, 95, 224, 224, 224, 57, 255, 255, 255, 0, 224, 224, 224, 99, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 93, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 90, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 93, 224, 224, 224, 255, 224, 224, 224, 254, 224, 224, 224, 165, 224, 224, 224, 217, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 214, 225, 225, 225, 167, 224, 224, 224, 254, 224, 224, 224, 254, 224, 224, 224, 88, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 228, 228, 228, 55, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 166, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 160, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 33, 224, 224, 224, 99, 224, 224, 224, 217, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 186, 224, 224, 224, 32, 224, 224, 224, 33, 224, 224, 224, 187, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 98, 224, 224, 224, 32, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 229, 229, 229, 38, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 31, 226, 226, 226, 95, 224, 224, 224, 216, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 187, 225, 225, 225, 34, 226, 226, 226, 35, 224, 224, 224, 192, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 226, 226, 226, 95, 231, 231, 231, 31, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 166, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 163, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 254, 227, 227, 227, 54, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 90, 224, 224, 224, 254, 224, 224, 224, 253, 224, 224, 224, 161, 225, 225, 225, 215, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 224, 224, 224, 162, 224, 224, 224, 253, 224, 224, 224, 253, 226, 226, 226, 86, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 88, 225, 225, 225, 51, 255, 255, 255, 0, 224, 224, 224, 98, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 95, 255, 255, 255, 0, 227, 227, 227, 53, 226, 226, 226, 86, 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, 224, 224, 224, 32, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 31, 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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), 32 + "format": "RGBA8", 33 + "height": 16, 34 + "mipmaps": false, 35 + "width": 16 36 + } 37 + 38 + [sub_resource type="ImageTexture" id="ImageTexture_ghict"] 39 + image = SubResource("Image_4wc14") 40 + 41 + [sub_resource type="Image" id="Image_7rebo"] 42 + data = { 43 + "data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 99, 224, 224, 224, 213, 224, 224, 224, 212, 224, 224, 224, 97, 255, 255, 255, 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, 4, 224, 224, 224, 99, 224, 224, 224, 222, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 224, 224, 224, 97, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 99, 224, 224, 224, 222, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 226, 226, 226, 87, 224, 224, 224, 88, 224, 224, 224, 214, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 224, 224, 224, 97, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 199, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 89, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 90, 224, 224, 224, 216, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 194, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 221, 224, 224, 224, 99, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 101, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 3, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 222, 225, 225, 225, 100, 225, 225, 225, 100, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 3, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 2, 226, 226, 226, 87, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 87, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 1, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 100, 255, 255, 255, 5, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 225, 225, 225, 101, 255, 255, 255, 5, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 193, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 3, 225, 225, 225, 93, 224, 224, 224, 218, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 216, 225, 225, 225, 91, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 3, 225, 225, 225, 93, 224, 224, 224, 218, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 216, 225, 225, 225, 91, 255, 255, 255, 2, 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, 3, 225, 225, 225, 93, 224, 224, 224, 208, 225, 225, 225, 207, 225, 225, 225, 91, 255, 255, 255, 2, 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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), 44 + "format": "RGBA8", 45 + "height": 16, 46 + "mipmaps": false, 47 + "width": 16 48 + } 49 + 50 + [sub_resource type="ImageTexture" id="ImageTexture_grjtr"] 51 + image = SubResource("Image_7rebo") 52 + 53 + [sub_resource type="Image" id="Image_e7nb8"] 54 + data = { 55 + "data": PackedByteArray(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, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 181, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 77, 225, 225, 225, 76, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 8, 224, 224, 224, 222, 224, 224, 224, 221, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 120, 224, 224, 224, 32, 224, 224, 224, 128, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 226, 226, 226, 35, 224, 224, 224, 248, 224, 224, 224, 195, 224, 224, 224, 247, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 247, 225, 225, 225, 34, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 178, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 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), 56 + "format": "RGBA8", 57 + "height": 16, 58 + "mipmaps": false, 59 + "width": 16 60 + } 61 + 62 + [sub_resource type="ImageTexture" id="ImageTexture_xupch"] 63 + image = SubResource("Image_e7nb8") 64 + 65 + [sub_resource type="Image" id="Image_gfvg1"] 66 + data = { 67 + "data": PackedByteArray(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, 255, 255, 255, 0, 225, 225, 225, 68, 224, 224, 224, 184, 224, 224, 224, 240, 224, 224, 224, 232, 224, 224, 224, 186, 227, 227, 227, 62, 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, 224, 224, 224, 129, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 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, 225, 225, 225, 68, 224, 224, 224, 254, 224, 224, 224, 254, 224, 224, 224, 123, 224, 224, 224, 32, 224, 224, 224, 33, 225, 225, 225, 125, 224, 224, 224, 254, 224, 224, 224, 254, 226, 226, 226, 69, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 123, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 125, 224, 224, 224, 255, 225, 225, 225, 174, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 240, 224, 224, 224, 255, 231, 231, 231, 31, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 35, 224, 224, 224, 255, 224, 224, 224, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 232, 224, 224, 224, 255, 224, 224, 224, 32, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 228, 228, 228, 37, 224, 224, 224, 255, 224, 224, 224, 228, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 186, 224, 224, 224, 255, 224, 224, 224, 123, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 130, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 62, 224, 224, 224, 255, 224, 224, 224, 254, 225, 225, 225, 126, 225, 225, 225, 34, 227, 227, 227, 36, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 77, 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, 224, 224, 224, 122, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 226, 226, 226, 69, 225, 225, 225, 174, 224, 224, 224, 233, 224, 224, 224, 228, 224, 224, 224, 173, 226, 226, 226, 77, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 227, 225, 225, 225, 34, 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, 231, 231, 231, 21, 225, 225, 225, 34, 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), 68 + "format": "RGBA8", 69 + "height": 16, 70 + "mipmaps": false, 71 + "width": 16 72 + } 73 + 74 + [sub_resource type="ImageTexture" id="ImageTexture_w6vkw"] 75 + image = SubResource("Image_gfvg1") 76 + 77 + [node name="QuickOpenPanel" type="PopupPanel"] 78 + size = Vector2i(624, 100) 79 + visible = true 80 + script = ExtResource("1_3tl1s") 81 + 82 + [node name="PanelContainer" type="PanelContainer" parent="."] 83 + anchors_preset = 15 84 + anchor_right = 1.0 85 + anchor_bottom = 1.0 86 + offset_left = 4.0 87 + offset_top = 4.0 88 + offset_right = -4.0 89 + offset_bottom = -4.0 90 + grow_horizontal = 2 91 + grow_vertical = 2 92 + size_flags_horizontal = 3 93 + size_flags_vertical = 3 94 + 95 + [node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] 96 + layout_mode = 2 97 + theme_override_constants/margin_left = 5 98 + theme_override_constants/margin_top = 5 99 + theme_override_constants/margin_right = 5 100 + theme_override_constants/margin_bottom = 5 101 + 102 + [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] 103 + layout_mode = 2 104 + theme_override_constants/separation = 5 105 + 106 + [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] 107 + layout_mode = 2 108 + theme_override_constants/separation = 4 109 + 110 + [node name="FilterBar" type="TabBar" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 111 + unique_name_in_owner = true 112 + layout_mode = 2 113 + current_tab = 0 114 + clip_tabs = false 115 + scrolling_enabled = false 116 + tab_count = 5 117 + tab_0/title = "All" 118 + tab_0/icon = SubResource("ImageTexture_p6ab8") 119 + tab_1/title = "Scene" 120 + tab_1/icon = SubResource("ImageTexture_bbwjp") 121 + tab_2/title = "GDscript" 122 + tab_2/icon = SubResource("ImageTexture_ghict") 123 + tab_3/title = "Resource" 124 + tab_3/icon = SubResource("ImageTexture_grjtr") 125 + tab_4/title = "Other" 126 + tab_4/icon = SubResource("ImageTexture_xupch") 127 + 128 + [node name="SearchOptionBtn" type="OptionButton" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 129 + unique_name_in_owner = true 130 + layout_mode = 2 131 + selected = 0 132 + item_count = 2 133 + popup/item_0/text = "Project" 134 + popup/item_0/id = 0 135 + popup/item_1/text = "Project+Addons" 136 + popup/item_1/id = 1 137 + 138 + [node name="FilterTxt" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"] 139 + unique_name_in_owner = true 140 + layout_mode = 2 141 + placeholder_text = "Filter files" 142 + right_icon = SubResource("ImageTexture_w6vkw") 143 + 144 + [node name="FilesList" type="ItemList" parent="PanelContainer/MarginContainer/VBoxContainer"] 145 + unique_name_in_owner = true 146 + layout_mode = 2 147 + size_flags_vertical = 3 148 + allow_reselect = true
+3 -4
project.godot
··· 39 39 40 40 [editor] 41 41 42 - movie_writer/mjpeg_quality=0.99 43 - version_control/plugin_name="GitPlugin" 44 - version_control/autoload_on_startup=true 42 + movie_writer/mjpeg_quality=0.98 43 + movie_writer/movie_file="res://Movies/movie.avi" 45 44 46 45 [editor_plugins] 47 46 48 - enabled=PackedStringArray("res://addons/TopDownCamera2D/plugin.cfg", "res://addons/gameconsole/plugin.cfg", "res://addons/ggt-core/plugin.cfg", "res://addons/ggt-debug-shortcuts/plugin.cfg") 47 + enabled=PackedStringArray("res://addons/TopDownCamera2D/plugin.cfg", "res://addons/gameconsole/plugin.cfg", "res://addons/ggt-core/plugin.cfg", "res://addons/ggt-debug-shortcuts/plugin.cfg", "res://addons/gwj_accessibility_scripts/plugin.cfg", "res://addons/script-ide/plugin.cfg") 49 48 50 49 [file_customization] 51 50