Added menu settings add-on
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
extends Button
|
||||
class_name ButtonElement
|
||||
|
||||
## Reference to the element's panel scene.
|
||||
@export var ElementPanelScene: PackedScene
|
||||
|
||||
## Reference to the node the settings element is under.
|
||||
@onready var ParentRef: Node = owner
|
||||
|
||||
## Reference to the element's panel.
|
||||
var ElementPanelRef: Node
|
||||
|
||||
|
||||
func _ready():
|
||||
# Connect necessary signals
|
||||
connect("pressed", pressed)
|
||||
create_element_panel()
|
||||
|
||||
|
||||
func pressed() -> void:
|
||||
# Switch panels
|
||||
ParentRef.SettingsMenuRef.SettingsPanelRef.hide()
|
||||
ElementPanelRef.show()
|
||||
# Populate the settings cache of the panel
|
||||
ElementPanelRef.get_settings()
|
||||
|
||||
|
||||
## Called to create the element's panel.
|
||||
func create_element_panel() -> void:
|
||||
var ElementPanelsRef: Control = ParentRef.SettingsMenuRef.ElementPanelsRef
|
||||
ElementPanelRef = ElementPanelScene.instantiate()
|
||||
|
||||
# Check if the element panel exists
|
||||
if not ElementPanelsRef.find_child(ElementPanelRef.name):
|
||||
# Give a reference of the element
|
||||
ElementPanelRef.PanelOwnerRef = self
|
||||
ElementPanelRef.hide()
|
||||
# Add the panel to the element panels list
|
||||
ElementPanelsRef.add_child(ElementPanelRef)
|
||||
ElementPanelRef.set_owner(ParentRef.SettingsMenuRef)
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3nlqtnyyndrg
|
||||
@@ -0,0 +1,67 @@
|
||||
extends Control
|
||||
class_name MultiElement
|
||||
## A wrapper node for multi elements.
|
||||
|
||||
@export var MainElementRef: SettingsElement
|
||||
@export var SUB_ELEMENTS_: Array[SettingsElement]
|
||||
|
||||
var ParentRef: SettingsSection
|
||||
|
||||
var currentValue :
|
||||
get:
|
||||
return MainElementRef.currentValue
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
ParentRef = owner
|
||||
ParentRef.connect("setting_changed", update_element)
|
||||
ParentRef.connect("apply_button_pressed", apply_settings)
|
||||
ParentRef.SettingsMenuRef.connect("changes_discarded", load_settings)
|
||||
SettingsDataManager.connect("settings_retrieved", load_settings)
|
||||
init_main_element()
|
||||
init_sub_elements()
|
||||
|
||||
|
||||
func init_main_element() -> void:
|
||||
var elementId: String = MainElementRef.IDENTIFIER
|
||||
MainElementRef.IS_MULTI_ELEMENT = true
|
||||
MainElementRef.ParentRef = ParentRef
|
||||
ParentRef.ELEMENT_REFERENCE_TABLE_[elementId] = MainElementRef
|
||||
|
||||
|
||||
## Used to initialize sub elements of the multi element.
|
||||
func init_sub_elements() -> void:
|
||||
for ElementRef in SUB_ELEMENTS_:
|
||||
ElementRef.IS_MULTI_ELEMENT = true
|
||||
ElementRef.IS_SUB_ELEMENT = true
|
||||
ElementRef.ParentRef = ParentRef
|
||||
ParentRef.ELEMENT_REFERENCE_TABLE_[ElementRef.IDENTIFIER] = ElementRef
|
||||
|
||||
|
||||
## Called when settings are loaded to display the appropriate elements.
|
||||
func load_settings() -> void:
|
||||
call_deferred("_display_sub_elements")
|
||||
|
||||
|
||||
## Called when the main element's value changes do display the appropriate elements.
|
||||
func update_element(elementId: String) -> void:
|
||||
if elementId == MainElementRef.IDENTIFIER:
|
||||
call_deferred("_display_sub_elements")
|
||||
|
||||
|
||||
## Called to update the visibility of sub elements based on the main elements's current value.
|
||||
## This function is overwritten by the multi element wrapper.
|
||||
func _display_sub_elements() -> void:
|
||||
return
|
||||
|
||||
|
||||
## Called when the apply button is pressed.
|
||||
func apply_settings() -> void:
|
||||
if ParentRef.changedElements_.has(MainElementRef.IDENTIFIER):
|
||||
for SubElementRef in SUB_ELEMENTS_:
|
||||
if (
|
||||
not SubElementRef.is_visible_in_tree()
|
||||
or ParentRef.changedElements_.has(SubElementRef.IDENTIFIER)
|
||||
):
|
||||
continue
|
||||
SubElementRef._apply_settings()
|
||||
@@ -0,0 +1 @@
|
||||
uid://c74spwofs62nw
|
||||
@@ -0,0 +1,72 @@
|
||||
extends SettingsElement
|
||||
class_name OptionElement
|
||||
## A settings element specifically for elements that have option buttons.
|
||||
|
||||
## Default value for the element.
|
||||
## Value has to exist in OPTION_LIST_ otherwise the first option will be used.
|
||||
@export var DEFAULT_VALUE: String
|
||||
|
||||
## Element node references
|
||||
@export var OptionsRef: OptionButton
|
||||
|
||||
## List of options related to the settings element
|
||||
var OPTION_LIST_
|
||||
|
||||
## Index of the currently selected item
|
||||
var selectedIndex: int
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
OPTION_LIST_.make_read_only()
|
||||
OptionsRef.connect("item_selected", option_selected)
|
||||
|
||||
|
||||
func init_element() -> void:
|
||||
fill_options_button()
|
||||
|
||||
|
||||
func get_valid_values() -> Dictionary:
|
||||
if not OPTION_LIST_.has(DEFAULT_VALUE):
|
||||
push_warning("Invalid default value for element '" + IDENTIFIER + "'.")
|
||||
if OPTION_LIST_ is Dictionary:
|
||||
DEFAULT_VALUE = OPTION_LIST_.keys()[0]
|
||||
else:
|
||||
DEFAULT_VALUE = OPTION_LIST_[0]
|
||||
|
||||
return {
|
||||
"defaultValue": DEFAULT_VALUE,
|
||||
"validOptions": OPTION_LIST_
|
||||
}
|
||||
|
||||
|
||||
## Used to initialize the option button element.
|
||||
func fill_options_button() -> void:
|
||||
var index: int = 0
|
||||
# Get the current item count of the option button
|
||||
var itemCount: int = OptionsRef.get_item_count()
|
||||
|
||||
# Add the options from the received option list of the element
|
||||
for option in OPTION_LIST_:
|
||||
# Check if the option button has not been initialized yet
|
||||
if itemCount == 0:
|
||||
OptionsRef.add_item(option, index)
|
||||
# Select the option that was loaded
|
||||
if option == currentValue:
|
||||
OptionsRef.select(index)
|
||||
selectedIndex = index
|
||||
|
||||
index += 1
|
||||
|
||||
|
||||
func option_selected(index: int) -> void:
|
||||
# Check if the settings menu is open
|
||||
if ParentRef.settingsCache_.size() > 0:
|
||||
# Update the settings cache with the selected option
|
||||
ParentRef.settingsCache_[IDENTIFIER] = OptionsRef.get_item_text(index)
|
||||
# Check if the selected value is different than the saved value
|
||||
ParentRef.settings_changed(IDENTIFIER)
|
||||
|
||||
# Update the element's values
|
||||
currentValue = OptionsRef.get_item_text(index)
|
||||
selectedIndex = index
|
||||
@@ -0,0 +1 @@
|
||||
uid://1dxqbc07as1r
|
||||
@@ -0,0 +1,205 @@
|
||||
extends Control
|
||||
class_name SettingsElement
|
||||
## The base script for settings elements.
|
||||
|
||||
## Identifier for the element.
|
||||
## This value is used as the key in the settings data.
|
||||
@export var IDENTIFIER: String = "Element"
|
||||
|
||||
## Toggle based on whether the element handles a setting that requires an in game node to exist.
|
||||
@export var IS_IN_GAME_SETTING: bool
|
||||
|
||||
## The name of the section the element is under.
|
||||
@onready var SECTION: String = ParentRef.IDENTIFIER
|
||||
|
||||
## Reference to the section the settings element is under.
|
||||
var ParentRef: SettingsSection
|
||||
|
||||
# Multi element flags
|
||||
## Flag to turn an element into the main element of a multi element.
|
||||
var IS_MULTI_ELEMENT: bool = false
|
||||
## Flag to turn an element into a sub element of a multi element.
|
||||
var IS_SUB_ELEMENT: bool = false
|
||||
|
||||
## Current value of the element.
|
||||
var currentValue
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if not IS_MULTI_ELEMENT:
|
||||
ParentRef = owner
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
SettingsDataManager.connect("settings_retrieved", load_settings)
|
||||
# Check if the element is a sub element
|
||||
if not IS_SUB_ELEMENT:
|
||||
ParentRef.connect("apply_button_pressed", _apply_settings)
|
||||
# Add an entry of the settings element to the section's reference table
|
||||
ParentRef.ELEMENT_REFERENCE_TABLE_[IDENTIFIER] = self
|
||||
|
||||
|
||||
## Used to initialize a settings element.
|
||||
## This function is overwritten by each [b]type[/b] of element.
|
||||
func init_element() -> void:
|
||||
return
|
||||
|
||||
|
||||
## Loads the saved or default value of the element.
|
||||
func load_settings() -> void:
|
||||
# List of valid values for the element
|
||||
var VALUES_: Dictionary = get_valid_values()
|
||||
VALUES_.make_read_only()
|
||||
|
||||
# Check if no save file exists
|
||||
if SettingsDataManager.noSaveFile:
|
||||
# Assign default value as current value
|
||||
currentValue = VALUES_["defaultValue"]
|
||||
# Add default value of element to the settings data
|
||||
SettingsDataManager.settingsData_[SECTION][IDENTIFIER] = currentValue
|
||||
else:
|
||||
# Verify the existance and validity of the element in the settings data
|
||||
if verify_settings_data(VALUES_):
|
||||
# Get the current value from the settings data
|
||||
currentValue = SettingsDataManager.settingsData_[SECTION][IDENTIFIER]
|
||||
else:
|
||||
# Assign default value as current value
|
||||
currentValue = VALUES_["defaultValue"]
|
||||
# Add default value of the element to the settings data
|
||||
SettingsDataManager.settingsData_[SECTION][IDENTIFIER] = currentValue
|
||||
SettingsDataManager.invalidSaveFile = true
|
||||
|
||||
init_element()
|
||||
|
||||
# Check if the current element is in an in game menu or if it is a sub element
|
||||
if (
|
||||
ParentRef.SettingsMenuRef.IS_IN_GAME_MENU == IS_IN_GAME_SETTING
|
||||
or not IS_SUB_ELEMENT
|
||||
):
|
||||
# Apply the loaded values to the game
|
||||
call_deferred("_apply_settings")
|
||||
|
||||
|
||||
## Used to get the valid values an element can have for validating settings data.
|
||||
## This function is overwritten by each [b]type[/b] of element.
|
||||
func get_valid_values() -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
## Checks if the loaded values are valid for the element.
|
||||
## If a value is wrong, it will be fixed automatically.
|
||||
func verify_settings_data(VALUES_: Dictionary) -> bool:
|
||||
# Check if an entry exists for the element
|
||||
if not entry_exists():
|
||||
return false
|
||||
|
||||
# Get the value of the element
|
||||
var RETRIEVED_VALUE = SettingsDataManager.settingsData_[SECTION][IDENTIFIER]
|
||||
|
||||
# Check if the retrieved value is the correct type
|
||||
if not is_valid_type(VALUES_, RETRIEVED_VALUE):
|
||||
return false
|
||||
|
||||
# Check if the retrieved value has the expected value
|
||||
if not is_valid_value(VALUES_, RETRIEVED_VALUE):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Used by verify_settings_data() to check if the element
|
||||
## and the section it is under exists in the settings data.
|
||||
func entry_exists() -> bool:
|
||||
# Check if the section exists in settings data
|
||||
if not SettingsDataManager.settingsData_.has(SECTION):
|
||||
push_warning("Settings section missing: ", SECTION)
|
||||
return false
|
||||
|
||||
# Check if the element exists in the settings data
|
||||
if not SettingsDataManager.settingsData_[SECTION].has(IDENTIFIER):
|
||||
push_warning("Settings element is missing: ", IDENTIFIER)
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Used by verify_settings_data() to check if the retrieved value has the correct type.
|
||||
func is_valid_type(VALUES_: Dictionary, RETRIEVED_VALUE) -> bool:
|
||||
if typeof(RETRIEVED_VALUE) != typeof(VALUES_["defaultValue"]):
|
||||
push_warning(
|
||||
"Invalid value type of '"
|
||||
+ type_string(typeof(RETRIEVED_VALUE))
|
||||
+ "' for element '"
|
||||
+ IDENTIFIER
|
||||
+ "' expected value type of '"
|
||||
+ type_string(typeof(VALUES_["defaultValue"]))
|
||||
+ "'"
|
||||
)
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Used by verify_settings_data() to check if the retrieved value has a valid value.
|
||||
func is_valid_value(VALUES_: Dictionary, RETRIEVED_VALUE) -> bool:
|
||||
# Get the type of the valid value
|
||||
match typeof(VALUES_["defaultValue"]):
|
||||
# If the type is either string or bool
|
||||
TYPE_STRING, TYPE_BOOL:
|
||||
# Check if the retrieved value is valid
|
||||
if not VALUES_["validOptions"].has(RETRIEVED_VALUE):
|
||||
push_warning(
|
||||
"Invalid value '"
|
||||
+ str(RETRIEVED_VALUE)
|
||||
+ "' for element '"
|
||||
+ IDENTIFIER
|
||||
+ "' expected values: "
|
||||
+ str(VALUES_["validOptions"])
|
||||
)
|
||||
return false
|
||||
# If the type is either int or float
|
||||
TYPE_INT, TYPE_FLOAT:
|
||||
# Check if the retrieved value is valid
|
||||
if (
|
||||
RETRIEVED_VALUE < VALUES_["minValue"]
|
||||
or RETRIEVED_VALUE > VALUES_["maxValue"]
|
||||
):
|
||||
# Special check if max fps is set to 0 (unlimited)
|
||||
if IDENTIFIER == "MaxFPS" and RETRIEVED_VALUE == 0:
|
||||
return true
|
||||
|
||||
push_warning(
|
||||
"Invalid value "
|
||||
+ str(RETRIEVED_VALUE)
|
||||
+ " for element '"
|
||||
+ IDENTIFIER
|
||||
+ "' expected values between "
|
||||
+ str(VALUES_["minValue"])
|
||||
+ " and "
|
||||
+ str(VALUES_["maxValue"])
|
||||
)
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Used to apply in game settings that require a node to exist to be applied,
|
||||
## i.e., world environment related settings and or most gameplay settings.
|
||||
func apply_in_game_setting(value = null) -> bool:
|
||||
if ParentRef.SettingsMenuRef.IS_IN_GAME_MENU:
|
||||
SettingsDataManager.call_deferred(
|
||||
"emit_signal",
|
||||
"applied_in_game_setting",
|
||||
SECTION,
|
||||
IDENTIFIER,
|
||||
value
|
||||
)
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
## Called to apply the setting to the game.
|
||||
## This function is overwritten by each [b]element[/b].
|
||||
func _apply_settings() -> void:
|
||||
return
|
||||
@@ -0,0 +1 @@
|
||||
uid://fv4elvbeqrqg
|
||||
@@ -0,0 +1,96 @@
|
||||
extends SettingsElement
|
||||
class_name SliderElement
|
||||
## A settings element specifically for elements that have a slider.
|
||||
|
||||
# Default values for the element
|
||||
@export var MIN_VALUE: float = 0
|
||||
@export var MAX_VALUE: float = 1
|
||||
@export var STEP_VALUE: float = 0.1
|
||||
@export var DEFAULT_VALUE: float = 1
|
||||
|
||||
## If true, displays 0 to 100 instead of 0 to 1 in the settings,
|
||||
## but the true value remains the same.
|
||||
@export var DISPLAY_PERCENT_VALUE: bool = false
|
||||
|
||||
## An extra suffix for the value (optional).
|
||||
@export var VALUE_SUFFIX: String = ""
|
||||
|
||||
## Reference to the slider of the element.
|
||||
@export var SliderRef: HSlider
|
||||
## Reference to the SpinBox or Label of the element.
|
||||
@export var ValueBoxRef: Control
|
||||
|
||||
|
||||
## Overwrite for SettingsElement.
|
||||
func init_element() -> void:
|
||||
init_slider(100 if DISPLAY_PERCENT_VALUE else 1)
|
||||
|
||||
|
||||
## Called to initialize the slider element.
|
||||
func init_slider(FACTOR: float) -> void:
|
||||
# Apply the min/max/step/current value of the SliderRef
|
||||
SliderRef.set_min(MIN_VALUE * FACTOR)
|
||||
SliderRef.set_max(MAX_VALUE * FACTOR)
|
||||
SliderRef.set_step(STEP_VALUE * FACTOR)
|
||||
SliderRef.set_value(currentValue * FACTOR)
|
||||
|
||||
# Connect the value changed signal for the SliderRef
|
||||
if not SliderRef.is_connected("value_changed", slider_value_changed):
|
||||
SliderRef.connect("value_changed", slider_value_changed.bind(FACTOR))
|
||||
|
||||
# Check if the value box is a spin box or a label
|
||||
if ValueBoxRef is SpinBox:
|
||||
# Apply the min/max/step/current value of the spin box
|
||||
ValueBoxRef.set_min(MIN_VALUE * FACTOR)
|
||||
ValueBoxRef.set_max(MAX_VALUE * FACTOR)
|
||||
ValueBoxRef.set_step(STEP_VALUE * FACTOR)
|
||||
ValueBoxRef.set_value(currentValue * FACTOR)
|
||||
|
||||
# Add caret blink to spin box
|
||||
ValueBoxRef.get_line_edit().set_caret_blink_enabled(true)
|
||||
|
||||
ValueBoxRef.set_suffix(VALUE_SUFFIX)
|
||||
|
||||
# Connect the value changed signal of the spin box
|
||||
if not ValueBoxRef.is_connected("value_changed", value_box_value_changed):
|
||||
ValueBoxRef.connect("value_changed", value_box_value_changed)
|
||||
else:
|
||||
# Set the text as the current value
|
||||
ValueBoxRef.set_text(str(currentValue) + VALUE_SUFFIX)
|
||||
|
||||
|
||||
## Gets the valid values from the element to be used for validating data.
|
||||
func get_valid_values() -> Dictionary:
|
||||
# Check if value is out of bounds
|
||||
if DEFAULT_VALUE > MAX_VALUE or DEFAULT_VALUE < MIN_VALUE:
|
||||
push_warning("Invalid default value for element '" + IDENTIFIER + "'.")
|
||||
DEFAULT_VALUE = clampf(DEFAULT_VALUE, MIN_VALUE, MAX_VALUE)
|
||||
|
||||
return {
|
||||
"defaultValue": DEFAULT_VALUE,
|
||||
"minValue": MIN_VALUE,
|
||||
"maxValue": MAX_VALUE,
|
||||
}
|
||||
|
||||
|
||||
## Used to update values of the section cache the element is under.
|
||||
func value_changed(value: float) -> void:
|
||||
# Check if the settings menu is open
|
||||
if ParentRef.settingsCache_.size() > 0:
|
||||
ParentRef.settingsCache_[IDENTIFIER] = value
|
||||
# Check if the new value is different than the saved value
|
||||
ParentRef.settings_changed(IDENTIFIER)
|
||||
currentValue = value
|
||||
|
||||
|
||||
func slider_value_changed(value: float, FACTOR: float) -> void:
|
||||
if ValueBoxRef is SpinBox:
|
||||
ValueBoxRef.set_value(value)
|
||||
else:
|
||||
ValueBoxRef.set_text(str(value) + VALUE_SUFFIX)
|
||||
|
||||
value_changed(value / FACTOR)
|
||||
|
||||
|
||||
func value_box_value_changed(value: float) -> void:
|
||||
SliderRef.set_value(value)
|
||||
@@ -0,0 +1 @@
|
||||
uid://084wuqxrcn2t
|
||||
@@ -0,0 +1,38 @@
|
||||
extends SettingsElement
|
||||
class_name ToggleElement
|
||||
## A settings element specifically for elements that have a toggle button.
|
||||
|
||||
## Default value for the element
|
||||
@export var DEFAULT_VALUE: bool = false
|
||||
|
||||
## Reference to the toggle button of the element.
|
||||
@export var ToggleRef: Button
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
ToggleRef.connect("toggled", toggled)
|
||||
|
||||
|
||||
## Overwrite for SettingsElement.
|
||||
func init_element() -> void:
|
||||
ToggleRef.set_pressed(currentValue)
|
||||
|
||||
|
||||
## Gets the valid values from the element to be used for validating data.
|
||||
func get_valid_values() -> Dictionary:
|
||||
return {
|
||||
"defaultValue": DEFAULT_VALUE,
|
||||
"validOptions": [true, false]
|
||||
}
|
||||
|
||||
|
||||
## Used to update values of the section cache the element is under.
|
||||
func toggled(state: bool) -> void:
|
||||
# Check if the settings menu is open
|
||||
if ParentRef.settingsCache_.size() > 0:
|
||||
# Update the settings cache with the new toggle state
|
||||
ParentRef.settingsCache_[IDENTIFIER] = state
|
||||
# Check if the new state is different than the saved state
|
||||
ParentRef.settings_changed(IDENTIFIER)
|
||||
currentValue = state
|
||||
@@ -0,0 +1 @@
|
||||
uid://djvaswjdtm251
|
||||
@@ -0,0 +1,54 @@
|
||||
extends SettingsSection
|
||||
|
||||
# Panel node references
|
||||
@onready var BackButtonRef: Button = $VBoxContainer/HBoxContainer/BackButton
|
||||
@onready var ApplyButtonRef: Button = $VBoxContainer/HBoxContainer/ApplyButton
|
||||
|
||||
# Reference to the element this panel belongs to
|
||||
var PanelOwnerRef: ButtonElement
|
||||
|
||||
|
||||
func _ready():
|
||||
# Connect neccessary signals
|
||||
BackButtonRef.connect("pressed", on_back_pressed)
|
||||
ApplyButtonRef.connect("pressed", on_apply_settings)
|
||||
|
||||
# Add a reference of the section to the reference table
|
||||
SettingsDataManager.ELEMENT_PANEL_REFERENCE_TABLE_[IDENTIFIER] = self
|
||||
|
||||
# Check if a save file exists
|
||||
if SettingsDataManager.noSaveFile:
|
||||
# Add the section to the settings data dictionary
|
||||
SettingsDataManager.settingsData_[IDENTIFIER] = {}
|
||||
|
||||
SettingsMenuRef = owner
|
||||
# Load the settings of the elements inside of the panel
|
||||
call_deferred("init_elements")
|
||||
|
||||
|
||||
# Called to load the settings of the elements inside of the panel
|
||||
func init_elements() -> void:
|
||||
for element in ELEMENT_REFERENCE_TABLE_:
|
||||
ELEMENT_REFERENCE_TABLE_[element].load_settings()
|
||||
|
||||
|
||||
func settings_changed(elementId: String) -> void:
|
||||
ApplyButtonRef.set_disabled(check_for_changes(elementId))
|
||||
|
||||
|
||||
func on_back_pressed():
|
||||
# Check if there have been any changes made
|
||||
if ApplyButtonRef.is_disabled():
|
||||
# Clear the cache and return normally
|
||||
settingsCache_.clear()
|
||||
hide()
|
||||
SettingsMenuRef.SettingsPanelRef.show()
|
||||
else:
|
||||
SettingsMenuRef.display_discard_changes(self)
|
||||
|
||||
|
||||
func on_apply_settings():
|
||||
super.on_apply_settings()
|
||||
# Save the updated settings data
|
||||
SettingsDataManager.call_deferred("save_data")
|
||||
ApplyButtonRef.set_disabled(true)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cyig515shrgnb
|
||||
@@ -0,0 +1,13 @@
|
||||
extends SliderElement
|
||||
|
||||
## Name of the audio bus that the volume slider is assigned to.
|
||||
@export var AUDIO_BUS: String
|
||||
|
||||
|
||||
# Element specific script for applying its value to the game
|
||||
func _apply_settings() -> void:
|
||||
# Get the index of the audio bus
|
||||
var busIndex: int = AudioServer.get_bus_index(AUDIO_BUS)
|
||||
|
||||
# Set the volume of the audio bus
|
||||
AudioServer.set_bus_volume_db(busIndex, linear_to_db(currentValue))
|
||||
@@ -0,0 +1 @@
|
||||
uid://b16tk8008cqdj
|
||||
@@ -0,0 +1,20 @@
|
||||
extends Node
|
||||
|
||||
@export var CameraRef: Camera3D
|
||||
|
||||
|
||||
func _ready():
|
||||
# Connect neccessary signal
|
||||
SettingsDataManager.connect("applied_in_game_setting", apply_in_game_settings)
|
||||
|
||||
|
||||
# Called to apply in game settings for the specific node
|
||||
func apply_in_game_settings(section: String, element: String, value) -> void:
|
||||
match element:
|
||||
"FOV":
|
||||
CameraRef.set_fov(value)
|
||||
"DepthOfField":
|
||||
var enabled: bool = false if value == "Disabled" else true
|
||||
# Disable/Enable DOF
|
||||
CameraRef.attributes.set_dof_blur_far_enabled(enabled)
|
||||
CameraRef.attributes.set_dof_blur_near_enabled(enabled)
|
||||
@@ -0,0 +1 @@
|
||||
uid://b52warfwk40xd
|
||||
@@ -0,0 +1,42 @@
|
||||
extends Node
|
||||
|
||||
@export var WorldEnvRef: WorldEnvironment
|
||||
|
||||
@onready var EnvironmentRef: Environment = WorldEnvRef.environment
|
||||
|
||||
|
||||
func _ready():
|
||||
SettingsDataManager.connect("applied_in_game_setting", apply_in_game_settings)
|
||||
|
||||
|
||||
# Called by elements to apply in game settings
|
||||
func apply_in_game_settings(section: String, element: String, value) -> void:
|
||||
match element:
|
||||
"SSRQuality":
|
||||
if SettingsDataManager.settingsData_[section][element] == "Disabled":
|
||||
EnvironmentRef.set_ssr_enabled(false)
|
||||
return
|
||||
EnvironmentRef.set_ssr_enabled(true)
|
||||
EnvironmentRef.set_ssr_max_steps(value["maxSteps"])
|
||||
EnvironmentRef.set_ssr_fade_in(value["fadeIn"])
|
||||
EnvironmentRef.set_ssr_fade_out(value["fadeOut"])
|
||||
|
||||
"SSAOQuality":
|
||||
EnvironmentRef.set_ssao_enabled(
|
||||
false if value == "Disabled" else true
|
||||
)
|
||||
|
||||
"SSILQuality":
|
||||
EnvironmentRef.set_ssil_enabled(
|
||||
false if value == "Disabled" else true
|
||||
)
|
||||
|
||||
"SDFGIQuality":
|
||||
EnvironmentRef.set_sdfgi_enabled(
|
||||
false if value == "Disabled" else true
|
||||
)
|
||||
|
||||
"GlowQuality":
|
||||
EnvironmentRef.set_glow_enabled(
|
||||
false if value == "Disabled" else true
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dtgajfyolcqno
|
||||
@@ -0,0 +1,83 @@
|
||||
extends Control
|
||||
class_name SettingsMenu
|
||||
|
||||
## Emitted when the settings menu is made visible.
|
||||
signal settings_menu_opened
|
||||
## Emitted when the apply button is pressed.
|
||||
signal apply_button_pressed
|
||||
## Emitted when the settings menu is hidden.
|
||||
signal settings_menu_closed
|
||||
## Emitted when changes are discarded.
|
||||
signal changes_discarded
|
||||
|
||||
## Used to check if gameplay related settings should be applied
|
||||
@export var IS_IN_GAME_MENU: bool = true
|
||||
## Reference to the parent node of the menu UI.
|
||||
## The node this references will get set visible when pressing the back button.
|
||||
@export var MenuPanelRef: Node
|
||||
## List of settings sections that should be left out of the settings menu instance.
|
||||
@export var IGNORED_SECTIONS_: Array[String]
|
||||
|
||||
|
||||
@onready var DiscardChangesRef: PanelContainer = $DiscardChangesPopup
|
||||
@onready var SettingsPanelRef: VBoxContainer = $SettingsPanel
|
||||
@onready var ApplyButtonRef: Button = %ApplyButton
|
||||
|
||||
var ElementPanelsRef: Control
|
||||
var SettingsTabsRef: TabContainer
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
ElementPanelsRef = $ElementPanels
|
||||
SettingsTabsRef = $SettingsPanel/SettingsTabs
|
||||
ignore_sections()
|
||||
|
||||
|
||||
func _ready():
|
||||
# Load the settings menu
|
||||
SettingsDataManager.call_deferred("emit_signal", "settings_retrieved")
|
||||
|
||||
|
||||
func on_back_button_pressed() -> void:
|
||||
# Check if there have been any changes made
|
||||
if ApplyButtonRef.is_disabled():
|
||||
hide()
|
||||
MenuPanelRef.show()
|
||||
# Clear the settings cache
|
||||
emit_signal("settings_menu_closed")
|
||||
else:
|
||||
# Display the discard changes popup
|
||||
display_discard_changes(self)
|
||||
|
||||
|
||||
func on_apply_button_pressed() -> void:
|
||||
ApplyButtonRef.set_disabled(true)
|
||||
# Apply the settings of each section
|
||||
emit_signal("apply_button_pressed")
|
||||
# Save the updated settings data
|
||||
SettingsDataManager.call_deferred("save_data")
|
||||
# Reset the changed elements count
|
||||
SettingsDataManager.changedElementsCount = 0
|
||||
|
||||
|
||||
func on_visibility_changed() -> void:
|
||||
if is_visible_in_tree():
|
||||
emit_signal("settings_menu_opened")
|
||||
|
||||
|
||||
# Called to discard the changes in the settings menu
|
||||
func discard_changes() -> void:
|
||||
emit_signal("changes_discarded")
|
||||
for SectionRef in SettingsTabsRef.get_children():
|
||||
SectionRef.discard_changes()
|
||||
|
||||
|
||||
func display_discard_changes(CallerRef: Control) -> void:
|
||||
DiscardChangesRef.show()
|
||||
DiscardChangesRef.CallerRef = CallerRef
|
||||
|
||||
|
||||
func ignore_sections() -> void:
|
||||
for SectionRef in SettingsTabsRef.get_children():
|
||||
if IGNORED_SECTIONS_.has(SectionRef.IDENTIFIER):
|
||||
SectionRef.queue_free()
|
||||
@@ -0,0 +1 @@
|
||||
uid://houdhjao14e7
|
||||
@@ -0,0 +1,123 @@
|
||||
extends Control
|
||||
class_name SettingsSection
|
||||
## The base script for settings sections.
|
||||
|
||||
## Emitted when the apply button is pressed.
|
||||
signal apply_button_pressed
|
||||
## Emitted when a setting has it's value changed.
|
||||
signal setting_changed(elementId: String)
|
||||
|
||||
## Identifier for the section.
|
||||
## This value is used as the key in the settings data.
|
||||
@export var IDENTIFIER: String
|
||||
|
||||
## Reference to the settings menu node.
|
||||
var SettingsMenuRef: SettingsMenu
|
||||
|
||||
## Reference table of all elements under the section.
|
||||
var ELEMENT_REFERENCE_TABLE_: Dictionary
|
||||
## Cache of all the settings values for the section.
|
||||
var settingsCache_: Dictionary
|
||||
## A list of all the elements that were changed since the settings were last applied.
|
||||
var changedElements_: Array[String]
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
SettingsMenuRef = owner
|
||||
|
||||
|
||||
func _ready():
|
||||
# Connect neccessary signals from the central root node for the settings
|
||||
SettingsMenuRef.connect("settings_menu_opened", get_settings)
|
||||
SettingsMenuRef.connect("apply_button_pressed", on_apply_settings)
|
||||
SettingsMenuRef.connect("settings_menu_closed", clear_cache)
|
||||
|
||||
# Add a reference of the section to the reference table
|
||||
SettingsDataManager.SECTION_REFERENCE_TABLE_[IDENTIFIER] = self
|
||||
|
||||
# Check if a save file exists
|
||||
if SettingsDataManager.noSaveFile:
|
||||
# Add the section to the settings data dictionary
|
||||
SettingsDataManager.settingsData_[IDENTIFIER] = {}
|
||||
|
||||
|
||||
## Called when opening the settings menu to fill the settings cache.
|
||||
func get_settings() -> void:
|
||||
# Copy the settings data for the section into it's cache
|
||||
settingsCache_ =\
|
||||
SettingsDataManager.settingsData_[IDENTIFIER].duplicate(true)
|
||||
|
||||
# If no save file exists saves the default values retrieved from the section's elements
|
||||
if SettingsDataManager.noSaveFile or SettingsDataManager.invalidSaveFile:
|
||||
SettingsDataManager.call_deferred("save_data")
|
||||
|
||||
# Clear the changed elements array
|
||||
changedElements_.clear()
|
||||
|
||||
|
||||
## Called to clear the section's cache.
|
||||
func clear_cache() -> void:
|
||||
settingsCache_.clear()
|
||||
|
||||
|
||||
## Called when a setting has been changed.
|
||||
func settings_changed(elementId: String) -> void:
|
||||
SettingsMenuRef.ApplyButtonRef.set_disabled(check_for_changes(elementId))
|
||||
emit_signal("setting_changed", elementId)
|
||||
|
||||
|
||||
## Called to check for changes between the cache and the settings data.
|
||||
func check_for_changes(elementId: String) -> bool:
|
||||
var cacheValue = settingsCache_[elementId]
|
||||
var savedValue = SettingsDataManager.settingsData_[IDENTIFIER][elementId]
|
||||
# Check if there are differences between the cache and the settings data
|
||||
if cacheValue == savedValue:
|
||||
# Check if the element is on the changed elements list
|
||||
if changedElements_.has(elementId):
|
||||
# Remove the element from the list
|
||||
changedElements_.erase(elementId)
|
||||
# Decrease the changed elements count
|
||||
SettingsDataManager.changedElementsCount -= 1
|
||||
|
||||
# Check if there are any other changed elements
|
||||
if SettingsDataManager.changedElementsCount == 0:
|
||||
# Disabled the apply button
|
||||
return true
|
||||
|
||||
# Check if the element is not the changed elements list
|
||||
if not changedElements_.has(elementId):
|
||||
# Add the element to the list
|
||||
changedElements_.append(elementId)
|
||||
# Increase the changed elements count
|
||||
SettingsDataManager.changedElementsCount += 1
|
||||
|
||||
# Enable the apply button
|
||||
return false
|
||||
|
||||
|
||||
## Called to saved the data in the section's cache to the settings data
|
||||
## and apply the settings to the game.
|
||||
func on_apply_settings() -> void:
|
||||
# Check if any of the sections elements have been changed
|
||||
if changedElements_.size() > 0:
|
||||
# Copy the section cache into the settings data dictionary
|
||||
SettingsDataManager.settingsData_[IDENTIFIER] = settingsCache_.duplicate(true)
|
||||
|
||||
# Apply the settings for the changed elements
|
||||
for element in changedElements_:
|
||||
ELEMENT_REFERENCE_TABLE_[element]._apply_settings()
|
||||
|
||||
# Clear the changed elements array
|
||||
changedElements_.clear()
|
||||
|
||||
|
||||
## Called to discard changes that have been made since the last save.
|
||||
func discard_changes() -> void:
|
||||
# Check if any of the sections elements have been changed
|
||||
if changedElements_.size() > 0:
|
||||
# Load the saved settings for each element in the section
|
||||
for element in changedElements_:
|
||||
ELEMENT_REFERENCE_TABLE_[element].load_settings()
|
||||
|
||||
# Clear the changed elements array
|
||||
changedElements_.clear()
|
||||
@@ -0,0 +1 @@
|
||||
uid://c3ssroxjs8wt
|
||||
Reference in New Issue
Block a user