From 9ea4a6d5e1c711a27c4a0a2701ef889d57303272 Mon Sep 17 00:00:00 2001 From: Voyager Date: Sun, 16 Aug 2026 17:08:19 -0400 Subject: [PATCH] Redesign settings as tabbed panel --- tests/art_tools_validation.gd | 34 +- ...ontroller_menu_accessibility_validation.gd | 89 +- tests/keyboard_mouse_mapping_validation.gd | 4 +- ui/settings_panel.gd | 1142 ++++++-------- ui/settings_panel.tscn | 1350 +++++++---------- 5 files changed, 1065 insertions(+), 1554 deletions(-) diff --git a/tests/art_tools_validation.gd b/tests/art_tools_validation.gd index 45e76c0..765222f 100644 --- a/tests/art_tools_validation.gd +++ b/tests/art_tools_validation.gd @@ -99,23 +99,25 @@ func _run() -> void: var settings_panel := game_ui.get( "_pause_settings_panel" ) as SettingsPanel - var chat_dock_button := settings_panel.get_node("%ChatDock") as BubbleButton - var chat_mode_button := settings_panel.get_node("%ChatMode") as BubbleButton - var paint_dock_button := settings_panel.get_node("%PaintDock") as BubbleButton - assert(chat_dock_button.neutral_size.x == chat_dock_button.neutral_size.y) - assert(chat_mode_button.neutral_size.x == chat_mode_button.neutral_size.y) - assert(paint_dock_button.neutral_size.x == paint_dock_button.neutral_size.y) + var chat_dock_selector := settings_panel.get_node( + "%ChatDockSelector" + ) as OptionButton + var chat_mode_selector := settings_panel.get_node( + "%ChatModeSelector" + ) as OptionButton + var paint_dock_selector := settings_panel.get_node( + "%PaintDockSelector" + ) as OptionButton + assert(chat_dock_selector != null) + assert(chat_mode_selector != null) + assert(paint_dock_selector != null) + assert(chat_dock_selector.custom_minimum_size.x == 300.0) + assert(chat_mode_selector.custom_minimum_size.x == 300.0) + assert(paint_dock_selector.custom_minimum_size.x == 300.0) assert( - chat_dock_button.compact_minimum_size.x - == chat_dock_button.compact_minimum_size.y - ) - assert( - chat_mode_button.compact_minimum_size.x - == chat_mode_button.compact_minimum_size.y - ) - assert( - paint_dock_button.compact_minimum_size.x - == paint_dock_button.compact_minimum_size.y + settings_panel.find_children( + "*", "BubbleButton", true, false + ).is_empty() ) assert(not chat_ui.is_docked_right()) assert(toolbar.is_docked_right()) diff --git a/tests/controller_menu_accessibility_validation.gd b/tests/controller_menu_accessibility_validation.gd index da18d79..b6f9c43 100644 --- a/tests/controller_menu_accessibility_validation.gd +++ b/tests/controller_menu_accessibility_validation.gd @@ -168,15 +168,15 @@ func _validate_join_game_navigation() -> void: func _validate_data_settings_navigation() -> void: - var panel := SettingsPanelScene.instantiate() as Control + var panel := SettingsPanelScene.instantiate() as SettingsPanel root.add_child(panel) await process_frame panel.show() - var data_page := panel.get_node("%DataPage") as SettingsBubblePage - data_page.show_page(false) + panel.call("_select_page", &"data", false) for _frame: int in 2: await process_frame var controls: Array[Control] = [ + panel.get_node("%DataTab") as Control, panel.get_node("%OpenDataFolder") as Control, panel.get_node("%ChangeDataFolder") as Control, panel.get_node("%CopyPlayerFingerprint") as Control, @@ -184,7 +184,8 @@ func _validate_data_settings_navigation() -> void: panel.get_node("%ImportPlayerIdentity") as Control, panel.get_node("%ExportHostIdentity") as Control, panel.get_node("%ImportHostIdentity") as Control, - panel.get_node("%DataBackButton") as Control, + panel.get_node("%ApplySettingsButton") as Control, + panel.get_node("%SettingsBackButton") as Control, ] for control: Control in controls: _expect( @@ -193,6 +194,10 @@ func _validate_data_settings_navigation() -> void: % control.name, ) _assert_directionally_reachable(controls.front(), controls) + _expect( + panel.find_children("*", "BubbleButton", true, false).is_empty(), + "Settings children still contain bubble controls.", + ) panel.queue_free() await process_frame @@ -202,56 +207,48 @@ func _validate_settings_adjustment_navigation() -> void: root.add_child(panel) await process_frame panel.show() - var sound_page := panel.get_node("%SoundPage") as SettingsBubblePage - sound_page.show_page(false) + panel.call("_select_page", &"sound", false) for _frame: int in 2: await process_frame - var environment := panel.get_node("%EnvironmentVolumeSlider") as HSlider - var sound_back := panel.get_node("%SoundBackButton") as Button - _assert_neighbor( - environment, - &"focus_neighbor_bottom", - sound_back, - ) - _assert_neighbor(sound_back, &"focus_neighbor_top", environment) - sound_page.hide_page() - - var controls_page := panel.get_node("%ControlsPage") as SettingsBubblePage - controls_page.show_page(false) + var sound_controls: Array[Control] = [ + panel.get_node("%SoundTab") as Control, + panel.get_node("%MasterVolumeSlider") as Control, + panel.get_node("%MusicVolumeSlider") as Control, + panel.get_node("%EffectsVolumeSlider") as Control, + panel.get_node("%EnvironmentVolumeSlider") as Control, + panel.get_node("%ApplySettingsButton") as Control, + panel.get_node("%SettingsBackButton") as Control, + ] + _assert_directionally_reachable(sound_controls.front(), sound_controls) + panel.call("_select_page", &"controls", false) for _frame: int in 2: await process_frame - var parent := panel.get_node("%MouseValue") as Button - var decrease := panel.get_node("%MouseDecrease") as Button - var increase := panel.get_node("%MouseIncrease") as Button + var mouse_slider := panel.get_node("%MouseSensitivitySlider") as HSlider + var controller_slider := panel.get_node( + "%ControllerSensitivitySlider" + ) as HSlider _expect( - decrease.focus_mode == Control.FOCUS_NONE - and increase.focus_mode == Control.FOCUS_NONE, - "Sensitivity adjustment bubbles are reachable before their parent.", - ) - parent.grab_focus() - var accept := InputEventJoypadButton.new() - accept.button_index = JOY_BUTTON_A - accept.pressed = true - panel.call("_input", accept) - _expect( - decrease.focus_mode == Control.FOCUS_ALL - and increase.focus_mode == Control.FOCUS_ALL, - "Selecting a sensitivity parent did not enter its adjustment zone.", - ) - _assert_neighbor(parent, &"focus_neighbor_left", decrease) - _assert_neighbor(parent, &"focus_neighbor_right", increase) - panel.handle_back() - for _frame: int in 2: - await process_frame - _expect( - decrease.focus_mode == Control.FOCUS_NONE - and increase.focus_mode == Control.FOCUS_NONE, - "Leaving an adjustment zone did not hide its child controls.", + mouse_slider.focus_mode == Control.FOCUS_ALL + and controller_slider.focus_mode == Control.FOCUS_ALL, + "Standard sensitivity sliders are not controller-focusable.", ) _expect( - root.gui_get_focus_owner() == parent, - "Leaving an adjustment zone did not restore its parent focus.", + is_equal_approx(mouse_slider.step, 0.0005) + and is_equal_approx(controller_slider.step, 0.1), + "Sensitivity sliders do not retain their authored increments.", ) + var control_inputs: Array[Control] = [ + panel.get_node("%ControlsTab") as Control, + mouse_slider, + controller_slider, + panel.get_node("%InvertYToggle") as Control, + panel.get_node("%OnScreenKeyboardToggle") as Control, + panel.get_node("%ControllerMapping") as Control, + panel.get_node("%KeyboardMapping") as Control, + panel.get_node("%ApplySettingsButton") as Control, + panel.get_node("%SettingsBackButton") as Control, + ] + _assert_directionally_reachable(control_inputs.front(), control_inputs) panel.queue_free() await process_frame diff --git a/tests/keyboard_mouse_mapping_validation.gd b/tests/keyboard_mouse_mapping_validation.gd index b532f4b..cca2ac2 100644 --- a/tests/keyboard_mouse_mapping_validation.gd +++ b/tests/keyboard_mouse_mapping_validation.gd @@ -107,8 +107,8 @@ func _run() -> void: "%ControllerMapping" ) as Button var keyboard_bubble := settings_panel.get_node("%KeyboardMapping") as Button - assert(controller_bubble.text == "controller\nbinds") - assert(keyboard_bubble.text == "keyboard\nbinds") + assert(controller_bubble.text == "controller binds") + assert(keyboard_bubble.text == "keyboard binds") assert(manager.reset_mapping()) assert(not manager.has_custom_mapping()) diff --git a/ui/settings_panel.gd b/ui/settings_panel.gd index f0169af..e1f2039 100644 --- a/ui/settings_panel.gd +++ b/ui/settings_panel.gd @@ -1,9 +1,8 @@ class_name SettingsPanel extends Control -const MAX_PANEL_SIZE: Vector2 = Vector2(960.0, 700.0) +const PANEL_SIZE: Vector2 = Vector2(880.0, 660.0) const PANEL_EDGE_MARGIN: float = 16.0 -const PAGE_ROOT: StringName = &"root" const PAGE_DISPLAY: StringName = &"display" const PAGE_SOUND: StringName = &"sound" const PAGE_CONTROLS: StringName = &"controls" @@ -34,6 +33,9 @@ const KeyboardMouseMappingPanelType = preload( const DialogControllerNavigationType = preload( "res://ui/file_dialog_controller_navigation.gd" ) +const ControllerFocusNavigationType = preload( + "res://ui/controller_focus_navigation.gd" +) signal applied signal closed @@ -48,26 +50,28 @@ enum PresentationMode { GAMEPLAY_MODAL, } -@onready var _root_page: SettingsBubblePage = %RootPage -@onready var _display_page: SettingsBubblePage = %DisplayPage -@onready var _sound_page: SettingsBubblePage = %SoundPage -@onready var _controls_page: SettingsBubblePage = %ControlsPage -@onready var _accessibility_page: SettingsBubblePage = %AccessibilityPage -@onready var _data_page: SettingsBubblePage = %DataPage +@onready var _main_panel: PanelContainer = %MainPanel +@onready var _content_panel: PanelContainer = %ContentPanel @onready var _feedback: Label = %SettingsFeedback +@onready var _display_page: Control = %DisplayPage +@onready var _sound_page: Control = %SoundPage +@onready var _controls_page: Control = %ControlsPage +@onready var _accessibility_page: Control = %AccessibilityPage +@onready var _data_page: Control = %DataPage + +@onready var _display_tab: OrganizerTab = %DisplayTab +@onready var _sound_tab: OrganizerTab = %SoundTab +@onready var _controls_tab: OrganizerTab = %ControlsTab +@onready var _accessibility_tab: OrganizerTab = %AccessibilityTab +@onready var _data_tab: OrganizerTab = %DataTab + +@onready var _world_pixelation: OptionButton = %WorldPixelationSelector +@onready var _ui_pixelation: OptionButton = %UIPixelationSelector +@onready var _chat_dock: OptionButton = %ChatDockSelector +@onready var _chat_mode: OptionButton = %ChatModeSelector +@onready var _paint_dock: OptionButton = %PaintDockSelector +@onready var _fullscreen_toggle: Button = %FullscreenToggle -@onready var _world_value: BubbleButton = %WorldValue -@onready var _ui_value: BubbleButton = %UIValue -@onready var _chat_dock: BubbleButton = %ChatDock -@onready var _chat_mode: BubbleButton = %ChatMode -@onready var _paint_dock: BubbleButton = %PaintDock -@onready var _fullscreen_toggle: BubbleButton = %FullscreenToggle -@onready var _mouse_value: BubbleButton = %MouseValue -@onready var _controller_value: BubbleButton = %ControllerValue -@onready var _invert_y_toggle: BubbleButton = %InvertYToggle -@onready var _on_screen_keyboard_toggle: BubbleButton = %OnScreenKeyboardToggle -@onready var _auto_click_toggle: BubbleButton = %AutoClickToggle -@onready var _auto_click_interval: BubbleButton = %AutoClickIntervalValue @onready var _master_volume_slider: HSlider = %MasterVolumeSlider @onready var _music_volume_slider: HSlider = %MusicVolumeSlider @onready var _effects_volume_slider: HSlider = %EffectsVolumeSlider @@ -77,29 +81,36 @@ enum PresentationMode { @onready var _effects_volume_value: Label = %EffectsVolumeValue @onready var _environment_volume_value: Label = %EnvironmentVolumeValue -@onready var _world_options: Array[BubbleButton] = [ - %WorldLegible, - %WorldCute, - %WorldRetro, - %WorldHardcore, - %WorldWtf, -] -@onready var _ui_options: Array[BubbleButton] = [ - %UILegible, - %UICute, - %UIRetro, - %UIHardcore, - %UIWtf, -] +@onready var _mouse_sensitivity_slider: HSlider = %MouseSensitivitySlider +@onready var _controller_sensitivity_slider: HSlider = ( + %ControllerSensitivitySlider +) +@onready var _mouse_sensitivity_value: Label = %MouseSensitivityValue +@onready var _controller_sensitivity_value: Label = ( + %ControllerSensitivityValue +) +@onready var _invert_y_toggle: Button = %InvertYToggle +@onready var _on_screen_keyboard_toggle: Button = %OnScreenKeyboardToggle +@onready var _auto_click_toggle: Button = %AutoClickToggle +@onready var _auto_click_interval_slider: HSlider = ( + %AutoClickIntervalSlider +) +@onready var _auto_click_interval_value_label: Label = ( + %AutoClickIntervalValue +) +@onready var _apply_button: Button = %ApplySettingsButton +@onready var _back_button: Button = %SettingsBackButton var _settings_manager: SettingsManagerType var _effective_ui_pixel_size: int = PlayerSettings.DEFAULT_UI_PIXEL_SIZE -var _page_stack: Array[StringName] = [] -var _pages: Dictionary[StringName, SettingsBubblePage] = {} -var _page_transition_generation: int = 0 -var _page_transition_active: bool = false +var _pages: Dictionary[StringName, Control] = {} +var _tabs: Dictionary[StringName, OrganizerTab] = {} +var _active_page_id: StringName = PAGE_DISPLAY var _presentation_mode: PresentationMode = PresentationMode.GAMEPLAY_MODAL var _animate_gameplay_host_transitions: bool = false +var _panel_tween: Tween +var _transition_generation: int = 0 +var _transition_active: bool = false var _auto_click_enabled: bool = false var _auto_click_interval_value: float = 0.20 var _mouse_sensitivity: float = 0.005 @@ -131,86 +142,73 @@ var _pending_identity_operation := "" var _pending_identity_type := "" var _pending_identity_path := "" var _pending_import_data: Dictionary = {} -var _active_adjustment_group: Dictionary = {} func _ready() -> void: _pages = { - PAGE_ROOT: _root_page, PAGE_DISPLAY: _display_page, PAGE_SOUND: _sound_page, PAGE_CONTROLS: _controls_page, PAGE_ACCESSIBILITY: _accessibility_page, PAGE_DATA: _data_page, } - %DisplayCategory.pressed.connect(_push_page.bind(PAGE_DISPLAY)) - %SoundCategory.pressed.connect(_push_page.bind(PAGE_SOUND)) - %ControlsCategory.pressed.connect(_push_page.bind(PAGE_CONTROLS)) - %AccessibilityCategory.pressed.connect( - _push_page.bind(PAGE_ACCESSIBILITY) + _tabs = { + PAGE_DISPLAY: _display_tab, + PAGE_SOUND: _sound_tab, + PAGE_CONTROLS: _controls_tab, + PAGE_ACCESSIBILITY: _accessibility_tab, + PAGE_DATA: _data_tab, + } + for page_id: StringName in _tabs: + _tabs[page_id].pressed.connect(_select_page.bind(page_id, true)) + _populate_option_buttons() + _connect_controls() + _configure_style() + _controller_mapping_panel = ControllerMappingPanelType.new() + add_child(_controller_mapping_panel) + _controller_mapping_panel.closed.connect( + _on_controller_mapping_panel_closed ) - %DataCategory.pressed.connect(_push_page.bind(PAGE_DATA)) - %ApplySettingsButton.pressed.connect(_apply_settings) - %RootBackButton.pressed.connect(close_panel) - %DisplayBackButton.pressed.connect(handle_back) - %SoundBackButton.pressed.connect(handle_back) - %ControlsBackButton.pressed.connect(handle_back) - %ControllerMapping.pressed.connect(_open_controller_mapping) - %KeyboardMapping.pressed.connect(_open_keyboard_mouse_mapping) - %AccessibilityBackButton.pressed.connect(handle_back) - %DataBackButton.pressed.connect(handle_back) - %RootBackButton.gui_input.connect(_on_back_bubble_gui_input) - %DisplayBackButton.gui_input.connect(_on_back_bubble_gui_input) - %SoundBackButton.gui_input.connect(_on_back_bubble_gui_input) - %ControlsBackButton.gui_input.connect(_on_back_bubble_gui_input) - %AccessibilityBackButton.gui_input.connect(_on_back_bubble_gui_input) - %DataBackButton.gui_input.connect(_on_back_bubble_gui_input) - %OpenDataFolder.pressed.connect(_open_data_folder) - %ChangeDataFolder.pressed.connect(_choose_data_folder) - %ExportPlayerIdentity.pressed.connect(_choose_identity_export.bind("player")) - %ImportPlayerIdentity.pressed.connect(_choose_identity_import.bind("player")) - %CopyPlayerFingerprint.pressed.connect(_copy_player_fingerprint) - %ExportHostIdentity.pressed.connect(_choose_identity_export.bind("host")) - %ImportHostIdentity.pressed.connect(_choose_identity_import.bind("host")) - for index: int in _world_options.size(): - _world_options[index].pressed.connect( - _set_world_pixelation.bind(index + 1) - ) - for index: int in _ui_options.size(): - _ui_options[index].pressed.connect( - _set_ui_pixelation.bind(index + 1) - ) - _chat_dock.pressed.connect(_toggle_chat_dock) - _chat_mode.pressed.connect(_toggle_chat_mode) - _paint_dock.pressed.connect(_toggle_paint_dock) - _fullscreen_toggle.pressed.connect(_toggle_fullscreen) - %MouseDecrease.pressed.connect(_adjust_mouse_sensitivity.bind(-1)) - %MouseIncrease.pressed.connect(_adjust_mouse_sensitivity.bind(1)) - _mouse_value.pressed.connect(_adjust_mouse_sensitivity.bind(1)) - %ControllerDecrease.pressed.connect( - _adjust_controller_sensitivity.bind(-1) + _keyboard_mouse_mapping_panel = KeyboardMouseMappingPanelType.new() + add_child(_keyboard_mouse_mapping_panel) + _keyboard_mouse_mapping_panel.closed.connect( + _on_keyboard_mouse_mapping_panel_closed ) - %ControllerIncrease.pressed.connect( - _adjust_controller_sensitivity.bind(1) - ) - _controller_value.pressed.connect( - _adjust_controller_sensitivity.bind(1) - ) - _invert_y_toggle.pressed.connect(_toggle_invert_y) - _on_screen_keyboard_toggle.pressed.connect(_toggle_on_screen_keyboard) - _auto_click_toggle.pressed.connect(_toggle_auto_click) - for control: Control in [_auto_click_toggle, _auto_click_interval]: - control.mouse_entered.connect( - _show_accessibility_helper.bind(&"auto_click") - ) - control.focus_entered.connect( - _show_accessibility_helper.bind(&"auto_click") - ) - %IntervalDecrease.pressed.connect(_adjust_auto_click_interval.bind(-1)) - %IntervalIncrease.pressed.connect(_adjust_auto_click_interval.bind(1)) - _auto_click_interval.pressed.connect( - _adjust_auto_click_interval.bind(1) + resized.connect(_refresh_panel_size) + var parent_control := get_parent() as Control + if parent_control != null: + parent_control.resized.connect(_refresh_panel_size) + _select_page(PAGE_DISPLAY, false) + call_deferred("_refresh_panel_size") + + +func _populate_option_buttons() -> void: + for selector: OptionButton in [_world_pixelation, _ui_pixelation]: + selector.clear() + for index: int in PIXELATION_NAMES.size(): + selector.add_item(PIXELATION_NAMES[index], index + 1) + _chat_dock.clear() + _chat_dock.add_item("left", 0) + _chat_dock.add_item("right", 1) + _chat_mode.clear() + _chat_mode.add_item("desktop", 0) + _chat_mode.add_item("mobile", 1) + _paint_dock.clear() + _paint_dock.add_item("left", 0) + _paint_dock.add_item("right", 1) + + +func _connect_controls() -> void: + _apply_button.pressed.connect(_apply_settings) + _back_button.pressed.connect(close_panel) + _world_pixelation.item_selected.connect( + _on_world_pixelation_selected ) + _ui_pixelation.item_selected.connect(_on_ui_pixelation_selected) + _chat_dock.item_selected.connect(_on_chat_dock_selected) + _chat_mode.item_selected.connect(_on_chat_mode_selected) + _paint_dock.item_selected.connect(_on_paint_dock_selected) + _fullscreen_toggle.toggled.connect(_set_fullscreen) _master_volume_slider.value_changed.connect( _on_audio_volume_changed.bind(&"master") ) @@ -223,34 +221,79 @@ func _ready() -> void: _environment_volume_slider.value_changed.connect( _on_audio_volume_changed.bind(&"environment") ) - _mouse_value.gui_input.connect( - _on_continuous_value_input.bind(&"mouse") + _mouse_sensitivity_slider.value_changed.connect( + _on_mouse_sensitivity_changed ) - _controller_value.gui_input.connect( - _on_continuous_value_input.bind(&"controller") + _controller_sensitivity_slider.value_changed.connect( + _on_controller_sensitivity_changed ) - _auto_click_interval.gui_input.connect( - _on_continuous_value_input.bind(&"interval") + _invert_y_toggle.toggled.connect(_set_invert_y) + _on_screen_keyboard_toggle.toggled.connect(_set_on_screen_keyboard) + _auto_click_toggle.toggled.connect(_set_auto_click) + _auto_click_interval_slider.value_changed.connect( + _on_auto_click_interval_changed ) - resized.connect(_refresh_panel_size) - var parent_control := get_parent() as Control - if parent_control != null: - parent_control.resized.connect(_refresh_panel_size) - for page: SettingsBubblePage in _pages.values(): - page.hide_page() - _controller_mapping_panel = ControllerMappingPanelType.new() - add_child(_controller_mapping_panel) - _controller_mapping_panel.closed.connect( - _on_controller_mapping_panel_closed + %ControllerMapping.pressed.connect(_open_controller_mapping) + %KeyboardMapping.pressed.connect(_open_keyboard_mouse_mapping) + %OpenDataFolder.pressed.connect(_open_data_folder) + %ChangeDataFolder.pressed.connect(_choose_data_folder) + %ExportPlayerIdentity.pressed.connect( + _choose_identity_export.bind("player") ) - _keyboard_mouse_mapping_panel = KeyboardMouseMappingPanelType.new() - add_child(_keyboard_mouse_mapping_panel) - _keyboard_mouse_mapping_panel.closed.connect( - _on_keyboard_mouse_mapping_panel_closed + %ImportPlayerIdentity.pressed.connect( + _choose_identity_import.bind("player") + ) + %CopyPlayerFingerprint.pressed.connect(_copy_player_fingerprint) + %ExportHostIdentity.pressed.connect( + _choose_identity_export.bind("host") + ) + %ImportHostIdentity.pressed.connect( + _choose_identity_import.bind("host") + ) + + +func _configure_style() -> void: + UtilityPageStyle.apply_page(self) + _main_panel.add_theme_stylebox_override( + "panel", + UtilityPageStyle.rounded_style( + UtilityPageStyle.OCEAN_PANEL_MID, + 28, + ), + ) + _content_panel.add_theme_stylebox_override( + "panel", + UtilityPageStyle.rounded_style( + UtilityPageStyle.OCEAN_FIELD, + 20, + ), + ) + for node: Node in find_children("*", "Label", true, false): + var label := node as Label + label.add_theme_color_override( + "font_color", + UtilityPageStyle.OCEAN_TEXT_PRIMARY, + ) + for node: Node in find_children("*", "Button", true, false): + if node is OrganizerTab: + continue + UtilityPageStyle.apply_ocean_button(node as BaseButton) + for node: Node in find_children("*", "OptionButton", true, false): + UtilityPageStyle.apply_ocean_button(node as BaseButton) + _apply_button.add_theme_stylebox_override( + "normal", + UtilityPageStyle.ocean_button_style(Color("31594d")), + ) + _back_button.add_theme_stylebox_override( + "normal", + UtilityPageStyle.ocean_button_style( + UtilityPageStyle.OCEAN_PANEL_DEEP, + ), + ) + _feedback.add_theme_color_override( + "font_color", + UtilityPageStyle.OCEAN_TEXT_SECONDARY, ) - _style_data_page() - _style_sound_page() - call_deferred("_refresh_panel_size") func setup_network_profile( @@ -289,93 +332,41 @@ func setup_data_and_identity( _host_identity = host_identity _network_session = session _interface_fonts = interface_fonts - _identity_backups.operation_finished.connect(_on_identity_operation_finished) + if not _identity_backups.operation_finished.is_connected( + _on_identity_operation_finished + ): + _identity_backups.operation_finished.connect( + _on_identity_operation_finished + ) _interface_fonts.apply_utility_theme(_data_page) _refresh_data_page() -func _input(event: InputEvent) -> void: - if not visible or is_input_mapping_capturing(): - return - var mouse_button := event as InputEventMouseButton - if ( - mouse_button != null - and mouse_button.pressed - and not _active_adjustment_group.is_empty() - ): - _exit_adjustment_zone(false) - return - var button := event as InputEventJoypadButton - if button == null or not button.pressed: - return - if ( - not _active_adjustment_group.is_empty() - and _event_matches_controller_role( - event, - ControllerMappingManagerType.ROLE_B, - &"ui_cancel", - JOY_BUTTON_B, - ) - ): - _exit_adjustment_zone(true) - get_viewport().set_input_as_handled() - return - if not _event_matches_controller_role( - event, - ControllerMappingManagerType.ROLE_A, - &"ui_accept", - JOY_BUTTON_A, - ): - return - if _active_adjustment_group.is_empty(): - var group: Dictionary = _adjustment_group_for_control( - get_viewport().gui_get_focus_owner() - ) - if group.is_empty(): - return - _enter_adjustment_zone(group) - get_viewport().set_input_as_handled() - return - var focused := get_viewport().gui_get_focus_owner() as BaseButton - var decrease := _active_adjustment_group.get("decrease") as BaseButton - var increase := _active_adjustment_group.get("increase") as BaseButton - if focused == decrease or focused == increase: - focused.pressed.emit() - get_viewport().set_input_as_handled() - - func open_panel( settings_manager: SettingsManagerType, presentation_mode: PresentationMode = PresentationMode.GAMEPLAY_MODAL, animate_gameplay_host_transitions: bool = false, ) -> void: - _cancel_page_transition() + _cancel_panel_transition() _presentation_mode = presentation_mode _animate_gameplay_host_transitions = animate_gameplay_host_transitions _settings_manager = settings_manager _load_controls() _feedback.text = "" _refresh_data_page() + _select_page(PAGE_DISPLAY, false) show() - _page_stack.clear() - _page_stack.append(PAGE_ROOT) panel_visibility_changed.emit(true) + _main_panel.modulate.a = 1.0 + _main_panel.scale = Vector2.ONE + call_deferred("_configure_controller_navigation") + call_deferred("_focus_active_tab") if ( presentation_mode == PresentationMode.TITLE_EMBEDDED or _animate_gameplay_host_transitions ): - for page: SettingsBubblePage in _pages.values(): - page.hide_page() - _page_transition_generation += 1 - _page_transition_active = true - var generation: int = _page_transition_generation - _root_page.transition_in( - true, - _finish_animated_open.bind(generation), - 0.0 - ) + _animate_panel_open() else: - _show_active_page(true) opened.emit() @@ -389,15 +380,86 @@ func close_panel(immediate: bool = false) -> void: _presentation_mode == PresentationMode.TITLE_EMBEDDED or _animate_gameplay_host_transitions ): - if _page_transition_active: - return - _begin_animated_close(false) + _animate_panel_close(false) return _finish_panel_close(false) +func _animate_panel_open() -> void: + _transition_generation += 1 + _transition_active = true + var generation: int = _transition_generation + _main_panel.pivot_offset = _main_panel.size * 0.5 + _main_panel.scale = Vector2.ONE * UIMotion.UTILITY_ENTER_SCALE + _main_panel.modulate.a = 0.0 + _panel_tween = create_tween() + _panel_tween.set_parallel(true) + _panel_tween.tween_property( + _main_panel, + "scale", + Vector2.ONE, + UIMotion.UTILITY_ENTER_DURATION, + ).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT) + _panel_tween.tween_property( + _main_panel, + "modulate:a", + 1.0, + UIMotion.UTILITY_ENTER_DURATION, + ) + _panel_tween.finished.connect( + _finish_panel_open.bind(generation), + CONNECT_ONE_SHOT, + ) + + +func _finish_panel_open(generation: int) -> void: + if generation != _transition_generation or not visible: + return + _transition_active = false + _panel_tween = null + opened.emit() + + +func _animate_panel_close(applied_result: bool) -> void: + if _transition_active: + return + _transition_generation += 1 + _transition_active = true + var generation: int = _transition_generation + navigation_transition_started.emit() + closing.emit() + _main_panel.pivot_offset = _main_panel.size * 0.5 + _panel_tween = create_tween() + _panel_tween.set_parallel(true) + _panel_tween.tween_property( + _main_panel, + "scale", + Vector2.ONE * UIMotion.UTILITY_ENTER_SCALE, + UIMotion.UTILITY_EXIT_DURATION, + ).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN) + _panel_tween.tween_property( + _main_panel, + "modulate:a", + 0.0, + UIMotion.UTILITY_EXIT_DURATION, + ) + _panel_tween.finished.connect( + _finish_animated_close.bind(generation, applied_result), + CONNECT_ONE_SHOT, + ) + + +func _finish_animated_close( + generation: int, + applied_result: bool, +) -> void: + if generation != _transition_generation or not visible: + return + _finish_panel_close(applied_result) + + func _finish_panel_close(applied_result: bool) -> void: - _cancel_page_transition() + _cancel_panel_transition() if ( _controller_mapping_panel != null and _controller_mapping_panel.is_open() @@ -408,9 +470,8 @@ func _finish_panel_close(applied_result: bool) -> void: and _keyboard_mouse_mapping_panel.is_open() ): _keyboard_mouse_mapping_panel.close_panel() - for page: SettingsBubblePage in _pages.values(): - page.hide_page() - _page_stack.clear() + _main_panel.modulate.a = 1.0 + _main_panel.scale = Vector2.ONE hide() panel_visibility_changed.emit(false) if applied_result: @@ -420,10 +481,15 @@ func _finish_panel_close(applied_result: bool) -> void: closed.emit() +func _cancel_panel_transition() -> void: + _transition_generation += 1 + _transition_active = false + if _panel_tween != null: + _panel_tween.kill() + _panel_tween = null + + func handle_back() -> void: - if not _active_adjustment_group.is_empty(): - _exit_adjustment_zone(true) - return if ( _keyboard_mouse_mapping_panel != null and _keyboard_mouse_mapping_panel.is_open() @@ -436,14 +502,69 @@ func handle_back() -> void: ): _controller_mapping_panel.request_back() return - if _page_transition_active: - return - if _page_stack.size() > 1: - _start_page_transition(_page_stack[-2], false) + for selector: OptionButton in [ + _world_pixelation, + _ui_pixelation, + _chat_dock, + _chat_mode, + _paint_dock, + ]: + if selector.get_popup().visible: + selector.get_popup().hide() + selector.grab_focus() + return + if _transition_active: return close_panel() +func _select_page(page_id: StringName, focus_tab: bool = true) -> void: + if not _pages.has(page_id): + return + _active_page_id = page_id + for candidate_id: StringName in _pages: + _pages[candidate_id].visible = candidate_id == page_id + _tabs[candidate_id].set_selected( + candidate_id == page_id, + is_inside_tree(), + ) + if page_id == PAGE_DATA: + _refresh_data_page() + call_deferred("_configure_controller_navigation") + if focus_tab: + _tabs[page_id].call_deferred("grab_focus") + + +func _focus_active_tab() -> void: + var tab: OrganizerTab = _tabs.get(_active_page_id) + if tab != null: + tab.grab_focus() + + +func _configure_controller_navigation() -> void: + if not is_node_ready() or not visible: + return + var controls: Array[Control] = [] + _collect_focusable_controls(_main_panel, controls) + ControllerFocusNavigationType.configure_spatial_neighbors(controls) + + +func _collect_focusable_controls( + node: Node, + controls: Array[Control], +) -> void: + for child: Node in node.get_children(): + var control := child as Control + if control != null and not control.is_visible_in_tree(): + continue + if ( + control != null + and ControllerFocusNavigationType.is_focusable(control) + ): + controls.append(control) + _collect_focusable_controls(child, controls) + + func _open_controller_mapping() -> void: if _controller_mapping_manager == null: _feedback.text = "no controller mapping service is available" @@ -467,7 +588,7 @@ func _on_keyboard_mouse_mapping_panel_closed() -> void: func get_active_page_id() -> StringName: - return _page_stack.back() if not _page_stack.is_empty() else StringName() + return _active_page_id if visible else StringName() func is_controller_mapping_capturing() -> bool: @@ -487,207 +608,11 @@ func is_input_mapping_capturing() -> bool: ) -func _push_page(page_id: StringName) -> void: - if ( - _page_transition_active - or not _pages.has(page_id) - or get_active_page_id() == page_id - ): - return - _exit_adjustment_zone(false) - _start_page_transition(page_id, true) - - -func _adjustment_group_for_control(control: Control) -> Dictionary: - for group: Dictionary in _adjustment_groups(): - if group.get("parent") as Control == control: - return group - return {} - - -func _adjustment_groups() -> Array[Dictionary]: - return [ - { - "page": _controls_page, - "parent": _mouse_value, - "decrease": %MouseDecrease, - "increase": %MouseIncrease, - }, - { - "page": _controls_page, - "parent": _controller_value, - "decrease": %ControllerDecrease, - "increase": %ControllerIncrease, - }, - { - "page": _accessibility_page, - "parent": _auto_click_interval, - "decrease": %IntervalDecrease, - "increase": %IntervalIncrease, - }, - ] - - -func _enter_adjustment_zone(group: Dictionary) -> void: - var page := group.get("page") as SettingsBubblePage - var parent := group.get("parent") as Control - var decrease := group.get("decrease") as Control - var increase := group.get("increase") as Control - if page == null or parent == null or decrease == null or increase == null: - return - _active_adjustment_group = group - var controls: Array[Control] = [decrease, parent, increase] - page.set_controller_focus_scope(controls) - _set_adjustment_neighbors(decrease, parent, increase) - parent.grab_focus() - - -func _exit_adjustment_zone(restore_parent_focus: bool) -> void: - if _active_adjustment_group.is_empty(): - return - var page := _active_adjustment_group.get("page") as SettingsBubblePage - var parent := _active_adjustment_group.get("parent") as Control - var decrease := _active_adjustment_group.get("decrease") as Control - var increase := _active_adjustment_group.get("increase") as Control - _active_adjustment_group.clear() - for control: Control in [decrease, increase]: - if control != null: - control.focus_mode = Control.FOCUS_NONE - if page != null: - page.restore_controller_focus_scope() - if restore_parent_focus and parent != null: - parent.call_deferred("grab_focus") - - -func _set_adjustment_neighbors( - decrease: Control, - parent: Control, - increase: Control, -) -> void: - decrease.focus_neighbor_left = decrease.get_path_to(decrease) - decrease.focus_neighbor_right = decrease.get_path_to(parent) - parent.focus_neighbor_left = parent.get_path_to(decrease) - parent.focus_neighbor_right = parent.get_path_to(increase) - increase.focus_neighbor_left = increase.get_path_to(parent) - increase.focus_neighbor_right = increase.get_path_to(increase) - for control: Control in [decrease, parent, increase]: - control.focus_neighbor_top = control.get_path_to(control) - control.focus_neighbor_bottom = control.get_path_to(control) - - -func _event_matches_controller_role( - event: InputEvent, - role: StringName, - action: StringName, - fallback_button: JoyButton, -) -> bool: - if _controller_mapping_manager != null: - return _controller_mapping_manager.event_matches_role(event, role) - var button := event as InputEventJoypadButton - return ( - button != null - and ( - button.button_index == fallback_button - or event.is_action_pressed(action) - ) - ) - - -func _start_page_transition(page_id: StringName, push_page: bool) -> void: - var outgoing_page: SettingsBubblePage = _get_active_page() - var incoming_page: SettingsBubblePage = _pages.get(page_id) - if outgoing_page == null or incoming_page == null: - return - _page_transition_generation += 1 - _page_transition_active = true - navigation_transition_started.emit() - var generation: int = _page_transition_generation - if push_page: - _page_stack.append(page_id) - else: - _page_stack.pop_back() - for page: SettingsBubblePage in _pages.values(): - if page != outgoing_page and page != incoming_page: - page.hide_page() - outgoing_page.transition_out( - Callable() - ) - get_tree().create_timer( - UIMotion.BUBBLE_TRANSITION_OVERLAP_DELAY - ).timeout.connect( - func() -> void: - if ( - generation == _page_transition_generation - and _page_transition_active - ): - incoming_page.transition_in( - true, - _finish_incoming_page.bind(generation) - ), - CONNECT_ONE_SHOT - ) - - -func _finish_incoming_page(generation: int) -> void: - if generation != _page_transition_generation or not _page_transition_active: - return - _page_transition_active = false - - -func _finish_animated_open(generation: int) -> void: - if generation != _page_transition_generation or not _page_transition_active: - return - _page_transition_active = false - opened.emit() - - -func _begin_animated_close(applied_result: bool) -> void: - var active_page: SettingsBubblePage = _get_active_page() - if active_page == null: - return - _page_transition_generation += 1 - _page_transition_active = true - navigation_transition_started.emit() - closing.emit() - var generation: int = _page_transition_generation - active_page.transition_out( - _finish_animated_close.bind(generation, applied_result), - 0.0 - ) - - -func _finish_animated_close( - generation: int, - applied_result: bool, -) -> void: - if generation != _page_transition_generation or not _page_transition_active: - return - _finish_panel_close(applied_result) - - -func _cancel_page_transition() -> void: - _page_transition_generation += 1 - _page_transition_active = false - - -func _show_active_page(should_focus: bool) -> void: - for page_id: StringName in _pages: - var page: SettingsBubblePage = _pages[page_id] - if page_id == get_active_page_id(): - page.show_page(should_focus) - else: - page.hide_page() - if get_active_page_id() == PAGE_DATA: - _refresh_data_page() - if should_focus: - %OpenDataFolder.call_deferred("grab_focus") - - func _refresh_data_page() -> void: if not is_node_ready() or _data_root == null: return %DataFolderPath.text = _data_root.root_path - %DataStorageMode.text = "Storage Mode: " + _data_root.storage_mode_text() + %DataStorageMode.text = "storage mode: " + _data_root.storage_mode_text() %ChangeDataFolder.disabled = ( _data_root.override_active or (_network_session != null and _network_session.is_session_active()) @@ -699,14 +624,15 @@ func _refresh_data_page() -> void: fingerprint ) %CopyPlayerFingerprint.text = ( - "Copy Player Fingerprint · %s" + "copy player fingerprint · %s" % NetworkIdentityCrypto.compact_suffix(fingerprint) ) + call_deferred("_configure_controller_navigation") func _open_data_folder() -> void: if _data_root == null or not _data_root.open_folder(): - _feedback.text = "Could not open the data folder." + _feedback.text = "could not open the data folder." func _copy_player_fingerprint() -> void: @@ -714,18 +640,18 @@ func _copy_player_fingerprint() -> void: _player_identity.fingerprint if _player_identity != null else "" ) if not NetworkIdentityCrypto.valid_fingerprint(fingerprint): - _feedback.text = "Player identity is unavailable." + _feedback.text = "player identity is unavailable." return DisplayServer.clipboard_set(fingerprint) - _feedback.text = "Full player fingerprint copied for server operator setup." + _feedback.text = "full player fingerprint copied for server operator setup." func _choose_data_folder() -> void: if _data_root == null or _data_root.override_active: - _feedback.text = "The data folder is externally managed." + _feedback.text = "the data folder is externally managed." return if _network_session != null and _network_session.is_session_active(): - _feedback.text = "Return to title to change the data folder." + _feedback.text = "return to title to change the data folder." return if _data_folder_dialog == null: _data_folder_dialog = FileDialog.new() @@ -747,25 +673,27 @@ func _change_data_folder(path: String) -> void: _show_existing_data_folder_choice(path) return if bool(result.get("ok", false)): - _feedback.text = "Data folder changed. NETfishing will close safely." + _feedback.text = "data folder changed. NETfishing will close safely." _refresh_data_page() get_tree().call_deferred("quit") else: - _feedback.text = str(result.get("message", "Could not change the data folder.")) + _feedback.text = str( + result.get("message", "could not change the data folder.") + ) func _show_existing_data_folder_choice(path: String) -> void: - var dialog: ConfirmationDialog = ConfirmationDialog.new() - dialog.title = "Existing NETfishing data" - dialog.ok_button_text = "Use Selected Data" + var dialog := ConfirmationDialog.new() + dialog.title = "existing NETfishing data" + dialog.ok_button_text = "use selected data" dialog.dialog_text = ( - "The selected folder contains different NETfishing data.\n\n" - + "Choose one complete data set. Data will not be merged." + "the selected folder contains different NETfishing data.\n\n" + + "choose one complete data set. data will not be merged." ) - dialog.add_button("Replace Selected Data", false, "replace") + dialog.add_button("replace selected data", false, "replace") dialog.confirmed.connect(func() -> void: if _data_root.use_existing_root(path): - _feedback.text = "Data folder changed. NETfishing will close safely." + _feedback.text = "data folder changed. NETfishing will close safely." get_tree().call_deferred("quit") else: _feedback.text = _data_root.error_message @@ -777,7 +705,9 @@ func _show_existing_data_folder_choice(path: String) -> void: var result: Dictionary = PortableDataMigration.replace_existing_with_active( _data_root, path ) - _feedback.text = str(result.get("message", "Could not replace selected data.")) + _feedback.text = str( + result.get("message", "could not replace selected data.") + ) if bool(result.get("ok", false)): get_tree().call_deferred("quit") dialog.queue_free() @@ -801,8 +731,12 @@ func _choose_identity_export(identity_type: String) -> void: _export_file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE _export_file_dialog.access = FileDialog.ACCESS_FILESYSTEM _export_file_dialog.use_native_dialog = false - _export_file_dialog.filters = PackedStringArray(["*.nfidentity ; NETfishing identity backup"]) - _export_file_dialog.file_selected.connect(_identity_export_file_selected) + _export_file_dialog.filters = PackedStringArray([ + "*.nfidentity ; NETfishing identity backup", + ]) + _export_file_dialog.file_selected.connect( + _identity_export_file_selected + ) _interface_fonts.apply_utility_theme(_export_file_dialog) add_child(_export_file_dialog) _export_file_dialog.current_dir = suggested.get_base_dir() @@ -827,8 +761,12 @@ func _choose_identity_import(identity_type: String) -> void: _backup_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE _backup_file_dialog.access = FileDialog.ACCESS_FILESYSTEM _backup_file_dialog.use_native_dialog = false - _backup_file_dialog.filters = PackedStringArray(["*.nfidentity ; NETfishing identity backup"]) - _backup_file_dialog.file_selected.connect(_identity_import_file_selected) + _backup_file_dialog.filters = PackedStringArray([ + "*.nfidentity ; NETfishing identity backup", + ]) + _backup_file_dialog.file_selected.connect( + _identity_import_file_selected + ) _interface_fonts.apply_utility_theme(_backup_file_dialog) add_child(_backup_file_dialog) _backup_file_dialog.current_dir = _data_root.identity_backup_directory() @@ -843,21 +781,21 @@ func _identity_import_file_selected(path: String) -> void: func _show_passphrase_dialog(exporting: bool) -> void: if _passphrase_dialog == null: _passphrase_dialog = ConfirmationDialog.new() - _passphrase_dialog.title = "Encrypted identity backup" + _passphrase_dialog.title = "encrypted identity backup" _passphrase_dialog.confirmed.connect(_submit_identity_passphrase) - var fields: VBoxContainer = VBoxContainer.new() - var warning: Label = Label.new() + var fields := VBoxContainer.new() + var warning := Label.new() warning.text = ( - "Anyone with this backup and passphrase can use your identity." + "anyone with this backup and passphrase can use your identity." ) warning.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART fields.add_child(warning) _passphrase_entry = LineEdit.new() - _passphrase_entry.placeholder_text = "Passphrase (12 characters minimum)" + _passphrase_entry.placeholder_text = "passphrase (12 characters minimum)" _passphrase_entry.secret = true fields.add_child(_passphrase_entry) _passphrase_confirm = LineEdit.new() - _passphrase_confirm.placeholder_text = "Confirm passphrase" + _passphrase_confirm.placeholder_text = "confirm passphrase" _passphrase_confirm.secret = true fields.add_child(_passphrase_confirm) _passphrase_dialog.add_child(fields) @@ -867,8 +805,8 @@ func _show_passphrase_dialog(exporting: bool) -> void: _passphrase_entry.clear() _passphrase_confirm.clear() _passphrase_dialog.dialog_text = ( - "Create a passphrase-encrypted backup." - if exporting else "Enter the backup passphrase." + "create a passphrase-encrypted backup." + if exporting else "enter the backup passphrase." ) _passphrase_dialog.popup_centered(Vector2i(560, 300)) _configure_confirmation_dialog.call_deferred( @@ -902,12 +840,12 @@ func _submit_identity_passphrase() -> void: func _show_identity_replacement_confirmation() -> void: - var dialog: ConfirmationDialog = ConfirmationDialog.new() - dialog.title = "Replace active identity?" - dialog.ok_button_text = "Review Replacement" + var dialog := ConfirmationDialog.new() + dialog.title = "replace active identity?" + dialog.ok_button_text = "review replacement" dialog.dialog_text = ( - "Current:\n%s\n\nIncoming:\n%s\n\n" - + "Other players will recognize this device as the imported identity." + "current:\n%s\n\nincoming:\n%s\n\n" + + "other players will recognize this device as the imported identity." ) % [ NetworkIdentityCrypto.format_fingerprint(_pending_import_data["current"]), NetworkIdentityCrypto.format_fingerprint(_pending_import_data["incoming"]), @@ -926,9 +864,9 @@ func _show_identity_replacement_confirmation() -> void: func _advance_identity_replacement(dialog: ConfirmationDialog) -> void: if int(dialog.get_meta("confirmation_step", 1)) == 1: dialog.set_meta("confirmation_step", 2) - dialog.ok_button_text = "Replace Identity" + dialog.ok_button_text = "replace identity" dialog.dialog_text = ( - "Replace the active identity and archive the current key locally?" + "replace the active identity and archive the current key locally?" ) dialog.call_deferred("popup_centered", Vector2i(560, 280)) _configure_confirmation_dialog.call_deferred( @@ -961,10 +899,10 @@ func _configure_confirmation_dialog( func _identity_operation_allowed() -> bool: if _identity_backups == null: - _feedback.text = "Identity backup is unavailable." + _feedback.text = "identity backup is unavailable." return false if _network_session != null and _network_session.is_session_active(): - _feedback.text = "Return to title to change an identity." + _feedback.text = "return to title to change an identity." return false return true @@ -973,12 +911,8 @@ func _on_identity_operation_finished(_success: bool, message: String) -> void: _feedback.text = message -func _get_active_page() -> SettingsBubblePage: - return _pages.get(get_active_page_id()) as SettingsBubblePage - - func _apply_settings() -> void: - if _page_transition_active: + if _transition_active: return if _settings_manager == null: _feedback.text = "settings are unavailable." @@ -999,7 +933,7 @@ func _apply_settings() -> void: _presentation_mode == PresentationMode.TITLE_EMBEDDED or _animate_gameplay_host_transitions ): - _begin_animated_close(true) + _animate_panel_close(true) else: _finish_panel_close(true) else: @@ -1020,101 +954,49 @@ func _load_controls() -> void: _music_volume = settings.music_volume _effects_volume = settings.effects_volume _environment_volume = settings.environment_volume + _world_pixelation.select(settings.world_pixel_size - 1) + _ui_pixelation.select(settings.ui_pixel_size - 1) + _chat_dock.select(1 if settings.chat_dock_right else 0) + _chat_mode.select(1 if settings.chat_mobile_mode else 0) + _paint_dock.select(1 if settings.paint_dock_right else 0) + _fullscreen_toggle.set_pressed_no_signal(settings.fullscreen_enabled) _master_volume_slider.set_value_no_signal(_master_volume * 100.0) _music_volume_slider.set_value_no_signal(_music_volume * 100.0) _effects_volume_slider.set_value_no_signal(_effects_volume * 100.0) _environment_volume_slider.set_value_no_signal( _environment_volume * 100.0 ) + _mouse_sensitivity_slider.set_value_no_signal(_mouse_sensitivity) + _controller_sensitivity_slider.set_value_no_signal( + _controller_sensitivity + ) + _invert_y_toggle.set_pressed_no_signal(_invert_camera_y) + _on_screen_keyboard_toggle.set_pressed_no_signal( + _on_screen_keyboard_enabled + ) + _auto_click_toggle.set_pressed_no_signal(_auto_click_enabled) + _auto_click_interval_slider.set_value_no_signal( + _auto_click_interval_value + ) _settings_manager.restore_audio_levels() _refresh_value_labels() func _refresh_value_labels() -> void: - if _settings_manager == null: - return - var settings: PlayerSettings = _settings_manager.current_settings - _world_value.text = ( - "world\npixelation\n" - + _pixel_size_label(settings.world_pixel_size) - ) - _ui_value.text = ( - "ui\npixelation\n" - + _pixel_size_label(settings.ui_pixel_size) - ) - _chat_dock.text = "chat dock\n" + ("right" if settings.chat_dock_right else "left") - _chat_mode.text = ( - "chat mode\n" + ("mobile" if settings.chat_mobile_mode else "desktop") - ) - _paint_dock.text = ( - "paint dock\n" + ("right" if settings.paint_dock_right else "left") - ) _fullscreen_toggle.text = ( - "fullscreen\n" + ("on" if settings.fullscreen_enabled else "off") - ) - _mouse_value.text = "mouse\nsensitivity\n%.4f" % _mouse_sensitivity - _controller_value.text = ( - "controller\nsensitivity\n%.1f" % _controller_sensitivity - ) - _invert_y_toggle.text = ( - "invert\nvertical\ncamera\n" - + ("on" if _invert_camera_y else "off") + "on" if _fullscreen_toggle.button_pressed else "off" ) + _invert_y_toggle.text = "on" if _invert_camera_y else "off" _on_screen_keyboard_toggle.text = ( - "on-screen\nkeyboard\n" - + ("on" if _on_screen_keyboard_enabled else "off") + "on" if _on_screen_keyboard_enabled else "off" ) - _auto_click_toggle.text = ( - "accessibility\nauto-click\n" - + ("on" if _auto_click_enabled else "off") - ) - _auto_click_interval.text = ( - "auto-click\ninterval\n%.2f s" % _auto_click_interval_value + _auto_click_toggle.text = "on" if _auto_click_enabled else "off" + _mouse_sensitivity_value.text = "%.4f" % _mouse_sensitivity + _controller_sensitivity_value.text = "%.1f" % _controller_sensitivity + _auto_click_interval_value_label.text = ( + "%.2f s" % _auto_click_interval_value ) _refresh_audio_value_labels() - for index: int in _world_options.size(): - _world_options[index].button_pressed = ( - index + 1 == settings.world_pixel_size - ) - for index: int in _ui_options.size(): - _ui_options[index].button_pressed = index + 1 == settings.ui_pixel_size - - -func _show_accessibility_helper(_kind: StringName) -> void: - var helper := %IntervalHelp as BubbleButton - helper.text = ( - "Lower intervals click\nbarriers faster\nwhile held." - ) - - -func _style_data_page() -> void: - UtilityPageStyle.apply_page(_data_page) - var paper := _data_page.get_node("Paper") as PanelContainer - paper.add_theme_stylebox_override( - "panel", UtilityPageStyle.panel_style() - ) - var content := _data_page.get_node("Paper/Content") as VBoxContainer - content.add_theme_constant_override("separation", 12) - for node: Node in content.find_children("*", "", true, false): - if node is BaseButton: - UtilityPageStyle.apply_ocean_button(node) - elif node is Label: - node.add_theme_color_override( - "font_color", UtilityPageStyle.OCEAN_TEXT_PRIMARY - ) - - -func _style_sound_page() -> void: - UtilityPageStyle.apply_page(_sound_page) - var paper := _sound_page.get_node("Paper") as PanelContainer - paper.add_theme_stylebox_override( - "panel", UtilityPageStyle.panel_style() - ) - var content := _sound_page.get_node("Paper/Content") as VBoxContainer - for node: Node in content.find_children("*", "Label", true, false): - (node as Label).add_theme_color_override( - "font_color", UtilityPageStyle.OCEAN_TEXT_PRIMARY - ) func _on_audio_volume_changed(value: float, channel: StringName) -> void: @@ -1147,16 +1029,22 @@ func _refresh_audio_value_labels() -> void: ) +func _on_world_pixelation_selected(index: int) -> void: + _set_world_pixelation(_world_pixelation.get_item_id(index)) + + +func _on_ui_pixelation_selected(index: int) -> void: + _set_ui_pixelation(_ui_pixelation.get_item_id(index)) + + func _set_world_pixelation(pixel_size: int) -> void: if _settings_manager == null: return if not _settings_manager.apply_pixelation( pixel_size, - _settings_manager.current_settings.ui_pixel_size + _settings_manager.current_settings.ui_pixel_size, ): _feedback.text = "failed to save pixelation settings." - return - _refresh_value_labels() func _set_ui_pixelation(pixel_size: int) -> void: @@ -1164,149 +1052,101 @@ func _set_ui_pixelation(pixel_size: int) -> void: return if not _settings_manager.apply_pixelation( _settings_manager.current_settings.world_pixel_size, - pixel_size + pixel_size, ): _feedback.text = "failed to save pixelation settings." - return - _refresh_value_labels() -func _toggle_chat_dock() -> void: - if _settings_manager == null: - return - var edited: PlayerSettings = _settings_manager.current_settings.copy() - edited.chat_dock_right = not edited.chat_dock_right - if not _settings_manager.apply_settings(edited): - _feedback.text = "failed to save chat dock setting." - return - _refresh_value_labels() - - -func _toggle_chat_mode() -> void: - if _settings_manager == null: - return - var edited: PlayerSettings = _settings_manager.current_settings.copy() - edited.chat_mobile_mode = not edited.chat_mobile_mode - if not _settings_manager.apply_settings(edited): - _feedback.text = "failed to save chat mode setting." - return - _refresh_value_labels() - - -func _toggle_fullscreen() -> void: - if _settings_manager == null: - return - var edited: PlayerSettings = _settings_manager.current_settings.copy() - edited.fullscreen_enabled = not edited.fullscreen_enabled - if not _settings_manager.apply_settings(edited): - _feedback.text = "failed to save fullscreen setting." - return - _refresh_value_labels() - - -func _toggle_paint_dock() -> void: - if _settings_manager == null: - return - var edited: PlayerSettings = _settings_manager.current_settings.copy() - edited.paint_dock_right = not edited.paint_dock_right - if not _settings_manager.apply_settings(edited): - _feedback.text = "failed to save paint dock setting." - return - _refresh_value_labels() - - -func _adjust_mouse_sensitivity(direction: int) -> void: - _mouse_sensitivity = clampf( - _mouse_sensitivity + float(direction) * 0.0005, - PlayerSettings.MIN_MOUSE_SENSITIVITY, - PlayerSettings.MAX_MOUSE_SENSITIVITY +func _on_chat_dock_selected(index: int) -> void: + _set_presentation_toggle( + &"chat_dock_right", + _chat_dock.get_item_id(index) == 1, ) - _refresh_value_labels() -func _adjust_controller_sensitivity(direction: int) -> void: - _controller_sensitivity = clampf( - _controller_sensitivity + float(direction) * 0.1, - PlayerSettings.MIN_CONTROLLER_SENSITIVITY, - PlayerSettings.MAX_CONTROLLER_SENSITIVITY +func _on_chat_mode_selected(index: int) -> void: + _set_presentation_toggle( + &"chat_mobile_mode", + _chat_mode.get_item_id(index) == 1, ) - _refresh_value_labels() -func _adjust_auto_click_interval(direction: int) -> void: - _auto_click_interval_value = clampf( - _auto_click_interval_value + float(direction) * 0.01, - PlayerSettings.MIN_AUTO_CLICK_INTERVAL, - PlayerSettings.MAX_AUTO_CLICK_INTERVAL +func _on_paint_dock_selected(index: int) -> void: + _set_presentation_toggle( + &"paint_dock_right", + _paint_dock.get_item_id(index) == 1, ) + + +func _set_fullscreen(enabled: bool) -> void: + _set_presentation_toggle(&"fullscreen_enabled", enabled) _refresh_value_labels() -func _toggle_invert_y() -> void: - _invert_camera_y = not _invert_camera_y - _refresh_value_labels() - - -func _toggle_on_screen_keyboard() -> void: - _on_screen_keyboard_enabled = not _on_screen_keyboard_enabled - _refresh_value_labels() - - -func _toggle_auto_click() -> void: - _auto_click_enabled = not _auto_click_enabled - _refresh_value_labels() - - -func _on_continuous_value_input( - event: InputEvent, - control_id: StringName, +func _set_presentation_toggle( + property_name: StringName, + enabled: bool, ) -> void: - var direction: int = 0 - if event.is_action_pressed("ui_left"): - direction = -1 - elif event.is_action_pressed("ui_right"): - direction = 1 - if direction == 0: + if _settings_manager == null: return - match control_id: - &"mouse": - _adjust_mouse_sensitivity(direction) - &"controller": - _adjust_controller_sensitivity(direction) - &"interval": - _adjust_auto_click_interval(direction) - accept_event() + var edited: PlayerSettings = _settings_manager.current_settings.copy() + edited.set(property_name, enabled) + if not _settings_manager.apply_settings(edited): + _feedback.text = "failed to save display setting." -func _pixel_size_label(pixel_size: int) -> String: - var index: int = clampi( - pixel_size - 1, - 0, - PIXELATION_NAMES.size() - 1 +func _on_mouse_sensitivity_changed(value: float) -> void: + _mouse_sensitivity = clampf( + value, + PlayerSettings.MIN_MOUSE_SENSITIVITY, + PlayerSettings.MAX_MOUSE_SENSITIVITY, ) - return PIXELATION_NAMES[index] + _refresh_value_labels() + + +func _on_controller_sensitivity_changed(value: float) -> void: + _controller_sensitivity = clampf( + value, + PlayerSettings.MIN_CONTROLLER_SENSITIVITY, + PlayerSettings.MAX_CONTROLLER_SENSITIVITY, + ) + _refresh_value_labels() + + +func _set_invert_y(enabled: bool) -> void: + _invert_camera_y = enabled + _refresh_value_labels() + + +func _set_on_screen_keyboard(enabled: bool) -> void: + _on_screen_keyboard_enabled = enabled + _refresh_value_labels() + + +func _set_auto_click(enabled: bool) -> void: + _auto_click_enabled = enabled + _refresh_value_labels() + + +func _on_auto_click_interval_changed(value: float) -> void: + _auto_click_interval_value = clampf( + value, + PlayerSettings.MIN_AUTO_CLICK_INTERVAL, + PlayerSettings.MAX_AUTO_CLICK_INTERVAL, + ) + _refresh_value_labels() func set_effective_ui_pixel_size(pixel_size: int) -> void: _effective_ui_pixel_size = clampi( pixel_size, PlayerSettings.MIN_UI_PIXEL_SIZE, - PlayerSettings.MAX_UI_PIXEL_SIZE + PlayerSettings.MAX_UI_PIXEL_SIZE, ) - if is_node_ready(): - _refresh_value_labels() func focus_back_button() -> void: - var active_page: SettingsBubblePage = _get_active_page() - if active_page != null: - active_page.focus_back() - - -func _on_back_bubble_gui_input(event: InputEvent) -> void: - if event.is_action_pressed("ui_down") or event.is_action_pressed("ui_focus_next"): - crisp_reset_focus_requested.emit() - accept_event() + _back_button.grab_focus() func refresh_open_panel() -> void: @@ -1317,19 +1157,21 @@ func refresh_open_panel() -> void: func _refresh_panel_size() -> void: if not is_node_ready(): return + custom_minimum_size = PANEL_SIZE var parent_control := get_parent() as Control - if parent_control == null: + if parent_control == null or parent_control is CenterContainer: return var available_size: Vector2 = parent_control.size - Vector2.ONE * ( PANEL_EDGE_MARGIN * 2.0 ) - var target_size := Vector2( - minf(MAX_PANEL_SIZE.x, maxf(320.0, available_size.x)), - minf(MAX_PANEL_SIZE.y, maxf(240.0, available_size.y)) + var scale_factor: float = minf( + 1.0, + minf( + available_size.x / PANEL_SIZE.x, + available_size.y / PANEL_SIZE.y, + ), ) - custom_minimum_size = target_size - if parent_control is CenterContainer: - return + var target_size: Vector2 = PANEL_SIZE * maxf(scale_factor, 0.1) set_anchors_preset(Control.PRESET_CENTER) position = (parent_control.size - target_size) * 0.5 size = target_size diff --git a/ui/settings_panel.tscn b/ui/settings_panel.tscn index 7c62481..2aa46a6 100644 --- a/ui/settings_panel.tscn +++ b/ui/settings_panel.tscn @@ -1,170 +1,205 @@ -[gd_scene load_steps=9 format=3] +[gd_scene load_steps=4 format=3] [ext_resource type="Script" path="res://ui/settings_panel.gd" id="1_panel"] [ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"] -[ext_resource type="Script" path="res://ui/settings/settings_bubble_page.gd" id="3_page"] -[ext_resource type="PackedScene" path="res://ui/components/bubble_menu/bubble_button.tscn" id="4_bubble"] -[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_cluster.gd" id="5_cluster"] -[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="6_profile"] -[ext_resource type="Texture2D" path="res://ui/icons/pictograms/undo_dark.png" id="7_undo_dark"] -[ext_resource type="Texture2D" path="res://ui/icons/pictograms/check_mark_dark.png" id="8_check_mark_dark"] +[ext_resource type="Script" path="res://ui/components/organizer_tab.gd" id="3_tab"] [node name="SettingsPanel" type="Control"] visible = false -custom_minimum_size = Vector2(960, 700) +custom_minimum_size = Vector2(880, 660) layout_mode = 3 anchors_preset = 0 theme = ExtResource("2_theme") script = ExtResource("1_panel") -[node name="SettingsFeedback" type="Label" parent="."] +[node name="MainPanel" type="PanelContainer" parent="."] unique_name_in_owner = true layout_mode = 1 -anchors_preset = 12 +anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 -offset_top = -42.0 -offset_bottom = -8.0 grow_horizontal = 2 -grow_vertical = 0 -mouse_filter = 2 +grow_vertical = 2 + +[node name="OuterMargin" type="MarginContainer" parent="MainPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 24 +theme_override_constants/margin_top = 18 +theme_override_constants/margin_right = 24 +theme_override_constants/margin_bottom = 18 + +[node name="Layout" type="VBoxContainer" parent="MainPanel/OuterMargin"] +layout_mode = 2 +theme_override_constants/separation = 8 + +[node name="Heading" type="Label" parent="MainPanel/OuterMargin/Layout"] +layout_mode = 2 +theme_override_font_sizes/font_size = 30 +text = "settings" horizontal_alignment = 1 + +[node name="TabBar" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 52) +layout_mode = 2 +theme_override_constants/separation = 8 +alignment = 1 + +[node name="DisplayTab" type="Button" parent="MainPanel/OuterMargin/Layout/TabBar"] +unique_name_in_owner = true +custom_minimum_size = Vector2(145, 52) +layout_mode = 2 +focus_mode = 2 +text = "display" +script = ExtResource("3_tab") + +[node name="SoundTab" type="Button" parent="MainPanel/OuterMargin/Layout/TabBar"] +unique_name_in_owner = true +custom_minimum_size = Vector2(128, 52) +layout_mode = 2 +focus_mode = 2 +text = "sound" +script = ExtResource("3_tab") +palette_index = 1 + +[node name="ControlsTab" type="Button" parent="MainPanel/OuterMargin/Layout/TabBar"] +unique_name_in_owner = true +custom_minimum_size = Vector2(142, 52) +layout_mode = 2 +focus_mode = 2 +text = "controls" +script = ExtResource("3_tab") +palette_index = 2 + +[node name="AccessibilityTab" type="Button" parent="MainPanel/OuterMargin/Layout/TabBar"] +unique_name_in_owner = true +custom_minimum_size = Vector2(180, 52) +layout_mode = 2 +focus_mode = 2 +text = "accessibility" +script = ExtResource("3_tab") + +[node name="DataTab" type="Button" parent="MainPanel/OuterMargin/Layout/TabBar"] +unique_name_in_owner = true +custom_minimum_size = Vector2(115, 52) +layout_mode = 2 +focus_mode = 2 +text = "data" +script = ExtResource("3_tab") +palette_index = 1 + +[node name="ContentPanel" type="PanelContainer" parent="MainPanel/OuterMargin/Layout"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 440) +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ContentMargin" type="MarginContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel"] +layout_mode = 2 +theme_override_constants/margin_left = 28 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 28 +theme_override_constants/margin_bottom = 20 + +[node name="PageStack" type="Control" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin"] +layout_mode = 2 + +[node name="DisplayPage" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 12 + +[node name="Intro" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage"] +layout_mode = 2 +theme_override_font_sizes/font_size = 18 +text = "presentation" + +[node name="Grid" type="GridContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage"] +layout_mode = 2 +theme_override_constants/h_separation = 20 +theme_override_constants/v_separation = 10 +columns = 2 + +[node name="WorldPixelationLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "world pixelation" vertical_alignment = 1 -[node name="RootPage" type="Control" parent="."] +[node name="WorldPixelationSelector" type="OptionButton" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"root" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/DisplayCategory"), NodePath("BubbleCluster/SoundCategory"), NodePath("BubbleCluster/ControlsCategory"), NodePath("BubbleCluster/AccessibilityCategory"), NodePath("BubbleCluster/DataCategory"), NodePath("BubbleCluster/ApplySettingsButton"), NodePath("BubbleCluster/RootBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/DisplayCategory"), NodePath("BubbleCluster/SoundCategory"), NodePath("BubbleCluster/ControlsCategory"), NodePath("BubbleCluster/AccessibilityCategory"), NodePath("BubbleCluster/DataCategory"), NodePath("BubbleCluster/ApplySettingsButton"), NodePath("BubbleCluster/RootBackButton")]) -initial_focus_path = NodePath("BubbleCluster/DisplayCategory") -back_focus_path = NodePath("BubbleCluster/RootBackButton") -compact_maximum_layout_size = Vector2(544, 400) +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 -[node name="BubbleCluster" type="Control" parent="RootPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) +[node name="UIPixelationLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "ui pixelation" +vertical_alignment = 1 -[node name="DisplayCategory" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] +[node name="UIPixelationSelector" type="OptionButton" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -offset_left = 135.0 -offset_top = 90.0 -offset_right = 305.0 -offset_bottom = 250.0 -text = "display" -neutral_size = Vector2(170, 160) -desktop_anchor = Vector2(280, 180) -compact_anchor = Vector2(220, 150) -compact_minimum_size = Vector2(130, 124) -minimum_font_size = 18 -maximum_font_size = 27 -motion_phase = 0.35 +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 -[node name="ControlsCategory" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] +[node name="ChatDockLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "chat dock" +vertical_alignment = 1 + +[node name="ChatDockSelector" type="OptionButton" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -offset_left = 377.0 -offset_top = 96.0 -offset_right = 533.0 -offset_bottom = 244.0 -text = "controls" -neutral_size = Vector2(156, 148) -desktop_anchor = Vector2(440, 180) -compact_anchor = Vector2(385, 150) -compact_minimum_size = Vector2(124, 118) -minimum_font_size = 17 -maximum_font_size = 25 -motion_phase = 1.45 +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 -[node name="SoundCategory" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] +[node name="ChatModeLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "chat mode" +vertical_alignment = 1 + +[node name="ChatModeSelector" type="OptionButton" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "sound" -neutral_size = Vector2(144, 136) -desktop_anchor = Vector2(100, 180) -compact_anchor = Vector2(90, 150) -compact_minimum_size = Vector2(118, 112) -minimum_font_size = 17 -maximum_font_size = 25 -motion_phase = 2.0 +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 -[node name="AccessibilityCategory" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] +[node name="PaintDockLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "art kit dock" +vertical_alignment = 1 + +[node name="PaintDockSelector" type="OptionButton" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -offset_left = 240.0 -offset_top = 262.0 -offset_right = 420.0 -offset_bottom = 428.0 -text = "accessibility" -neutral_size = Vector2(180, 168) -desktop_anchor = Vector2(367, 328) -compact_anchor = Vector2(307, 311) -compact_minimum_size = Vector2(150, 142) -minimum_font_size = 17 -maximum_font_size = 27 -motion_phase = 2.65 +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 -[node name="ApplySettingsButton" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] +[node name="FullscreenLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] +custom_minimum_size = Vector2(260, 48) +layout_mode = 2 +text = "fullscreen" +vertical_alignment = 1 + +[node name="FullscreenToggle" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DisplayPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -offset_left = 474.0 -offset_top = 308.0 -offset_right = 586.0 -offset_bottom = 412.0 -icon = ExtResource("8_check_mark_dark") -tooltip_text = "apply" -accessibility_name = "apply" -neutral_size = Vector2(112, 104) -desktop_anchor = Vector2(511, 332) -compact_anchor = Vector2(470, 330) -compact_minimum_size = Vector2(94, 90) -minimum_font_size = 15 -maximum_font_size = 19 -motion_phase = 3.7 +custom_minimum_size = Vector2(300, 48) +layout_mode = 2 +focus_mode = 2 +toggle_mode = true +text = "off" -[node name="DataCategory" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "data &\nidentity" -neutral_size = Vector2(140, 132) -desktop_anchor = Vector2(610, 220) -compact_anchor = Vector2(540, 205) -compact_minimum_size = Vector2(116, 108) -minimum_font_size = 14 -maximum_font_size = 21 -motion_phase = 5.4 - -[node name="RootBackButton" parent="RootPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -offset_left = 70.0 -offset_top = 343.0 -offset_right = 170.0 -offset_bottom = 437.0 -icon = ExtResource("7_undo_dark") -tooltip_text = "back" -accessibility_name = "back" -neutral_size = Vector2(100, 94) -desktop_anchor = Vector2(220, 300) -compact_anchor = Vector2(155, 275) -compact_minimum_size = Vector2(84, 80) -minimum_font_size = 14 -maximum_font_size = 17 -motion_phase = 4.8 - -[node name="DisplayPage" type="Control" parent="."] +[node name="SoundPage" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack"] unique_name_in_owner = true visible = false layout_mode = 1 @@ -173,797 +208,432 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"display" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/WorldValue"), NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UIValue"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/ChatMode"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/FullscreenToggle"), NodePath("BubbleCluster/DisplayBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/ChatMode"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/FullscreenToggle"), NodePath("BubbleCluster/DisplayBackButton")]) -initial_focus_path = NodePath("BubbleCluster/WorldRetro") -back_focus_path = NodePath("BubbleCluster/DisplayBackButton") -compact_maximum_layout_size = Vector2(544, 400) +theme_override_constants/separation = 14 -[node name="BubbleCluster" type="Control" parent="DisplayPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) - -[node name="WorldValue" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -mouse_filter = 2 -focus_mode = 0 -text = "world\npixelation\nretro" -neutral_size = Vector2(140, 130) -desktop_anchor = Vector2(160, 240) -compact_anchor = Vector2(175, 210) -compact_minimum_size = Vector2(118, 110) -minimum_font_size = 15 -maximum_font_size = 22 -motion_phase = 0.2 - -[node name="WorldLegible" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "legible" -neutral_size = Vector2(90, 84) -desktop_anchor = Vector2(55, 175) -compact_anchor = Vector2(57, 135) -compact_minimum_size = Vector2(76, 72) -minimum_font_size = 12 -maximum_font_size = 15 -motion_phase = 0.8 - -[node name="WorldCute" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "cute" -neutral_size = Vector2(82, 78) -desktop_anchor = Vector2(130, 124) -compact_anchor = Vector2(145, 78) -compact_minimum_size = Vector2(70, 68) -minimum_font_size = 12 -maximum_font_size = 14 -motion_phase = 1.35 - -[node name="WorldRetro" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -button_pressed = true -text = "retro" -neutral_size = Vector2(84, 80) -desktop_anchor = Vector2(237, 149) -compact_anchor = Vector2(272, 115) -compact_minimum_size = Vector2(72, 68) -minimum_font_size = 12 -maximum_font_size = 14 -motion_phase = 1.9 - -[node name="WorldHardcore" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "hardcore" -neutral_size = Vector2(100, 94) -desktop_anchor = Vector2(288, 240) -compact_anchor = Vector2(70, 310) -compact_minimum_size = Vector2(88, 84) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 2.45 - -[node name="WorldWtf" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "wtf" -neutral_size = Vector2(76, 72) -desktop_anchor = Vector2(225, 337) -compact_anchor = Vector2(284, 284) -compact_minimum_size = Vector2(66, 64) -minimum_font_size = 12 -maximum_font_size = 13 -motion_phase = 3.0 - -[node name="UIValue" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -mouse_filter = 2 -focus_mode = 0 -text = "ui\npixelation\nretro" -neutral_size = Vector2(140, 130) -desktop_anchor = Vector2(560, 240) -compact_anchor = Vector2(545, 210) -compact_minimum_size = Vector2(118, 110) -minimum_font_size = 15 -maximum_font_size = 22 -motion_phase = 3.55 - -[node name="UILegible" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "legible" -neutral_size = Vector2(90, 84) -desktop_anchor = Vector2(665, 175) -compact_anchor = Vector2(663, 135) -compact_minimum_size = Vector2(76, 72) -minimum_font_size = 12 -maximum_font_size = 15 -motion_phase = 4.1 - -[node name="UICute" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "cute" -neutral_size = Vector2(82, 78) -desktop_anchor = Vector2(590, 124) -compact_anchor = Vector2(575, 78) -compact_minimum_size = Vector2(70, 68) -minimum_font_size = 12 -maximum_font_size = 14 -motion_phase = 4.65 - -[node name="UIRetro" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -button_pressed = true -text = "retro" -neutral_size = Vector2(84, 80) -desktop_anchor = Vector2(483, 149) -compact_anchor = Vector2(448, 115) -compact_minimum_size = Vector2(72, 68) -minimum_font_size = 12 -maximum_font_size = 14 -motion_phase = 5.2 - -[node name="UIHardcore" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "hardcore" -neutral_size = Vector2(100, 94) -desktop_anchor = Vector2(432, 240) -compact_anchor = Vector2(650, 310) -compact_minimum_size = Vector2(88, 84) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 5.75 - -[node name="UIWtf" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -toggle_mode = true -text = "wtf" -neutral_size = Vector2(76, 72) -desktop_anchor = Vector2(495, 337) -compact_anchor = Vector2(436, 284) -compact_minimum_size = Vector2(66, 64) -minimum_font_size = 12 -maximum_font_size = 13 -motion_phase = 0.55 - -[node name="ChatDock" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "chat dock\nleft" -neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(70, 435) -compact_anchor = Vector2(55, 378) -compact_minimum_size = Vector2(82, 82) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 1.1 - -[node name="ChatMode" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "chat mode\ndesktop" -neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(215, 435) -compact_anchor = Vector2(180, 378) -compact_minimum_size = Vector2(82, 82) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 1.4 - -[node name="PaintDock" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "paint dock\nright" -neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(360, 435) -compact_anchor = Vector2(305, 378) -compact_minimum_size = Vector2(82, 82) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 1.7 - -[node name="FullscreenToggle" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "fullscreen\noff" -neutral_size = Vector2(104, 96) -desktop_anchor = Vector2(505, 435) -compact_anchor = Vector2(430, 378) -compact_minimum_size = Vector2(88, 82) -minimum_font_size = 11 -maximum_font_size = 15 -motion_phase = 1.85 - -[node name="DisplayBackButton" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "back" -neutral_size = Vector2(96, 90) -desktop_anchor = Vector2(650, 435) -compact_anchor = Vector2(555, 378) -compact_minimum_size = Vector2(82, 78) -minimum_font_size = 13 -maximum_font_size = 16 -motion_phase = 2.15 - -[node name="SoundPage" type="Control" parent="."] -unique_name_in_owner = true -visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"sound" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/SoundBackButton")]) -focus_paths = Array[NodePath]([NodePath("Paper/Content/VolumeGrid/MasterVolumeSlider"), NodePath("Paper/Content/VolumeGrid/MusicVolumeSlider"), NodePath("Paper/Content/VolumeGrid/EffectsVolumeSlider"), NodePath("Paper/Content/VolumeGrid/EnvironmentVolumeSlider"), NodePath("BubbleCluster/SoundBackButton")]) -initial_focus_path = NodePath("Paper/Content/VolumeGrid/MasterVolumeSlider") -back_focus_path = NodePath("BubbleCluster/SoundBackButton") -back_entry_path = NodePath("Paper/Content/VolumeGrid/EnvironmentVolumeSlider") -compact_maximum_layout_size = Vector2(544, 400) - -[node name="BubbleCluster" type="Control" parent="SoundPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) - -[node name="Paper" type="PanelContainer" parent="SoundPage"] -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -310.0 -offset_top = -230.0 -offset_right = 310.0 -offset_bottom = 205.0 -grow_horizontal = 2 -grow_vertical = 2 -z_index = 1 - -[node name="Content" type="VBoxContainer" parent="SoundPage/Paper"] +[node name="Intro" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage"] layout_mode = 2 -theme_override_constants/separation = 18 +theme_override_font_sizes/font_size = 18 +text = "audio mix" -[node name="Heading" type="Label" parent="SoundPage/Paper/Content"] +[node name="Grid" type="GridContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage"] layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "sound" -horizontal_alignment = 1 - -[node name="Helper" type="Label" parent="SoundPage/Paper/Content"] -layout_mode = 2 -text = "Adjust the mix. Changes are saved when you apply settings." -horizontal_alignment = 1 - -[node name="VolumeGrid" type="GridContainer" parent="SoundPage/Paper/Content"] -layout_mode = 2 -theme_override_constants/h_separation = 16 +theme_override_constants/h_separation = 18 theme_override_constants/v_separation = 18 columns = 3 -[node name="MasterLabel" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] -custom_minimum_size = Vector2(118, 42) +[node name="MasterLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] +custom_minimum_size = Vector2(180, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "master" vertical_alignment = 1 -[node name="MasterVolumeSlider" type="HSlider" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="MasterVolumeSlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(350, 42) +custom_minimum_size = Vector2(390, 48) layout_mode = 2 focus_mode = 2 -tooltip_text = "master volume" max_value = 100.0 step = 1.0 value = 100.0 -[node name="MasterVolumeValue" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="MasterVolumeValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(70, 42) +custom_minimum_size = Vector2(70, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "100%" horizontal_alignment = 2 vertical_alignment = 1 -[node name="MusicLabel" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] -custom_minimum_size = Vector2(118, 42) +[node name="MusicLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] +custom_minimum_size = Vector2(180, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "music" vertical_alignment = 1 -[node name="MusicVolumeSlider" type="HSlider" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="MusicVolumeSlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(350, 42) +custom_minimum_size = Vector2(390, 48) layout_mode = 2 focus_mode = 2 -tooltip_text = "music volume" max_value = 100.0 step = 1.0 value = 100.0 -[node name="MusicVolumeValue" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="MusicVolumeValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(70, 42) +custom_minimum_size = Vector2(70, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "100%" horizontal_alignment = 2 vertical_alignment = 1 -[node name="EffectsLabel" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] -custom_minimum_size = Vector2(118, 42) +[node name="EffectsLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] +custom_minimum_size = Vector2(180, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "effects" vertical_alignment = 1 -[node name="EffectsVolumeSlider" type="HSlider" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="EffectsVolumeSlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(350, 42) +custom_minimum_size = Vector2(390, 48) layout_mode = 2 focus_mode = 2 -tooltip_text = "effects volume" max_value = 100.0 step = 1.0 value = 100.0 -[node name="EffectsVolumeValue" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="EffectsVolumeValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(70, 42) +custom_minimum_size = Vector2(70, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "100%" horizontal_alignment = 2 vertical_alignment = 1 -[node name="EnvironmentLabel" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] -custom_minimum_size = Vector2(118, 42) +[node name="EnvironmentLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] +custom_minimum_size = Vector2(180, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "environment" vertical_alignment = 1 -[node name="EnvironmentVolumeSlider" type="HSlider" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="EnvironmentVolumeSlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(350, 42) +custom_minimum_size = Vector2(390, 48) layout_mode = 2 focus_mode = 2 -tooltip_text = "environment volume" max_value = 100.0 step = 1.0 value = 100.0 -[node name="EnvironmentVolumeValue" type="Label" parent="SoundPage/Paper/Content/VolumeGrid"] +[node name="EnvironmentVolumeValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage/Grid"] unique_name_in_owner = true -custom_minimum_size = Vector2(70, 42) +custom_minimum_size = Vector2(70, 48) layout_mode = 2 -theme_override_font_sizes/font_size = 18 text = "100%" horizontal_alignment = 2 vertical_alignment = 1 -[node name="SoundBackButton" parent="SoundPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -z_index = 4 -layout_mode = 0 -text = "back" -neutral_size = Vector2(96, 90) -desktop_anchor = Vector2(60, 460) -compact_anchor = Vector2(55, 410) -compact_minimum_size = Vector2(82, 78) -minimum_font_size = 13 -maximum_font_size = 16 -motion_phase = 5.0 - -[node name="ControlsPage" type="Control" parent="."] -unique_name_in_owner = true -visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"controls" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/MouseDecrease"), NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/MouseIncrease"), NodePath("BubbleCluster/ControllerDecrease"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/ControllerIncrease"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/OnScreenKeyboardToggle"), NodePath("BubbleCluster/ControllerMapping"), NodePath("BubbleCluster/KeyboardMapping"), NodePath("BubbleCluster/ControlsBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/OnScreenKeyboardToggle"), NodePath("BubbleCluster/ControllerMapping"), NodePath("BubbleCluster/KeyboardMapping"), NodePath("BubbleCluster/ControlsBackButton")]) -initial_focus_path = NodePath("BubbleCluster/MouseValue") -back_focus_path = NodePath("BubbleCluster/ControlsBackButton") - -[node name="BubbleCluster" type="Control" parent="ControlsPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) - -[node name="MouseDecrease" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "−" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(75, 140) -compact_anchor = Vector2(49, 125) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 0.3 - -[node name="MouseValue" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "mouse\nsensitivity\n0.0050" -neutral_size = Vector2(190, 180) -desktop_anchor = Vector2(210, 140) -compact_anchor = Vector2(200, 125) -compact_minimum_size = Vector2(160, 152) -minimum_font_size = 15 -maximum_font_size = 25 -motion_phase = 1.0 - -[node name="MouseIncrease" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "+" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(345, 140) -compact_anchor = Vector2(351, 125) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 1.7 - -[node name="ControllerDecrease" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "−" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(75, 365) -compact_anchor = Vector2(49, 340) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 2.4 - -[node name="ControllerValue" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "controller\nsensitivity\n2.5" -neutral_size = Vector2(190, 180) -desktop_anchor = Vector2(210, 365) -compact_anchor = Vector2(200, 340) -compact_minimum_size = Vector2(160, 152) -minimum_font_size = 15 -maximum_font_size = 25 -motion_phase = 3.1 - -[node name="ControllerIncrease" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "+" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(345, 365) -compact_anchor = Vector2(351, 340) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 3.8 - -[node name="InvertYToggle" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "invert\nvertical\ncamera\noff" -neutral_size = Vector2(176, 170) -compact_minimum_size = Vector2(170, 164) -minimum_font_size = 14 -maximum_font_size = 24 -desktop_anchor = Vector2(525, 105) -compact_anchor = Vector2(485, 95) -motion_phase = 4.5 - -[node name="OnScreenKeyboardToggle" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "on-screen\nkeyboard\noff" -neutral_size = Vector2(170, 150) -compact_minimum_size = Vector2(154, 136) -minimum_font_size = 14 -maximum_font_size = 22 -desktop_anchor = Vector2(525, 255) -compact_anchor = Vector2(485, 235) -motion_phase = 4.7 - -[node name="ControllerMapping" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "controller\nbinds" -neutral_size = Vector2(130, 108) -desktop_anchor = Vector2(470, 390) -compact_anchor = Vector2(425, 350) -compact_minimum_size = Vector2(116, 98) -minimum_font_size = 14 -maximum_font_size = 20 -motion_phase = 4.9 - -[node name="KeyboardMapping" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "keyboard\nbinds" -neutral_size = Vector2(130, 108) -desktop_anchor = Vector2(610, 380) -compact_anchor = Vector2(545, 345) -compact_minimum_size = Vector2(116, 98) -minimum_font_size = 14 -maximum_font_size = 20 -motion_phase = 5.2 - -[node name="ControlsBackButton" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "back" -neutral_size = Vector2(100, 94) -desktop_anchor = Vector2(635, 470) -compact_anchor = Vector2(555, 420) -compact_minimum_size = Vector2(84, 80) -minimum_font_size = 14 -maximum_font_size = 17 -motion_phase = 5.5 - -[node name="AccessibilityPage" type="Control" parent="."] -unique_name_in_owner = true -visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"accessibility" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/AutoClickToggle"), NodePath("BubbleCluster/IntervalDecrease"), NodePath("BubbleCluster/AutoClickIntervalValue"), NodePath("BubbleCluster/IntervalIncrease"), NodePath("BubbleCluster/IntervalHelp"), NodePath("BubbleCluster/AccessibilityBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/AutoClickToggle"), NodePath("BubbleCluster/AutoClickIntervalValue"), NodePath("BubbleCluster/AccessibilityBackButton")]) -initial_focus_path = NodePath("BubbleCluster/AutoClickToggle") -back_focus_path = NodePath("BubbleCluster/AccessibilityBackButton") - -[node name="BubbleCluster" type="Control" parent="AccessibilityPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) - -[node name="AutoClickToggle" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "accessibility\nauto-click\noff" -neutral_size = Vector2(190, 180) -desktop_anchor = Vector2(200, 195) -compact_anchor = Vector2(129, 185) -compact_minimum_size = Vector2(160, 152) -minimum_font_size = 14 -maximum_font_size = 27 -motion_phase = 0.5 - -[node name="IntervalDecrease" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "−" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(340, 210) -compact_anchor = Vector2(280, 205) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 1.4 - -[node name="AutoClickIntervalValue" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "auto-click\ninterval\n0.20 s" -neutral_size = Vector2(190, 180) -desktop_anchor = Vector2(475, 210) -compact_anchor = Vector2(431, 205) -compact_minimum_size = Vector2(160, 152) -minimum_font_size = 14 -maximum_font_size = 26 -motion_phase = 2.3 - -[node name="IntervalIncrease" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "+" -neutral_size = Vector2(80, 76) -desktop_anchor = Vector2(610, 210) -compact_anchor = Vector2(582, 205) -compact_minimum_size = Vector2(68, 66) -minimum_font_size = 17 -maximum_font_size = 24 -motion_phase = 3.2 - -[node name="IntervalHelp" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -mouse_filter = 2 -focus_mode = 0 -text = "Focus a control\nfor a helpful\npreview." -neutral_size = Vector2(210, 176) -desktop_anchor = Vector2(315, 405) -compact_anchor = Vector2(280, 370) -compact_minimum_size = Vector2(160, 152) -minimum_font_size = 13 -maximum_font_size = 22 -motion_phase = 4.1 - -[node name="AccessibilityBackButton" parent="AccessibilityPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "back" -neutral_size = Vector2(96, 90) -desktop_anchor = Vector2(560, 420) -compact_anchor = Vector2(520, 380) -compact_minimum_size = Vector2(82, 78) -minimum_font_size = 13 -maximum_font_size = 16 -motion_phase = 5.0 - -[node name="DataPage" type="Control" parent="."] -unique_name_in_owner = true -visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_page") -page_id = &"data" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/DataBackButton")]) -focus_paths = Array[NodePath]([NodePath("Paper/Content/OpenDataFolder"), NodePath("Paper/Content/ChangeDataFolder"), NodePath("Paper/Content/CopyPlayerFingerprint"), NodePath("Paper/Content/IdentityGrid/ExportPlayerIdentity"), NodePath("Paper/Content/IdentityGrid/ImportPlayerIdentity"), NodePath("Paper/Content/IdentityGrid/ExportHostIdentity"), NodePath("Paper/Content/IdentityGrid/ImportHostIdentity"), NodePath("BubbleCluster/DataBackButton")]) -initial_focus_path = NodePath("Paper/Content/OpenDataFolder") -back_focus_path = NodePath("BubbleCluster/DataBackButton") - -[node name="BubbleCluster" type="Control" parent="DataPage"] -layout_mode = 0 -offset_right = 720.0 -offset_bottom = 520.0 -script = ExtResource("5_cluster") -profile = ExtResource("6_profile") -desktop_reference_size = Vector2(720, 520) -compact_reference_size = Vector2(608, 448) - -[node name="Paper" type="PanelContainer" parent="DataPage"] -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -330.0 -offset_top = -255.0 -offset_right = 330.0 -offset_bottom = 210.0 -grow_horizontal = 2 -grow_vertical = 2 -z_index = 1 - -[node name="Content" type="VBoxContainer" parent="DataPage/Paper"] +[node name="Helper" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/SoundPage"] layout_mode = 2 +text = "Changes are previewed immediately and saved when settings are applied." +autowrap_mode = 2 + +[node name="ControlsPage" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack"] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 12 + +[node name="Intro" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage"] +layout_mode = 2 +theme_override_font_sizes/font_size = 18 +text = "camera and input" + +[node name="Grid" type="GridContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage"] +layout_mode = 2 +theme_override_constants/h_separation = 18 +theme_override_constants/v_separation = 10 +columns = 3 + +[node name="MouseLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +custom_minimum_size = Vector2(210, 48) +layout_mode = 2 +text = "mouse sensitivity" +vertical_alignment = 1 + +[node name="MouseSensitivitySlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 48) +layout_mode = 2 +focus_mode = 2 +min_value = 0.001 +max_value = 0.012 +step = 0.0005 +value = 0.005 + +[node name="MouseSensitivityValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 48) +layout_mode = 2 +text = "0.0050" +horizontal_alignment = 2 +vertical_alignment = 1 + +[node name="ControllerLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +custom_minimum_size = Vector2(210, 48) +layout_mode = 2 +text = "controller sensitivity" +vertical_alignment = 1 + +[node name="ControllerSensitivitySlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 48) +layout_mode = 2 +focus_mode = 2 +min_value = 0.5 +max_value = 5.0 +step = 0.1 +value = 2.5 + +[node name="ControllerSensitivityValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 48) +layout_mode = 2 +text = "2.5" +horizontal_alignment = 2 +vertical_alignment = 1 + +[node name="InvertYLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +custom_minimum_size = Vector2(210, 48) +layout_mode = 2 +text = "invert vertical camera" +vertical_alignment = 1 + +[node name="InvertYToggle" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 48) +layout_mode = 2 +focus_mode = 2 +toggle_mode = true +text = "off" + +[node name="InvertYSpacer" type="Control" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +layout_mode = 2 + +[node name="KeyboardLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +custom_minimum_size = Vector2(210, 48) +layout_mode = 2 +text = "on-screen keyboard" +vertical_alignment = 1 + +[node name="OnScreenKeyboardToggle" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 48) +layout_mode = 2 +focus_mode = 2 +toggle_mode = true +text = "off" + +[node name="KeyboardSpacer" type="Control" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/Grid"] +layout_mode = 2 + +[node name="BindingButtons" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage"] +layout_mode = 2 +theme_override_constants/separation = 16 +alignment = 1 + +[node name="ControllerMapping" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/BindingButtons"] +unique_name_in_owner = true +custom_minimum_size = Vector2(300, 52) +layout_mode = 2 +focus_mode = 2 +text = "controller binds" + +[node name="KeyboardMapping" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/ControlsPage/BindingButtons"] +unique_name_in_owner = true +custom_minimum_size = Vector2(300, 52) +layout_mode = 2 +focus_mode = 2 +text = "keyboard binds" + +[node name="AccessibilityPage" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack"] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 18 + +[node name="Intro" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage"] +layout_mode = 2 +theme_override_font_sizes/font_size = 18 +text = "interaction assistance" + +[node name="Grid" type="GridContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage"] +layout_mode = 2 +theme_override_constants/h_separation = 18 +theme_override_constants/v_separation = 18 +columns = 3 + +[node name="AutoClickLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +custom_minimum_size = Vector2(210, 52) +layout_mode = 2 +text = "auto-click" +vertical_alignment = 1 + +[node name="AutoClickToggle" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 52) +layout_mode = 2 +focus_mode = 2 +toggle_mode = true +text = "off" + +[node name="AutoClickSpacer" type="Control" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +layout_mode = 2 + +[node name="IntervalLabel" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +custom_minimum_size = Vector2(210, 52) +layout_mode = 2 +text = "auto-click interval" +vertical_alignment = 1 + +[node name="AutoClickIntervalSlider" type="HSlider" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(330, 52) +layout_mode = 2 +focus_mode = 2 +min_value = 0.1 +max_value = 0.5 +step = 0.01 +value = 0.2 + +[node name="AutoClickIntervalValue" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage/Grid"] +unique_name_in_owner = true +custom_minimum_size = Vector2(100, 52) +layout_mode = 2 +text = "0.20 s" +horizontal_alignment = 2 +vertical_alignment = 1 + +[node name="IntervalHelp" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/AccessibilityPage"] +unique_name_in_owner = true +layout_mode = 2 +text = "While the fishing input is held, lower intervals clear barriers faster." +autowrap_mode = 2 + +[node name="DataPage" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack"] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 theme_override_constants/separation = 10 -[node name="Heading" type="Label" parent="DataPage/Paper/Content"] +[node name="DataFolderPath" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage"] +unique_name_in_owner = true layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "Data & Identity" +text = "Data folder unavailable" +text_overrun_behavior = 3 + +[node name="DataStorageMode" type="Label" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage"] +unique_name_in_owner = true +layout_mode = 2 +text = "storage mode unavailable" + +[node name="DataScroll" type="ScrollContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage"] +layout_mode = 2 +size_flags_vertical = 3 +horizontal_scroll_mode = 0 +follow_focus = true + +[node name="DataButtons" type="VBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 8 + +[node name="FolderRow" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="OpenDataFolder" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/FolderRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "open data folder" + +[node name="ChangeDataFolder" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/FolderRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "change data folder" + +[node name="CopyPlayerFingerprint" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +focus_mode = 2 +text = "copy player fingerprint" + +[node name="PlayerIdentityRow" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="ExportPlayerIdentity" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/PlayerIdentityRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "export player identity" + +[node name="ImportPlayerIdentity" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/PlayerIdentityRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "import player identity" + +[node name="HostIdentityRow" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="ExportHostIdentity" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/HostIdentityRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "export host identity" + +[node name="ImportHostIdentity" type="Button" parent="MainPanel/OuterMargin/Layout/ContentPanel/ContentMargin/PageStack/DataPage/DataScroll/DataButtons/HostIdentityRow"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 44) +layout_mode = 2 +size_flags_horizontal = 3 +focus_mode = 2 +text = "import host identity" + +[node name="SettingsFeedback" type="Label" parent="MainPanel/OuterMargin/Layout"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 24) +layout_mode = 2 +mouse_filter = 2 horizontal_alignment = 1 +vertical_alignment = 1 +text_overrun_behavior = 3 -[node name="DataFolderLabel" type="Label" parent="DataPage/Paper/Content"] +[node name="Footer" type="HBoxContainer" parent="MainPanel/OuterMargin/Layout"] layout_mode = 2 -text = "Data Folder:" +theme_override_constants/separation = 12 +alignment = 2 -[node name="DataFolderPath" type="Label" parent="DataPage/Paper/Content"] +[node name="ApplySettingsButton" type="Button" parent="MainPanel/OuterMargin/Layout/Footer"] unique_name_in_owner = true +custom_minimum_size = Vector2(180, 44) layout_mode = 2 -text = "Unavailable" -autowrap_mode = 2 +focus_mode = 2 +text = "apply" -[node name="DataStorageMode" type="Label" parent="DataPage/Paper/Content"] +[node name="SettingsBackButton" type="Button" parent="MainPanel/OuterMargin/Layout/Footer"] unique_name_in_owner = true +custom_minimum_size = Vector2(180, 44) layout_mode = 2 -text = "Storage Mode: unavailable" - -[node name="OpenDataFolder" type="Button" parent="DataPage/Paper/Content"] -unique_name_in_owner = true -layout_mode = 2 -text = "Open Data Folder" - -[node name="ChangeDataFolder" type="Button" parent="DataPage/Paper/Content"] -unique_name_in_owner = true -layout_mode = 2 -text = "Change Data Folder" - -[node name="IdentityHelper" type="Label" parent="DataPage/Paper/Content"] -layout_mode = 2 -text = "Active identity keys stay on this device.\nEncrypted backups can be stored in your synced data folder.\nDo not play the same profile on two devices at the same time." -autowrap_mode = 2 - -[node name="CopyPlayerFingerprint" type="Button" parent="DataPage/Paper/Content"] -unique_name_in_owner = true -layout_mode = 2 -text = "Copy Player Fingerprint" - -[node name="IdentityGrid" type="GridContainer" parent="DataPage/Paper/Content"] -layout_mode = 2 -columns = 2 - -[node name="ExportPlayerIdentity" type="Button" parent="DataPage/Paper/Content/IdentityGrid"] -unique_name_in_owner = true -layout_mode = 2 -text = "Export Player Identity" - -[node name="ImportPlayerIdentity" type="Button" parent="DataPage/Paper/Content/IdentityGrid"] -unique_name_in_owner = true -layout_mode = 2 -text = "Import Player Identity" - -[node name="ExportHostIdentity" type="Button" parent="DataPage/Paper/Content/IdentityGrid"] -unique_name_in_owner = true -layout_mode = 2 -text = "Export Host Identity" - -[node name="ImportHostIdentity" type="Button" parent="DataPage/Paper/Content/IdentityGrid"] -unique_name_in_owner = true -layout_mode = 2 -text = "Import Host Identity" - -[node name="DataBackButton" parent="DataPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -z_index = 4 -layout_mode = 0 +focus_mode = 2 text = "back" -neutral_size = Vector2(96, 90) -desktop_anchor = Vector2(-25, 470) -compact_anchor = Vector2(-20, 420) -compact_minimum_size = Vector2(82, 78) -minimum_font_size = 13 -maximum_font_size = 16 -motion_phase = 5.0