aboutsummaryrefslogtreecommitdiff
path: root/game/src/OptionMenu
diff options
context:
space:
mode:
author Spartan322 <Megacake1234@gmail.com>2023-02-10 10:18:46 +0100
committer Spartan322 <Megacake1234@gmail.com>2023-02-10 10:31:28 +0100
commit3798205c740e7e2faf2594866cb497260012508c (patch)
tree4ca4a0835cb833fbba1983f0e8de5fa66227b86e /game/src/OptionMenu
parent6525b89a37a31eaf88182b11410bd46b6658e297 (diff)
Implement a usable settings UI, should fulfill:
SS-58, SS-61, SS-6, SS-9, SS-10, SS-11, SS-13 UI-11, UI-12, UI-19, UI-44, UI-47, UI-22
Diffstat (limited to 'game/src/OptionMenu')
-rw-r--r--game/src/OptionMenu/MonitorDisplaySelector.gd16
-rw-r--r--game/src/OptionMenu/OptionsMenu.gd72
-rw-r--r--game/src/OptionMenu/OptionsMenu.tscn181
-rw-r--r--game/src/OptionMenu/ResolutionSelector.gd24
-rw-r--r--game/src/OptionMenu/ScreenModeSelector.gd33
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingHSlider.gd20
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingOptionButton.gd22
-rw-r--r--game/src/OptionMenu/VolumeGrid.gd54
-rw-r--r--game/src/OptionMenu/VolumeGrid.tscn8
9 files changed, 430 insertions, 0 deletions
diff --git a/game/src/OptionMenu/MonitorDisplaySelector.gd b/game/src/OptionMenu/MonitorDisplaySelector.gd
new file mode 100644
index 0000000..600b296
--- /dev/null
+++ b/game/src/OptionMenu/MonitorDisplaySelector.gd
@@ -0,0 +1,16 @@
+extends SettingOptionButton
+
+
+func _ready():
+ clear()
+ for screen_index in range(DisplayServer.get_screen_count()):
+ add_item("Monitor %d" % (screen_index + 1))
+
+func _on_item_selected(index):
+ print("Selected index: %d" % index)
+ var window := get_viewport().get_window()
+ var mode := window.mode
+ window.mode = Window.MODE_WINDOWED
+ get_viewport().get_window().set_current_screen(index)
+ window.mode = mode
+ print(get_viewport().get_window().current_screen)
diff --git a/game/src/OptionMenu/OptionsMenu.gd b/game/src/OptionMenu/OptionsMenu.gd
new file mode 100644
index 0000000..e3c8433
--- /dev/null
+++ b/game/src/OptionMenu/OptionsMenu.gd
@@ -0,0 +1,72 @@
+extends Control
+
+@export
+var user_settings_file_path : String = "settings.cfg"
+
+signal back_button_pressed
+
+signal save_settings(save_file: ConfigFile)
+signal load_settings(load_file: ConfigFile)
+signal reset_settings()
+
+@onready
+var _settings_file_path := "user://" + user_settings_file_path
+var _settings_file := ConfigFile.new()
+
+func _ready():
+ # Prepare options menu before loading user settings
+
+ print("TODO: Load user settings!")
+
+ if FileAccess.file_exists(_settings_file_path):
+ _settings_file.load(_settings_file_path)
+ load_settings.emit(_settings_file)
+
+ var tab_bar : TabBar = $Margin/Tab.get_child(0, true)
+
+ # This ends up easier to manage then trying to manually recreate the TabContainer's behavior
+ # These buttons can be accessed regardless of the tab
+ var button_list := HBoxContainer.new()
+ button_list.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
+ button_list.alignment = BoxContainer.ALIGNMENT_END
+ tab_bar.add_child(button_list)
+
+ var reset_button := Button.new()
+ reset_button.text = "R"
+ reset_button.pressed.connect(func(): reset_settings.emit())
+ button_list.add_child(reset_button)
+
+ var back_button := Button.new()
+ back_button.text = "X"
+ back_button.pressed.connect(_on_back_button_pressed)
+ button_list.add_child(back_button)
+
+ get_viewport().get_window().close_requested.connect(_on_window_close_requested)
+
+func _notification(what):
+ match what:
+ NOTIFICATION_CRASH:
+ _on_window_close_requested()
+
+# Could pass the LocaleButton between the MainMenu and OptionsMenu
+# but that seems a bit excessive
+func toggle_locale_button_visibility(locale_visible : bool):
+ print("Toggling locale button: %s" % locale_visible)
+ $LocaleVBox/LocaleHBox/LocaleButton.visible = locale_visible
+
+func _on_ear_exploder_toggled(button_pressed):
+ print("KABOOM!!!" if button_pressed else "DEFUSED!!!")
+
+
+func _on_back_button_pressed():
+ save_settings.emit(_settings_file)
+ _settings_file.save(_settings_file_path)
+ back_button_pressed.emit()
+
+
+func _on_spin_box_value_changed(value):
+ print("Spinbox: %d" % value)
+
+func _on_window_close_requested() -> void:
+ if visible:
+ _on_back_button_pressed()
diff --git a/game/src/OptionMenu/OptionsMenu.tscn b/game/src/OptionMenu/OptionsMenu.tscn
new file mode 100644
index 0000000..0ed531f
--- /dev/null
+++ b/game/src/OptionMenu/OptionsMenu.tscn
@@ -0,0 +1,181 @@
+[gd_scene load_steps=7 format=3 uid="uid://cnbfxjy1m6wja"]
+
+[ext_resource type="Script" path="res://src/OptionMenu/OptionsMenu.gd" id="1_tlein"]
+[ext_resource type="PackedScene" uid="uid://b7oncobnacxmt" path="res://src/LocaleButton.tscn" id="2_d7wvq"]
+[ext_resource type="Script" path="res://src/OptionMenu/ResolutionSelector.gd" id="2_jk1ey"]
+[ext_resource type="Script" path="res://src/OptionMenu/ScreenModeSelector.gd" id="3_hsicf"]
+[ext_resource type="Script" path="res://src/OptionMenu/MonitorDisplaySelector.gd" id="3_q1cm3"]
+[ext_resource type="PackedScene" uid="uid://dy4si8comamnv" path="res://src/OptionMenu/VolumeGrid.tscn" id="4_n4oqr"]
+
+[node name="OptionsMenu" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_tlein")
+
+[node name="Margin" type="MarginContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme_override_constants/margin_left = 250
+theme_override_constants/margin_top = 100
+theme_override_constants/margin_right = 250
+theme_override_constants/margin_bottom = 200
+
+[node name="Tab" type="TabContainer" parent="Margin"]
+layout_mode = 2
+size_flags_vertical = 3
+tab_alignment = 1
+use_hidden_tabs_for_min_size = true
+
+[node name="Video" type="HBoxContainer" parent="Margin/Tab"]
+layout_mode = 2
+tooltip_text = "This is my cool and very nice tooltip"
+alignment = 1
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Margin/Tab/Video"]
+layout_mode = 2
+
+[node name="Control" type="Control" parent="Margin/Tab/Video/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+size_flags_stretch_ratio = 0.1
+
+[node name="GridContainer" type="GridContainer" parent="Margin/Tab/Video/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+columns = 2
+
+[node name="ResolutionLabel" type="Label" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+text = "Resolution"
+
+[node name="ResolutionSelector" type="OptionButton" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+item_count = 1
+selected = 0
+popup/item_0/text = "MISSING"
+popup/item_0/id = 0
+script = ExtResource("2_jk1ey")
+section_name = "Video"
+setting_name = "Resolution"
+default_value = -1
+
+[node name="ScreenModeLabel" type="Label" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+text = "Screen Mode"
+
+[node name="ScreenModeSelector" type="OptionButton" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+item_count = 3
+selected = 0
+popup/item_0/text = "Fullscreen"
+popup/item_0/id = 0
+popup/item_1/text = "Borderless"
+popup/item_1/id = 1
+popup/item_2/text = "Windowed"
+popup/item_2/id = 2
+script = ExtResource("3_hsicf")
+section_name = "Video"
+setting_name = "Mode Selected"
+
+[node name="MonitorSelectionLabel" type="Label" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+text = "Monitor Selection"
+
+[node name="MonitorDisplaySelector" type="OptionButton" parent="Margin/Tab/Video/VBoxContainer/GridContainer"]
+layout_mode = 2
+item_count = 1
+selected = 0
+popup/item_0/text = "MISSING"
+popup/item_0/id = 0
+script = ExtResource("3_q1cm3")
+section_name = "Video"
+setting_name = "Current Screen"
+
+[node name="Sound" type="HBoxContainer" parent="Margin/Tab"]
+visible = false
+layout_mode = 2
+alignment = 1
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Margin/Tab/Sound"]
+layout_mode = 2
+
+[node name="Control" type="Control" parent="Margin/Tab/Sound/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+size_flags_stretch_ratio = 0.1
+
+[node name="VolumeGrid" parent="Margin/Tab/Sound/VBoxContainer" instance=ExtResource("4_n4oqr")]
+layout_mode = 2
+
+[node name="ButtonGrid" type="GridContainer" parent="Margin/Tab/Sound/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 2
+columns = 2
+
+[node name="Spacer" type="Control" parent="Margin/Tab/Sound/VBoxContainer/ButtonGrid"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="EarExploder" type="CheckButton" parent="Margin/Tab/Sound/VBoxContainer/ButtonGrid"]
+layout_mode = 2
+text = "Explode Eardrums on Startup?"
+
+[node name="Other" type="Control" parent="Margin/Tab"]
+visible = false
+layout_mode = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Margin/Tab/Other"]
+layout_mode = 0
+offset_right = 40.0
+offset_bottom = 40.0
+
+[node name="Label" type="Label" parent="Margin/Tab/Other/HBoxContainer"]
+layout_mode = 2
+text = "Spinbox Example :)"
+
+[node name="SpinBox" type="SpinBox" parent="Margin/Tab/Other/HBoxContainer"]
+layout_mode = 2
+
+[node name="LocaleVBox" type="VBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+alignment = 2
+
+[node name="LocaleHBox" type="HBoxContainer" parent="LocaleVBox"]
+layout_mode = 2
+mouse_filter = 2
+alignment = 2
+
+[node name="LocaleButton" parent="LocaleVBox/LocaleHBox" instance=ExtResource("2_d7wvq")]
+layout_mode = 2
+
+[connection signal="load_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ResolutionSelector" method="load_setting"]
+[connection signal="load_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ScreenModeSelector" method="load_setting"]
+[connection signal="load_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/MonitorDisplaySelector" method="load_setting"]
+[connection signal="load_settings" from="." to="Margin/Tab/Sound/VBoxContainer/VolumeGrid" method="_on_options_menu_load_settings"]
+[connection signal="reset_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ResolutionSelector" method="reset_setting"]
+[connection signal="reset_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ScreenModeSelector" method="reset_setting"]
+[connection signal="reset_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/MonitorDisplaySelector" method="reset_setting"]
+[connection signal="reset_settings" from="." to="Margin/Tab/Sound/VBoxContainer/VolumeGrid" method="_on_options_menu_reset_settings"]
+[connection signal="save_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ResolutionSelector" method="save_setting"]
+[connection signal="save_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/ScreenModeSelector" method="save_setting"]
+[connection signal="save_settings" from="." to="Margin/Tab/Video/VBoxContainer/GridContainer/MonitorDisplaySelector" method="save_setting"]
+[connection signal="save_settings" from="." to="Margin/Tab/Sound/VBoxContainer/VolumeGrid" method="_on_options_menu_save_settings"]
+[connection signal="item_selected" from="Margin/Tab/Video/VBoxContainer/GridContainer/ResolutionSelector" to="Margin/Tab/Video/VBoxContainer/GridContainer/ResolutionSelector" method="_on_item_selected"]
+[connection signal="item_selected" from="Margin/Tab/Video/VBoxContainer/GridContainer/ScreenModeSelector" to="Margin/Tab/Video/VBoxContainer/GridContainer/ScreenModeSelector" method="_on_item_selected"]
+[connection signal="item_selected" from="Margin/Tab/Video/VBoxContainer/GridContainer/MonitorDisplaySelector" to="Margin/Tab/Video/VBoxContainer/GridContainer/MonitorDisplaySelector" method="_on_item_selected"]
+[connection signal="toggled" from="Margin/Tab/Sound/VBoxContainer/ButtonGrid/EarExploder" to="." method="_on_ear_exploder_toggled"]
+[connection signal="value_changed" from="Margin/Tab/Other/HBoxContainer/SpinBox" to="." method="_on_spin_box_value_changed"]
diff --git a/game/src/OptionMenu/ResolutionSelector.gd b/game/src/OptionMenu/ResolutionSelector.gd
new file mode 100644
index 0000000..ef1a0ff
--- /dev/null
+++ b/game/src/OptionMenu/ResolutionSelector.gd
@@ -0,0 +1,24 @@
+extends SettingOptionButton
+
+func _ready():
+ print("Resolution selector ready")
+
+ clear()
+ var resolution_index := 0
+ for resolution in Resolution.get_resolution_name_list():
+ add_item(resolution)
+
+ if Vector2(Resolution.get_resolution(resolution)) == Resolution.get_current_resolution():
+ if default_value == -1:
+ default_value = resolution_index
+ _select_int(resolution_index)
+ print(resolution)
+
+ resolution_index += 1
+
+
+func _on_item_selected(index):
+ print("Selected index: %d" % index)
+
+ var resolution_size : Vector2i = Resolution.get_resolution(get_item_text(index))
+ Resolution.set_resolution(resolution_size)
diff --git a/game/src/OptionMenu/ScreenModeSelector.gd b/game/src/OptionMenu/ScreenModeSelector.gd
new file mode 100644
index 0000000..fae0771
--- /dev/null
+++ b/game/src/OptionMenu/ScreenModeSelector.gd
@@ -0,0 +1,33 @@
+extends SettingOptionButton
+
+enum ScreenMode { Unknown = -1, Fullscreen, Borderless, Windowed }
+
+func get_screen_mode_from_window_mode(window_mode : int) -> ScreenMode:
+ match window_mode:
+ Window.MODE_EXCLUSIVE_FULLSCREEN:
+ return ScreenMode.Fullscreen
+ Window.MODE_FULLSCREEN:
+ return ScreenMode.Borderless
+ Window.MODE_WINDOWED:
+ return ScreenMode.Windowed
+ _:
+ return ScreenMode.Unknown
+
+func get_window_mode_from_screen_mode(screen_mode : int) -> Window.Mode:
+ match screen_mode:
+ ScreenMode.Fullscreen:
+ return Window.MODE_EXCLUSIVE_FULLSCREEN
+ ScreenMode.Borderless:
+ return Window.MODE_FULLSCREEN
+ ScreenMode.Windowed:
+ return Window.MODE_WINDOWED
+ _:
+ return Window.MODE_EXCLUSIVE_FULLSCREEN
+
+func _on_item_selected(index : int):
+ print("Selected index: %d" % index)
+
+ var window := get_viewport().get_window()
+ var current_resolution := Resolution.get_current_resolution()
+ window.mode = get_window_mode_from_screen_mode(index)
+ Resolution.set_resolution(current_resolution)
diff --git a/game/src/OptionMenu/SettingNodes/SettingHSlider.gd b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
new file mode 100644
index 0000000..da9348f
--- /dev/null
+++ b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
@@ -0,0 +1,20 @@
+extends HSlider
+class_name SettingHSlider
+
+@export
+var section_name : String = "Setting"
+
+@export
+var setting_name : String = "SettingHSlider"
+
+@export
+var default_value : float = 0
+
+func load_setting(file : ConfigFile):
+ value = file.get_value(section_name, setting_name, default_value)
+
+func save_setting(file : ConfigFile):
+ file.set_value(section_name, setting_name, value)
+
+func reset_setting():
+ value = default_value
diff --git a/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
new file mode 100644
index 0000000..46fc825
--- /dev/null
+++ b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
@@ -0,0 +1,22 @@
+extends OptionButton
+class_name SettingOptionButton
+
+@export
+var section_name : String = "Setting"
+
+@export
+var setting_name : String = "SettingOptionMenu"
+
+@export
+var default_value : int = 0
+
+func load_setting(file : ConfigFile):
+ selected = file.get_value(section_name, setting_name, default_value)
+ item_selected.emit(selected)
+
+func save_setting(file : ConfigFile):
+ file.set_value(section_name, setting_name, selected)
+
+func reset_setting():
+ selected = default_value
+ item_selected.emit(selected)
diff --git a/game/src/OptionMenu/VolumeGrid.gd b/game/src/OptionMenu/VolumeGrid.gd
new file mode 100644
index 0000000..fae5ff6
--- /dev/null
+++ b/game/src/OptionMenu/VolumeGrid.gd
@@ -0,0 +1,54 @@
+extends GridContainer
+
+const RATIO_FOR_LINEAR = 100
+
+var _slider_dictionary := {}
+
+func get_db_as_volume_value(db : float) -> float:
+ # db_to_linear produces a float between 0 and 1 from a db value
+ return db_to_linear(db) * RATIO_FOR_LINEAR
+
+func get_volume_value_as_db(value : float) -> float:
+ # linear_to_db consumes a float between 0 and 1 to produce the db value
+ return linear_to_db(value / RATIO_FOR_LINEAR)
+
+func add_volume_column(bus_name : StringName, bus_index : int) -> HSlider:
+ var volume_label := Label.new()
+ volume_label.text = bus_name + " Volume"
+ add_child(volume_label)
+
+ var volume_slider := SettingHSlider.new()
+ volume_slider.section_name = "Audio"
+ volume_slider.setting_name = volume_label.text
+ volume_slider.custom_minimum_size = Vector2(290, 0)
+ volume_slider.size_flags_vertical = Control.SIZE_FILL
+ volume_slider.min_value = 0
+ volume_slider.default_value = 100
+ volume_slider.max_value = 120 # 120 so volume can be boosted somewhat
+ volume_slider.value_changed.connect(_on_slider_value_changed.bind(bus_index))
+ add_child(volume_slider)
+
+ _slider_dictionary[volume_label.text] = volume_slider
+ return volume_slider
+
+func _ready():
+ for bus_index in AudioServer.bus_count:
+ add_volume_column(AudioServer.get_bus_name(bus_index), bus_index)
+
+func _on_slider_value_changed(value : float, bus_index : int) -> void:
+ AudioServer.set_bus_volume_db(bus_index, get_volume_value_as_db(value))
+
+
+func _on_options_menu_load_settings(load_file : ConfigFile):
+ for volume_label_text in _slider_dictionary:
+ _slider_dictionary[volume_label_text].load_setting(load_file)
+
+
+func _on_options_menu_save_settings(save_file : ConfigFile):
+ for volume_label_text in _slider_dictionary:
+ _slider_dictionary[volume_label_text].save_setting(save_file)
+
+
+func _on_options_menu_reset_settings():
+ for volume_label_text in _slider_dictionary:
+ _slider_dictionary[volume_label_text].reset_setting()
diff --git a/game/src/OptionMenu/VolumeGrid.tscn b/game/src/OptionMenu/VolumeGrid.tscn
new file mode 100644
index 0000000..6d4de3c
--- /dev/null
+++ b/game/src/OptionMenu/VolumeGrid.tscn
@@ -0,0 +1,8 @@
+[gd_scene load_steps=2 format=3 uid="uid://dy4si8comamnv"]
+
+[ext_resource type="Script" path="res://src/OptionMenu/VolumeGrid.gd" id="1_wb64h"]
+
+[node name="VolumeGrid" type="GridContainer"]
+size_flags_vertical = 0
+columns = 2
+script = ExtResource("1_wb64h")