From 57d7f5c02004ca629549e31358d056358d03c490 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:01:09 -0500 Subject: [PATCH 01/13] Updated Project Setup Main Theme for UI. --- project.godot | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/project.godot b/project.godot index 7f2f0d55..019fc408 100644 --- a/project.godot +++ b/project.godot @@ -43,6 +43,10 @@ window/per_pixel_transparency/allowed=true enabled=PackedStringArray("res://addons/gdata_orm/plugin.cfg", "res://addons/gde_gozen/plugin.cfg", "res://addons/kenny_spritesheet_importer/plugin.cfg", "res://addons/no-obs-ws/plugin.cfg", "res://addons/sc_editor/plugin.cfg", "res://addons/twitcher/plugin.cfg") +[gui] + +theme/custom="uid://dh11pgqmtpeig" + [input] spawn_avatar={ From 2e217326cdaec7eaff91cafdf8bfcc00a1dd022c Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:01:41 -0500 Subject: [PATCH 02/13] Updated SettingsPanel Scene Applied TabPanel style to Tab containers. --- UI/settings_panel.tscn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/settings_panel.tscn b/UI/settings_panel.tscn index 322c83c7..ceeb836e 100644 --- a/UI/settings_panel.tscn +++ b/UI/settings_panel.tscn @@ -37,9 +37,11 @@ layout_mode = 2 [node name="Music" type="PanelContainer" parent="MarginContainer/VBoxContainer/TabContainer" unique_id=22912491] visible = false layout_mode = 2 +theme_type_variation = &"TabPanel" metadata/_tab_index = 2 [node name="Chat Avatars" type="PanelContainer" parent="MarginContainer/VBoxContainer/TabContainer" unique_id=429108220] visible = false layout_mode = 2 +theme_type_variation = &"TabPanel" metadata/_tab_index = 3 From afe8862a279c393bd58db6ea18e953cdf5067ce7 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:02:04 -0500 Subject: [PATCH 03/13] Updated FloatingMenu Changed size of Settings Window to be 1530x1000. --- UI/floating_menu.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/floating_menu.gd b/UI/floating_menu.gd index f74f48d2..4ea937fe 100644 --- a/UI/floating_menu.gd +++ b/UI/floating_menu.gd @@ -173,7 +173,7 @@ func _handle_settings() -> void: win.mode = Window.MODE_WINDOWED var pnl := SETTINGS_PANEL.instantiate() win.add_child(pnl) - win.size = Vector2i(1530,800) + win.size = Vector2i(1530,1000) win.close_requested.connect(func(): win.queue_free(); _set_win = null) win.name = "SettingsWindow" win.title = "Settings" From ce880536a142e335df98ef0ee737041cffbc1dfe Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:02:45 -0500 Subject: [PATCH 04/13] Updated MainTheme Added new StyleBoxFlat's for Entry, PanelContainer, TabPanel and TooltipLabel --- UI/assets/main_theme.tres | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/UI/assets/main_theme.tres b/UI/assets/main_theme.tres index c157f77f..85d249a9 100644 --- a/UI/assets/main_theme.tres +++ b/UI/assets/main_theme.tres @@ -14,6 +14,38 @@ bg_color = Color(1, 1, 1, 0.57254905) [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_u7u7u"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_frgrh"] +bg_color = Color(0.13684635, 0.13684635, 0.13684635, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qhjvx"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0.07058824, 0.07058824, 0.07058824, 0.95686275) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.4121524, 0.4121525, 0.41215223, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ay4fc"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.12260859, 0.12260859, 0.12260859, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_u7u7u"] +bg_color = Color(0.07058824, 0.07058824, 0.07058824, 0.8901961) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_25vrv"] +bg_color = Color(0.07058824, 0.07058824, 0.07058824, 0.8901961) + [resource] BlankButton/base_type = &"Button" BlankButton/styles/disabled = SubResource("StyleBoxEmpty_dfugh") @@ -22,3 +54,10 @@ BlankButton/styles/hover = SubResource("StyleBoxFlat_dfugh") BlankButton/styles/hover_pressed = SubResource("StyleBoxFlat_hlhir") BlankButton/styles/normal = SubResource("StyleBoxEmpty_ay4fc") BlankButton/styles/pressed = SubResource("StyleBoxEmpty_u7u7u") +Entry/base_type = &"PanelContainer" +Entry/styles/panel = SubResource("StyleBoxFlat_frgrh") +PanelContainer/styles/panel = SubResource("StyleBoxFlat_qhjvx") +TabPanel/base_type = &"PanelContainer" +TabPanel/styles/panel = SubResource("StyleBoxFlat_ay4fc") +TooltipLabel/styles/focus = SubResource("StyleBoxFlat_u7u7u") +TooltipLabel/styles/normal = SubResource("StyleBoxFlat_25vrv") From 7aa064fe2454944e765538014ea91c81e4d7f79f Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:03:10 -0500 Subject: [PATCH 05/13] Created ItchAppPanel Started working on implementing Itch.io App panel --- UI/Controls/itch_app_panel.gd | 167 +++++++++++++++++++++++++++ UI/Controls/itch_app_panel.gd.uid | 1 + UI/Controls/itch_app_panel.tscn | 186 ++++++++++++++++++++++++++++++ 3 files changed, 354 insertions(+) create mode 100644 UI/Controls/itch_app_panel.gd create mode 100644 UI/Controls/itch_app_panel.gd.uid create mode 100644 UI/Controls/itch_app_panel.tscn diff --git a/UI/Controls/itch_app_panel.gd b/UI/Controls/itch_app_panel.gd new file mode 100644 index 00000000..064d37be --- /dev/null +++ b/UI/Controls/itch_app_panel.gd @@ -0,0 +1,167 @@ +@tool +extends PanelContainer +class_name ItchIOAppInfo + +@export var enable_logger: bool = true +@warning_ignore("unused_private_class_variable") +@export_tool_button("Search", "Button") var _search = tool_search +@export var tool_app_url: String + +#region Test Apps +enum ItchIOGames{ + RIDICULOUS_SHOPPING, + THE_MAZE_AND_THE_BEAST, + THE_SUNNYSIDE_MOTEL_IN_HUTTSVILLE_ARKANSAS, + VOID_DRIVE_THROUGH, + POTION_QUEST, + SUPER_ROLL_OUT, + COVINOS_ROTTEN_FRUIT, + AUTENTIC_ITALIAN_PIZZA, +} +const ITCHIO_APP_URLS: Dictionary[ItchIOGames, String] = { + ItchIOGames.RIDICULOUS_SHOPPING: "https://uff.itch.io/ridiculous-shopping", + ItchIOGames.THE_MAZE_AND_THE_BEAST: "https://uff.itch.io/the-maze-and-the-beast", + ItchIOGames.THE_SUNNYSIDE_MOTEL_IN_HUTTSVILLE_ARKANSAS: "https://fgaha56.itch.io/the-sunnyside-motel-in-huttsville-arkansas", + ItchIOGames.VOID_DRIVE_THROUGH: "https://fgaha56.itch.io/void-drive-through", + ItchIOGames.POTION_QUEST: "https://vex667.itch.io/potion-quest", + ItchIOGames.SUPER_ROLL_OUT: "https://seano4d.itch.io/super-roll-out", + ItchIOGames.COVINOS_ROTTEN_FRUIT: "https://jerem-watts.itch.io/gorley-cleans-up-covinos-rotten-fruit", + ItchIOGames.AUTENTIC_ITALIAN_PIZZA: "https://trevron.itch.io/authentic-italian-pizza", +} +@export var selected_itchio_game: ItchIOGames: + set(val): + selected_itchio_game = val + if is_node_ready(): get_app_info(ITCHIO_APP_URLS[selected_itchio_game]) +@export var test_data: ItchIOAppData +#endregion + +const IMG_VALID_FORMATS = ["png", "jpeg", "jpg", "bmp", "webp", "svg"] + +static var _log: TwitchLogger = TwitchLogger.new(&"ItchAppInfo") +var data: ItchIOAppData: + set(val): + data = val + if is_node_ready(): + %VisitPage.disabled = data == null + +var _save_data: ItchIOAppData + +func _ready() -> void: + %Clear.pressed.connect(clear) + if Engine.is_editor_hint(): + return + clear() + +func tool_search() -> void: + if !Engine.is_editor_hint(): + return + if tool_app_url: + get_app_info(tool_app_url) + +func get_app_info(app_url: String) -> ItchIOAppData: + var _data: ItchIOAppData = await %ItchIOService.get_itch_app_data(app_url) + if not _data: + return null + + display_app_info(_data) + if Engine.is_editor_hint(): + test_data = _data + return _data + +func display_app_info(_data: ItchIOAppData) -> void: + clear() + data = _data + if not data: return + %AppSearch.text = str(data.url) + %AppId.text = str(data.id) + %GameName.text = data.title + + var authors_string: String = "" + for i: int in data.authors.size(): + var author_dic: Dictionary = data.authors[i] + authors_string += "[b][url={url}]{name}[/url][/b]".format(author_dic) + if i+1 < data.authors.size(): + authors_string += ", " + + %AuthorName.text = "[i]by %s[/i]" % authors_string + if data.cover_image: + %CapsuleImage.texture = await load_texture_from_url(data.cover_image) + if not data.screenshots_thumbnails.is_empty(): + var texture := await load_texture_from_url(data.screenshots_thumbnails.front()) + if texture: + %Background.texture = texture + + %lb_price_desc.visible = !data.is_free + if data.is_free: + %GamePrice.text = "[color=green][wave][b]Free to play![/b][/wave][/color]" + else: + %GamePrice.text = "[color=green][b]%s[/b][/color]" % data.price + + %Description.text = data.description + +func clear() -> void: + data = null + %AppSearch.text = "" + %GameName.text = "" + %AuthorName.text = "" + %CapsuleImage.texture = null + %Background.texture = null + %ReleaseDate.text = "" + %GamePrice.text = "" + %h_price.hide() + %Description.text = "" + +func load_texture_from_url(url: String) -> ImageTexture: + var http := HTTPRequest.new() + add_child(http) + var url_no_query: String = url.split("?")[0] + var file_type = url_no_query.get_extension() + if not file_type in ["png", "jpeg", "jpg", "bmp", "webp", "svg"]: + file_type = "webp" + + var _err = http.request(url) + if _err != OK: + print("_err != OK") + return + + var result: Array = await http.request_completed + var _result: int = result[0] + var response_code: int = result[1] + var _headers: PackedStringArray = result[2] + var buffer: PackedByteArray = result[3] + if response_code != HTTPClient.RESPONSE_OK: + print("response_code != HTTPClient.RESPONSE_OK") + return + + var tex_image := Image.new() + match file_type: + "png": tex_image.load_png_from_buffer(buffer) + "jpeg", "jpg": tex_image.load_jpg_from_buffer(buffer) + "bmp": tex_image.load_bmp_from_buffer(buffer) + "webp": tex_image.load_webp_from_buffer(buffer) + "svg": tex_image.load_svg_from_buffer(buffer) + _: + _log.e("%s format not recognized." % file_type) + return null + + var tex = ImageTexture.create_from_image(tex_image) + http.queue_free() + return tex + + +func _notification(what: int) -> void: + if not Engine.is_editor_hint(): return + match what: + NOTIFICATION_EDITOR_PRE_SAVE: + _save_data = data + #_save_capsule_texture = %CapsuleImage.texture + #_save_bg_texture = %Background.texture + #test_data = null + clear() + NOTIFICATION_EDITOR_POST_SAVE: + test_data = _save_data + display_app_info.call_deferred(_save_data) + #%CapsuleImage.texture = _save_capsule_texture + #%Background.texture = _save_bg_texture + #_save_capsule_texture = null + #_save_bg_texture = null diff --git a/UI/Controls/itch_app_panel.gd.uid b/UI/Controls/itch_app_panel.gd.uid new file mode 100644 index 00000000..033aea1f --- /dev/null +++ b/UI/Controls/itch_app_panel.gd.uid @@ -0,0 +1 @@ +uid://cc2x4u4d0qrg1 diff --git a/UI/Controls/itch_app_panel.tscn b/UI/Controls/itch_app_panel.tscn new file mode 100644 index 00000000..35b7260c --- /dev/null +++ b/UI/Controls/itch_app_panel.tscn @@ -0,0 +1,186 @@ +[gd_scene format=3 uid="uid://c0ahhupmdstxq"] + +[ext_resource type="Script" uid="uid://cc2x4u4d0qrg1" path="res://UI/Controls/itch_app_panel.gd" id="1_5d14s"] +[ext_resource type="Script" uid="uid://cyef5m8x5f7k6" path="res://lib/games_info/itch_io_service.gd" id="2_15a0r"] +[ext_resource type="Texture2D" uid="uid://bw7yr2aonagxc" path="res://UI/assets/font_awesome/itch-io.svg" id="3_xpc18"] +[ext_resource type="Texture2D" uid="uid://4juherhkw8hp" path="res://addons/script_splitter/assets/Close.svg" id="4_g2paa"] +[ext_resource type="FontFile" uid="uid://cx1a4aqqxhsrn" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Italic.ttf" id="5_itotn"] +[ext_resource type="FontFile" uid="uid://b6u8lwedqawa7" path="res://UI/assets/neon-wave-theme/polentical_neon/Polentical Neon Bold italic.ttf" id="6_3efm0"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3mi7s"] +content_margin_left = 8.0 +content_margin_top = 8.0 +content_margin_right = 8.0 +content_margin_bottom = 8.0 +bg_color = Color(0.1, 0.1, 0.1, 0.6) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.6215238, 0.6215239, 0.62152356, 1) +border_blend = true +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="LabelSettings" id="LabelSettings_tbax8"] +font_size = 24 + +[sub_resource type="LabelSettings" id="LabelSettings_s4fpn"] +font = ExtResource("5_itotn") +font_size = 20 + +[sub_resource type="LabelSettings" id="LabelSettings_cc846"] +font = ExtResource("6_3efm0") +font_size = 20 + +[node name="ItchAppPanel" type="PanelContainer" unique_id=691251029] +offset_right = 616.0 +offset_bottom = 860.0 +script = ExtResource("1_5d14s") +selected_itchio_game = 1 + +[node name="ItchIOService" type="Node" parent="." unique_id=1316795504] +unique_name_in_owner = true +script = ExtResource("2_15a0r") +metadata/_custom_type_script = "uid://cyef5m8x5f7k6" + +[node name="Background" type="TextureRect" parent="." unique_id=1907032212] +unique_name_in_owner = true +layout_mode = 2 + +[node name="v" type="VBoxContainer" parent="." unique_id=279286858] +layout_mode = 2 + +[node name="m" type="MarginContainer" parent="v" unique_id=357824354] +layout_mode = 2 + +[node name="h" type="HBoxContainer" parent="v/m" unique_id=833665550] +layout_mode = 2 +alignment = 1 + +[node name="Icon" type="TextureRect" parent="v/m/h" unique_id=1660071037] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +texture = ExtResource("3_xpc18") +expand_mode = 1 +stretch_mode = 5 + +[node name="Title" type="Label" parent="v/m/h" unique_id=833828536] +layout_mode = 2 +text = "itchIO App Info" + +[node name="Clear" type="Button" parent="v/m" unique_id=1103305607] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 4 +icon = ExtResource("4_g2paa") +icon_alignment = 1 + +[node name="hsep" type="HSeparator" parent="v" unique_id=1999803799] +layout_mode = 2 + +[node name="h" type="HBoxContainer" parent="v" unique_id=660296882] +layout_mode = 2 + +[node name="Label" type="Label" parent="v/h" unique_id=1424894063] +layout_mode = 2 +text = "App url" + +[node name="AppSearch" type="LineEdit" parent="v/h" unique_id=1792920414] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="AppId" type="LineEdit" parent="v" unique_id=327619984] +unique_name_in_owner = true +layout_mode = 2 +text = "2673807" +placeholder_text = "App ID" +alignment = 1 + +[node name="info" type="PanelContainer" parent="v" unique_id=1542425427] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_3mi7s") + +[node name="sc" type="ScrollContainer" parent="v/info" unique_id=1867214191] +layout_mode = 2 + +[node name="v" type="VBoxContainer" parent="v/info/sc" unique_id=3173697] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="GameName" type="Label" parent="v/info/sc/v" unique_id=279823622] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_tbax8") +horizontal_alignment = 1 +text_overrun_behavior = 3 + +[node name="AuthorName" type="RichTextLabel" parent="v/info/sc/v" unique_id=348439232] +unique_name_in_owner = true +layout_mode = 2 +bbcode_enabled = true +fit_content = true +scroll_active = false +autowrap_mode = 0 +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="CapsuleImage" type="TextureRect" parent="v/info/sc/v" unique_id=1515227202] +unique_name_in_owner = true +layout_mode = 2 +stretch_mode = 5 + +[node name="hr" type="HBoxContainer" parent="v/info/sc/v" unique_id=1865485586] +layout_mode = 2 +alignment = 2 + +[node name="lb" type="Label" parent="v/info/sc/v/hr" unique_id=1295698123] +layout_mode = 2 +text = "Release Date:" +label_settings = SubResource("LabelSettings_s4fpn") + +[node name="ReleaseDate" type="Label" parent="v/info/sc/v/hr" unique_id=489036318] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_cc846") + +[node name="h_price" type="HBoxContainer" parent="v/info/sc/v" unique_id=2028526260] +unique_name_in_owner = true +visible = false +layout_mode = 2 +alignment = 2 + +[node name="lb_price_desc" type="Label" parent="v/info/sc/v/h_price" unique_id=956528954] +unique_name_in_owner = true +visible = false +layout_mode = 2 +text = "Price:" +label_settings = SubResource("LabelSettings_s4fpn") + +[node name="GamePrice" type="Label" parent="v/info/sc/v/h_price" unique_id=290394728] +unique_name_in_owner = true +layout_mode = 2 +label_settings = SubResource("LabelSettings_cc846") + +[node name="hsep" type="HSeparator" parent="v/info/sc/v" unique_id=343519708] +layout_mode = 2 + +[node name="Description" type="RichTextLabel" parent="v/info/sc/v" unique_id=1459602721] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +bbcode_enabled = true + +[node name="VisitPage" type="Button" parent="v" unique_id=914935418] +unique_name_in_owner = true +layout_mode = 2 +disabled = true +text = "Visit Steam Page" From f5aeb44cfd2e0da2c5bff0362bd00f145cd5c235 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:03:27 -0500 Subject: [PATCH 06/13] Created GameEntry Created GameEntry item for Game lists in User Panel --- UI/Controls/game_entry.gd | 93 +++++++++++++++++++++++++++++++++++ UI/Controls/game_entry.gd.uid | 1 + UI/Controls/game_entry.tscn | 88 +++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 UI/Controls/game_entry.gd create mode 100644 UI/Controls/game_entry.gd.uid create mode 100644 UI/Controls/game_entry.tscn diff --git a/UI/Controls/game_entry.gd b/UI/Controls/game_entry.gd new file mode 100644 index 00000000..80662597 --- /dev/null +++ b/UI/Controls/game_entry.gd @@ -0,0 +1,93 @@ +extends PanelContainer +class_name GameEntry + +enum Type {STEAM, ITCHIO} +var type: Type + +var steam_app_id: int +var itchio_app_url: String + +var steam_data: SteamAppData +var itchio_data: ItchIOAppData + +signal game_info_steam_pressed(steam_data: SteamAppData) +signal game_info_itchio_pressesd(itchio_data: ItchIOAppData) +signal entry_deleted(entry: GameEntry) + +func _ready() -> void: + populate() + %Refresh.pressed.connect(_reload_data) + %GameName.pressed.connect(_select_game) + %Promote.pressed.connect(_promote_game) + %SteamLink.pressed.connect(_launch_game_site) + %ItchLink.pressed.connect(_launch_game_site) + %Delete.pressed.connect(entry_deleted.emit.bind(self)) + +func populate() -> void: + %SteamLink.visible = type == Type.STEAM + %ItchLink.visible = type == Type.ITCHIO + + match type: + Type.STEAM: + if not steam_data: + steam_data = await %SteamService.get_steam_app_data(steam_app_id) + %GameName.text = steam_data.name + %GameName.tooltip_text = steam_data.name + var url_no_query: String = steam_data.header_image.split("?")[0] + %Background.texture = ImageTexture.create_from_image(await Globals.twitcher.media.load_image(url_no_query)) + Type.ITCHIO: + if not itchio_data: + itchio_data = await %ItchIOService.get_itch_app_data(itchio_app_url) + %GameName.text = itchio_data.title + var url: String = itchio_data.cover_image + %Background.texture = ImageTexture.create_from_image(await Globals.twitcher.media.load_image(url)) + +func _reload_data() -> void: + match type: + Type.STEAM: + steam_data = await %SteamService.get_steam_app_data(steam_app_id) + populate() + game_info_steam_pressed.emit(steam_data) + Type.ITCHIO: + itchio_data = await %ItchIOService.get_itch_app_data(itchio_app_url) + populate() + game_info_itchio_pressesd.emit(itchio_data) + +func _select_game() -> void: + if type == Type.STEAM: game_info_steam_pressed.emit(steam_data) + elif type == Type.ITCHIO: game_info_itchio_pressesd.emit(itchio_data) + +func _promote_game() -> void: + var msg: String = "Check out {title} by {developer}! {description} {link}" + var title: String + var developer: String + var description: String + var link: String + match type: + Type.STEAM: + title = steam_data.name + developer = steam_data.developers.front() + description = steam_data.short_description + link = steam_data.s_team_url + pass + Type.ITCHIO: + title = itchio_data.title + developer = itchio_data.developer + description = itchio_data.description.left(200) + "..." + link = itchio_data.url + msg = msg.format({ + "title": title, + "developer": developer, + "description": description, + "link": link + }) + Globals.twitcher.send_message(msg) + +func _launch_game_site() -> void: + var link: String + match type: + Type.STEAM: link = "https://s.team/a/%d" % steam_app_id + Type.ITCHIO: link = itchio_app_url + _: + link = "https://google.com" + OS.shell_open(link) diff --git a/UI/Controls/game_entry.gd.uid b/UI/Controls/game_entry.gd.uid new file mode 100644 index 00000000..8fe65d94 --- /dev/null +++ b/UI/Controls/game_entry.gd.uid @@ -0,0 +1 @@ +uid://c0gqgv8ixdudx diff --git a/UI/Controls/game_entry.tscn b/UI/Controls/game_entry.tscn new file mode 100644 index 00000000..496cde10 --- /dev/null +++ b/UI/Controls/game_entry.tscn @@ -0,0 +1,88 @@ +[gd_scene format=3 uid="uid://qu7opwfv2ejy"] + +[ext_resource type="Texture2D" uid="uid://bb2asei1pibev" path="res://UI/assets/bootstrap/arrow-repeat.png" id="1_b8obq"] +[ext_resource type="Script" uid="uid://c0gqgv8ixdudx" path="res://UI/Controls/game_entry.gd" id="1_eo48f"] +[ext_resource type="Script" uid="uid://chgufd1youdel" path="res://lib/games_info/steam_service.gd" id="1_lcnnc"] +[ext_resource type="Texture2D" uid="uid://eybcntflwjpx" path="res://UI/assets/bootstrap/megaphone.svg" id="2_7t4x7"] +[ext_resource type="Script" uid="uid://cyef5m8x5f7k6" path="res://lib/games_info/itch_io_service.gd" id="2_eo48f"] +[ext_resource type="Texture2D" uid="uid://pur2a3t6vlfb" path="res://UI/assets/simple/steam.svg" id="3_lcnnc"] +[ext_resource type="Texture2D" uid="uid://bw7yr2aonagxc" path="res://UI/assets/font_awesome/itch-io.svg" id="4_eo48f"] +[ext_resource type="Texture2D" uid="uid://i8rcx5bhkd5x" path="res://UI/assets/bootstrap/trash.svg" id="5_b1mm0"] + +[node name="GameEntry" type="PanelContainer" unique_id=2093938454] +offset_right = 8.0 +offset_bottom = 8.0 +size_flags_horizontal = 3 +script = ExtResource("1_eo48f") + +[node name="SteamService" type="Node" parent="." unique_id=1960802515] +unique_name_in_owner = true +script = ExtResource("1_lcnnc") +metadata/_custom_type_script = "uid://chgufd1youdel" + +[node name="ItchIOService" type="Node" parent="." unique_id=641518539] +unique_name_in_owner = true +script = ExtResource("2_eo48f") +metadata/_custom_type_script = "uid://cyef5m8x5f7k6" + +[node name="Background" type="TextureRect" parent="." unique_id=593212671] +unique_name_in_owner = true +layout_mode = 2 +expand_mode = 1 +stretch_mode = 6 + +[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=1820948686] +layout_mode = 2 + +[node name="Refresh" type="Button" parent="HBoxContainer" unique_id=827162280] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +tooltip_text = "Refresh" +icon = ExtResource("1_b8obq") +icon_alignment = 1 +expand_icon = true + +[node name="GameName" type="Button" parent="HBoxContainer" unique_id=1669812435] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Name of the game very very long name so that we check if the ellipsis work" +text_overrun_behavior = 3 + +[node name="Promote" type="Button" parent="HBoxContainer" unique_id=710639076] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +tooltip_text = "Promote" +icon = ExtResource("2_7t4x7") +icon_alignment = 1 +expand_icon = true + +[node name="SteamLink" type="Button" parent="HBoxContainer" unique_id=1282286487] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +tooltip_text = "Steam Page" +icon = ExtResource("3_lcnnc") +icon_alignment = 1 +expand_icon = true + +[node name="ItchLink" type="Button" parent="HBoxContainer" unique_id=414407013] +unique_name_in_owner = true +visible = false +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +tooltip_text = "Itch Page" +icon = ExtResource("4_eo48f") +icon_alignment = 1 +expand_icon = true + +[node name="Delete" type="Button" parent="HBoxContainer" unique_id=1920032998] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +tooltip_text = "Delete" +icon = ExtResource("5_b1mm0") +icon_alignment = 1 +expand_icon = true From 0a98c9310f75a6741044572cd0f6684c932ebeca Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:03:51 -0500 Subject: [PATCH 07/13] Created UserGames panel Created UserGames Panel for user games being added to a Chatter database entry. --- UI/Controls/user_games.gd | 85 ++++++++++++ UI/Controls/user_games.gd.uid | 1 + UI/Controls/user_games.tscn | 249 ++++++++++++++++++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 UI/Controls/user_games.gd create mode 100644 UI/Controls/user_games.gd.uid create mode 100644 UI/Controls/user_games.tscn diff --git a/UI/Controls/user_games.gd b/UI/Controls/user_games.gd new file mode 100644 index 00000000..b45a1b89 --- /dev/null +++ b/UI/Controls/user_games.gd @@ -0,0 +1,85 @@ +extends PanelContainer +class_name UserGamesPanel +const GAME_ENTRY = preload("res://UI/Controls/game_entry.tscn") + +@onready var splitter: HSplitContainer = %Splitter +var chatter: Chatter: + set(value): + chatter = value + if not chatter: return + clear() + populate_games() + +func _ready() -> void: + %SteamSearch.pressed.connect(_handle_search) + %AddSteamGame.pressed.connect(_handle_add) + +func _handle_search() -> void: + var info: String = %SteamGameInput.text + var app_id: int = -1 + if info.begins_with("https:"): + var parts := Array(info.split("/")) + parts.reverse() + for part in parts: + if part.is_valid_int(): + app_id = part.to_int() + break + elif info.is_valid_int(): + app_id = info.to_int() + if app_id == -1: return + var data: SteamAppData = await %SteamService.get_steam_app_data(app_id) + if data: + %SteamAppPanel.display_app_info(data) + %SteamAppPanel.show() + +func _handle_add() -> void: + var info: String = %SteamGameInput.text + var app_id: int = -1 + if info.begins_with("https:"): + var parts = Array(info.split("/")) + parts.reverse() + for part in parts: + if part.is_valid_int(): + app_id = part.to_int() + break + elif info.is_valid_int(): + app_id = info.to_int() + + if app_id == -1: return + + var data: SteamAppData = await %SteamService.get_steam_app_data(app_id) + if data: + chatter.steam_games.append(app_id) + chatter.save() + clear() + populate_games() + +func populate_games() -> void: + for game in chatter.steam_games: + var inst: GameEntry = GAME_ENTRY.instantiate() + inst.steam_app_id = game + inst.type = GameEntry.Type.STEAM + inst.game_info_steam_pressed.connect(func(x: SteamAppData): + %SteamAppPanel.show() + %SteamAppPanel.display_app_info(x) + ) + %SteamList.add_child(inst) + + for game in chatter.itch_games: + var inst: GameEntry = GAME_ENTRY.instantiate() + inst.itchio_app_url = chatter.itch_games[game] + inst.type = GameEntry.Type.ITCHIO + inst.game_info_itchio_pressesd.connect(func(x: ItchIOAppData): + %ItchAppPanel.show() + %ItchAppPanel.display_app_info(x) + ) + %ItchList.add_child(inst) + +func clear() -> void: + for node in %SteamList.get_children(): + node.queue_free() + for node in %ItchList.get_children(): + node.queue_free() + + %SteamAppPanel.clear() + %ItchAppPanel.clear() diff --git a/UI/Controls/user_games.gd.uid b/UI/Controls/user_games.gd.uid new file mode 100644 index 00000000..43f4b37b --- /dev/null +++ b/UI/Controls/user_games.gd.uid @@ -0,0 +1 @@ +uid://bj06jd8vt70im diff --git a/UI/Controls/user_games.tscn b/UI/Controls/user_games.tscn new file mode 100644 index 00000000..54089c29 --- /dev/null +++ b/UI/Controls/user_games.tscn @@ -0,0 +1,249 @@ +[gd_scene format=3 uid="uid://cojuxefo7cryj"] + +[ext_resource type="Texture2D" uid="uid://bexdhdpprh6aa" path="res://UI/assets/font_awesome/magnifying-glass-location.svg" id="1_7mil5"] +[ext_resource type="Script" uid="uid://bj06jd8vt70im" path="res://UI/Controls/user_games.gd" id="1_myc1y"] +[ext_resource type="Texture2D" uid="uid://4nae34ce8pjn" path="res://UI/assets/bootstrap/plus-circle.svg" id="2_0hl8v"] +[ext_resource type="Script" uid="uid://chgufd1youdel" path="res://lib/games_info/steam_service.gd" id="2_u0xo6"] +[ext_resource type="Script" uid="uid://cyef5m8x5f7k6" path="res://lib/games_info/itch_io_service.gd" id="3_hk3mv"] +[ext_resource type="PackedScene" uid="uid://685pgmw1cdw3" path="res://UI/Controls/steam_app_panel.tscn" id="3_j36q5"] +[ext_resource type="Script" uid="uid://bllsv2cy6komw" path="res://lib/models/steam_app_data.gd" id="4_myc1y"] +[ext_resource type="PackedScene" uid="uid://c0ahhupmdstxq" path="res://UI/Controls/itch_app_panel.tscn" id="8_hk3mv"] + +[sub_resource type="Resource" id="Resource_hk3mv"] +script = ExtResource("4_myc1y") +steam_app_id = 3712430 +type = "game" +name = "Carbrix" +short_description = "Carbrix is a sci-fi inspired multiplayer vehicle-building sandbox game where creativity meets action. Design and construct anything you can imagine—from sleek cars and powerful trucks to futuristic planes, bikes, and rockets." +detailed_description = "

Carbrix is a sci-fi inspired multiplayer vehicle-building sandbox game where creativity meets action. Design and construct anything you can imagine, from sleek cars and powerful trucks to futuristic planes, bikes, and rockets.

Play solo or team up with friends in multiplayer to share your creations, race, battle, or simply explore endless possibilities. With intuitive building tools and a physics-driven world, Carbrix offers a playground of imagination, competition, and fun.

With Carbrix, you can build cars, trucks, planes, bikes—and so much more!

Thanks to the intuitive building system, you can build, test, and drive with ease.

Looking for something to sink your teeth into?

With the built-in destruction system, worry no more

Create combat-oriented vehicles and battle your friends!

With multiplayer, the fun never ends!
Team up with your friends to build together—or challenge them in head-to-head battles.

Take part in thrilling races, compete in creative build contests,
or just mess around and see who can come up with the wildest inventions.

With so many ways to play, there’s always something new to try!

" +header_image = "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/a18c9a286445c8553a4eac10ba42df6b96ce63ed/header.jpg?t=1771564874" +capsule_image = "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/0e3354ecdcc92437b51dcc8a7ce5aec3c956d6b8/capsule_231x87.jpg?t=1771564874" +capsule_imagev5 = "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/0e3354ecdcc92437b51dcc8a7ce5aec3c956d6b8/capsule_184x69.jpg?t=1771564874" +developers = Array[String](["Redston4D"]) +publishers = Array[String](["Redston4D"]) +platforms = { +"linux": true, +"mac": false, +"windows": true +} +genres = Array[Dictionary]([{ +"description": "Action", +"id": "1" +}, { +"description": "Adventure", +"id": "25" +}, { +"description": "Casual", +"id": "4" +}, { +"description": "Indie", +"id": "23" +}, { +"description": "Racing", +"id": "9" +}, { +"description": "Simulation", +"id": "28" +}]) +release_date = { +"coming_soon": true, +"date": "Coming soon" +} +screenshots_full = Array[String](["https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/4a0c3b9405921fd84ee530e87c4bb49e5bac47d5/ss_4a0c3b9405921fd84ee530e87c4bb49e5bac47d5.1920x1080.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/c3bfb9c95fafd7e2e42bf22b2e1a6324202ff3b3/ss_c3bfb9c95fafd7e2e42bf22b2e1a6324202ff3b3.1920x1080.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/41a0157dabd641a59f561befa2d36687405f906c/ss_41a0157dabd641a59f561befa2d36687405f906c.1920x1080.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/d6440c8c03850fa478c8c845561c6729bf69b981/ss_d6440c8c03850fa478c8c845561c6729bf69b981.1920x1080.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/8c8af6ab67b663d1860e5ebdfe3943eebe85e222/ss_8c8af6ab67b663d1860e5ebdfe3943eebe85e222.1920x1080.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/7ebb66440d8eef2e94a818d95f0805f89ca881d3/ss_7ebb66440d8eef2e94a818d95f0805f89ca881d3.1920x1080.jpg?t=1771564874"]) +screenshots_thumbs = Array[String](["https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/4a0c3b9405921fd84ee530e87c4bb49e5bac47d5/ss_4a0c3b9405921fd84ee530e87c4bb49e5bac47d5.600x338.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/c3bfb9c95fafd7e2e42bf22b2e1a6324202ff3b3/ss_c3bfb9c95fafd7e2e42bf22b2e1a6324202ff3b3.600x338.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/41a0157dabd641a59f561befa2d36687405f906c/ss_41a0157dabd641a59f561befa2d36687405f906c.600x338.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/d6440c8c03850fa478c8c845561c6729bf69b981/ss_d6440c8c03850fa478c8c845561c6729bf69b981.600x338.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/8c8af6ab67b663d1860e5ebdfe3943eebe85e222/ss_8c8af6ab67b663d1860e5ebdfe3943eebe85e222.600x338.jpg?t=1771564874", "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/3712430/7ebb66440d8eef2e94a818d95f0805f89ca881d3/ss_7ebb66440d8eef2e94a818d95f0805f89ca881d3.600x338.jpg?t=1771564874"]) +categories = Array[Dictionary]([{ +"description": "Single-player", +"id": 2.0 +}, { +"description": "Multi-player", +"id": 1.0 +}, { +"description": "PvP", +"id": 49.0 +}, { +"description": "Online PvP", +"id": 36.0 +}, { +"description": "Co-op", +"id": 9.0 +}, { +"description": "Online Co-op", +"id": 38.0 +}, { +"description": "Steam Achievements", +"id": 22.0 +}, { +"description": "Steam Workshop", +"id": 30.0 +}, { +"description": "Custom Volume Controls", +"id": 68.0 +}, { +"description": "Adjustable Difficulty", +"id": 78.0 +}, { +"description": "Playable without Timed Input", +"id": 74.0 +}, { +"description": "Save Anytime", +"id": 79.0 +}, { +"description": "Stereo Sound", +"id": 69.0 +}, { +"description": "Surround Sound", +"id": 70.0 +}, { +"description": "Partial Controller Support", +"id": 18.0 +}, { +"description": "Family Sharing", +"id": 62.0 +}]) +pc_requirements = "Minimum:
  • Requires a 64-bit processor and operating system
  • OS *: Windows 7 +
  • Processor: Intel Core i5-4670k
  • Memory: 8 GB RAM
  • Graphics: Intel HD 4600 Graphics
  • DirectX: Version 12
  • Storage: 1 GB available space
  • Additional Notes: Please make sure your GraphicsCard has vulkan
" +mac_requirements = "{ \"minimum\": \"Minimum:
    \", \"recommended\": \"Recommended:
      \" }" +linux_requirements = "{ \"minimum\": \"Minimum:
      • Processor: Intel Core i5-4670k
      • Memory: 8 GB RAM
      • Graphics: Please make sure your GraphicsCard has vulkan
      • Storage: 1 GB available space
      \", \"recommended\": \"Recommended:
      • Processor: Intel Core i5-8500
      • Memory: 16 GB RAM
      • Graphics: Please make sure your GraphicsCard has vulkan
      • Storage: 1 GB available space
      \" }" +support_email = "CarbrixGame@gmail.com" +background_image = "https://store.akamai.steamstatic.com/images/storepagebackground/app/3712430?t=1771564874" +background_image_raw = "https://store.akamai.steamstatic.com/images/storepagebackground/app/3712430?t=1771564874" + +[node name="UserGames" type="PanelContainer" unique_id=2022365407] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_myc1y") + +[node name="SteamService" type="Node" parent="." unique_id=1181960445] +unique_name_in_owner = true +script = ExtResource("2_u0xo6") +metadata/_custom_type_script = "uid://chgufd1youdel" + +[node name="ItchIOService" type="Node" parent="." unique_id=400309790] +unique_name_in_owner = true +script = ExtResource("3_hk3mv") +metadata/_custom_type_script = "uid://cyef5m8x5f7k6" + +[node name="Splitter" type="HSplitContainer" parent="." unique_id=182228020] +unique_name_in_owner = true +layout_mode = 2 +split_offsets = PackedInt32Array(530) +split_offset = 530 + +[node name="VBoxContainer" type="VBoxContainer" parent="Splitter" unique_id=869345086] +layout_mode = 2 + +[node name="Label" type="Label" parent="Splitter/VBoxContainer" unique_id=385647229] +layout_mode = 2 +text = "Games" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="Splitter/VBoxContainer" unique_id=1347394535] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="Splitter/VBoxContainer" unique_id=123570347] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="SteamColumn" type="VBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer" unique_id=1965017268] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="SteamSearch" type="HBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn" unique_id=476996992] +layout_mode = 2 + +[node name="SteamGameInput" type="LineEdit" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn/SteamSearch" unique_id=135652688] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "steam app id or url" + +[node name="SteamSearch" type="Button" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn/SteamSearch" unique_id=1427348414] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +icon = ExtResource("1_7mil5") +icon_alignment = 1 +expand_icon = true + +[node name="AddSteamGame" type="Button" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn/SteamSearch" unique_id=1199771317] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +icon = ExtResource("2_0hl8v") +icon_alignment = 1 +expand_icon = true + +[node name="PanelContainer" type="PanelContainer" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn" unique_id=1782797010] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ScrollContainer" type="ScrollContainer" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn/PanelContainer" unique_id=1538765940] +layout_mode = 2 + +[node name="SteamList" type="VBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer/SteamColumn/PanelContainer/ScrollContainer" unique_id=788126228] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VSeparator" type="VSeparator" parent="Splitter/VBoxContainer/HBoxContainer" unique_id=220505221] +layout_mode = 2 + +[node name="ItchColumn" type="VBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer" unique_id=1035792899] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="ItchSearch" type="HBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn" unique_id=58917565] +layout_mode = 2 + +[node name="ItchInput" type="LineEdit" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn/ItchSearch" unique_id=81918204] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "itch.io link" + +[node name="ItchFetch" type="Button" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn/ItchSearch" unique_id=1917953068] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +icon = ExtResource("1_7mil5") +icon_alignment = 1 +expand_icon = true + +[node name="ItchAdd" type="Button" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn/ItchSearch" unique_id=1726319206] +unique_name_in_owner = true +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +icon = ExtResource("2_0hl8v") +icon_alignment = 1 +expand_icon = true + +[node name="PanelContainer" type="PanelContainer" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn" unique_id=1055230274] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ScrollContainer" type="ScrollContainer" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn/PanelContainer" unique_id=1143536360] +layout_mode = 2 + +[node name="ItchList" type="VBoxContainer" parent="Splitter/VBoxContainer/HBoxContainer/ItchColumn/PanelContainer/ScrollContainer" unique_id=1691269823] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="TabContainer" type="TabContainer" parent="Splitter" unique_id=298665581] +layout_mode = 2 +current_tab = 1 +tabs_visible = false + +[node name="SteamAppPanel" parent="Splitter/TabContainer" unique_id=597550935 instance=ExtResource("3_j36q5")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +test_data = SubResource("Resource_hk3mv") +metadata/_tab_index = 0 + +[node name="ItchAppPanel" parent="Splitter/TabContainer" unique_id=691251029 instance=ExtResource("8_hk3mv")] +unique_name_in_owner = true +layout_mode = 2 +metadata/_tab_index = 1 From c05fe30b8cc5d7087f7cd3b2d67bf2c192676d93 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:05:26 -0500 Subject: [PATCH 08/13] Updated Users Renamed ClosePanel to Clear. Added handle clear for the Clear button. Removed set_tab_names() as Godot now allows setting a tab child's title in the editor. Added hiding and showing of the SearchTwitchUser panel when selecting a user / clearing a user. --- UI/Controls/users.gd | 14 +++++++------- UI/Controls/users.tscn | 28 +++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/UI/Controls/users.gd b/UI/Controls/users.gd index e1482d71..8dde653a 100644 --- a/UI/Controls/users.gd +++ b/UI/Controls/users.gd @@ -8,15 +8,15 @@ func _ready() -> void: %SearchTwitchUser.users_updated.connect(%UserList.update_list) %UserList.populate_list() %UserList.user_selected.connect(_handle_user_selected) - set_tab_names() - -func set_tab_names() -> void: - for pnl in %Tabs.get_children(): - var title := pnl.name.trim_prefix("Internal").capitalize() - %Tabs.set_tab_title(pnl.get_index(), title) - + %Clear.pressed.connect(_handle_clear) func _handle_user_selected(user: Chatter) -> void: itu.chatter = user iul.chatter = user %Tabs.current_tab = 0 + %SearchTwitchUser.hide() + +func _handle_clear() -> void: + itu.chatter = null + iul.chatter = null + %SearchTwitchUser.show() diff --git a/UI/Controls/users.tscn b/UI/Controls/users.tscn index b4a59e06..c5caa5c6 100644 --- a/UI/Controls/users.tscn +++ b/UI/Controls/users.tscn @@ -5,6 +5,7 @@ [ext_resource type="PackedScene" uid="uid://2ifvkmqd0q3i" path="res://UI/Controls/search_twitch_user.tscn" id="2_hl8i0"] [ext_resource type="PackedScene" uid="uid://d3fhwrt28r08x" path="res://UI/Controls/internal_twitch_user_info.tscn" id="4_jqw2j"] [ext_resource type="PackedScene" uid="uid://bipoye4ww4ua6" path="res://UI/Controls/internal_user_live.tscn" id="5_8sme5"] +[ext_resource type="Texture2D" uid="uid://4juherhkw8hp" path="res://addons/script_splitter/assets/Close.svg" id="6_oms12"] [node name="Users" type="PanelContainer" unique_id=823449222] anchors_preset = 15 @@ -12,6 +13,7 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +theme_type_variation = &"TabPanel" script = ExtResource("1_8sme5") metadata/_tab_index = 1 @@ -33,21 +35,41 @@ layout_mode = 2 [node name="SearchTwitchUser" parent="HSplitContainer/UserManager/VBoxContainer" unique_id=83637811 instance=ExtResource("2_hl8i0")] unique_name_in_owner = true layout_mode = 2 +theme_type_variation = &"TabPanel" [node name="HSeparator" type="HSeparator" parent="HSplitContainer/UserManager/VBoxContainer" unique_id=195418375] layout_mode = 2 -[node name="Tabs" type="TabContainer" parent="HSplitContainer/UserManager/VBoxContainer" unique_id=140135258] +[node name="MarginContainer" type="MarginContainer" parent="HSplitContainer/UserManager/VBoxContainer" unique_id=408900267] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_right = 10 + +[node name="Tabs" type="TabContainer" parent="HSplitContainer/UserManager/VBoxContainer/MarginContainer" unique_id=140135258] unique_name_in_owner = true custom_minimum_size = Vector2(0, 300) layout_mode = 2 +size_flags_vertical = 3 current_tab = 0 +tab_0/title = "Twitch User Info" +tab_1/title = "User Live" -[node name="InternalTwitchUserInfo" parent="HSplitContainer/UserManager/VBoxContainer/Tabs" unique_id=1986869556 instance=ExtResource("4_jqw2j")] +[node name="InternalTwitchUserInfo" parent="HSplitContainer/UserManager/VBoxContainer/MarginContainer/Tabs" unique_id=1986869556 instance=ExtResource("4_jqw2j")] unique_name_in_owner = true layout_mode = 2 +theme_type_variation = &"" +metadata/_tab_name = "Twitch User Info" -[node name="InternalUserLive" parent="HSplitContainer/UserManager/VBoxContainer/Tabs" unique_id=17956466 instance=ExtResource("5_8sme5")] +[node name="InternalUserLive" parent="HSplitContainer/UserManager/VBoxContainer/MarginContainer/Tabs" unique_id=17956466 instance=ExtResource("5_8sme5")] unique_name_in_owner = true visible = false layout_mode = 2 +metadata/_tab_name = "User Live" + +[node name="Clear" type="Button" parent="HSplitContainer/UserManager/VBoxContainer/MarginContainer" unique_id=624044174] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 0 +icon = ExtResource("6_oms12") From 9bbc1111d8c34a434f16e2cd236def03a8e03218 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:08:01 -0500 Subject: [PATCH 09/13] Updated UserEntry Added theme type variations for UserEntry. Added custom minimum size for User button, ensure that Text Overrun behavior is set to use ellipses when to much text is set for the button. Added Tooltip texts for Shoutout, Promote, Refresh Twitch Data, Raid and Delete from database. Added connection of ButtonMenu being pressed to toggle menu options. Added support function to update all tooltips to include the Streamer's Display name. --- UI/Controls/user_entry.gd | 6 ++++++ UI/Controls/user_entry.tscn | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/UI/Controls/user_entry.gd b/UI/Controls/user_entry.gd index 2c8cf7e6..b384ee11 100644 --- a/UI/Controls/user_entry.gd +++ b/UI/Controls/user_entry.gd @@ -22,6 +22,12 @@ func _ready() -> void: %User.pressed.connect(user_selected.emit.bind(chatter)) %Shoutout.pressed.connect(func(): Globals.twitcher.shoutout(chatter.user)) %Promote.pressed.connect(func(): Globals.twitcher.send_message(chatter.promo_msg)) + %ButtonMenu.pressed.connect(func(): toggle_buttons(!is_expanded)) + _update_tooltips() + +func _update_tooltips() -> void: + for node: Control in [%Shoutout, %Promote, %Refresh, %Raid, %Delete]: + node.tooltip_text = node.tooltip_text % chatter.user.display_name func update() -> void: if not chatter: diff --git a/UI/Controls/user_entry.tscn b/UI/Controls/user_entry.tscn index 0d111c26..695ce23b 100644 --- a/UI/Controls/user_entry.tscn +++ b/UI/Controls/user_entry.tscn @@ -26,6 +26,7 @@ corner_detail = 5 [node name="UserEntry" type="PanelContainer" unique_id=1215925059] offset_right = 40.0 offset_bottom = 40.0 +theme_type_variation = &"Entry" script = ExtResource("1_xsfty") [node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=582266053] @@ -62,9 +63,11 @@ theme_type_variation = &"BlankButton" [node name="User" type="Button" parent="HBoxContainer" unique_id=565524419] unique_name_in_owner = true +custom_minimum_size = Vector2(130, 0) layout_mode = 2 size_flags_horizontal = 3 text = "Falinere" +text_overrun_behavior = 3 [node name="LiveStatus" type="ColorRect" parent="HBoxContainer/User" unique_id=1459190091] unique_name_in_owner = true @@ -81,6 +84,7 @@ color = Color(0.3647059, 1, 0.44313726, 0.3764706) unique_name_in_owner = true custom_minimum_size = Vector2(32, 32) layout_mode = 2 +tooltip_text = "Shoutout %s" icon = ExtResource("3_sck47") icon_alignment = 1 expand_icon = true @@ -97,6 +101,7 @@ layout_mode = 2 unique_name_in_owner = true custom_minimum_size = Vector2(32, 32) layout_mode = 2 +tooltip_text = "Promote %s" icon = ExtResource("4_0jtnn") icon_alignment = 1 expand_icon = true @@ -105,6 +110,7 @@ expand_icon = true unique_name_in_owner = true custom_minimum_size = Vector2(32, 32) layout_mode = 2 +tooltip_text = "Refresh %s Twitch Data" icon = ExtResource("5_xsfty") icon_alignment = 1 expand_icon = true @@ -114,6 +120,7 @@ unique_name_in_owner = true modulate = Color(0.6392157, 0.38431373, 0.84313726, 1) custom_minimum_size = Vector2(32, 32) layout_mode = 2 +tooltip_text = "Raid %s channel" icon = ExtResource("6_mi6bx") icon_alignment = 1 expand_icon = true @@ -123,6 +130,7 @@ unique_name_in_owner = true modulate = Color(1, 0, 0, 1) custom_minimum_size = Vector2(32, 32) layout_mode = 2 +tooltip_text = "Delete %s from Chatter Database" icon = ExtResource("9_k1oax") icon_alignment = 1 expand_icon = true From 37bd07498333bd7c260e329d037d17000d348e2c Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:08:55 -0500 Subject: [PATCH 10/13] Updated TwitchUserInfo Added hiding of loading icon, when clear() is used on the control. Added TabPanel stylebox variation to ExtraInfo. --- UI/Controls/twitch_user_info.gd | 1 + UI/Controls/twitch_user_info.tscn | 1 + 2 files changed, 2 insertions(+) diff --git a/UI/Controls/twitch_user_info.gd b/UI/Controls/twitch_user_info.gd index 184b08f8..4f057844 100644 --- a/UI/Controls/twitch_user_info.gd +++ b/UI/Controls/twitch_user_info.gd @@ -71,6 +71,7 @@ func populate_from_chatter(_chatter: Chatter) -> void: func clear() -> void: %AvatarImg.texture = preload("res://UI/assets/twitch_user_profile_pic.png") + %LoadingSimple.hide() %Username.text = "" %DisplayName.text = "" %UserId.text = "" diff --git a/UI/Controls/twitch_user_info.tscn b/UI/Controls/twitch_user_info.tscn index 9cfe01ff..5cd0fbd1 100644 --- a/UI/Controls/twitch_user_info.tscn +++ b/UI/Controls/twitch_user_info.tscn @@ -74,6 +74,7 @@ expand_icon = true [node name="ExtraInfo" type="PanelContainer" parent="HBoxContainer" unique_id=1175412769] unique_name_in_owner = true layout_mode = 2 +theme_type_variation = &"TabPanel" [node name="ScrollContainer" type="ScrollContainer" parent="HBoxContainer/ExtraInfo" unique_id=1105674920] layout_mode = 2 From f417151be4f76a64c9cdad90c203cf94bfe00bd9 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:09:59 -0500 Subject: [PATCH 11/13] Updated SteamAppPanel Updated Backgroudn Expand mode to cover. Renamed ClosePanel button to Clear Remoevd ClosePanel handler, and added Clear pressed signal connecting to clear function. --- UI/Controls/steam_app_panel.gd | 5 +---- UI/Controls/steam_app_panel.tscn | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/UI/Controls/steam_app_panel.gd b/UI/Controls/steam_app_panel.gd index 6e6f0395..d70405f7 100644 --- a/UI/Controls/steam_app_panel.gd +++ b/UI/Controls/steam_app_panel.gd @@ -111,7 +111,7 @@ var data: SteamAppData: func _ready() -> void: %VisitPage.pressed.connect(_on_btn_visit_page_pressed) - %ClosePanel.pressed.connect(_on_btn_close_png_pressed) + %Clear.pressed.connect(clear) if Engine.is_editor_hint(): if selected_steam_game != 0: get_app_info(STEAM_APP_IDS[selected_steam_game]) @@ -205,9 +205,6 @@ func load_texture_from_url(url: String) -> ImageTexture: http.queue_free() return tex -func _on_btn_close_png_pressed() -> void: - hide() - func _on_btn_visit_page_pressed() -> void: if data: OS.shell_open(data.short_url) diff --git a/UI/Controls/steam_app_panel.tscn b/UI/Controls/steam_app_panel.tscn index 7498bf65..3f82d6c0 100644 --- a/UI/Controls/steam_app_panel.tscn +++ b/UI/Controls/steam_app_panel.tscn @@ -167,6 +167,7 @@ metadata/_custom_type_script = "uid://chgufd1youdel" [node name="Background" type="TextureRect" parent="." unique_id=2131684228] unique_name_in_owner = true layout_mode = 2 +expand_mode = 1 [node name="v" type="VBoxContainer" parent="." unique_id=711622106] layout_mode = 2 @@ -191,7 +192,7 @@ stretch_mode = 5 layout_mode = 2 text = "Steam App Info" -[node name="ClosePanel" type="Button" parent="v/m" unique_id=1693377160] +[node name="Clear" type="Button" parent="v/m" unique_id=1693377160] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 8 From fce33bfd31bdf20bf6e74c55245e48d0759af1f0 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:12:48 -0500 Subject: [PATCH 12/13] Updated TwitchUserInfo Updated PanelContainer to use TabPanel stylebox variant. Updated structure of Scene. Added UserGames panel to the panel. Updated code to handle clearing of other panels, if the chatter is null, otherwise populate information in the other panels. Added resized signal connect, to set the UserGames panel to an even split between the lists of games, and the game info panels. Ensure that TwitchUserInfo, UserPromo and UserGames are properly updates with the correct information on becoming ready in the SceneTree. --- UI/Controls/internal_twitch_user_info.gd | 26 +++++++++++++++++----- UI/Controls/internal_twitch_user_info.tscn | 18 ++++++++++++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/UI/Controls/internal_twitch_user_info.gd b/UI/Controls/internal_twitch_user_info.gd index 34755355..cc7793d8 100644 --- a/UI/Controls/internal_twitch_user_info.gd +++ b/UI/Controls/internal_twitch_user_info.gd @@ -1,16 +1,32 @@ extends PanelContainer + +@onready var user_games: UserGamesPanel = %UserGames @onready var tui := %TwitchUserInfo @onready var up := %UserPromo + var chatter: Chatter: set(value): chatter = value - if not value: return - if not tui: return - tui.populate_from_chatter(chatter) - if not up: return - up.chatter = value + if not value: + tui.clear() + up.chatter = value + user_games.clear() + return + if tui: + tui.populate_from_chatter(chatter) + if up: + up.chatter = value + if user_games: + user_games.chatter = value func _ready() -> void: tui.extra_expanding.connect(func(x): if x: up.visible = false) tui.extra_expanded.connect(func(x): if not x: up.visible = true) + resized.connect(func(): + var width := int(size.x / 2) + user_games.splitter.split_offsets[0] = width + ) + tui.populate_from_chatter(chatter) + up.chatter = chatter + user_games.chatter = chatter diff --git a/UI/Controls/internal_twitch_user_info.tscn b/UI/Controls/internal_twitch_user_info.tscn index 6a02b2a2..fcac5b4b 100644 --- a/UI/Controls/internal_twitch_user_info.tscn +++ b/UI/Controls/internal_twitch_user_info.tscn @@ -3,20 +3,32 @@ [ext_resource type="PackedScene" uid="uid://bk7elsy5s3equ" path="res://UI/Controls/twitch_user_info.tscn" id="1_bbob4"] [ext_resource type="Script" uid="uid://bbyomfy4iqbq3" path="res://UI/Controls/internal_twitch_user_info.gd" id="1_l8fl7"] [ext_resource type="PackedScene" uid="uid://cadil3rnqh61e" path="res://UI/Controls/user_promo.tscn" id="2_l8fl7"] +[ext_resource type="PackedScene" uid="uid://cojuxefo7cryj" path="res://UI/Controls/user_games.tscn" id="4_h7tf2"] [node name="InternalTwitchUserInfo" type="PanelContainer" unique_id=1986869556] +offset_right = 1346.0 +offset_bottom = 536.0 +theme_type_variation = &"TabPanel" script = ExtResource("1_l8fl7") metadata/_tab_index = 0 -[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=515716981] +[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=92971307] layout_mode = 2 -[node name="TwitchUserInfo" parent="HBoxContainer" unique_id=1944732530 instance=ExtResource("1_bbob4")] +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer" unique_id=515716981] +layout_mode = 2 + +[node name="TwitchUserInfo" parent="VBoxContainer/HBoxContainer" unique_id=1944732530 instance=ExtResource("1_bbob4")] unique_name_in_owner = true layout_mode = 2 size_flags_vertical = 0 -[node name="UserPromo" parent="HBoxContainer" unique_id=1364169576 instance=ExtResource("2_l8fl7")] +[node name="UserPromo" parent="VBoxContainer/HBoxContainer" unique_id=1364169576 instance=ExtResource("2_l8fl7")] unique_name_in_owner = true layout_mode = 2 size_flags_vertical = 1 + +[node name="UserGames" parent="VBoxContainer" unique_id=2022365407 instance=ExtResource("4_h7tf2")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 From 85fff938fbf20161b734775586aee815e93b1a03 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Mon, 9 Mar 2026 03:13:49 -0500 Subject: [PATCH 13/13] Updated GeneralPanel Update StyleBoxes for ObsPassword line entry. Added TabPanel theme variation to General panel. --- UI/Controls/general_panel.tscn | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/UI/Controls/general_panel.tscn b/UI/Controls/general_panel.tscn index b0e8d6cb..c4626b71 100644 --- a/UI/Controls/general_panel.tscn +++ b/UI/Controls/general_panel.tscn @@ -4,12 +4,62 @@ [ext_resource type="Texture2D" uid="uid://cnu6l3x820i82" path="res://UI/assets/bootstrap/eye-slash.png" id="1_rbtts"] [ext_resource type="Script" uid="uid://ch7qf8iy31pfy" path="res://lib/UI/line_edit_with_buttons.gd" id="2_oookw"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oookw"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 35.0 +content_margin_bottom = 4.0 +bg_color = Color(0.1, 0.1, 0.1, 0.6) +border_width_bottom = 2 +border_color = Color(0, 0, 0, 0.6) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +corner_detail = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7naex"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 35.0 +content_margin_bottom = 4.0 +bg_color = Color(0.1, 0.1, 0.1, 0.3) +border_width_bottom = 2 +border_color = Color(0, 0, 0, 0.3) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +corner_detail = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_en626"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 35.0 +content_margin_bottom = 4.0 +bg_color = Color(1, 1, 1, 0.75) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +corner_detail = 5 +expand_margin_left = 2.0 +expand_margin_top = 2.0 +expand_margin_right = 2.0 +expand_margin_bottom = 2.0 + [node name="General" type="PanelContainer" unique_id=1071328377] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +theme_type_variation = &"TabPanel" script = ExtResource("1_oafot") metadata/_tab_index = 0 @@ -126,6 +176,9 @@ text = "Password:" [node name="ObsPass" type="LineEdit" parent="MarginContainer/VBoxContainer/GridContainer" unique_id=170190217] unique_name_in_owner = true layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_oookw") +theme_override_styles/read_only = SubResource("StyleBoxFlat_7naex") +theme_override_styles/focus = SubResource("StyleBoxFlat_en626") secret = true script = ExtResource("2_oookw") right = ExtResource("1_rbtts")