feat: complete mobile UI implementation

This commit is contained in:
shenlei
2026-09-04 19:54:33 +09:00
parent 9a4a044da5
commit b19d5b5dd3
132 changed files with 6643 additions and 180 deletions
+106
View File
@@ -15,6 +15,7 @@
# 设置持久化到 `user://system_option.cfg`= 原 systemSetting 的配置文件)。
extends Node
const MobileTouchButton = preload("res://ui/mobile/mobile_touch_button.gd")
const CFG_PATH := "user://system_option.cfg"
const CAMERA_MAX := [11.0, 20.0] # 近 / 远(game_camera.max_dist
const FOG_DENSITY := [0.055, 0.018, 0.004] # 浓 / 中 / 淡(Environment.fog_density
@@ -37,6 +38,8 @@ var _env_get: Callable = Callable()
var _win: Dictionary = {}
var _cfg := ConfigFile.new()
var _mobile_mode := false
var _mobile_root: Control
# --- 状态(= systemSetting 值)---
var music_volume := 0.6
@@ -72,18 +75,36 @@ func setup(ui_manager: CanvasLayer, assets: String, audio_node: Node = null,
# --- open / close ---------------------------------------------------
func is_open() -> bool:
if _mobile_mode:
return _mobile_root != null and is_instance_valid(_mobile_root)
return not _win.is_empty() and is_instance_valid(_win.get("root"))
func set_mobile_mode(enabled: bool) -> void:
if not enabled and _mobile_root != null:
var old_mode := _mobile_mode
_mobile_mode = true
close()
_mobile_mode = old_mode
_mobile_mode = enabled
func toggle() -> void:
if is_open(): close()
else: open()
func close() -> void:
if _mobile_mode:
if _mobile_root and is_instance_valid(_mobile_root) and ui:
ui.close(_mobile_root)
_mobile_root = null
return
if is_open():
ui.close(_win["root"])
_win = {}
func open() -> void:
if _mobile_mode:
_open_mobile()
return
if is_open():
return
var path := uiscript_dir.path_join("systemoptiondialog.py")
@@ -97,6 +118,91 @@ func open() -> void:
_wire()
_sync_controls()
func _open_mobile() -> void:
if is_open():
return
_mobile_root = Control.new()
_mobile_root.name = "MobileSystemOptionWindow"
_mobile_root.size = Vector2(680, 340)
_mobile_root.set_meta("mobile_title", "系统设置")
_mobile_root.mouse_filter = Control.MOUSE_FILTER_STOP
var panel := Panel.new()
panel.set_anchors_preset(Control.PRESET_FULL_RECT)
panel.add_theme_stylebox_override("panel", _mobile_panel_style())
_mobile_root.add_child(panel)
var content := VBoxContainer.new()
content.position = Vector2(18, 50)
content.size = Vector2(644, 270)
content.add_theme_constant_override("separation", 8)
_mobile_root.add_child(content)
_add_mobile_slider(content, "背景音乐", music_volume, func(v: float): _on_music_volume(v))
_add_mobile_slider(content, "音效", sound_volume, func(v: float): _on_sound_volume(v))
_add_mobile_radio(content, "镜头距离", ["", ""], camera_mode,
func(i: int): camera_mode = i; _apply_camera(); _save())
_add_mobile_radio(content, "", ["", "", ""], fog_level,
func(i: int): fog_level = i; _apply_fog(); _save())
_add_mobile_radio(content, "图形内存", ["CPU", "GPU"], tiling_mode,
func(i: int): tiling_mode = i; _save())
var hint := Label.new()
hint.text = "设置会自动保存;图形内存选项将在下次启动时使用"
hint.add_theme_font_size_override("font_size", 11)
hint.add_theme_color_override("font_color", Color(0.62, 0.72, 0.84))
content.add_child(hint)
ui.open(_mobile_root)
func _add_mobile_slider(parent: VBoxContainer, caption: String, initial: float, changed: Callable) -> void:
var row := HBoxContainer.new()
row.custom_minimum_size = Vector2(640, 42)
var label := Label.new()
label.text = caption
label.custom_minimum_size = Vector2(92, 38)
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.add_theme_font_size_override("font_size", 13)
row.add_child(label)
var slider := HSlider.new()
slider.min_value = 0.0
slider.max_value = 1.0
slider.step = 0.01
slider.value = initial
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.custom_minimum_size = Vector2(500, 38)
slider.value_changed.connect(changed)
row.add_child(slider)
parent.add_child(row)
func _add_mobile_radio(parent: VBoxContainer, caption: String, choices: Array, active: int, picked: Callable) -> void:
var row := HBoxContainer.new()
row.custom_minimum_size = Vector2(640, 44)
var label := Label.new()
label.text = caption
label.custom_minimum_size = Vector2(92, 40)
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.add_theme_font_size_override("font_size", 13)
row.add_child(label)
var buttons: Array[Button] = []
for i in choices.size():
var button := Button.new()
button.text = String(choices[i])
button.toggle_mode = true
button.button_pressed = i == active
button.custom_minimum_size = Vector2(100, 40)
var idx := i
button.pressed.connect(func():
for other in buttons.size():
buttons[other].set_pressed_no_signal(other == idx)
picked.call(idx))
buttons.append(button)
row.add_child(button)
parent.add_child(row)
func _mobile_panel_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.04, 0.065, 0.1, 0.98)
style.border_color = Color(0.52, 0.68, 0.9, 0.86)
style.set_border_width_all(1)
style.set_corner_radius_all(8)
return style
func _node(nm: String) -> Control:
if _win.is_empty():
return null