diff --git a/ui/components/bubble_menu/bubble_confirmation_page.gd b/ui/components/bubble_menu/bubble_confirmation_page.gd new file mode 100644 index 0000000..cbb0ede --- /dev/null +++ b/ui/components/bubble_menu/bubble_confirmation_page.gd @@ -0,0 +1,250 @@ +class_name BubbleConfirmationPage +extends Control + +signal confirmed +signal cancelled + +enum InitialFocus { + CONFIRM, + CANCEL, +} + +@export var cluster_path: NodePath = ^"BubbleCluster" +@export var message_path: NodePath = ^"BubbleCluster/MessageBubble" +@export var message_label_path: NodePath = ( + ^"BubbleCluster/MessageBubble/MessageLabel" +) +@export var confirm_path: NodePath = ^"BubbleCluster/ConfirmButton" +@export var confirm_label_path: NodePath = ( + ^"BubbleCluster/ConfirmButton/ConfirmLabel" +) +@export var cancel_path: NodePath = ^"BubbleCluster/CancelButton" +@export var cancel_label_path: NodePath = ( + ^"BubbleCluster/CancelButton/CancelLabel" +) +@export var maximum_layout_size: Vector2 = Vector2(720.0, 520.0) +@export var compact_maximum_layout_size: Vector2 = Vector2(544.0, 400.0) +@export var compact_width_threshold: float = 680.0 +@export var compact_height_threshold: float = 500.0 +@export_range(0.0, 128.0, 1.0) var transition_safe_margin: float = 24.0 + +var _cluster: BubbleCluster +var _message: BubbleButton +var _message_label: Label +var _confirm_button: BubbleButton +var _confirm_label: Label +var _cancel_button: BubbleButton +var _cancel_label: Label +var _bubbles: Array[BubbleButton] = [] +var _initial_focus: InitialFocus = InitialFocus.CONFIRM +var _resting_cluster_position: Vector2 = Vector2.ZERO +var _transition: Tween +var _transition_generation: int = 0 +var _is_transitioning: bool = false + + +func _ready() -> void: + _cluster = get_node(cluster_path) as BubbleCluster + _message = get_node(message_path) as BubbleButton + _message_label = get_node(message_label_path) as Label + _confirm_button = get_node(confirm_path) as BubbleButton + _confirm_label = get_node(confirm_label_path) as Label + _cancel_button = get_node(cancel_path) as BubbleButton + _cancel_label = get_node(cancel_label_path) as Label + _bubbles = [_message, _confirm_button, _cancel_button] + _cluster.configure(_bubbles) + _message.focus_mode = Control.FOCUS_NONE + _message.mouse_filter = Control.MOUSE_FILTER_IGNORE + _confirm_button.pressed.connect(confirmed.emit) + _cancel_button.pressed.connect(cancelled.emit) + _configure_focus() + resized.connect(_update_layout) + call_deferred("_update_layout") + hide_page() + + +func configure( + message_text: String, + confirm_text: String, + cancel_text: String = "cancel", + initial_focus: InitialFocus = InitialFocus.CONFIRM, +) -> void: + _message_label.text = message_text + _confirm_label.text = confirm_text + _cancel_label.text = cancel_text + _initial_focus = initial_focus + + +func transition_in(duration: float, completed: Callable) -> void: + _transition_generation += 1 + _cancel_transition() + show() + _is_transitioning = true + _set_interactive(false) + set_process(true) + _cluster.position = Vector2( + _resting_cluster_position.x, + size.y + transition_safe_margin + ) + var generation: int = _transition_generation + _transition = create_tween() + _transition.tween_property( + _cluster, + "position", + _resting_cluster_position, + duration + ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) + _transition.finished.connect( + _finish_transition_in.bind(generation, completed), + CONNECT_ONE_SHOT + ) + + +func transition_out(duration: float, completed: Callable) -> void: + if not visible or _is_transitioning: + return + _transition_generation += 1 + _cancel_transition() + _is_transitioning = true + _set_interactive(false) + var generation: int = _transition_generation + _transition = create_tween() + _transition.tween_property( + _cluster, + "position:y", + -_cluster.size.y - transition_safe_margin, + duration + ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) + _transition.finished.connect( + _finish_transition_out.bind(generation, completed), + CONNECT_ONE_SHOT + ) + + +func hide_page() -> void: + _transition_generation += 1 + _cancel_transition() + _is_transitioning = false + _set_interactive(false) + set_process(false) + hide() + if _cluster != null: + _cluster.position = _resting_cluster_position + + +func lock_interaction() -> void: + _set_interactive(false) + + +func is_transitioning() -> bool: + return _is_transitioning + + +func focus_initial() -> void: + var target: BubbleButton = ( + _cancel_button + if _initial_focus == InitialFocus.CANCEL + else _confirm_button + ) + if target.visible and target.focus_mode != Control.FOCUS_NONE: + target.grab_focus() + + +func _process(delta: float) -> void: + if visible: + _cluster.advance_motion(delta) + + +func _update_layout() -> void: + if not is_node_ready() or _cluster == null: + return + var compact: bool = ( + size.x < compact_width_threshold + or size.y < compact_height_threshold + ) + var layout_maximum: Vector2 = ( + compact_maximum_layout_size + if compact + else maximum_layout_size + ) + var field_size := Vector2( + minf(size.x, layout_maximum.x), + minf(size.y, layout_maximum.y) + ) + field_size.x = maxf(1.0, field_size.x) + field_size.y = maxf(1.0, field_size.y) + _resting_cluster_position = (size - field_size) * 0.5 + if not _is_transitioning: + _cluster.position = _resting_cluster_position + _cluster.size = field_size + _cluster.apply_layout(field_size, compact) + + +func _configure_focus() -> void: + var confirm_to_cancel: NodePath = _confirm_button.get_path_to( + _cancel_button + ) + var cancel_to_confirm: NodePath = _cancel_button.get_path_to( + _confirm_button + ) + _confirm_button.focus_neighbor_left = confirm_to_cancel + _confirm_button.focus_neighbor_right = confirm_to_cancel + _confirm_button.focus_neighbor_top = confirm_to_cancel + _confirm_button.focus_neighbor_bottom = confirm_to_cancel + _cancel_button.focus_neighbor_left = cancel_to_confirm + _cancel_button.focus_neighbor_right = cancel_to_confirm + _cancel_button.focus_neighbor_top = cancel_to_confirm + _cancel_button.focus_neighbor_bottom = cancel_to_confirm + + +func _set_interactive(interactive: bool) -> void: + mouse_filter = ( + Control.MOUSE_FILTER_PASS + if interactive + else Control.MOUSE_FILTER_IGNORE + ) + for bubble: BubbleButton in [_confirm_button, _cancel_button]: + if not interactive and bubble.has_focus(): + bubble.release_focus() + bubble.focus_mode = ( + Control.FOCUS_ALL if interactive else Control.FOCUS_NONE + ) + bubble.mouse_filter = ( + Control.MOUSE_FILTER_STOP + if interactive + else Control.MOUSE_FILTER_IGNORE + ) + + +func _finish_transition_in( + generation: int, + completed: Callable, +) -> void: + if generation != _transition_generation or not visible: + return + _transition = null + _is_transitioning = false + _cluster.position = _resting_cluster_position + _set_interactive(true) + focus_initial() + completed.call() + + +func _finish_transition_out( + generation: int, + completed: Callable, +) -> void: + if generation != _transition_generation or not visible: + return + _transition = null + _is_transitioning = false + hide() + _cluster.position = _resting_cluster_position + set_process(false) + completed.call() + + +func _cancel_transition() -> void: + if _transition != null: + _transition.kill() + _transition = null diff --git a/ui/components/bubble_menu/bubble_confirmation_page.gd.uid b/ui/components/bubble_menu/bubble_confirmation_page.gd.uid new file mode 100644 index 0000000..ef9111c --- /dev/null +++ b/ui/components/bubble_menu/bubble_confirmation_page.gd.uid @@ -0,0 +1 @@ +uid://c5q6yypya7fr1 diff --git a/ui/components/bubble_menu/bubble_confirmation_page.tscn b/ui/components/bubble_menu/bubble_confirmation_page.tscn new file mode 100644 index 0000000..8f3e0fe --- /dev/null +++ b/ui/components/bubble_menu/bubble_confirmation_page.tscn @@ -0,0 +1,139 @@ +[gd_scene load_steps=7 format=3] + +[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_confirmation_page.gd" id="1_page"] +[ext_resource type="PackedScene" path="res://ui/components/bubble_menu/bubble_button.tscn" id="2_bubble"] +[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_cluster.gd" id="3_cluster"] +[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_menu_profile.gd" id="4_profile_script"] +[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="5_profile"] + +[sub_resource type="Resource" id="BubbleMenuProfile_confirmation_action"] +script = ExtResource("4_profile_script") +normal_border_width = 3 +emphasized_border_width = 4 + +[sub_resource type="Resource" id="BubbleMenuProfile_confirmation_message"] +script = ExtResource("4_profile_script") +corner_radius = 256 + +[node name="BubbleConfirmationPage" type="Control"] +visible = false +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("1_page") + +[node name="BubbleCluster" type="Control" parent="."] +layout_mode = 0 +offset_right = 720.0 +offset_bottom = 520.0 +script = ExtResource("3_cluster") +profile = ExtResource("5_profile") +desktop_reference_size = Vector2(720, 520) +compact_reference_size = Vector2(544, 400) + +[node name="MessageBubble" parent="BubbleCluster" instance=ExtResource("2_bubble")] +custom_minimum_size = Vector2(0, 0) +profile = SubResource("BubbleMenuProfile_confirmation_message") +neutral_size = Vector2(356, 350) +desktop_anchor = Vector2(360, 214) +compact_anchor = Vector2(360, 196) +compact_minimum_size = Vector2(292, 288) +label_control_path = NodePath("MessageLabel") +minimum_font_size = 15 +maximum_font_size = 22 +horizontal_amplitude = 0.8 +vertical_amplitude = 2.2 +motion_period = 6.8 +motion_phase = 0.45 +deformation_amplitude = 0.008 +deformation_period = 7.4 + +[node name="MessageLabel" type="Label" parent="BubbleCluster/MessageBubble"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 38.0 +offset_top = 36.0 +offset_right = -38.0 +offset_bottom = -36.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1) +theme_override_constants/line_spacing = -2 +text = "confirm?" +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 2 + +[node name="ConfirmButton" parent="BubbleCluster" instance=ExtResource("2_bubble")] +custom_minimum_size = Vector2(0, 0) +profile = SubResource("BubbleMenuProfile_confirmation_action") +neutral_size = Vector2(142, 136) +desktop_anchor = Vector2(258, 432) +compact_anchor = Vector2(210, 432) +compact_minimum_size = Vector2(108, 104) +label_control_path = NodePath("ConfirmLabel") +minimum_font_size = 14 +maximum_font_size = 22 +horizontal_amplitude = 1.7 +vertical_amplitude = 4.2 +motion_period = 5.6 +motion_phase = 2.15 +deformation_amplitude = 0.014 +deformation_period = 5.9 + +[node name="ConfirmLabel" type="Label" parent="BubbleCluster/ConfirmButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 14.0 +offset_top = 14.0 +offset_right = -14.0 +offset_bottom = -14.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +text = "confirm" +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 2 + +[node name="CancelButton" parent="BubbleCluster" instance=ExtResource("2_bubble")] +custom_minimum_size = Vector2(0, 0) +neutral_size = Vector2(124, 120) +desktop_anchor = Vector2(462, 426) +compact_anchor = Vector2(510, 426) +compact_minimum_size = Vector2(98, 94) +label_control_path = NodePath("CancelLabel") +minimum_font_size = 14 +maximum_font_size = 20 +horizontal_amplitude = 1.5 +vertical_amplitude = 3.8 +motion_period = 5.1 +motion_phase = 4.0 +deformation_amplitude = 0.015 +deformation_period = 5.4 + +[node name="CancelLabel" type="Label" parent="BubbleCluster/CancelButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 12.0 +offset_top = 12.0 +offset_right = -12.0 +offset_bottom = -12.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +text = "cancel" +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 2 diff --git a/ui/pause_menu.gd b/ui/pause_menu.gd index 9d569af..c3101b8 100644 --- a/ui/pause_menu.gd +++ b/ui/pause_menu.gd @@ -15,6 +15,9 @@ const SettingsManagerType = preload( "res://settings/player_settings_manager.gd" ) const SettingsPanelType = preload("res://ui/settings_panel.gd") +const BubbleConfirmationPageType = preload( + "res://ui/components/bubble_menu/bubble_confirmation_page.gd" +) const FishingSpotType = preload("res://fishing/fishing_spot.gd") signal return_to_title_requested @@ -46,11 +49,9 @@ enum CloseReason { @onready var _transition_flurry: BubbleTransitionFlurry = ( %TransitionBubbleLayer ) -@onready var _confirmation_panel: PanelContainer = %ConfirmationPanel -@onready var _confirmation_title: Label = %ConfirmationTitle -@onready var _confirmation_text: Label = %ConfirmationText -@onready var _confirm_button: Button = %ConfirmButton -@onready var _cancel_button: Button = %CancelConfirmButton +@onready var _confirmation_page: BubbleConfirmationPageType = ( + %ConfirmationPage +) @onready var _feedback: Label = %FeedbackLabel @onready var _save_button: BubbleButton = %SaveButton @@ -70,9 +71,6 @@ var _root_transition_generation: int = 0 var _closing_menu: bool = false var _backdrop_fade: Tween var _backdrop_fade_generation: int = 0 -var _confirmation_fade: Tween -var _confirmation_fade_generation: int = 0 -var _confirmation_fade_active: bool = false func _ready() -> void: @@ -82,16 +80,15 @@ func _ready() -> void: %ReturnToTitleButton.pressed.connect(_confirm_return_to_title) %ResetProgressButton.pressed.connect(_confirm_reset_progress) %QuitButton.pressed.connect(_request_quit) - _confirm_button.pressed.connect(_accept_confirmation) - _cancel_button.pressed.connect(_close_confirmation) + _confirmation_page.confirmed.connect(_accept_confirmation) + _confirmation_page.cancelled.connect(_close_confirmation) _settings_panel.applied.connect(_on_settings_applied) _settings_panel.closed.connect(_on_settings_closed) _settings_panel.navigation_transition_started.connect( _emit_transition_flurry ) _dim_background.color.a = 0.0 - _confirmation_panel.modulate.a = 0.0 - _set_confirmation_interactive(false) + _confirmation_page.hide_page() resized.connect(_update_responsive_pause_stage) call_deferred("_update_responsive_pause_stage") @@ -124,7 +121,7 @@ func open_menu() -> void: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE _feedback.text = "" _settings_panel.hide() - _confirmation_panel.hide() + _confirmation_page.hide_page() _confirmation_action = ConfirmationAction.NONE _action_in_progress = false _root_page.hide_page() @@ -168,9 +165,9 @@ func close_menu( func handle_escape() -> bool: if not visible: return false - if _root_transition_active or _confirmation_fade_active: + if _root_transition_active or _confirmation_page.is_transitioning(): return true - if _confirmation_panel.visible: + if _confirmation_page.visible: _close_confirmation() elif _settings_panel.visible: _settings_panel.handle_back() @@ -281,53 +278,57 @@ func _open_confirmation( if _action_in_progress or _root_transition_active: return _confirmation_action = action - _confirmation_title.text = title - _confirmation_text.text = message - _confirm_button.text = confirm_text - _confirm_button.theme_type_variation = ( - &"DangerButton" if dangerous else StringName() + _confirmation_page.configure( + "%s\n\n%s" % [title, message], + confirm_text, + "cancel", + ( + BubbleConfirmationPageType.InitialFocus.CANCEL + if dangerous + else BubbleConfirmationPageType.InitialFocus.CONFIRM + ) ) - _begin_root_exit(_show_confirmation.bind(dangerous)) + _begin_root_exit(_show_confirmation) -func _show_confirmation(dangerous: bool) -> void: - _fade_confirmation( - true, - _finish_confirmation_open.bind(dangerous) +func _show_confirmation() -> void: + _confirmation_page.transition_in( + PAGE_INCOMING_DURATION, + _finish_confirmation_open ) -func _finish_confirmation_open(dangerous: bool) -> void: - _set_confirmation_interactive(true) - if dangerous: - _cancel_button.grab_focus() - else: - _confirm_button.grab_focus() +func _finish_confirmation_open() -> void: + pass func _close_confirmation() -> void: - if _root_transition_active or _confirmation_fade_active: + if _root_transition_active or _confirmation_page.is_transitioning(): return _confirmation_action = ConfirmationAction.NONE - _fade_confirmation(false, _finish_confirmation_cancel) + _emit_transition_flurry() + _confirmation_page.transition_out( + PAGE_OUTGOING_DURATION, + _finish_confirmation_cancel + ) func _finish_confirmation_cancel() -> void: - _begin_root_entry(false) + _begin_root_entry(true) func _accept_confirmation() -> void: if ( _action_in_progress or _root_transition_active - or _confirmation_fade_active + or _confirmation_page.is_transitioning() ): return var action: ConfirmationAction = _confirmation_action _confirmation_action = ConfirmationAction.NONE _action_in_progress = true - _fade_confirmation( - false, + _confirmation_page.transition_out( + VISIBILITY_FADE_DURATION, _finish_confirmation_accept.bind(action) ) @@ -417,14 +418,11 @@ func _finish_close(reason: CloseReason, restore_controls: bool) -> void: _root_transition_generation += 1 _root_transition_active = false _cancel_backdrop_fade() - _cancel_confirmation_fade() _dim_background.color.a = 0.0 _dim_background.hide() - _confirmation_panel.modulate.a = 0.0 - _set_confirmation_interactive(false) _settings_panel.hide() _root_page.hide_page() - _confirmation_panel.hide() + _confirmation_page.hide_page() _confirmation_action = ConfirmationAction.NONE _action_in_progress = false _transition_flurry.clear_flurries() @@ -483,83 +481,6 @@ func _cancel_backdrop_fade() -> void: _backdrop_fade = null -func _fade_confirmation( - fade_in: bool, - completed: Callable, -) -> void: - _confirmation_fade_generation += 1 - _cancel_confirmation_fade() - _confirmation_fade_active = true - _set_confirmation_interactive(false) - _confirmation_panel.show() - var target_alpha: float = 1.0 if fade_in else 0.0 - if is_equal_approx(_confirmation_panel.modulate.a, target_alpha): - _finish_confirmation_fade( - _confirmation_fade_generation, - fade_in, - completed - ) - return - var generation: int = _confirmation_fade_generation - _confirmation_fade = create_tween() - _confirmation_fade.tween_property( - _confirmation_panel, - "modulate:a", - target_alpha, - VISIBILITY_FADE_DURATION - ).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT) - _confirmation_fade.finished.connect( - _finish_confirmation_fade.bind( - generation, - fade_in, - completed - ), - CONNECT_ONE_SHOT - ) - - -func _finish_confirmation_fade( - generation: int, - faded_in: bool, - completed: Callable, -) -> void: - if generation != _confirmation_fade_generation or not visible: - return - _confirmation_fade = null - _confirmation_fade_active = false - _confirmation_panel.modulate.a = 1.0 if faded_in else 0.0 - if not faded_in: - _confirmation_panel.hide() - completed.call() - - -func _cancel_confirmation_fade() -> void: - _confirmation_fade_generation += 1 - _confirmation_fade_active = false - if _confirmation_fade != null: - _confirmation_fade.kill() - _confirmation_fade = null - - -func _set_confirmation_interactive(interactive: bool) -> void: - _confirmation_panel.mouse_filter = ( - Control.MOUSE_FILTER_STOP - if interactive - else Control.MOUSE_FILTER_IGNORE - ) - for button: Button in [_confirm_button, _cancel_button]: - if not interactive and button.has_focus(): - button.release_focus() - button.focus_mode = ( - Control.FOCUS_ALL if interactive else Control.FOCUS_NONE - ) - button.mouse_filter = ( - Control.MOUSE_FILTER_STOP - if interactive - else Control.MOUSE_FILTER_IGNORE - ) - - func _update_responsive_pause_stage() -> void: if not is_node_ready(): return diff --git a/ui/pause_menu.tscn b/ui/pause_menu.tscn index 79d8f1c..318caa5 100644 --- a/ui/pause_menu.tscn +++ b/ui/pause_menu.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=9 format=3] +[gd_scene load_steps=10 format=3] [ext_resource type="Script" path="res://ui/pause_menu.gd" id="1_script"] [ext_resource type="PackedScene" path="res://ui/settings_panel.tscn" id="2_settings"] @@ -8,6 +8,7 @@ [ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_cluster.gd" id="6_cluster"] [ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="7_profile"] [ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_transition_flurry.gd" id="8_flurry"] +[ext_resource type="PackedScene" path="res://ui/components/bubble_menu/bubble_confirmation_page.tscn" id="9_confirmation"] [node name="PauseMenu" type="Control"] unique_name_in_owner = true @@ -200,61 +201,11 @@ mouse_filter = 2 unique_name_in_owner = true layout_mode = 2 -[node name="ConfirmationCenter" type="CenterContainer" parent="."] -z_index = 3 +[node name="ConfirmationPage" parent="ResponsivePauseStage/PausePresentationScaleRoot" instance=ExtResource("9_confirmation")] +unique_name_in_owner = true layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -mouse_filter = 2 - -[node name="ConfirmationPanel" type="PanelContainer" parent="ConfirmationCenter"] -unique_name_in_owner = true -visible = false -custom_minimum_size = Vector2(700, 0) -layout_mode = 2 - -[node name="Margin" type="MarginContainer" parent="ConfirmationCenter/ConfirmationPanel"] -layout_mode = 2 -theme_override_constants/margin_left = 28 -theme_override_constants/margin_top = 24 -theme_override_constants/margin_right = 28 -theme_override_constants/margin_bottom = 24 - -[node name="Content" type="VBoxContainer" parent="ConfirmationCenter/ConfirmationPanel/Margin"] -layout_mode = 2 -theme_override_constants/separation = 15 - -[node name="ConfirmationTitle" type="Label" parent="ConfirmationCenter/ConfirmationPanel/Margin/Content"] -unique_name_in_owner = true -layout_mode = 2 -theme_override_colors/font_color = Color(0.937, 0.357, 0.384, 1) -theme_override_font_sizes/font_size = 36 -text = "confirm" -horizontal_alignment = 1 - -[node name="ConfirmationText" type="Label" parent="ConfirmationCenter/ConfirmationPanel/Margin/Content"] -unique_name_in_owner = true -layout_mode = 2 -text = "are you sure?" -horizontal_alignment = 1 -autowrap_mode = 2 - -[node name="Buttons" type="HBoxContainer" parent="ConfirmationCenter/ConfirmationPanel/Margin/Content"] -layout_mode = 2 -theme_override_constants/separation = 12 -alignment = 1 - -[node name="ConfirmButton" type="Button" parent="ConfirmationCenter/ConfirmationPanel/Margin/Content/Buttons"] -unique_name_in_owner = true -custom_minimum_size = Vector2(240, 64) -layout_mode = 2 -text = "confirm" - -[node name="CancelConfirmButton" type="Button" parent="ConfirmationCenter/ConfirmationPanel/Margin/Content/Buttons"] -unique_name_in_owner = true -custom_minimum_size = Vector2(180, 64) -layout_mode = 2 -text = "cancel"