Files
whale-town-front-v2/_Core/managers/UiEscapeManager.gd
2026-07-21 23:07:31 +08:00

59 lines
2.1 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
# 统一处理 UI 的 Esc 退出。可关闭界面加入 whaletown_escape_dismissible 分组,
# 并实现 is_escape_dismissible / get_escape_priority / request_escape_close。
const ESCAPE_DISMISSIBLE_GROUP: StringName = &"whaletown_escape_dismissible"
func _ready() -> void:
# 公告、排行榜等界面会暂停场景树Esc 仍必须有效。
process_mode = Node.PROCESS_MODE_ALWAYS
func _input(event: InputEvent) -> void:
if not (event is InputEventKey):
return
var key_event: InputEventKey = event as InputEventKey
if not key_event.pressed or key_event.echo or key_event.keycode != KEY_ESCAPE:
return
if _hide_open_popup_menu() or _close_topmost_dismissible() or _release_control_focus():
get_viewport().set_input_as_handled()
func _hide_open_popup_menu() -> bool:
var popup_nodes: Array[Node] = get_tree().root.find_children("*", "PopupMenu", true, false)
for popup_node: Node in popup_nodes:
var popup: PopupMenu = popup_node as PopupMenu
if popup != null and popup.visible:
popup.hide()
return true
return false
func _close_topmost_dismissible() -> bool:
var target: Node = null
var target_priority: int = -2147483648
var dismissibles: Array[Node] = get_tree().get_nodes_in_group(ESCAPE_DISMISSIBLE_GROUP)
for dismissible: Node in dismissibles:
if not is_instance_valid(dismissible):
continue
if not dismissible.has_method("is_escape_dismissible") or not dismissible.has_method("request_escape_close"):
continue
var is_dismissible_variant: Variant = dismissible.call("is_escape_dismissible")
if not bool(is_dismissible_variant):
continue
var priority: int = 0
if dismissible.has_method("get_escape_priority"):
var priority_variant: Variant = dismissible.call("get_escape_priority")
priority = int(priority_variant)
if target == null or priority > target_priority:
target = dismissible
target_priority = priority
if target == null:
return false
target.call("request_escape_close")
return true
func _release_control_focus() -> bool:
var focus_owner: Control = get_viewport().gui_get_focus_owner()
if focus_owner == null:
return false
focus_owner.release_focus()
return true