# MessageBox.gd extends Window class_name MessageBox signal accepted() signal rejected() enum ButtonRole { ACCEPT, REJECT, DESTRUCTIVE, ACTION } enum StandardButton { OK = 1, CANCEL = 2, YES = 4, NO = 8, ABORT = 16, RETRY = 32, IGNORE = 64, YES_ALL = 128, NO_ALL = 256, SAVE = 512, DISCARD = 1024 } var _main_panel: PanelContainer var _buttons: HBoxContainer var label: Label var _icon: TextureRect var _theme = preload("res://Resources/Theme/basic_theme.tres") static var _node: Node # 静态方法 static func normal(parent: Control, _title: String, text: String, buttons: int = StandardButton.OK) -> MessageBox: var msgbox = _create_message_box(parent, _title, text, buttons, "") msgbox.label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER return msgbox static func information(parent: Control, _title: String, text: String, buttons: int = StandardButton.OK) -> MessageBox: return _create_message_box(parent, _title, text, buttons, "information") static func warning(parent: Control, _title: String, text: String, buttons: int = StandardButton.OK) -> MessageBox: return _create_message_box(parent, _title, text, buttons, "warning") static func error(parent: Control, _title: String, text: String, buttons: int = StandardButton.OK) -> MessageBox: return _create_message_box(parent, _title, text, buttons, "error") static func question(parent: Control, _title: String, text: String, buttons: int = StandardButton.YES | StandardButton.NO) -> MessageBox: return _create_message_box(parent, _title, text, buttons, "question") static func _create_message_box(parent: Node, _title: String, text: String, buttons: int, icon_type: String) -> MessageBox: var msg_box = MessageBox.new() if parent == null: parent = _node.get_tree().get_root() parent.add_child(msg_box) msg_box.title = _title msg_box.setup(text, buttons, icon_type) msg_box.popup_centered() return msg_box func _ready(): size = Vector2(300, 150) exclusive = true #unresizable = true _main_panel = PanelContainer.new() #_main_panel.size = size #_main_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL #_main_panel.size_flags_vertical = Control.SIZE_EXPAND_FILL _main_panel.anchor_right = 1.0 _main_panel.anchor_bottom = 1.0 _main_panel.offset_right = 0 _main_panel.offset_bottom = 0 _main_panel.theme = _theme add_child(_main_panel) # 创建主容器 var main_vbox = VBoxContainer.new() #main_vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL #main_vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL main_vbox.anchor_right = 1.0 main_vbox.anchor_bottom = 1.0 main_vbox.offset_right = 0 main_vbox.offset_bottom = 0 _main_panel.add_child(main_vbox) # 创建内容容器 var content_hbox = HBoxContainer.new() content_hbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL content_hbox.size_flags_vertical = Control.SIZE_EXPAND_FILL #content_hbox.add_theme_constant_override("separation", 20) main_vbox.add_child(content_hbox) # 图标 _icon = TextureRect.new() _icon.size_flags_horizontal = Control.SIZE_FILL _icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER _icon.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL _icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED _icon.custom_minimum_size = Vector2(80, 64) content_hbox.add_child(_icon) # 文本标签 label = Label.new() label.size_flags_horizontal = Control.SIZE_EXPAND_FILL #label.size_flags_vertical = Control.SIZE_EXPAND_FILL #label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART content_hbox.add_child(label) # 按钮容器 _buttons = HBoxContainer.new() _buttons.size_flags_horizontal = Control.SIZE_EXPAND_FILL _buttons.size_flags_vertical = Control.SIZE_SHRINK_CENTER _buttons.alignment = BoxContainer.ALIGNMENT_CENTER _buttons.add_theme_constant_override("separation", 20) main_vbox.add_child(_buttons) close_requested.connect(_on_close_requested) size_changed.connect(func(): _main_panel.size = size) func setup(text: String, buttons: int, icon_type: String = ""): label.text = text _setup_icon(icon_type) _setup_buttons(buttons) func resize(new_size: Vector2, center_window:bool = true): size = new_size await get_tree().process_frame _main_panel.custom_minimum_size = new_size _main_panel.reset_size() if center_window: var viewport_size = get_tree().root.get_viewport().get_visible_rect().size position = (viewport_size - new_size) / 2 func _setup_icon(icon_type: String): var icon_texture: Texture2D match icon_type: "information": icon_texture = preload("res://Resources/UI/msgbox_infomation.png") # 需要提供图标 "warning": icon_texture = preload("res://Resources/UI/msgbox_warning.png") "error": icon_texture = preload("res://Resources/UI/msgbox_error.png") "question": icon_texture = preload("res://Resources/UI/msgbox_question.png") if icon_texture: _icon.texture = icon_texture _icon.show() else: _icon.hide() func _setup_buttons(buttons_mask: int): # 清空现有按钮 for child in _buttons.get_children(): child.queue_free() var button_definitions = [ [StandardButton.OK, "OK", ButtonRole.ACCEPT], [StandardButton.CANCEL, "Cancel", ButtonRole.REJECT], [StandardButton.YES, "Yes", ButtonRole.ACCEPT], [StandardButton.NO, "No", ButtonRole.REJECT], [StandardButton.ABORT, "Abort", ButtonRole.REJECT], [StandardButton.RETRY, "Retry", ButtonRole.ACTION], [StandardButton.IGNORE, "Ignore", ButtonRole.ACTION], [StandardButton.SAVE, "Save", ButtonRole.ACCEPT], [StandardButton.DISCARD, "Discard", ButtonRole.DESTRUCTIVE] ] for definition in button_definitions: var button_flag = definition[0] var button_text = definition[1] var button_role = definition[2] if buttons_mask & button_flag: var button = Button.new() button.text = button_text button.custom_minimum_size = Vector2(80.0, 30) button.theme = _theme button.pressed.connect(_on_button_pressed.bind(button_role)) _buttons.add_child(button) func _on_button_pressed(role: ButtonRole): match role: ButtonRole.ACCEPT: accepted.emit() ButtonRole.REJECT: rejected.emit() ButtonRole.DESTRUCTIVE: rejected.emit() hide() queue_free() func _on_close_requested(): rejected.emit() hide() queue_free() # 阻塞式调用(模拟) static func information_blocking(parent: Control, _title: String, text: String, buttons: int = StandardButton.OK) -> int: var result = -1 var msg_box = information(parent, _title, text, buttons) # 连接信号来设置结果 msg_box.accepted.connect(func(): result = StandardButton.OK) msg_box.rejected.connect(func(): result = StandardButton.CANCEL) # 等待对话框关闭 await msg_box.tree_exited return result