Files
Dawn-Godot/ui/component/ClosableMenu.gd
T
2026-06-14 10:19:31 -05:00

77 lines
1.7 KiB
GDScript

class_name ClosableMenu extends Control
signal opened
signal closed
signal focusGained
signal focusLost
@export var canClose:bool = true
@export var isOpen:bool = false:
set(v):
isOpen = v
visible = v
get():
return isOpen
var _savedFocusNode:Control = null
func _enter_tree() -> void:
visible = isOpen
func _exit_tree() -> void:
visible = false
func _ready() -> void:
visible = isOpen
if canClose:
set_process_unhandled_input(false)
func open() -> void:
visible = true
if canClose:
UI.FOCUS_STACK.push(self)
isOpen = true
opened.emit()
func close() -> void:
if canClose:
UI.FOCUS_STACK.pop()
isOpen = false
closed.emit()
func toggle() -> void:
if isOpen:
close()
else:
open()
func _onFocusGained() -> void:
set_process_unhandled_input(true)
get_viewport().gui_focus_changed.connect(_onViewportFocusChanged)
if _savedFocusNode != null and is_instance_valid(_savedFocusNode):
_savedFocusNode.grab_focus()
else:
_grabInitialFocus()
var currentFocus:Control = get_viewport().gui_get_focus_owner()
if currentFocus != null and is_ancestor_of(currentFocus):
_savedFocusNode = currentFocus
focusGained.emit()
func _onFocusLost() -> void:
_savedFocusNode = get_viewport().gui_get_focus_owner()
if get_viewport().gui_focus_changed.is_connected(_onViewportFocusChanged):
get_viewport().gui_focus_changed.disconnect(_onViewportFocusChanged)
set_process_unhandled_input(false)
focusLost.emit()
func _onViewportFocusChanged(control:Control) -> void:
if control == null or is_ancestor_of(control):
return
if _savedFocusNode != null and is_instance_valid(_savedFocusNode):
_savedFocusNode.grab_focus()
else:
_grabInitialFocus()
func _grabInitialFocus() -> void:
pass