extends Control ## #528: Audio settings dialog — 5-bus volume sliders. ## Opens on OPEN_MENU (ESC) from main.gd. Closes on OPEN_MENU again or CLOSE button. ## Volumes persist via AudioManager._save_prefs() on each slider change. const BG_COLOR := Color(0.05, 0.05, 0.08, 0.90) const BORDER_COLOR := Color("#4a9ebb") const TEXT_COLOR := Color(0.878, 0.969, 0.98, 1) const TITLE_COLOR := Color("#4a9ebb") const FONT_SIZE := 14 const BOX_WIDTH := 460 const BOX_HEIGHT := 340 const PADDING := 20 const ROW_HEIGHT := 36 # Bus display labels → bus name strings (must match AudioManager BUS_* constants) const BUS_ROWS: Array = [ ["Music", "Music"], ["Ambient", "Ambient"], ["World SFX", "WorldSFX"], ["Player Actions", "PlayerActions"], ["UI Sounds", "UISounds"], ] var _active: bool = false var _container: VBoxContainer = null signal closed func _ready() -> void: visible = false mouse_filter = Control.MOUSE_FILTER_STOP func open() -> void: if _active: return _active = true visible = true _build_ui() queue_redraw() func close() -> void: if not _active: return _active = false visible = false _destroy_ui() queue_redraw() closed.emit() func is_open() -> bool: return _active func _build_ui() -> void: var vp_size := get_viewport_rect().size var box_pos := Vector2( (vp_size.x - BOX_WIDTH) / 2.0, (vp_size.y - BOX_HEIGHT) / 2.0 ) _container = VBoxContainer.new() _container.position = box_pos + Vector2(PADDING, PADDING + 28) _container.custom_minimum_size = Vector2(BOX_WIDTH - PADDING * 2, 0) _container.add_theme_constant_override("separation", 4) add_child(_container) for row_data in BUS_ROWS: var label_text: String = row_data[0] var bus_name: String = row_data[1] var hbox := HBoxContainer.new() hbox.custom_minimum_size = Vector2(0, ROW_HEIGHT) _container.add_child(hbox) var label := Label.new() label.text = label_text label.custom_minimum_size = Vector2(150, 0) label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER label.add_theme_font_size_override("font_size", FONT_SIZE) label.add_theme_color_override("font_color", TEXT_COLOR) hbox.add_child(label) var slider := HSlider.new() slider.min_value = -40.0 slider.max_value = 0.0 slider.step = 0.5 slider.value = AudioManager.get_volume(bus_name) slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL hbox.add_child(slider) var db_label := Label.new() db_label.text = _format_db(slider.value) db_label.custom_minimum_size = Vector2(70, 0) db_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT db_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER db_label.add_theme_font_size_override("font_size", FONT_SIZE) db_label.add_theme_color_override("font_color", TEXT_COLOR) hbox.add_child(db_label) slider.value_changed.connect(func(value: float) -> void: AudioManager.set_volume(bus_name, value) db_label.text = _format_db(value) ) # Spacer var spacer := Control.new() spacer.custom_minimum_size = Vector2(0, 8) _container.add_child(spacer) # Close button var close_btn := Button.new() close_btn.text = "CLOSE" close_btn.add_theme_font_size_override("font_size", FONT_SIZE) close_btn.pressed.connect(close) _container.add_child(close_btn) # Quit to Menu button (#258: D-085 session management) var quit_btn := Button.new() quit_btn.text = UIStrings.get_text("menu.quit_to_menu") quit_btn.add_theme_font_size_override("font_size", FONT_SIZE) quit_btn.add_theme_color_override("font_color", Color("#c87040")) quit_btn.pressed.connect(_on_quit_to_menu) _container.add_child(quit_btn) func _destroy_ui() -> void: if _container: _container.queue_free() _container = null func _draw() -> void: if not _active: return var viewport_size := get_viewport_rect().size # Dim overlay draw_rect(Rect2(Vector2.ZERO, viewport_size), BG_COLOR) # Dialog box var box_pos := Vector2( (viewport_size.x - BOX_WIDTH) / 2.0, (viewport_size.y - BOX_HEIGHT) / 2.0 ) var box_rect := Rect2(box_pos, Vector2(BOX_WIDTH, BOX_HEIGHT)) draw_rect(box_rect, Color(0.08, 0.08, 0.12, 0.95)) draw_rect(box_rect, BORDER_COLOR, false, 1.0) # Title var font := ThemeDB.fallback_font draw_string(font, box_pos + Vector2(PADDING, PADDING + 18), "AUDIO SETTINGS", HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE + 2, TITLE_COLOR) func _on_quit_to_menu() -> void: close() SessionManager.quit_to_menu() static func _format_db(db: float) -> String: if db <= -40.0: return "mute" return "%d dB" % int(db)