RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
standard_settings_popup.gd
Go to the documentation of this file.
1extends RefCounted
2
3
6
7const SettingsPanelController = preload("res://scripts/systems/settingsManager/settings_panel_controller.gd")
8const SettingsManagerScript = preload("res://scripts/systems/settingsManager/settings_manager.gd")
9const LayoutManager = preload("res://scripts/systems/layoutManager/layout_manager.gd")
10
11var controller = SettingsPanelController.new()
12var layout_manager = LayoutManager.new()
13var managed_popups:Array = []
14var settings_manager_fallback
15
16
17
18func create_popup(owner:Node, options:Dictionary = {}) -> PopupPanel:
19 layout_manager.load_theme_file("res://data/themes/default.json")
20 var popup = PopupPanel.new()
21 popup.name = str(options.get("name", "StandardSettingsPopup"))
22 popup.size = Vector2i(int(options.get("width", 380)), int(options.get("height", 520)))
23 var content = VBoxContainer.new()
24 content.name = "Content"
25 content.set_anchors_preset(Control.PRESET_FULL_RECT)
26 content.add_theme_constant_override("separation", int(options.get("separation", 10)))
27 content.offset_left = 16
28 content.offset_top = 16
29 content.offset_right = -16
30 content.offset_bottom = -16
31 content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
32 content.size_flags_vertical = Control.SIZE_EXPAND_FILL
33 popup.add_child(content)
34 var title = Label.new()
35 title.name = "Title"
36 title.text = str(options.get("title", "Settings"))
37 title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
38 content.add_child(title)
39 var scroll = ScrollContainer.new()
40 scroll.name = "Scroll"
41 scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL
42 scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
43 scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
44 content.add_child(scroll)
45 var body = VBoxContainer.new()
46 body.name = "Body"
47 body.size_flags_horizontal = Control.SIZE_EXPAND_FILL
48 body.add_theme_constant_override("separation", int(options.get("control_separation", 8)))
49 scroll.add_child(body)
50 var controls = _build_controls(body)
51 var close = Button.new()
52 close.name = "CloseButton"
53 close.text = str(options.get("close_label", "Back"))
54 close.custom_minimum_size = Vector2(0, 48)
55 close.pressed.connect(popup.hide)
56 content.add_child(close)
57 if owner != null:
58 owner.add_child(popup)
59 controller.bind(controls)
60 if not managed_popups.has(popup):
61 managed_popups.append(popup)
62 var settings_manager = _settings_manager()
63 if not settings_manager.settings_changed.is_connected(_on_settings_changed):
64 settings_manager.settings_changed.connect(_on_settings_changed)
65 _apply_popup_theme(popup)
66 return popup
67
68
69func popup_centered(popup:PopupPanel, viewport_size:Vector2, options:Dictionary = {}) -> void:
70 if popup == null:
71 return
72 var content_margin := int(options.get("content_margin", 16))
73 layout_manager.popup_centered_standard(popup, viewport_size, {
74 "size": Vector2i(int(options.get("max_width", 420)), int(options.get("max_height", 560))),
75 "minimum": Vector2i(int(options.get("min_width", 260)), int(options.get("min_height", 180))),
76 "content_margin": content_margin
77 })
78 controller.sync_values()
79 _apply_popup_theme(popup)
80 _apply_content_margin(popup, content_margin)
81
82
83func _on_settings_changed(_settings:Dictionary) -> void:
84 _prune_managed_popups()
85 for popup in managed_popups:
86 _apply_popup_theme(popup)
87
88
89func _apply_popup_theme(popup:PopupPanel) -> void:
90 if popup == null or not is_instance_valid(popup):
91 return
92 var settings_manager = _settings_manager()
93 layout_manager.apply_theme(popup, str(settings_manager.get_settings().get("theme", "dark")))
94 settings_manager.apply_text_size(popup)
95 _apply_content_margin(popup, 16)
96
97
98func _apply_content_margin(popup:PopupPanel, margin:int) -> void:
99 if popup == null or not is_instance_valid(popup):
100 return
101 var content = popup.get_node_or_null("Content")
102 if content is Control:
103 content.set_anchors_preset(Control.PRESET_FULL_RECT)
104 content.offset_left = margin
105 content.offset_top = margin
106 content.offset_right = -margin
107 content.offset_bottom = -margin
108
109
110func _build_controls(content:VBoxContainer) -> Dictionary:
111 var window_size = _option_row(content, "Window Size")
112 var theme = _option_row(content, "Theme")
113 var text_size = _option_row(content, "Text Size")
114 var fullscreen = CheckBox.new()
115 fullscreen.name = "Fullscreen"
116 fullscreen.text = "Fullscreen"
117 content.add_child(fullscreen)
118 var low_power = CheckBox.new()
119 low_power.name = "LowPowerMode"
120 low_power.text = "Low-power mode"
121 content.add_child(low_power)
122 var master = _volume_row(content, "Master")
123 var music = _volume_row(content, "Music")
124 var sfx = _volume_row(content, "Sound Effects")
125 return {
126 "window_size": window_size,
127 "theme": theme,
128 "text_size": text_size,
129 "fullscreen": fullscreen,
130 "low_power_mode": low_power,
131 "master_slider": master["slider"],
132 "master_mute": master["mute"],
133 "music_slider": music["slider"],
134 "music_mute": music["mute"],
135 "sfx_slider": sfx["slider"],
136 "sfx_mute": sfx["mute"]
137 }
138
139
140func _option_row(content:VBoxContainer, label_text:String) -> OptionButton:
141 var row = HBoxContainer.new()
142 row.name = "%sRow" % label_text.replace(" ", "")
143 row.add_theme_constant_override("separation", 8)
144 var label = Label.new()
145 label.text = label_text
146 label.custom_minimum_size = Vector2(112, 0)
147 row.add_child(label)
148 var option = OptionButton.new()
149 option.name = label_text.replace(" ", "")
150 option.size_flags_horizontal = Control.SIZE_EXPAND_FILL
151 row.add_child(option)
152 content.add_child(row)
153 return option
154
155
156func _volume_row(content:VBoxContainer, label_text:String) -> Dictionary:
157 var row = HBoxContainer.new()
158 row.name = "%sVolume" % label_text.replace(" ", "")
159 row.add_theme_constant_override("separation", 8)
160 var label = Label.new()
161 label.text = label_text
162 label.custom_minimum_size = Vector2(112, 0)
163 row.add_child(label)
164 var slider = HSlider.new()
165 slider.name = "Slider"
166 slider.min_value = 0
167 slider.max_value = 100
168 slider.step = 1
169 slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
170 row.add_child(slider)
171 var mute = CheckBox.new()
172 mute.name = "Mute"
173 mute.text = "Mute"
174 row.add_child(mute)
175 content.add_child(row)
176 return {"slider": slider, "mute": mute}
177
178
179func _get_autoload(name:String):
180 var loop = Engine.get_main_loop()
181 if loop is SceneTree:
182 return loop.root.get_node_or_null(name)
183 return null
184
185
186func _settings_manager():
187 var manager = _get_autoload("SettingsManager")
188 if manager != null:
189 return manager
190 if settings_manager_fallback == null:
191 settings_manager_fallback = SettingsManagerScript.new()
192 return settings_manager_fallback
193
194
195func dispose() -> void:
196 var settings_manager = _settings_manager()
197 if settings_manager.settings_changed.is_connected(_on_settings_changed):
198 settings_manager.settings_changed.disconnect(_on_settings_changed)
199 managed_popups.clear()
200
201
202func _prune_managed_popups() -> void:
203 var active_popups:Array = []
204 for popup in managed_popups:
205 if popup != null and is_instance_valid(popup):
206 active_popups.append(popup)
207 managed_popups = active_popups