├── icon.ico ├── assets ├── sprites │ ├── star.png │ ├── folder.png │ ├── download_btn.png │ ├── settings_icon.png │ ├── arrows │ │ ├── arrow_up.png │ │ ├── arrow_down.png │ │ ├── arrow_left.png │ │ ├── arrow_right.png │ │ ├── option_btn.png │ │ ├── arrow_up.png.import │ │ ├── arrow_left.png.import │ │ ├── arrow_down.png.import │ │ ├── arrow_right.png.import │ │ └── option_btn.png.import │ ├── crosses │ │ ├── cross_hover.png │ │ ├── cross_white.png │ │ ├── cross_default.png │ │ ├── cross_hover.png.import │ │ ├── cross_white.png.import │ │ └── cross_default.png.import │ ├── folder_compressed.png │ ├── check_boxes │ │ ├── box_checked.png │ │ ├── box_unchecked.png │ │ ├── box_checked_disabled.png │ │ ├── box_unchecked_disabled.png │ │ ├── box_checked.png.import │ │ ├── box_unchecked.png.import │ │ ├── box_checked_disabled.png.import │ │ └── box_unchecked_disabled.png.import │ ├── check_buttons │ │ ├── btn_checked.png │ │ ├── btn_unchecked.png │ │ ├── btn_checked_disabled.png │ │ ├── btn_checked_mirrored.png │ │ ├── btn_unchecked_disabled.png │ │ ├── btn_unchecked_mirrored.png │ │ ├── btn_check_disabled_mirrored.png │ │ ├── btn_checked_disabled_mirrored.png │ │ ├── btn_unchecked_disabled_mirrored.png │ │ ├── btn_checked.png.import │ │ ├── btn_unchecked.png.import │ │ ├── btn_checked_disabled.png.import │ │ ├── btn_checked_mirrored.png.import │ │ ├── btn_unchecked_disabled.png.import │ │ ├── btn_unchecked_mirrored.png.import │ │ ├── btn_check_disabled_mirrored.png.import │ │ ├── btn_checked_disabled_mirrored.png.import │ │ └── btn_unchecked_disabled_mirrored.png.import │ ├── star.png.import │ ├── folder.png.import │ ├── download_btn.png.import │ ├── settings_icon.png.import │ └── folder_compressed.png.import ├── gdh_splash-screen.png ├── fonts │ ├── JetBrainsMono-Bold.ttf │ ├── JetBrainsMono-Italic.ttf │ ├── JetBrainsMono-Medium.ttf │ ├── JetBrainsMono-Regular.ttf │ ├── JetBrainsMono-ExtraBold.ttf │ ├── JetBrainsMono-Bold-Italic.ttf │ ├── JetBrainsMono-Medium-Italic.ttf │ ├── JetBrainsMono-ExtraBold-Italic.ttf │ ├── JetBrainsMono-Bold.ttf.import │ ├── JetBrainsMono-Italic.ttf.import │ ├── JetBrainsMono-Medium.ttf.import │ ├── JetBrainsMono-Regular.ttf.import │ ├── JetBrainsMono-ExtraBold.ttf.import │ ├── JetBrainsMono-Bold-Italic.ttf.import │ ├── JetBrainsMono-Medium-Italic.ttf.import │ └── JetBrainsMono-ExtraBold-Italic.ttf.import ├── gdh_splash-screen.png.import ├── default_icon.svg.import └── default_icon.svg ├── .gitattributes ├── resources ├── themes │ ├── main.theme │ ├── blue_btn.theme │ ├── close_btn.theme │ ├── settings.theme │ ├── sort_btn.theme │ ├── star_btn.theme │ ├── half_red_btn.theme │ └── half_blue_btn.theme ├── button_groups │ ├── tab_btn_group.tres │ └── install_btn_group.tres └── style_boxes │ ├── hseparator.stylebox │ ├── progress_bg.stylebox │ ├── vseparator.stylebox │ ├── progress_fill.stylebox │ ├── tabs │ ├── tab_disabled.stylebox │ ├── tab_selected.stylebox │ └── tab_unselected.stylebox │ ├── panels │ ├── dark_window.stylebox │ ├── dark_window_bg.stylebox │ ├── hard_dark_panel.stylebox │ ├── mid_dark_panel.stylebox │ ├── soft_dark_panel.stylebox │ └── light_dark_panel.stylebox │ ├── buttons │ ├── red │ │ ├── red_hover.stylebox │ │ └── red_pressed.stylebox │ ├── blue │ │ ├── blue_hover.stylebox │ │ ├── blue_normal.stylebox │ │ ├── blue_disabled.stylebox │ │ └── blue_pressed.stylebox │ ├── transparent_btn.stylebox │ ├── default │ │ ├── default_hover.stylebox │ │ ├── default_disabled.stylebox │ │ ├── default_normal.stylebox │ │ └── default_pressed.stylebox │ ├── star │ │ ├── star_normal.tres │ │ ├── star_hover.tres │ │ ├── star_disabled.tres │ │ └── star_pressed.tres │ ├── close │ │ ├── close_disabled.tres │ │ ├── close_hover.tres │ │ ├── close_normal.tres │ │ └── close_pressed.tres │ └── download │ │ ├── download_disabled.tres │ │ ├── download_hover.tres │ │ ├── download_normal.tres │ │ └── download_pressed.tres │ └── scrolls │ ├── scroll_scroll.stylebox │ ├── scroll_grabber_normal.stylebox │ └── scroll_grabber_highlight.stylebox ├── scripts ├── core │ ├── data │ │ ├── Architecture.cs │ │ ├── OS.cs │ │ ├── GDFile.cs │ │ ├── FullParameterContractResolver.cs │ │ ├── Source.cs │ │ ├── Version.cs │ │ └── ProjectsData.cs │ ├── tabs │ │ ├── projects │ │ │ ├── VersioningMode.cs │ │ │ ├── RenderMode.cs │ │ │ └── ProjectsTabs.cs │ │ ├── SortedPanel.cs │ │ ├── documentation │ │ │ └── DocumentationTab.cs │ │ ├── Tab.cs │ │ ├── UpdateRepoButton.cs │ │ ├── SortToggle.cs │ │ ├── versions │ │ │ ├── VersionsTab.cs │ │ │ ├── ReleasePanel.cs │ │ │ ├── DownloadPanel.cs │ │ │ ├── EnginesPanel.cs │ │ │ └── EngineItem.cs │ │ └── TabManager.cs │ ├── settings │ │ ├── buttons │ │ │ ├── ISettingButton.cs │ │ │ ├── ResetButton.cs │ │ │ ├── toggles │ │ │ │ ├── SettingToggle.cs │ │ │ │ ├── AutoDeleteToggle.cs │ │ │ │ ├── AutoCloseDLToggle.cs │ │ │ │ ├── AutoShortcutToggle.cs │ │ │ │ ├── AutoUpdateToggle.cs │ │ │ │ ├── DebugToggle.cs │ │ │ │ └── SameDirToggle.cs │ │ │ ├── directory │ │ │ │ ├── ProjectDirButton.cs │ │ │ │ ├── InstallDirButton.cs │ │ │ │ ├── DownloadDirButton.cs │ │ │ │ └── DirButton.cs │ │ │ └── SettingButton.cs │ │ └── SettingsPanel.cs │ ├── utils │ │ ├── comparisons │ │ │ ├── INamedItem.cs │ │ │ ├── IMonoItem.cs │ │ │ ├── IValidItem.cs │ │ │ ├── IFavoriteItem.cs │ │ │ ├── ITimedItem.cs │ │ │ ├── IVersionItem.cs │ │ │ └── Comparer.cs │ │ ├── BBCodeT.cs │ │ ├── Error.cs │ │ ├── Colors.cs │ │ ├── TimeFormater.cs │ │ └── PathT.cs │ ├── SplashScreen.cs │ ├── debug │ │ ├── ExceptionHandler.cs │ │ └── Debugger.cs │ └── Main.cs ├── installer │ ├── JumpInstruction.cs │ ├── InstallerConstants.cs │ ├── InstallProgram.cs │ └── AdminInstaller.cs ├── uninstaller │ └── UninstallProgram.cs └── updater │ └── UpdateProgram.cs ├── scenes ├── utils │ └── colors.tscn ├── message_dialog.tscn ├── confirmation_dialog.tscn ├── settings │ └── folder_dialog.tscn ├── sort_button.tscn ├── versions │ ├── subbutton.tscn │ ├── installer.tscn │ ├── release_item.tscn │ └── engine_item.tscn └── projects │ ├── project_item.tscn │ └── new_project_dialog.tscn ├── project.godot ├── icon.svg.import ├── README.md ├── Godot Hub.csproj ├── GodotHubUpdater.csproj ├── GodotUninstaller.csproj ├── GodotInstaller.csproj ├── CHANGELOG.md ├── godot_installer.manifest ├── godot_uninstaller.manifest ├── export_presets.cfg └── icon.svg /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/icon.ico -------------------------------------------------------------------------------- /assets/sprites/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/star.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=crlf 3 | -------------------------------------------------------------------------------- /assets/sprites/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/folder.png -------------------------------------------------------------------------------- /assets/gdh_splash-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/gdh_splash-screen.png -------------------------------------------------------------------------------- /resources/themes/main.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/main.theme -------------------------------------------------------------------------------- /assets/sprites/download_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/download_btn.png -------------------------------------------------------------------------------- /assets/sprites/settings_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/settings_icon.png -------------------------------------------------------------------------------- /resources/themes/blue_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/blue_btn.theme -------------------------------------------------------------------------------- /resources/themes/close_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/close_btn.theme -------------------------------------------------------------------------------- /resources/themes/settings.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/settings.theme -------------------------------------------------------------------------------- /resources/themes/sort_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/sort_btn.theme -------------------------------------------------------------------------------- /resources/themes/star_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/star_btn.theme -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Bold.ttf -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/arrows/arrow_up.png -------------------------------------------------------------------------------- /resources/themes/half_red_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/half_red_btn.theme -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/arrows/arrow_down.png -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/arrows/arrow_left.png -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/arrows/arrow_right.png -------------------------------------------------------------------------------- /assets/sprites/arrows/option_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/arrows/option_btn.png -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/crosses/cross_hover.png -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/crosses/cross_white.png -------------------------------------------------------------------------------- /assets/sprites/folder_compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/folder_compressed.png -------------------------------------------------------------------------------- /resources/themes/half_blue_btn.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/themes/half_blue_btn.theme -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/crosses/cross_default.png -------------------------------------------------------------------------------- /resources/button_groups/tab_btn_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ButtonGroup" format=3 uid="uid://degxsui0oeqmj"] 2 | 3 | [resource] 4 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Bold-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Bold-Italic.ttf -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_boxes/box_checked.png -------------------------------------------------------------------------------- /resources/style_boxes/hseparator.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/hseparator.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/progress_bg.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/progress_bg.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/vseparator.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/vseparator.stylebox -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Medium-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-Medium-Italic.ttf -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_boxes/box_unchecked.png -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_checked.png -------------------------------------------------------------------------------- /resources/style_boxes/progress_fill.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/progress_fill.stylebox -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-ExtraBold-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/fonts/JetBrainsMono-ExtraBold-Italic.ttf -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_unchecked.png -------------------------------------------------------------------------------- /resources/style_boxes/tabs/tab_disabled.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/tabs/tab_disabled.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/tabs/tab_selected.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/tabs/tab_selected.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/dark_window.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/dark_window.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/tabs/tab_unselected.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/tabs/tab_unselected.stylebox -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_checked_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_boxes/box_checked_disabled.png -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_unchecked_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_boxes/box_unchecked_disabled.png -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_checked_disabled.png -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_mirrored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_checked_mirrored.png -------------------------------------------------------------------------------- /resources/style_boxes/buttons/red/red_hover.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/red/red_hover.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/dark_window_bg.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/dark_window_bg.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/hard_dark_panel.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/hard_dark_panel.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/mid_dark_panel.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/mid_dark_panel.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/soft_dark_panel.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/soft_dark_panel.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/scrolls/scroll_scroll.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/scrolls/scroll_scroll.stylebox -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_unchecked_disabled.png -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_mirrored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_unchecked_mirrored.png -------------------------------------------------------------------------------- /resources/style_boxes/buttons/blue/blue_hover.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/blue/blue_hover.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/blue/blue_normal.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/blue/blue_normal.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/red/red_pressed.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/red/red_pressed.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/transparent_btn.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/transparent_btn.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/panels/light_dark_panel.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/panels/light_dark_panel.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/blue/blue_disabled.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/blue/blue_disabled.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/blue/blue_pressed.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/blue/blue_pressed.stylebox -------------------------------------------------------------------------------- /scripts/core/data/Architecture.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Data 2 | { 3 | public enum Architecture 4 | { 5 | x32 = 0, 6 | x64 = 1, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_check_disabled_mirrored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_check_disabled_mirrored.png -------------------------------------------------------------------------------- /resources/button_groups/install_btn_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="ButtonGroup" format=3 uid="uid://c2ypx5qbtttva"] 2 | 3 | [resource] 4 | resource_local_to_scene = false 5 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/default/default_hover.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/default/default_hover.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/scrolls/scroll_grabber_normal.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/scrolls/scroll_grabber_normal.stylebox -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_disabled_mirrored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_checked_disabled_mirrored.png -------------------------------------------------------------------------------- /resources/style_boxes/buttons/default/default_disabled.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/default/default_disabled.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/default/default_normal.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/default/default_normal.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/buttons/default/default_pressed.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/buttons/default/default_pressed.stylebox -------------------------------------------------------------------------------- /resources/style_boxes/scrolls/scroll_grabber_highlight.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/resources/style_boxes/scrolls/scroll_grabber_highlight.stylebox -------------------------------------------------------------------------------- /scripts/core/tabs/projects/VersioningMode.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Tabs.Projects 2 | { 3 | public enum VersioningMode 4 | { 5 | None, 6 | Git, 7 | } 8 | } -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_disabled_mirrored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Astral-Sheep/GodotHub/HEAD/assets/sprites/check_buttons/btn_unchecked_disabled_mirrored.png -------------------------------------------------------------------------------- /scripts/core/data/OS.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Data 2 | { 3 | public enum OS 4 | { 5 | Windows = 0, 6 | Linux = 1, 7 | MacOS = 2, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/installer/JumpInstruction.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Installer 2 | { 3 | public enum JumpInstruction : byte 4 | { 5 | None = 0, 6 | Delete = 1, 7 | Cancel = 2, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/ISettingButton.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Settings.Buttons 2 | { 3 | public interface ISettingButton 4 | { 5 | void Connect(); 6 | void Disconnect(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /scripts/core/tabs/SortedPanel.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Tabs 4 | { 5 | public abstract partial class SortedPanel : Control 6 | { 7 | [Export] protected Control itemContainer; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scenes/utils/colors.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://cd5aapghu6aef"] 2 | 3 | [ext_resource type="Script" path="res://scripts/core/utils/Colors.cs" id="1_rs3ov"] 4 | 5 | [node name="Colors" type="Node"] 6 | script = ExtResource("1_rs3ov") 7 | -------------------------------------------------------------------------------- /scripts/core/tabs/documentation/DocumentationTab.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Tabs.Documentation 2 | { 3 | public partial class DocumentationTab : Tab 4 | { 5 | protected override void Connect() { } 6 | protected override void Disconnect() { } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/INamedItem.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 2 | { 3 | public interface INamedItem 4 | { 5 | /// 6 | /// Name of this item 7 | /// 8 | string ItemName { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/IMonoItem.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 2 | { 3 | public interface IMonoItem 4 | { 5 | /// 6 | /// Whether or not this item supports C# 7 | /// 8 | bool IsMono { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/IValidItem.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 2 | { 3 | public interface IValidItem 4 | { 5 | /// 6 | /// Whether or not this item has valid data 7 | /// 8 | bool IsValid { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/IFavoriteItem.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 2 | { 3 | public interface IFavoriteItem 4 | { 5 | /// 6 | /// Whether or not the user marked this as favorite 7 | /// 8 | bool IsFavorite { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/ITimedItem.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 2 | { 3 | public interface ITimedItem 4 | { 5 | /// 6 | /// Time since the last time this item's files were opened 7 | /// 8 | double TimeSinceLastOpening { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/IVersionItem.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 4 | { 5 | public interface IVersionItem 6 | { 7 | /// 8 | /// of the item 9 | /// 10 | Version Version { get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/star/star_normal.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://b8t8n87drtecc"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://n0ngwfu5xhvd" path="res://assets/sprites/star.png" id="1_h2w4n"] 4 | 5 | [resource] 6 | texture = ExtResource("1_h2w4n") 7 | modulate_color = Color(0.2, 0.2, 0.2, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/star/star_hover.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://pgwj67bkuk6y"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://n0ngwfu5xhvd" path="res://assets/sprites/star.png" id="1_wov08"] 4 | 5 | [resource] 6 | texture = ExtResource("1_wov08") 7 | modulate_color = Color(0.564706, 0.564706, 0.564706, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/star/star_disabled.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://b0rpaplouipyq"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://n0ngwfu5xhvd" path="res://assets/sprites/star.png" id="1_5ycx7"] 4 | 5 | [resource] 6 | texture = ExtResource("1_5ycx7") 7 | modulate_color = Color(0.117647, 0.117647, 0.117647, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/star/star_pressed.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://bwyc8ejlx13my"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://n0ngwfu5xhvd" path="res://assets/sprites/star.png" id="1_660vt"] 4 | 5 | [resource] 6 | texture = ExtResource("1_660vt") 7 | modulate_color = Color(0.721569, 0.721569, 0.721569, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/close/close_disabled.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://c1mypphbuba7b"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://crtj2ch3o166n" path="res://assets/sprites/crosses/cross_white.png" id="1_cdmas"] 4 | 5 | [resource] 6 | texture = ExtResource("1_cdmas") 7 | modulate_color = Color(0.2, 0.2, 0.2, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/download/download_disabled.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://cmj13fvlu7cfh"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b6m2numrdnkgc" path="res://assets/sprites/download_btn.png" id="1_ydfhs"] 4 | 5 | [resource] 6 | texture = ExtResource("1_ydfhs") 7 | modulate_color = Color(0.2, 0.2, 0.2, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/close/close_hover.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://sog30gklctc4"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://crtj2ch3o166n" path="res://assets/sprites/crosses/cross_white.png" id="1_nnru4"] 4 | 5 | [resource] 6 | texture = ExtResource("1_nnru4") 7 | modulate_color = Color(0.831373, 0.313726, 0.309804, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/close/close_normal.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://be7jhdr22wtea"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://crtj2ch3o166n" path="res://assets/sprites/crosses/cross_white.png" id="1_pp1ot"] 4 | 5 | [resource] 6 | texture = ExtResource("1_pp1ot") 7 | modulate_color = Color(0.564706, 0.564706, 0.564706, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/download/download_hover.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://cm15h4syelk5n"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b6m2numrdnkgc" path="res://assets/sprites/download_btn.png" id="1_a8s4b"] 4 | 5 | [resource] 6 | texture = ExtResource("1_a8s4b") 7 | modulate_color = Color(0.215686, 0.615686, 0.65098, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/download/download_normal.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://cx2kkw3gpsr06"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b6m2numrdnkgc" path="res://assets/sprites/download_btn.png" id="1_48ssx"] 4 | 5 | [resource] 6 | texture = ExtResource("1_48ssx") 7 | modulate_color = Color(0.564706, 0.564706, 0.564706, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/download/download_pressed.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://dupfk7wsjifh8"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://b6m2numrdnkgc" path="res://assets/sprites/download_btn.png" id="1_lixio"] 4 | 5 | [resource] 6 | texture = ExtResource("1_lixio") 7 | modulate_color = Color(0.14902, 0.423529, 0.45098, 1) 8 | -------------------------------------------------------------------------------- /resources/style_boxes/buttons/close/close_pressed.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://cdmqwnpe0kc12"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://crtj2ch3o166n" path="res://assets/sprites/crosses/cross_white.png" id="1_ybsvh"] 4 | 5 | [resource] 6 | texture = ExtResource("1_ybsvh") 7 | modulate_color = Color(0.427451, 0.156863, 0.156863, 1) 8 | -------------------------------------------------------------------------------- /scripts/core/tabs/projects/RenderMode.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Tabs.Projects 2 | { 3 | public enum RenderMode : int 4 | { 5 | OpenGL2 = 0b000, 6 | OpenGL3 = 0b001, 7 | Forward = 0b100, 8 | Mobile = 0b101, 9 | Compatibility = 0b110, 10 | /// 11 | /// This is not a render mode but a way to separate older modes from newer ones 12 | /// 13 | Config5 = 0b100, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/ResetButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Godot; 3 | 4 | namespace Com.Astral.GodotHub.Core.Settings.Buttons 5 | { 6 | public partial class ResetButton : Button, ISettingButton 7 | { 8 | public void Connect() 9 | { 10 | Pressed += AppConfig.ResetAll; 11 | } 12 | 13 | public void Disconnect() 14 | { 15 | Pressed -= AppConfig.ResetAll; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/SettingToggle.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 2 | { 3 | public abstract partial class SettingToggle : SettingButton 4 | { 5 | public override void Connect() 6 | { 7 | button.Toggled += OnToggled; 8 | } 9 | 10 | public override void Disconnect() 11 | { 12 | button.Toggled -= OnToggled; 13 | } 14 | 15 | protected abstract void OnToggled(bool pToggled); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/AutoDeleteToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 4 | { 5 | public partial class AutoDeleteToggle : SettingToggle 6 | { 7 | protected override void OnToggled(bool pToggled) 8 | { 9 | AppConfig.AutoDeleteZip = pToggled; 10 | } 11 | 12 | protected override void Reset() 13 | { 14 | button.ButtonPressed = AppConfig.AutoDeleteZip; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/AutoCloseDLToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 4 | { 5 | public partial class AutoCloseDLToggle : SettingToggle 6 | { 7 | protected override void OnToggled(bool pToggled) 8 | { 9 | AppConfig.AutoCloseDownload = pToggled; 10 | } 11 | 12 | protected override void Reset() 13 | { 14 | button.ButtonPressed = AppConfig.AutoCloseDownload; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/AutoShortcutToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 4 | { 5 | public partial class AutoShortcutToggle : SettingToggle 6 | { 7 | protected override void OnToggled(bool pToggled) 8 | { 9 | AppConfig.AutoCreateShortcut = pToggled; 10 | } 11 | 12 | protected override void Reset() 13 | { 14 | button.ButtonPressed = AppConfig.AutoCreateShortcut; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/AutoUpdateToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 4 | { 5 | public partial class AutoUpdateToggle : SettingToggle 6 | { 7 | protected override void OnToggled(bool pToggled) 8 | { 9 | AppConfig.AutoUpdateRepository = pToggled; 10 | } 11 | 12 | protected override void Reset() 13 | { 14 | button.ButtonPressed = AppConfig.AutoUpdateRepository; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/directory/ProjectDirButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Directory 4 | { 5 | public partial class ProjectDirButton : DirButton 6 | { 7 | protected override void OnDirSelected(string pDir) 8 | { 9 | AppConfig.ProjectDir = pDir; 10 | base.OnDirSelected(pDir); 11 | } 12 | 13 | protected override void Reset() 14 | { 15 | button.Text = $" {AppConfig.ProjectDir}"; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/DebugToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Debug; 3 | 4 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 5 | { 6 | public partial class DebugToggle : SettingToggle 7 | { 8 | protected override void OnToggled(bool pToggled) 9 | { 10 | AppConfig.Debug = pToggled; 11 | Debugger.Enabled = pToggled; 12 | } 13 | 14 | protected override void Reset() 15 | { 16 | button.ButtonPressed = AppConfig.Debug; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/core/tabs/Tab.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Tabs 4 | { 5 | public abstract partial class Tab : Control 6 | { 7 | public virtual void Toggle(bool pToggled) 8 | { 9 | if (Visible == pToggled) 10 | return; 11 | 12 | if (pToggled) 13 | { 14 | Visible = true; 15 | Connect(); 16 | } 17 | else 18 | { 19 | Disconnect(); 20 | Visible = false; 21 | } 22 | } 23 | 24 | protected abstract void Connect(); 25 | protected abstract void Disconnect(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scenes/message_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://cjui7vv5c4tpk"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_w1lgf"] 4 | 5 | [node name="MessageDialog" type="AcceptDialog"] 6 | transparent_bg = true 7 | title = "Error" 8 | position = Vector2i(300, 150) 9 | size = Vector2i(650, 350) 10 | visible = true 11 | transient = false 12 | unresizable = true 13 | always_on_top = true 14 | popup_window = true 15 | theme = ExtResource("1_w1lgf") 16 | dialog_text = "This is an error" 17 | dialog_autowrap = true 18 | -------------------------------------------------------------------------------- /scenes/confirmation_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bilwvy6kxj1nk"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_kav0p"] 4 | 5 | [node name="ConfirmationDialog" type="ConfirmationDialog"] 6 | transparent_bg = true 7 | title = "Remove version?" 8 | size = Vector2i(400, 200) 9 | visible = true 10 | exclusive = false 11 | unresizable = true 12 | popup_window = true 13 | theme = ExtResource("1_kav0p") 14 | dialog_text = "Are you confirming you want to do the action you clicked on?" 15 | dialog_autowrap = true 16 | -------------------------------------------------------------------------------- /scenes/settings/folder_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://c54ctd2k2mbg0"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_madp0"] 4 | 5 | [node name="FileDialog" type="FileDialog"] 6 | transparent_bg = true 7 | title = "Open a Directory" 8 | position = Vector2i(125, 100) 9 | size = Vector2i(1000, 550) 10 | visible = true 11 | always_on_top = true 12 | popup_window = true 13 | min_size = Vector2i(600, 300) 14 | theme = ExtResource("1_madp0") 15 | ok_button_text = "Select This Folder" 16 | file_mode = 2 17 | access = 2 18 | -------------------------------------------------------------------------------- /scripts/core/tabs/UpdateRepoButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Debug; 3 | using Godot; 4 | 5 | using Error = Com.Astral.GodotHub.Core.Utils.Error; 6 | 7 | namespace Com.Astral.GodotHub.Core.Tabs 8 | { 9 | public partial class UpdateRepoButton : Button 10 | { 11 | public override void _Ready() 12 | { 13 | Pressed += OnPressed; 14 | } 15 | 16 | protected async void OnPressed() 17 | { 18 | Error lError = await GDRepository.UpdateReleases(); 19 | 20 | if (!lError.Ok) 21 | { 22 | Debugger.LogException(lError.Exception); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/toggles/SameDirToggle.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Settings.Buttons.Directory; 3 | using Godot; 4 | 5 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Toggles 6 | { 7 | public partial class SameDirToggle : SettingToggle 8 | { 9 | [Export] protected DownloadDirButton downloadDirButton; 10 | 11 | protected override void OnToggled(bool pToggled) 12 | { 13 | AppConfig.UseInstallDirForDownload = pToggled; 14 | downloadDirButton.Enabled = !pToggled; 15 | } 16 | 17 | protected override void Reset() 18 | { 19 | button.ButtonPressed = AppConfig.UseInstallDirForDownload; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/SettingButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Godot; 3 | 4 | namespace Com.Astral.GodotHub.Core.Settings.Buttons 5 | { 6 | public abstract partial class SettingButton : Control, ISettingButton 7 | { 8 | [Export] protected Button button; 9 | 10 | public override void _Ready() 11 | { 12 | Reset(); 13 | AppConfig.Reset += Reset; 14 | } 15 | 16 | protected override void Dispose(bool pDisposing) 17 | { 18 | if (!pDisposing) 19 | return; 20 | 21 | AppConfig.Reset -= Reset; 22 | } 23 | 24 | public abstract void Connect(); 25 | public abstract void Disconnect(); 26 | protected abstract void Reset(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/directory/InstallDirButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Godot; 3 | 4 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Directory 5 | { 6 | public partial class InstallDirButton : DirButton 7 | { 8 | [Export] protected DownloadDirButton downloadDirButton; 9 | 10 | protected override void OnDirSelected(string pDir) 11 | { 12 | AppConfig.InstallDir = pDir; 13 | 14 | if (AppConfig.UseInstallDirForDownload) 15 | { 16 | AppConfig.DownloadDir = pDir; 17 | downloadDirButton.Text = $" {pDir}"; 18 | } 19 | 20 | base.OnDirSelected(pDir); 21 | } 22 | 23 | protected override void Reset() 24 | { 25 | button.Text = $" {AppConfig.InstallDir}"; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/core/SplashScreen.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core 4 | { 5 | public partial class SplashScreen : ColorRect 6 | { 7 | [Export] protected float fadeDuration = 0.2f; 8 | 9 | public override void _Ready() 10 | { 11 | #if DEBUG 12 | Visible = true; 13 | #endif //DEBUG 14 | 15 | Main.Instance.Initialized += FadeOut; 16 | } 17 | 18 | protected void FadeOut() 19 | { 20 | Main.Instance.Initialized -= FadeOut; 21 | CreateTween() 22 | .SetTrans(Tween.TransitionType.Linear) 23 | .SetEase(Tween.EaseType.InOut) 24 | .TweenProperty(this, "self_modulate:a", 0f, fadeDuration) 25 | .Finished += OnFadeOutFinished; 26 | } 27 | 28 | protected void OnFadeOutFinished() 29 | { 30 | Visible = false; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scripts/uninstaller/UninstallProgram.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Uninstaller 2 | { 3 | internal class UninstallProgram 4 | { 5 | public static void Main(string[] pArgs) 6 | { 7 | if (pArgs == null || pArgs.Length == 0) 8 | return; 9 | 10 | try 11 | { 12 | for (int i = 0; i < pArgs.Length; i++) 13 | { 14 | DeletePath(pArgs[i]); 15 | } 16 | } 17 | catch (Exception lException) 18 | { 19 | Console.WriteLine(lException); 20 | Console.ReadKey(); 21 | } 22 | } 23 | 24 | private static void DeletePath(string pPath) 25 | { 26 | if (File.Exists(pPath)) 27 | { 28 | File.Delete(pPath); 29 | } 30 | else if (Directory.Exists(pPath)) 31 | { 32 | Directory.Delete(pPath, true); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/directory/DownloadDirButton.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Directory 4 | { 5 | public partial class DownloadDirButton : DirButton 6 | { 7 | public bool Enabled 8 | { 9 | get => _enabled; 10 | set 11 | { 12 | if (Enabled == value) 13 | return; 14 | 15 | Visible = value; 16 | _enabled = value; 17 | } 18 | } 19 | protected bool _enabled = true; 20 | 21 | protected override void OnDirSelected(string pDir) 22 | { 23 | AppConfig.DownloadDir = pDir; 24 | base.OnDirSelected(pDir); 25 | } 26 | 27 | protected override void Reset() 28 | { 29 | button.Text = $" {AppConfig.DownloadDir}"; 30 | Enabled = !AppConfig.UseInstallDirForDownload; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scripts/core/data/GDFile.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Core.Data 2 | { 3 | /// 4 | /// Struct corresponding to an engine executable or a Godot project 5 | /// 6 | public struct GDFile 7 | { 8 | /// 9 | /// Absolute path to the file 10 | /// 11 | public string Path { get; private set; } 12 | /// 13 | /// Whether or not this file is marked as favorite by the user 14 | /// 15 | public bool IsFavorite { get; private set; } 16 | /// 17 | /// of the engine or the project 18 | /// 19 | public Version Version { get; private set; } 20 | 21 | public GDFile(string pPath, bool pIsFavorite, Version pVersion) 22 | { 23 | Path = pPath; 24 | IsFavorite = pIsFavorite; 25 | Version = pVersion; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Bold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://ykab4b3ximf0" 6 | path="res://.godot/imported/JetBrainsMono-Bold.ttf-f31f88c88fdce3c3d6a7829dad9ca238.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Bold.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Bold.ttf-f31f88c88fdce3c3d6a7829dad9ca238.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Italic.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://bwv0di287lde3" 6 | path="res://.godot/imported/JetBrainsMono-Italic.ttf-826933456e09d4ab84cb3226492f017f.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Italic.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Italic.ttf-826933456e09d4ab84cb3226492f017f.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Medium.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://deriya3c1o017" 6 | path="res://.godot/imported/JetBrainsMono-Medium.ttf-06044950c8d4b6cfb6cde21dbc11f060.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Medium.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Medium.ttf-06044950c8d4b6cfb6cde21dbc11f060.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Regular.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://20nkj2oqpwl4" 6 | path="res://.godot/imported/JetBrainsMono-Regular.ttf-4207f0122299d0c43a34895264f1b346.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Regular.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Regular.ttf-4207f0122299d0c43a34895264f1b346.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-ExtraBold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://b2dha2ictl01s" 6 | path="res://.godot/imported/JetBrainsMono-ExtraBold.ttf-ff94f9e44a98cadab98702a1a9f8d738.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-ExtraBold.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-ExtraBold.ttf-ff94f9e44a98cadab98702a1a9f8d738.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Bold-Italic.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://u11pwpfdqleg" 6 | path="res://.godot/imported/JetBrainsMono-Bold-Italic.ttf-bbd6d59f11a5a87ded8f47223085fd53.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Bold-Italic.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Bold-Italic.ttf-bbd6d59f11a5a87ded8f47223085fd53.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-Medium-Italic.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://drc4cb0obved2" 6 | path="res://.godot/imported/JetBrainsMono-Medium-Italic.ttf-31da2408e034706a3d6e2311723282bb.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-Medium-Italic.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-Medium-Italic.ttf-31da2408e034706a3d6e2311723282bb.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/fonts/JetBrainsMono-ExtraBold-Italic.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://cjyj30pvj70c3" 6 | path="res://.godot/imported/JetBrainsMono-ExtraBold-Italic.ttf-0f48647bc6a20054160164675a934b31.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/JetBrainsMono-ExtraBold-Italic.ttf" 11 | dest_files=["res://.godot/imported/JetBrainsMono-ExtraBold-Italic.ttf-0f48647bc6a20054160164675a934b31.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | multichannel_signed_distance_field=false 19 | msdf_pixel_range=8 20 | msdf_size=48 21 | allow_system_fallback=true 22 | force_autohinter=false 23 | hinting=1 24 | subpixel_positioning=1 25 | oversampling=0.0 26 | Fallbacks=null 27 | fallbacks=[] 28 | Compress=null 29 | compress=true 30 | preload=[] 31 | language_support={} 32 | script_support={} 33 | opentype_features={} 34 | -------------------------------------------------------------------------------- /assets/sprites/star.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://n0ngwfu5xhvd" 6 | path="res://.godot/imported/star.png-3ab12433f97fcbd385d38b1404557e14.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/star.png" 14 | dest_files=["res://.godot/imported/star.png-3ab12433f97fcbd385d38b1404557e14.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scripts/core/utils/BBCodeT.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils 4 | { 5 | public static class BBCodeT 6 | { 7 | public static string GetColoredText(string pText, Color pColor) 8 | { 9 | return $"[color=#{Colors.ToHexa(pColor)}]{pText}[/color]"; 10 | } 11 | 12 | public static string GetBoldText(string pText) 13 | { 14 | return $"[b]{pText}[/b]"; 15 | } 16 | 17 | public static string GetItalicText(string pText) 18 | { 19 | return $"[i]{pText}[/i]"; 20 | } 21 | 22 | public static string GetTaggedText(string pText, params string[] pTags) 23 | { 24 | string lRet = ""; 25 | 26 | for (int i = 0; i < pTags.Length; i++) 27 | { 28 | lRet += "[" + pTags[i] + "]"; 29 | } 30 | 31 | lRet += pText; 32 | 33 | for (int i = pTags.Length - 1; i >= 0; i--) 34 | { 35 | lRet += "[/" + pTags[i] + "]"; 36 | } 37 | 38 | return lRet; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /assets/sprites/folder.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://ck0fei3vii0gs" 6 | path="res://.godot/imported/folder.png-829cf927d0a48d4f049a0065b70db740.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/folder.png" 14 | dest_files=["res://.godot/imported/folder.png-829cf927d0a48d4f049a0065b70db740.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_up.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://buy4vfi18sdga" 6 | path="res://.godot/imported/arrow_up.png-b589b15a8fe6b3ade68f2301877f8175.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/arrows/arrow_up.png" 14 | dest_files=["res://.godot/imported/arrow_up.png-b589b15a8fe6b3ade68f2301877f8175.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/download_btn.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b6m2numrdnkgc" 6 | path="res://.godot/imported/download_btn.png-03e8306191a71276e7b0c19d1c821d62.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/download_btn.png" 14 | dest_files=["res://.godot/imported/download_btn.png-03e8306191a71276e7b0c19d1c821d62.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/gdh_splash-screen.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://nl42yg4oevc5" 6 | path="res://.godot/imported/gdh_splash-screen.png-4e34233a7513afe045c9ca70e07f4b53.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/gdh_splash-screen.png" 14 | dest_files=["res://.godot/imported/gdh_splash-screen.png-4e34233a7513afe045c9ca70e07f4b53.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_left.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://p3bmkkhysbnv" 6 | path="res://.godot/imported/arrow_left.png-5d4dd23636f1aa4b65fbe4304c04c362.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/arrows/arrow_left.png" 14 | dest_files=["res://.godot/imported/arrow_left.png-5d4dd23636f1aa4b65fbe4304c04c362.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/settings_icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b56ynjybl3xm3" 6 | path="res://.godot/imported/settings_icon.png-57802a87571912e0dc8029db181701e9.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/settings_icon.png" 14 | dest_files=["res://.godot/imported/settings_icon.png-57802a87571912e0dc8029db181701e9.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_down.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://be2gnv6tr4e73" 6 | path="res://.godot/imported/arrow_down.png-03ba2e3a36a34345e1d37c177ddd62f3.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/arrows/arrow_down.png" 14 | dest_files=["res://.godot/imported/arrow_down.png-03ba2e3a36a34345e1d37c177ddd62f3.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/arrows/arrow_right.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://jvyrvv8bmy4u" 6 | path="res://.godot/imported/arrow_right.png-8a166a9fcca6ecefe76397f8567adf53.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/arrows/arrow_right.png" 14 | dest_files=["res://.godot/imported/arrow_right.png-8a166a9fcca6ecefe76397f8567adf53.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/arrows/option_btn.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dklahbv7sporm" 6 | path="res://.godot/imported/option_btn.png-67c2d353f69841bef12fa861a15c99b0.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/arrows/option_btn.png" 14 | dest_files=["res://.godot/imported/option_btn.png-67c2d353f69841bef12fa861a15c99b0.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scripts/core/utils/Error.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils 4 | { 5 | /// 6 | /// Structure used to approximate a Rust enum: Error(string) 7 | /// 8 | public struct Error 9 | { 10 | /// 11 | /// If true, everything went well 12 | /// 13 | public bool Ok => _exception == null; 14 | /// 15 | /// The that happened. null if everything went well 16 | /// 17 | public Exception Exception => _exception; 18 | /// 19 | /// Message that describes the current exception. Empty if there's no 20 | /// 21 | public string Message => _exception.Message; 22 | 23 | private readonly Exception _exception; 24 | 25 | public Error() 26 | { 27 | _exception = null; 28 | } 29 | 30 | public Error(Exception pException) 31 | { 32 | _exception = pException; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_hover.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://y0dvw21vgsyb" 6 | path="res://.godot/imported/cross_hover.png-3a8dabdb0ddde2e365ac12bf00096d72.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/crosses/cross_hover.png" 14 | dest_files=["res://.godot/imported/cross_hover.png-3a8dabdb0ddde2e365ac12bf00096d72.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_white.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://crtj2ch3o166n" 6 | path="res://.godot/imported/cross_white.png-ddfe8f6addb29cf1ae60b65b9f616ec2.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/crosses/cross_white.png" 14 | dest_files=["res://.godot/imported/cross_white.png-ddfe8f6addb29cf1ae60b65b9f616ec2.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_checked.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://4v0f3326dtvv" 6 | path="res://.godot/imported/box_checked.png-79e23c933897f27818e2c329bcc93a7a.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_boxes/box_checked.png" 14 | dest_files=["res://.godot/imported/box_checked.png-79e23c933897f27818e2c329bcc93a7a.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/crosses/cross_default.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bq2mnb0nva1gp" 6 | path="res://.godot/imported/cross_default.png-daf0d358465aa1087bbf479b327a5c58.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/crosses/cross_default.png" 14 | dest_files=["res://.godot/imported/cross_default.png-daf0d358465aa1087bbf479b327a5c58.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/folder_compressed.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dohlskxd3lklq" 6 | path="res://.godot/imported/folder_compressed.png-2c1c2ab6f20a44ffee9665d45887f435.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/folder_compressed.png" 14 | dest_files=["res://.godot/imported/folder_compressed.png-2c1c2ab6f20a44ffee9665d45887f435.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_unchecked.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://qoq1yljgu7" 6 | path="res://.godot/imported/box_unchecked.png-0c915cc974d352116442923221fce1ab.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_boxes/box_unchecked.png" 14 | dest_files=["res://.godot/imported/box_unchecked.png-0c915cc974d352116442923221fce1ab.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cbkbi55l2es62" 6 | path="res://.godot/imported/btn_checked.png-bcddafa2be736af435af086d09375cda.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_checked.png" 14 | dest_files=["res://.godot/imported/btn_checked.png-bcddafa2be736af435af086d09375cda.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="Godot Hub" 14 | run/main_scene="res://scenes/main.tscn" 15 | config/features=PackedStringArray("4.0", "C#", "Mobile") 16 | config/icon="res://icon.svg" 17 | config/windows_native_icon="res://icon.ico" 18 | 19 | [autoload] 20 | 21 | ExceptionHandler="*res://scenes/debug/exception_handler.tscn" 22 | Colors="*res://scenes/utils/colors.tscn" 23 | 24 | [display] 25 | 26 | window/size/viewport_width=1280 27 | window/size/viewport_height=720 28 | window/stretch/mode="canvas_items" 29 | window/stretch/aspect="expand" 30 | 31 | [dotnet] 32 | 33 | project/assembly_name="Godot Hub" 34 | 35 | [rendering] 36 | 37 | renderer/rendering_method="mobile" 38 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cyqq5wt7y5ri8" 6 | path="res://.godot/imported/btn_unchecked.png-f4ad166b5aeae3bc9397d8214bac88dc.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_unchecked.png" 14 | dest_files=["res://.godot/imported/btn_unchecked.png-f4ad166b5aeae3bc9397d8214bac88dc.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scripts/installer/InstallerConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Installer 2 | { 3 | public static class InstallerConstants 4 | { 5 | #if DEBUG 6 | public const string MUTEX_NAME = "GodotHub-AdminMutex-Debug"; 7 | 8 | public const string DOWNLOAD_MAP_NAME = "GodotHub-DownloadContentMap-Debug"; 9 | public const string ZIP_MAP_NAME = "GodotHub-ZipPathMap-Debug"; 10 | public const string EXTRACT_MAP_NAME = "GodotHub-ExtractDirMap-Debug"; 11 | public const string JUMP_MAP_NAME = "GodotHub-JumpMap-Debug"; 12 | #else 13 | public const string MUTEX_NAME = "GodotHub-AdminMutex"; 14 | 15 | public const string DOWNLOAD_MAP_NAME = "GodotHub-DownloadContentMap"; 16 | public const string ZIP_MAP_NAME = "GodotHub-ZipPathMap"; 17 | public const string EXTRACT_MAP_NAME = "GodotHub-ExtractDirMap"; 18 | public const string JUMP_MAP_NAME = "GodotHub-JumpMap"; 19 | #endif //DEBUG 20 | 21 | public const string WRITE_ARGUMENT = "--write-zip"; 22 | public const string EXTRACT_ARGUMENT = "--unzip"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /icon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cvbiw0kj5o88y" 6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://icon.svg" 14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_checked_disabled.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cmrbnnr3hcyq2" 6 | path="res://.godot/imported/box_checked_disabled.png-17e0744206c3f93fc44653b613f42220.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_boxes/box_checked_disabled.png" 14 | dest_files=["res://.godot/imported/box_checked_disabled.png-17e0744206c3f93fc44653b613f42220.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_disabled.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://e5s3gekp2tfn" 6 | path="res://.godot/imported/btn_checked_disabled.png-ffc20e03046a8024825db0efd03735c8.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_checked_disabled.png" 14 | dest_files=["res://.godot/imported/btn_checked_disabled.png-ffc20e03046a8024825db0efd03735c8.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_mirrored.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bjyjla6t1lot7" 6 | path="res://.godot/imported/btn_checked_mirrored.png-1fc948935607ba22dd7c71f0ab1effd2.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_checked_mirrored.png" 14 | dest_files=["res://.godot/imported/btn_checked_mirrored.png-1fc948935607ba22dd7c71f0ab1effd2.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Quick info: I haven't abandonned this project. It's just that I don't have the time and the energy to work on it. I still want to finish it and make it a good tool for Godot users. 2 | 3 | # GodotHub 4 | Like Unity hub but for Godot. 5 | 6 | It's supposed to be a project and version manager, but I plan to add more features in the future. 7 | 8 | ## Getting Godot Hub 9 | 10 | You can either get the executable, or get the source code and export it with Godot 4.0. Since I can't export on Mac, you'll have to go for the second option if you want it on this platform. 11 | 12 | ## Screenshots 13 | 14 | ### Project List: 15 | ![projects_tab](https://github.com/Astral-Sheep/GodotHub/assets/109028693/fdc2fe93-e35f-4188-bdc8-cdaf2d76b07c) 16 | 17 | ### Installed Versions List: 18 | ![installs_tab](https://github.com/Astral-Sheep/GodotHub/assets/109028693/031b7091-135f-4db0-a176-6eaf4182d94a) 19 | 20 | ### Releases List: 21 | ![releases_tab](https://github.com/Astral-Sheep/GodotHub/assets/109028693/1f214a07-5bcd-4e9c-97f2-e138a30e8dad) 22 | -------------------------------------------------------------------------------- /assets/sprites/check_boxes/box_unchecked_disabled.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://do74hj6aewgif" 6 | path="res://.godot/imported/box_unchecked_disabled.png-1772e9cc2d632b02e756c852d0374894.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_boxes/box_unchecked_disabled.png" 14 | dest_files=["res://.godot/imported/box_unchecked_disabled.png-1772e9cc2d632b02e756c852d0374894.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_disabled.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://by1q0nrfe4s6w" 6 | path="res://.godot/imported/btn_unchecked_disabled.png-155ccf176e20559c74bbc5dbff4e5219.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_unchecked_disabled.png" 14 | dest_files=["res://.godot/imported/btn_unchecked_disabled.png-155ccf176e20559c74bbc5dbff4e5219.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_mirrored.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bcadjo1extons" 6 | path="res://.godot/imported/btn_unchecked_mirrored.png-da679aa1223739c8099ebf63de801857.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_unchecked_mirrored.png" 14 | dest_files=["res://.godot/imported/btn_unchecked_mirrored.png-da679aa1223739c8099ebf63de801857.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_check_disabled_mirrored.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cs727hgthptx" 6 | path="res://.godot/imported/btn_check_disabled_mirrored.png-e79de934ca3eb99dd3f9867ac5e507c2.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_check_disabled_mirrored.png" 14 | dest_files=["res://.godot/imported/btn_check_disabled_mirrored.png-e79de934ca3eb99dd3f9867ac5e507c2.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /assets/default_icon.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://4wgos1q8t8tv" 6 | path="res://.godot/imported/default_icon.svg-89937e2172e005a1330a2139d4b6965d.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/default_icon.svg" 14 | dest_files=["res://.godot/imported/default_icon.svg-89937e2172e005a1330a2139d4b6965d.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_checked_disabled_mirrored.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bv4yc4m6wi3tk" 6 | path="res://.godot/imported/btn_checked_disabled_mirrored.png-69ab4ab8d22f405838b5d15acc7b9bf1.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_checked_disabled_mirrored.png" 14 | dest_files=["res://.godot/imported/btn_checked_disabled_mirrored.png-69ab4ab8d22f405838b5d15acc7b9bf1.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scenes/sort_button.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://dcyk3xxppgacf"] 2 | 3 | [ext_resource type="Theme" uid="uid://dpsfmlg5cj4ka" path="res://resources/themes/sort_btn.theme" id="1_0gx4y"] 4 | [ext_resource type="Script" path="res://scripts/core/tabs/SortToggle.cs" id="2_hv8wg"] 5 | [ext_resource type="Texture2D" uid="uid://be2gnv6tr4e73" path="res://assets/sprites/arrows/arrow_down.png" id="3_0pcu5"] 6 | 7 | [node name="NameButton" type="Button" node_paths=PackedStringArray("arrowRect")] 8 | anchors_preset = -1 9 | anchor_left = 0.075 10 | anchor_top = 0.25 11 | anchor_right = 0.35 12 | anchor_bottom = 0.75 13 | focus_mode = 0 14 | theme = ExtResource("1_0gx4y") 15 | toggle_mode = true 16 | text = "Name" 17 | alignment = 0 18 | script = ExtResource("2_hv8wg") 19 | arrowRect = NodePath("Arrow") 20 | 21 | [node name="Arrow" type="TextureRect" parent="."] 22 | layout_mode = 1 23 | anchors_preset = 9 24 | anchor_bottom = 1.0 25 | offset_left = 55.0 26 | offset_right = 70.0 27 | grow_vertical = 2 28 | texture = ExtResource("3_0pcu5") 29 | stretch_mode = 5 30 | -------------------------------------------------------------------------------- /assets/sprites/check_buttons/btn_unchecked_disabled_mirrored.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://4e1jphqiexep" 6 | path="res://.godot/imported/btn_unchecked_disabled_mirrored.png-6d595d74a6c4b7bfaa00c01f8925ca95.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/check_buttons/btn_unchecked_disabled_mirrored.png" 14 | dest_files=["res://.godot/imported/btn_unchecked_disabled_mirrored.png-6d595d74a6c4b7bfaa00c01f8925ca95.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scripts/core/utils/Colors.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils 4 | { 5 | public partial class Colors : Node 6 | { 7 | public static Colors Singleton { get; private set; } 8 | 9 | public Color White => _white; 10 | public Color Blue => _blue; 11 | public Color Green => _green; 12 | public Color Yellow => _yellow; 13 | public Color Red => _red; 14 | 15 | [Export] protected Color _white = new Color(0xB8B8B8FF); 16 | [Export] protected Color _blue = new Color(0x379DA6FF); 17 | [Export] protected Color _green = new Color(0x769656FF); 18 | [Export] protected Color _yellow = new Color(0xE7B44FFF); 19 | [Export] protected Color _red = new Color(0xD4504FFF); 20 | 21 | public override void _EnterTree() 22 | { 23 | Singleton = this; 24 | } 25 | 26 | public override void _ExitTree() 27 | { 28 | Singleton = null; 29 | } 30 | 31 | /// 32 | /// Return a string of the color converted to hexadecimal 33 | /// 34 | public static string ToHexa(Color pColor) 35 | { 36 | return $"{pColor.R8:x2}{pColor.G8:x2}{pColor.B8:x2}"; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /scripts/core/tabs/SortToggle.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | namespace Com.Astral.GodotHub.Core.Tabs 5 | { 6 | public partial class SortToggle : Button 7 | { 8 | public event Action CustomToggled; 9 | 10 | [Export] protected TextureRect arrowRect; 11 | 12 | protected bool toggled = false; 13 | 14 | public override void _Ready() 15 | { 16 | arrowRect.Visible = false; 17 | arrowRect.PivotOffset = arrowRect.Size / 2f; 18 | Toggled += OnToggled; 19 | } 20 | 21 | public void Enable() 22 | { 23 | if (ButtonPressed) 24 | return; 25 | 26 | SetPressedNoSignal(true); 27 | arrowRect.Visible = true; 28 | toggled = true; 29 | arrowRect.Rotation = 0f; 30 | } 31 | 32 | public void Disable() 33 | { 34 | if (!ButtonPressed) 35 | return; 36 | 37 | SetPressedNoSignal(false); 38 | arrowRect.Visible = false; 39 | toggled = false; 40 | } 41 | 42 | protected void OnToggled(bool pToggled) 43 | { 44 | SetPressedNoSignal(true); 45 | toggled = !toggled; 46 | arrowRect.Visible = true; 47 | arrowRect.Rotation = toggled ? 0f : Mathf.Pi; 48 | CustomToggled?.Invoke(toggled); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /scripts/core/settings/buttons/directory/DirButton.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Settings.Buttons.Directory 4 | { 5 | public abstract partial class DirButton : SettingButton 6 | { 7 | public string Text 8 | { 9 | get => button.Text; 10 | set 11 | { 12 | button.Text = value; 13 | } 14 | } 15 | 16 | [Export] protected PackedScene folderDialogScene; 17 | 18 | public override void Connect() 19 | { 20 | button.Pressed += OnPressed; 21 | } 22 | 23 | public override void Disconnect() 24 | { 25 | button.Pressed -= OnPressed; 26 | } 27 | 28 | protected virtual void OnPressed() 29 | { 30 | button.Pressed -= OnPressed; 31 | FileDialog lDialog = folderDialogScene.Instantiate(); 32 | Main.Instance.AddChild(lDialog); 33 | lDialog.PopupCentered(); 34 | lDialog.RootSubfolder = ""; 35 | lDialog.CurrentDir = button.Text[1..]; 36 | lDialog.DirSelected += OnDirSelected; 37 | lDialog.Canceled += OnCanceled; 38 | } 39 | 40 | protected virtual void OnDirSelected(string pDir) 41 | { 42 | button.Text = $" {pDir}"; 43 | button.Pressed += OnPressed; 44 | } 45 | 46 | protected void OnCanceled() 47 | { 48 | button.Pressed += OnPressed; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /scripts/core/data/FullParameterContractResolver.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Serialization; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace Com.Astral.GodotHub.Core.Data 8 | { 9 | /// 10 | /// used to select the most complete constructor when deserializing a .json file 11 | /// 12 | internal class FullParameterContractResolver : DefaultContractResolver 13 | { 14 | protected override JsonObjectContract CreateObjectContract(Type pObjectType) 15 | { 16 | JsonObjectContract lContract = base.CreateObjectContract(pObjectType); 17 | ConstructorInfo lConstructor = pObjectType 18 | .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) 19 | .OrderBy(constructor => constructor.GetParameters().Length) 20 | .LastOrDefault(); 21 | 22 | if (lConstructor == null) 23 | { 24 | return lContract; 25 | } 26 | 27 | lContract.OverrideCreator = (@params) => lConstructor.Invoke(@params); 28 | IList lProperties = CreateConstructorParameters(lConstructor, lContract.Properties); 29 | 30 | for (int i = 0; i < lProperties.Count; i++) 31 | { 32 | lContract.CreatorParameters.Add(lProperties[i]); 33 | } 34 | 35 | return lContract; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /scripts/core/tabs/versions/VersionsTab.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Tabs.Versions 4 | { 5 | public partial class VersionsTab : Tab 6 | { 7 | [ExportGroup("Panels")] 8 | [Export] protected EnginesPanel enginesPanel; 9 | [Export] protected ReleasePanel releasesPanel; 10 | [Export] protected Button enginesButton; 11 | [Export] protected Button releasesButton; 12 | 13 | public override void _Ready() 14 | { 15 | enginesButton.ButtonPressed = true; 16 | releasesButton.ButtonPressed = false; 17 | enginesPanel.Visible = true; 18 | releasesPanel.Visible = false; 19 | } 20 | 21 | protected override void Connect() 22 | { 23 | enginesButton.Toggled += OnInstallsToggled; 24 | releasesButton.Toggled += OnReleasesToggled; 25 | } 26 | 27 | protected override void Disconnect() 28 | { 29 | releasesButton.Toggled -= OnReleasesToggled; 30 | enginesButton.Toggled -= OnInstallsToggled; 31 | } 32 | 33 | protected void OnInstallsToggled(bool pToggled) 34 | { 35 | if (!pToggled || enginesPanel.Visible) 36 | return; 37 | 38 | enginesPanel.Visible = true; 39 | releasesPanel.Visible = false; 40 | } 41 | 42 | protected void OnReleasesToggled(bool pToggled) 43 | { 44 | if (!pToggled || releasesPanel.Visible) 45 | return; 46 | 47 | releasesPanel.Visible = true; 48 | enginesPanel.Visible = false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Godot Hub.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | Com.Astral.GodotHub.Core 6 | False 7 | 8 | 9 | 1701;1702;IDE0090;IDE0063;CA1822 10 | 11 | 12 | 1701;1702;IDE0090;IDE0063;CA1822 13 | 14 | 15 | 1701;1702;IDE0090;IDE0063;CA1822 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /scenes/versions/subbutton.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://dpptd81s7nml2"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_pl5se"] 4 | [ext_resource type="StyleBox" uid="uid://bwbtmxumfpuux" path="res://resources/style_boxes/buttons/default/default_pressed.stylebox" id="2_gb8s2"] 5 | [ext_resource type="StyleBox" uid="uid://cy18s2lgnjx5u" path="res://resources/style_boxes/buttons/default/default_hover.stylebox" id="3_nyalc"] 6 | [ext_resource type="StyleBox" uid="uid://c7pi54b60wghh" path="res://resources/style_boxes/buttons/default/default_normal.stylebox" id="4_7okq5"] 7 | [ext_resource type="StyleBox" uid="uid://donklkuk8tnlx" path="res://resources/style_boxes/buttons/default/default_disabled.stylebox" id="5_be4ah"] 8 | [ext_resource type="ButtonGroup" uid="uid://c2ypx5qbtttva" path="res://resources/button_groups/install_btn_group.tres" id="6_dgadc"] 9 | 10 | [node name="SubButton" type="Button"] 11 | custom_minimum_size = Vector2(0, 45) 12 | offset_left = 25.0 13 | offset_top = 15.0 14 | offset_right = 140.0 15 | offset_bottom = 60.0 16 | focus_mode = 0 17 | theme = ExtResource("1_pl5se") 18 | theme_override_colors/font_color = Color(0.721569, 0.721569, 0.721569, 1) 19 | theme_override_colors/font_pressed_color = Color(0.721569, 0.721569, 0.721569, 1) 20 | theme_override_colors/font_hover_color = Color(0.933333, 0.933333, 0.933333, 1) 21 | theme_override_colors/font_focus_color = Color(0.933333, 0.933333, 0.933333, 1) 22 | theme_override_colors/font_hover_pressed_color = Color(0.933333, 0.933333, 0.933333, 1) 23 | theme_override_styles/normal = ExtResource("2_gb8s2") 24 | theme_override_styles/hover = ExtResource("3_nyalc") 25 | theme_override_styles/pressed = ExtResource("4_7okq5") 26 | theme_override_styles/disabled = ExtResource("5_be4ah") 27 | toggle_mode = true 28 | button_group = ExtResource("6_dgadc") 29 | text = "Installs" 30 | -------------------------------------------------------------------------------- /scripts/core/tabs/TabManager.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Com.Astral.GodotHub.Core.Tabs 4 | { 5 | public partial class TabManager : Control 6 | { 7 | [ExportGroup("Tabs")] 8 | [Export] protected Tab projectsTab; 9 | [Export] protected Tab versionsTab; 10 | [Export] protected Tab documentationTab; 11 | 12 | [ExportGroup("Buttons")] 13 | [Export] protected Button projectsButton; 14 | [Export] protected Button versionsButton; 15 | [Export] protected Button documentationButton; 16 | 17 | public override void _Ready() 18 | { 19 | projectsButton.Toggled += OnProjectsToggled; 20 | versionsButton.Toggled += OnVersionsToggled; 21 | #if DEBUG 22 | documentationButton.Toggled += OnDocumentationToggled; 23 | #endif //DEBUG 24 | 25 | projectsTab.Toggle(projectsButton.ButtonPressed); 26 | versionsTab.Toggle(versionsButton.ButtonPressed); 27 | #if DEBUG 28 | documentationTab.Toggle(documentationButton.ButtonPressed); 29 | #else 30 | documentationButton.Visible = false; 31 | documentationTab.Visible = false; 32 | #endif //DEBUG 33 | } 34 | 35 | protected void OnProjectsToggled(bool pToggle) 36 | { 37 | if (projectsTab.Visible || !pToggle) 38 | return; 39 | 40 | projectsTab.Toggle(true); 41 | versionsTab.Toggle(false); 42 | #if DEBUG 43 | documentationTab.Toggle(false); 44 | #endif //DEBUG 45 | } 46 | 47 | protected void OnVersionsToggled(bool pToggle) 48 | { 49 | if (versionsTab.Visible || !pToggle) 50 | return; 51 | 52 | versionsTab.Toggle(true); 53 | projectsTab.Toggle(false); 54 | #if DEBUG 55 | documentationTab.Toggle(false); 56 | #endif //DEBUG 57 | } 58 | 59 | #if DEBUG 60 | protected void OnDocumentationToggled(bool pToggle) 61 | { 62 | if (documentationTab.Visible || !pToggle) 63 | return; 64 | 65 | documentationTab.Toggle(true); 66 | projectsTab.Toggle(false); 67 | versionsTab.Toggle(false); 68 | } 69 | #endif //DEBUG 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /scripts/core/utils/TimeFormater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils 4 | { 5 | public static class TimeFormater 6 | { 7 | private const string YEAR = "year"; 8 | private const string MONTH = "month"; 9 | private const string DAY = "day"; 10 | private const string HOUR = "hour"; 11 | private const string MINUTE = "minute"; 12 | private const string SECOND = "second"; 13 | private const string NOW = "Now"; 14 | 15 | public static string Format(DateTime pTime) 16 | { 17 | DateTime lCurrentTime = DateTime.UtcNow; 18 | TimeSpan lDifferenceSpan = lCurrentTime - pTime; 19 | 20 | // Basic comparisons 21 | if (lDifferenceSpan.TotalSeconds < 1d) 22 | { 23 | return NOW; 24 | } 25 | 26 | if (lDifferenceSpan.TotalMinutes < 1d) 27 | { 28 | return FormatInternal((int)Math.Floor(lDifferenceSpan.TotalSeconds), SECOND); 29 | } 30 | 31 | if (lDifferenceSpan.TotalHours < 1d) 32 | { 33 | return FormatInternal((int)Math.Floor(lDifferenceSpan.TotalMinutes), MINUTE); 34 | } 35 | 36 | if (lDifferenceSpan.TotalDays < 1d) 37 | { 38 | return FormatInternal((int)Math.Floor(lDifferenceSpan.TotalHours), HOUR); 39 | } 40 | 41 | // Comparisons that need more information on the date of the year 42 | int lYearDiff = (int)Math.Floor(lDifferenceSpan.TotalDays / 365.2425); 43 | 44 | if (lYearDiff > 0) 45 | { 46 | return FormatInternal(lYearDiff, YEAR); 47 | } 48 | 49 | if (lCurrentTime.Month == pTime.Month) 50 | { 51 | return FormatInternal((int)Math.Floor(lDifferenceSpan.TotalDays), DAY); 52 | } 53 | 54 | int lMonthDiff = lCurrentTime.Month - pTime.Month; 55 | 56 | if (lMonthDiff < 0) 57 | { 58 | lMonthDiff += 12; 59 | } 60 | 61 | if (lMonthDiff == 1 && lCurrentTime.Day < pTime.Day) 62 | { 63 | return FormatInternal((int)Math.Floor(lDifferenceSpan.TotalDays), DAY); 64 | } 65 | 66 | return FormatInternal(lMonthDiff, MONTH); 67 | } 68 | 69 | private static string FormatInternal(int pValue, string pSuffix) 70 | { 71 | // Will need refactoring if localisation is added 72 | return $"{pValue} {pSuffix}{(pValue > 1 ? "s" : "")} ago"; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /GodotHubUpdater.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | Com.Astral.GodotHub.Updater 9 | bin\GodotHubUpdater\ 10 | obj\GodotHubUpdater\ 11 | Com.Astral.GodotHub.Updater.UpdateProgram 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /GodotUninstaller.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net6.0 6 | enable 7 | enable 8 | Com.Astral.GodotHub.Uninstaller.UninstallProgram 9 | Com.Astral.GodotHub.Uninstaller 10 | godot_uninstaller.manifest 11 | bin\GodotUninstaller 12 | obj\GodotUninstaller 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /scripts/core/utils/comparisons/Comparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Com.Astral.GodotHub.Core.Utils.Comparisons 4 | { 5 | public static class Comparer 6 | { 7 | public static int CompareFavorites(T pLhs, T pRhs) where T : IFavoriteItem, IValidItem 8 | { 9 | return CompareItems(pLhs, pRhs, (lhs, rhs) => rhs.IsFavorite.CompareTo(lhs.IsFavorite)); 10 | } 11 | 12 | public static int CompareMonos(T pLhs, T pRhs) where T : IMonoItem, IValidItem 13 | { 14 | return CompareItems(pLhs, pRhs, (lhs, rhs) => rhs.IsMono.CompareTo(lhs.IsMono)); 15 | } 16 | 17 | public static int CompareNames(T pLhs, T pRhs) where T : INamedItem, IValidItem 18 | { 19 | return CompareItems(pLhs, pRhs, (lhs, rhs) => lhs.ItemName.CompareTo(rhs.ItemName)); 20 | } 21 | 22 | public static int CompareTimes(T pLhs, T pRhs) where T : ITimedItem, IValidItem 23 | { 24 | return CompareItems(pLhs, pRhs, (lhs, rhs) => lhs.TimeSinceLastOpening.CompareTo(rhs.TimeSinceLastOpening)); 25 | } 26 | 27 | public static int CompareVersions(T pLhs, T pRhs) where T : IVersionItem, IValidItem 28 | { 29 | return CompareItems(pLhs, pRhs, (lhs, rhs) => rhs.Version.CompareTo(lhs.Version)); 30 | } 31 | 32 | public static int ReversedCompareFavorites(T pLhs, T pRhs) where T : IFavoriteItem, IValidItem 33 | { 34 | return CompareFavorites(pRhs, pLhs); 35 | } 36 | 37 | public static int ReversedCompareMonos(T pLhs, T pRhs) where T : IMonoItem, IValidItem 38 | { 39 | return CompareMonos(pRhs, pLhs); 40 | } 41 | 42 | public static int ReversedCompareNames(T pLhs, T pRhs) where T : INamedItem, IValidItem 43 | { 44 | return CompareNames(pRhs, pLhs); 45 | } 46 | 47 | public static int ReversedCompareTimes(T pLhs, T pRhs) where T : ITimedItem, IValidItem 48 | { 49 | return CompareTimes(pRhs, pLhs); 50 | } 51 | 52 | public static int ReversedCompareVersions(T pLhs, T pRhs) where T : IVersionItem, IValidItem 53 | { 54 | return CompareVersions(pRhs, pLhs); 55 | } 56 | 57 | private static int CompareItems(T pLhs, T pRhs, Func pComparison) where T : IValidItem 58 | { 59 | if (pLhs.IsValid ^ pRhs.IsValid) 60 | { 61 | return pLhs.IsValid ? -1 : 1; 62 | } 63 | 64 | return pComparison(pLhs, pRhs); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /scripts/core/debug/ExceptionHandler.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | using Colors = Com.Astral.GodotHub.Core.Utils.Colors; 5 | 6 | namespace Com.Astral.GodotHub.Core.Debug 7 | { 8 | public partial class ExceptionHandler : Node 9 | { 10 | public enum ExceptionGravity 11 | { 12 | Message, 13 | Warning, 14 | Error, 15 | } 16 | 17 | public static ExceptionHandler Singleton { get; private set; } 18 | 19 | [Export] protected PackedScene popupScene; 20 | [ExportGroup("Colors")] 21 | [Export] protected Color warningColor = new Color(1f, 1f, 0f); 22 | [Export] protected Color errorColor = new Color(1f, 0f, 0f); 23 | 24 | public override void _EnterTree() 25 | { 26 | Singleton = this; 27 | } 28 | 29 | public override void _ExitTree() 30 | { 31 | Singleton = null; 32 | } 33 | 34 | public void LogException(Exception pException, bool pLogOnConsole = true) 35 | { 36 | if (pLogOnConsole) 37 | { 38 | Debugger.LogException(pException); 39 | } 40 | 41 | LogMessage(pException.Message, pException.GetType().ToString(), ExceptionGravity.Error); 42 | } 43 | 44 | public void LogMessage(string pMessage, string pTitle = null, ExceptionGravity pGravity = ExceptionGravity.Message) 45 | { 46 | Color? lColor = pGravity switch { 47 | ExceptionGravity.Error => errorColor, 48 | ExceptionGravity.Warning => warningColor, 49 | _ => null 50 | }; 51 | 52 | CreatePopup(pMessage, pTitle ?? pGravity.ToString(), lColor); 53 | } 54 | 55 | private void CreatePopup(string pMessage, string pTitle, Color? pColor = null) 56 | { 57 | AcceptDialog lPopup = popupScene.Instantiate(); 58 | AddChild(lPopup); 59 | 60 | if (pColor != null) 61 | { 62 | StyleBoxFlat lStyleBox = lPopup.GetThemeStylebox("panel").Duplicate() as StyleBoxFlat; 63 | lStyleBox.BorderColor = (Color)pColor; 64 | lPopup.AddThemeStyleboxOverride("panel", lStyleBox); 65 | lStyleBox = lPopup.GetThemeStylebox("embedded_border").Duplicate() as StyleBoxFlat; 66 | lStyleBox.BgColor = (Color)pColor; 67 | lPopup.AddThemeStyleboxOverride("embedded_border", lStyleBox); 68 | } 69 | 70 | lPopup.GetOkButton().FocusMode = Control.FocusModeEnum.None; 71 | lPopup.PopupCentered(); 72 | lPopup.Title = pTitle; 73 | lPopup.DialogText = pMessage; 74 | lPopup.CloseRequested += () => lPopup.QueueFree(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /GodotInstaller.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net6.0 6 | enable 7 | enable 8 | Com.Astral.GodotHub.Installer.InstallProgram 9 | godot_installer.manifest 10 | Com.Astral.GodotHub.Installer 11 | True 12 | False 13 | bin\GodotInstaller 14 | obj\GodotInstaller 15 | 16 | 17 | 18 | 1701;1702;IDE0090;IDE0063 19 | bin\Debug\ 20 | 21 | 22 | 23 | 1701;1702;IDE0090;IDE0063 24 | bin\Release\ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /scripts/core/data/Source.cs: -------------------------------------------------------------------------------- 1 | using Octokit; 2 | 3 | namespace Com.Astral.GodotHub.Core.Data 4 | { 5 | /// 6 | /// Struct representing a with additional data 7 | /// 8 | public class Source 9 | { 10 | /// 11 | /// Specific asset from a github release 12 | /// 13 | public ReleaseAsset asset; 14 | /// 15 | /// of the release 16 | /// 17 | public Version version; 18 | /// 19 | /// Whether or not it has C# support 20 | /// 21 | public bool mono; 22 | /// 23 | /// Target of the release 24 | /// 25 | public OS os; 26 | /// 27 | /// Target of the release 28 | /// 29 | public Architecture? architecture; 30 | 31 | public Source() { } 32 | 33 | public Source(ReleaseAsset pAsset, Version pVersion, bool pMono, OS pOS, Architecture? pArchitecture = null) 34 | { 35 | asset = pAsset; 36 | version = pVersion; 37 | mono = pMono; 38 | os = pOS; 39 | architecture = pArchitecture; 40 | } 41 | 42 | /// 43 | /// Return the of the release 44 | /// 45 | public static Version GetVersion(Release pRelease) 46 | { 47 | return (Version)pRelease.TagName; 48 | } 49 | 50 | /// 51 | /// Whether or not the has C# support 52 | /// 53 | public static bool IsMono(ReleaseAsset pAsset) 54 | { 55 | return pAsset.Name.Contains("mono"); 56 | } 57 | 58 | /// 59 | /// Return the target of the 60 | /// 61 | public static OS GetOS(ReleaseAsset pAsset) 62 | { 63 | if (pAsset.Name.Contains("win")) 64 | { 65 | return OS.Windows; 66 | } 67 | else if (pAsset.Name.Contains("linux")) 68 | { 69 | return OS.Linux; 70 | } 71 | else 72 | { 73 | return OS.MacOS; 74 | } 75 | } 76 | 77 | /// 78 | /// Return the target of the 79 | /// 80 | public static Architecture GetArchitecture(ReleaseAsset pAsset) 81 | { 82 | if (pAsset.Name.Contains("64")) 83 | { 84 | return Architecture.x64; 85 | } 86 | else 87 | { 88 | return Architecture.x32; 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /scripts/updater/UpdateProgram.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Updater 2 | { 3 | internal static class UpdateProgram 4 | { 5 | private static readonly string Appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).Replace('\\', '/') + "/Godot Hub"; 6 | 7 | private static readonly string NewProjectsPath = Appdata + "/projects.cfg"; 8 | private static readonly string NewEnginesPath = Appdata + "/engines.cfg"; 9 | 10 | private static readonly string[] OldProjectsPaths = new string[] { 11 | Appdata + "/project.cfg", 12 | }; 13 | private static readonly string[] OldEnginesPaths = new string[] { 14 | Appdata + "/installs.cfg", 15 | }; 16 | 17 | public static void Main(string[] pArgs) 18 | { 19 | bool lAutoDeleteSource = pArgs.Length > 0 && (pArgs[0].ToLower() == "-d" || pArgs[0].ToLower() == "--delete"); 20 | 21 | if (UpdatePath(OldProjectsPaths, NewProjectsPath, lAutoDeleteSource)) 22 | { 23 | Console.WriteLine("Projects data updated."); 24 | } 25 | else 26 | { 27 | Console.WriteLine("Projects data can't be updated."); 28 | } 29 | 30 | if (UpdatePath(OldEnginesPaths, NewEnginesPath, lAutoDeleteSource)) 31 | { 32 | Console.WriteLine("Engines data updated."); 33 | } 34 | else 35 | { 36 | Console.WriteLine("Engines data can't be updated."); 37 | } 38 | 39 | Console.WriteLine("\nPress any key to close the window"); 40 | Console.ReadKey(); 41 | } 42 | 43 | private static bool UpdatePath(string[] pOldPaths, string pNewPath, bool pDeleteSource = false) 44 | { 45 | for (int i = 0; i < pOldPaths.Length; i++) 46 | { 47 | if (CopyFile(pOldPaths[i], pNewPath, pDeleteSource)) 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | private static bool CopyFile(string pSource, string pDestination, bool pDeleteSource) 55 | { 56 | if (!File.Exists(pSource)) 57 | return false; 58 | 59 | try 60 | { 61 | using ( 62 | FileStream lSourceFStream = new FileStream(pSource, FileMode.Open), 63 | lDestFStream = new FileStream(pDestination, FileMode.OpenOrCreate) 64 | ) 65 | { 66 | lSourceFStream.CopyTo(lDestFStream); 67 | lDestFStream.Close(); 68 | lSourceFStream.Close(); 69 | } 70 | } 71 | catch (Exception lException) 72 | { 73 | Console.WriteLine(lException); 74 | return false; 75 | } 76 | 77 | if (pDeleteSource) 78 | { 79 | File.Delete(pSource); 80 | } 81 | 82 | return true; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /scripts/installer/InstallProgram.cs: -------------------------------------------------------------------------------- 1 | namespace Com.Astral.GodotHub.Installer 2 | { 3 | internal class InstallProgram 4 | { 5 | //arg[0] = --mode (--write_zip | --unzip) 6 | public static void Main(string[] pArgs) 7 | { 8 | using (Mutex lMutex = Mutex.OpenExisting(InstallerConstants.MUTEX_NAME)) 9 | { 10 | if (pArgs.Length == 0) 11 | { 12 | Console.WriteLine("No argument given"); 13 | Console.ReadKey(); 14 | throw new ArgumentException("No argument given"); 15 | } 16 | 17 | switch (pArgs[0]) 18 | { 19 | case InstallerConstants.WRITE_ARGUMENT: 20 | goto WRITE; 21 | case InstallerConstants.EXTRACT_ARGUMENT: 22 | goto EXTRACT; 23 | default: 24 | throw new ArgumentException($"Invalid mode given: {pArgs[0]}"); 25 | } 26 | 27 | #region WRITE 28 | 29 | WRITE: 30 | lMutex.WaitOne(); 31 | 32 | try 33 | { 34 | AdminInstaller.WriteZip(); 35 | } 36 | catch (Exception e) 37 | { 38 | Console.WriteLine($"Writing exception:\n{e}"); 39 | Console.ReadKey(); 40 | lMutex.ReleaseMutex(); 41 | throw; 42 | } 43 | 44 | lMutex.ReleaseMutex(); 45 | 46 | #endregion //WRITE 47 | 48 | #region EXTRACT 49 | 50 | EXTRACT: 51 | lMutex.WaitOne(); 52 | 53 | switch (AdminInstaller.Jump()) 54 | { 55 | case (byte)JumpInstruction.Delete: 56 | goto DELETE; 57 | case (byte)JumpInstruction.Cancel: 58 | AdminInstaller.CancelInstall(true, false); 59 | goto END; 60 | default: 61 | break; 62 | } 63 | 64 | try 65 | { 66 | AdminInstaller.Extract(); 67 | } 68 | catch (Exception e) 69 | { 70 | Console.WriteLine($"Extraction exception:\n{e}"); 71 | Console.ReadKey(); 72 | lMutex.ReleaseMutex(); 73 | throw; 74 | } 75 | 76 | lMutex.ReleaseMutex(); 77 | 78 | #endregion //EXTRACT 79 | 80 | #region DELETE 81 | 82 | lMutex.WaitOne(); 83 | 84 | if (AdminInstaller.Jump() == (byte)JumpInstruction.Cancel) 85 | { 86 | AdminInstaller.CancelInstall(true, true); 87 | goto END; 88 | } 89 | 90 | DELETE: 91 | try 92 | { 93 | AdminInstaller.DeleteZip(); 94 | } 95 | catch (Exception e) 96 | { 97 | Console.WriteLine($"Deletion exception:\n{e}"); 98 | Console.ReadKey(); 99 | lMutex.ReleaseMutex(); 100 | throw; 101 | } 102 | 103 | #endregion //DELETE 104 | 105 | END: 106 | lMutex.ReleaseMutex(); 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /scenes/versions/installer.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://3ek1c5uks77u"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_6dfu7"] 4 | [ext_resource type="Script" path="res://scripts/core/tabs/versions/Installer.cs" id="1_ke4qi"] 5 | [ext_resource type="Theme" uid="uid://c2cgnbja48m7i" path="res://resources/themes/close_btn.theme" id="3_gl0mp"] 6 | 7 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i8jxo"] 8 | bg_color = Color(0.117647, 0.117647, 0.117647, 1) 9 | 10 | [node name="Installer" type="Panel" node_paths=PackedStringArray("versionLabel", "statusLabel", "loadingBar", "cancelButton")] 11 | clip_contents = true 12 | custom_minimum_size = Vector2(0, 100) 13 | offset_right = 320.0 14 | offset_bottom = 100.0 15 | theme = ExtResource("1_6dfu7") 16 | theme_override_styles/panel = SubResource("StyleBoxFlat_i8jxo") 17 | script = ExtResource("1_ke4qi") 18 | closeDuration = 0.2 19 | versionLabel = NodePath("VersionLabel") 20 | statusLabel = NodePath("StatusLabel") 21 | loadingBar = NodePath("ProgressBar") 22 | cancelButton = NodePath("CancelButton") 23 | 24 | [node name="VersionLabel" type="Label" parent="."] 25 | layout_mode = 1 26 | anchors_preset = -1 27 | anchor_right = 1.0 28 | offset_left = 10.0 29 | offset_top = 5.0 30 | offset_right = -10.0 31 | grow_horizontal = 2 32 | theme_override_colors/font_color = Color(0.588235, 0.588235, 0.588235, 1) 33 | theme_override_font_sizes/font_size = 14 34 | text = "Godot 4.0.4 Mono Windows x64" 35 | horizontal_alignment = 1 36 | vertical_alignment = 1 37 | 38 | [node name="StatusLabel" type="Label" parent="."] 39 | layout_mode = 1 40 | anchors_preset = -1 41 | anchor_top = 0.5 42 | anchor_right = 1.0 43 | anchor_bottom = 0.5 44 | offset_left = 25.0 45 | offset_top = -10.0 46 | offset_right = -25.0 47 | offset_bottom = 20.0 48 | grow_horizontal = 2 49 | grow_vertical = 2 50 | text = "Downloading" 51 | horizontal_alignment = 1 52 | vertical_alignment = 1 53 | 54 | [node name="ProgressBar" type="ProgressBar" parent="."] 55 | layout_mode = 1 56 | anchors_preset = -1 57 | anchor_top = 1.0 58 | anchor_right = 1.0 59 | anchor_bottom = 1.0 60 | offset_left = 20.0 61 | offset_top = -15.0 62 | offset_right = -20.0 63 | offset_bottom = -11.0 64 | grow_horizontal = 2 65 | grow_vertical = 0 66 | 67 | [node name="CancelButton" type="Button" parent="."] 68 | custom_minimum_size = Vector2(15, 15) 69 | layout_mode = 1 70 | anchors_preset = -1 71 | anchor_left = 1.0 72 | anchor_right = 1.0 73 | offset_left = -25.0 74 | offset_top = 7.5 75 | offset_right = -10.0 76 | offset_bottom = 22.5 77 | grow_horizontal = 0 78 | focus_mode = 0 79 | theme = ExtResource("3_gl0mp") 80 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 6 | 7 | ## [Unreleased] 8 | 9 | ### Added 10 | - GodotHub updater to update config files 11 | - Option to delete old data when updating data to new version with GodotHubUpdater 12 | 13 | ### Changed 14 | - Release item text alignement 15 | - Rename installs as versions and install items as engine items 16 | - Rename config files 17 | 18 | ### Fixed 19 | - Application version not shown on build 20 | - Bad C# solution initialization on mono project creation 21 | 22 | ### Removed 23 | 24 | 25 | ## [0.1.3] - 2024-02-08 26 | 27 | ### Added 28 | - Tooltip on project path and version path 29 | - Process elevation for engine installation and deletion on windows 30 | - "Update Repo" button to check for new releases without restarting the application 31 | - Icon creation when creating a new project 32 | - Changelog 33 | 34 | ### Changed 35 | - Tab buttons always have the same space between them 36 | 37 | ### Fixed 38 | - Focus on "Add" button in installs tab removed 39 | - Install items auto sort when adding a new item 40 | - Check installs config file when checking if an engine is installed 41 | - Date going crazy after new year 42 | 43 | ## [0.1.2] - 2023-11-05 44 | 45 | ### Added 46 | - Error popups 47 | 48 | ### Changed 49 | - Use only alpha for splash screen animation 50 | 51 | ### Fixed 52 | - Repository first initialization 53 | 54 | ## [0.1.1] - 2023-09-24 55 | 56 | ### Added 57 | - Install item instantiation only if the downloaded engine is put in the config file 58 | - Project creation for supported versions 59 | 60 | ### Changed 61 | - Increased sorting button size in installs tab 62 | 63 | ### Fixed 64 | - Project items auto sort when adding a new item 65 | - Syntax error in linux and macos builds 66 | 67 | ## [0.1] - 2023-09-18 68 | 69 | ### Added 70 | - Releases download from Github 71 | - Projects tab 72 | - Installs tab 73 | - Releases tab 74 | - Settings panel 75 | - Config files 76 | * Store settings, projects and engine versions 77 | - Release item 78 | * Release configuration before download 79 | * OS selection 80 | * Architecture selection 81 | * C# support selection 82 | * Check for installed versions 83 | - Items sorting 84 | - Download status 85 | - Releases storage on disk 86 | - Project item 87 | * Project opening 88 | * Project deletion (only in config file) 89 | * Engine version selection 90 | * Favorite tag 91 | * Project item sorting 92 | - Project addition in project tab ("Add" button in project tab) 93 | - Check for project in default folder 94 | - Support for releases greater or equal to 3.1.1 95 | - UI theme 96 | - License 97 | - Readme 98 | 99 | [unreleased]: https://github.com/Astral-Sheep/GodotHub/compare/0.1.3...HEAD 100 | [0.1.3]: https://github.com/Astral-Sheep/GodotHub/compare/0.1.2...0.1.3 101 | [0.1.2]: https://github.com/Astral-Sheep/GodotHub/compare/0.1.1...0.1.2 102 | [0.1.1]: https://github.com/Astral-Sheep/GodotHub/compare/0.1...0.1.1 103 | [0.1]: https://github.com/Astral-Sheep/GodotHub/releases/tag/0.1 104 | -------------------------------------------------------------------------------- /scripts/installer/AdminInstaller.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Compression; 2 | using System.IO.MemoryMappedFiles; 3 | using System.Text; 4 | 5 | namespace Com.Astral.GodotHub.Installer 6 | { 7 | internal static class AdminInstaller 8 | { 9 | internal static void WriteZip() 10 | { 11 | byte[] lContent; 12 | 13 | using (MemoryMappedFile lMMFile = MemoryMappedFile.OpenExisting(InstallerConstants.DOWNLOAD_MAP_NAME)) 14 | { 15 | using (MemoryMappedViewStream lMMVStream = lMMFile.CreateViewStream()) 16 | { 17 | lContent = new byte[lMMVStream.Length]; 18 | lMMVStream.Read(lContent, 0, lContent.Length); 19 | lMMVStream.Close(); 20 | } 21 | } 22 | 23 | using (FileStream lFStream = new FileStream(GetZipPath(), FileMode.Create)) 24 | { 25 | lFStream.Write(lContent, 0, lContent.Length); 26 | lFStream.Close(); 27 | } 28 | } 29 | 30 | internal static void Extract() 31 | { 32 | ZipFile.ExtractToDirectory( 33 | GetZipPath(), 34 | GetExtractPath() 35 | ); 36 | } 37 | 38 | internal static void DeleteZip() 39 | { 40 | File.Delete(GetZipPath()); 41 | } 42 | 43 | internal static void CancelInstall(bool pDeleteZip, bool pDeleteExecutable) 44 | { 45 | if (pDeleteZip) 46 | { 47 | string lZip = GetZipPath(); 48 | 49 | if (File.Exists(lZip)) 50 | { 51 | File.Delete(lZip); 52 | } 53 | } 54 | 55 | if (pDeleteExecutable) 56 | { 57 | string lExecutable = GetExtractPath(); 58 | 59 | if (File.Exists(lExecutable)) 60 | { 61 | File.Delete(lExecutable); 62 | } 63 | else if (Directory.Exists(lExecutable)) 64 | { 65 | Directory.Delete(lExecutable); 66 | } 67 | } 68 | } 69 | 70 | internal static byte Jump() 71 | { 72 | using (MemoryMappedFile lMMFile = MemoryMappedFile.OpenExisting(InstallerConstants.JUMP_MAP_NAME)) 73 | { 74 | using (MemoryMappedViewStream lMMVStream = lMMFile.CreateViewStream()) 75 | { 76 | byte[] lBytes = new byte[1]; 77 | lMMVStream.Read(lBytes, 0, 1); 78 | return lBytes[0]; 79 | } 80 | } 81 | } 82 | 83 | private static string GetZipPath() 84 | { 85 | return GetStringFromMap(InstallerConstants.ZIP_MAP_NAME); 86 | } 87 | 88 | private static string GetExtractPath() 89 | { 90 | return GetStringFromMap(InstallerConstants.EXTRACT_MAP_NAME); 91 | } 92 | 93 | private static string GetStringFromMap(string pMapName) 94 | { 95 | using (MemoryMappedFile lMMFile = MemoryMappedFile.OpenExisting(pMapName)) 96 | { 97 | using (MemoryMappedViewStream lMMVStream = lMMFile.CreateViewStream()) 98 | { 99 | byte[] lStringBytes = new byte[lMMVStream.Length]; 100 | lMMVStream.Read(lStringBytes, 0, lStringBytes.Length); 101 | lMMVStream.Close(); 102 | string lString = Encoding.UTF8.GetString(lStringBytes); 103 | 104 | // Since the stream has a static size, the string can be shorter than the allocated space. 105 | // The remaining bytes are set to 0, and we don't want to recover that part, 106 | // thus the lString[..lString.IndexOf('\0')] 107 | return lString[..lString.IndexOf('\0')]; 108 | } 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /scenes/versions/release_item.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://c75ty2plb2sys"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_0r2wn"] 4 | [ext_resource type="Script" path="res://scripts/core/tabs/versions/ReleaseItem.cs" id="1_ukbs0"] 5 | [ext_resource type="Theme" uid="uid://m20yduadk25m" path="res://resources/themes/half_blue_btn.theme" id="3_78hul"] 6 | 7 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_d0sgs"] 8 | bg_color = Color(0.117647, 0.117647, 0.117647, 1) 9 | 10 | [node name="ReleaseItem" type="Panel" node_paths=PackedStringArray("versionLabel", "dateLabel", "monoCheck", "osButton", "architectureButton", "installButton")] 11 | clip_contents = true 12 | custom_minimum_size = Vector2(0, 75) 13 | offset_right = 850.0 14 | offset_bottom = 75.0 15 | theme = ExtResource("1_0r2wn") 16 | theme_override_styles/panel = SubResource("StyleBoxFlat_d0sgs") 17 | script = ExtResource("1_ukbs0") 18 | versionLabel = NodePath("Version") 19 | dateLabel = NodePath("Date") 20 | monoCheck = NodePath("MonoCheck") 21 | osButton = NodePath("OSOption") 22 | architectureButton = NodePath("ArchitectureOption") 23 | installButton = NodePath("InstallButton") 24 | 25 | [node name="Version" type="RichTextLabel" parent="."] 26 | layout_mode = 1 27 | anchors_preset = -1 28 | anchor_right = 0.2 29 | anchor_bottom = 1.0 30 | offset_left = 25.0 31 | offset_top = 15.0 32 | offset_bottom = -35.0 33 | grow_horizontal = 2 34 | grow_vertical = 2 35 | bbcode_enabled = true 36 | text = "[b]Godot 1.0.0[/b]" 37 | 38 | [node name="Date" type="Label" parent="."] 39 | layout_mode = 1 40 | anchors_preset = -1 41 | anchor_top = 1.0 42 | anchor_right = 0.2 43 | anchor_bottom = 1.0 44 | offset_left = 25.0 45 | offset_top = -35.0 46 | offset_bottom = -20.0 47 | grow_vertical = 0 48 | theme_override_colors/font_color = Color(0.588235, 0.588235, 0.588235, 1) 49 | theme_override_font_sizes/font_size = 10 50 | text = "jj/mm/yyyy" 51 | vertical_alignment = 1 52 | 53 | [node name="MonoCheck" type="CheckBox" parent="."] 54 | layout_mode = 1 55 | anchors_preset = -1 56 | anchor_left = 0.25 57 | anchor_right = 0.25 58 | anchor_bottom = 1.0 59 | offset_top = 10.0 60 | offset_bottom = -10.0 61 | focus_mode = 0 62 | button_pressed = true 63 | text = "Mono" 64 | 65 | [node name="OSOption" type="OptionButton" parent="."] 66 | layout_mode = 1 67 | anchors_preset = -1 68 | anchor_left = 0.4 69 | anchor_right = 0.55 70 | anchor_bottom = 1.0 71 | offset_top = 10.0 72 | offset_bottom = -10.0 73 | focus_mode = 0 74 | text_overrun_behavior = 3 75 | 76 | [node name="ArchitectureOption" type="OptionButton" parent="."] 77 | layout_mode = 1 78 | anchors_preset = -1 79 | anchor_left = 0.6 80 | anchor_right = 0.7 81 | anchor_bottom = 1.0 82 | offset_top = 10.0 83 | offset_bottom = -10.0 84 | focus_mode = 0 85 | text_overrun_behavior = 3 86 | 87 | [node name="InstallButton" type="Button" parent="."] 88 | layout_mode = 1 89 | anchors_preset = -1 90 | anchor_left = 1.0 91 | anchor_right = 1.0 92 | anchor_bottom = 1.0 93 | offset_top = 15.0 94 | offset_right = -25.0 95 | offset_bottom = -15.0 96 | grow_horizontal = 0 97 | focus_mode = 0 98 | theme = ExtResource("3_78hul") 99 | text = "Install" 100 | -------------------------------------------------------------------------------- /scripts/core/debug/Debugger.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Godot; 3 | using System; 4 | using Com.Astral.GodotHub.Core.Utils; 5 | using Colors = Com.Astral.GodotHub.Core.Utils.Colors; 6 | 7 | namespace Com.Astral.GodotHub.Core.Debug 8 | { 9 | /// 10 | /// In-app console 11 | /// 12 | public sealed partial class Debugger : Control 13 | { 14 | /// 15 | /// Whether or not the console is visible 16 | /// 17 | public static bool Enabled 18 | { 19 | get => instance.Visible; 20 | set 21 | { 22 | if (instance.Visible == value) 23 | return; 24 | 25 | instance.Visible = value; 26 | } 27 | } 28 | 29 | private static Debugger instance; 30 | 31 | [ExportGroup("Parameters")] 32 | [Export] private RichTextLabel label; 33 | 34 | private Debugger() : base() 35 | { 36 | if (instance != null) 37 | { 38 | GD.PushWarning($"{nameof(Debugger)} instance already exists, destroying the last added."); 39 | Free(); 40 | return; 41 | } 42 | 43 | instance = this; 44 | } 45 | 46 | public override void _Ready() 47 | { 48 | if (!label.BbcodeEnabled) 49 | { 50 | label.BbcodeEnabled = true; 51 | } 52 | 53 | Enabled = AppConfig.Debug; 54 | } 55 | 56 | protected override void Dispose(bool pDisposing) 57 | { 58 | if (!pDisposing) 59 | return; 60 | 61 | if (instance == this) 62 | { 63 | instance = null; 64 | } 65 | } 66 | 67 | /// 68 | /// Print an in 69 | /// 70 | public static void LogObject(object pObject) 71 | { 72 | LogMessage(pObject.ToString()); 73 | } 74 | 75 | /// 76 | /// Print a message in 77 | /// 78 | public static void LogMessage(string pMessage) 79 | { 80 | instance.label.Text += FormatMessage(pMessage, Colors.Singleton.White); 81 | } 82 | 83 | /// 84 | /// Print a message in 85 | /// 86 | public static void LogValidation(string pMessage) 87 | { 88 | instance.label.Text += FormatMessage(pMessage, Colors.Singleton.Green); 89 | } 90 | 91 | /// 92 | /// Print a message in 93 | /// 94 | public static void LogWarning(string pMessage) 95 | { 96 | instance.label.Text += FormatMessage(pMessage, Colors.Singleton.Yellow); 97 | } 98 | 99 | /// 100 | /// Print a message in bold 101 | /// 102 | public static void LogError(string pMessage) 103 | { 104 | instance.label.Text += FormatMessage($"[b]{pMessage}[/b]", Colors.Singleton.Red); 105 | } 106 | 107 | /// 108 | /// Print an in bold 109 | /// 110 | public static void LogException(Exception pException) 111 | { 112 | LogError($"{pException.GetType()}: {pException.Message}"); 113 | #if DEBUG 114 | GD.PrintErr(pException); 115 | #endif //DEBUG 116 | } 117 | 118 | private static string FormatMessage(string pMessage, Color pColor) 119 | { 120 | return BBCodeT.GetColoredText(pMessage, pColor) + '\n'; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /scripts/core/Main.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Debug; 3 | using Godot; 4 | using System; 5 | 6 | using Error = Com.Astral.GodotHub.Core.Utils.Error; 7 | using GError = Godot.Error; 8 | 9 | namespace Com.Astral.GodotHub.Core 10 | { 11 | public partial class Main : Node 12 | { 13 | private const string CURRENT_VERSION = "0.1.4"; 14 | private static readonly Vector2I DefaultWindowSize = new Vector2I(1100, 600); 15 | 16 | public static Main Instance { get; private set; } 17 | 18 | public event Action Initialized; 19 | 20 | [Export] protected PackedScene fileDialogScene; 21 | 22 | private Main() : base() 23 | { 24 | if (Instance != null) 25 | { 26 | GD.PushWarning($"{nameof(Main)} instance already exists, destroying the last added"); 27 | Free(); 28 | return; 29 | } 30 | 31 | Instance = this; 32 | } 33 | 34 | public override void _EnterTree() 35 | { 36 | DisplayServer.WindowSetMinSize(DefaultWindowSize); 37 | 38 | // ConfigFile lExportPresets = new ConfigFile(); 39 | // lExportPresets.Load("res://export_presets.cfg"); 40 | // string lAppVersion = (string)lExportPresets.GetValue("preset.0.options", "application/product_version", "0.0.0.0"); 41 | // lAppVersion = lAppVersion[..lAppVersion.RFind(".")]; 42 | 43 | DisplayServer.WindowSetTitle( 44 | $"{ProjectSettings.GetSetting("application/config/name", "Godot Hub")}" + 45 | " " + 46 | $"{GetProductVersion()}" 47 | ); 48 | } 49 | 50 | public override void _Ready() 51 | { 52 | Init(); 53 | } 54 | 55 | protected override void Dispose(bool pDisposing) 56 | { 57 | if (!pDisposing) 58 | return; 59 | 60 | if (Instance == this) 61 | { 62 | Instance = null; 63 | } 64 | } 65 | 66 | protected async void Init() 67 | { 68 | Error lError = await GDRepository.Init(); 69 | 70 | if (!lError.Ok) 71 | { 72 | ExceptionHandler.Singleton.LogException(lError.Exception); 73 | } 74 | 75 | Initialized?.Invoke(); 76 | } 77 | 78 | protected string GetProductVersion() 79 | { 80 | ConfigFile lExportPresets = new ConfigFile(); 81 | GError lError = lExportPresets.Load("res://export_presets.cfg"); 82 | 83 | if (lError != GError.Ok) 84 | { 85 | return "0.0.0"; 86 | } 87 | 88 | #if GODOT_WINDOWS 89 | int lPreset = 0; 90 | #elif GODOT_LINUXBSD 91 | int lPreset = 1; 92 | #else 93 | int lPreset = 2; 94 | #endif 95 | 96 | string lVersion = (string)lExportPresets.GetValue($"preset.{lPreset}.options", "application/product_version", "0.0.0.0"); 97 | return lVersion[..lVersion.RFind(".")]; 98 | } 99 | 100 | public FileDialog InstantiateFileDialog(Node pParent = null, bool pAutoFree = true) 101 | { 102 | FileDialog lDialog = fileDialogScene.Instantiate(); 103 | 104 | if (pParent == null) 105 | { 106 | AddChild(lDialog); 107 | } 108 | else 109 | { 110 | pParent.AddChild(lDialog); 111 | } 112 | 113 | lDialog.GetCancelButton().FocusMode = Control.FocusModeEnum.None; 114 | lDialog.GetOkButton().FocusMode = Control.FocusModeEnum.None; 115 | lDialog.PopupCentered(); 116 | 117 | if (pAutoFree) 118 | { 119 | lDialog.CloseRequested += () => lDialog.QueueFree(); 120 | } 121 | 122 | return lDialog; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /scripts/core/tabs/versions/ReleasePanel.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Utils.Comparisons; 3 | using Godot; 4 | using Octokit; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | using Version = Com.Astral.GodotHub.Core.Data.Version; 9 | 10 | namespace Com.Astral.GodotHub.Core.Tabs.Versions 11 | { 12 | public partial class ReleasePanel : SortedPanel 13 | { 14 | [Export] protected PackedScene releaseItemScene; 15 | 16 | [ExportGroup("Sorting")] 17 | [Export] protected SortToggle versionButton; 18 | [Export] protected SortToggle dateButton; 19 | 20 | protected List items = new List(); 21 | protected Comparison currentComparison = CompareIndices; 22 | 23 | public override void _Ready() 24 | { 25 | GDRepository.Loaded += OnRepoLoaded; 26 | } 27 | 28 | protected override void Dispose(bool pDisposing) 29 | { 30 | base.Dispose(pDisposing); 31 | 32 | if (!pDisposing) 33 | return; 34 | 35 | GDRepository.Loaded -= OnRepoLoaded; 36 | GDRepository.Updated -= OnRepoUpdated; 37 | } 38 | 39 | protected void OnRepoLoaded() 40 | { 41 | GDRepository.Loaded -= OnRepoLoaded; 42 | List lReleases = GDRepository.Releases; 43 | Release lRelease; 44 | 45 | for (int i = 0; i < lReleases.Count; i++) 46 | { 47 | lRelease = lReleases[i]; 48 | 49 | if ((Version)lRelease.TagName < Version.minimumSupportedVersion) 50 | continue; 51 | 52 | items.Add(CreateItem(lReleases[i], i)); 53 | } 54 | 55 | Sort(); 56 | 57 | versionButton.CustomToggled += OnVersionToggled; 58 | dateButton.CustomToggled += OnDateToggled; 59 | dateButton.ButtonPressed = true; 60 | 61 | GDRepository.Updated += OnRepoUpdated; 62 | } 63 | 64 | protected void OnRepoUpdated(List pReleases) 65 | { 66 | if (pReleases.Count <= 0) 67 | return; 68 | 69 | for (int i = 0; i < pReleases.Count; i++) 70 | { 71 | if ((Version)pReleases[i].TagName < Version.minimumSupportedVersion) 72 | continue; 73 | 74 | items.Add(CreateItem(pReleases[i], i)); 75 | } 76 | 77 | Sort(); 78 | } 79 | 80 | protected ReleaseItem CreateItem(Release pRelease, int pIndex) 81 | { 82 | ReleaseItem lItem = releaseItemScene.Instantiate(); 83 | itemContainer.AddChild(lItem); 84 | lItem.Init(pRelease, pIndex); 85 | return lItem; 86 | } 87 | 88 | protected void OnVersionToggled(bool pToggled) 89 | { 90 | dateButton.Disable(); 91 | currentComparison = pToggled ? Comparer.CompareVersions : Comparer.ReversedCompareVersions; 92 | Sort(); 93 | } 94 | 95 | protected void OnDateToggled(bool pToggled) 96 | { 97 | versionButton.Disable(); 98 | currentComparison = pToggled ? CompareIndices : ReversedCompareIndices; 99 | Sort(); 100 | } 101 | 102 | protected void Sort() 103 | { 104 | items.Sort(currentComparison); 105 | 106 | for (int i = 0; i < items.Count; i++) 107 | { 108 | itemContainer.MoveChild(items[i], i); 109 | } 110 | } 111 | 112 | protected static int CompareIndices(ReleaseItem pLhs, ReleaseItem pRhs) 113 | { 114 | return pLhs.Index - pRhs.Index; 115 | } 116 | 117 | protected static int ReversedCompareIndices(ReleaseItem pLhs, ReleaseItem pRhs) 118 | { 119 | return CompareIndices(pRhs, pLhs); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /scripts/core/settings/SettingsPanel.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Settings.Buttons; 3 | using Godot; 4 | using Godot.Collections; 5 | using System.Collections.Generic; 6 | 7 | namespace Com.Astral.GodotHub.Core.Settings 8 | { 9 | public partial class SettingsPanel : Control 10 | { 11 | [Export] protected Control content; 12 | [Export] protected float openDuration = 0.2f; 13 | 14 | [ExportGroup("Buttons")] 15 | [Export] protected Button openButton; 16 | [Export] protected Button closeButton; 17 | [Export] protected Button backgroundButton; 18 | [ExportSubgroup("Settings buttons")] 19 | [Export] protected Array buttonsPath; 20 | 21 | protected List buttons; 22 | protected (float top, float bottom) anchor; 23 | 24 | public override void _Ready() 25 | { 26 | #if DEBUG 27 | Visible = true; 28 | #endif //DEBUG 29 | 30 | buttons = new List(); 31 | 32 | for (int i = 0; i < buttonsPath.Count; i++) 33 | { 34 | buttons.Add(GetNode(buttonsPath[i])); 35 | } 36 | 37 | anchor = (content.AnchorTop, content.AnchorBottom); 38 | CloseInstant(); 39 | openButton.Pressed += OnOpenPressed; 40 | } 41 | 42 | protected override void Dispose(bool pDisposing) 43 | { 44 | if (!pDisposing) 45 | return; 46 | 47 | if (openButton != null) 48 | { 49 | openButton.Pressed -= OnOpenPressed; 50 | } 51 | } 52 | 53 | protected void EnableButtons() 54 | { 55 | for (int i = 0; i < buttons.Count; i++) 56 | { 57 | buttons[i].Connect(); 58 | } 59 | } 60 | 61 | protected void DisableButtons() 62 | { 63 | for (int i = 0; i < buttons.Count; i++) 64 | { 65 | buttons[i].Disconnect(); 66 | } 67 | } 68 | 69 | protected void OnOpenPressed() 70 | { 71 | Tween lTween = CreateTween() 72 | .SetParallel() 73 | .SetTrans(Tween.TransitionType.Cubic) 74 | .SetEase(Tween.EaseType.Out); 75 | lTween.TweenProperty(content, "anchor_top", anchor.top,openDuration); 76 | lTween.TweenProperty(content, "anchor_bottom", anchor.bottom, openDuration); 77 | lTween.TweenProperty(backgroundButton, "self_modulate", new Color(backgroundButton.SelfModulate, 1f), openDuration); 78 | 79 | EnableButtons(); 80 | openButton.Pressed -= OnOpenPressed; 81 | closeButton.Pressed += OnClosePressed; 82 | backgroundButton.Pressed += OnClosePressed; 83 | backgroundButton.MouseFilter = MouseFilterEnum.Stop; 84 | } 85 | 86 | protected void OnClosePressed() 87 | { 88 | AppConfig.Save(); 89 | 90 | backgroundButton.MouseFilter = MouseFilterEnum.Ignore; 91 | backgroundButton.Pressed -= OnClosePressed; 92 | closeButton.Pressed -= OnClosePressed; 93 | openButton.Pressed += OnOpenPressed; 94 | DisableButtons(); 95 | 96 | Tween lTween = CreateTween() 97 | .SetParallel() 98 | .SetTrans(Tween.TransitionType.Cubic) 99 | .SetEase(Tween.EaseType.In); 100 | lTween.TweenProperty(content, "anchor_top", -anchor.bottom, openDuration); 101 | lTween.TweenProperty(content, "anchor_bottom", anchor.top, openDuration); 102 | lTween.TweenProperty(backgroundButton, "self_modulate", new Color(backgroundButton.SelfModulate, 0f), openDuration); 103 | } 104 | 105 | protected void CloseInstant() 106 | { 107 | content.AnchorTop = -anchor.bottom; 108 | content.AnchorBottom = anchor.top; 109 | backgroundButton.SelfModulate = new Color(backgroundButton.SelfModulate, 0f); 110 | backgroundButton.MouseFilter = MouseFilterEnum.Ignore; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /scripts/core/utils/PathT.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Debug; 2 | using Godot; 3 | using System; 4 | using System.IO; 5 | 6 | using Environment = System.Environment; 7 | using OS = Com.Astral.GodotHub.Core.Data.OS; 8 | using Version = Com.Astral.GodotHub.Core.Data.Version; 9 | 10 | namespace Com.Astral.GodotHub.Core.Utils 11 | { 12 | public static class PathT 13 | { 14 | #if GODOT_WINDOWS 15 | public const string EOL = "\r\n"; 16 | #elif GODOT_MACOS 17 | public const string EOL = "\r"; 18 | #else 19 | public const string EOL = "\n"; 20 | #endif 21 | 22 | private const string MAC_EXE_PATH = "/Contents/MacOS/Godot"; 23 | private const string DEFAULT_EXE_PATH = "/"; 24 | 25 | /// 26 | /// The roaming appdata path 27 | /// 28 | public static readonly string appdata = GetEnvironmentPath(Environment.SpecialFolder.ApplicationData) + "/Godot Hub"; 29 | private static readonly string exePath; 30 | 31 | static PathT() 32 | { 33 | if (!Directory.Exists(appdata)) 34 | { 35 | Directory.CreateDirectory(appdata); 36 | } 37 | 38 | #if GODOT_MACOS 39 | exePath = MAC_EXE_PATH; 40 | #else 41 | exePath = DEFAULT_EXE_PATH; 42 | #endif 43 | } 44 | 45 | public static string FormatLinuxFolder(string pPath) 46 | { 47 | int lIndex = pPath.RFind("linux_x86"); 48 | 49 | if (lIndex >= 0) 50 | { 51 | pPath = $"{pPath[..(lIndex + 5)]}.{pPath[(lIndex + 6)..]}"; 52 | } 53 | 54 | return pPath; 55 | } 56 | 57 | public static string FormatMacOSFolder(string pPath, Version pVersion, bool pMono) 58 | { 59 | int lIndex = pPath.RFind($"Godot{(pMono ? "_mono" : "")}.app"); 60 | 61 | if (lIndex >= 0) 62 | { 63 | string lVersion = $"_v{(string)pVersion}"; 64 | pPath = pPath[..(lIndex + 5)] + lVersion + pPath[(lIndex + 5 + lVersion.Length)..]; 65 | } 66 | 67 | return pPath; 68 | } 69 | 70 | public static string GetMacOSFolderFromZip(string pZip, bool pMono) 71 | { 72 | return pZip[..pZip.RFind("/")] + $"/Godot{(pMono ? "_mono" : "")}.app"; 73 | } 74 | 75 | public static string GetExeFromFolder(string pPath) 76 | { 77 | #if GODOT_MACOS 78 | return pPath + exePath; 79 | #elif GODOT_LINUXBSD 80 | return pPath + pPath[pPath.RFind(exePath)..]; 81 | #else 82 | return pPath + pPath[pPath.RFind(exePath)..] + ".exe"; 83 | #endif 84 | } 85 | 86 | public static string GetExeFromFolder(string pPath, OS pOS) 87 | { 88 | if (pOS == OS.MacOS) 89 | { 90 | return pPath + MAC_EXE_PATH; 91 | } 92 | 93 | string lPath = pPath + pPath[pPath.RFind(DEFAULT_EXE_PATH)..]; 94 | 95 | if (pOS == OS.Windows) 96 | { 97 | lPath += ".exe"; 98 | } 99 | 100 | return lPath; 101 | } 102 | 103 | public static string GetFolderFromExe(string pPath) 104 | { 105 | return pPath[..pPath.RFind(exePath)]; 106 | } 107 | 108 | public static string GetFolderFromExe(string pPath, OS pOS) 109 | { 110 | return pPath[..pPath.RFind(pOS == OS.MacOS ? MAC_EXE_PATH : DEFAULT_EXE_PATH)]; 111 | } 112 | 113 | /// 114 | /// Rename the folder to 115 | /// 116 | public static bool RenameFolder(string pSource, string pTarget) 117 | { 118 | try 119 | { 120 | Directory.Move(pSource, pTarget); 121 | } 122 | catch (Exception lException) 123 | { 124 | Debugger.LogException(lException); 125 | return false; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | /// 132 | /// Get a path with every \ replaced by a / 133 | /// 134 | public static string GetEnvironmentPath(Environment.SpecialFolder pFolder) 135 | { 136 | return Environment.GetFolderPath(pFolder).Replace('\\', '/'); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /godot_installer.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | 62 | 63 | 64 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /godot_uninstaller.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | 62 | 63 | 64 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /scripts/core/tabs/versions/DownloadPanel.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Godot; 3 | using System.Collections.Generic; 4 | 5 | namespace Com.Astral.GodotHub.Core.Tabs.Versions 6 | { 7 | public partial class DownloadPanel : Control 8 | { 9 | [Export] protected float openDuration = 0.2f; 10 | [Export] protected Control panel; 11 | [Export] protected Button background; 12 | 13 | [ExportGroup("Installation")] 14 | [Export] protected PackedScene installerScene; 15 | [Export] protected Control installerContainer; 16 | 17 | [ExportGroup("Buttons")] 18 | [Export] protected Button openButton; 19 | [Export] protected Button closeButton; 20 | 21 | protected List installers = new List(); 22 | protected Tween tween; 23 | 24 | public override void _Ready() 25 | { 26 | panel.Position = new Vector2(-panel.Size.X, panel.Position.Y); 27 | background.MouseFilter = MouseFilterEnum.Ignore; 28 | background.SelfModulate = new Color(background.SelfModulate, 0f); 29 | 30 | CreateCustomTween(Tween.EaseType.Out); 31 | ReleaseItem.InstallPressed += Install; 32 | openButton.Pressed += Open; 33 | Visible = true; 34 | } 35 | 36 | protected override void Dispose(bool pDisposing) 37 | { 38 | if (!pDisposing) 39 | return; 40 | 41 | ReleaseItem.InstallPressed -= Install; 42 | } 43 | 44 | /// 45 | /// Create a new to download and install the given 46 | /// 47 | public void Install(ReleaseItem pItem, Source pSource) 48 | { 49 | Installer lInstaller = installerScene.Instantiate(); 50 | installerContainer.AddChild(lInstaller); 51 | installers.Add(lInstaller); 52 | pItem.Connect(lInstaller); 53 | lInstaller.Init(pSource); 54 | lInstaller.Completed += OnInstallerCompleted; 55 | 56 | if (installers.Count < 2) 57 | { 58 | lInstaller.Install(); 59 | } 60 | } 61 | 62 | protected void OnInstallerCompleted(Installer pInstaller, InstallT.Result _) 63 | { 64 | pInstaller.Completed -= OnInstallerCompleted; 65 | installers.Remove(pInstaller); 66 | 67 | if (installers.Count > 0) 68 | { 69 | Installer lInstaller = installers[0]; 70 | lInstaller.Install(); 71 | } 72 | } 73 | 74 | protected void Open() 75 | { 76 | openButton.Pressed -= Open; 77 | openButton.Pressed += Close; 78 | closeButton.Pressed += Close; 79 | background.Pressed += Close; 80 | 81 | background.MouseFilter = MouseFilterEnum.Stop; 82 | ResetTween(Tween.EaseType.Out); 83 | tween.TweenProperty(background, "self_modulate:a", 1f, openDuration); 84 | tween 85 | .TweenProperty(panel, "position:x", 0, openDuration) 86 | .Finished += OnTweenFinished; 87 | tween.Play(); 88 | } 89 | 90 | protected void Close() 91 | { 92 | background.Pressed -= Close; 93 | closeButton.Pressed -= Close; 94 | openButton.Pressed -= Close; 95 | openButton.Pressed += Open; 96 | 97 | background.MouseFilter = MouseFilterEnum.Ignore; 98 | ResetTween(Tween.EaseType.In); 99 | tween.TweenProperty(background, "self_modulate:a", 0f, openDuration); 100 | tween 101 | .TweenProperty(panel, "position:x", -panel.Size.X, openDuration) 102 | .Finished += OnTweenFinished; 103 | tween.Play(); 104 | } 105 | 106 | protected void OnTweenFinished() 107 | { 108 | tween.Stop(); 109 | } 110 | 111 | protected void ResetTween(Tween.EaseType pEase) 112 | { 113 | if (tween != null && tween.IsValid()) 114 | { 115 | tween.Kill(); 116 | } 117 | 118 | CreateCustomTween(pEase); 119 | } 120 | 121 | protected void CreateCustomTween(Tween.EaseType pEase) 122 | { 123 | tween = CreateTween() 124 | .SetTrans(Tween.TransitionType.Cubic) 125 | .SetEase(pEase); 126 | tween.Stop(); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /assets/default_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/core/data/Version.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Debug; 2 | using System; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace Com.Astral.GodotHub.Core.Data 6 | { 7 | /// 8 | /// Representation of a Godot version as major.minor.patch 9 | /// 10 | public struct Version : IComparable 11 | { 12 | /// 13 | /// s older than this one aren't supported by Godot Hub 14 | /// since it would be too much work for little to no use 15 | /// 16 | public static readonly Version minimumSupportedVersion = new Version(3, 1, 1); 17 | private static readonly Regex expression = new Regex(@"([0-9]+)([.]{1}?[0-9]+){1,2}"); 18 | 19 | public int major; 20 | public int minor; 21 | public int patch; 22 | 23 | public Version(int pMajor, int pMinor, int pPatch) 24 | { 25 | major = pMajor; 26 | minor = pMinor; 27 | patch = pPatch; 28 | } 29 | 30 | /// 31 | /// For 4.x: whether or not each has the same and indices
32 | /// For 3.x: whether or not each has the same index 33 | ///
34 | public bool IsCompatible(Version pOther) 35 | { 36 | if (major >= 4) 37 | { 38 | return major == pOther.major && minor == pOther.minor; 39 | } 40 | else 41 | { 42 | return major == pOther.major; 43 | } 44 | } 45 | 46 | public int CompareTo(Version pOther) 47 | { 48 | if (major == pOther.major) 49 | { 50 | if (minor == pOther.minor) 51 | { 52 | return patch - pOther.patch; 53 | } 54 | 55 | return minor - pOther.minor; 56 | } 57 | 58 | return major - pOther.major; 59 | } 60 | 61 | public override bool Equals(object pObj) 62 | { 63 | if (pObj is Version version) 64 | { 65 | return this == version; 66 | } 67 | 68 | return false; 69 | } 70 | 71 | public override int GetHashCode() 72 | { 73 | return major ^ minor ^ patch; 74 | } 75 | 76 | public override string ToString() 77 | { 78 | return (string)this; 79 | } 80 | 81 | public static bool operator==(Version pLhs, Version pRhs) 82 | { 83 | return pLhs.major == pRhs.major && pLhs.minor == pRhs.minor && pLhs.patch == pRhs.patch; 84 | } 85 | 86 | public static bool operator!=(Version pLhs, Version pRhs) 87 | { 88 | return !(pLhs == pRhs); 89 | } 90 | 91 | public static bool operator <(Version pLhs, Version pRhs) 92 | { 93 | return pLhs.CompareTo(pRhs) < 0; 94 | } 95 | 96 | public static bool operator <=(Version pLhs, Version pRhs) 97 | { 98 | return pLhs.CompareTo(pRhs) <= 0; 99 | } 100 | 101 | public static bool operator >(Version pLhs, Version pRhs) 102 | { 103 | return pLhs.CompareTo(pRhs) > 0; 104 | } 105 | 106 | public static bool operator >=(Version pLhs, Version pRhs) 107 | { 108 | return pLhs.CompareTo(pRhs) >= 0; 109 | } 110 | 111 | public static explicit operator Version(string pValue) 112 | { 113 | Match lMatch = expression.Match(pValue); 114 | 115 | if (!lMatch.Success) 116 | { 117 | Debugger.LogError($"Invalid format: can't convert string \"{pValue}\" to {nameof(Version)}"); 118 | return new Version(0, 0, 0); 119 | } 120 | 121 | CaptureCollection lMinorCapture = lMatch.Groups[2].Captures; 122 | return new Version( 123 | int.Parse(lMatch.Groups[1].Value), 124 | int.Parse(lMinorCapture[0].Value[1..]), 125 | lMinorCapture.Count > 1 ? int.Parse(lMinorCapture[1].Value[1..]) : 0 126 | ); 127 | } 128 | 129 | public static explicit operator string(Version pValue) 130 | { 131 | string lResult = $"{pValue.major}.{pValue.minor}"; 132 | 133 | if (pValue.patch != 0) 134 | { 135 | lResult += $".{pValue.patch}"; 136 | } 137 | 138 | return lResult; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /export_presets.cfg: -------------------------------------------------------------------------------- 1 | [preset.0] 2 | 3 | name="Windows Desktop" 4 | platform="Windows Desktop" 5 | runnable=true 6 | dedicated_server=false 7 | custom_features="" 8 | export_filter="all_resources" 9 | include_filter="export_presets.cfg" 10 | exclude_filter="" 11 | export_path="bin/GodotHub_v0.1.4/GodotHub_v0.1.4_win64/GodotHub_v0.1.4_win64.exe" 12 | encryption_include_filters="" 13 | encryption_exclude_filters="" 14 | encrypt_pck=false 15 | encrypt_directory=false 16 | script_encryption_key="" 17 | 18 | [preset.0.options] 19 | 20 | custom_template/debug="" 21 | custom_template/release="" 22 | debug/export_console_script=1 23 | binary_format/embed_pck=false 24 | texture_format/bptc=true 25 | texture_format/s3tc=true 26 | texture_format/etc=false 27 | texture_format/etc2=false 28 | binary_format/architecture="x86_64" 29 | codesign/enable=false 30 | codesign/identity_type=0 31 | codesign/identity="" 32 | codesign/password="" 33 | codesign/timestamp=true 34 | codesign/timestamp_server_url="" 35 | codesign/digest_algorithm=1 36 | codesign/description="" 37 | codesign/custom_options=PackedStringArray() 38 | application/modify_resources=true 39 | application/icon="res://icon.ico" 40 | application/console_wrapper_icon="" 41 | application/icon_interpolation=4 42 | application/file_version="0.1.4.0" 43 | application/product_version="0.1.4.0" 44 | application/company_name="Astral_Sheep" 45 | application/product_name="Godot Hub" 46 | application/file_description="" 47 | application/copyright="" 48 | application/trademarks="" 49 | ssh_remote_deploy/enabled=false 50 | ssh_remote_deploy/host="user@host_ip" 51 | ssh_remote_deploy/port="22" 52 | ssh_remote_deploy/extra_args_ssh="" 53 | ssh_remote_deploy/extra_args_scp="" 54 | ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' 55 | $action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' 56 | $trigger = New-ScheduledTaskTrigger -Once -At 00:00 57 | $settings = New-ScheduledTaskSettingsSet 58 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings 59 | Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true 60 | Start-ScheduledTask -TaskName godot_remote_debug 61 | while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } 62 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" 63 | ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue 64 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue 65 | Remove-Item -Recurse -Force '{temp_dir}'" 66 | 67 | [preset.1] 68 | 69 | name="Linux/X11" 70 | platform="Linux/X11" 71 | runnable=true 72 | dedicated_server=false 73 | custom_features="" 74 | export_filter="all_resources" 75 | include_filter="" 76 | exclude_filter="" 77 | export_path="bin/GodotHub_v0.1.3/linux_x86_64/Godot Hub.x86_64" 78 | encryption_include_filters="" 79 | encryption_exclude_filters="" 80 | encrypt_pck=false 81 | encrypt_directory=false 82 | script_encryption_key="" 83 | 84 | [preset.1.options] 85 | 86 | custom_template/debug="" 87 | custom_template/release="" 88 | debug/export_console_script=1 89 | binary_format/embed_pck=false 90 | texture_format/bptc=true 91 | texture_format/s3tc=true 92 | texture_format/etc=false 93 | texture_format/etc2=false 94 | binary_format/architecture="x86_64" 95 | ssh_remote_deploy/enabled=false 96 | ssh_remote_deploy/host="user@host_ip" 97 | ssh_remote_deploy/port="22" 98 | ssh_remote_deploy/extra_args_ssh="" 99 | ssh_remote_deploy/extra_args_scp="" 100 | ssh_remote_deploy/run_script="#!/usr/bin/env bash 101 | export DISPLAY=:0 102 | unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" 103 | \"{temp_dir}/{exe_name}\" {cmd_args}" 104 | ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash 105 | kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") 106 | rm -rf \"{temp_dir}\"" 107 | -------------------------------------------------------------------------------- /scenes/projects/project_item.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=3 uid="uid://83qph142ha7s"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_hu2pw"] 4 | [ext_resource type="Script" path="res://scripts/core/tabs/projects/ProjectItem.cs" id="2_uxxbh"] 5 | [ext_resource type="PackedScene" uid="uid://bilwvy6kxj1nk" path="res://scenes/confirmation_dialog.tscn" id="3_58hgf"] 6 | [ext_resource type="Theme" uid="uid://bwmtny758y0se" path="res://resources/themes/half_red_btn.theme" id="4_efnx3"] 7 | [ext_resource type="Theme" uid="uid://brtddydnujip" path="res://resources/themes/blue_btn.theme" id="4_fp7tl"] 8 | [ext_resource type="Theme" uid="uid://owhv26bfo2cv" path="res://resources/themes/star_btn.theme" id="4_i21nj"] 9 | 10 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gi7kc"] 11 | bg_color = Color(0.117647, 0.117647, 0.117647, 1) 12 | 13 | [node name="ProjectItem" type="Panel" node_paths=PackedStringArray("nameLabel", "pathLabel", "lastOpenedLabel", "favoriteToggle", "versionButton", "openButton", "removeButton")] 14 | clip_contents = true 15 | custom_minimum_size = Vector2(0, 75) 16 | offset_right = 1000.0 17 | offset_bottom = 75.0 18 | theme = ExtResource("1_hu2pw") 19 | theme_override_styles/panel = SubResource("StyleBoxFlat_gi7kc") 20 | script = ExtResource("2_uxxbh") 21 | nameLabel = NodePath("Name") 22 | pathLabel = NodePath("Path") 23 | lastOpenedLabel = NodePath("LastOpened") 24 | favoriteToggle = NodePath("FavoriteButton") 25 | versionButton = NodePath("VersionButton") 26 | openButton = NodePath("OpenButton") 27 | removeButton = NodePath("RemoveButton") 28 | confirmationPopupScene = ExtResource("3_58hgf") 29 | 30 | [node name="FavoriteButton" type="Button" parent="."] 31 | layout_mode = 1 32 | anchors_preset = -1 33 | anchor_left = 0.038 34 | anchor_top = 0.5 35 | anchor_right = 0.038 36 | anchor_bottom = 0.5 37 | offset_left = -16.0 38 | offset_top = -15.0 39 | offset_right = 16.0 40 | offset_bottom = 15.0 41 | focus_mode = 0 42 | theme = ExtResource("4_i21nj") 43 | toggle_mode = true 44 | 45 | [node name="Name" type="RichTextLabel" parent="."] 46 | layout_mode = 1 47 | anchors_preset = -1 48 | anchor_left = 0.05 49 | anchor_right = 0.35 50 | anchor_bottom = 1.0 51 | offset_left = 25.0 52 | offset_top = 15.0 53 | offset_bottom = -35.0 54 | bbcode_enabled = true 55 | text = "Godot Hub" 56 | scroll_active = false 57 | shortcut_keys_enabled = false 58 | 59 | [node name="Path" type="Label" parent="."] 60 | layout_mode = 1 61 | anchors_preset = -1 62 | anchor_left = 0.05 63 | anchor_top = 1.0 64 | anchor_right = 0.35 65 | anchor_bottom = 1.0 66 | offset_left = 25.0 67 | offset_top = -35.0 68 | offset_bottom = -20.0 69 | mouse_filter = 1 70 | theme_override_colors/font_color = Color(0.588235, 0.588235, 0.588235, 1) 71 | theme_override_font_sizes/font_size = 10 72 | text = "E:/Path/69/ProjectName" 73 | vertical_alignment = 1 74 | text_overrun_behavior = 3 75 | 76 | [node name="LastOpened" type="RichTextLabel" parent="."] 77 | layout_mode = 1 78 | anchors_preset = -1 79 | anchor_left = 0.375 80 | anchor_top = 0.3 81 | anchor_right = 0.55 82 | anchor_bottom = 0.7 83 | bbcode_enabled = true 84 | text = "69 months ago" 85 | scroll_active = false 86 | 87 | [node name="VersionButton" type="OptionButton" parent="."] 88 | layout_mode = 1 89 | anchors_preset = -1 90 | anchor_left = 0.575 91 | anchor_top = 0.2 92 | anchor_right = 0.725 93 | anchor_bottom = 0.8 94 | focus_mode = 0 95 | 96 | [node name="OpenButton" type="Button" parent="."] 97 | layout_mode = 1 98 | anchors_preset = -1 99 | anchor_left = 0.75 100 | anchor_top = 0.2 101 | anchor_right = 0.85 102 | anchor_bottom = 0.8 103 | grow_horizontal = 0 104 | grow_vertical = 2 105 | focus_mode = 0 106 | theme = ExtResource("4_fp7tl") 107 | text = "Open" 108 | 109 | [node name="RemoveButton" type="Button" parent="."] 110 | layout_mode = 1 111 | anchors_preset = -1 112 | anchor_left = 0.875 113 | anchor_top = 0.2 114 | anchor_right = 0.975 115 | anchor_bottom = 0.8 116 | grow_horizontal = 0 117 | grow_vertical = 2 118 | focus_mode = 0 119 | theme = ExtResource("4_efnx3") 120 | text = "Remove" 121 | -------------------------------------------------------------------------------- /scenes/versions/engine_item.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=3 uid="uid://8wgykcf75ex1"] 2 | 3 | [ext_resource type="Theme" uid="uid://ce3m7fxsw8f6t" path="res://resources/themes/main.theme" id="1_wybn5"] 4 | [ext_resource type="Script" path="res://scripts/core/tabs/versions/EngineItem.cs" id="2_us1bx"] 5 | [ext_resource type="PackedScene" uid="uid://bilwvy6kxj1nk" path="res://scenes/confirmation_dialog.tscn" id="3_woeeq"] 6 | [ext_resource type="Theme" uid="uid://owhv26bfo2cv" path="res://resources/themes/star_btn.theme" id="4_36lft"] 7 | [ext_resource type="Theme" uid="uid://brtddydnujip" path="res://resources/themes/blue_btn.theme" id="4_oxtu8"] 8 | [ext_resource type="Theme" uid="uid://bwmtny758y0se" path="res://resources/themes/half_red_btn.theme" id="5_4lvaj"] 9 | 10 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gi7kc"] 11 | bg_color = Color(0.117647, 0.117647, 0.117647, 1) 12 | 13 | [node name="EngineItem" type="Panel" node_paths=PackedStringArray("nameLabel", "pathLabel", "isMonoBox", "timeLabel", "favoriteToggle", "openButton", "uninstallButton")] 14 | clip_contents = true 15 | custom_minimum_size = Vector2(0, 75) 16 | offset_right = 1000.0 17 | offset_bottom = 75.0 18 | theme = ExtResource("1_wybn5") 19 | theme_override_styles/panel = SubResource("StyleBoxFlat_gi7kc") 20 | script = ExtResource("2_us1bx") 21 | confirmationPopup = ExtResource("3_woeeq") 22 | nameLabel = NodePath("VersionLabel") 23 | pathLabel = NodePath("Path") 24 | isMonoBox = NodePath("IsMono") 25 | timeLabel = NodePath("DateLabel") 26 | favoriteToggle = NodePath("FavoriteButton") 27 | openButton = NodePath("OpenButton") 28 | uninstallButton = NodePath("UninstallButton") 29 | 30 | [node name="FavoriteButton" type="Button" parent="."] 31 | layout_mode = 1 32 | anchors_preset = -1 33 | anchor_left = 0.038 34 | anchor_top = 0.5 35 | anchor_right = 0.038 36 | anchor_bottom = 0.5 37 | offset_left = -16.0 38 | offset_top = -15.0 39 | offset_right = 16.0 40 | offset_bottom = 15.0 41 | focus_mode = 0 42 | theme = ExtResource("4_36lft") 43 | toggle_mode = true 44 | 45 | [node name="VersionLabel" type="RichTextLabel" parent="."] 46 | layout_mode = 1 47 | anchors_preset = -1 48 | anchor_left = 0.05 49 | anchor_right = 0.3 50 | anchor_bottom = 1.0 51 | offset_left = 25.0 52 | offset_top = 15.0 53 | offset_bottom = -35.0 54 | bbcode_enabled = true 55 | text = "[b]Godot 4.0[/b]" 56 | scroll_active = false 57 | 58 | [node name="Path" type="Label" parent="."] 59 | layout_mode = 1 60 | anchors_preset = -1 61 | anchor_left = 0.05 62 | anchor_top = 1.0 63 | anchor_right = 0.3 64 | anchor_bottom = 1.0 65 | offset_left = 25.0 66 | offset_top = -35.0 67 | offset_bottom = -20.0 68 | mouse_filter = 1 69 | theme_override_colors/font_color = Color(0.588235, 0.588235, 0.588235, 1) 70 | theme_override_font_sizes/font_size = 10 71 | text = "E:/Path/69/ProjectName" 72 | vertical_alignment = 1 73 | text_overrun_behavior = 3 74 | 75 | [node name="IsMono" type="CheckBox" parent="."] 76 | layout_mode = 1 77 | anchors_preset = -1 78 | anchor_left = 0.325 79 | anchor_right = 0.425 80 | anchor_bottom = 1.0 81 | focus_mode = 0 82 | theme_override_colors/font_color = Color(0.721569, 0.721569, 0.721569, 1) 83 | theme_override_colors/font_pressed_color = Color(0.721569, 0.721569, 0.721569, 1) 84 | theme_override_colors/font_hover_color = Color(0.721569, 0.721569, 0.721569, 1) 85 | theme_override_colors/font_hover_pressed_color = Color(0.721569, 0.721569, 0.721569, 1) 86 | theme_override_colors/font_focus_color = Color(0.721569, 0.721569, 0.721569, 1) 87 | button_pressed = true 88 | button_mask = 0 89 | shortcut_feedback = false 90 | shortcut_in_tooltip = false 91 | text = "Mono" 92 | 93 | [node name="DateLabel" type="RichTextLabel" parent="."] 94 | layout_mode = 1 95 | anchors_preset = -1 96 | anchor_left = 0.45 97 | anchor_top = 0.3 98 | anchor_right = 0.65 99 | anchor_bottom = 0.7 100 | bbcode_enabled = true 101 | text = "69 months ago" 102 | 103 | [node name="OpenButton" type="Button" parent="."] 104 | layout_mode = 1 105 | anchors_preset = -1 106 | anchor_left = 0.725 107 | anchor_top = 0.2 108 | anchor_right = 0.825 109 | anchor_bottom = 0.8 110 | grow_horizontal = 0 111 | grow_vertical = 2 112 | focus_mode = 0 113 | theme = ExtResource("4_oxtu8") 114 | text = "Open" 115 | 116 | [node name="UninstallButton" type="Button" parent="."] 117 | layout_mode = 1 118 | anchors_preset = -1 119 | anchor_left = 0.85 120 | anchor_top = 0.2 121 | anchor_right = 0.975 122 | anchor_bottom = 0.8 123 | grow_horizontal = 0 124 | grow_vertical = 2 125 | focus_mode = 0 126 | theme = ExtResource("5_4lvaj") 127 | text = "Uninstall" 128 | -------------------------------------------------------------------------------- /scripts/core/tabs/versions/EnginesPanel.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Utils.Comparisons; 3 | using Godot; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Com.Astral.GodotHub.Core.Tabs.Versions 8 | { 9 | public partial class EnginesPanel : SortedPanel 10 | { 11 | [Export] protected PackedScene engineItemScene; 12 | 13 | [ExportGroup("Engine addition")] 14 | [Export] protected Button addButton; 15 | [Export] protected PackedScene fileDialogScene; 16 | 17 | [ExportGroup("Sorting")] 18 | [Export] protected Button favoriteButton; 19 | [Export] protected SortToggle versionButton; 20 | [Export] protected SortToggle monoButton; 21 | [Export] protected SortToggle dateButton; 22 | 23 | protected List items = new List(); 24 | protected Comparison currentComparison = Comparer.CompareTimes; 25 | 26 | public override void _Ready() 27 | { 28 | List lVersions = VersionsData.GetAllVersions(); 29 | 30 | for (int i = 0; i < lVersions.Count; i++) 31 | { 32 | CreateItem(lVersions[i]); 33 | } 34 | 35 | Sort(); 36 | 37 | VersionsData.VersionAdded += OnVersionAdded; 38 | EngineItem.Closed += OnItemClosed; 39 | 40 | favoriteButton.Toggled += OnFavoriteToggled; 41 | versionButton.CustomToggled += OnVersionToggled; 42 | monoButton.CustomToggled += OnMonoToggled; 43 | dateButton.CustomToggled += OnDateToggled; 44 | addButton.Pressed += OnAddPressed; 45 | 46 | dateButton.ButtonPressed = true; 47 | } 48 | 49 | protected override void Dispose(bool pDisposing) 50 | { 51 | if (pDisposing) 52 | { 53 | EngineItem.Closed -= OnItemClosed; 54 | VersionsData.VersionAdded -= OnVersionAdded; 55 | } 56 | } 57 | 58 | protected EngineItem CreateItem(GDFile pInstall) 59 | { 60 | EngineItem lItem = engineItemScene.Instantiate(); 61 | itemContainer.AddChild(lItem); 62 | lItem.Init(pInstall); 63 | items.Add(lItem); 64 | return lItem; 65 | } 66 | 67 | #region EVENT_HANDLING 68 | 69 | protected void OnVersionAdded(GDFile pInstall) 70 | { 71 | CreateItem(pInstall); 72 | Sort(); 73 | } 74 | 75 | protected void OnItemClosed(EngineItem pItem) 76 | { 77 | items.Remove(pItem); 78 | } 79 | 80 | protected void OnAddPressed() 81 | { 82 | FileDialog lDialog = fileDialogScene.Instantiate(); 83 | Main.Instance.AddChild(lDialog); 84 | lDialog.PopupCentered(); 85 | lDialog.FileMode = FileDialog.FileModeEnum.OpenFiles; 86 | 87 | #if GODOT_WINDOWS 88 | lDialog.Filters = new string[] { "*.exe" }; 89 | #else 90 | lDialog.Filters = new string [] { "*" }; 91 | #endif 92 | 93 | lDialog.CurrentDir = AppConfig.InstallDir; 94 | lDialog.FilesSelected += OnFilesSelected; 95 | } 96 | 97 | protected void OnFilesSelected(string[] pPaths) 98 | { 99 | string lPath; 100 | 101 | for (int i = 0; i < pPaths.Length; i++) 102 | { 103 | lPath = pPaths[i]; 104 | VersionsData.AddVersion(lPath, true); 105 | } 106 | } 107 | 108 | protected void OnFavoriteToggled(bool pToggled) 109 | { 110 | versionButton.Disable(); 111 | monoButton.Disable(); 112 | 113 | if (pToggled) 114 | { 115 | dateButton.Disable(); 116 | currentComparison = Comparer.CompareFavorites; 117 | Sort(); 118 | } 119 | else 120 | { 121 | dateButton.Enable(); 122 | currentComparison = Comparer.CompareTimes; 123 | Sort(); 124 | } 125 | } 126 | 127 | protected void OnVersionToggled(bool pToggled) 128 | { 129 | favoriteButton.SetPressedNoSignal(false); 130 | monoButton.Disable(); 131 | dateButton.Disable(); 132 | currentComparison = pToggled ? Comparer.CompareVersions : Comparer.ReversedCompareVersions; 133 | Sort(); 134 | } 135 | 136 | protected void OnMonoToggled(bool pToggled) 137 | { 138 | favoriteButton.SetPressedNoSignal(false); 139 | versionButton.Disable(); 140 | dateButton.Disable(); 141 | currentComparison = pToggled ? Comparer.CompareMonos : Comparer.ReversedCompareMonos; 142 | Sort(); 143 | } 144 | 145 | protected void OnDateToggled(bool pToggled) 146 | { 147 | favoriteButton.SetPressedNoSignal(false); 148 | versionButton.Disable(); 149 | monoButton.Disable(); 150 | currentComparison = pToggled ? Comparer.CompareTimes : Comparer.ReversedCompareTimes; 151 | Sort(); 152 | } 153 | 154 | #endregion //EVENT_HANDLING 155 | 156 | protected void Sort() 157 | { 158 | items.Sort(currentComparison); 159 | 160 | for (int i = 0; i < items.Count; i++) 161 | { 162 | itemContainer.MoveChild(items[i], i); 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 38 | 44 | 50 | 55 | 61 | 66 | 71 | 77 | -------------------------------------------------------------------------------- /scripts/core/tabs/versions/EngineItem.cs: -------------------------------------------------------------------------------- 1 | using Com.Astral.GodotHub.Core.Data; 2 | using Com.Astral.GodotHub.Core.Debug; 3 | using Com.Astral.GodotHub.Core.Utils; 4 | using Com.Astral.GodotHub.Core.Utils.Comparisons; 5 | using Godot; 6 | using System; 7 | using System.Diagnostics; 8 | using System.IO; 9 | 10 | using Colors = Com.Astral.GodotHub.Core.Utils.Colors; 11 | using Label = Godot.Label; 12 | using Version = Com.Astral.GodotHub.Core.Data.Version; 13 | 14 | namespace Com.Astral.GodotHub.Core.Tabs.Versions 15 | { 16 | public partial class EngineItem : Control, IFavoriteItem, IMonoItem, ITimedItem, IVersionItem, IValidItem 17 | { 18 | /// 19 | /// Event called when has been called and the item is going to be disposed 20 | /// 21 | public static event Action Closed; 22 | 23 | public bool IsFavorite { get; protected set; } 24 | public bool IsMono { get; protected set; } 25 | public bool IsValid { get; protected set; } = true; 26 | public double TimeSinceLastOpening { get; protected set; } 27 | public Version Version => engine.Version; 28 | 29 | [Export] protected PackedScene confirmationPopup; 30 | [Export] protected float closeDuration = 0.25f; 31 | 32 | [ExportGroup("Data")] 33 | [Export] protected RichTextLabel nameLabel; 34 | [Export] protected Label pathLabel; 35 | [Export] protected CheckBox isMonoBox; 36 | [Export] protected RichTextLabel timeLabel; 37 | 38 | [ExportGroup("Buttons")] 39 | [Export] protected Button favoriteToggle; 40 | [Export] protected Button openButton; 41 | [Export] protected Button uninstallButton; 42 | 43 | protected GDFile engine; 44 | 45 | /// 46 | /// Set the data of this 47 | /// 48 | public void Init(GDFile pEngine) 49 | { 50 | engine = pEngine; 51 | pathLabel.Text = engine.Path; 52 | pathLabel.TooltipText = engine.Path; 53 | favoriteToggle.ButtonPressed = engine.IsFavorite; 54 | favoriteToggle.Toggled += OnFavoriteToggled; 55 | IsFavorite = engine.IsFavorite; 56 | 57 | if (!File.Exists(engine.Path)) 58 | { 59 | nameLabel.Text = $"[color=#{Colors.ToHexa(Colors.Singleton.Red)}][b]Missing version[/b][/color]"; 60 | isMonoBox.ButtonPressed = false; 61 | timeLabel.Text = $"[color=#{Colors.ToHexa(Colors.Singleton.Red)}]N/A[/color]"; 62 | openButton.Disabled = true; 63 | uninstallButton.Text = "Remove"; 64 | uninstallButton.Pressed += OnRemovePressed; 65 | IsValid = false; 66 | return; 67 | } 68 | 69 | nameLabel.Text = $"[b]Godot {engine.Version}[/b]"; 70 | isMonoBox.ButtonPressed = engine.Path.Contains("mono"); 71 | IsMono = isMonoBox.ButtonPressed; 72 | DateTime lTime = new FileInfo(engine.Path).LastAccessTimeUtc; 73 | TimeSinceLastOpening = (DateTime.UtcNow - lTime).TotalSeconds; 74 | timeLabel.Text = TimeFormater.Format(lTime); 75 | openButton.Pressed += Open; 76 | uninstallButton.Pressed += OnUninstallPressed; 77 | } 78 | 79 | protected void Open() 80 | { 81 | try 82 | { 83 | Process.Start(new ProcessStartInfo() { 84 | FileName = pathLabel.Text, 85 | WorkingDirectory = pathLabel.Text[..pathLabel.Text.RFind("/")], 86 | Arguments = "--project-manager" 87 | }); 88 | } 89 | catch (Exception lException) 90 | { 91 | ExceptionHandler.Singleton.LogException(lException); 92 | } 93 | } 94 | 95 | protected void Uninstall() 96 | { 97 | string lPath = PathT.GetFolderFromExe(pathLabel.Text); 98 | 99 | try 100 | { 101 | Directory.Delete(lPath, true); 102 | } 103 | #if GODOT_WINDOWS 104 | catch (UnauthorizedAccessException) 105 | { 106 | if (!Admin.DeletePaths(lPath)) 107 | return; 108 | } 109 | #endif //GODOT_WINDOWS 110 | catch (Exception lException) 111 | { 112 | ExceptionHandler.Singleton.LogException(lException); 113 | return; 114 | } 115 | 116 | Remove(); 117 | } 118 | 119 | protected void Remove() 120 | { 121 | VersionsData.RemoveVersion(engine.Version); 122 | Close(); 123 | } 124 | 125 | protected void Close() 126 | { 127 | CreateTween() 128 | .SetTrans(Tween.TransitionType.Quad) 129 | .SetEase(Tween.EaseType.Out) 130 | .TweenProperty(this, "custom_minimum_size:y", 0f, closeDuration) 131 | .Finished += QueueFree; 132 | Closed?.Invoke(this); 133 | } 134 | 135 | protected ConfirmationDialog CreateDialog(string pTitle, string pText) 136 | { 137 | ConfirmationDialog lDialog = confirmationPopup.Instantiate(); 138 | Main.Instance.AddChild(lDialog); 139 | lDialog.Title = pTitle; 140 | lDialog.DialogText = pText; 141 | lDialog.GetChild
104 | /// If the path doesn't refer to a project, it returns the default 105 | /// 106 | public static Version GetVersionFromFolder(string pPath) 107 | { 108 | ConfigFile lConfig = new ConfigFile(); 109 | GError lError = lConfig.Load(pPath + "/project.godot"); 110 | 111 | if (lError == GError.Ok) 112 | { 113 | int lConfigVersion = (int)lConfig.GetValue("", "config_version"); 114 | 115 | if (lConfigVersion >= 5) 116 | { 117 | return GetGodot4OrHigherVersion(lConfig); 118 | } 119 | else 120 | { 121 | return GetGodot3OrLowerVersion(lConfigVersion); 122 | } 123 | } 124 | else 125 | { 126 | ExceptionHandler.Singleton.LogMessage( 127 | $"Invalid project passed, can't find version from folder: {lError}", 128 | lError.ToString(), 129 | ExceptionHandler.ExceptionGravity.Error 130 | ); 131 | Debugger.LogError($"Invalid project passed, can't find version from folder: {lError}"); 132 | return new Version(); 133 | } 134 | } 135 | 136 | private static Version GetGodot4OrHigherVersion(ConfigFile pConfig) 137 | { 138 | Array lFeatures = (Array)pConfig.GetValue("application", "config/features"); 139 | return (Version)lFeatures[0]; 140 | } 141 | 142 | private static Version GetGodot3OrLowerVersion(int pConfigVersion) 143 | { 144 | if (pConfigVersion != 4) 145 | return new Version(); 146 | 147 | return new Version(3, 5, 2); 148 | } 149 | 150 | /// 151 | /// Return all saved projects 152 | /// 153 | public static List GetProjects() 154 | { 155 | List lProjects = new List(); 156 | 157 | foreach (string project in file.GetSections()) 158 | { 159 | lProjects.Add(new GDFile( 160 | project, 161 | (bool)file.GetValue(project, FAVORITE), 162 | (Version)(string)file.GetValue(project, VERSION) 163 | )); 164 | } 165 | 166 | return lProjects; 167 | } 168 | 169 | /// 170 | /// Save projects.cfg 171 | /// 172 | public static void Save() 173 | { 174 | file.Save(filePath); 175 | } 176 | 177 | private static void Reset() 178 | { 179 | IEnumerator lDirectories = Directory.EnumerateDirectories(AppConfig.ProjectDir).GetEnumerator(); 180 | string lDirectory; 181 | 182 | while (lDirectories.MoveNext()) 183 | { 184 | if (File.Exists($"{lDirectories.Current}/project.godot")) 185 | { 186 | lDirectory = lDirectories.Current.Replace("\\", "/"); 187 | file.SetValue(lDirectory, VERSION, (string)GetVersionFromFolder(lDirectories.Current)); 188 | file.SetValue(lDirectory, FAVORITE, false); 189 | } 190 | } 191 | } 192 | } 193 | } 194 | --------------------------------------------------------------------------------