diff --git a/Makefile b/Makefile index c3fde88e..c0764927 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ $(EXPORT_TEMPLATE): .PHONY: debug debug: $(IMPORT_DIR) ## Run the project in debug mode in gamescope - $(GAMESCOPE) --xwayland-count 2 -- \ + $(GAMESCOPE) -e --xwayland-count 2 -- \ $(GODOT) --path $(PWD) --remote-debug tcp://127.0.0.1:6007 \ --position 320,140 res://entrypoint.tscn diff --git a/assets/editor-icons/fluent--brain-circuit-24-filled.svg b/assets/editor-icons/fluent--brain-circuit-24-filled.svg new file mode 100644 index 00000000..a63f851b --- /dev/null +++ b/assets/editor-icons/fluent--brain-circuit-24-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/editor-icons/fluent--brain-circuit-24-filled.svg.import b/assets/editor-icons/fluent--brain-circuit-24-filled.svg.import new file mode 100644 index 00000000..b69c5471 --- /dev/null +++ b/assets/editor-icons/fluent--brain-circuit-24-filled.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dumpjvnmyvle0" +path="res://.godot/imported/fluent--brain-circuit-24-filled.svg-deafc844fbbb2acb1300ed1eab205035.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/editor-icons/fluent--brain-circuit-24-filled.svg" +dest_files=["res://.godot/imported/fluent--brain-circuit-24-filled.svg-deafc844fbbb2acb1300ed1eab205035.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/assets/editor-icons/fluent--draw-text-24-filled.svg b/assets/editor-icons/fluent--draw-text-24-filled.svg new file mode 100644 index 00000000..f3346aeb --- /dev/null +++ b/assets/editor-icons/fluent--draw-text-24-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/editor-icons/fluent--draw-text-24-filled.svg.import b/assets/editor-icons/fluent--draw-text-24-filled.svg.import new file mode 100644 index 00000000..cdeda7a3 --- /dev/null +++ b/assets/editor-icons/fluent--draw-text-24-filled.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b37mlly16qbny" +path="res://.godot/imported/fluent--draw-text-24-filled.svg-62a66cb94069dc7c979f10a171be9c30.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/editor-icons/fluent--draw-text-24-filled.svg" +dest_files=["res://.godot/imported/fluent--draw-text-24-filled.svg-62a66cb94069dc7c979f10a171be9c30.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/assets/state/state_machines/global_state_machine.tres b/assets/state/state_machines/global_state_machine.tres index 39c6c6df..468c96e2 100644 --- a/assets/state/state_machines/global_state_machine.tres +++ b/assets/state/state_machines/global_state_machine.tres @@ -1,7 +1,13 @@ -[gd_resource type="Resource" script_class="StateMachine" load_steps=2 format=3 uid="uid://cr544el0cqjlm"] +[gd_resource type="Resource" script_class="StateMachine" load_steps=6 format=3 uid="uid://cr544el0cqjlm"] +[ext_resource type="Resource" uid="uid://c640rq4e1xmrn" path="res://assets/state/states/in_game.tres" id="1_dtppc"] [ext_resource type="Script" path="res://core/systems/state/state_machine.gd" id="1_dw1uo"] +[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="2_pg6ge"] +[ext_resource type="Resource" uid="uid://cv3vduo0ojk1u" path="res://assets/state/states/menu.tres" id="3_4n6bo"] +[ext_resource type="Resource" uid="uid://dgbe422crufa4" path="res://assets/state/states/popup.tres" id="4_j3a4g"] [resource] script = ExtResource("1_dw1uo") logger_name = "GlobalStateMachine" +minimum_states = 1 +allowed_states = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("1_dtppc"), ExtResource("2_pg6ge"), ExtResource("3_4n6bo"), ExtResource("4_j3a4g")]) diff --git a/assets/state/state_machines/menu_state_machine.tres b/assets/state/state_machines/menu_state_machine.tres new file mode 100644 index 00000000..e5e2caf5 --- /dev/null +++ b/assets/state/state_machines/menu_state_machine.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="StateMachine" load_steps=2 format=3 uid="uid://bcr6c0281lb5b"] + +[ext_resource type="Script" path="res://core/systems/state/state_machine.gd" id="1_18avi"] + +[resource] +script = ExtResource("1_18avi") +logger_name = "MenuStateMachine" +minimum_states = 0 diff --git a/assets/state/state_machines/popup_state_machine.tres b/assets/state/state_machines/popup_state_machine.tres new file mode 100644 index 00000000..77866321 --- /dev/null +++ b/assets/state/state_machines/popup_state_machine.tres @@ -0,0 +1,14 @@ +[gd_resource type="Resource" script_class="StateMachine" load_steps=7 format=3 uid="uid://cadriyl38ny5y"] + +[ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="1_7fvmm"] +[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="2_detpa"] +[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="3_0mhn6"] +[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="4_qu5fi"] +[ext_resource type="Resource" uid="uid://db5gbdl3xgwlq" path="res://assets/state/states/help_menu.tres" id="5_5ytlq"] +[ext_resource type="Script" path="res://core/systems/state/state_machine.gd" id="6_82te1"] + +[resource] +script = ExtResource("6_82te1") +logger_name = "PopupStateMachine" +minimum_states = 0 +allowed_states = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("1_7fvmm"), ExtResource("2_detpa"), ExtResource("3_0mhn6"), ExtResource("4_qu5fi"), ExtResource("5_5ytlq")]) diff --git a/assets/state/states/menu.tres b/assets/state/states/menu.tres new file mode 100644 index 00000000..fb1878ea --- /dev/null +++ b/assets/state/states/menu.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="State" load_steps=2 format=3 uid="uid://cv3vduo0ojk1u"] + +[ext_resource type="Script" path="res://core/systems/state/state.gd" id="1_8q8t2"] + +[resource] +script = ExtResource("1_8q8t2") +name = "menu" +data = {} diff --git a/assets/state/states/popup.tres b/assets/state/states/popup.tres new file mode 100644 index 00000000..32e2341d --- /dev/null +++ b/assets/state/states/popup.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="State" load_steps=2 format=3 uid="uid://dgbe422crufa4"] + +[ext_resource type="Script" path="res://core/systems/state/state.gd" id="1_t0m3s"] + +[resource] +script = ExtResource("1_t0m3s") +name = "popup" +data = {} diff --git a/assets/styles/dracula/quick_bar_panel.tres b/assets/styles/dracula/quick_bar_panel.tres index 3de48999..f1cb30b3 100644 --- a/assets/styles/dracula/quick_bar_panel.tres +++ b/assets/styles/dracula/quick_bar_panel.tres @@ -1,7 +1,7 @@ [gd_resource type="StyleBoxFlat" format=3 uid="uid://br2w1fnanqkfa"] [resource] -bg_color = Color(0.0823529, 0.0862745, 0.105882, 1) +bg_color = Color(0.156863, 0.164706, 0.211765, 1) corner_radius_bottom_left = 10 shadow_size = 5 shadow_offset = Vector2(-4, 4) diff --git a/assets/themes/card_ui-dracula.tres b/assets/themes/card_ui-dracula.tres index c3716d32..0c10fd7a 100644 --- a/assets/themes/card_ui-dracula.tres +++ b/assets/themes/card_ui-dracula.tres @@ -16,7 +16,7 @@ [ext_resource type="StyleBox" uid="uid://y3qbwgrt2wai" path="res://assets/styles/dracula/settings_menu_panel.tres" id="10_rxp5w"] [ext_resource type="StyleBox" uid="uid://dj0ysj0o6beba" path="res://assets/styles/dracula/power_menu_panel.tres" id="10_u1qhh"] [ext_resource type="StyleBox" uid="uid://bifp73vg5vmau" path="res://assets/styles/dracula/plugin_store_card_panel.tres" id="11_83cpl"] -[ext_resource type="StyleBox" uid="uid://daavpt58e7jlj" path="res://assets/styles/darksoul/quick_bar_panel.tres" id="14_fm0xr"] +[ext_resource type="StyleBox" uid="uid://br2w1fnanqkfa" path="res://assets/styles/dracula/quick_bar_panel.tres" id="15_354e6"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_s2sy6"] bg_color = Color(0.133333, 0.137255, 0.180392, 1) @@ -112,14 +112,14 @@ MainMenu/styles/panel = ExtResource("7_n80rp") Notification/base_type = &"PanelContainer" Notification/styles/panel = ExtResource("9_sy73e") Panel/styles/panel = ExtResource("2_f7nj8") -PanelContainer/styles/panel = ExtResource("2_f7nj8") +PanelContainer/styles/panel = ExtResource("4_wqh56") PluginStoreCard/base_type = &"PanelContainer" PluginStoreCard/styles/panel = ExtResource("11_83cpl") PowerMenu/base_type = &"PanelContainer" PowerMenu/styles/panel = ExtResource("10_u1qhh") ProgressBar/styles/fill = SubResource("StyleBoxFlat_4nys6") QuickBar/base_type = &"PanelContainer" -QuickBar/styles/panel = ExtResource("14_fm0xr") +QuickBar/styles/panel = ExtResource("15_354e6") RoundedPanel/base_type = &"PanelContainer" RoundedPanel/styles/panel = SubResource("StyleBoxFlat_knf7f") SearchBar/base_type = &"PanelContainer" diff --git a/core/global/gamescope.gd b/core/global/gamescope.gd index 8def04e7..d8ae55f7 100644 --- a/core/global/gamescope.gd +++ b/core/global/gamescope.gd @@ -248,7 +248,7 @@ func get_window_pid(window_id: int, display: XWAYLAND) -> int: ## window was found. func get_window_id(pid: int, display: XWAYLAND) -> int: var display_name := get_display_name(display) - logger.debug("Getting Window ID for {0} on display {1}".format([pid, display_name])) + logger.trace("Getting Window ID for {0} on display {1}".format([pid, display_name])) var xwayland := get_xwayland(display) if not xwayland: return -1 @@ -270,7 +270,7 @@ func get_window_id(pid: int, display: XWAYLAND) -> int: func get_window_ids(pid: int, display: XWAYLAND) -> PackedInt32Array: var window_ids := PackedInt32Array() var display_name := get_display_name(display) - logger.debug("Getting Window ID for {0} on display {1}".format([pid, display_name])) + logger.trace("Getting Window ID for {0} on display {1}".format([pid, display_name])) var xwayland := get_xwayland(display) if not xwayland: return window_ids diff --git a/core/global/launch_manager.gd b/core/global/launch_manager.gd index d2cb28b0..7d65adff 100644 --- a/core/global/launch_manager.gd +++ b/core/global/launch_manager.gd @@ -55,8 +55,10 @@ var _apps_by_name: Dictionary = {} var _data_dir: String = ProjectSettings.get_setting("OpenGamepadUI/data/directory") var _persist_path: String = "/".join([_data_dir, "launcher.json"]) var _persist_data: Dictionary = {"version": 1} -var logger := Log.get_logger("LaunchManager", Log.LEVEL.INFO) +var _ogui_window_id := gamescope.get_window_id(PID, gamescope.XWAYLAND.OGUI) var should_manage_overlay := true +var logger := Log.get_logger("LaunchManager", Log.LEVEL.INFO) + # Connect to Gamescope signals func _init() -> void: @@ -64,19 +66,18 @@ func _init() -> void: var on_focus_changed := func(from: int, to: int): logger.info("Window focus changed from " + str(from) + " to: " + str(to)) var last_app := _current_app - _current_app = get_running_from_window_id(to) - # If there is no _current_app then another process opened this window. Find it. - if _current_app == null: - _current_app = _detect_running_app(to) + _current_app = _detect_running_app(to) logger.debug("Last app: " + str(last_app) + " current_app: " + str(_current_app)) app_switched.emit(last_app, _current_app) + # If the app has a gamepad profile, set it - set_app_gamepad_profile(_current_app) + if to != _ogui_window_id and _current_app: + set_app_gamepad_profile(_current_app) - # If we don't want LaunchManager to manage overlay (I.E. overlay mode), return false always. - if not should_manage_overlay: - return + # If we don't want LaunchManager to manage overlay (I.E. overlay mode), return false always. + if not should_manage_overlay: + return gamescope.focused_window_updated.connect(on_focus_changed) @@ -94,21 +95,19 @@ func _init() -> void: if not should_manage_overlay: return - logger.debug("Enabling STEAM_OVERLAY.") - var ogui_window_id = gamescope.get_window_id(PID, gamescope.XWAYLAND.OGUI) - gamescope.set_overlay(ogui_window_id, 0) - + logger.debug("Enabling STEAM_OVERLAY atom") + gamescope.set_overlay(_ogui_window_id, 0) + var on_game_state_exited := func(_to: State): # Set the gamepad profile to the global profile set_gamepad_profile("") - + # If we don't want LaunchManager to manage overlay (I.E. overlay mode), return false always. if not should_manage_overlay: return - logger.debug("Removing STEAM_OVERLAY.") - var ogui_window_id = gamescope.get_window_id(PID, gamescope.XWAYLAND.OGUI) - gamescope.set_overlay(ogui_window_id, 1) + logger.debug("Disabling STEAM_OVERLAY atom") + gamescope.set_overlay(_ogui_window_id, 1) in_game_state.state_entered.connect(on_game_state_entered) in_game_state.state_exited.connect(on_game_state_exited) @@ -118,12 +117,12 @@ func _init() -> void: func _load_persist_data(): # Create the data directory if it doesn't exist DirAccess.make_dir_absolute(_data_dir) - + # Create our data file if it doesn't exist if not FileAccess.file_exists(_persist_path): logger.debug("LaunchManager: Launcher data does not exist. Creating it.") _save_persist_data() - + # Read our persistent data and parse it var file: FileAccess = FileAccess.open(_persist_path, FileAccess.READ) var data: String = file.get_as_text() @@ -168,12 +167,12 @@ func launch(app: LibraryLaunchItem) -> RunningApp: env = user_env var sandboxing_key := ".".join(["use_sandboxing", app._provider_id]) var use_sandboxing := settings_manager.get_value(section, sandboxing_key, true) as bool - + # Set the display environment if one was not set. if not "DISPLAY" in env: env["DISPLAY"] = gamescope.get_display_name(Gamescope.XWAYLAND.GAME) var display := env["DISPLAY"] as String - + # Set the OGUI ID environment variable env["OGUI_ID"] = app.name @@ -309,7 +308,7 @@ func set_gamepad_profile(path: String, target_gamepad: String = "") -> void: var profile_path := settings_manager.get_value("input", "gamepad_profile", InputPlumber.DEFAULT_GLOBAL_PROFILE) as String if not profile_path.ends_with(".json") or not FileAccess.file_exists(profile_path): profile_path = InputPlumber.DEFAULT_GLOBAL_PROFILE - logger.debug("Loading global gamepad profile: " + profile_path) + logger.info("Loading global gamepad profile: " + profile_path) for gamepad in input_plumber.composite_devices: gamepad.target_modify_profile(profile_path, profile_modifier) @@ -322,12 +321,12 @@ func set_gamepad_profile(path: String, target_gamepad: String = "") -> void: target_devices.append("touchpad") _: logger.debug(target_gamepad, "needs no additional target devices.") - logger.debug("Setting target devices to: ", target_devices) + logger.info("Setting target devices to: ", target_devices) gamepad.set_target_devices(target_devices) return - logger.debug("Loading gamepad profile: " + path) + logger.info("Loading gamepad profile: " + path) if not FileAccess.file_exists(path): logger.warn("Gamepad profile not found: " + path) return @@ -350,7 +349,7 @@ func set_gamepad_profile(path: String, target_gamepad: String = "") -> void: target_devices.append("touchpad") _: logger.debug(target_gamepad, "needs no additional target devices.") - logger.debug("Setting target devices to: ", target_devices) + logger.info("Setting target devices to: ", target_devices) gamepad.set_target_devices(target_devices) var notify := Notification.new("Using gamepad profile: " + profile.name) @@ -409,7 +408,7 @@ func _remove_running(app: RunningApp): # Checks for running apps and updates our state accordingly -func _check_running() -> void: +func check_running() -> void: # Find the root window var root_id := gamescope.get_root_window_id(Gamescope.XWAYLAND.GAME) if root_id < 0: diff --git a/core/systems/input/back_input_handler.gd b/core/systems/input/back_input_handler.gd index 0cadd6ca..a2770823 100644 --- a/core/systems/input/back_input_handler.gd +++ b/core/systems/input/back_input_handler.gd @@ -2,6 +2,8 @@ extends Node class_name BackInputHandler +## DEPRECATED: Use [InputWatcher] with [StateUpdater] instead + ## The state machine to use to update when back input is pressed @export var state_machine: StateMachine = preload( "res://assets/state/state_machines/global_state_machine.tres" diff --git a/core/systems/input/focus_group.gd b/core/systems/input/focus_group.gd index 9814a0b6..a477dc7a 100644 --- a/core/systems/input/focus_group.gd +++ b/core/systems/input/focus_group.gd @@ -11,10 +11,13 @@ class_name FocusGroup @export_category("Focus Control") ## The current focus of the focus group @export var current_focus: Control +## DEPRECATED: Use [InputWatcher] nodes with [FocusSetter] to handle back input. ## Menus with multiple levels of focus groups can be part of a chain of focus @export var focus_stack: FocusStack ## The InputEvent that will trigger focusing a parent focus group @export var back_action := "ogui_east" +## Whether or not to wrap around focus chains +@export var wrap_focus: bool = true @export_category("Focus Group Neighbors") @export var focus_neighbor_bottom: FocusGroup @@ -144,7 +147,7 @@ func _input(event: InputEvent) -> void: return # Only handle back button pressed and when the guide button is not held - if not event.is_action_pressed(back_action) or Input.is_action_pressed("ogui_guide"): + if not event.is_action_released(back_action) or Input.is_action_pressed("ogui_guide"): return # Only handle input if a focus stack is defined @@ -421,12 +424,21 @@ func _vbox_set_focus_tree(control_children: Array[Control]) -> void: child.focus_next = control_children[i + 1].get_path() child.focus_neighbor_bottom = control_children[i + 1].get_path() else: - child.focus_next = control_children[0].get_path() - child.focus_neighbor_bottom = control_children[0].get_path() + # If wrap focus is enabled, then link focus of the last node to the first node. + if wrap_focus: + child.focus_next = control_children[0].get_path() + child.focus_neighbor_bottom = control_children[0].get_path() + else: + child.focus_next = control_children[i].get_path() + child.focus_neighbor_bottom = control_children[i].get_path() # Index -1 - child.focus_previous = control_children[i - 1].get_path() - child.focus_neighbor_top = control_children[i - 1].get_path() + if i == 0 and not wrap_focus: + child.focus_previous = control_children[i].get_path() + child.focus_neighbor_top = control_children[i].get_path() + else: + child.focus_previous = control_children[i - 1].get_path() + child.focus_neighbor_top = control_children[i - 1].get_path() # Block leaving the UI element unless B button is pressed. child.focus_neighbor_left = control_children[i].get_path() diff --git a/core/systems/input/input_manager.gd b/core/systems/input/input_manager.gd index 82a0d88a..7925a935 100644 --- a/core/systems/input/input_manager.gd +++ b/core/systems/input/input_manager.gd @@ -13,21 +13,25 @@ class_name InputManager ## Reference to the on-screen keyboard instance to open when the OSK action is ## pressed. -const osk := preload("res://core/global/keyboard_instance.tres") +var osk := load("res://core/global/keyboard_instance.tres") as KeyboardInstance ## The audio manager to use to adjust the audio when audio input events happen. var audio_manager := load("res://core/global/audio_manager.tres") as AudioManager ## InputPlumber receives and sends DBus input events. var input_plumber := load("res://core/systems/input/input_plumber.tres") as InputPlumber - +## LaunchManager provides context on the currently running app so we can switch profiles +var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager +## The Global State Machine +var state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine ## State machine to use to switch menu states in response to input events. -var state_machine := ( - preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var popup_state_machine := ( + preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine ) var in_game_menu_state := preload("res://assets/state/states/in_game_menu.tres") as State var main_menu_state := preload("res://assets/state/states/main_menu.tres") as State var quick_bar_state := preload("res://assets/state/states/quick_bar_menu.tres") as State var osk_state := preload("res://assets/state/states/osk.tres") as State +var popup_state := preload("res://assets/state/states/popup.tres") as State ## Map of pressed actions to prevent double inputs var actions_pressed := {} @@ -135,6 +139,8 @@ func _input(event: InputEvent) -> void: # Handle inputs when the guide button is being held if Input.is_action_pressed("ogui_guide"): + # Prevent ALL input from propagating if guide is held! + get_viewport().set_input_as_handled() logger.debug("Additional action while guide wad pressed.") # OSK if event.is_action_pressed("ogui_north"): @@ -146,9 +152,6 @@ func _input(event: InputEvent) -> void: logger.debug("Trigger QB") action_press(dbus_path, "ogui_qb") action_press(dbus_path, "ogui_guide_action") - - # Prevent ALL input from propagating if guide is held! - get_viewport().set_input_as_handled() return if event.is_action_pressed("ogui_south"): @@ -158,6 +161,13 @@ func _input(event: InputEvent) -> void: logger.debug("South released on its own.") action_release(dbus_path, "ui_accept") + if event.is_action_pressed("ogui_north"): + logger.debug("North pressed on its own.") + action_press(dbus_path, "ogui_search") + elif event.is_action_released("ogui_north"): + logger.debug("North released on its own.") + action_release(dbus_path, "ogui_search") + ## Handle guide button events and determine whether this is a guide action ## (e.g. guide + A to open the Quick Bar), or if it's just a normal guide button press. @@ -165,7 +175,11 @@ func _guide_input(event: InputEvent) -> void: var dbus_path := event.get_meta("dbus_path", "") as String # Only act on release events if event.is_pressed(): - logger.debug("Guide pressed. Waiting for additional events.") + logger.warn("Guide pressed. Waiting for additional events.") + # Set the gamepad profile to the global default so we can capture button events. + # This ensures that we use the global profile and not the game's input profile for + # processing guide button combos and navigating the menu. + launch_manager.set_gamepad_profile("") return # If a guide action combo was pressed and we released the guide button, @@ -188,15 +202,14 @@ func _main_menu_input(event: InputEvent) -> void: return # Open the main menu - var state := state_machine.current_state() - var menu_state := main_menu_state + var state := popup_state_machine.current_state() - if state == menu_state: - state_machine.pop_state() + if state == main_menu_state: + popup_state_machine.pop_state() elif state in [quick_bar_state, osk_state]: - state_machine.replace_state(menu_state) + popup_state_machine.replace_state(main_menu_state) else: - state_machine.push_state(menu_state) + popup_state_machine.push_state(main_menu_state) ## Handle quick bar menu events to open the quick bar menu @@ -205,13 +218,13 @@ func _on_quick_bar_open(event: InputEvent) -> void: if not event.is_pressed(): return - var state := state_machine.current_state() + var state := popup_state_machine.current_state() if state == quick_bar_state: - state_machine.pop_state() + popup_state_machine.pop_state() elif state in [main_menu_state, in_game_menu_state, osk_state]: - state_machine.replace_state(quick_bar_state) + popup_state_machine.replace_state(quick_bar_state) else: - state_machine.push_state(quick_bar_state) + popup_state_machine.push_state(quick_bar_state) ## Handle OSK events for bringing up the on-screen keyboard @@ -220,18 +233,22 @@ func _osk_input(event: InputEvent) -> void: if not event.is_pressed(): return + var state := popup_state_machine.current_state() + if state == osk_state: + osk.close() + popup_state_machine.pop_state() + return + + if state in [main_menu_state, in_game_menu_state, quick_bar_state]: + popup_state_machine.replace_state(osk_state) + else: + popup_state_machine.push_state(osk_state) + state_machine.push_state(popup_state) + var context := KeyboardContext.new() context.type = KeyboardContext.TYPE.X11 osk.open(context) - var state := state_machine.current_state() - if state == osk_state: - state_machine.pop_state() - elif state in [main_menu_state, in_game_menu_state, quick_bar_state]: - state_machine.replace_state(osk_state) - else: - state_machine.push_state(osk_state) - ## Handle audio input events such as mute, volume up, and volume down func _audio_input(event: InputEvent) -> void: @@ -285,8 +302,12 @@ func _on_dbus_input_event(event: String, value: float, dbus_path: String) -> voi action = "ogui_osk" "ui_r1": action = "ogui_tab_right" + "ui_r2": + action = "ogui_right_trigger" "ui_l1": action = "ogui_tab_left" + "ui_l2": + action = "ogui_left_trigger" if pressed: action_press(dbus_path, action) diff --git a/core/systems/input/input_watcher.gd b/core/systems/input/input_watcher.gd index 765dc9e2..f1e8543e 100644 --- a/core/systems/input/input_watcher.gd +++ b/core/systems/input/input_watcher.gd @@ -16,20 +16,43 @@ signal input_released ## If true, consumes the event, marking it as handled so no other nodes ## try to handle this input event. @export var stop_propagation: bool +## Always process inputs or only when parent node is visible +@export_flags("When visible", "When child focused") var process_input_mode: int = 3 ## Name of the input action in the InputMap to watch for var action: String +@onready var logger := Log.get_logger("InputWatcher", Log.LEVEL.INFO) + func _ready() -> void: if action.is_empty(): set_process_input(false) + if process_input_mode == 0: + return + + # Only process input if the parent node is visible + var parent := get_parent() + if parent is Control: + var control := parent as Control + var on_visibility := func(): + set_process_input(control.is_visible_in_tree()) + control.visibility_changed.connect(on_visibility) + set_process_input(control.is_visible_in_tree()) + func _input(event: InputEvent) -> void: if not event.is_action(action): return + # Only process input if a child node has focus + if (process_input_mode & 2): + var focus_owner := get_viewport().gui_get_focus_owner() + var parent := get_parent() + if not parent.is_ancestor_of(focus_owner): + return + if event.is_pressed(): input_pressed.emit() elif event.is_released(): @@ -37,6 +60,8 @@ func _input(event: InputEvent) -> void: # Stop the event from propagating if stop_propagation: + var parent := get_parent() + logger.debug("Consuming input event '{action}' for node {n}".format({"action": action, "n": str(parent)})) get_viewport().set_input_as_handled() diff --git a/core/systems/input/overlay_mode_input_manager.gd b/core/systems/input/overlay_mode_input_manager.gd index cf5a84a9..f060c8fe 100644 --- a/core/systems/input/overlay_mode_input_manager.gd +++ b/core/systems/input/overlay_mode_input_manager.gd @@ -15,11 +15,15 @@ class_name OverlayInputManager var audio_manager := load("res://core/global/audio_manager.tres") as AudioManager ## InputPlumber receives and sends DBus input events. var input_plumber := load("res://core/systems/input/input_plumber.tres") as InputPlumber - +## LaunchManager provides context on the currently running app so we can switch profiles +var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager +## The Global State Machine +var state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine ## State machine to use to switch menu states in response to input events. -var state_machine := ( - preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var popup_state_machine := ( + preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine ) +var menu_state_machine := preload("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine var in_game_menu_state := preload("res://assets/state/states/in_game_menu.tres") as State var main_menu_state := preload("res://assets/state/states/main_menu.tres") as State var quick_bar_state := preload("res://assets/state/states/quick_bar_menu.tres") as State @@ -67,7 +71,6 @@ func _send_input(dbus_path: String, action: String, pressed: bool, strength: flo ## https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#how-does-it-work func _input(event: InputEvent) -> void: logger.debug("Got input event to handle: " + str(event)) - _trace_input_status("START") var dbus_path := event.get_meta("dbus_path", "") as String # Consume double inputs for controllers with DPads that have TRIGGER_HAPPY events @@ -88,26 +91,22 @@ func _input(event: InputEvent) -> void: if event.is_action("ogui_guide_ov"): _guide_input(event) get_viewport().set_input_as_handled() - _trace_input_status("END") return # Steam chord events if _send_steam_chord(event): get_viewport().set_input_as_handled() - _trace_input_status("END") return # Quick Bar open events if event.is_action("ogui_qb_ov"): _quick_bar_input(event) get_viewport().set_input_as_handled() - _trace_input_status("END") return # Handle audio events if event.is_action("ogui_volume_down") or event.is_action("ogui_volume_up") or event.is_action("ogui_volume_mute"): _audio_input(event) - _trace_input_status("END") return # Handle guide action release events @@ -117,39 +116,37 @@ func _input(event: InputEvent) -> void: if event.is_action_released("ogui_north_ov"): action_release(dbus_path, "ogui_osk_ov") get_viewport().set_input_as_handled() - _trace_input_status("END") return # Steam QAM if event.is_action_released("ogui_south_ov"): action_release(dbus_path, "ogui_qam_ov") get_viewport().set_input_as_handled() - _trace_input_status("END") return # Steam Video Capture if event.is_action_released("ogui_west_ov"): action_release(dbus_path, "ogui_vc_ov") get_viewport().set_input_as_handled() - _trace_input_status("END") return # Steam Screenshot if event.is_action_released("ogui_rb_ov"): action_release(dbus_path, "ogui_sc_ov") get_viewport().set_input_as_handled() - _trace_input_status("END") return # Quick Bar if event.is_action_released("ogui_east_ov"): action_release(dbus_path, "ogui_qb_ov") get_viewport().set_input_as_handled() - _trace_input_status("END") return # Handle inputs when the guide button is being held if Input.is_action_pressed("ogui_guide_ov"): + # Prevent ALL input from propagating if guide is held! + get_viewport().set_input_as_handled() + if event.is_pressed(): logger.debug("Additional action while guide wad pressed.") # Steam OSK @@ -177,7 +174,6 @@ func _input(event: InputEvent) -> void: action_press(dbus_path, "ogui_guide_action") action_press(dbus_path, "ogui_qb_ov") - elif event.is_released(): # Steam OSK if event.is_action_released("ogui_north_ov"): @@ -199,9 +195,6 @@ func _input(event: InputEvent) -> void: if event.is_action_released("ogui_east_ov"): action_release(dbus_path, "ogui_qb_ov") - # Prevent ALL input from propagating if guide is held! - get_viewport().set_input_as_handled() - _trace_input_status("END") return # Handle events in the UI while it is open. @@ -245,8 +238,6 @@ func _input(event: InputEvent) -> void: action_release(dbus_path, "ogui_tab_left") get_viewport().set_input_as_handled() - _trace_input_status("END") - ## Handle guide button events and determine whether this is a guide action ## (e.g. guide + A to open the Quick Bar), or if it's just a normal guide button press. @@ -255,6 +246,10 @@ func _guide_input(event: InputEvent) -> void: # Only act on release events if event.is_pressed(): logger.debug("Guide pressed. Waiting for additional events.") + # Set the gamepad profile to the global default so we can capture button events. + # This ensures that we use the global profile and not the game's input profile for + # processing guide button combos and navigating the menu. + launch_manager.set_gamepad_profile("") return # If a guide action combo was pressed and we released the guide button, @@ -272,22 +267,17 @@ func _guide_input(event: InputEvent) -> void: ## Handle quick bar menu events to open the quick bar menu func _quick_bar_input(event: InputEvent) -> void: - logger.debug("Trigger Quick Bar") - # Only act on press events if not event.is_pressed(): - logger.debug("Event is up event, ignore.") return - var state := state_machine.current_state() - logger.debug("Current State: " +str(state)) - if state != base_state: - logger.debug("Close Quick Bar") - _close_focused_window() - return - - logger.debug("Push Quick Bar") - state_machine.push_state(quick_bar_state) + var state := popup_state_machine.current_state() + if state == quick_bar_state: + popup_state_machine.pop_state() + elif state in [main_menu_state, in_game_menu_state]: + popup_state_machine.replace_state(quick_bar_state) + else: + popup_state_machine.push_state(quick_bar_state) ## Handle Steam chord events. Returns true if this was a Steam chord. @@ -399,16 +389,5 @@ func _on_dbus_input_event(event: String, value: float, dbus_path: String) -> voi # Closes all windows until we return to the base_state func _close_focused_window() -> void: - while state_machine.stack_length() > state_machine.minimum_states: - state_machine.pop_state() - - -# Does a trace print of the status of all events. -func _trace_input_status(point: String) -> void: - logger.trace(point +": Guide Pressed: " + str(Input.is_action_pressed("ogui_guide_ov"))) - logger.trace(point +": Guide Used: " + str(Input.is_action_pressed("ogui_guide_action"))) - logger.trace(point +": QAM Pressed: " + str(Input.is_action_pressed("ogui_qam_ov"))) - logger.trace(point +": OSK Pressed: " + str(Input.is_action_pressed("ogui_osk_ov"))) - logger.trace(point +": SC Pressed: " + str(Input.is_action_pressed("ogui_sc_ov"))) - logger.trace(point +": VC Pressed: " + str(Input.is_action_pressed("ogui_vc_ov"))) - logger.trace(point +": QB Pressed: " + str(Input.is_action_pressed("ogui_qb_ov"))) + popup_state_machine.clear_states() + menu_state_machine.clear_states() diff --git a/core/systems/launcher/launch_manager.gd b/core/systems/launcher/launch_manager.gd index c9accfa2..b7e36fa9 100644 --- a/core/systems/launcher/launch_manager.gd +++ b/core/systems/launcher/launch_manager.gd @@ -10,10 +10,6 @@ func _init() -> void: launch_manager._load_persist_data() -func _ready() -> void: - # Set a timer that will update our state based on if anything is running. - var running_timer = Timer.new() - running_timer.timeout.connect(launch_manager._check_running) - running_timer.wait_time = 1 - add_child(running_timer) - running_timer.start() +# TODO: Replace this with dbus signaling. This is super shitty. +func _process(delta) -> void: + launch_manager.check_running() diff --git a/core/systems/launcher/running_app.gd b/core/systems/launcher/running_app.gd index 8b20cb65..145fefff 100644 --- a/core/systems/launcher/running_app.gd +++ b/core/systems/launcher/running_app.gd @@ -122,10 +122,10 @@ func update() -> void: # Ensure that the running app has a corresponding window ID var has_valid_window := false if needs_window_id(): - logger.debug("App needs a valid window id") + logger.trace("App needs a valid window id") var id := _discover_window_id() if id > 0 and window_id != id: - logger.debug("Setting window ID " + str(id) + " for " + launch_item.name) + logger.trace("Setting window ID " + str(id) + " for " + launch_item.name) window_id = id else: has_valid_window = true @@ -155,13 +155,13 @@ func update() -> void: STATE.STOPPING: "stopping", STATE.STOPPED: "stopped" } - logger.debug(launch_item.name + " current state: " + state_str[state]) + logger.trace(launch_item.name + " current state: " + state_str[state]) # TODO: Check all windows for STEAM_GAME prop # If this was launched by Steam, try and detect if the game closed # so we can kill Steam gracefully if is_steam_app() and state == STATE.MISSING_WINDOW and is_ogui_managed: - logger.debug(launch_item.name + " is a Steam game and has no valid window ID. It may have closed.") + logger.trace(launch_item.name + " is a Steam game and has no valid window ID. It may have closed.") # Don't try closing Steam immediately. Wait a few more ticks before attempting # to close Steam. if steam_close_tries < 4: @@ -204,7 +204,7 @@ func get_all_window_ids() -> PackedInt32Array: var window_ids := PackedInt32Array() var pids := get_child_pids() pids.append(pid) - logger.debug(app_name + " found related PIDs: " + str(pids)) + logger.trace(app_name + " found related PIDs: " + str(pids)) for process_id in pids: var windows := Gamescope.get_window_ids(process_id, display_type) @@ -214,7 +214,7 @@ func get_all_window_ids() -> PackedInt32Array: if window in window_ids: continue window_ids.append(window) - logger.debug(app_name + " found related window IDs: " + str(window_ids)) + logger.trace(app_name + " found related window IDs: " + str(window_ids)) return window_ids @@ -227,19 +227,19 @@ func is_running() -> bool: return true # If that failed, check if reaper can get the status. - logger.debug("Reaper pid State: " + Reaper.get_pid_state(pid)) + logger.trace("Reaper pid State: " + Reaper.get_pid_state(pid)) if Reaper.get_pid_state(pid) in ["R (running)", "S (sleeping)"]: return true - logger.debug("Original process not running. Checking child PID's...") + logger.trace("Original process not running. Checking child PID's...") # If it's not running, let's check to make sure it's REALLY not running # and hasn't re-parented itself var children := get_child_pids() if children.size() > 0: var pids := Array(children) - logger.debug("{0} is not running, but lives on in {1}".format([pid, ",".join(pids)])) + logger.trace("{0} is not running, but lives on in {1}".format([pid, ",".join(pids)])) return true - logger.debug("Process " + str(pid) + " has died and no child PID's could be found.") + logger.trace("Process " + str(pid) + " has died and no child PID's could be found.") return false @@ -348,18 +348,18 @@ func _ensure_app_id() -> void: ## Returns whether or not the window id of the running app needs to be discovered func needs_window_id() -> bool: if window_id <= 0: - logger.debug(launch_item.name + " has a bad window ID: " + str(window_id)) + logger.trace(launch_item.name + " has a bad window ID: " + str(window_id)) return true var focusable_windows := Gamescope.get_focusable_windows() if not window_id in focusable_windows: - logger.debug(str(window_id) + " is not in the list of focusable windows") + logger.trace(str(window_id) + " is not in the list of focusable windows") return true # Check if the current window ID exists in the list of open windows var root_window := Gamescope.get_root_window_id(Gamescope.XWAYLAND.GAME) var all_windows := Gamescope.get_all_windows(root_window, Gamescope.XWAYLAND.GAME) if not window_id in all_windows: - logger.debug(str(window_id) + " is not in the list of all windows") + logger.trace(str(window_id) + " is not in the list of all windows") return true # If this is a Steam app, the only acceptable window will have its STEAM_GAME @@ -368,10 +368,10 @@ func needs_window_id() -> bool: var display_type := Gamescope.get_display_type(display) var steam_app_id := get_meta("steam_app_id") as int if not Gamescope.has_app_id(window_id, display_type): - logger.debug(str(window_id) + " does not have an app ID already set by Steam") + logger.trace(str(window_id) + " does not have an app ID already set by Steam") return true if Gamescope.get_app_id(window_id) != steam_app_id: - logger.debug(str(window_id) + " has an app ID but it does not match " + str(steam_app_id)) + logger.trace(str(window_id) + " has an app ID but it does not match " + str(steam_app_id)) return true # Track that a window has been successfully detected at least once. @@ -387,7 +387,7 @@ func _discover_window_id() -> int: # If there's a window directly associated with the PID, return that var win_id := get_window_id_from_pid() if win_id > 0: - logger.debug("Found window ID for {0} from PID: {1}".format([launch_item.name, window_id])) + logger.trace("Found window ID for {0} from PID: {1}".format([launch_item.name, window_id])) return win_id # Get all windows associated with the running app @@ -427,7 +427,7 @@ func find_steam() -> int: continue var process_name := pid_info["Name"] as String if process_name == "steam": - logger.debug("Found steam PID: " + str(child_pid)) + logger.trace("Found steam PID: " + str(child_pid)) return child_pid return -1 diff --git a/core/systems/state/state.gd b/core/systems/state/state.gd index 54a93e51..e76304cc 100644 --- a/core/systems/state/state.gd +++ b/core/systems/state/state.gd @@ -2,9 +2,38 @@ extends Resource class_name State +## Object for tracking the current state of a [StateMachine] +## +## A [State] represents some state of the application, such as the currently +## focused menu. Together with a [StateMachine], a [State] can be used to listen +## for signals whenever the state of the application changes. +## +## A [State] takes advantage of the fact that Godot resources are globally +## unique. This allows you to load a [State] resource from anywhere in the project +## to subscribe to state changes. + +## Emitted whenever a [StateMachine] has set this [State] as the current state. +## The "from" [State] will be populated with the last [State] the [StateMachine] +## was in. signal state_entered(from: State) +## Emitted whenever a [StateMachine] has left this [State]. The "to" [State] will +## be populated with the new current [State] of the [StateMachine]. signal state_exited(to: State) +## Emitted whenever a [StateMachine] has added this [State] to its state stack. +signal state_added +## Emitted whenever a [StateMachine] has removed this [State] from its state stack. signal state_removed +## Emitted whenever a [StateMachine] calls "refresh" on the current [State] +signal refreshed +## Optional human-readable name for the state @export var name: String +## DEPRECATED: Use 'set_meta()' or 'get_meta()' instead @export var data: Dictionary + + +func _to_string() -> String: + if not name.is_empty(): + return "".format({"name": name}) + return "".format({"rid": get_rid()}) + diff --git a/core/systems/state/state_machine.gd b/core/systems/state/state_machine.gd index a78424ef..49689563 100644 --- a/core/systems/state/state_machine.gd +++ b/core/systems/state/state_machine.gd @@ -1,15 +1,38 @@ -# https://www.reddit.com/r/godot/comments/vodp2a/comment/iegv4fs/?utm_source=reddit&utm_medium=web2x&context=3 -# The state machine takes advantage of the fact that resources are globally unique. -# This allows you to load a state machine resource from anywhere to subscribe to -# state changes. @icon("res://assets/editor-icons/state-machine.svg") extends Resource class_name StateMachine +## Manages the current [State] for some part of the application. +## +## A [StateMachine] is responsible for managing an arbitrary number of [State] +## objects. The [StateMachine] keeps a "stack" of states that can be set, pushed, +## popped, removed, or cleared, and will fire signals for each kind of change. +## This can allow the application to update and respond to different states of +## the [StateMachine]. +## +## Only one [State] is considered the "current" state in a [StateMachine]: the +## last state in the stack. A [State] will fire the "entered" signal whenever it +## becomes the "current" state, and fires the "exited" signal whenever it leaves +## the "current" state. +## +## The [StateMachine] takes advantage of the fact that Godot resources are globally +## unique. This allows you to load a [StateMachine] resource from anywhere in the +## project to subscribe to state changes. + +## Emitted whenever this [StateMachine] has changed states signal state_changed(from: State, to: State) +## Emitted whenever all states have been removed from the state machine +signal emptied +## Name of the state machine to use for logging purposes @export var logger_name := "StateMachine" +## The minimum number of states that this [StateMachine] must have. This parameter +## can be used to ensure that states cannot be popped below this number of states. @export var minimum_states: int = 1 +## If set, only the given [State] objects will be allowed to be added to the [StateMachine]. +## Will panic if an invalid state is added to the stack. If empty, all [State] +## objects will be allowed. +@export var allowed_states: Array[State] = [] var _state_stack: Array[State] = [] var logger := Log.get_logger(logger_name) @@ -25,16 +48,16 @@ func _on_state_changed(from: State, to: State) -> void: var to_str = "" if from != null: from_str = from.name - from.state_exited.emit(to) if to != null: to_str = to.name - to.state_entered.emit(from) if logger.get_name() != logger_name: logger = Log.get_logger(logger_name) logger.info("Switched from state {0} to {1}".format([from_str, to_str])) var state_names := PackedStringArray() for state in _state_stack: state_names.append(state.name) + if not to: + emptied.emit() logger.info("Stack: " + "-> ".join(state_names)) @@ -46,20 +69,42 @@ func current_state() -> State: return _state_stack[length-1] +## Emits the 'refreshed' signal on the current [State]. This can be used to +## trigger hand-offs between multiple state machines. +func refresh() -> void: + var current := current_state() + if not current: + return + current.refreshed.emit() + + ## Set state will set the entire state stack to the given array of states -func set_state(stack: Array[State]) -> void: - if null in stack: +func set_state(new_stack: Array[State]) -> void: + if null in new_stack: logger.warn("Invalid NULL state pushed.") return - var cur := current_state() - var old_stack := _state_stack - _state_stack = stack - for s in old_stack: - var state := s as State - if has_state(state): - continue + var states_added: Array[State] = [] + var states_removed: Array[State] = [] + for state: State in new_stack: + _ensure_state_allowed(state) + if not has_state(state): + states_added.push_back(state) + for state: State in _state_stack: + if not state in new_stack: + states_removed.push_back(state) + var last_current := current_state() + _state_stack = new_stack + var new_current := current_state() + if last_current != new_current: + if last_current: + last_current.state_exited.emit(new_current) + if new_current: + new_current.state_entered.emit(last_current) + state_changed.emit(last_current, new_current) + for state: State in states_removed: state.state_removed.emit() - state_changed.emit(cur, stack[-1]) + for state: State in states_added: + state.state_added.emit() ## Push state will push the given state to the top of the state stack. @@ -67,9 +112,18 @@ func push_state(state: State) -> void: if state == null: logger.warn("Invalid NULL state pushed.") return - var cur := current_state() + _ensure_state_allowed(state) + var current := current_state() + if state == current: + return + var is_new := not has_state(state) _push_unique(state) - state_changed.emit(cur, state) + if is_new: + state.state_added.emit() + if current: + current.state_exited.emit(state) + state.state_entered.emit(current) + state_changed.emit(current, state) ## Pushes the given state to the front of the stack @@ -77,17 +131,32 @@ func push_state_front(state: State) -> void: if state == null: logger.warn("Invalid NULL state pushed.") return - var cur = current_state() - _state_stack.push_front(state) - state_changed.emit(cur, current_state()) + _ensure_state_allowed(state) + var is_new := not has_state(state) + var last_current := current_state() + _push_front_unique(state) + var new_current := current_state() + if is_new: + state.state_added.emit() + if last_current != new_current: + if last_current: + last_current.state_exited.emit(new_current) + if new_current: + new_current.state_entered.emit(last_current) + state_changed.emit(last_current, new_current) ## Pop state will remove the last state from the stack and return it. func pop_state() -> State: if self.stack_length() > minimum_states: - var popped = _state_stack.pop_back() - var cur = current_state() - state_changed.emit(popped, cur) + var popped := _state_stack.pop_back() as State + var current := current_state() + if popped: + popped.state_exited.emit(current) + popped.state_removed.emit() + if current: + current.state_entered.emit(popped) + state_changed.emit(popped, current) return popped return current_state() @@ -97,29 +166,54 @@ func replace_state(state: State) -> void: if state == null: logger.warn("Invalid NULL state pushed.") return + _ensure_state_allowed(state) + var current := current_state() + if state == current: + return + var is_new := not has_state(state) var popped := _state_stack.pop_back() as State _push_unique(state) - if popped != null: + if is_new: + state.state_added.emit() + if popped: + popped.state_exited.emit(state) popped.state_removed.emit() + state.state_entered.emit(popped) state_changed.emit(popped, state) ## Removes all instances of the given state from the stack func remove_state(state: State) -> void: - var cur := current_state() + if not state: + return + if not has_state(state): + return + var last_current := current_state() var new_state_stack: Array[State] = [] - for i in range(0, len(_state_stack)): - var s := _state_stack[i] - if state != s: - new_state_stack.push_back(s) + for existing_state: State in _state_stack: + if state == existing_state: + continue + new_state_stack.push_back(existing_state) _state_stack = new_state_stack + if last_current == state: + state.state_exited.emit(current_state()) state.state_removed.emit() - state_changed.emit(cur, current_state()) + var new_current := current_state() + if last_current != new_current: + if new_current: + new_current.state_entered.emit(last_current) + state_changed.emit(last_current, new_current) ## Removes all states func clear_states() -> void: + var current := current_state() + if current: + current.state_exited.emit(null) + for state: State in _state_stack: + state.state_removed.emit() _state_stack.clear() + state_changed.emit(current, null) ## Returns the length of the state stack @@ -140,8 +234,29 @@ func has_state(state: State) -> bool: func _push_unique(state: State) -> void: - var i = _state_stack.find(state) + var i := _state_stack.find(state) if i >= 0: _state_stack.remove_at(i) _state_stack.push_back(state) + +func _push_front_unique(state: State) -> void: + var i := _state_stack.find(state) + if i >= 0: + _state_stack.remove_at(i) + _state_stack.push_front(state) + + +func _ensure_state_allowed(state: State) -> void: + if allowed_states.is_empty(): + return + if state in allowed_states: + return + var msg := "State '{name}' is not in allowed states for state machine '{sm}'. Allowed: {list}".format( + { + "name": str(state), + "sm": str(logger_name), + "list": str(allowed_states) + } + ) + assert(false, msg) diff --git a/core/systems/state/state_machine_test.gd b/core/systems/state/state_machine_test.gd index 2041e481..528bcbaf 100644 --- a/core/systems/state/state_machine_test.gd +++ b/core/systems/state/state_machine_test.gd @@ -9,17 +9,174 @@ func before_each() -> void: watch_signals(state_machine) +func test_set_state() -> void: + var state1 := State.new() + state1.name = "State1" + watch_signals(state1) + var state2 := State.new() + state2.name = "State2" + watch_signals(state2) + var state3 := State.new() + state3.name = "State3" + watch_signals(state3) + state_machine.set_state([state1, state2, state3]) + assert_eq(state_machine.stack_length(), 3, "should have three states in the stack") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [null, state3]) + assert_signal_emitted(state1, "state_added", "should have emitted state_added signal") + assert_signal_emitted(state2, "state_added", "should have emitted state_added signal") + assert_signal_emitted(state3, "state_added", "should have emitted state_added signal") + assert_signal_emitted_with_parameters(state3, "state_entered", [null]) + assert_signal_not_emitted(state2, "state_entered", "state2 should not have been entered") + assert_signal_not_emitted(state1, "state_entered", "state1 should not have been entered") + + state_machine.set_state([state2]) + assert_eq(state_machine.stack_length(), 1, "should have one state in the stack") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [state3, state2]) + assert_signal_emitted(state1, "state_removed", "should have emitted state_removed signal") + assert_signal_emitted(state3, "state_removed", "should have emitted state_removed signal") + assert_signal_emitted_with_parameters(state2, "state_entered", [state3]) + assert_signal_emitted_with_parameters(state3, "state_exited", [state2]) + + func test_push_state() -> void: - var state := State.new() - state_machine.push_state(state) + var state1 := State.new() + state1.name = "State1" + watch_signals(state1) + state_machine.push_state(state1) assert_eq(state_machine.stack_length(), 1, "should have one state in the stack") - assert_signal_emitted_with_parameters(state_machine, "state_changed", [null, state]) + assert_signal_emitted_with_parameters(state_machine, "state_changed", [null, state1]) + assert_signal_emitted(state1, "state_added", "should have emitted state_added signal") + assert_signal_emitted_with_parameters(state1, "state_entered", [null]) + + var state2 := State.new() + state2.name = "State2" + watch_signals(state2) + state_machine.push_state(state2) + assert_eq(state_machine.stack_length(), 2, "should have two states in the stack") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [state1, state2]) + assert_signal_emitted_with_parameters(state1, "state_exited", [state2]) + assert_signal_emitted(state2, "state_added", "should have emitted state_added signal") + assert_signal_emitted_with_parameters(state2, "state_entered", [state1]) + + +func test_push_state_front() -> void: + var state1 := State.new() + state1.name = "State1" + watch_signals(state1) + var state2 := State.new() + state2.name = "State2" + watch_signals(state2) + state_machine.push_state_front(state1) + state_machine.push_state_front(state2) + assert_eq(state_machine.stack_length(), 2, "should have two states in the stack") + assert_eq(state_machine.current_state(), state1, "state1 should be the current state") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [null, state1]) + assert_signal_emitted(state1, "state_added") + assert_signal_emitted(state2, "state_added") + assert_signal_not_emitted(state2, "state_entered", "state2 should not have been entered") + assert_signal_emitted_with_parameters(state1, "state_entered", [null]) func test_pop_state() -> void: var state := State.new() + state.name = "State1" state_machine.set_state([state]) + watch_signals(state) var popped := state_machine.pop_state() assert_signal_emitted_with_parameters(state_machine, "state_changed", [state, null]) + assert_signal_emitted_with_parameters(state, "state_exited", [null]) + assert_signal_emitted(state, "state_removed", "should have emitted state_removed signal") assert_eq(state_machine.stack_length(), 0, "should have no state in the stack") assert_same(state, popped, "popped state is original state") + + popped = state_machine.pop_state() + assert_eq(state_machine.stack_length(), 0, "should have no state in the stack") + assert_null(popped) + + state_machine.minimum_states = 1 + state_machine.push_state(state) + state_machine.pop_state() + assert_eq(state_machine.stack_length(), 1, "should have not have popped state") + + +func test_replace_state() -> void: + var state1 := State.new() + state1.name = "State1" + watch_signals(state1) + var state2 := State.new() + state2.name = "State2" + watch_signals(state2) + state_machine.replace_state(state1) + assert_eq(state_machine.stack_length(), 1, "should have one state in the stack") + assert_eq(state_machine.current_state(), state1, "state1 should be the current state") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [null, state1]) + assert_signal_emitted(state1, "state_added") + assert_signal_emitted_with_parameters(state1, "state_entered", [null]) + + state_machine.replace_state(state2) + assert_eq(state_machine.stack_length(), 1, "should have one state in the stack") + assert_eq(state_machine.current_state(), state2, "state2 should be the current state") + assert_signal_emitted_with_parameters(state_machine, "state_changed", [state1, state2]) + assert_signal_emitted(state2, "state_added") + assert_signal_emitted_with_parameters(state1, "state_exited", [state2]) + assert_signal_emitted_with_parameters(state2, "state_entered", [state1]) + + var state3 := State.new() + state3.name = "State3" + state_machine.replace_state(state3) + watch_signals(state3) + state_machine.replace_state(state3) + assert_signal_not_emitted(state3, "state_entered", "should not have re-entered state") + assert_signal_not_emitted(state3, "state_exited", "should not have exited state") + assert_signal_not_emitted(state3, "state_removed", "should not have removed state") + assert_signal_not_emitted(state3, "state_added", "should not have added state") + + +func test_remove_state() -> void: + var state1 := State.new() + state1.name = "State1" + watch_signals(state1) + var state2 := State.new() + state2.name = "State2" + watch_signals(state2) + var state3 := State.new() + state3.name = "State3" + watch_signals(state3) + state_machine.set_state([state1, state2, state3]) + assert_eq(state_machine.stack_length(), 3, "should have three states in the stack") + + state_machine.remove_state(state3) + assert_eq(state_machine.stack_length(), 2, "should have two states in the stack") + assert_eq(state_machine.current_state(), state2, "state2 should be the current state") + assert_signal_emitted_with_parameters(state2, "state_entered", [state3]) + assert_signal_emitted_with_parameters(state3, "state_exited", [state2]) + assert_signal_emitted(state3, "state_removed") + assert_signal_not_emitted(state1, "state_entered") + assert_signal_not_emitted(state1, "state_exited") + + state_machine.remove_state(state1) + assert_eq(state_machine.stack_length(), 1, "should have one state in the stack") + assert_eq(state_machine.current_state(), state2, "state2 should be the current state") + assert_signal_emitted(state1, "state_removed") + assert_signal_not_emitted(state1, "state_entered") + assert_signal_not_emitted(state1, "state_exited") + + +func test_clear_state() -> void: + var state1 := State.new() + state1.name = "State1" + var state2 := State.new() + state2.name = "State2" + var state3 := State.new() + state3.name = "State3" + + state_machine.set_state([state1, state2, state3]) + watch_signals(state1) + watch_signals(state2) + watch_signals(state3) + state_machine.clear_states() + assert_eq(state_machine.stack_length(), 0, "should have no states in the stack") + assert_signal_emitted(state1, "state_removed") + assert_signal_emitted(state2, "state_removed") + assert_signal_emitted(state3, "state_removed") + assert_signal_emitted_with_parameters(state3, "state_exited", [null]) diff --git a/core/systems/state/state_machine_watcher.gd b/core/systems/state/state_machine_watcher.gd new file mode 100644 index 00000000..fcfe3161 --- /dev/null +++ b/core/systems/state/state_machine_watcher.gd @@ -0,0 +1,41 @@ +@tool +@icon("res://assets/editor-icons/visible.svg") +extends Node +class_name StateMachineWatcher + +## Fires signals based on [StateMachine] changes +## +## The [StateMachineWatcher] fires signals based changes to the given +## [StateMachine]. This enables other nodes to react to state changes. + +## Emitted when the configured [StateMachine] changes states +signal state_changed(to: State, from: State) +## Emitted when the configured [StateMachine] no longer has any [State] objects +## in its stack +signal emptied + +## Fire signals when this state machine changes +@export var state_machine: StateMachine: + set(v): + state_machine = v + if Engine.is_editor_hint(): + update_configuration_warnings() + + +func _ready() -> void: + if not state_machine: + return + if Engine.is_editor_hint(): + return + var on_changed := func(from: State, to: State): + state_changed.emit(from, to) + state_machine.state_changed.connect(on_changed) + var on_emptied := func(): + emptied.emit() + state_machine.emptied.connect(on_emptied) + + +func _get_configuration_warnings() -> PackedStringArray: + if not state_machine: + return ["No state machine configured!"] + return [] diff --git a/core/systems/state/state_updater.gd b/core/systems/state/state_updater.gd index 1f330abc..09670971 100644 --- a/core/systems/state/state_updater.gd +++ b/core/systems/state/state_updater.gd @@ -15,13 +15,20 @@ const in_game := preload("res://assets/state/states/in_game.tres") ## Possible state actions to take enum ACTION { PUSH, ## Pushes the state on top of the state stack + PUSH_FRONT, ## Pushes the state to the beginning of the state stack POP, ## Removes the state at the top of the state stack REPLACE, ## Replaces the state at the top of the state stack SET, ## Removes all states and sets the given state + REFRESH, ## Calls the 'refresh' signal on the current state of the [StateMachine] + CLEAR, ## Clear all states from the [StateMachine] } ## The state machine instance to use for managing state changes -@export var state_machine: StateMachine +@export var state_machine: StateMachine: + set(v): + state_machine = v + if Engine.is_editor_hint(): + update_configuration_warnings() ## Signal on our parent to connect to. When this signal fires, the [StateUpdater] ## will change the state machine to the given state. var on_signal: String @@ -32,6 +39,9 @@ var on_signal: String func _ready() -> void: + # Don't run in the editor + if Engine.is_editor_hint(): + return notify_property_list_changed() get_parent().connect(on_signal, _on_signal) @@ -46,6 +56,8 @@ func _on_signal(metakey: String = "", metadata: Variant = null): match action: ACTION.PUSH: sm.push_state(state) + ACTION.PUSH_FRONT: + sm.push_state_front(state) ACTION.POP: sm.pop_state() ACTION.REPLACE: @@ -56,6 +68,10 @@ func _on_signal(metakey: String = "", metadata: Variant = null): if sm.has_state(in_game): states.push_front(in_game) sm.set_state(states) + ACTION.REFRESH: + sm.refresh() + ACTION.CLEAR: + sm.clear_states() # Customize editor properties that we expose. Here we dynamically look up @@ -85,3 +101,9 @@ func _get_property_list(): ) return properties + + +func _get_configuration_warnings() -> PackedStringArray: + if not state_machine: + return ["No state machine configured!"] + return [] diff --git a/core/systems/state/state_updater.tscn b/core/systems/state/state_updater.tscn index fdb20c19..1e06f1f2 100644 --- a/core/systems/state/state_updater.tscn +++ b/core/systems/state/state_updater.tscn @@ -3,5 +3,6 @@ [ext_resource type="Script" path="res://core/systems/state/state_updater.gd" id="1_anggw"] [node name="StateUpdater" type="Node"] +editor_description = "Update a state machine when a node signal fires" script = ExtResource("1_anggw") on_signal = "" diff --git a/core/systems/state/state_watcher.gd b/core/systems/state/state_watcher.gd index 093529d7..9f362041 100644 --- a/core/systems/state/state_watcher.gd +++ b/core/systems/state/state_watcher.gd @@ -10,6 +10,8 @@ class_name StateWatcher signal state_entered signal state_exited signal state_removed +signal state_added +signal state_refreshed ## Fire signals when this state is switched to @export var state: State @@ -17,12 +19,18 @@ signal state_removed func _ready() -> void: assert(state != null) - var on_entered := func(from: State): + var on_entered := func(_from: State): state_entered.emit() state.state_entered.connect(on_entered) - var on_exited := func(to: State): + var on_exited := func(_to: State): state_exited.emit() state.state_exited.connect(on_exited) var on_removed := func(): state_removed.emit() state.state_removed.connect(on_removed) + var on_added := func(): + state_added.emit() + state.state_added.connect(on_added) + var on_refresh := func(): + state_refreshed.emit() + state.refreshed.connect(on_refresh) diff --git a/core/systems/state/states_watcher.gd b/core/systems/state/states_watcher.gd new file mode 100644 index 00000000..4ead2259 --- /dev/null +++ b/core/systems/state/states_watcher.gd @@ -0,0 +1,40 @@ +@icon("res://assets/editor-icons/visible.svg") +extends Node +class_name StatesWatcher + +## Fires signals based on [State] changes to a [StateMachine] +## +## The [StatesWatcher] fires signals based on the current [State] of a +## [StateMachine]. This enables other nodes to react to state changes. + +signal state_entered +signal state_exited +signal state_removed +signal state_added +signal state_refreshed + +## Fire signals when this state is switched to +@export var states: Array[State] + + +func _ready() -> void: + for state in states: + var on_entered := func(from: State): + if from in states: + return + state_entered.emit() + state.state_entered.connect(on_entered) + var on_exited := func(to: State): + if to in states: + return + state_exited.emit() + state.state_exited.connect(on_exited) + var on_removed := func(): + state_removed.emit() + state.state_removed.connect(on_removed) + var on_added := func(): + state_added.emit() + state.state_added.connect(on_added) + var on_refresh := func(): + state_refreshed.emit() + state.refreshed.connect(on_refresh) diff --git a/core/systems/state/states_watcher.tscn b/core/systems/state/states_watcher.tscn new file mode 100644 index 00000000..054a9a60 --- /dev/null +++ b/core/systems/state/states_watcher.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://bfiia7vnbfw3s"] + +[ext_resource type="Script" path="res://core/systems/state/states_watcher.gd" id="1_ob7ue"] + +[node name="StatesWatcher" type="Node"] +script = ExtResource("1_ob7ue") diff --git a/core/systems/threading/shared_thread.gd b/core/systems/threading/shared_thread.gd index 1c508fb1..ffd820f1 100644 --- a/core/systems/threading/shared_thread.gd +++ b/core/systems/threading/shared_thread.gd @@ -55,6 +55,9 @@ func _init(options: int = Option.WATCHDOG_ENABLE as int) -> void: func _notification(what: int): if what == NOTIFICATION_PREDELETE: + if not self: + logger.error("Unable to stop thread, lost reference to self... Somehow...") + return stop() diff --git a/core/systems/user_interface/behavior_node.gd b/core/systems/user_interface/behavior_node.gd new file mode 100644 index 00000000..521c07e8 --- /dev/null +++ b/core/systems/user_interface/behavior_node.gd @@ -0,0 +1,72 @@ +@tool +@icon("res://assets/editor-icons/fluent--brain-circuit-24-filled.svg") +extends Node +class_name BehaviorNode + +## Base class for defining signal-based behavior +## +## A [BehaviorNode] is a node that follows a signaling pattern. These nodes can +## be added as a child of any node and can be configured to listen for and react +## to signals from its parent. This can allow developers to attach behaviors +## to nodes in the scene tree from the editor in a compositional way. + + +## The signal to connect to on this behavior's parent node. This behavior will +## execute whenever this signal is fired. +var on_signal: String: + set(v): + on_signal = v + if Engine.is_editor_hint(): + update_configuration_warnings() + +func _init() -> void: + ready.connect(_on_ready) + + +## Automatically connect to the configured parent signal on ready +func _on_ready() -> void: + notify_property_list_changed() + # Don't run in the editor + if Engine.is_editor_hint(): + return + if on_signal != "": + get_parent().connect(on_signal, _on_signal) + + +## Invoked whenever the configured parent signal fires. This should be overridden +## in a child class. +func _on_signal(arg1: Variant = null, arg2: Variant = null, arg3: Variant = null, arg4: Variant = null): + pass + + +# Customize editor properties that we expose. Here we dynamically look up +# the parent node's signals so we can display them in a list. +func _get_property_list(): + # By default, `on_signal` is not visible in the editor. + var property_usage := PROPERTY_USAGE_NO_EDITOR + + var parent_signals := [] + if get_parent() != null: + property_usage = PROPERTY_USAGE_DEFAULT + for sig in get_parent().get_signal_list(): + parent_signals.push_back(sig["name"]) + + var properties := [] + properties.append( + { + "name": "on_signal", + "type": TYPE_STRING, + "usage": property_usage, # See above assignment. + "hint": PROPERTY_HINT_ENUM, + "hint_string": ",".join(parent_signals) + } + ) + + return properties + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings := PackedStringArray() + if on_signal.is_empty(): + warnings.append("No parent signal selected!") + return warnings diff --git a/core/systems/user_interface/tab_setter.gd b/core/systems/user_interface/tab_setter.gd new file mode 100644 index 00000000..094514ad --- /dev/null +++ b/core/systems/user_interface/tab_setter.gd @@ -0,0 +1,32 @@ +@tool +extends BehaviorNode +class_name TabSetter + +## Set the current tab on a [TabContainer] in reaction to a parent signal +## +## This [BehaviorNode] can be added as a child to any node and configured to +## listen for a signal. When the parent signal fires, this behavior will set +## the current tab on the given target [TabContainer]. + +## The target [TabContainer] to update the current tab in response to a signal +@export var target: TabContainer: + set(v): + target = v + if Engine.is_editor_hint(): + update_configuration_warnings() +## The current tab number to switch to +@export var tab_number: int = 0 + + +## Set the current tab on the target node +func _on_signal(_arg1: Variant = null, _arg2: Variant = null, _arg3: Variant = null, _arg4: Variant = null): + if not target: + return + target.current_tab = tab_number + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings := super() + if not target: + warnings.append("No target tab container configured!") + return warnings diff --git a/core/systems/user_interface/text_setter.gd b/core/systems/user_interface/text_setter.gd new file mode 100644 index 00000000..5d3b627e --- /dev/null +++ b/core/systems/user_interface/text_setter.gd @@ -0,0 +1,33 @@ +@tool +@icon("res://assets/editor-icons/fluent--draw-text-24-filled.svg") +extends BehaviorNode +class_name TextSetter + +## Set text on the target [Label] node in reaction to a parent signal +## +## This [BehaviorNode] can be added as a child to any node and configured to +## listen for a signal. When the parent signal fires, this behavior will set +## the text on the given target [Label]. + +## The target [Label] to update with the given text when a parent signal fires +@export var target: Label: + set(v): + target = v + if Engine.is_editor_hint(): + update_configuration_warnings() +## The text to set on the target label +@export var text: String = "" + + +## Set the current tab on the target node +func _on_signal(_arg1: Variant = null, _arg2: Variant = null, _arg3: Variant = null, _arg4: Variant = null): + if not target: + return + target.text = tr(text) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings := super() + if not target: + warnings.append("No target label configured!") + return warnings diff --git a/core/systems/utility/theme_utils.gd b/core/systems/utility/theme_utils.gd new file mode 100644 index 00000000..b25b2d7c --- /dev/null +++ b/core/systems/utility/theme_utils.gd @@ -0,0 +1,19 @@ +extends RefCounted +class_name ThemeUtils + + +## Returns the effective theme of the node. This will visit each parent node +## until it finds a theme and returns it. If no theme is found, null will be +## returned. +static func get_effective_theme(node: Control) -> Theme: + if not node: + return null + var parent := node.get_parent() + if not parent is Control: + return null + + var parent_control := parent as Control + if parent_control.theme: + return parent_control.theme + + return get_effective_theme(parent_control) diff --git a/core/ui/card_ui/card_ui.gd b/core/ui/card_ui/card_ui.gd index acc7964e..44327f30 100644 --- a/core/ui/card_ui/card_ui.gd +++ b/core/ui/card_ui/card_ui.gd @@ -9,6 +9,10 @@ var input_plumber := load("res://core/systems/input/input_plumber.tres") as Inpu var state_machine := ( preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine ) +var menu_state_machine := preload("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine +var popup_state_machine := preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine +var menu_state := preload("res://assets/state/states/menu.tres") as State +var popup_state := preload("res://assets/state/states/popup.tres") as State var first_boot_state := preload("res://assets/state/states/first_boot_menu.tres") as State var home_state := preload("res://assets/state/states/home.tres") as State var in_game_state := preload("res://assets/state/states/in_game.tres") as State @@ -16,21 +20,21 @@ var osk_state := preload("res://assets/state/states/osk.tres") as State var power_state := preload("res://assets/state/states/power_menu.tres") as State var PID: int = OS.get_process_id() -var overlay_window_id = gamescope.get_window_id(PID, gamescope.XWAYLAND.OGUI) +var overlay_window_id := gamescope.get_window_id(PID, gamescope.XWAYLAND.OGUI) -@onready var panel := $%Panel -@onready var ui_container := $%MenuContent -@onready var boot_video := $%BootVideoPlayer -@onready var fade_transition := $%FadeTransitionPlayer -@onready var fade_texture := $%FadeTexture -@onready var power_timer := $%PowerTimer -@onready var settings_menu := $%SettingsMenu +@onready var panel := $%Panel as Panel +@onready var ui_container := $%MenuContent as MarginContainer +@onready var boot_video := $%BootVideoPlayer as VideoStreamPlayer +@onready var fade_transition := $%FadeTransitionPlayer as AnimationPlayer +@onready var fade_texture := $%FadeTexture as TextureRect +@onready var power_timer := $%PowerTimer as Timer +@onready var settings_menu := $%SettingsMenu as Control var logger = Log.get_logger("Main", Log.LEVEL.INFO) func _init() -> void: # Tell gamescope that we're an overlay - if overlay_window_id < 0: + if overlay_window_id <= 0: logger.error("Unable to detect Window ID. Overlay is not going to work!") logger.debug("Found primary window id: {0}".format([overlay_window_id])) _setup(overlay_window_id) @@ -38,7 +42,7 @@ func _init() -> void: # Lets us run as an overlay in gamescope func _setup(window_id: int) -> void: - if window_id < 0: + if window_id <= 0: logger.error("Unable to configure gamescope atoms") return # Pretend to be Steam @@ -68,8 +72,36 @@ func _ready() -> void: # Set the FPS limit Engine.max_fps = settings_manager.get_value("general", "max_fps", 60) as int - # Listen for global state changes - state_machine.state_changed.connect(_on_state_changed) + # Always push the menu state if we end up with an empty stack. + var on_states_emptied := func(): + state_machine.push_state.call_deferred(menu_state) + state_machine.emptied.connect(on_states_emptied) + + # Whenever the menu state is refreshed, refresh the menu state machine to + # re-grab focus. + var on_menu_refreshed := func(): + menu_state_machine.refresh() + menu_state.refreshed.connect(on_menu_refreshed) + + # Whenever the menu state is entered, refresh the menu state machine to + # re-grab focus + var on_menu_state_entered := func(_from: State): + menu_state_machine.refresh() + menu_state.state_entered.connect(on_menu_state_entered) + var on_menu_state_removed := func(): + menu_state_machine.clear_states() + menu_state.state_removed.connect(on_menu_state_removed) + var on_menu_states_empty := func(): + state_machine.remove_state(menu_state) + menu_state_machine.emptied.connect(on_menu_states_empty) + + # Whenever an popup state is pushed, update the global state + var on_popup_state_changed := func(_from: State, to: State): + if to: + state_machine.push_state(popup_state) + else: + state_machine.remove_state(popup_state) + popup_state_machine.state_changed.connect(on_popup_state_changed) # Show/hide the overlay when we enter/exit the in-game state in_game_state.state_entered.connect(_on_game_state_entered) @@ -88,21 +120,13 @@ func _ready() -> void: input_plumber.composite_device_changed.connect(on_device_changed) # Set the theme if one was set - var theme_path := settings_manager.get_value("general", "theme", "") as String - if theme_path == "": - logger.debug("No theme set. Using default theme.") - - var current_theme = get_theme() - if theme_path != "" && current_theme.resource_path != theme_path: - logger.debug("Setting theme to: " + theme_path) - var loaded_theme = load(theme_path) - if loaded_theme != null: - # TODO: This is a workaround, themes aren't properly set the first time. - call_deferred("set_theme", loaded_theme) - call_deferred("set_theme", current_theme) - call_deferred("set_theme", loaded_theme) - else: - logger.debug("Unable to load theme") + var theme_path := settings_manager.get_value("general", "theme", "res://assets/themes/card_ui-dracula.tres") as String + logger.debug("Setting theme to: " + theme_path) + var loaded_theme = load(theme_path) + if loaded_theme != null: + set_theme(loaded_theme) + else: + logger.debug("Unable to load theme") func _on_focus_changed(control: Control) -> void: @@ -110,12 +134,6 @@ func _on_focus_changed(control: Control) -> void: logger.debug("Focus changed to: " + control.get_parent().name + " | " + control.name) -# Always push the home state if we end up with an empty stack. -func _on_state_changed(_from: State, _to: State) -> void: - if state_machine.stack_length() == 0: - state_machine.push_state.call_deferred(home_state) - - ## Invoked when the in-game state was entered func _on_game_state_entered(_from: State) -> void: # Pass all gamepad input to the game @@ -131,7 +149,12 @@ func _on_game_state_entered(_from: State) -> void: # Ensure panel is invisible panel.visible = false for child in ui_container.get_children(): - child.visible = false + if not child is Control: + continue + (child as Control).visible = false + + # Clear all menu states + menu_state_machine.clear_states() ## Invoked when the in-game state is exited @@ -143,22 +166,30 @@ func _on_game_state_exited(to: State) -> void: #gamepad_manager.set_gamepads_profile(null) # Set gamescope input focus to on so the user can interact with the UI + if to == popup_state: + var current_popup := popup_state_machine.current_state() + if current_popup == osk_state: + return + if gamescope.set_input_focus(overlay_window_id, 1) != OK: logger.error("Unable to set STEAM_INPUT_FOCUS atom!") # If the in-game state still exists in the stack, set the blur state. if state_machine.has_state(in_game_state): panel.visible = false - if to != osk_state: - # Only blur if the focused GFX app is set - if gamescope.get_focused_app_gfx() != Gamescope.OVERLAY_GAME_ID: - _set_blur(gamescope.BLUR_MODE.ALWAYS) + # Only blur if the focused GFX app is set + var should_blur := settings_manager.get_value("display", "enable_overlay_blur", true) as bool + if should_blur and gamescope.get_focused_app_gfx() != Gamescope.OVERLAY_GAME_ID: + _set_blur(gamescope.BLUR_MODE.ALWAYS) + else: _on_game_state_removed() # Un-hide all UI elements for child in ui_container.get_children(): - child.visible = true + if not child is Control: + continue + (child as Control).visible = true ## Invoked when the in-game state is removed @@ -169,9 +200,11 @@ func _on_game_state_removed() -> void: # Un-hide the background panel panel.visible = true - # Reset the state stack if no home state exists - if not state_machine.has_state(home_state): - state_machine.set_state([home_state]) + # Reset the state stack if no menu state exists + if not state_machine.has_state(menu_state): + state_machine.set_state([menu_state]) + if not menu_state_machine.has_state(home_state): + menu_state_machine.set_state([home_state]) # Sets the blur mode in gamescope @@ -192,13 +225,16 @@ func _on_boot_video_player_finished() -> void: fade_transition.play("fade") boot_video.visible = false + # Set the initial global state + state_machine.push_state(menu_state) + # If this is the first boot, enter the first-boot menu state. Otherwise, # go to the home state. if settings_manager.get_value("general", "first_boot", true): - state_machine.push_state(first_boot_state) + menu_state_machine.push_state(first_boot_state) else: # Initialize the state machine with its initial state - state_machine.push_state(home_state) + menu_state_machine.push_state(home_state) ## Called when any unhandled input reaches the main node @@ -210,7 +246,7 @@ func _input(event: InputEvent) -> void: if event.is_action_pressed("ogui_power"): var open_power_menu := func(): logger.info("Power menu requested") - state_machine.push_state(power_state) + popup_state_machine.push_state(power_state) power_timer.timeout.connect(open_power_menu, CONNECT_ONE_SHOT) power_timer.start() return diff --git a/core/ui/card_ui/card_ui.tscn b/core/ui/card_ui/card_ui.tscn index 45a1044c..870a3dab 100644 --- a/core/ui/card_ui/card_ui.tscn +++ b/core/ui/card_ui/card_ui.tscn @@ -1,7 +1,6 @@ -[gd_scene load_steps=39 format=3 uid="uid://fhriwlhm0lcj"] +[gd_scene load_steps=38 format=3 uid="uid://fhriwlhm0lcj"] [ext_resource type="PackedScene" uid="uid://n83wlhmmsu3j" path="res://core/systems/input/input_manager.tscn" id="1_34t85"] -[ext_resource type="Theme" uid="uid://ehplgpp70vxa" path="res://assets/themes/card_ui-dracula.tres" id="1_ajgj2"] [ext_resource type="Script" path="res://core/ui/card_ui/card_ui.gd" id="1_f8851"] [ext_resource type="PackedScene" uid="uid://dlegwm7jqfe2i" path="res://core/systems/boxart/boxart_local.tscn" id="2_600i0"] [ext_resource type="PackedScene" uid="uid://ch6qw6obetalo" path="res://core/systems/library/library_desktop.tscn" id="3_68bes"] @@ -83,7 +82,6 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -theme = ExtResource("1_ajgj2") script = ExtResource("1_f8851") [node name="InputManager" parent="." instance=ExtResource("1_34t85")] @@ -176,7 +174,6 @@ visible = false layout_mode = 2 [node name="TopMargin" type="MarginContainer" parent="MenuContent"] -z_index = 20 layout_mode = 2 mouse_filter = 2 theme_override_constants/margin_left = 30 @@ -264,6 +261,8 @@ size_flags_vertical = 0 unique_name_in_owner = true visible = false layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 [node name="OnScreenKeyboard" parent="AlwaysVisibleContent" instance=ExtResource("18_462u5")] visible = false @@ -306,7 +305,7 @@ mouse_filter = 2 [node name="FadeTexture" type="TextureRect" parent="."] unique_name_in_owner = true -z_index = 20 +z_index = 21 layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -323,7 +322,7 @@ libraries = { [node name="BootVideoPlayer" type="VideoStreamPlayer" parent="."] unique_name_in_owner = true -z_index = 20 +z_index = 21 layout_mode = 1 anchors_preset = 8 anchor_left = 0.5 diff --git a/core/ui/card_ui/gamepad/gamepad_mapper.tscn b/core/ui/card_ui/gamepad/gamepad_mapper.tscn index 5abedf6e..a208cd53 100644 --- a/core/ui/card_ui/gamepad/gamepad_mapper.tscn +++ b/core/ui/card_ui/gamepad/gamepad_mapper.tscn @@ -1,12 +1,13 @@ -[gd_scene load_steps=22 format=3 uid="uid://b3o3wo40sfih1"] +[gd_scene load_steps=23 format=3 uid="uid://b3o3wo40sfih1"] [ext_resource type="Script" path="res://core/ui/card_ui/gamepad/gamepad_mapper.gd" id="1_alala"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_4osef"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_o3mis"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_2kcao"] [ext_resource type="Resource" uid="uid://c4er7pfmn7x50" path="res://assets/state/state_machines/gamepad_settings_state_machine.tres" id="3_wgp64"] [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_scwwv"] [ext_resource type="Resource" uid="uid://46cu324n427u" path="res://assets/state/states/gamepad_change_input.tres" id="4_sv30y"] [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="5_i6uqd"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="5_roi3c"] [ext_resource type="Texture2D" uid="uid://dyemqkvdtk43e" path="res://assets/images/gamepad/xbox/xbox_button_color_a.svg" id="8_5jaa6"] [ext_resource type="PackedScene" uid="uid://cgmb4kr2ec4ha" path="res://core/ui/components/tabs_header.tscn" id="8_okgql"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="9_an8os"] @@ -34,6 +35,16 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_alala") +[node name="InputWatcher" parent="." instance=ExtResource("2_o3mis")] +stop_propagation = true +process_input_mode = 1 +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_2kcao")] +state_machine = ExtResource("3_wgp64") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_4osef")] state = ExtResource("4_sv30y") @@ -47,11 +58,6 @@ on_signal = "state_entered" target = NodePath("../../VBoxContainer/TabContainer/Gamepad/MarginContainer/HBoxContainer/PanelContainer/MarginContainer/ScrollContainer/GamepadInputContainer/GamepadFocusGroup") on_signal = "state_entered" -[node name="BackInputHandler" parent="." instance=ExtResource("5_roi3c")] -state_machine = ExtResource("3_wgp64") -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("4_sv30y")]) -minimum_states = 0 - [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 anchors_preset = 15 diff --git a/core/ui/card_ui/gamepad/gamepad_settings.gd b/core/ui/card_ui/gamepad/gamepad_settings.gd index 177591ab..d5dbdab0 100644 --- a/core/ui/card_ui/gamepad/gamepad_settings.gd +++ b/core/ui/card_ui/gamepad/gamepad_settings.gd @@ -10,7 +10,7 @@ var in_game_state := load("res://assets/state/states/in_game.tres") as State var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager var notification_manager := load("res://core/global/notification_manager.tres") as NotificationManager var settings_manager := load("res://core/global/settings_manager.tres") as SettingsManager -var global_state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var global_state_machine := load("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine var state_machine := load("res://assets/state/state_machines/gamepad_settings_state_machine.tres") as StateMachine var input_plumber := load("res://core/systems/input/input_plumber.tres") as InputPlumber var input_icons := load("res://core/systems/input/input_icon_manager.tres") as InputIconManager @@ -428,6 +428,9 @@ func _update_mapping_elements() -> void: mappings = profile.get_mappings_by_source_capability(capability) else: var mapping := InputPlumberMapping.from_source_capability(capability) + if not mapping: + logger.error("Failed to create Mapping from Capability", capability) + continue var target_event = InputPlumberEvent.from_capability(capability) logger.debug("Adding", capability, "to mappings as:", mapping, " with event:", target_event) mapping.target_events = [target_event] diff --git a/core/ui/card_ui/gamepad/gamepad_settings.tscn b/core/ui/card_ui/gamepad/gamepad_settings.tscn index 039ec89f..8bd77f19 100644 --- a/core/ui/card_ui/gamepad/gamepad_settings.tscn +++ b/core/ui/card_ui/gamepad/gamepad_settings.tscn @@ -1,14 +1,16 @@ -[gd_scene load_steps=22 format=3 uid="uid://cwarv58ju0sow"] +[gd_scene load_steps=24 format=3 uid="uid://cwarv58ju0sow"] [ext_resource type="Script" path="res://core/ui/card_ui/gamepad/gamepad_settings.gd" id="1_o4hh5"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_3x6ad"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_ck60w"] [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="3_wyv83"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_yygaq"] [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_8f1hr"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="4_wxnal"] [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="5_7qogg"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="6_lxfig"] [ext_resource type="Resource" uid="uid://46cu324n427u" path="res://assets/state/states/gamepad_change_input.tres" id="6_oe11l"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="7_fyh3u"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="9_5ao07"] [ext_resource type="Texture2D" uid="uid://cfpaw2eck4ftr" path="res://assets/ui/icons/save-fill.svg" id="10_y71gk"] [ext_resource type="PackedScene" uid="uid://dbll03tbmw3ps" path="res://core/ui/components/card_mapping_button.tscn" id="11_unkgl"] [ext_resource type="Texture2D" uid="uid://dj1ohb74chydb" path="res://assets/ui/icons/round-delete-forever.svg" id="12_64hbv"] @@ -32,6 +34,16 @@ grow_vertical = 2 mouse_filter = 2 script = ExtResource("1_o4hh5") +[node name="InputWatcher" parent="." instance=ExtResource("2_ck60w")] +stop_propagation = true +process_input_mode = 1 +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_yygaq")] +state_machine = ExtResource("4_wxnal") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_3x6ad")] state = ExtResource("3_wyv83") @@ -45,9 +57,6 @@ on_signal = "state_entered" target = NodePath("../../MainContainer/TopLevelContainer/HBoxContainer/VBoxContainer/MainFocusGroup") on_signal = "state_entered" -[node name="BackInputHandler" parent="." instance=ExtResource("9_5ao07")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_wyv83")]) - [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 anchors_preset = 15 diff --git a/core/ui/card_ui/help/help_menu.tscn b/core/ui/card_ui/help/help_menu.tscn index 3f7aa1c7..1234be16 100644 --- a/core/ui/card_ui/help/help_menu.tscn +++ b/core/ui/card_ui/help/help_menu.tscn @@ -1,15 +1,20 @@ -[gd_scene load_steps=9 format=3 uid="uid://dj1fooc3gh13l"] +[gd_scene load_steps=13 format=3 uid="uid://dj1fooc3gh13l"] [ext_resource type="Script" path="res://core/ui/card_ui/help/help_menu.gd" id="1_7fti5"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_pli5u"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="3_effq8"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_cxu4x"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_10mqr"] [ext_resource type="Resource" uid="uid://db5gbdl3xgwlq" path="res://assets/state/states/help_menu.tres" id="3_hidel"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="4_x24i3"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_1uaoh"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="5_uocjd"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="5_wfsen"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="7_15bya"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="7_dlovl"] [ext_resource type="Script" path="res://core/ui/components/input_icon.gd" id="8_swg2f"] +[ext_resource type="PackedScene" uid="uid://ekhjpmat02f8" path="res://core/systems/effects/slide_effect.tscn" id="8_ut6gk"] [node name="HelpMenu" type="Control"] +z_index = 20 layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -18,11 +23,32 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_7fti5") -[node name="VisibilityManager" parent="." instance=ExtResource("2_pli5u")] +[node name="InputWatcher" parent="." instance=ExtResource("2_cxu4x")] +stop_propagation = true +process_input_mode = 1 +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_10mqr")] +state_machine = ExtResource("4_x24i3") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_1uaoh")] state = ExtResource("3_hidel") -[node name="BackInputHandler" parent="." instance=ExtResource("3_effq8")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_hidel")]) +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("7_dlovl")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" + +[node name="SlideEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("8_ut6gk")] +target = NodePath("../../MarginContainer") +slide_speed = 0.25 +direction = "up" +on_signal = "state_entered" +slide_out_signal = "state_exited" +on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 diff --git a/core/ui/card_ui/home/cardui_home.gd b/core/ui/card_ui/home/cardui_home.gd index 2884a53e..41ba2809 100644 --- a/core/ui/card_ui/home/cardui_home.gd +++ b/core/ui/card_ui/home/cardui_home.gd @@ -6,7 +6,8 @@ var LaunchManager := preload("res://core/global/launch_manager.tres") as LaunchM var InstallManager := preload("res://core/global/install_manager.tres") var BoxArtManager := load("res://core/global/boxart_manager.tres") as BoxArtManager var LibraryManager := load("res://core/global/library_manager.tres") as LibraryManager -var state_machine := preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var state_machine := preload("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine +var popup_state_machine := preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine var home_state := preload("res://assets/state/states/home.tres") as State var main_menu_state := preload("res://assets/state/states/main_menu.tres") as State var launcher_state := preload("res://assets/state/states/game_launcher.tres") as State @@ -19,13 +20,13 @@ var recent_apps: Array var tween: Tween var logger := Log.get_logger("HomeMenu", Log.LEVEL.INFO) -@onready var container: HBoxContainer = $%CardContainer -@onready var banner: TextureRect = $%BannerTexture -@onready var library_banner := $%LibraryBanner -@onready var player: AnimationPlayer = $%AnimationPlayer -@onready var scroll_container: ScrollContainer = $%ScrollContainer -@onready var library_deck: LibraryDeck = $%LibraryDeck -@onready var end_spacer := $%EndSpacer +@onready var container := $%CardContainer as HBoxContainer +@onready var banner := $%BannerTexture as TextureRect +@onready var library_banner := $%LibraryBanner as Control +@onready var player := $%AnimationPlayer as AnimationPlayer +@onready var scroll_container := $%ScrollContainer as ScrollContainer +@onready var library_deck := $%LibraryDeck as LibraryDeck +@onready var end_spacer := $%EndSpacer as Control # Called when the node enters the scene tree for the first time. @@ -33,6 +34,7 @@ func _ready() -> void: # Connect to state entered/exited signals home_state.state_entered.connect(_on_state_entered) home_state.state_exited.connect(_on_state_exited) + home_state.refreshed.connect(_on_state_refreshed) # Clear any example grid items for child in container.get_children(): @@ -54,8 +56,6 @@ func _ready() -> void: # Show the library banner when the library deck is focused var on_library_focused := func(): - if state_machine.current_state() != home_state: - return player.stop() player.play("fade_in") library_banner.visible = true @@ -83,7 +83,7 @@ func refresh() -> void: refresh.call_deferred() -func _on_state_entered(from: State) -> void: +func _on_state_entered(_from: State) -> void: set_process_input(true) library_banner.visible = false _grab_focus() @@ -93,17 +93,21 @@ func _on_state_exited(_to: State) -> void: set_process_input(false) +func _on_state_refreshed() -> void: + _grab_focus() + + # Push the main menu state when the back button is pressed func _input(event: InputEvent) -> void: - # Only handle back button pressed and when the guide button is not held - if not event.is_action_pressed("ogui_east") or Input.is_action_pressed("ogui_guide"): + # Only handle back button released and when the guide button is not held + if not event.is_action_released("ogui_east") or Input.is_action_pressed("ogui_guide"): return # Stop the event from propagating get_viewport().set_input_as_handled() # Push the main menu state when the back button is pressed - state_machine.push_state(main_menu_state) + popup_state_machine.push_state(main_menu_state) # When an install is queued, connect signals to show a progress bar on the library @@ -193,8 +197,6 @@ func _grab_focus() -> void: # Called when a card is focused func _on_card_focused(item: LibraryItem, card: Control) -> void: - if state_machine.current_state() != home_state: - return player.stop() player.play("fade_in") banner.texture = await BoxArtManager.get_boxart_or_placeholder(item, BoxArtProvider.LAYOUT.BANNER) diff --git a/core/ui/card_ui/home/cardui_home.tscn b/core/ui/card_ui/home/cardui_home.tscn index be4aeb2a..eea547d8 100644 --- a/core/ui/card_ui/home/cardui_home.tscn +++ b/core/ui/card_ui/home/cardui_home.tscn @@ -1,21 +1,19 @@ -[gd_scene load_steps=20 format=3 uid="uid://o70x5igrlq30"] +[gd_scene load_steps=18 format=3 uid="uid://o70x5igrlq30"] [ext_resource type="Script" path="res://core/ui/card_ui/home/cardui_home.gd" id="1_a4a3j"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_u18ot"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_d1wwx"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_eo81q"] [ext_resource type="Resource" uid="uid://oaavalv0wcoa" path="res://assets/state/states/home.tres" id="3_x1rvr"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="4_d0dnr"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="4_mrwia"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_pbfsf"] [ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="5_gbh30"] -[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="6_jlesr"] -[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="7_ao7st"] -[ext_resource type="Resource" uid="uid://bfoequ6xb7csn" path="res://assets/state/states/quick_bar_button_submenu.tres" id="8_dx6pe"] -[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="9_kvuqp"] [ext_resource type="Texture2D" uid="uid://d1mksukdkqorr" path="res://assets/images/placeholder-grid-banner.png" id="10_mmfgs"] [ext_resource type="PackedScene" uid="uid://rosd00fxjrs8" path="res://core/ui/components/library_banner.tscn" id="11_16gcd"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="12_h5dxg"] [ext_resource type="PackedScene" uid="uid://bkhrcemal7uxo" path="res://core/ui/components/card.tscn" id="12_m30ge"] [ext_resource type="PackedScene" uid="uid://crsu0vpicq0vh" path="res://core/ui/components/library_deck.tscn" id="13_rxwf5"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="14_8pw3l"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="14_wdgux"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="15_484n7"] [ext_resource type="Resource" uid="uid://boq501bigx8kl" path="res://assets/state/states/library.tres" id="16_6odlo"] [sub_resource type="Animation" id="Animation_638a6"] @@ -48,9 +46,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_a4a3j") -[node name="VisibilityManager" parent="." instance=ExtResource("2_u18ot")] +[node name="InputWatcher" parent="." instance=ExtResource("2_d1wwx")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("14_wdgux")] +state_machine = ExtResource("4_mrwia") +state = ExtResource("5_gbh30") +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("2_eo81q")] state = ExtResource("3_x1rvr") -visible_during = Array[Resource]([ExtResource("4_d0dnr"), ExtResource("5_gbh30"), ExtResource("6_jlesr"), ExtResource("7_ao7st"), ExtResource("8_dx6pe"), ExtResource("9_kvuqp")]) + +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_pbfsf")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -137,7 +149,7 @@ unique_name_in_owner = true layout_mode = 2 [node name="StateUpdater" parent="VBoxContainer/PanelContainer/MarginContainer/ScrollContainer/CardContainer/LibraryDeck" instance=ExtResource("14_wdgux")] -state_machine = ExtResource("15_484n7") +state_machine = ExtResource("14_8pw3l") state = ExtResource("16_6odlo") on_signal = "button_up" diff --git a/core/ui/card_ui/launch/game_launch_menu.tscn b/core/ui/card_ui/launch/game_launch_menu.tscn index 44c01073..430a0b74 100644 --- a/core/ui/card_ui/launch/game_launch_menu.tscn +++ b/core/ui/card_ui/launch/game_launch_menu.tscn @@ -1,23 +1,18 @@ -[gd_scene load_steps=25 format=3 uid="uid://bcdk1lj6enq3l"] +[gd_scene load_steps=20 format=3 uid="uid://bcdk1lj6enq3l"] [ext_resource type="Script" path="res://core/ui/card_ui/launch/game_launch_menu.gd" id="1_u3ehs"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_135m3"] [ext_resource type="Texture2D" uid="uid://d1mksukdkqorr" path="res://assets/images/placeholder-grid-banner.png" id="2_oae7b"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_slsfk"] [ext_resource type="PackedScene" uid="uid://2tdbi1v6qb6h" path="res://core/ui/components/loading02.tscn" id="3_dp3a3"] [ext_resource type="Resource" uid="uid://dav2b3n384cso" path="res://assets/state/states/game_launcher.tres" id="3_w7th1"] -[ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="4_le731"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="4_aqvfw"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_4ja2v"] [ext_resource type="Texture2D" uid="uid://bec6fhiswf6ve" path="res://assets/ui/icons/gamepad-bold.svg" id="5_ewj68"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="5_tdidy"] -[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="6_gnrnf"] -[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="7_qt0bt"] -[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="8_3e46i"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="9_hnl5c"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="9_k6q8g"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="7_ch3qu"] [ext_resource type="Texture2D" uid="uid://d2ipfga47yjju" path="res://assets/images/empty-grid-logo.png" id="12_01uv6"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="14_3h1st"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="15_f3ktw"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="15_lat8h"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="16_m8g5y"] [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="17_7ydn0"] [ext_resource type="Resource" uid="uid://3vw3bk76d88w" path="res://assets/state/states/game_settings.tres" id="19_b21vy"] [ext_resource type="Texture2D" uid="uid://dj1ohb74chydb" path="res://assets/ui/icons/round-delete-forever.svg" id="21_agq5k"] @@ -58,15 +53,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_u3ehs") -[node name="VisibilityManager" parent="." instance=ExtResource("2_135m3")] -state = ExtResource("3_w7th1") -visible_during = Array[Resource]([ExtResource("4_le731"), ExtResource("5_tdidy"), ExtResource("6_gnrnf"), ExtResource("7_qt0bt"), ExtResource("8_3e46i")]) +[node name="InputWatcher" parent="." instance=ExtResource("2_slsfk")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("15_lat8h")] +state_machine = ExtResource("4_aqvfw") +action = 2 +on_signal = "input_released" -[node name="TransitionFadeIn" parent="VisibilityManager" instance=ExtResource("9_k6q8g")] -root_node = NodePath("../..") +[node name="StateWatcher" parent="." instance=ExtResource("5_4ja2v")] +state = ExtResource("3_w7th1") -[node name="BackInputHandler" parent="." instance=ExtResource("9_hnl5c")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_w7th1")]) +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("7_ch3qu")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -162,11 +165,12 @@ layout_mode = 2 texture = ExtResource("5_ewj68") [node name="StateUpdater" parent="CenterContainer/HBoxContainer/ExtraMenu/MarginContainer/HBoxContainer/GamepadButton" instance=ExtResource("15_lat8h")] -state_machine = ExtResource("16_m8g5y") +state_machine = ExtResource("4_aqvfw") state = ExtResource("17_7ydn0") on_signal = "player_button_up" [node name="VSeparator" type="VSeparator" parent="CenterContainer/HBoxContainer/ExtraMenu/MarginContainer/HBoxContainer"] +visible = false custom_minimum_size = Vector2(0, 24) layout_mode = 2 size_flags_vertical = 4 @@ -177,7 +181,7 @@ custom_minimum_size = Vector2(28, 28) layout_mode = 2 [node name="StateUpdater" parent="CenterContainer/HBoxContainer/ExtraMenu/MarginContainer/HBoxContainer/SettingsButton" instance=ExtResource("15_lat8h")] -state_machine = ExtResource("16_m8g5y") +state_machine = ExtResource("4_aqvfw") state = ExtResource("19_b21vy") on_signal = "button_up" @@ -190,6 +194,7 @@ layout_mode = 2 layout_mode = 2 [node name="VSeparator" type="VSeparator" parent="CenterContainer/HBoxContainer/ExtraMenu/MarginContainer/HBoxContainer/DeleteContainer/HBoxContainer"] +visible = false custom_minimum_size = Vector2(0, 24) layout_mode = 2 size_flags_vertical = 4 diff --git a/core/ui/card_ui/launch/game_settings.tscn b/core/ui/card_ui/launch/game_settings.tscn index 97e6319d..1e03f2d0 100644 --- a/core/ui/card_ui/launch/game_settings.tscn +++ b/core/ui/card_ui/launch/game_settings.tscn @@ -1,14 +1,12 @@ -[gd_scene load_steps=26 format=3 uid="uid://58qlqqbh58im"] +[gd_scene load_steps=24 format=3 uid="uid://58qlqqbh58im"] [ext_resource type="Script" path="res://core/ui/card_ui/launch/game_settings.gd" id="1_vrr6s"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_1eqgx"] [ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_pga6u"] [ext_resource type="Resource" uid="uid://3vw3bk76d88w" path="res://assets/state/states/game_settings.tres" id="3_s80bx"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="4_qjhtj"] -[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="5_t4x4x"] -[ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="6_c6jr8"] -[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="7_7cc3x"] -[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="8_j5oy4"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="9_e1xsr"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="4_5bv80"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_0v30m"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="7_5qmye"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="11_u6frn"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="12_86g2h"] [ext_resource type="Resource" uid="uid://cc6i4i264dmqd" path="res://core/ui/card_ui/launch/game_settings_focus.tres" id="12_e0uun"] @@ -35,12 +33,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_vrr6s") -[node name="VisibilityManager" parent="." instance=ExtResource("2_pga6u")] +[node name="InputWatcher" parent="." instance=ExtResource("2_1eqgx")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("15_lmmqq")] +state_machine = ExtResource("4_5bv80") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_0v30m")] state = ExtResource("3_s80bx") -visible_during = Array[Resource]([ExtResource("4_qjhtj"), ExtResource("5_t4x4x"), ExtResource("6_c6jr8"), ExtResource("7_7cc3x"), ExtResource("8_j5oy4")]) -[node name="BackInputHandler" parent="." instance=ExtResource("9_e1xsr")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_s80bx")]) +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("7_5qmye")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 diff --git a/core/ui/card_ui/library/library_menu.gd b/core/ui/card_ui/library/library_menu.gd index 8021998d..b032739c 100644 --- a/core/ui/card_ui/library/library_menu.gd +++ b/core/ui/card_ui/library/library_menu.gd @@ -5,7 +5,7 @@ signal refresh_completed var settings_manager := load("res://core/global/settings_manager.tres") as SettingsManager var library_manager := load("res://core/global/library_manager.tres") as LibraryManager var install_manager := load("res://core/global/install_manager.tres") as InstallManager -var state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var menu_state_machine := load("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine var library_state := load("res://assets/state/states/library.tres") as State var launcher_state := load("res://assets/state/states/game_launcher.tres") as State var osk_state := load("res://assets/state/states/osk.tres") as State @@ -35,6 +35,9 @@ func _ready() -> void: # Connect to state entered signals library_state.state_entered.connect(_on_state_entered) + var on_refresh := func(): + _on_state_entered(null) + library_state.refreshed.connect(on_refresh) # Listen for tab container changes tabs_state.tab_changed.connect(_on_tab_container_tab_changed) @@ -87,8 +90,6 @@ func _on_state_entered(_from: State): # Handle searches func _on_search(text: String): - if not state_machine.current_state() in [library_state, osk_state]: - return text = text.to_lower() # If the text is empty, set all items to visible @@ -157,7 +158,7 @@ func _build_card(item: LibraryItem) -> GameCard: # Listen for button presses and pass the library item with the state var on_button_up := func(): launcher_state.data = {"item": item} - state_machine.push_state(launcher_state) + menu_state_machine.push_state(launcher_state) card.button_up.connect(on_button_up) return card diff --git a/core/ui/card_ui/library/library_menu.tscn b/core/ui/card_ui/library/library_menu.tscn index 8063421d..71934b98 100644 --- a/core/ui/card_ui/library/library_menu.tscn +++ b/core/ui/card_ui/library/library_menu.tscn @@ -1,15 +1,13 @@ -[gd_scene load_steps=14 format=3 uid="uid://uqkwpeq7f1o"] +[gd_scene load_steps=12 format=3 uid="uid://uqkwpeq7f1o"] [ext_resource type="Script" path="res://core/ui/card_ui/library/library_menu.gd" id="1_7invr"] [ext_resource type="Resource" uid="uid://cjda3nse6s3n1" path="res://core/ui/card_ui/library/library_tabs_state.tres" id="2_4hmwr"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="3_2qh2a"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="3_7wtey"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="3_l8ff2"] [ext_resource type="Resource" uid="uid://boq501bigx8kl" path="res://assets/state/states/library.tres" id="4_dffbv"] -[ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="5_i24wn"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="6_gwkmd"] -[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="7_oigb4"] -[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="8_s5vy4"] -[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="9_swp14"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="10_brww5"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="4_qje1c"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="5_ctjfn"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="5_nj5st"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="11_27umd"] [ext_resource type="PackedScene" uid="uid://bkhrcemal7uxo" path="res://core/ui/components/card.tscn" id="11_bj8cj"] @@ -26,12 +24,23 @@ grow_vertical = 2 script = ExtResource("1_7invr") tabs_state = ExtResource("2_4hmwr") -[node name="VisibilityManager" parent="." instance=ExtResource("3_2qh2a")] +[node name="InputWatcher" parent="." instance=ExtResource("3_l8ff2")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("4_qje1c")] +state_machine = ExtResource("5_nj5st") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("3_7wtey")] state = ExtResource("4_dffbv") -visible_during = Array[Resource]([ExtResource("5_i24wn"), ExtResource("6_gwkmd"), ExtResource("7_oigb4"), ExtResource("8_s5vy4"), ExtResource("9_swp14")]) -[node name="BackInputHandler" parent="." instance=ExtResource("10_brww5")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("4_dffbv")]) +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("5_ctjfn")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="TabContainer" type="TabContainer" parent="."] unique_name_in_owner = true diff --git a/core/ui/card_ui/main-menu/main_menu.tscn b/core/ui/card_ui/main-menu/main_menu.tscn index adddd5f6..62ca824c 100644 --- a/core/ui/card_ui/main-menu/main_menu.tscn +++ b/core/ui/card_ui/main-menu/main_menu.tscn @@ -1,14 +1,14 @@ -[gd_scene load_steps=20 format=3 uid="uid://jfacx7uys32r"] +[gd_scene load_steps=23 format=3 uid="uid://jfacx7uys32r"] [ext_resource type="Script" path="res://core/ui/card_ui/main-menu/main_menu.gd" id="1_3looj"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_5xlnh"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="2_jmie1"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_bcynd"] [ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="3_3xh32"] [ext_resource type="PackedScene" uid="uid://ekhjpmat02f8" path="res://core/systems/effects/slide_effect.tscn" id="4_hfk5i"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="4_maija"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="4_w4cpu"] [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="5_88bts"] +[ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="6_r2ip5"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="6_ris1l"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="7_n0655"] [ext_resource type="Resource" uid="uid://boq501bigx8kl" path="res://assets/state/states/library.tres" id="8_iv515"] [ext_resource type="PackedScene" uid="uid://4t4jt26o2fbr" path="res://core/ui/card_ui/navigation/system_container.tscn" id="8_p8fdd"] [ext_resource type="Resource" uid="uid://ba34axjjpixwc" path="res://assets/state/states/store.tres" id="9_2jho2"] @@ -17,8 +17,11 @@ [ext_resource type="Resource" uid="uid://bytra6gw0dr4c" path="res://core/ui/card_ui/main-menu/main_menu_focus.tres" id="10_v2rc1"] [ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="11_e52bm"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="11_obt01"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="14_8hmym"] [ext_resource type="Resource" uid="uid://oaavalv0wcoa" path="res://assets/state/states/home.tres" id="14_lxab3"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="19_b6ano"] +[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="19_vkv5c"] +[ext_resource type="Resource" uid="uid://cv3vduo0ojk1u" path="res://assets/state/states/menu.tres" id="20_vym73"] [node name="MainMenu" type="Control"] z_index = 20 @@ -28,6 +31,15 @@ anchor_bottom = 1.0 grow_vertical = 2 script = ExtResource("1_3looj") +[node name="InputWatcher" parent="." instance=ExtResource("2_bcynd")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("4_w4cpu") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_5xlnh")] state = ExtResource("3_3xh32") @@ -46,8 +58,9 @@ on_signal = "state_entered" slide_out_signal = "state_exited" on_signal = "state_entered" -[node name="BackInputHandler" parent="." instance=ExtResource("2_jmie1")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_3xh32"), ExtResource("4_maija")]) +[node name="FocusGroupSetter" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("6_r2ip5")] +target = NodePath("../../PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/FocusGroup") +on_signal = "state_entered" [node name="PanelContainer" type="PanelContainer" parent="."] custom_minimum_size = Vector2(280, 0) @@ -105,9 +118,19 @@ text = "Home" click_focuses = false [node name="StateUpdater" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/HomeButton" instance=ExtResource("6_ris1l")] -state_machine = ExtResource("7_n0655") +state_machine = ExtResource("14_8hmym") state = ExtResource("14_lxab3") -action = 3 +action = 4 +on_signal = "button_up" + +[node name="StateUpdater2" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/HomeButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("19_vkv5c") +state = ExtResource("20_vym73") +on_signal = "button_up" + +[node name="ClearOverlay" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/HomeButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("4_w4cpu") +action = 6 on_signal = "button_up" [node name="LibraryButton" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer" instance=ExtResource("11_obt01")] @@ -116,9 +139,18 @@ text = "Library" click_focuses = false [node name="StateUpdater" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/LibraryButton" instance=ExtResource("6_ris1l")] -state_machine = ExtResource("7_n0655") +state_machine = ExtResource("14_8hmym") state = ExtResource("8_iv515") -action = 2 +on_signal = "button_up" + +[node name="StateUpdater2" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/LibraryButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("19_vkv5c") +state = ExtResource("20_vym73") +on_signal = "button_up" + +[node name="ClearOverlay" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/LibraryButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("4_w4cpu") +action = 6 on_signal = "button_up" [node name="StoreButton" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer" instance=ExtResource("11_obt01")] @@ -128,9 +160,18 @@ text = "Store" click_focuses = false [node name="StateUpdater" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/StoreButton" instance=ExtResource("6_ris1l")] -state_machine = ExtResource("7_n0655") +state_machine = ExtResource("14_8hmym") state = ExtResource("9_2jho2") -action = 2 +on_signal = "button_up" + +[node name="StateUpdater2" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/StoreButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("19_vkv5c") +state = ExtResource("20_vym73") +on_signal = "button_up" + +[node name="ClearOverlay" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/StoreButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("4_w4cpu") +action = 6 on_signal = "button_up" [node name="SettingsButton" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer" instance=ExtResource("11_obt01")] @@ -139,9 +180,18 @@ text = "Settings" click_focuses = false [node name="StateUpdater" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/SettingsButton" instance=ExtResource("6_ris1l")] -state_machine = ExtResource("7_n0655") +state_machine = ExtResource("14_8hmym") state = ExtResource("10_irj46") -action = 2 +on_signal = "button_up" + +[node name="StateUpdater2" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/SettingsButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("19_vkv5c") +state = ExtResource("20_vym73") +on_signal = "button_up" + +[node name="ClearOverlay" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/SettingsButton" instance=ExtResource("6_ris1l")] +state_machine = ExtResource("4_w4cpu") +action = 6 on_signal = "button_up" [node name="PowerButton" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer" instance=ExtResource("11_obt01")] @@ -150,7 +200,7 @@ text = "Power" click_focuses = false [node name="StateUpdater" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/MarginContainer/ButtonContainer/PowerButton" instance=ExtResource("6_ris1l")] -state_machine = ExtResource("7_n0655") +state_machine = ExtResource("4_w4cpu") state = ExtResource("11_e52bm") on_signal = "button_up" diff --git a/core/ui/card_ui/navigation/running_game_card.gd b/core/ui/card_ui/navigation/running_game_card.gd index 4400ada4..e5302252 100644 --- a/core/ui/card_ui/navigation/running_game_card.gd +++ b/core/ui/card_ui/navigation/running_game_card.gd @@ -16,17 +16,26 @@ var launch_manager := load("res://core/global/launch_manager.tres") as LaunchMan var boxart_manager := load("res://core/global/boxart_manager.tres") as BoxArtManager var library_manager := load("res://core/global/library_manager.tres") as LibraryManager var state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var menu_state_machine := load("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine +var popup_state_machine := load("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine var in_game_state := load("res://assets/state/states/in_game.tres") as State var button_scene := load("res://core/ui/components/card_button.tscn") as PackedScene @export_category("Card") -@export var is_toggled := false +@export var is_toggled := false: + set(v): + is_toggled = v + if is_toggled: + toggled_on.emit() + else: + toggled_off.emit() + toggled.emit(is_toggled) @onready var content_container := $%ContentContainer @onready var game_logo := $%GameLogo @onready var game_label := $%GameLabel @onready var resume_button := $%ResumeButton as CardButton -@onready var suspend_button := $%SuspendButton as CardButton +@onready var pause_button := $%PauseButton as CardButton @onready var exit_button := $%ExitButton as CardButton @onready var highlight_rect := $%HighlightTextureRect @onready var focus_group := $%FocusGroup as FocusGroup @@ -39,11 +48,18 @@ var logger := Log.get_logger("RunningGameCard", Log.LEVEL.INFO) # Called when the node enters the scene tree for the first time. func _ready() -> void: + if Engine.is_editor_hint(): + return + focus_entered.connect(_on_focus) focus_exited.connect(_on_unfocus) - pressed.connect(_on_pressed) + button_up.connect(_on_button_up) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() # Auto-close when visibility is lost var on_visibility_changed := func(): @@ -55,19 +71,20 @@ func _ready() -> void: # Connect sub-buttons var on_resume_game := func(): state_machine.set_state([in_game_state]) + menu_state_machine.clear_states() + popup_state_machine.clear_states() resume_button.pressed.connect(on_resume_game) var on_exit_game := func(): - # TODO: Handle this better + # TODO: Handle "this" better? launch_manager.stop(running_app) - state_machine.pop_state() exit_button.pressed.connect(on_exit_game) var on_suspend := func(): running_app.suspend(not running_app.is_suspended) if running_app.is_suspended: - suspend_button.text = "Continue" + pause_button.text = "Unpause" else: - suspend_button.text = "Suspend" - suspend_button.pressed.connect(on_suspend) + pause_button.text = "Pause" + pause_button.pressed.connect(on_suspend) func _on_theme_changed() -> void: @@ -134,7 +151,7 @@ func _on_focus() -> void: # the user has focused outside the card, and we should shrink to hide the # content if is_toggled: - _on_pressed() + _on_button_up() func _on_unfocus() -> void: @@ -148,7 +165,7 @@ func _on_unfocus() -> void: return -func _on_pressed() -> void: +func _on_button_up() -> void: is_toggled = !is_toggled if is_toggled: toggled_on.emit() @@ -159,9 +176,34 @@ func _on_pressed() -> void: func _gui_input(event: InputEvent) -> void: + var is_valid := [event is InputEventAction, event is InputEventKey] + if not true in is_valid: + return if event.is_action("ui_accept"): if event.is_pressed(): button_down.emit() pressed.emit() else: button_up.emit() + + +func _input(event: InputEvent) -> void: + if not is_toggled: + return + if not event.is_action("ogui_east"): + return + if not event.is_released(): + return + + # Only process input if a child node has focus + #var focus_owner := get_viewport().gui_get_focus_owner() + #if not self.is_ancestor_of(focus_owner): + # return + + # Handle back input + is_toggled = false + + # Stop the event from propagating + #logger.debug("Consuming input event '{action}' for node {n}".format({"action": action, "n": str(self)})) + get_viewport().set_input_as_handled() + self.grab_focus() diff --git a/core/ui/card_ui/navigation/running_game_card.tscn b/core/ui/card_ui/navigation/running_game_card.tscn index da72739b..279c8c8a 100644 --- a/core/ui/card_ui/navigation/running_game_card.tscn +++ b/core/ui/card_ui/navigation/running_game_card.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=17 format=3 uid="uid://dlouq0b0bnm41"] +[gd_scene load_steps=19 format=3 uid="uid://dlouq0b0bnm41"] [ext_resource type="Texture2D" uid="uid://d2ipfga47yjju" path="res://assets/images/empty-grid-logo.png" id="1_4m4go"] [ext_resource type="Script" path="res://core/ui/card_ui/navigation/running_game_card.gd" id="1_vgpef"] @@ -10,12 +10,14 @@ [ext_resource type="PackedScene" uid="uid://hbgypx7p3gyw" path="res://core/systems/effects/grower_effect.tscn" id="4_f5kjd"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="5_smmwr"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="6_s452c"] -[ext_resource type="Resource" uid="uid://bytra6gw0dr4c" path="res://core/ui/card_ui/main-menu/main_menu_focus.tres" id="6_xmlue"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="7_yrgt0"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="8_ixs6g"] [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="8_nyd1y"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="13_aslkr"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="15_70rxc"] +[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="15_p4kr0"] +[ext_resource type="Resource" uid="uid://cv3vduo0ojk1u" path="res://assets/state/states/menu.tres" id="16_vmedb"] -[sub_resource type="Image" id="Image_blvbp"] +[sub_resource type="Image" id="Image_2yqt6"] data = { "data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), "format": "RGBA8", @@ -25,7 +27,7 @@ data = { } [sub_resource type="ImageTexture" id="ImageTexture_osglk"] -image = SubResource("Image_blvbp") +image = SubResource("Image_2yqt6") [node name="RunningGameCard" type="PanelContainer"] anchors_preset = 10 @@ -143,7 +145,6 @@ size_flags_vertical = 3 [node name="FocusGroup" parent="MarginContainer/VBoxContainer/ContentContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("5_smmwr")] unique_name_in_owner = true current_focus = NodePath("../ResumeButton") -focus_stack = ExtResource("6_xmlue") [node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer/ContentContainer"] layout_mode = 2 @@ -151,23 +152,38 @@ layout_mode = 2 [node name="ResumeButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] unique_name_in_owner = true layout_mode = 2 -text = "Resume" +text = "Return" -[node name="SuspendButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] +[node name="PauseButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] unique_name_in_owner = true layout_mode = 2 -text = "Suspend" +text = "Pause" [node name="GamepadButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] layout_mode = 2 text = "Gamepad" [node name="StateUpdater" parent="MarginContainer/VBoxContainer/ContentContainer/GamepadButton" instance=ExtResource("6_s452c")] -state_machine = ExtResource("7_yrgt0") +state_machine = ExtResource("13_aslkr") state = ExtResource("8_nyd1y") on_signal = "player_button_up" +[node name="StateUpdater2" parent="MarginContainer/VBoxContainer/ContentContainer/GamepadButton" instance=ExtResource("6_s452c")] +state_machine = ExtResource("15_p4kr0") +state = ExtResource("16_vmedb") +on_signal = "button_up" + +[node name="ClearOverlay" parent="MarginContainer/VBoxContainer/ContentContainer/GamepadButton" instance=ExtResource("6_s452c")] +state_machine = ExtResource("15_70rxc") +action = 6 +on_signal = "button_up" + [node name="ExitButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] unique_name_in_owner = true layout_mode = 2 text = "Exit" + +[node name="ClearOverlay" parent="MarginContainer/VBoxContainer/ContentContainer/ExitButton" instance=ExtResource("6_s452c")] +state_machine = ExtResource("15_70rxc") +action = 6 +on_signal = "button_up" diff --git a/core/ui/card_ui/navigation/search_bar_menu.tscn b/core/ui/card_ui/navigation/search_bar_menu.tscn index 8999d533..433e6f4d 100644 --- a/core/ui/card_ui/navigation/search_bar_menu.tscn +++ b/core/ui/card_ui/navigation/search_bar_menu.tscn @@ -1,11 +1,11 @@ [gd_scene load_steps=12 format=3 uid="uid://d4bmkauhrlhq0"] -[ext_resource type="Script" path="res://core/systems/state/visibility_manager.gd" id="1_3s0wp"] [ext_resource type="Script" path="res://core/ui/card_ui/navigation/search_bar_menu.gd" id="1_518qs"] [ext_resource type="PackedScene" uid="uid://bx0fnuxd8mm51" path="res://core/ui/components/search_bar.tscn" id="2_gqstr"] [ext_resource type="Resource" uid="uid://oaavalv0wcoa" path="res://assets/state/states/home.tres" id="2_kr4pi"] +[ext_resource type="PackedScene" uid="uid://bfiia7vnbfw3s" path="res://core/systems/state/states_watcher.tscn" id="2_nb2d7"] [ext_resource type="Resource" uid="uid://boq501bigx8kl" path="res://assets/state/states/library.tres" id="3_sj5or"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="4_r83xd"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_1043g"] [ext_resource type="Texture2D" uid="uid://8pmccsyfv3u7" path="res://assets/ui/icons/search.svg" id="5_pq07x"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="6_dilc0"] [ext_resource type="PackedScene" uid="uid://cgmb4kr2ec4ha" path="res://core/ui/components/tabs_header.tscn" id="8_uixir"] @@ -13,20 +13,21 @@ [ext_resource type="Script" path="res://core/ui/components/input_icon.gd" id="9_qnoau"] [node name="SearchBarMenu" type="PanelContainer"] -z_index = 20 +z_index = 19 custom_minimum_size = Vector2(0, 48) size_flags_horizontal = 0 size_flags_vertical = 0 theme_type_variation = &"SearchBar" script = ExtResource("1_518qs") -[node name="VisibilityManager" type="Node" parent="."] -script = ExtResource("1_3s0wp") -state = ExtResource("2_kr4pi") -visible_during = Array[Resource]([ExtResource("2_kr4pi"), ExtResource("3_sj5or")]) +[node name="StatesWatcher" parent="." instance=ExtResource("2_nb2d7")] +states = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("2_kr4pi"), ExtResource("3_sj5or")]) -[node name="TransitionFadeIn" parent="VisibilityManager" instance=ExtResource("4_r83xd")] -root_node = NodePath("..") +[node name="FadeEffect" parent="StatesWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_1043g")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 diff --git a/core/ui/card_ui/navigation/top_button_menu.tscn b/core/ui/card_ui/navigation/top_button_menu.tscn index f6fb739f..2539834e 100644 --- a/core/ui/card_ui/navigation/top_button_menu.tscn +++ b/core/ui/card_ui/navigation/top_button_menu.tscn @@ -1,15 +1,15 @@ [gd_scene load_steps=13 format=3 uid="uid://by0i08fw1fwty"] +[ext_resource type="PackedScene" uid="uid://bfiia7vnbfw3s" path="res://core/systems/state/states_watcher.tscn" id="1_onljq"] [ext_resource type="Texture2D" uid="uid://bjscvn2us6tal" path="res://assets/ui/icons/bell.svg" id="1_te2kv"] -[ext_resource type="Script" path="res://core/systems/state/visibility_manager.gd" id="1_ue0mf"] [ext_resource type="Texture2D" uid="uid://dq32os2qn6atc" path="res://assets/ui/icons/help.svg" id="2_1q5o3"] [ext_resource type="Resource" uid="uid://oaavalv0wcoa" path="res://assets/state/states/home.tres" id="2_a2ifc"] -[ext_resource type="Resource" uid="uid://boq501bigx8kl" path="res://assets/state/states/library.tres" id="3_5xjwl"] [ext_resource type="Resource" uid="uid://dav2b3n384cso" path="res://assets/state/states/game_launcher.tres" id="4_g6or7"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="4_lk3ix"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_m8oxr"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="6_b4g8u"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="9_74mn5"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="9_atx4m"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="9_nhibw"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="10_5h6sh"] [ext_resource type="Resource" uid="uid://d3gp85f35oiw6" path="res://assets/state/states/settings.tres" id="11_eo1bd"] [ext_resource type="Resource" uid="uid://db5gbdl3xgwlq" path="res://assets/state/states/help_menu.tres" id="11_q3ls8"] @@ -20,13 +20,14 @@ size_flags_horizontal = 8 size_flags_vertical = 0 theme_type_variation = &"ButtonMenu" -[node name="VisibilityManager" type="Node" parent="."] -script = ExtResource("1_ue0mf") -state = ExtResource("2_a2ifc") -visible_during = Array[Resource]([ExtResource("2_a2ifc"), ExtResource("3_5xjwl"), ExtResource("4_g6or7")]) +[node name="StatesWatcher" parent="." instance=ExtResource("1_onljq")] +states = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("2_a2ifc"), ExtResource("4_g6or7")]) -[node name="TransitionFadeIn" parent="VisibilityManager" instance=ExtResource("4_lk3ix")] -root_node = NodePath("..") +[node name="FadeEffect" parent="StatesWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_m8oxr")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 @@ -37,6 +38,7 @@ theme_override_constants/margin_right = 10 layout_mode = 2 [node name="NotifyButton" parent="MarginContainer/HBoxContainer" instance=ExtResource("6_b4g8u")] +visible = false custom_minimum_size = Vector2(36, 36) layout_mode = 2 texture = ExtResource("1_te2kv") @@ -47,7 +49,7 @@ layout_mode = 2 texture = ExtResource("2_1q5o3") [node name="StateUpdater" parent="MarginContainer/HBoxContainer/HelpButton" instance=ExtResource("9_nhibw")] -state_machine = ExtResource("10_5h6sh") +state_machine = ExtResource("9_atx4m") state = ExtResource("11_q3ls8") on_signal = "button_up" @@ -56,6 +58,6 @@ custom_minimum_size = Vector2(36, 36) layout_mode = 2 [node name="StateUpdater" parent="MarginContainer/HBoxContainer/SettingsButton" instance=ExtResource("9_nhibw")] -state_machine = ExtResource("10_5h6sh") +state_machine = ExtResource("9_74mn5") state = ExtResource("11_eo1bd") on_signal = "button_up" diff --git a/core/ui/card_ui/ootbe/first_boot_menu.tscn b/core/ui/card_ui/ootbe/first_boot_menu.tscn index b054b16a..e52ce622 100644 --- a/core/ui/card_ui/ootbe/first_boot_menu.tscn +++ b/core/ui/card_ui/ootbe/first_boot_menu.tscn @@ -1,7 +1,6 @@ -[gd_scene load_steps=13 format=3 uid="uid://b30stcxjwk3od"] +[gd_scene load_steps=14 format=3 uid="uid://b30stcxjwk3od"] [ext_resource type="Script" path="res://core/ui/card_ui/ootbe/first_boot_menu.gd" id="1_37dam"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_bh7el"] [ext_resource type="PackedScene" uid="uid://cwdf3dyj7grrk" path="res://core/ui/card_ui/ootbe/language_select.tscn" id="2_djjvb"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="2_ikevm"] [ext_resource type="Resource" uid="uid://bj8aa7rky3u36" path="res://assets/state/state_machines/first_boot_state_machine.tres" id="3_0m4gw"] @@ -10,7 +9,9 @@ [ext_resource type="PackedScene" uid="uid://b64v61ut4e1qv" path="res://core/ui/card_ui/ootbe/network_select.tscn" id="4_mx76i"] [ext_resource type="Resource" uid="uid://cawipbut6fx5o" path="res://assets/state/states/first_boot_language.tres" id="4_pe1rt"] [ext_resource type="PackedScene" uid="uid://cq5do4hbuevrd" path="res://core/ui/card_ui/ootbe/plugin_select.tscn" id="5_8uql2"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_ipx1n"] [ext_resource type="PackedScene" uid="uid://cx0pugv62qwkw" path="res://core/ui/card_ui/ootbe/plugin_setup.tscn" id="6_jawcd"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="7_4d0j5"] [ext_resource type="PackedScene" uid="uid://lbf0ycha2pav" path="res://core/ui/card_ui/ootbe/finished_menu.tscn" id="12_5m0q4"] [node name="FirstBootMenu" type="Control"] @@ -27,9 +28,15 @@ state_machine = ExtResource("3_0m4gw") state = ExtResource("4_pe1rt") on_signal = "ready" -[node name="VisibilityManager" parent="." instance=ExtResource("2_bh7el")] +[node name="StateWatcher" parent="." instance=ExtResource("5_ipx1n")] state = ExtResource("3_yp1h6") +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("7_4d0j5")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" + [node name="ContentContainer" type="MarginContainer" parent="."] layout_mode = 1 anchors_preset = 15 diff --git a/core/ui/card_ui/power/power_menu.gd b/core/ui/card_ui/power/power_menu.gd index ad56c0b6..8e62e954 100644 --- a/core/ui/card_ui/power/power_menu.gd +++ b/core/ui/card_ui/power/power_menu.gd @@ -1,7 +1,7 @@ extends Control var state_machine := ( - preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine + preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine ) var power_state := load("res://assets/state/states/power_menu.tres") as State var logger := Log.get_logger("PowerMenu") @@ -50,10 +50,12 @@ func _on_state_entered(_from: State) -> void: func _on_systemctl_cmd(command: String) -> void: - state_machine.pop_state() - var output: Array = [] - if OS.execute("systemctl", [command], output) != OK: - logger.warn("Failed to " + command + ": '" + output[0] + "'") + state_machine.clear_states() + var exec := func(): + var output: Array = [] + if OS.execute("systemctl", [command], output) != OK: + logger.warn("Failed to " + command + ": '" + output[0] + "'") + exec.call_deferred() func _on_exit() -> void: diff --git a/core/ui/card_ui/power/power_menu.tscn b/core/ui/card_ui/power/power_menu.tscn index eaf69499..b67c488e 100644 --- a/core/ui/card_ui/power/power_menu.tscn +++ b/core/ui/card_ui/power/power_menu.tscn @@ -1,12 +1,13 @@ -[gd_scene load_steps=16 format=3 uid="uid://lfm3ps837gy5"] +[gd_scene load_steps=17 format=3 uid="uid://lfm3ps837gy5"] [ext_resource type="Script" path="res://core/ui/card_ui/power/power_menu.gd" id="2_0vc46"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="3_1whtm"] [ext_resource type="Shader" path="res://assets/shaders/simple_blur.gdshader" id="3_oe8pc"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="4_7v8tn"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="4_4rhfl"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="5_kxixy"] [ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="5_u1rly"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="6_j6s3o"] -[ext_resource type="PackedScene" uid="uid://b6p2lrkowintj" path="res://core/ui/components/transition_container.tscn" id="7_7o4m4"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="8_tx8jn"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="6_34b1q"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="8_xohsw"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="9_vlbso"] [ext_resource type="Script" path="res://core/systems/input/focus_stack.gd" id="10_6ywv6"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="10_y3iyf"] @@ -48,15 +49,23 @@ grow_horizontal = 2 grow_vertical = 2 texture = SubResource("GradientTexture1D_nu0jx") -[node name="BackInputHandler" parent="." instance=ExtResource("4_7v8tn")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("5_u1rly")]) +[node name="InputWatcher" parent="." instance=ExtResource("3_1whtm")] +stop_propagation = true +action = "ogui_east" -[node name="VisibilityManager" parent="." instance=ExtResource("6_j6s3o")] -state = ExtResource("5_u1rly") +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("4_4rhfl")] +state_machine = ExtResource("5_kxixy") +action = 2 +on_signal = "input_released" -[node name="TransitionContainer" parent="." instance=ExtResource("7_7o4m4")] +[node name="StateWatcher" parent="." instance=ExtResource("6_34b1q")] +state = ExtResource("5_u1rly") -[node name="TransitionFadeIn" parent="TransitionContainer" instance=ExtResource("8_tx8jn")] +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("8_xohsw")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" [node name="PanelContainer" type="PanelContainer" parent="."] custom_minimum_size = Vector2(200, 150) diff --git a/core/ui/card_ui/quick_bar/qb_card.gd b/core/ui/card_ui/quick_bar/qb_card.gd index de5ad674..7fc45969 100644 --- a/core/ui/card_ui/quick_bar/qb_card.gd +++ b/core/ui/card_ui/quick_bar/qb_card.gd @@ -3,7 +3,7 @@ extends Container class_name QuickBarCard -# DEPRECATED +# DEPRECATED: Change this to [ExpandableCard] signal pressed signal button_up @@ -15,7 +15,14 @@ signal nonchild_focused @export_category("Card") @export var title := "Section" -@export var is_toggled := false +@export var is_toggled := false: + set(v): + is_toggled = v + if is_toggled: + toggled_on.emit() + else: + toggled_off.emit() + toggled.emit(is_toggled) @onready var header_container := $%HeaderContainer as VBoxContainer @onready var label := $%SectionLabel as Label @@ -31,17 +38,24 @@ var logger := Log.get_logger("QBCard", Log.LEVEL.INFO) # Called when the node enters the scene tree for the first time. func _ready() -> void: - focus_entered.connect(_on_focus) - focus_exited.connect(_on_unfocus) - pressed.connect(_on_pressed) - theme_changed.connect(_on_theme_changed) - _on_theme_changed() label.text = title - + # Do nothing if running in the editor if Engine.is_editor_hint(): return + var on_focus_exited := func(): + self._on_unfocus.call_deferred() + focus_exited.connect(on_focus_exited) + focus_entered.connect(_on_focus) + button_up.connect(_on_button_up) + theme_changed.connect(_on_theme_changed) + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() + # Try to find a scroll container to do smooth scrolling on expansion var scroll_container := find_parent("ScrollContainer") if scroll_container and scroll_container is ScrollContainer: @@ -51,11 +65,9 @@ func _ready() -> void: grower.effect_finished.connect(on_grow_finished) # Auto-close when visibility is lost - var on_visibility_changed := func(): - var grower := get_node("GrowerEffect") as GrowerEffect - grower.shrink() + var on_hidden := func(): is_toggled = false - hidden.connect(on_visibility_changed) + hidden.connect(on_hidden) # Resize any children that are Control nodes for child in content_container.get_children(): @@ -132,23 +144,47 @@ func _on_focus() -> void: # the user has focused outside the card, and we should shrink to hide the # content if is_toggled: - _on_pressed() + _on_button_up() func _on_unfocus() -> void: - # If a child focus group is focused, don't do anything. That means that - if not focus_group: - logger.warn("No focus group defined!") + # Get the new focus owner + var focus_owner := get_viewport().gui_get_focus_owner() + + # Emit a signal if a non-child node grabs focus + if not self.is_ancestor_of(focus_owner): + nonchild_focused.emit() + is_toggled = false return - # a child node is focused and we want the card to remain "selected" - if focus_group.is_in_focus_stack(): + # If a child has focus, listen for focus changes until a non-child has focus + get_viewport().gui_focus_changed.connect(_on_focus_change) + + +func _on_focus_change(focused: Control) -> void: + # Don't do anything if the focused node is a child + if self.is_ancestor_of(focused): return - + + # If the focus owner is a child of an on-screen keyboard, don't do anything + # so the card remains open. + var virtual_keyboards := get_tree().get_nodes_in_group("osk") + for kb in virtual_keyboards: + if not kb: + continue + if kb.is_ancestor_of(focused): + return + + # If a non-child has focus, emit a signal to indicate that this node and none + # of its children have focus. nonchild_focused.emit() + is_toggled = false + var viewport := get_viewport() + if viewport.gui_focus_changed.is_connected(_on_focus_change): + viewport.gui_focus_changed.disconnect(_on_focus_change) -func _on_pressed() -> void: +func _on_button_up() -> void: is_toggled = !is_toggled if is_toggled: toggled_on.emit() @@ -168,3 +204,24 @@ func _gui_input(event: InputEvent) -> void: pressed.emit() else: button_up.emit() + + +func _input(event: InputEvent) -> void: + if not is_toggled: + return + if not event.is_action("ogui_east"): + return + if not event.is_released(): + return + + # Only process input if a child node has focus + #var focus_owner := get_viewport().gui_get_focus_owner() + #if not self.is_ancestor_of(focus_owner): + # return + + # Handle back input + is_toggled = false + + # Stop the event from propagating + #logger.debug("Consuming input event '{action}' for node {n}".format({"action": action, "n": str(self)})) + get_viewport().set_input_as_handled() diff --git a/core/ui/card_ui/quick_bar/qb_card.tscn b/core/ui/card_ui/quick_bar/qb_card.tscn index ca3e085d..aa4ebd1d 100644 --- a/core/ui/card_ui/quick_bar/qb_card.tscn +++ b/core/ui/card_ui/quick_bar/qb_card.tscn @@ -7,18 +7,8 @@ [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="5_2hiwt"] [ext_resource type="PackedScene" uid="uid://btg3dylh0tqoi" path="res://core/systems/effects/smooth_scroll_effect.tscn" id="6_hklca"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="6_qh1ai"] - -[sub_resource type="Image" id="Image_6pbp1"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_sa6yd"] -image = SubResource("Image_6pbp1") +[ext_resource type="Script" path="res://core/systems/input/input_watcher.gd" id="8_7kulb"] +[ext_resource type="Script" path="res://core/systems/input/focus_setter.gd" id="9_wwxqw"] [node name="QuickBarCard" type="PanelContainer"] anchors_preset = 10 @@ -69,7 +59,6 @@ theme_type_variation = &"ExpandableCard" unique_name_in_owner = true visible = false layout_mode = 2 -texture = SubResource("ImageTexture_sa6yd") expand_mode = 1 stretch_mode = 6 @@ -113,3 +102,13 @@ layout_mode = 2 unique_name_in_owner = true visible = false layout_mode = 2 + +[node name="InputWatcher" type="Node" parent="MarginContainer/CardVBoxContainer/ContentContainer"] +script = ExtResource("8_7kulb") +stop_propagation = true +action = "ogui_east" + +[node name="FocusSetter" type="Node" parent="MarginContainer/CardVBoxContainer/ContentContainer/InputWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("9_wwxqw") +target = NodePath("../../../../..") +on_signal = "input_released" diff --git a/core/ui/card_ui/quick_bar/quick_bar_menu.tscn b/core/ui/card_ui/quick_bar/quick_bar_menu.tscn index 71f49464..c8944223 100644 --- a/core/ui/card_ui/quick_bar/quick_bar_menu.tscn +++ b/core/ui/card_ui/quick_bar/quick_bar_menu.tscn @@ -1,18 +1,18 @@ -[gd_scene load_steps=26 format=3 uid="uid://hroo3ll4inrb"] +[gd_scene load_steps=29 format=3 uid="uid://hroo3ll4inrb"] [ext_resource type="Script" path="res://core/ui/card_ui/quick_bar/quick_bar_menu.gd" id="1_56jo7"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_6rvrx"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_kmwe3"] [ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="3_cxjne"] [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_l64vu"] +[ext_resource type="Resource" uid="uid://cadriyl38ny5y" path="res://assets/state/state_machines/popup_state_machine.tres" id="4_n117t"] [ext_resource type="PackedScene" uid="uid://ekhjpmat02f8" path="res://core/systems/effects/slide_effect.tscn" id="5_i1kur"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="5_ro2hl"] [ext_resource type="PackedScene" uid="uid://4t4jt26o2fbr" path="res://core/ui/card_ui/navigation/system_container.tscn" id="7_xtcf0"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="8_5082k"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="9_6qs1m"] [ext_resource type="Texture2D" uid="uid://bjscvn2us6tal" path="res://assets/ui/icons/bell.svg" id="10_4yppf"] [ext_resource type="Texture2D" uid="uid://dq32os2qn6atc" path="res://assets/ui/icons/help.svg" id="11_a0ma3"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="12_ldp5y"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="13_u3r8o"] [ext_resource type="Resource" uid="uid://d3gp85f35oiw6" path="res://assets/state/states/settings.tres" id="14_didkb"] [ext_resource type="Resource" uid="uid://db5gbdl3xgwlq" path="res://assets/state/states/help_menu.tres" id="14_gr3i0"] [ext_resource type="Texture2D" uid="uid://c8pq5h4uim4pj" path="res://assets/ui/icons/game-controller.svg" id="15_0l0p5"] @@ -21,6 +21,9 @@ [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="16_74m7a"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="17_qgen2"] [ext_resource type="Resource" uid="uid://dpc1o781f43ef" path="res://core/ui/card_ui/quick_bar/quick_bar_menu_focus.tres" id="18_4nxly"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="18_lj3fv"] +[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="18_q6xfk"] +[ext_resource type="Resource" uid="uid://cv3vduo0ojk1u" path="res://assets/state/states/menu.tres" id="19_orchh"] [ext_resource type="PackedScene" uid="uid://bjy50kdrebgre" path="res://core/ui/card_ui/quick_bar/notifications_card.tscn" id="19_pppbi"] [ext_resource type="PackedScene" uid="uid://dxaeufuk7ump2" path="res://core/ui/card_ui/quick_bar/quick_settings_card.tscn" id="20_17ks0"] [ext_resource type="PackedScene" uid="uid://dycb7m0oj13ly" path="res://core/ui/card_ui/quick_bar/performance_card.tscn" id="21_uw510"] @@ -37,6 +40,15 @@ grow_horizontal = 0 grow_vertical = 2 script = ExtResource("1_56jo7") +[node name="InputWatcher" parent="." instance=ExtResource("2_kmwe3")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("12_ldp5y")] +state_machine = ExtResource("4_n117t") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_6rvrx")] state = ExtResource("3_cxjne") @@ -54,9 +66,6 @@ on_signal = "state_entered" slide_out_signal = "state_exited" on_signal = "state_entered" -[node name="BackInputHandler" parent="." instance=ExtResource("5_ro2hl")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_cxjne")]) - [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 anchors_preset = 11 @@ -95,6 +104,7 @@ focus_neighbor_bottom = NodePath("../../ScrollContainer/Viewport/FocusGroup") [node name="NotifyButton" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer" instance=ExtResource("9_6qs1m")] unique_name_in_owner = true +visible = false custom_minimum_size = Vector2(26, 26) layout_mode = 2 texture = ExtResource("10_4yppf") @@ -105,7 +115,7 @@ layout_mode = 2 texture = ExtResource("11_a0ma3") [node name="StateUpdater" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/HelpButton" instance=ExtResource("12_ldp5y")] -state_machine = ExtResource("13_u3r8o") +state_machine = ExtResource("4_n117t") state = ExtResource("14_gr3i0") on_signal = "button_up" @@ -115,10 +125,20 @@ layout_mode = 2 texture = ExtResource("15_0l0p5") [node name="StateUpdater" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/GamepadButton" instance=ExtResource("12_ldp5y")] -state_machine = ExtResource("13_u3r8o") +state_machine = ExtResource("18_lj3fv") state = ExtResource("16_74m7a") on_signal = "player_button_up" +[node name="StateUpdater2" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/GamepadButton" instance=ExtResource("12_ldp5y")] +state_machine = ExtResource("18_q6xfk") +state = ExtResource("19_orchh") +on_signal = "button_up" + +[node name="ClearOverlay" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/GamepadButton" instance=ExtResource("12_ldp5y")] +state_machine = ExtResource("4_n117t") +action = 6 +on_signal = "button_up" + [node name="Spacer" type="Control" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer"] layout_mode = 2 size_flags_horizontal = 3 @@ -128,10 +148,20 @@ custom_minimum_size = Vector2(26, 26) layout_mode = 2 [node name="StateUpdater" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/SettingsButton" instance=ExtResource("12_ldp5y")] -state_machine = ExtResource("13_u3r8o") +state_machine = ExtResource("18_lj3fv") state = ExtResource("14_didkb") on_signal = "button_up" +[node name="StateUpdater2" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/SettingsButton" instance=ExtResource("12_ldp5y")] +state_machine = ExtResource("18_q6xfk") +state = ExtResource("19_orchh") +on_signal = "button_up" + +[node name="ClearOverlay" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer/ButtonContainer/SettingsButton" instance=ExtResource("12_ldp5y")] +state_machine = ExtResource("4_n117t") +action = 6 +on_signal = "button_up" + [node name="PlayingNowContainer" type="HBoxContainer" parent="MarginContainer/PanelContainer/MarginContainer/VBoxContainer"] unique_name_in_owner = true visible = false diff --git a/core/ui/card_ui/quick_bar/quick_settings_card.tscn b/core/ui/card_ui/quick_bar/quick_settings_card.tscn index 68481fda..a6360fe3 100644 --- a/core/ui/card_ui/quick_bar/quick_settings_card.tscn +++ b/core/ui/card_ui/quick_bar/quick_settings_card.tscn @@ -1,26 +1,11 @@ -[gd_scene load_steps=5 format=3 uid="uid://dxaeufuk7ump2"] +[gd_scene load_steps=3 format=3 uid="uid://dxaeufuk7ump2"] [ext_resource type="PackedScene" uid="uid://b5xnora73yd8x" path="res://core/ui/card_ui/quick_bar/qb_card.tscn" id="1_xq1be"] [ext_resource type="PackedScene" uid="uid://gjrgimao0edi" path="res://core/ui/common/quick_bar/quick_settings_menu.tscn" id="2_gwynk"] -[sub_resource type="Image" id="Image_n6cge"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_ca0vc"] -image = SubResource("Image_n6cge") - [node name="QuickSettingsCard" instance=ExtResource("1_xq1be")] title = "Quick Settings" -[node name="HighlightTexture" parent="PanelContainer" index="0"] -texture = SubResource("ImageTexture_ca0vc") - [node name="SectionLabel" parent="MarginContainer/CardVBoxContainer" index="0"] text = "Quick Settings" diff --git a/core/ui/card_ui/settings/bluetooth_settings_menu.tscn b/core/ui/card_ui/settings/bluetooth_settings_menu.tscn index a26e3046..92d5e7c4 100644 --- a/core/ui/card_ui/settings/bluetooth_settings_menu.tscn +++ b/core/ui/card_ui/settings/bluetooth_settings_menu.tscn @@ -1,9 +1,14 @@ -[gd_scene load_steps=5 format=3 uid="uid://6ygxdkvh1hib"] +[gd_scene load_steps=10 format=3 uid="uid://6ygxdkvh1hib"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/bluetooth_settings_menu.gd" id="1_7sjpd"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_36ef6"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_rx42r"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_p7et2"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_2trn0"] [ext_resource type="PackedScene" uid="uid://d1qb7euwlu7bh" path="res://core/ui/components/toggle.tscn" id="4_isnhb"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_l428g"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_ivwga"] +[ext_resource type="Resource" uid="uid://5r7ehi4t5mri" path="res://assets/state/states/settings_bluetooth.tres" id="6_2ogat"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_klxjh"] [node name="BluetoothSettingsMenu" type="Control"] layout_mode = 3 @@ -14,6 +19,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_7sjpd") +[node name="InputWatcher" parent="." instance=ExtResource("2_p7et2")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_2trn0")] +state_machine = ExtResource("4_l428g") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_ivwga")] +state = ExtResource("6_2ogat") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_klxjh") +target = NodePath("../../MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="DiscoverTimer" type="Timer" parent="."] unique_name_in_owner = true @@ -65,21 +87,18 @@ layout_mode = 2 [node name="FocusGroup" parent="MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("2_36ef6")] current_focus = NodePath("../EnableToggle") -focus_stack = ExtResource("3_rx42r") [node name="EnableToggle" parent="MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer" instance=ExtResource("4_isnhb")] unique_name_in_owner = true layout_mode = 2 text = "Enabled" separator_visible = false -button_pressed = false [node name="DiscoverToggle" parent="MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer" instance=ExtResource("4_isnhb")] unique_name_in_owner = true layout_mode = 2 text = "Enable Discovery" separator_visible = false -button_pressed = false [node name="Tree" type="Tree" parent="MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer"] unique_name_in_owner = true diff --git a/core/ui/card_ui/settings/disks_settings_menu.gd b/core/ui/card_ui/settings/disks_settings_menu.gd index 2c86791b..3fe3439c 100644 --- a/core/ui/card_ui/settings/disks_settings_menu.gd +++ b/core/ui/card_ui/settings/disks_settings_menu.gd @@ -7,7 +7,7 @@ const drive_card_scene: PackedScene = preload("res://core/ui/components/drive_ca var logger := Log.get_logger("DisksMenu", Log.LEVEL.INFO) -@onready var container: HFlowContainer = $%DriveCardContainer +@onready var container: VBoxContainer = $%DriveCardContainer @onready var focus_group: FocusGroup = $%FocusGroup @onready var no_drive_label: Label = $%NoDisksLabel @@ -42,6 +42,12 @@ func _on_drives_updated(devices: Array[BlockDevice]) -> void: # Poplulate drives var last_focus: FocusGroup for drive in devices: + var drive_type = drive.dbus_path.trim_prefix(steam_disks.BLOCK_PREFIX) + + # Ignore loop devices + if drive_type.contains("loop"): + continue + # Create Drive Card var drive_card := drive_card_scene.instantiate() container.add_child(drive_card) diff --git a/core/ui/card_ui/settings/disks_settings_menu.tscn b/core/ui/card_ui/settings/disks_settings_menu.tscn index 9cb27349..babb7c5b 100644 --- a/core/ui/card_ui/settings/disks_settings_menu.tscn +++ b/core/ui/card_ui/settings/disks_settings_menu.tscn @@ -1,12 +1,14 @@ -[gd_scene load_steps=9 format=3 uid="uid://clbapexwfoqtu"] +[gd_scene load_steps=11 format=3 uid="uid://clbapexwfoqtu"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/disks_settings_menu.gd" id="1_ct0k3"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_6shyw"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_8gros"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_8w0tf"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_lwwgd"] [ext_resource type="PackedScene" uid="uid://caeaxm6st4a4u" path="res://core/ui/components/drive_card.tscn" id="4_brwek"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_vkilo"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_hkv7e"] [ext_resource type="Resource" uid="uid://cn236k0ajm0uw" path="res://assets/state/states/settings_disks.tres" id="6_txokm"] -[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="7_kihn7"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_lonxh"] [ext_resource type="Script" path="res://core/systems/input/scroller_joystick.gd" id="8_x4sfx"] [node name="DisksMenu" type="ScrollContainer"] @@ -17,6 +19,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_ct0k3") +[node name="InputWatcher" parent="." instance=ExtResource("2_6shyw")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_lwwgd")] +state_machine = ExtResource("4_vkilo") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_hkv7e")] +state = ExtResource("6_txokm") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_lonxh") +target = NodePath("../../MarginContainer/DriveCardContainer/FocusGroup") +on_signal = "state_entered" + [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 size_flags_horizontal = 3 @@ -29,14 +48,13 @@ Verify your media device is plugged in and that it is not mounted to a protected horizontal_alignment = 1 uppercase = true -[node name="DriveCardContainer" type="HFlowContainer" parent="MarginContainer"] +[node name="DriveCardContainer" type="VBoxContainer" parent="MarginContainer"] unique_name_in_owner = true visible = false layout_mode = 2 [node name="FocusGroup" parent="MarginContainer/DriveCardContainer" instance=ExtResource("2_8gros")] unique_name_in_owner = true -focus_stack = ExtResource("3_8w0tf") [node name="DriveCard" parent="MarginContainer/DriveCardContainer" instance=ExtResource("4_brwek")] layout_mode = 2 @@ -47,14 +65,5 @@ layout_mode = 2 [node name="DriveCard3" parent="MarginContainer/DriveCardContainer" instance=ExtResource("4_brwek")] layout_mode = 2 -[node name="StateWatcher" parent="." instance=ExtResource("5_hkv7e")] -state = ExtResource("6_txokm") - -[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("7_kihn7")] -target = NodePath("../..") -on_signal = "state_entered" -fade_out_signal = "state_exited" -on_signal = "state_entered" - [node name="ScrollerJoystick" type="Node" parent="."] script = ExtResource("8_x4sfx") diff --git a/core/ui/card_ui/settings/general_controller_settings_menu.tscn b/core/ui/card_ui/settings/general_controller_settings_menu.tscn index 8ff4d89f..8530ea27 100644 --- a/core/ui/card_ui/settings/general_controller_settings_menu.tscn +++ b/core/ui/card_ui/settings/general_controller_settings_menu.tscn @@ -1,14 +1,15 @@ -[gd_scene load_steps=11 format=3 uid="uid://cgxl1qiu50h15"] +[gd_scene load_steps=12 format=3 uid="uid://cgxl1qiu50h15"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/general_controller_settings_menu.gd" id="1_r712q"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_fdccl"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_siloa"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_6p4qa"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_w65oc"] [ext_resource type="Resource" uid="uid://bcekyu20uvkxv" path="res://assets/state/states/settings_general_controller.tres" id="3_yy4fy"] -[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_g1xc4"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_s8rkr"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_28fjg"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="7_ynn8u"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="8_1egj0"] -[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="9_3kuiy"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="10_ij44t"] [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="10_uoc6p"] [node name="GeneralControllerSettings" type="Control"] @@ -20,13 +21,21 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_r712q") +[node name="InputWatcher" parent="." instance=ExtResource("2_w65oc")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("8_1egj0")] +state_machine = ExtResource("4_s8rkr") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_siloa")] state = ExtResource("3_yy4fy") -[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_g1xc4")] -target = NodePath("../..") -on_signal = "state_entered" -fade_out_signal = "state_exited" +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_28fjg") +target = NodePath("../../MarginContainer/VBoxContainer/FocusGroup") on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] @@ -45,13 +54,12 @@ theme_override_constants/margin_bottom = 5 layout_mode = 2 [node name="FocusGroup" parent="MarginContainer/VBoxContainer" instance=ExtResource("2_fdccl")] -focus_stack = ExtResource("3_6p4qa") [node name="CardButton" parent="MarginContainer/VBoxContainer" instance=ExtResource("7_ynn8u")] layout_mode = 2 text = "Gamepad Settings" [node name="StateUpdater" parent="MarginContainer/VBoxContainer/CardButton" instance=ExtResource("8_1egj0")] -state_machine = ExtResource("9_3kuiy") +state_machine = ExtResource("10_ij44t") state = ExtResource("10_uoc6p") -on_signal = "player_button_down" +on_signal = "player_button_up" diff --git a/core/ui/card_ui/settings/general_settings_menu.tscn b/core/ui/card_ui/settings/general_settings_menu.tscn index 2399dc7e..83869bf0 100644 --- a/core/ui/card_ui/settings/general_settings_menu.tscn +++ b/core/ui/card_ui/settings/general_settings_menu.tscn @@ -1,12 +1,17 @@ -[gd_scene load_steps=18 format=3 uid="uid://dsgrw1grwef4m"] +[gd_scene load_steps=23 format=3 uid="uid://dsgrw1grwef4m"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/general_settings_menu.gd" id="1_if7xt"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_b5gbi"] [ext_resource type="PackedScene" uid="uid://bnhxravpuheh2" path="res://core/systems/updater/software_updater.tscn" id="2_ogwq4"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="3_36sdt"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="4_fyrmg"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_bxo72"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_31ujl"] +[ext_resource type="Script" path="res://core/systems/state/state_watcher.gd" id="5_7jxnc"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="5_caxj0"] [ext_resource type="PackedScene" uid="uid://d1qb7euwlu7bh" path="res://core/ui/components/toggle.tscn" id="6_ghdw1"] +[ext_resource type="Resource" uid="uid://4n3376qdy3y3" path="res://assets/state/states/settings_general.tres" id="6_vwiy7"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="7_qenel"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_sb10a"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="8_2m3jw"] [ext_resource type="PackedScene" uid="uid://xei5afwefxud" path="res://core/ui/components/dropdown.tscn" id="8_r15pa"] [ext_resource type="Texture2D" uid="uid://ckbrrln8fngno" path="res://assets/images/platform/ayaneoair-ctr_v1a_1172023.png" id="9_00g0t"] @@ -30,6 +35,24 @@ follow_focus = true horizontal_scroll_mode = 0 script = ExtResource("1_if7xt") +[node name="InputWatcher" parent="." instance=ExtResource("2_b5gbi")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_bxo72")] +state_machine = ExtResource("4_31ujl") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" type="Node" parent="."] +script = ExtResource("5_7jxnc") +state = ExtResource("6_vwiy7") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_sb10a") +target = NodePath("../../MarginContainer/VBoxContainer/VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="SoftwareUpdater" parent="." instance=ExtResource("2_ogwq4")] [node name="UpdateTimer" type="Timer" parent="."] @@ -56,7 +79,7 @@ theme_override_constants/separation = 10 [node name="FocusGroup" parent="MarginContainer/VBoxContainer/VBoxContainer" node_paths=PackedStringArray("current_focus", "focus_neighbor_bottom") instance=ExtResource("3_36sdt")] current_focus = NodePath("../AutoUpdateToggle") -focus_stack = ExtResource("4_fyrmg") +wrap_focus = false focus_neighbor_bottom = NodePath("../../ThemeButtonContainer/FocusGroup") [node name="UpdatesLabel" parent="MarginContainer/VBoxContainer/VBoxContainer" instance=ExtResource("5_caxj0")] @@ -110,7 +133,7 @@ theme_override_constants/v_separation = 10 [node name="FocusGroup" parent="MarginContainer/VBoxContainer/ThemeButtonContainer" node_paths=PackedStringArray("current_focus", "focus_neighbor_bottom", "focus_neighbor_top") instance=ExtResource("3_36sdt")] current_focus = NodePath("../ThemeDraculaButton") -focus_stack = ExtResource("4_fyrmg") +wrap_focus = false focus_neighbor_bottom = NodePath("../../VBoxContainer3/FocusGroup") focus_neighbor_top = NodePath("../../VBoxContainer/FocusGroup") @@ -160,7 +183,7 @@ theme_override_constants/separation = 10 [node name="FocusGroup" parent="MarginContainer/VBoxContainer/VBoxContainer3" node_paths=PackedStringArray("current_focus", "focus_neighbor_top") instance=ExtResource("3_36sdt")] current_focus = NodePath("../ClientVersionText") -focus_stack = ExtResource("4_fyrmg") +wrap_focus = false focus_neighbor_top = NodePath("../../ThemeButtonContainer/FocusGroup") [node name="HSeparator3" type="HSeparator" parent="MarginContainer/VBoxContainer/VBoxContainer3"] diff --git a/core/ui/card_ui/settings/library_settings_menu.tscn b/core/ui/card_ui/settings/library_settings_menu.tscn index 8e703fcb..39d3547d 100644 --- a/core/ui/card_ui/settings/library_settings_menu.tscn +++ b/core/ui/card_ui/settings/library_settings_menu.tscn @@ -1,13 +1,15 @@ -[gd_scene load_steps=9 format=3 uid="uid://drbp6ec8646v3"] +[gd_scene load_steps=11 format=3 uid="uid://drbp6ec8646v3"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/library_settings_menu.gd" id="1_0w1vu"] [ext_resource type="PackedScene" uid="uid://cemxrvvjgm4g" path="res://core/ui/components/slider.tscn" id="1_obgkx"] [ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_guba0"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_oc808"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_k7tqg"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="3_x5lfl"] [ext_resource type="Resource" uid="uid://blcfrofi5oawd" path="res://assets/state/states/settings_library.tres" id="3_ykj28"] -[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_148sd"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_cd7pj"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="5_sh522"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="6_ou60g"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_5nxbl"] [node name="LibrarySettingsMenu" type="ScrollContainer"] anchors_preset = 15 @@ -18,13 +20,21 @@ grow_vertical = 2 follow_focus = true script = ExtResource("1_0w1vu") +[node name="InputWatcher" parent="." instance=ExtResource("2_oc808")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_k7tqg")] +state_machine = ExtResource("4_cd7pj") +action = 2 +on_signal = "input_released" + [node name="StateWatcher" parent="." instance=ExtResource("2_guba0")] state = ExtResource("3_ykj28") -[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_148sd")] -target = NodePath("../..") -on_signal = "state_entered" -fade_out_signal = "state_exited" +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_5nxbl") +target = NodePath("../../MarginContainer/VBoxContainer/FocusGroup") on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] @@ -42,7 +52,6 @@ layout_mode = 2 [node name="FocusGroup" parent="MarginContainer/VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("5_sh522")] current_focus = NodePath("../MaxRecentAppsSlider") -focus_stack = ExtResource("6_ou60g") [node name="HomeLabel" parent="MarginContainer/VBoxContainer" instance=ExtResource("3_x5lfl")] layout_mode = 2 diff --git a/core/ui/card_ui/settings/plugin_settings_content.tscn b/core/ui/card_ui/settings/plugin_settings_content.tscn index b092323b..e58c9afd 100644 --- a/core/ui/card_ui/settings/plugin_settings_content.tscn +++ b/core/ui/card_ui/settings/plugin_settings_content.tscn @@ -1,8 +1,7 @@ -[gd_scene load_steps=5 format=3 uid="uid://by6gr07lw0gw3"] +[gd_scene load_steps=4 format=3 uid="uid://by6gr07lw0gw3"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="1_kkfns"] [ext_resource type="PackedScene" uid="uid://cmjjyqx1pl23d" path="res://core/ui/components/text.tscn" id="1_qr2e8"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="2_132sf"] [ext_resource type="PackedScene" uid="uid://d1qb7euwlu7bh" path="res://core/ui/components/toggle.tscn" id="2_sphif"] [node name="PluginSettingsContent" type="MarginContainer"] @@ -24,7 +23,7 @@ size_flags_vertical = 0 [node name="FocusGroup" parent="ContentLayout" node_paths=PackedStringArray("current_focus") instance=ExtResource("1_kkfns")] unique_name_in_owner = true current_focus = NodePath("../PluginNameText") -focus_stack = ExtResource("2_132sf") +wrap_focus = false [node name="PluginNameText" parent="ContentLayout" instance=ExtResource("1_qr2e8")] unique_name_in_owner = true diff --git a/core/ui/card_ui/settings/plugin_settings_menu.gd b/core/ui/card_ui/settings/plugin_settings_menu.gd index 005697ff..a181dd54 100644 --- a/core/ui/card_ui/settings/plugin_settings_menu.gd +++ b/core/ui/card_ui/settings/plugin_settings_menu.gd @@ -108,7 +108,6 @@ func _config_settings_menu(plugin_settings: Control, plugin_content_container: C # Create a focus group for the plugin settings var plugin_focus_group := FocusGroup.new() plugin_focus_group.name = "FocusGroup" - plugin_focus_group.focus_stack = load("res://core/ui/card_ui/settings/settings_menu_focus.tres") plugin_settings.add_child(plugin_focus_group) for child in plugin_settings.get_children(): if not child is Control: diff --git a/core/ui/card_ui/settings/plugin_settings_menu.tscn b/core/ui/card_ui/settings/plugin_settings_menu.tscn index b821e324..4706c2d7 100644 --- a/core/ui/card_ui/settings/plugin_settings_menu.tscn +++ b/core/ui/card_ui/settings/plugin_settings_menu.tscn @@ -1,17 +1,18 @@ -[gd_scene load_steps=12 format=3 uid="uid://cliqk7lo4t8ao"] +[gd_scene load_steps=13 format=3 uid="uid://cliqk7lo4t8ao"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/plugin_settings_menu.gd" id="1_1p4dc"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_d8jy7"] +[ext_resource type="Script" path="res://core/systems/input/input_watcher.gd" id="2_5h71d"] [ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="3_a1fhd"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_q7mwh"] [ext_resource type="Resource" uid="uid://doxatxmp2mlty" path="res://assets/state/states/settings_plugins.tres" id="4_m0d4b"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="5_0c8si"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_ipise"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="6_fo0yk"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="7_8k476"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_wmvad"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="8_rs83g"] [ext_resource type="PackedScene" uid="uid://o0equu1tyr4s" path="res://core/ui/components/expandable_card.tscn" id="8_veuxu"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="10_nbqrj"] -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oda2h"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xcwv0"] resource_local_to_scene = true bg_color = Color(0.105882, 0.109804, 0.141176, 1) border_blend = true @@ -30,11 +31,23 @@ follow_focus = true horizontal_scroll_mode = 0 script = ExtResource("1_1p4dc") -[node name="VisibilityManager" parent="." instance=ExtResource("2_d8jy7")] +[node name="InputWatcher" type="Node" parent="."] +script = ExtResource("2_5h71d") +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_q7mwh")] state_machine = ExtResource("3_a1fhd") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_ipise")] state = ExtResource("4_m0d4b") -[node name="TransitionFadeIn" parent="VisibilityManager" instance=ExtResource("5_0c8si")] +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_wmvad") +target = NodePath("../../MarginContainer/ContentContainer/FocusGroup") +on_signal = "state_entered" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 @@ -50,7 +63,6 @@ layout_mode = 2 [node name="FocusGroup" parent="MarginContainer/ContentContainer" instance=ExtResource("6_fo0yk")] unique_name_in_owner = true -focus_stack = ExtResource("7_8k476") [node name="NoPluginsLabel" parent="MarginContainer/ContentContainer" instance=ExtResource("8_rs83g")] unique_name_in_owner = true @@ -60,6 +72,6 @@ horizontal_alignment = 1 [node name="ExpandableCard" parent="MarginContainer/ContentContainer" instance=ExtResource("8_veuxu")] layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxFlat_oda2h") +theme_override_styles/panel = SubResource("StyleBoxFlat_xcwv0") [node name="ScrollerJoystick" parent="." instance=ExtResource("10_nbqrj")] diff --git a/core/ui/card_ui/settings/plugin_store_menu.gd b/core/ui/card_ui/settings/plugin_store_menu.gd index 44626e11..0d1bfea7 100644 --- a/core/ui/card_ui/settings/plugin_store_menu.gd +++ b/core/ui/card_ui/settings/plugin_store_menu.gd @@ -3,26 +3,20 @@ extends ScrollContainer signal plugin_store_loaded(plugin_items: Dictionary) const plugin_store_card_scene: PackedScene = preload("res://core/ui/components/plugin_store_card.tscn") -var PluginLoader := load("res://core/global/plugin_loader.tres") as PluginLoader -var plugin_store_state := preload("res://assets/state/states/settings_plugin_store.tres") as State -var NotificationManager := load("res://core/global/notification_manager.tres") as NotificationManager +var plugin_loader := load("res://core/global/plugin_loader.tres") as PluginLoader +var notification_manager := load("res://core/global/notification_manager.tres") as NotificationManager var plugin_nodes := {} -@onready var container := $%HFlowContainer -@onready var focus_group := $%FocusGroup -@onready var http_image := $HTTPImageFetcher -@onready var settings_menu := $"../../../.." #verbose? +@onready var container := $%HFlowContainer as HFlowContainer +@onready var focus_group := $%FocusGroup as FocusGroup +@onready var http_image := $HTTPImageFetcher as HTTPImageFetcher # Called when the node enters the scene tree for the first time. func _ready() -> void: plugin_store_loaded.connect(_on_plugin_store_loaded) - plugin_store_state.state_entered.connect(_on_state_entered) - PluginLoader.plugin_upgradable.connect(_on_plugin_upgradable) - load_plugin_store_items() - - -func _on_state_entered(_from: State) -> void: + plugin_loader.plugin_upgradable.connect(_on_plugin_upgradable) + visibility_changed.connect(load_plugin_store_items) load_plugin_store_items() @@ -30,7 +24,7 @@ func _on_state_entered(_from: State) -> void: # signal with the loaded items func load_plugin_store_items(): # Fetch available plugins from the plugin store - var plugin_items = await PluginLoader.get_plugin_store_items() + var plugin_items = await plugin_loader.get_plugin_store_items() plugin_store_loaded.emit(plugin_items) @@ -89,4 +83,4 @@ func _on_plugin_upgradable(plugin_id: String, update_type: int) -> void: if update_type == PluginLoader.update_type.UPDATE: notify.text=("Plugin upgrade available: {0}".format([plugin_id])) - NotificationManager.show(notify) + notification_manager.show(notify) diff --git a/core/ui/card_ui/settings/plugin_store_menu.tscn b/core/ui/card_ui/settings/plugin_store_menu.tscn index 48b4d32c..3d2ce7c8 100644 --- a/core/ui/card_ui/settings/plugin_store_menu.tscn +++ b/core/ui/card_ui/settings/plugin_store_menu.tscn @@ -1,14 +1,14 @@ [gd_scene load_steps=11 format=3 uid="uid://cf5bdr4sh2irb"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/plugin_store_menu.gd" id="1_o3w0b"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_vfjyq"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_stwp6"] [ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="3_7o5pg"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_o8kc3"] [ext_resource type="Resource" uid="uid://u6fyqt1ogrie" path="res://assets/state/states/settings_plugin_store.tres" id="4_moq21"] [ext_resource type="Script" path="res://core/systems/network/http_image_fetcher.gd" id="5_5l7jt"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="5_ghad7"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_gh7kv"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="6_oyayo"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="7_qbq53"] -[ext_resource type="PackedScene" uid="uid://cc7a35n2pqmmf" path="res://core/ui/components/plugin_store_card.tscn" id="8_g4q4p"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_u7s1j"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="10_c2505"] [node name="PluginStoreMenu" type="ScrollContainer"] @@ -22,11 +22,22 @@ horizontal_scroll_mode = 0 vertical_scroll_mode = 2 script = ExtResource("1_o3w0b") -[node name="VisibilityManager" parent="." instance=ExtResource("2_vfjyq")] +[node name="InputWatcher" parent="." instance=ExtResource("2_stwp6")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_o8kc3")] state_machine = ExtResource("3_7o5pg") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_gh7kv")] state = ExtResource("4_moq21") -[node name="TransitionFadeIn" parent="VisibilityManager" instance=ExtResource("5_ghad7")] +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_u7s1j") +target = NodePath("../../MarginContainer/HFlowContainer/FocusGroup") +on_signal = "state_entered" [node name="HTTPImageFetcher" type="Node" parent="."] script = ExtResource("5_5l7jt") @@ -47,18 +58,5 @@ theme_override_constants/v_separation = 42 [node name="FocusGroup" parent="MarginContainer/HFlowContainer" instance=ExtResource("6_oyayo")] unique_name_in_owner = true -focus_stack = ExtResource("7_qbq53") - -[node name="PluginStoreCard" parent="MarginContainer/HFlowContainer" instance=ExtResource("8_g4q4p")] -layout_mode = 2 - -[node name="PluginStoreCard2" parent="MarginContainer/HFlowContainer" instance=ExtResource("8_g4q4p")] -layout_mode = 2 - -[node name="PluginStoreCard3" parent="MarginContainer/HFlowContainer" instance=ExtResource("8_g4q4p")] -layout_mode = 2 - -[node name="PluginStoreCard4" parent="MarginContainer/HFlowContainer" instance=ExtResource("8_g4q4p")] -layout_mode = 2 [node name="ScrollerJoystick" parent="." instance=ExtResource("10_c2505")] diff --git a/core/ui/card_ui/settings/settings_menu.gd b/core/ui/card_ui/settings/settings_menu.gd index d0b9a5e2..96105346 100644 --- a/core/ui/card_ui/settings/settings_menu.gd +++ b/core/ui/card_ui/settings/settings_menu.gd @@ -1,31 +1,10 @@ extends Control -var state_machine := ( - preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine -) -var settings_state_machine := preload("res://assets/state/state_machines/settings_state_machine.tres") as StateMachine -var settings_state := preload("res://assets/state/states/settings.tres") as State var version := preload("res://core/global/version.tres") as Version -@onready var version_label := $%VersionLabel -@onready var setting_buttons_container: VBoxContainer = $%SettingButtonsContainer -@onready var focus_group := $%FocusGroup as FocusGroup -@onready var section_label := $%SectionLabel +@onready var version_label := $%VersionLabel as Label # Called when the node enters the scene tree for the first time. func _ready() -> void: version_label.text = "v" + str(version.core) - settings_state_machine.state_changed.connect(_on_settings_state_changed) - settings_state.state_entered.connect(_on_state_entered) - - -func _on_state_entered(_from: State) -> void: - focus_group.grab_focus() - - -func _on_settings_state_changed(_from: State, to: State) -> void: - var text := to.name - text = text.capitalize() - text = text.replace("_", " ") - section_label.text = text diff --git a/core/ui/card_ui/settings/settings_menu.tscn b/core/ui/card_ui/settings/settings_menu.tscn index daf0d20a..b6a2ff31 100644 --- a/core/ui/card_ui/settings/settings_menu.tscn +++ b/core/ui/card_ui/settings/settings_menu.tscn @@ -1,24 +1,25 @@ -[gd_scene load_steps=48 format=3 uid="uid://d2jiecrd5sw4s"] +[gd_scene load_steps=47 format=3 uid="uid://d2jiecrd5sw4s"] [ext_resource type="Script" path="res://core/ui/card_ui/settings/settings_menu.gd" id="1_x5bjx"] -[ext_resource type="PackedScene" uid="uid://orey8uxm7v6v" path="res://core/systems/state/visibility_manager.tscn" id="2_xwevg"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="2_xfs0b"] [ext_resource type="Resource" uid="uid://d3gp85f35oiw6" path="res://assets/state/states/settings.tres" id="3_an6bd"] -[ext_resource type="Resource" uid="uid://e7bbebwf7guj" path="res://assets/state/states/main_menu.tres" id="4_3yyw8"] -[ext_resource type="Resource" uid="uid://bmgs1ngma1523" path="res://assets/state/states/in_game_menu.tres" id="5_t0lm2"] -[ext_resource type="Resource" uid="uid://bp807nlks8eq1" path="res://assets/state/states/quick_bar_menu.tres" id="6_l4ywh"] -[ext_resource type="Resource" uid="uid://dja3m1mevv6xw" path="res://assets/state/states/osk.tres" id="7_mmjyu"] -[ext_resource type="Resource" uid="uid://bw0mtk7sso8m2" path="res://assets/state/states/power_menu.tres" id="8_u3uua"] -[ext_resource type="PackedScene" uid="uid://ccd4sw84h1qbc" path="res://core/systems/input/back_input_handler.tscn" id="9_op1y2"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="4_0rio2"] +[ext_resource type="Script" path="res://core/systems/state/state_machine_watcher.gd" id="5_wwlng"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="9_rn3rv"] +[ext_resource type="Script" path="res://core/systems/state/state_updater.gd" id="9_xkw8n"] [ext_resource type="Texture2D" uid="uid://djy4rejy21s6g" path="res://icon.svg" id="10_k4kqs"] +[ext_resource type="Resource" uid="uid://bcr6c0281lb5b" path="res://assets/state/state_machines/menu_state_machine.tres" id="11_5dh5k"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="11_s3f5p"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="13_atk08"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="14_cid64"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="14_obber"] [ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="14_t8wf4"] [ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="15_cb33u"] +[ext_resource type="Script" path="res://core/systems/user_interface/tab_setter.gd" id="16_l8xyu"] [ext_resource type="Resource" uid="uid://4n3376qdy3y3" path="res://assets/state/states/settings_general.tres" id="16_sfk74"] [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="18_axp35"] [ext_resource type="Resource" uid="uid://bfx7p4n4fhjwd" path="res://assets/state/states/settings_display.tres" id="18_ljeud"] +[ext_resource type="Script" path="res://core/systems/user_interface/text_setter.gd" id="18_wbniw"] [ext_resource type="Resource" uid="uid://2efht48q7i6v" path="res://assets/state/states/settings_network.tres" id="19_l8vuu"] [ext_resource type="Resource" uid="uid://blcfrofi5oawd" path="res://assets/state/states/settings_library.tres" id="19_wexln"] [ext_resource type="Resource" uid="uid://bdvbnao6j0o18" path="res://assets/state/states/settings_audio.tres" id="20_5v03o"] @@ -27,16 +28,14 @@ [ext_resource type="Resource" uid="uid://u6fyqt1ogrie" path="res://assets/state/states/settings_plugin_store.tres" id="22_ntyf3"] [ext_resource type="Resource" uid="uid://cffkiat2h10ms" path="res://assets/state/states/settings_processes.tres" id="23_ilbjf"] [ext_resource type="Resource" uid="uid://cn236k0ajm0uw" path="res://assets/state/states/settings_disks.tres" id="24_oep0o"] -[ext_resource type="Resource" uid="uid://0f3pirade1ok" path="res://assets/state/states/settings_windows.tres" id="24_oscnu"] [ext_resource type="Resource" uid="uid://cakuo0qwrrkk8" path="res://assets/state/states/settings_logging.tres" id="25_nijem"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="27_krt45"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="27_x4tym"] [ext_resource type="Resource" uid="uid://bcekyu20uvkxv" path="res://assets/state/states/settings_general_controller.tres" id="28_nmfnj"] [ext_resource type="PackedScene" uid="uid://dsgrw1grwef4m" path="res://core/ui/card_ui/settings/general_settings_menu.tscn" id="29_8hwjo"] -[ext_resource type="PackedScene" uid="uid://bo077a5mwi7xl" path="res://core/ui/components/transition_fade_in.tscn" id="29_grs7x"] [ext_resource type="PackedScene" uid="uid://521da7e2cdxd" path="res://core/ui/common/settings/display_settings_menu.tscn" id="30_22tgj"] [ext_resource type="PackedScene" uid="uid://cpss2bhdwm8t7" path="res://core/ui/common/settings/network_settings_menu.tscn" id="31_35x2h"] -[ext_resource type="PackedScene" path="res://core/ui/common/settings/audio_settings_menu.tscn" id="32_dqi6v"] +[ext_resource type="PackedScene" uid="uid://b4uvvjgnbxj25" path="res://core/ui/common/settings/audio_settings_menu.tscn" id="32_dqi6v"] [ext_resource type="PackedScene" uid="uid://6ygxdkvh1hib" path="res://core/ui/card_ui/settings/bluetooth_settings_menu.tscn" id="33_a7xb2"] [ext_resource type="PackedScene" uid="uid://drbp6ec8646v3" path="res://core/ui/card_ui/settings/library_settings_menu.tscn" id="34_lrrl0"] [ext_resource type="PackedScene" uid="uid://cf5bdr4sh2irb" path="res://core/ui/card_ui/settings/plugin_store_menu.tscn" id="35_0u4bv"] @@ -54,14 +53,7 @@ grow_begin = -10.0 grow_end = -10.0 vertical = true -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2j6m7"] -resource_local_to_scene = true -bg_color = Color(0.105882, 0.109804, 0.141176, 1) -border_blend = true -corner_radius_top_left = 10 -corner_radius_top_right = 10 -corner_radius_bottom_right = 10 -corner_radius_bottom_left = 10 +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_a60ci"] [node name="SettingsMenu" type="Control"] layout_mode = 3 @@ -72,12 +64,45 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_x5bjx") -[node name="VisibilityManager" parent="." instance=ExtResource("2_xwevg")] +[node name="InputWatcher" parent="." instance=ExtResource("9_rn3rv")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("14_cid64")] +state_machine = ExtResource("11_5dh5k") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("2_xfs0b")] state = ExtResource("3_an6bd") -visible_during = Array[Resource]([ExtResource("4_3yyw8"), ExtResource("5_t0lm2"), ExtResource("6_l4ywh"), ExtResource("7_mmjyu"), ExtResource("8_u3uua")]) -[node name="BackInputHandler" parent="." instance=ExtResource("9_op1y2")] -process_input_during = Array[Resource("res://core/systems/state/state.gd")]([ExtResource("3_an6bd")]) +[node name="FadeEffect" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("4_0rio2")] +target = NodePath("../..") +on_signal = "state_entered" +fade_out_signal = "state_exited" +on_signal = "state_entered" + +[node name="FocusGroupSetter" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] +target = NodePath("../../MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/FocusGroup") +on_signal = "state_entered" + +[node name="RefreshFocusGroupSetter" parent="StateWatcher" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] +target = NodePath("../../MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/FocusGroup") +on_signal = "state_refreshed" + +[node name="StateUpdater" type="Node" parent="StateWatcher"] +script = ExtResource("9_xkw8n") +state_machine = ExtResource("15_cb33u") +action = 6 +on_signal = "state_removed" + +[node name="StateMachineWatcher" type="Node" parent="."] +script = ExtResource("5_wwlng") +state_machine = ExtResource("15_cb33u") + +[node name="FocusGroupSetter" parent="StateMachineWatcher" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] +target = NodePath("../../MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/FocusGroup") +on_signal = "emptied" [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 1 @@ -186,11 +211,18 @@ text = "General" state_machine = ExtResource("15_cb33u") state = ExtResource("16_sfk74") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/GeneralButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/GeneralButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralSettings/MarginContainer/VBoxContainer/VBoxContainer/FocusGroup") -on_signal = "button_up" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/GeneralButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "General" +on_signal = "focus_entered" [node name="LibraryButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -200,11 +232,19 @@ text = "Library" state_machine = ExtResource("15_cb33u") state = ExtResource("19_wexln") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LibraryButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 1 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LibraryButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LibrarySettingsMenu/MarginContainer/VBoxContainer/FocusGroup") -on_signal = "button_up" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LibraryButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Library" +on_signal = "focus_entered" [node name="HSeparator3" type="HSeparator" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer"] layout_mode = 2 @@ -217,11 +257,19 @@ text = "Display" state_machine = ExtResource("15_cb33u") state = ExtResource("18_ljeud") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisplayButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 2 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisplayButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisplaySettings/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisplayButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Display" +on_signal = "focus_entered" [node name="NetworkButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -231,11 +279,19 @@ text = "Network" state_machine = ExtResource("15_cb33u") state = ExtResource("19_l8vuu") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/NetworkButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 3 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/NetworkButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/NetworkSettings/MarginContainer/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/NetworkButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Network" +on_signal = "focus_entered" [node name="BluetoothButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -245,11 +301,19 @@ text = "Bluetooth" state_machine = ExtResource("15_cb33u") state = ExtResource("21_cbayw") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/BluetoothButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 4 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/BluetoothButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu/MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/BluetoothButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Bluetooth" +on_signal = "focus_entered" [node name="AudioButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -259,11 +323,19 @@ text = "Audio" state_machine = ExtResource("15_cb33u") state = ExtResource("20_5v03o") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/AudioButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 5 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/AudioButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/AudioSettingsMenu/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/AudioButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Audio" +on_signal = "focus_entered" [node name="DisksButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -273,11 +345,19 @@ text = "Disks" state_machine = ExtResource("15_cb33u") state = ExtResource("24_oep0o") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisksButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 6 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisksButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisksMenu/MarginContainer/DriveCardContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/DisksButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Disks" +on_signal = "focus_entered" [node name="HSeparator4" type="HSeparator" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer"] layout_mode = 2 @@ -290,11 +370,19 @@ text = "Plugins" state_machine = ExtResource("15_cb33u") state = ExtResource("21_6lg2v") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginsButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 7 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginsButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/PluginSettingsMenu/MarginContainer/ContentContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginsButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Plugins" +on_signal = "focus_entered" [node name="PluginStoreButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -304,11 +392,19 @@ text = "Plugin Store" state_machine = ExtResource("15_cb33u") state = ExtResource("22_ntyf3") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginStoreButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 8 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginStoreButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/PluginStoreMenu/MarginContainer/HFlowContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/PluginStoreButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Plugin Store" +on_signal = "focus_entered" [node name="HSeparator5" type="HSeparator" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer"] layout_mode = 2 @@ -321,24 +417,19 @@ text = "Processes" state_machine = ExtResource("15_cb33u") state = ExtResource("23_ilbjf") action = 3 -on_signal = "focus_entered" - -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ProcessesButton" instance=ExtResource("18_axp35")] -on_signal = "pressed" - -[node name="WindowsButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] -visible = false -layout_mode = 2 -text = "Windows" +on_signal = "button_up" -[node name="StateUpdater" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/WindowsButton" instance=ExtResource("14_cid64")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("24_oscnu") -action = 3 +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ProcessesButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 9 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/WindowsButton" instance=ExtResource("18_axp35")] -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ProcessesButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Processes" +on_signal = "focus_entered" [node name="LoggingButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -348,11 +439,19 @@ text = "Logging" state_machine = ExtResource("15_cb33u") state = ExtResource("25_nijem") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LoggingButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 10 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LoggingButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LoggingSettings/MarginContainer/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/LoggingButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Logging" +on_signal = "focus_entered" [node name="ControllerButton" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer" instance=ExtResource("14_obber")] layout_mode = 2 @@ -362,11 +461,19 @@ text = "Controllers" state_machine = ExtResource("15_cb33u") state = ExtResource("28_nmfnj") action = 3 +on_signal = "button_up" + +[node name="TabSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ControllerButton" node_paths=PackedStringArray("target")] +script = ExtResource("16_l8xyu") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer") +tab_number = 11 on_signal = "focus_entered" -[node name="FocusGroupSetter" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ControllerButton" node_paths=PackedStringArray("target") instance=ExtResource("18_axp35")] -target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralControllerSettings/MarginContainer/VBoxContainer/FocusGroup") -on_signal = "pressed" +[node name="TextSetter" type="Node" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer/MarginContainer/SettingButtonsContainer/ControllerButton" node_paths=PackedStringArray("target")] +script = ExtResource("18_wbniw") +target = NodePath("../../../../../../../../../ContentContainer/VBoxContainer/TitleContainer/MarginContainer/HBoxContainer/SectionLabel") +text = "Controllers" +on_signal = "focus_entered" [node name="ScrollerJoystick" parent="MarginContainer/HBoxContainer/MenuContainer/VBoxContainer/ButtonContainer/MarginContainer/ScrollContainer" instance=ExtResource("27_krt45")] @@ -411,113 +518,55 @@ theme_override_constants/margin_top = 5 theme_override_constants/margin_right = 20 theme_override_constants/margin_bottom = 5 -[node name="GeneralSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("29_8hwjo")] +[node name="TabContainer" type="TabContainer" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer"] layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxEmpty_a60ci") +tabs_visible = false -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralSettings" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("16_sfk74") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralSettings/VisibilityManager" instance=ExtResource("29_grs7x")] +[node name="GeneralSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("29_8hwjo")] +layout_mode = 2 -[node name="LibrarySettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("34_lrrl0")] +[node name="LibrarySettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("34_lrrl0")] visible = false layout_mode = 2 -[node name="DisplaySettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("30_22tgj")] +[node name="DisplaySettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("30_22tgj")] visible = false layout_mode = 2 -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisplaySettings" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("18_ljeud") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisplaySettings/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="NetworkSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("31_35x2h")] +[node name="NetworkSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("31_35x2h")] visible = false layout_mode = 2 -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/NetworkSettings" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("19_l8vuu") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/NetworkSettings/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="BluetoothSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("33_a7xb2")] +[node name="BluetoothSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("33_a7xb2")] visible = false layout_mode = 2 -[node name="EnableToggle" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu/MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer" index="1"] -button_pressed = true - -[node name="DiscoverToggle" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu/MarginContainer/ScrollContainer/AvailableContainer/VBoxContainer" index="2"] -button_pressed = true - -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("21_cbayw") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="AudioSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("32_dqi6v")] +[node name="AudioSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("32_dqi6v")] visible = false layout_mode = 2 -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/AudioSettingsMenu" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("20_5v03o") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/AudioSettingsMenu/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="DisksMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("40_lyyu6")] +[node name="DisksMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("40_lyyu6")] visible = false layout_mode = 2 -[node name="PluginSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("35_dooq8")] +[node name="PluginSettingsMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("35_dooq8")] visible = false layout_mode = 2 -[node name="ExpandableCard" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/PluginSettingsMenu/MarginContainer/ContentContainer" index="2"] -theme_override_styles/panel = SubResource("StyleBoxFlat_2j6m7") - -[node name="PluginStoreMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("35_0u4bv")] +[node name="PluginStoreMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("35_0u4bv")] visible = false layout_mode = 2 -[node name="ProcessesMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("36_hnokx")] +[node name="ProcessesMenu" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("36_hnokx")] visible = false layout_mode = 2 -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/ProcessesMenu" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("23_ilbjf") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/ProcessesMenu/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="LoggingSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("37_iwtxk")] +[node name="LoggingSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("37_iwtxk")] visible = false layout_mode = 2 -[node name="VisibilityManager" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LoggingSettings" instance=ExtResource("2_xwevg")] -state_machine = ExtResource("15_cb33u") -state = ExtResource("25_nijem") - -[node name="TransitionFadeIn" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LoggingSettings/VisibilityManager" instance=ExtResource("29_grs7x")] - -[node name="GeneralControllerSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer" instance=ExtResource("40_uqw2r")] +[node name="GeneralControllerSettings" parent="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/TabContainer" instance=ExtResource("40_uqw2r")] visible = false layout_mode = 2 - -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralSettings"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LibrarySettingsMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisplaySettings"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/NetworkSettings"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/BluetoothSettingsMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/AudioSettingsMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/DisksMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/PluginSettingsMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/PluginStoreMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/ProcessesMenu"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/LoggingSettings"] -[editable path="MarginContainer/HBoxContainer/ContentContainer/VBoxContainer/ContentContainer/MarginContainer/GeneralControllerSettings"] diff --git a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd index dc837468..c83c7c43 100644 --- a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd +++ b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd @@ -8,6 +8,10 @@ var input_plumber := preload("res://core/systems/input/input_plumber.tres") as I var state_machine := ( preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine ) +var menu_state_machine := preload("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine +var popup_state_machine := preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine +var menu_state := preload("res://assets/state/states/menu.tres") as State +var popup_state := preload("res://assets/state/states/popup.tres") as State var quick_bar_state = preload("res://assets/state/states/quick_bar_menu.tres") as State var settings_state = preload("res://assets/state/states/settings.tres") as State var gamepad_state = preload("res://assets/state/states/gamepad_settings.tres") as State @@ -18,8 +22,7 @@ var PID: int = OS.get_process_id() var args := OS.get_cmdline_user_args() var cmdargs := OS.get_cmdline_args() var display := Gamescope.XWAYLAND.OGUI -var game_running: bool = false -var overlay_window_id: int +var overlay_window_id := gamescope.get_window_id(PID, display) var underlay_log: FileAccess var underlay_process: int var underlay_window_id: int @@ -31,16 +34,13 @@ var logger := Log.get_logger("Main", Log.LEVEL.INFO) ## Sets up overlay mode. func _init(): - - logger.debug("Overlay start _init") - # Tell gamescope that we're an overlay - if overlay_window_id < 0: + # Discover the OpenGamepadUI window ID + if overlay_window_id <= 0: logger.error("Unable to detect Window ID. Overlay is not going to work!") - logger.debug("Found primary window id: {0}".format([overlay_window_id])) + logger.info("Found primary window id: {0}".format([overlay_window_id])) # Back button wont close windows without this. OverlayInputManager prevents poping the last state. state_machine.push_state(base_state) - state_machine.state_changed.connect(_on_no_state) # Ensure LaunchManager doesn't override our custom overlay management l launch_manager.should_manage_overlay = false @@ -53,15 +53,9 @@ func _init(): var plugin_manager := plugin_manager_scene.instantiate() add_child(plugin_manager) - # Listen for home state changes - base_state.state_entered.connect(_on_base_state_entered) - base_state.state_exited.connect(_on_base_state_exited) - logger.debug("Overlay finish _init") - ## Starts the --overlay-mode session. func _ready() -> void: - logger.debug("Overlay start _ready") # Workaround old versions that don't pass launch args via update pack # TODO: Parse the parent PID's CLI args and use those instead. if "--skip-update-pack" in cmdargs and args.size() == 0: @@ -90,7 +84,6 @@ func _ready() -> void: # Set up the session logger.debug("Setup Overlay Mode") _setup_overlay_mode(args) - launch_manager.app_switched.connect(_on_app_switched) # Set the theme if one was set logger.debug("Setup Theme") @@ -114,10 +107,40 @@ func _ready() -> void: ## Finds needed PID's and global vars, Starts the user defined program as an ## underlay process. func _setup_overlay_mode(args: Array) -> void: - overlay_window_id = gamescope.get_window_id(PID, display) - for state in managed_states: - state.state_entered.connect(_on_window_open) - state.state_exited.connect(_on_window_closed) + # Always push the base state if we end up with an empty stack. + var on_states_emptied := func(): + state_machine.push_state.call_deferred(base_state) + state_machine.emptied.connect(on_states_emptied) + + # Whenever the menu state is refreshed, refresh the menu state machine to + # re-grab focus. + var on_menu_refreshed := func(): + menu_state_machine.refresh() + menu_state.refreshed.connect(on_menu_refreshed) + + # Whenever the menu state is entered, refresh the menu state machine to + # re-grab focus + var on_menu_state_entered := func(_from: State): + menu_state_machine.refresh() + menu_state.state_entered.connect(on_menu_state_entered) + var on_menu_state_removed := func(): + menu_state_machine.clear_states() + menu_state.state_removed.connect(on_menu_state_removed) + var on_menu_states_empty := func(): + state_machine.remove_state(menu_state) + menu_state_machine.emptied.connect(on_menu_states_empty) + + # Whenever an popup state is pushed, update the global state + var on_popup_state_changed := func(_from: State, to: State): + if to: + state_machine.push_state(popup_state) + else: + state_machine.remove_state(popup_state) + popup_state_machine.state_changed.connect(on_popup_state_changed) + + # Show/hide the overlay when we enter/exit the in-game state + base_state.state_entered.connect(_on_base_state_entered) + base_state.state_exited.connect(_on_base_state_exited) # Don't crash if we're not launching another program. if args == []: @@ -130,9 +153,6 @@ func _setup_overlay_mode(args: Array) -> void: var log_path := OS.get_environment("HOME") + "/.underlay-stdout.log" _start_underlay_process(args, log_path) - # Establish overlay focus in gamescope. - gamescope.set_overlay(overlay_window_id, 1, display) - # Remove unneeded/conflicting elements from default menues var remove_list: PackedStringArray = ["PerformanceCard", "NotifyButton", "HelpButton", "VolumeSlider", "BrightnessSlider", "PerGameToggle"] _remove_children(remove_list, quick_bar_menu) @@ -218,13 +238,15 @@ func _find_underlay_window_id() -> void: for window in all_windows: if window == overlay_window_id: continue - if gamescope.has_xprop(window, "STEAM_OVERLAY", display): + if gamescope.has_xprop(window, "STEAM_NOTIFICATION", display): underlay_window_id = window - logger.debug("Found steam! " + str(underlay_window_id)) + logger.info("Found steam! " + str(underlay_window_id)) + gamescope.focused_app_updated.connect(_on_app_focus_changed) break # If we didn't find the window_id, set up a tiemr to loop back and try again. - if not underlay_window_id: + if underlay_window_id <= 0: + logger.debug("Unable to find steam PID. Checking again in 1 second...") var underlay_window_timer := Timer.new() underlay_window_timer.set_one_shot(true) underlay_window_timer.set_timer_process_callback(Timer.TIMER_PROCESS_IDLE) @@ -233,37 +255,28 @@ func _find_underlay_window_id() -> void: underlay_window_timer.start() -## Called when "quick_bar_state" is entered. -func _on_window_open(from: State) -> void: - if from: - logger.info("Quick bar open state: " + from.name) - if game_running: - gamescope.set_overlay(overlay_window_id, 1, display) - gamescope.set_overlay(underlay_window_id, 0, display) - - -## Called when "quick_bar_state" is exited. -func _on_window_closed(to: State) -> void: - if to: - logger.info("Quick bar closed state: " + to.name) - if game_running: - gamescope.set_overlay(overlay_window_id, 0, display) - gamescope.set_overlay(underlay_window_id, 1, display) - - -## Called when a RunningApp is changed to another RunningApp, or to no app. -## Changes the overlay focus to the overlay if no game is running or to the -## underlay process if a game is running. -func _on_app_switched(_from: RunningApp, to: RunningApp) -> void: - if to == null: - # Establish overlay focus in gamescope. - gamescope.set_overlay(overlay_window_id, 1, display) - gamescope.set_overlay(underlay_window_id, 0, display) - game_running = false - return +## Called when the base state is entered. +func _on_base_state_entered(from: State) -> void: + # Manage input focus + input_plumber.set_intercept_mode(InputPlumber.INTERCEPT_MODE.PASS) + if gamescope.set_input_focus(overlay_window_id, 0) != OK: + logger.error("Unable to set STEAM_INPUT_FOCUS atom!") + + # Manage overlay gamescope.set_overlay(overlay_window_id, 0, display) gamescope.set_overlay(underlay_window_id, 1, display) - game_running = true + + +## Called when a the base state is exited. +func _on_base_state_exited(to: State) -> void: + # Manage input focus + input_plumber.set_intercept_mode(InputPlumber.INTERCEPT_MODE.ALL) + if gamescope.set_input_focus(overlay_window_id, 1) != OK: + logger.error("Unable to set STEAM_INPUT_FOCUS atom!") + + # Manage overlay + gamescope.set_overlay(overlay_window_id, 1, display) + gamescope.set_overlay(underlay_window_id, 0, display) ## Verifies steam is still running by checking for the steam overlay, closes otherwise. @@ -276,21 +289,16 @@ func _check_exit() -> void: get_tree().quit() -## Sets gamescope input focus to on so the user can interact with the UI -func _on_base_state_exited(_to: State) -> void: - input_plumber.set_intercept_mode(InputPlumber.INTERCEPT_MODE.ALL) - if gamescope.set_input_focus(overlay_window_id, 1) != OK: - logger.error("Unable to set STEAM_INPUT_FOCUS atom!") - - -## Sets gamescope input focus to off so the user can interact with the game -func _on_base_state_entered(_from: State) -> void: - input_plumber.set_intercept_mode(InputPlumber.INTERCEPT_MODE.PASS) - if gamescope.set_input_focus(overlay_window_id, 0) != OK: - logger.error("Unable to set STEAM_INPUT_FOCUS atom!") - +func _on_app_focus_changed(_from: int, to: int) -> void: + # On focus to the steam overlay, ensure the default profile is used. + logger.warn("Changed window focus to app ID:", to) + if to in [Gamescope.OVERLAY_GAME_ID, 0]: + launch_manager.set_gamepad_profile("") + return -## Ensures there is always a state on the state stack. -func _on_no_state(_from: State, to: State) -> void: - if state_machine.stack_length() == 0: - state_machine.push_state(base_state) + # On focus back to the game, ensure the game profile is set + var _current_app := launch_manager.get_current_app() + if not _current_app: + logger.error("Unable to set gamepad profile. Current app is NULL and we aren't focused") + return + launch_manager.set_app_gamepad_profile(_current_app) diff --git a/core/ui/common/debug/processes_menu.tscn b/core/ui/common/debug/processes_menu.tscn index 5821b3ce..363393f6 100644 --- a/core/ui/common/debug/processes_menu.tscn +++ b/core/ui/common/debug/processes_menu.tscn @@ -1,10 +1,15 @@ -[gd_scene load_steps=6 format=3 uid="uid://bfu4edkk5dqt2"] +[gd_scene load_steps=11 format=3 uid="uid://bfu4edkk5dqt2"] [ext_resource type="Script" path="res://core/ui/common/debug/processes_menu.gd" id="1_i5gve"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="2_t6r8e"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_tbk5a"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="3_2ttlw"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="4_1h6bm"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_10x0l"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_dva4v"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_cqojd"] [ext_resource type="Script" path="res://core/systems/input/focus_group.gd" id="5_nqvca"] +[ext_resource type="Resource" uid="uid://cffkiat2h10ms" path="res://assets/state/states/settings_processes.tres" id="6_kfvag"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_use1k"] [node name="ProcessesMenu" type="Control"] layout_mode = 3 @@ -15,6 +20,23 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_i5gve") +[node name="InputWatcher" parent="." instance=ExtResource("2_tbk5a")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_10x0l")] +state_machine = ExtResource("4_dva4v") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_cqojd")] +state = ExtResource("6_kfvag") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_use1k") +target = NodePath("../../MarginContainer/VBoxContainer/HBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="RefreshTimer" type="Timer" parent="."] [node name="MarginContainer" type="MarginContainer" parent="."] @@ -38,7 +60,6 @@ size_flags_vertical = 3 [node name="FocusGroup" parent="MarginContainer/VBoxContainer/HBoxContainer" node_paths=PackedStringArray("current_focus", "focus_neighbor_right") instance=ExtResource("3_2ttlw")] current_focus = NodePath("../PIDInspector") -focus_stack = ExtResource("4_1h6bm") focus_neighbor_right = NodePath("../MarginContainer/VBoxContainer/FocusGroup") [node name="PIDInspector" type="Tree" parent="MarginContainer/VBoxContainer/HBoxContainer"] diff --git a/core/ui/common/osk/on_screen_keyboard.gd b/core/ui/common/osk/on_screen_keyboard.gd index b332bb36..0d26da6d 100644 --- a/core/ui/common/osk/on_screen_keyboard.gd +++ b/core/ui/common/osk/on_screen_keyboard.gd @@ -10,6 +10,12 @@ signal closed const Gamescope := preload("res://core/global/gamescope.tres") const key_scene := preload("res://core/ui/components/button.tscn") + +## State machine to use to switch menu states in response to input events. +var popup_state_machine := ( + preload("res://assets/state/state_machines/popup_state_machine.tres") as StateMachine +) +var osk_state := preload("res://assets/state/states/osk.tres") as State var input_icons := load("res://core/systems/input/input_icon_manager.tres") as InputIconManager # Different states of mode shift (i.e. when the user presses "shift" or "caps") @@ -28,6 +34,9 @@ var logger := Log.get_logger("OSK") # Called when the node enters the scene tree for the first time. func _ready() -> void: + # Don't run in the editor + if Engine.is_editor_hint(): + return if not layout: logger.warn("No keyboard layout was defined") return @@ -155,8 +164,6 @@ func _nearest_neighbor(idx: int, from_size: int, to_size: int) -> int: # Opens the OSK with the given context. The keyboard context determines where # keyboard inputs should go, and how to handle submits. func open() -> void: - visible = true - # Grab focus on the first key in the first row for r in rows_container.get_children(): var row := r as HBoxContainer @@ -190,7 +197,7 @@ func open() -> void: # Closes the OSK func close() -> void: - visible = false + popup_state_machine.remove_state(osk_state) closed.emit() @@ -209,13 +216,16 @@ func set_mode_shift(mode: MODE_SHIFT) -> void: # Handle gamepad keyboard shortcuts func _input(event: InputEvent) -> void: - if not visible: + if not is_visible_in_tree(): return - if event.is_action_pressed("ogui_east"): + # Block propagation of any input if guide is held, avoids conflicts. + if Input.is_action_pressed("ogui_guide"): + return + if event.is_action_released("ogui_east"): instance.close() get_viewport().set_input_as_handled() return - if event.is_action_pressed("ogui_north"): + if event.is_action_released("ogui_north"): var key := KeyboardKeyConfig.new() key.input = InputEventKey.new() key.input.keycode = KEY_BACKSPACE diff --git a/core/ui/common/settings/audio_settings_menu.tscn b/core/ui/common/settings/audio_settings_menu.tscn index 078e257a..5cf0ea86 100644 --- a/core/ui/common/settings/audio_settings_menu.tscn +++ b/core/ui/common/settings/audio_settings_menu.tscn @@ -1,11 +1,16 @@ -[gd_scene load_steps=7 format=3] +[gd_scene load_steps=12 format=3 uid="uid://b4uvvjgnbxj25"] [ext_resource type="Script" path="res://core/ui/common/settings/audio_settings_menu.gd" id="1_hjnkk"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="1_x5cm4"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_73ivm"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_n36nh"] [ext_resource type="PackedScene" uid="uid://cemxrvvjgm4g" path="res://core/ui/components/slider.tscn" id="2_qsi2y"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_pfahh"] [ext_resource type="PackedScene" uid="uid://xei5afwefxud" path="res://core/ui/components/dropdown.tscn" id="3_pixnq"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_r3dmc"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_sfspm"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_06jyg"] +[ext_resource type="Resource" uid="uid://bdvbnao6j0o18" path="res://assets/state/states/settings_audio.tres" id="6_v2pqc"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_l6bmd"] [node name="AudioSettingsMenu" type="MarginContainer"] anchors_preset = 15 @@ -19,13 +24,29 @@ theme_override_constants/margin_right = 5 theme_override_constants/margin_bottom = 5 script = ExtResource("1_hjnkk") +[node name="InputWatcher" parent="." instance=ExtResource("2_n36nh")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_r3dmc")] +state_machine = ExtResource("4_sfspm") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_06jyg")] +state = ExtResource("6_v2pqc") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_l6bmd") +target = NodePath("../../VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 2 size_flags_horizontal = 3 [node name="FocusGroup" parent="VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("2_73ivm")] current_focus = NodePath("../VolumeSlider") -focus_stack = ExtResource("3_pfahh") [node name="AudioLabel" parent="VBoxContainer" instance=ExtResource("1_x5cm4")] layout_mode = 2 diff --git a/core/ui/common/settings/display_settings_menu.gd b/core/ui/common/settings/display_settings_menu.gd index 32aa33ca..09f45a3b 100644 --- a/core/ui/common/settings/display_settings_menu.gd +++ b/core/ui/common/settings/display_settings_menu.gd @@ -1,17 +1,26 @@ extends Control -var SettingsManager := load("res://core/global/settings_manager.tres") as SettingsManager -@onready var scale_slider := $%ScaleSlider +var settings_manager := load("res://core/global/settings_manager.tres") as SettingsManager +@onready var scale_slider := $%ScaleSlider as ValueSlider +@onready var blur_toggle := $%BlurToggle as Toggle # Called when the node enters the scene tree for the first time. func _ready() -> void: - var display_scale := SettingsManager.get_value("display", "scale", 1.0) as float + var display_scale := settings_manager.get_value("display", "scale", 1.0) as float scale_slider.value = display_scale get_window().content_scale_factor = display_scale scale_slider.value_changed.connect(_on_scale_changed) + + var blur_enabled := settings_manager.get_value("display", "enable_overlay_blur", true) as bool + blur_toggle.button_pressed = blur_enabled + blur_toggle.toggled.connect(_on_blur_toggled) func _on_scale_changed(value: float) -> void: get_window().content_scale_factor = value - SettingsManager.set_value("display", "scale", value) + settings_manager.set_value("display", "scale", value) + + +func _on_blur_toggled(pressed: bool) -> void: + settings_manager.set_value("display", "enable_overlay_blur", pressed) diff --git a/core/ui/common/settings/display_settings_menu.tscn b/core/ui/common/settings/display_settings_menu.tscn index ad9ac155..8f095b57 100644 --- a/core/ui/common/settings/display_settings_menu.tscn +++ b/core/ui/common/settings/display_settings_menu.tscn @@ -1,11 +1,17 @@ -[gd_scene load_steps=7 format=3 uid="uid://521da7e2cdxd"] +[gd_scene load_steps=13 format=3 uid="uid://521da7e2cdxd"] [ext_resource type="Script" path="res://core/ui/common/settings/display_settings_menu.gd" id="1_w4xaq"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_jrm6t"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_oj3r7"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_aiw87"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="3_nmfgp"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_rrkak"] [ext_resource type="PackedScene" uid="uid://cemxrvvjgm4g" path="res://core/ui/components/slider.tscn" id="4_fpepf"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_m2akb"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_m7ryc"] +[ext_resource type="Resource" uid="uid://bfx7p4n4fhjwd" path="res://assets/state/states/settings_display.tres" id="6_5275c"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="6_hgrqi"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_tlkhc"] +[ext_resource type="PackedScene" uid="uid://d1qb7euwlu7bh" path="res://core/ui/components/toggle.tscn" id="11_a21ac"] [node name="DisplaySettings" type="ScrollContainer"] anchors_preset = 15 @@ -17,6 +23,23 @@ size_flags_horizontal = 3 size_flags_vertical = 3 script = ExtResource("1_w4xaq") +[node name="InputWatcher" parent="." instance=ExtResource("2_jrm6t")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_aiw87")] +state_machine = ExtResource("4_m2akb") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_m7ryc")] +state = ExtResource("6_5275c") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_tlkhc") +target = NodePath("../../VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 2 size_flags_horizontal = 3 @@ -24,7 +47,6 @@ size_flags_vertical = 3 [node name="FocusGroup" parent="VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("2_oj3r7")] current_focus = NodePath("../ScaleSlider") -focus_stack = ExtResource("3_rrkak") [node name="DisplayLabel" parent="VBoxContainer" instance=ExtResource("3_nmfgp")] layout_mode = 2 @@ -37,9 +59,24 @@ layout_mode = 2 unique_name_in_owner = true layout_mode = 2 text = "Scale" -value = 1.2 -max_value = 5.0 +value = 1.0 +max_value = 3.0 min_value = 0.2 -step = 0.2 +step = 0.02 + +[node name="OverlayLabel" parent="VBoxContainer" instance=ExtResource("3_nmfgp")] +layout_mode = 2 +text = "Overlay" + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="BlurToggle" parent="VBoxContainer" instance=ExtResource("11_a21ac")] +unique_name_in_owner = true +layout_mode = 2 +text = "Blur" +separator_visible = false +description = "Blur background game when overlay is open" +button_pressed = true [node name="ScrollerJoystick" parent="." instance=ExtResource("6_hgrqi")] diff --git a/core/ui/common/settings/logging_settings_menu.tscn b/core/ui/common/settings/logging_settings_menu.tscn index 4dfabc1b..8093e0ea 100644 --- a/core/ui/common/settings/logging_settings_menu.tscn +++ b/core/ui/common/settings/logging_settings_menu.tscn @@ -1,11 +1,16 @@ -[gd_scene load_steps=8 format=3 uid="uid://csor0e54svgja"] +[gd_scene load_steps=13 format=3 uid="uid://csor0e54svgja"] [ext_resource type="Script" path="res://core/ui/common/settings/logging_settings_menu.gd" id="1_qleso"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_5va5m"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_qmfyc"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_w6ipu"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_86i0s"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="3_udmnv"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_hqn56"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="5_6uj1s"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_ufggl"] +[ext_resource type="Resource" uid="uid://cakuo0qwrrkk8" path="res://assets/state/states/settings_logging.tres" id="6_3ewnc"] [ext_resource type="PackedScene" uid="uid://xei5afwefxud" path="res://core/ui/components/dropdown.tscn" id="6_ljvn8"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_2p4q3"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="7_fbxhf"] [node name="LoggingSettings" type="ScrollContainer"] @@ -19,6 +24,23 @@ size_flags_vertical = 3 follow_focus = true script = ExtResource("1_qleso") +[node name="InputWatcher" parent="." instance=ExtResource("2_w6ipu")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_86i0s")] +state_machine = ExtResource("4_hqn56") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_ufggl")] +state = ExtResource("6_3ewnc") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_2p4q3") +target = NodePath("../../MarginContainer/VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 size_flags_horizontal = 3 @@ -37,7 +59,6 @@ size_flags_vertical = 3 [node name="FocusGroup" parent="MarginContainer/VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("2_5va5m")] unique_name_in_owner = true current_focus = NodePath("../GlobalDropdown") -focus_stack = ExtResource("3_qmfyc") [node name="LoggingLabel" parent="MarginContainer/VBoxContainer" instance=ExtResource("3_udmnv")] layout_mode = 2 diff --git a/core/ui/common/settings/network_settings_menu.tscn b/core/ui/common/settings/network_settings_menu.tscn index c6df6cd2..8ea0ed6d 100644 --- a/core/ui/common/settings/network_settings_menu.tscn +++ b/core/ui/common/settings/network_settings_menu.tscn @@ -1,12 +1,17 @@ -[gd_scene load_steps=10 format=3 uid="uid://cpss2bhdwm8t7"] +[gd_scene load_steps=15 format=3 uid="uid://cpss2bhdwm8t7"] [ext_resource type="Script" path="res://core/ui/common/settings/network_settings_menu.gd" id="1_2qdps"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="2_8jmkq"] +[ext_resource type="PackedScene" uid="uid://c6fg6uvng0ovi" path="res://core/systems/input/input_watcher.tscn" id="2_yj01k"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="3_ddyy1"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="3_emyir"] +[ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="3_hbsyi"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="4_t7br0"] +[ext_resource type="Resource" uid="uid://iqrotrmq62i6" path="res://assets/state/state_machines/settings_state_machine.tres" id="4_tf04q"] +[ext_resource type="PackedScene" uid="uid://shvyhrv5sx3v" path="res://core/systems/state/state_watcher.tscn" id="5_jobhc"] [ext_resource type="PackedScene" uid="uid://df5o1o2dsik84" path="res://core/ui/components/button.tscn" id="5_round"] [ext_resource type="Theme" uid="uid://bko0q7gp1hwjp" path="res://assets/themes/dracula.tres" id="6_i7u1a"] +[ext_resource type="Resource" uid="uid://2efht48q7i6v" path="res://assets/state/states/settings_network.tres" id="6_ke40f"] +[ext_resource type="Script" path="res://core/systems/input/focus_group_setter.gd" id="7_gnxgo"] [ext_resource type="PackedScene" uid="uid://d1rjdfxxrdccf" path="res://core/ui/components/text_input.tscn" id="7_qx5i7"] [ext_resource type="PackedScene" uid="uid://b0cyl6fdqxevn" path="res://core/systems/input/scroller_joystick.tscn" id="9_v6vet"] @@ -20,6 +25,23 @@ size_flags_horizontal = 3 size_flags_vertical = 3 script = ExtResource("1_2qdps") +[node name="InputWatcher" parent="." instance=ExtResource("2_yj01k")] +stop_propagation = true +action = "ogui_east" + +[node name="StateUpdater" parent="InputWatcher" instance=ExtResource("3_hbsyi")] +state_machine = ExtResource("4_tf04q") +action = 2 +on_signal = "input_released" + +[node name="StateWatcher" parent="." instance=ExtResource("5_jobhc")] +state = ExtResource("6_ke40f") + +[node name="FocusGroupSetter" type="Node" parent="StateWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("7_gnxgo") +target = NodePath("../../MarginContainer/VBoxContainer/FocusGroup") +on_signal = "state_entered" + [node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 size_flags_horizontal = 3 @@ -34,7 +56,6 @@ size_flags_vertical = 3 [node name="FocusGroup" parent="MarginContainer/VBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("2_8jmkq")] current_focus = NodePath("../RefreshButton") -focus_stack = ExtResource("3_emyir") [node name="NoNetworkLabel" parent="MarginContainer/VBoxContainer" instance=ExtResource("4_t7br0")] unique_name_in_owner = true diff --git a/core/ui/components/card_button.gd b/core/ui/components/card_button.gd index e3c19967..8ece6bef 100644 --- a/core/ui/components/card_button.gd +++ b/core/ui/components/card_button.gd @@ -71,7 +71,10 @@ func _ready() -> void: label.vertical_alignment = vertical_alignment label.autowrap_mode = autowrap_mode label.uppercase = uppercase - + + if Engine.is_editor_hint(): + return + # Connect signals pressed.connect(_play_sound.bind(select_audio_stream)) focus_entered.connect(_on_focus) @@ -79,7 +82,11 @@ func _ready() -> void: mouse_entered.connect(_on_focus) mouse_exited.connect(_on_unfocus) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: diff --git a/core/ui/components/card_button.tscn b/core/ui/components/card_button.tscn index bfa1138f..51a3f885 100644 --- a/core/ui/components/card_button.tscn +++ b/core/ui/components/card_button.tscn @@ -1,19 +1,7 @@ -[gd_scene load_steps=4 format=3 uid="uid://c71ayw7pcw6u6"] +[gd_scene load_steps=2 format=3 uid="uid://c71ayw7pcw6u6"] [ext_resource type="Script" path="res://core/ui/components/card_button.gd" id="1_62nf7"] -[sub_resource type="Image" id="Image_u87yt"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_ax6fu"] -image = SubResource("Image_u87yt") - [node name="CardButton" type="PanelContainer"] clip_children = 2 offset_right = 103.0 @@ -26,7 +14,6 @@ script = ExtResource("1_62nf7") unique_name_in_owner = true visible = false layout_mode = 2 -texture = SubResource("ImageTexture_ax6fu") expand_mode = 1 stretch_mode = 6 diff --git a/core/ui/components/card_icon_button.gd b/core/ui/components/card_icon_button.gd index d596f723..6f7cdbb1 100644 --- a/core/ui/components/card_icon_button.gd +++ b/core/ui/components/card_icon_button.gd @@ -35,7 +35,10 @@ var select_audio_stream = load(select_audio) func _ready() -> void: # Configure the icon icon.texture = texture - + + if Engine.is_editor_hint(): + return + # Connect signals pressed.connect(_play_sound.bind(select_audio_stream)) focus_entered.connect(_on_focus) @@ -43,7 +46,11 @@ func _ready() -> void: mouse_entered.connect(_on_focus) mouse_exited.connect(_on_unfocus) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: diff --git a/core/ui/components/card_input_icon_button.gd b/core/ui/components/card_input_icon_button.gd index 668478d7..1897d0ec 100644 --- a/core/ui/components/card_input_icon_button.gd +++ b/core/ui/components/card_input_icon_button.gd @@ -22,7 +22,11 @@ var logger := Log.get_logger("CardInputIconButton") func _ready() -> void: # Connect signals theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: diff --git a/core/ui/components/card_mapping_button.gd b/core/ui/components/card_mapping_button.gd index f65ff86c..d8ca680c 100644 --- a/core/ui/components/card_mapping_button.gd +++ b/core/ui/components/card_mapping_button.gd @@ -66,10 +66,17 @@ func _ready() -> void: target_label.vertical_alignment = vertical_alignment target_label.autowrap_mode = autowrap_mode target_label.uppercase = uppercase - + + if Engine.is_editor_hint(): + return + # Connect signals theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() ## Set the source input icon's icon mapping diff --git a/core/ui/components/card_mapping_button.tscn b/core/ui/components/card_mapping_button.tscn index 75a65eec..639f7f80 100644 --- a/core/ui/components/card_mapping_button.tscn +++ b/core/ui/components/card_mapping_button.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=8 format=3 uid="uid://dbll03tbmw3ps"] +[gd_scene load_steps=6 format=3 uid="uid://dbll03tbmw3ps"] [ext_resource type="Script" path="res://core/ui/components/card_mapping_button.gd" id="1_qi6wi"] [ext_resource type="Script" path="res://core/ui/components/input_icon.gd" id="2_d8vnj"] @@ -6,18 +6,6 @@ [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="3_h1m7y"] [ext_resource type="Texture2D" uid="uid://da6kcs5mhssov" path="res://assets/ui/icons/arrow-right-bold.svg" id="4_gjhmn"] -[sub_resource type="Image" id="Image_6pbp1"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_sa6yd"] -image = SubResource("Image_6pbp1") - [node name="CardMappingButton" type="MarginContainer"] editor_description = "Button used for mapping gamepad inputs" anchors_preset = 15 @@ -57,7 +45,6 @@ theme_type_variation = &"CardButton" unique_name_in_owner = true visible = false layout_mode = 2 -texture = SubResource("ImageTexture_sa6yd") expand_mode = 1 stretch_mode = 6 diff --git a/core/ui/components/dialog.gd b/core/ui/components/dialog.gd index 660d01a1..55f499df 100644 --- a/core/ui/components/dialog.gd +++ b/core/ui/components/dialog.gd @@ -37,11 +37,11 @@ signal choice_selected(accepted: bool) @export var close_on_selected := true @onready var label := $%Label as Label -@onready var confirm_button := $%ConfirmButton as Button -@onready var cancel_button := $%CancelButton as Button +@onready var confirm_button := $%ConfirmButton as CardButton +@onready var cancel_button := $%CancelButton as CardButton @onready var fade_effect := $%FadeEffect as Effect - +var _return_node: Control = null # Called when the node enters the scene tree for the first time. func _ready() -> void: confirm_button.button_up.connect(_on_selected.bind(true)) @@ -53,17 +53,20 @@ func _on_selected(accepted: bool) -> void: if close_on_selected: closed.emit() choice_selected.emit(accepted) + if _return_node: + _return_node.grab_focus.call_deferred() + _return_node = null ## Opens the dialog box with the given settings -func open(message: String = "", confirm_txt: String = "", cancel_txt: String = "") -> void: +func open(return_node: Control, message: String = "", confirm_txt: String = "", cancel_txt: String = "") -> void: if message != "": text = message if confirm_txt != "": confirm_text = confirm_txt if cancel_txt != "": cancel_text = cancel_txt - + _return_node = return_node opened.emit() await fade_effect.effect_finished confirm_button.grab_focus.call_deferred() diff --git a/core/ui/components/dialog.tscn b/core/ui/components/dialog.tscn index be8a4137..158d6a68 100644 --- a/core/ui/components/dialog.tscn +++ b/core/ui/components/dialog.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=5 format=3 uid="uid://eqqk1uve143x"] +[gd_scene load_steps=6 format=3 uid="uid://eqqk1uve143x"] [ext_resource type="Script" path="res://core/ui/components/dialog.gd" id="1_yqaeg"] [ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="2_q0yos"] [ext_resource type="PackedScene" uid="uid://ekhjpmat02f8" path="res://core/systems/effects/slide_effect.tscn" id="3_hbrr5"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="4_vp527"] +[ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="5_clb01"] [node name="Dialog" type="Control" groups=["dialog", "popup"]] editor_description = "Opens a dialog choice to the user." @@ -80,26 +81,10 @@ alignment = 1 [node name="FocusGroup" parent="Spacer/CenterContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("4_vp527")] -[node name="CancelButton" type="Button" parent="Spacer/CenterContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/HBoxContainer"] +[node name="CancelButton" parent="Spacer/CenterContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("5_clb01")] unique_name_in_owner = true layout_mode = 2 -size_flags_horizontal = 3 -focus_neighbor_left = NodePath("../ConfirmButton") -focus_neighbor_top = NodePath(".") -focus_neighbor_right = NodePath("../ConfirmButton") -focus_neighbor_bottom = NodePath(".") -focus_next = NodePath("../ConfirmButton") -focus_previous = NodePath("../ConfirmButton") -text = "No" -[node name="ConfirmButton" type="Button" parent="Spacer/CenterContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/HBoxContainer"] +[node name="ConfirmButton" parent="Spacer/CenterContainer/PanelContainer/MarginContainer/VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("5_clb01")] unique_name_in_owner = true layout_mode = 2 -size_flags_horizontal = 3 -focus_neighbor_left = NodePath("../CancelButton") -focus_neighbor_top = NodePath(".") -focus_neighbor_right = NodePath("../CancelButton") -focus_neighbor_bottom = NodePath(".") -focus_next = NodePath("../CancelButton") -focus_previous = NodePath("../CancelButton") -text = "Yes" diff --git a/core/ui/components/drive_card.gd b/core/ui/components/drive_card.gd index 33790888..12cce13f 100644 --- a/core/ui/components/drive_card.gd +++ b/core/ui/components/drive_card.gd @@ -15,6 +15,10 @@ var device: BlockDevice var device_path: String var highlight_tween: Tween +signal pressed +signal button_up +signal button_down +signal nonchild_focused signal format_drive(device: BlockDevice) signal format_sd_card signal init_partition(device: PartitionDevice) @@ -24,8 +28,9 @@ signal init_partition(device: PartitionDevice) @onready var drive_icon: TextureRect = $%IconTextureRect @onready var drive_focus_group: FocusGroup = $%DriveFocusGroup @onready var format_button: CardButton = $%FormatButton -@onready var partitions_container: VBoxContainer = $%PartitionsVBox +@onready var partitions_container: HBoxContainer = $%PartitionsHBox @onready var partitions_focus_group: FocusGroup = $%PartitionsFocusGroup +@onready var highlight := $%HighlightTexture as TextureRect var logger: Logger var log_level:= Log.LEVEL.INFO @@ -36,6 +41,7 @@ func setup(device: BlockDevice) -> void: # Setup UDisks2 information self.device = device self.device_path = "/dev" + self.device.dbus_path.trim_prefix(steam_disks.BLOCK_PREFIX) + logger = Log.get_logger("DriveCard|"+self.device_path, log_level) logger.debug("Setup Drive Card") drive_name_label.text = self.device_path @@ -52,20 +58,30 @@ func setup(device: BlockDevice) -> void: format_button.pressed.disconnect(_srm_format_drive) format_button.visible = true + var on_focus_exited := func(): + self._on_unfocus.call_deferred() + focus_exited.connect(on_focus_exited) + theme_changed.connect(_on_theme_changed) + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() + func _srm_format_drive() -> void: + if steam_disks.block_operations: + logger.debug("Format operation blocked.") + return + var dialog := get_tree().get_first_node_in_group("dialog") as Dialog var msg := "WARNING: All data on " + device_path + " device will be wiped. " + \ "This action cannot be undone. Do you wish to continue?" - dialog.open(msg, "Cancel", "Continue Format") + dialog.open(format_button, msg, "Cancel", "Continue Format") var cancel := await dialog.choice_selected as bool if cancel: return - if steam_disks.block_operations: - logger.debug("Format operation blocked.") - return - logger.debug("Format Drive", device_path) _clear_partitions() _on_format_started() @@ -76,18 +92,18 @@ func _srm_format_drive() -> void: func _srm_format_sd_card() -> void: + if steam_disks.block_operations: + logger.debug("Format operation blocked.") + return + var dialog := get_tree().get_first_node_in_group("dialog") as Dialog var msg := "WARNING: All data on " + device_path + " device will be wiped. " + \ "This action cannot be undone. Do you wish to continue?" - dialog.open(msg, "Cancel", "Continue Format") + dialog.open(format_button, msg, "Cancel", "Continue Format") var cancel := await dialog.choice_selected as bool if cancel: return - if steam_disks.block_operations: - logger.debug("Format operation blocked.") - return - logger.debug("Format SD Card", device_path) _clear_partitions() _on_format_started() @@ -116,7 +132,6 @@ func _srm_init_drive(partition: PartitionDevice) -> void: init_partition.emit(partition) - func _clear_partitions() -> void: # Clear the current grid of items var keep_nodes := [partitions_focus_group] @@ -150,9 +165,54 @@ func _populate_partitions() -> void: _clear_partitions() var last_focus: FocusGroup for partition in self.device.partitions: + + # Ignore loop devices + if partition.partition_name.contains("/dev/loop"): + continue + logger.debug("Drive has partition to set up:", partition.dbus_path) var partition_card := partition_card_scene.instantiate() as PartitionCard partitions_container.add_child(partition_card) partition_card.setup(partition) partition_card.visible = true partition_card.init_partition.connect(_srm_init_drive) + + +# Update the highlight texture on theme change +func _on_theme_changed() -> void: + # Configure the highlight texture from the theme + var highlight_texture := get_theme_icon("highlight", "ExpandableCard") + if highlight_texture: + highlight.texture = highlight_texture + + +func _gui_input(event: InputEvent) -> void: + if event.is_action("ui_accept"): + if event.is_pressed(): + button_down.emit() + pressed.emit() + else: + button_up.emit() + +func _on_unfocus() -> void: + # Emit a signal if a non-child node grabs focus + var focus_owner := get_viewport().gui_get_focus_owner() + if not self.is_ancestor_of(focus_owner): + nonchild_focused.emit() + return + + # If a child has focus, listen for focus changes until a non-child has focus + get_viewport().gui_focus_changed.connect(_on_focus_change) + + +func _on_focus_change(focused: Control) -> void: + # Don't do anything if the focused node is a child + if self.is_ancestor_of(focused): + return + + # If a non-child has focus, emit a signal to indicate that this node and none + # of its children have focus. + nonchild_focused.emit() + var viewport := get_viewport() + if viewport.gui_focus_changed.is_connected(_on_focus_change): + viewport.gui_focus_changed.disconnect(_on_focus_change) diff --git a/core/ui/components/drive_card.tscn b/core/ui/components/drive_card.tscn index 5a3b7066..a1a06426 100644 --- a/core/ui/components/drive_card.tscn +++ b/core/ui/components/drive_card.tscn @@ -1,16 +1,74 @@ -[gd_scene load_steps=6 format=3 uid="uid://caeaxm6st4a4u"] +[gd_scene load_steps=13 format=3 uid="uid://caeaxm6st4a4u"] [ext_resource type="Script" path="res://core/ui/components/drive_card.gd" id="1_jlhco"] +[ext_resource type="PackedScene" uid="uid://c5sfkhrfbao71" path="res://core/systems/effects/play_audio_effect.tscn" id="2_kr6y1"] [ext_resource type="Texture2D" uid="uid://bidhj1jikg827" path="res://assets/icons/interface-hdd.svg" id="2_uf6p1"] [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="3_84mee"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="3_aof0c"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="3_c72py"] [ext_resource type="PackedScene" uid="uid://bkdsn268g6hx7" path="res://core/ui/components/partition_card.tscn" id="4_wgas0"] +[ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="4_y8uw0"] +[ext_resource type="Script" path="res://core/systems/input/input_watcher.gd" id="5_7gf3k"] +[ext_resource type="Script" path="res://core/systems/input/focus_setter.gd" id="6_gomk5"] + +[sub_resource type="Gradient" id="Gradient_2e33l"] +colors = PackedColorArray(0.741176, 0.576471, 0.976471, 1, 1, 0.47451, 0.776471, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_ag6ju"] +gradient = SubResource("Gradient_2e33l") +fill = 1 +fill_to = Vector2(1, 2) [node name="DriveCard" type="MarginContainer"] custom_minimum_size = Vector2(340, 200) +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 209.0 +grow_horizontal = 2 +focus_mode = 2 script = ExtResource("1_jlhco") -[node name="BackgroundPanel" type="PanelContainer" parent="."] +[node name="PlayFocusAudioEffect" parent="." instance=ExtResource("2_kr6y1")] +on_signal = "focus_entered" + +[node name="PlaySelectedAudioEffect" parent="." instance=ExtResource("2_kr6y1")] +audio = "res://assets/audio/interface/select_002.ogg" +on_signal = "pressed" + +[node name="HighlightFadeEffect" parent="." node_paths=PackedStringArray("target") instance=ExtResource("3_aof0c")] +target = NodePath("../PanelContainer/HighlightTexture") +on_signal = "focus_entered" +fade_out_signal = "nonchild_focused" +on_signal = "focus_entered" + +[node name="FocusGroupSetter" parent="." node_paths=PackedStringArray("target") instance=ExtResource("4_y8uw0")] +target = NodePath("../EdgeMarginContainer/LayoutHBox/DriveDataVBox/DriveFocusGroup") +on_signal = "button_up" + +[node name="PanelContainer" type="PanelContainer" parent="."] +clip_children = 2 +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_type_variation = &"PluginStoreCard" + +[node name="HighlightTexture" type="TextureRect" parent="PanelContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +texture = SubResource("GradientTexture2D_ag6ju") +expand_mode = 1 +stretch_mode = 6 + +[node name="InsidePanelMargin" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="InsidePanel" type="Panel" parent="InsidePanelMargin"] +unique_name_in_owner = true layout_mode = 2 theme_type_variation = &"PluginStoreCard" @@ -25,6 +83,16 @@ theme_override_constants/margin_bottom = 20 layout_mode = 2 theme_override_constants/separation = 20 +[node name="InputWatcher" type="Node" parent="EdgeMarginContainer/LayoutHBox"] +script = ExtResource("5_7gf3k") +stop_propagation = true +action = "ogui_east" + +[node name="FocusSetter" type="Node" parent="EdgeMarginContainer/LayoutHBox/InputWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("6_gomk5") +target = NodePath("../../../..") +on_signal = "input_released" + [node name="IconTextureRect" type="TextureRect" parent="EdgeMarginContainer/LayoutHBox"] unique_name_in_owner = true custom_minimum_size = Vector2(40, 40) @@ -51,28 +119,30 @@ layout_mode = 2 text = "1337 Gb" horizontal_alignment = 2 +[node name="Control" type="Control" parent="EdgeMarginContainer/LayoutHBox/DriveDataVBox"] +layout_mode = 2 +size_flags_vertical = 3 + [node name="FormatButton" parent="EdgeMarginContainer/LayoutHBox/DriveDataVBox" instance=ExtResource("3_84mee")] unique_name_in_owner = true visible = false layout_mode = 2 text = "Format Drive" -[node name="HBoxContainer" type="HBoxContainer" parent="EdgeMarginContainer/LayoutHBox/DriveDataVBox"] -layout_mode = 2 - [node name="DriveFocusGroup" parent="EdgeMarginContainer/LayoutHBox/DriveDataVBox" node_paths=PackedStringArray("focus_neighbor_right") instance=ExtResource("3_c72py")] unique_name_in_owner = true -focus_neighbor_right = NodePath("../../PartitionsVBox/PartitionsFocusGroup") +focus_neighbor_right = NodePath("../../PartitionsHBox/PartitionsFocusGroup") -[node name="PartitionsVBox" type="VBoxContainer" parent="EdgeMarginContainer/LayoutHBox"] +[node name="PartitionsHBox" type="HBoxContainer" parent="EdgeMarginContainer/LayoutHBox"] unique_name_in_owner = true layout_mode = 2 size_flags_vertical = 4 theme_override_constants/separation = 20 -[node name="PartitionsFocusGroup" parent="EdgeMarginContainer/LayoutHBox/PartitionsVBox" node_paths=PackedStringArray("focus_neighbor_left") instance=ExtResource("3_c72py")] +[node name="PartitionsFocusGroup" parent="EdgeMarginContainer/LayoutHBox/PartitionsHBox" node_paths=PackedStringArray("focus_neighbor_left", "focus_neighbor_right") instance=ExtResource("3_c72py")] unique_name_in_owner = true focus_neighbor_left = NodePath("../../DriveDataVBox/DriveFocusGroup") +focus_neighbor_right = NodePath("../../DriveDataVBox/DriveFocusGroup") -[node name="PartitionCard" parent="EdgeMarginContainer/LayoutHBox/PartitionsVBox" instance=ExtResource("4_wgas0")] +[node name="PartitionCard" parent="EdgeMarginContainer/LayoutHBox/PartitionsHBox" instance=ExtResource("4_wgas0")] layout_mode = 2 diff --git a/core/ui/components/dropdown.gd b/core/ui/components/dropdown.gd index 5e3920f6..5955cb3a 100644 --- a/core/ui/components/dropdown.gd +++ b/core/ui/components/dropdown.gd @@ -41,16 +41,18 @@ signal item_selected(index: int) # Called when the node enters the scene tree for the first time. func _ready() -> void: - focus_entered.connect(_grab_focus) label.text = title description_label.text = description option_button.disabled = disabled + if Engine.is_editor_hint(): + return option_button.focus_neighbor_bottom = focus_neighbor_bottom option_button.focus_neighbor_left = focus_neighbor_left option_button.focus_neighbor_right = focus_neighbor_right option_button.focus_neighbor_top = focus_neighbor_top option_button.focus_previous = focus_previous option_button.focus_next = focus_next + focus_entered.connect(_grab_focus) # Hide labels if nothing is specified if title == "": @@ -76,10 +78,12 @@ func _ready() -> void: option_button.select(focused_item) option_button.item_selected.emit(focused_item) option_popup.visible = false - if event.is_action_pressed("ogui_east") \ - or event.is_action_pressed("ogui_back") \ - or event.is_action_pressed("ogui_east_ov"): + get_viewport().set_input_as_handled() + if event.is_action_released("ogui_east") \ + or event.is_action_released("ogui_back") \ + or event.is_action_released("ogui_east_ov"): option_popup.visible = false + get_viewport().set_input_as_handled() option_popup.window_input.connect(on_option_button_input) diff --git a/core/ui/components/expandable_card.gd b/core/ui/components/expandable_card.gd index a1786c14..cbee0d13 100644 --- a/core/ui/components/expandable_card.gd +++ b/core/ui/components/expandable_card.gd @@ -30,7 +30,12 @@ func _ready() -> void: focus_exited.connect(_on_unfocus) pressed.connect(_on_pressed) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() + label.text = title # Do nothing if running in the editor diff --git a/core/ui/components/input_icon.gd b/core/ui/components/input_icon.gd index b4711e1d..099ba1d3 100644 --- a/core/ui/components/input_icon.gd +++ b/core/ui/components/input_icon.gd @@ -105,6 +105,9 @@ var internal_children: Array[Node] = [] texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED func _ready(): + # Don't run in the editor + if Engine.is_editor_hint(): + return # Add the children self.add_child(label) # Only listen for input type changes if no mapping is forced diff --git a/core/ui/components/partition_card.gd b/core/ui/components/partition_card.gd index efc3bb9f..81e885ce 100644 --- a/core/ui/components/partition_card.gd +++ b/core/ui/components/partition_card.gd @@ -41,7 +41,7 @@ func _srm_init_drive() -> void: var dialog := get_tree().get_first_node_in_group("dialog") as Dialog var msg := "INFO: Adding " + device_path + " as a steam path will NOT cause data loss. " + \ "The drive will be made available to Steam for installing games. Do you wish to continue?" - dialog.open(msg, "Cancel", "Continue") + dialog.open(init_button, msg, "Cancel", "Continue") var cancel := await dialog.choice_selected as bool if cancel: return diff --git a/core/ui/components/partition_card.tscn b/core/ui/components/partition_card.tscn index 75a199dd..3462c5f6 100644 --- a/core/ui/components/partition_card.tscn +++ b/core/ui/components/partition_card.tscn @@ -60,6 +60,10 @@ unique_name_in_owner = true layout_mode = 2 text = "1000 Gb" +[node name="Control" type="Control" parent="EdgeMarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + [node name="HBoxContainer" type="HBoxContainer" parent="EdgeMarginContainer/VBoxContainer"] layout_mode = 2 size_flags_horizontal = 4 diff --git a/core/ui/components/plugin_store_card.gd b/core/ui/components/plugin_store_card.gd index 199bdb63..e86346a6 100644 --- a/core/ui/components/plugin_store_card.gd +++ b/core/ui/components/plugin_store_card.gd @@ -1,26 +1,18 @@ -extends PanelContainer +@tool +extends Container signal pressed signal button_up signal button_down +signal nonchild_focused const plugin_icon := preload("res://assets/ui/icons/plugin-solid.svg") const install_icon := preload("res://assets/ui/icons/download-cloud-2-fill.svg") const upgrade_icon := preload("res://assets/ui/icons/upgrade.svg") const delete_icon := preload("res://assets/ui/icons/round-delete-forever.svg") -@export_category("Animation") -@export var highlight_speed := 0.1 - -@export_category("AudioSteamPlayer") -@export_file("*.ogg") var focus_audio = "res://assets/audio/interface/536764__egomassive__toss.ogg" -@export_file("*.ogg") var select_audio = "res://assets/audio/interface/96127__bmaczero__contact1.ogg" - -var NotificationManager := load("res://core/global/notification_manager.tres") as NotificationManager -var PluginLoader := load("res://core/global/plugin_loader.tres") as PluginLoader -var highlight_tween: Tween -var focus_audio_stream = load(focus_audio) -var select_audio_stream = load(select_audio) +var notification_manager := load("res://core/global/notification_manager.tres") as NotificationManager +var plugin_loader := load("res://core/global/plugin_loader.tres") as PluginLoader var download_url: String var project_url: String var sha256: String @@ -38,14 +30,24 @@ var logger: Logger # Called when the node enters the scene tree for the first time. func _ready() -> void: - focus_entered.connect(_on_focus) - focus_exited.connect(_on_unfocus) + # Do nothing if running in the editor + if Engine.is_editor_hint(): + return + + var on_focus_exited := func(): + self._on_unfocus.call_deferred() + focus_exited.connect(on_focus_exited) theme_changed.connect(_on_theme_changed) - _on_theme_changed() - update_button.visible = PluginLoader.is_upgradable(plugin_id) + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() + + update_button.visible = plugin_loader.is_upgradable(plugin_id) action_button.pressed.connect(_on_install_button) update_button.pressed.connect(_on_update_button) - PluginLoader.plugin_upgradable.connect(_on_update_available) + plugin_loader.plugin_upgradable.connect(_on_update_available) _set_installed_state() @@ -58,7 +60,7 @@ func _on_theme_changed() -> void: # Updates the store item based on whether it is installed func _set_installed_state(): - if PluginLoader.is_installed(plugin_id): + if plugin_loader.is_installed(plugin_id): action_button.texture = delete_icon return action_button.texture = install_icon @@ -73,23 +75,23 @@ func _on_install_button() -> void: var notify := Notification.new("Installing plugin " + plugin_id) notify.icon = plugin_icon # Handle uninstall - if PluginLoader.is_installed(plugin_id): + if plugin_loader.is_installed(plugin_id): notify.text = "Plugin " + plugin_id + " uninstalled" - if PluginLoader.uninstall_plugin(plugin_id) != OK: + if plugin_loader.uninstall_plugin(plugin_id) != OK: notify.text = "Plugin " + plugin_id + " failed to uninstall" logger.error("Failed to uninstall plugin: " + plugin_id) _set_installed_state() - NotificationManager.show(notify) + notification_manager.show(notify) return # Handle install - NotificationManager.show(notify) - PluginLoader.install_plugin(plugin_id, download_url, sha256) - await PluginLoader.plugin_installed + notification_manager.show(notify) + plugin_loader.install_plugin(plugin_id, download_url, sha256) + await plugin_loader.plugin_installed _set_installed_state() notify = Notification.new("Plugin " + plugin_id + " installed") notify.icon = plugin_icon - NotificationManager.show(notify) + notification_manager.show(notify) # Shows in the store item if an update is available @@ -106,55 +108,38 @@ func _on_update_available(name: String, type: int) -> void: func _on_update_button() -> void: var notify := Notification.new("Updating plugin " + plugin_id) notify.icon = plugin_icon - NotificationManager.show(notify) - PluginLoader.install_plugin(plugin_id, download_url, sha256) - await PluginLoader.plugin_installed + notification_manager.show(notify) + plugin_loader.install_plugin(plugin_id, download_url, sha256) + await plugin_loader.plugin_installed notify = Notification.new("Plugin " + plugin_id + " updated") notify.icon = plugin_icon - NotificationManager.show(notify) - PluginLoader.set_plugin_upgraded(plugin_id) + notification_manager.show(notify) + plugin_loader.set_plugin_upgraded(plugin_id) update_button.visible = false -func _on_focus() -> void: - _highlight() - - func _on_unfocus() -> void: - # If a child focus group is focused, don't do anything. That means that - if not focus_group: - logger.warn("No focus group defined!") + # Emit a signal if a non-child node grabs focus + var focus_owner := get_viewport().gui_get_focus_owner() + if not self.is_ancestor_of(focus_owner): + nonchild_focused.emit() return - # a child node is focused and we want the card to remain "selected" - if focus_group.is_in_focus_stack(): - return - - _unhighlight() + # If a child has focus, listen for focus changes until a non-child has focus + get_viewport().gui_focus_changed.connect(_on_focus_change) -func _highlight() -> void: - if highlight_tween: - highlight_tween.kill() - highlight_tween = get_tree().create_tween() - highlight_tween.tween_property(highlight, "visible", true, 0) - highlight_tween.tween_property(highlight, "modulate", Color(1, 1, 1, 1), 0) - _play_sound(focus_audio_stream) - - -func _unhighlight() -> void: - if highlight_tween: - highlight_tween.kill() - highlight_tween = get_tree().create_tween() - highlight_tween.tween_property(highlight, "modulate", Color(1, 1, 1, 1), 0) - highlight_tween.tween_property(highlight, "modulate", Color(1, 1, 1, 0), highlight_speed) - highlight_tween.tween_property(highlight, "visible", false, 0) - - -func _play_sound(stream: AudioStream) -> void: - var audio_player: AudioStreamPlayer = $AudioStreamPlayer - audio_player.stream = stream - audio_player.play() +func _on_focus_change(focused: Control) -> void: + # Don't do anything if the focused node is a child + if self.is_ancestor_of(focused): + return + + # If a non-child has focus, emit a signal to indicate that this node and none + # of its children have focus. + nonchild_focused.emit() + var viewport := get_viewport() + if viewport.gui_focus_changed.is_connected(_on_focus_change): + viewport.gui_focus_changed.disconnect(_on_focus_change) func _gui_input(event: InputEvent) -> void: diff --git a/core/ui/components/plugin_store_card.tscn b/core/ui/components/plugin_store_card.tscn index c07b55ad..a0b3f879 100644 --- a/core/ui/components/plugin_store_card.tscn +++ b/core/ui/components/plugin_store_card.tscn @@ -1,37 +1,59 @@ -[gd_scene load_steps=12 format=3 uid="uid://cc7a35n2pqmmf"] +[gd_scene load_steps=15 format=3 uid="uid://cc7a35n2pqmmf"] [ext_resource type="Texture2D" uid="uid://djy4rejy21s6g" path="res://icon.svg" id="1_8yjid"] [ext_resource type="Script" path="res://core/ui/components/plugin_store_card.gd" id="1_mpwli"] +[ext_resource type="PackedScene" uid="uid://c5sfkhrfbao71" path="res://core/systems/effects/play_audio_effect.tscn" id="2_bs6e3"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="2_cg18p"] [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="2_wtj1w"] [ext_resource type="PackedScene" uid="uid://cr83fmlociwko" path="res://core/ui/components/card_icon_button.tscn" id="3_3jc55"] +[ext_resource type="PackedScene" uid="uid://bw8113ocotx2r" path="res://core/systems/effects/fade_effect.tscn" id="3_73lox"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="4_6yau4"] [ext_resource type="Texture2D" uid="uid://54ncgpi6yy3p" path="res://assets/ui/icons/download-cloud-2-fill.svg" id="4_b4p24"] [ext_resource type="Texture2D" uid="uid://dt1r8cyx48k2p" path="res://assets/ui/icons/upgrade.svg" id="6_dsefr"] -[ext_resource type="Resource" uid="uid://dgi16frh3mgj8" path="res://core/ui/card_ui/settings/settings_menu_focus.tres" id="6_fo8lr"] +[ext_resource type="Script" path="res://core/systems/input/input_watcher.gd" id="7_wgty6"] +[ext_resource type="Script" path="res://core/systems/input/focus_setter.gd" id="8_kpm75"] -[sub_resource type="Gradient" id="Gradient_2e33l"] +[sub_resource type="Gradient" id="Gradient_fhi2i"] colors = PackedColorArray(0.741176, 0.576471, 0.976471, 1, 1, 0.47451, 0.776471, 1) [sub_resource type="GradientTexture2D" id="GradientTexture2D_thoiv"] -gradient = SubResource("Gradient_2e33l") +gradient = SubResource("Gradient_fhi2i") fill = 1 fill_to = Vector2(1, 2) -[node name="PluginStoreCard" type="PanelContainer"] -clip_children = 2 -custom_minimum_size = Vector2(340, 200) -offset_right = 253.0 -offset_bottom = 143.0 +[node name="PluginStoreCard" type="MarginContainer"] +custom_minimum_size = Vector2(360, 200) +offset_right = 360.0 +offset_bottom = 200.0 focus_mode = 2 theme_type_variation = &"PluginStoreCard" script = ExtResource("1_mpwli") +[node name="PlayFocusAudioEffect" parent="." instance=ExtResource("2_bs6e3")] +on_signal = "focus_entered" + +[node name="PlaySelectedAudioEffect" parent="." instance=ExtResource("2_bs6e3")] +audio = "res://assets/audio/interface/select_002.ogg" +on_signal = "pressed" + +[node name="HighlightFadeEffect" parent="." node_paths=PackedStringArray("target") instance=ExtResource("3_73lox")] +target = NodePath("../PanelContainer/HighlightTexture") +on_signal = "focus_entered" +fade_out_signal = "nonchild_focused" +on_signal = "focus_entered" + [node name="FocusGroupSetter" parent="." node_paths=PackedStringArray("target") instance=ExtResource("2_wtj1w")] target = NodePath("../MarginContainer/HBoxContainer/FocusGroup") -on_signal = "pressed" +on_signal = "button_up" -[node name="HighlightTexture" type="TextureRect" parent="."] +[node name="PanelContainer" type="PanelContainer" parent="."] +clip_children = 2 +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_type_variation = &"PluginStoreCard" + +[node name="HighlightTexture" type="TextureRect" parent="PanelContainer"] unique_name_in_owner = true visible = false layout_mode = 2 @@ -100,10 +122,19 @@ size_flags_horizontal = 8 size_flags_vertical = 8 alignment = 2 +[node name="InputWatcher" type="Node" parent="MarginContainer/HBoxContainer"] +script = ExtResource("7_wgty6") +stop_propagation = true +action = "ogui_east" + +[node name="FocusSetter" type="Node" parent="MarginContainer/HBoxContainer/InputWatcher" node_paths=PackedStringArray("target")] +script = ExtResource("8_kpm75") +target = NodePath("../../../..") +on_signal = "input_released" + [node name="FocusGroup" parent="MarginContainer/HBoxContainer" node_paths=PackedStringArray("current_focus") instance=ExtResource("4_6yau4")] unique_name_in_owner = true current_focus = NodePath("../ActionButton") -focus_stack = ExtResource("6_fo8lr") [node name="UpgradeButton" parent="MarginContainer/HBoxContainer" instance=ExtResource("3_3jc55")] unique_name_in_owner = true @@ -121,6 +152,3 @@ layout_mode = 2 size_flags_horizontal = 8 size_flags_vertical = 8 texture = ExtResource("4_b4p24") - -[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] -unique_name_in_owner = true diff --git a/core/ui/components/search_bar.gd b/core/ui/components/search_bar.gd index 36a2c940..5b1d0c93 100644 --- a/core/ui/components/search_bar.gd +++ b/core/ui/components/search_bar.gd @@ -3,7 +3,7 @@ class_name SearchBar signal search_submitted(text: String) -var state_machine := load("res://assets/state/state_machines/global_state_machine.tres") as StateMachine +var state_machine := load("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine var library_state := load("res://assets/state/states/library.tres") var keyboard_context := KeyboardContext.new(KeyboardContext.TYPE.GODOT, self) diff --git a/core/ui/components/slider.gd b/core/ui/components/slider.gd index 5666369e..310b7e2a 100644 --- a/core/ui/components/slider.gd +++ b/core/ui/components/slider.gd @@ -83,7 +83,7 @@ func _ready() -> void: slider.focus_neighbor_top = focus_neighbor_top slider.focus_previous = focus_previous slider.focus_next = focus_next - + # Wire up all slider signals var on_drag_ended := func(changed: bool): drag_ended.emit(changed) @@ -98,7 +98,11 @@ func _ready() -> void: # Set color based on theme theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: diff --git a/core/ui/components/status.gd b/core/ui/components/status.gd index 80c1b0f5..eb689b72 100644 --- a/core/ui/components/status.gd +++ b/core/ui/components/status.gd @@ -54,17 +54,24 @@ var color: String = "green": # Called when the node enters the scene tree for the first time. func _ready() -> void: - focus_entered.connect(_on_focus.bind(true)) - focus_exited.connect(_on_focus.bind(false)) - theme_changed.connect(_on_theme_changed) - _on_theme_changed() - label.text = title description_label.text = description description_label.visible = description != "" texture_rect.texture = status_texture_map[status] texture_rect.modulate = get_theme_color(color, "Status") + if Engine.is_editor_hint(): + return + + focus_entered.connect(_on_focus.bind(true)) + focus_exited.connect(_on_focus.bind(false)) + theme_changed.connect(_on_theme_changed) + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() + func _on_theme_changed() -> void: # Get the style from the set theme so it can be set on the panel container diff --git a/core/ui/components/tabs_header.gd b/core/ui/components/tabs_header.gd index c0339267..de2648f8 100644 --- a/core/ui/components/tabs_header.gd +++ b/core/ui/components/tabs_header.gd @@ -29,6 +29,10 @@ func _ready() -> void: tab.text = tab_text container.add_child(tab) + # Don't run in the editor + if Engine.is_editor_hint(): + return + # Set the currently selected tab _on_tab_changed(tabs_state.current_tab) diff --git a/core/ui/components/text.gd b/core/ui/components/text.gd index 5bbfc4f7..7ec9aca2 100644 --- a/core/ui/components/text.gd +++ b/core/ui/components/text.gd @@ -39,7 +39,11 @@ func _ready() -> void: focus_entered.connect(_on_focus.bind(true)) focus_exited.connect(_on_focus.bind(false)) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: diff --git a/core/ui/components/toggle.gd b/core/ui/components/toggle.gd index 8c553864..0024da3a 100644 --- a/core/ui/components/toggle.gd +++ b/core/ui/components/toggle.gd @@ -63,7 +63,11 @@ func _ready() -> void: focus_entered.connect(_on_focus.bind(true)) focus_exited.connect(_on_focus.bind(false)) theme_changed.connect(_on_theme_changed) - _on_theme_changed() + + # Find the parent theme and update if required + var effective_theme := ThemeUtils.get_effective_theme(self) + if effective_theme: + _on_theme_changed() func _on_theme_changed() -> void: