Guard destructive settings and radio actions
- Route reset campaign and tutorial replay through one reusable confirmation dialog; repeated presses cannot stack or emit twice. - Keep emergency hold-to-send single-shot and cover the post-submit release. - Add destructive-action regression checks, strings and documentation.
This commit is contained in:
1 parent
f6aa26e6ca
commit
7315166361
10 files changed
+121
-14
No files matched your search
@@ -32,6 +32,7 @@ var _reduce_motion: CheckButton = null
|
||||
var _captions: CheckButton = null
|
||||
var _bind_buttons := {}
|
||||
var _listening_action := ""
|
||||
var _destructive_dialog: ConfirmationDialog = null
|
||||
var settings: Dictionary = {}
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -136,7 +137,7 @@ func _build() -> void:
|
||||
var replay := Button.new()
|
||||
replay.name = "ReplayTutorialButton"
|
||||
replay.text = Strings.lookup("ui.settings_replay")
|
||||
replay.pressed.connect(func(): replay_tutorial_requested.emit())
|
||||
replay.pressed.connect(_confirm_replay_tutorial)
|
||||
UiStyles.apply_button(replay, 16)
|
||||
replay_row.add_child(replay)
|
||||
var reset_campaign := Button.new()
|
||||
@@ -284,15 +285,46 @@ func _on_difficulty_selected(index: int) -> void:
|
||||
settings["ai_difficulty"] = ["easy", "normal", "hard"][clampi(index, 0, 2)]
|
||||
|
||||
func _confirm_reset_campaign() -> void:
|
||||
_open_destructive_dialog(Strings.lookup("ui.settings_reset_title"),
|
||||
Strings.lookup("ui.settings_reset_confirm"),
|
||||
func(): reset_campaign_requested.emit())
|
||||
|
||||
func _confirm_replay_tutorial() -> void:
|
||||
_open_destructive_dialog(Strings.lookup("ui.settings_replay_title"),
|
||||
Strings.lookup("ui.settings_replay_confirm"),
|
||||
func(): replay_tutorial_requested.emit())
|
||||
|
||||
## One modal at a time; a second press while it is open focuses the existing
|
||||
## dialog instead of creating another one (and possibly emitting twice).
|
||||
func _open_destructive_dialog(title: String, body: String, callback: Callable) -> void:
|
||||
if _destructive_dialog != null and is_instance_valid(_destructive_dialog):
|
||||
# Reuse the open confirmation instead of stacking a second one. The
|
||||
# dialog is dismissed on confirm/cancel, so an existing instance is
|
||||
# always the one waiting for the player's decision.
|
||||
if _destructive_dialog.is_inside_tree():
|
||||
_destructive_dialog.grab_focus()
|
||||
return
|
||||
var dialog := ConfirmationDialog.new()
|
||||
dialog.title = "Reset campaign"
|
||||
dialog.dialog_text = Strings.lookup("ui.settings_reset_confirm")
|
||||
dialog.confirmed.connect(func(): reset_campaign_requested.emit())
|
||||
_destructive_dialog = dialog
|
||||
dialog.title = title
|
||||
dialog.dialog_text = body
|
||||
dialog.confirmed.connect(func():
|
||||
if _destructive_dialog != dialog:
|
||||
return
|
||||
_dismiss_destructive_dialog(dialog)
|
||||
callback.call())
|
||||
dialog.canceled.connect(func(): _dismiss_destructive_dialog(dialog))
|
||||
add_child(dialog)
|
||||
UiStyles.apply_button(dialog.get_ok_button(), 16)
|
||||
UiStyles.apply_button(dialog.get_cancel_button(), 16)
|
||||
dialog.popup_centered()
|
||||
dialog.confirmed.connect(dialog.queue_free)
|
||||
|
||||
func _dismiss_destructive_dialog(dialog: ConfirmationDialog) -> void:
|
||||
if _destructive_dialog == dialog:
|
||||
_destructive_dialog = null
|
||||
if is_instance_valid(dialog):
|
||||
dialog.hide()
|
||||
dialog.queue_free()
|
||||
|
||||
func _refresh_bind_buttons() -> void:
|
||||
var remaps: Dictionary = settings.get("input_bindings", {})
|
||||
|
||||
Reference in new issue
Block a user