-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadvanced_settings.gd
More file actions
336 lines (296 loc) · 11.3 KB
/
advanced_settings.gd
File metadata and controls
336 lines (296 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
extends Control
var js_bridge_wrapper: JavaScriptBridgeWrapper = JavaScriptBridgeWrapper.new()
var os_wrapper: OSWrapper = OSWrapper.new() # Assuming OSWrapper is defined similarly
var js_window: JavaScriptObject
# Explicit mapping from display names to enum values
var log_level_display_to_enum: Dictionary = {
"DEBUG": Globals.LogLevel.DEBUG,
"INFO": Globals.LogLevel.INFO,
"WARNING": Globals.LogLevel.WARNING,
"ERROR": Globals.LogLevel.ERROR,
"NONE": Globals.LogLevel.NONE
}
var _change_log_level_cb: JavaScriptObject
# Reset button
var _advanced_reset_cb: Variant
# Back button
var _advanced_back_button_pressed_cb: Variant
var _intentional_exit: bool = false
@onready var advanced_back_button: Button = $Panel/Controls/BtnContainer/BackButton
@onready var advanced_reset_button: Button = $Panel/Controls/BtnContainer/ResetButton
@onready
var log_lvl_option: OptionButton = get_node("Panel/Controls/LogLevelContainer/LogLevelOptionButton")
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
# Populate Log level with all LogLevel enum values
for level: String in Globals.LogLevel.keys():
if level != "NONE": # Skip auto-add NONE; add manually as "None"
log_lvl_option.add_item(level) # "Debug", "Info", etc.
log_lvl_option.add_item("NONE") # Manual for title case
# Set to current log level (find index by enum value)
var current_value: int = Globals.settings.current_log_level
var index: int = Globals.LogLevel.values().find(current_value)
if index != -1:
log_lvl_option.selected = index
else:
log_lvl_option.selected = 1 # Fallback to INFO (index 1)
Globals.log_message("Invalid saved log level—reset to INFO.", Globals.LogLevel.WARNING)
# Connect signals to type-specific handlers (change: separate from JS callbacks)
tree_exited.connect(_on_tree_exited)
log_lvl_option.item_selected.connect(_on_log_level_item_selected)
if js_bridge_wrapper and os_wrapper.has_feature("web"):
# Toggle overlays...
(
js_bridge_wrapper
. eval(
"""
document.getElementById('log-level-select').style.display = 'block';
document.getElementById('advanced-back-button').style.display = 'block';
document.getElementById('advanced-reset-button').style.display = 'block';
""",
true
)
)
# Expose callbacks to JS (store refs to prevent GC)
js_window = js_bridge_wrapper.get_interface("window") as JavaScriptObject
if js_window:
_change_log_level_cb = js_bridge_wrapper.create_callback(
Callable(self, "_on_change_log_level_js")
)
js_window.changeLogLevel = _change_log_level_cb
# Back button
if not advanced_back_button.pressed.is_connected(_on_advanced_back_button_pressed):
advanced_back_button.pressed.connect(_on_advanced_back_button_pressed)
# Reset button listener
if not advanced_reset_button.pressed.is_connected(_on_advanced_reset_button_pressed):
advanced_reset_button.pressed.connect(_on_advanced_reset_button_pressed)
if os_wrapper.has_feature("web"):
if js_window: # New: Null check
# JS Callbacks
# Expose callbacks for back button
_advanced_back_button_pressed_cb = _register_js_callback(
"_on_advanced_back_button_pressed_js", "advancedBackPressed"
)
# Expose callbacks for Reset button
_advanced_reset_cb = _register_js_callback(
"_on_advanced_reset_js", "advancedResetPressed"
)
# Give keyboard focus to the log level slider (only if nothing in this menu already has focus)
Globals.ensure_initial_focus(
log_lvl_option,
[log_lvl_option, advanced_back_button, advanced_reset_button],
"Advanced Settings"
)
Globals.log_message("Advanced Settings menu loaded.", Globals.LogLevel.DEBUG)
## Registers a JS callback by creating and assigning it to window property.
## :param callback_method: Name of the GDScript method to call.
## :type callback_method: String
## :param window_property: Name of the JS window property to assign.
## :type window_property: String
## :rtype: Variant
func _register_js_callback(callback_method: String, window_property: String) -> Variant:
var callback: Variant = js_bridge_wrapper.create_callback(Callable(self, callback_method))
js_window[window_property] = callback
return callback
func _on_tree_exited() -> void:
if _intentional_exit:
return
var hidden_menu_found: bool = false
if not Globals.hidden_menus.is_empty():
var prev_menu: Node = Globals.hidden_menus.pop_back()
if is_instance_valid(prev_menu):
prev_menu.visible = true
Globals.log_message(
"Advanced menu exited unexpectedly, restored previous menu.",
Globals.LogLevel.WARNING
)
hidden_menu_found = true
if os_wrapper.has_feature("web") and js_window:
_unset_advanced_window_callbacks()
if hidden_menu_found and js_bridge_wrapper:
(
js_bridge_wrapper
. eval(
"""
// Show Options menu overlays
document.getElementById('controls-button').style.display = 'block';
document.getElementById('audio-button').style.display = 'block';
document.getElementById('advanced-button').style.display = 'block';
document.getElementById('gameplay-button').style.display = 'block';
document.getElementById('options-back-button').style.display = 'block';
// Hide Advanced Settings overlays
document.getElementById('log-level-select').style.display = 'none';
document.getElementById('advanced-back-button').style.display = 'none';
document.getElementById('advanced-reset-button').style.display = 'none';
""",
true
)
)
if not hidden_menu_found:
Globals.log_message("No hidden menu to show on unexpected exit.", Globals.LogLevel.INFO)
## A cleanup function
func _unset_advanced_window_callbacks() -> void:
if not os_wrapper.has_feature("web") or not js_window:
return
js_window.changeLogLevel = null
js_window.advancedBackPressed = null
js_window.advancedResetPressed = null
## RESET BUTTON
## Handles Advanced Settings reset button press.
func _on_advanced_reset_button_pressed() -> void:
Globals.log_message("Advanced Settings reset pressed.", Globals.LogLevel.DEBUG)
# Log level should be reset to INFO
Globals.settings.current_log_level = Globals.LogLevel.INFO
log_lvl_option.selected = Globals.LogLevel.values().find(Globals.LogLevel.INFO)
Globals._save_settings()
func _on_advanced_reset_js(_args: Array) -> void:
_on_advanced_reset_button_pressed()
func _on_advanced_back_button_pressed() -> void:
## Handles advanced back button press.
##
## Logs action, restores previous menu if available, performs web cleanup if applicable,
## and frees self. Uses focus helper for consistency on restore.
##
## :rtype: void
Globals.log_message("Advanced Back button pressed.", Globals.LogLevel.DEBUG)
var hidden_menu_found: bool = false
if not Globals.hidden_menus.is_empty():
var prev_menu: Node = Globals.hidden_menus.pop_back()
if is_instance_valid(prev_menu):
prev_menu.visible = true
hidden_menu_found = true
# Restore focus using helper for consistency
var advanced_btn: Button = prev_menu.get_node(
"Panel/OptionsVBoxContainer/AdvancedSettingsButton"
)
if is_instance_valid(advanced_btn):
Globals.ensure_initial_focus(
advanced_btn, [advanced_btn], "Options Menu - Advanced Button"
)
else:
Globals.log_message(
"AdvancedSettingsButton not found—skipping focus.", Globals.LogLevel.WARNING
)
# Decoupled cleanup: Run if web and js_window available, but gate eval on js_bridge_wrapper
if os_wrapper.has_feature("web") and js_window:
_unset_advanced_window_callbacks()
# Set Options menu buttons visible in DOM (if bridge available for eval)
if hidden_menu_found and js_bridge_wrapper:
(
js_bridge_wrapper
. eval(
"""
// Show Options menu overlays
document.getElementById('controls-button').style.display = 'block';
document.getElementById('audio-button').style.display = 'block';
document.getElementById('advanced-button').style.display = 'block';
document.getElementById('gameplay-button').style.display = 'block';
document.getElementById('options-back-button').style.display = 'block';
// Hide Advanced Settings overlays
document.getElementById('log-level-select').style.display = 'none';
document.getElementById('advanced-back-button').style.display = 'none';
document.getElementById('advanced-reset-button').style.display = 'none';
""",
true
)
)
if not hidden_menu_found:
Globals.log_message("No hidden menu to show.", Globals.LogLevel.INFO)
_intentional_exit = true
queue_free()
func _on_advanced_back_button_pressed_js(args: Array) -> void:
## JS callback for back press.
##
## Routes to signal handler.
##
## :param args: Unused array from JS.
## :type args: Array
## :rtype: void
Globals.log_message(
"JS _advanced_back_button_pressed_cb callback called with args: " + str(args),
Globals.LogLevel.DEBUG
)
_on_advanced_back_button_pressed()
func get_log_level_index() -> int:
## Retrieves the index of the current log level in the enum values.
##
## :returns: The index of the current log level.
## :rtype: int
return Globals.LogLevel.values().find(Globals.current_log_level)
# Change: Separate handler for signal (int index)
func _on_log_level_item_selected(index: int) -> void:
## Handles log level selection from the OptionButton signal.
##
## Updates global log level, logs the change, and saves settings.
##
## :param index: The selected item index.
## :type index: int
## :rtype: void
var selected_name: String = log_lvl_option.get_item_text(index)
var selected_enum: Globals.LogLevel = log_level_display_to_enum.get(
selected_name, Globals.LogLevel.INFO
)
# Only update the resource; the Observer handles the rest
Globals.settings.current_log_level = selected_enum
log_lvl_option.selected = Globals.LogLevel.values().find(selected_enum)
# Temporary raw print to bypass log_message
Globals.log_message("Log level changed to: " + selected_name, Globals.LogLevel.DEBUG)
# Globals._save_settings()
# New: JS-specific callback (exactly one Array arg, no default)
func _on_change_log_level_js(args: Array) -> void:
## JS callback for changing log level.
##
## Routes to the signal handler.
##
## :param args: Array containing the index (from JS).
## :type args: Array
## :rtype: void
if args.is_empty():
Globals.log_message(
"JS change_log_level callback received empty args—skipping.", Globals.LogLevel.WARNING
)
return
var first_arg: Variant = args[0]
if (
first_arg is not JavaScriptObject
and typeof(first_arg) != TYPE_ARRAY
and first_arg.size() == 0
and first_arg.is_empty()
):
Globals.log_message(
(
"JS change_log_level callback received invalid first arg (not a non-empty array): "
+ str(args)
),
Globals.LogLevel.WARNING
)
return
var potential_index: Variant = first_arg[0]
if (
typeof(potential_index) != TYPE_INT
and typeof(potential_index) != TYPE_FLOAT
and typeof(potential_index) != TYPE_STRING
):
Globals.log_message(
"JS change_log_level callback received non-convertible index value: " + str(args),
Globals.LogLevel.WARNING
)
return
var index: int = int(potential_index)
if index < 0 or index >= log_lvl_option.item_count:
Globals.log_message(
(
"JS change_log_level callback received out-of-bounds index: "
+ str(index)
+ " (args: "
+ str(args)
+ ")"
),
Globals.LogLevel.WARNING
)
return
Globals.log_message(
"JS change_log_level callback called with valid index: " + str(index),
Globals.LogLevel.DEBUG
)
_on_log_level_item_selected(index)