aboutsummaryrefslogtreecommitdiff
path: root/client/gui/menus/menu.gd
blob: e1dc8929dd9d0b7b992fede8d9b4f81df50b9f50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# Hurry Curry! - a game about cooking
# Copyright (C) 2025 Hurry Curry! contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
class_name Menu
extends Control


#enum Anim { NONE, FADE }
#@export var animation: Anim = Anim.NONE
@export var support_anim := true
@export var auto_anim := true

var data

signal submenu_close()

const transition_scene = preload("res://gui/menus/transition/scene_transition.tscn")
var transition: SceneTransition
var parent_menu: Menu = null
var previous_path = null # : String
var open_since = 0

func _ready():
	open_since = Time.get_ticks_msec()
	Global.focused_menu = self
	focus_first(self)
	connect_button_sounds(self)
	disable_context_menus(self)
	update_parent_menu(self.get_parent())
	if support_anim: anim_setup()
	if auto_anim: _menu_open()
	get_tree().get_root().go_back_requested.connect(exit_maybe)

func anim_setup():
	transition = transition_scene.instantiate()
	add_child(transition)
func _menu_open():
	if transition != null: await transition.fade_in()
func _menu_exit():
	if transition != null: await transition.fade_out()
func _menu_cover(_state: bool):
	pass

var popup: Menu = null
var covered := false
func submenu(path: String, data_ = null):
	var prev_focus = Global.focused_node
	if popup != null: return
	_disable_recursive(self, true)
	covered = true
	await _menu_cover(true)
	popup = load(path).instantiate()
	popup.data = data_
	add_child(popup)
	# print("Submenu opened ", path)
	await submenu_close
	# print("Submenu closed ", path)
	covered = false
	await _menu_cover(false)
	Global.focused_menu = self
	_disable_recursive(self, false)
	if prev_focus != null: prev_focus.grab_focus()

func _disable_recursive(node: Node, state: bool):
	if node is BaseButton: 
		if state and node.disabled: node.add_to_group("was_disabled")
		else: node.remove_from_group("was_disabled")
		node.disabled = state or node.is_in_group("was_disabled")
	for c in node.get_children(): _disable_recursive(c, state)

func exit():
	await self._menu_exit()
	if previous_path != null:
		replace_menu(previous_path)
	else:
		get_parent().submenu_close.emit()
		queue_free()

func quit():
	await exit()
	get_parent().quit()

func replace_menu(path: String, data_ = null, prev_path = null): # prev_path: String?
	print("Replace menu: ", path)
	if popup != null: await popup.exit()
	_disable_recursive(self, true)
	await _menu_exit()
	var new_popup: Menu = load(path).instantiate()
	new_popup.data = data_
	if prev_path != null: new_popup.previous_path = prev_path
	get_parent().add_child(new_popup)
	if parent_menu != null: parent_menu.popup = new_popup
	queue_free()

var focus_auto_changed := false
func focus_first(node: Node) -> bool:
	focus_auto_changed = true
	if node.is_in_group("no_auto_focus"):
		return false
	if node is Button or node.is_in_group("autoselect"):
		node.grab_focus()
		# print("Node %s (%s) was selected for focus" % [node.name, node])
		return true
	for c in node.get_children():
		if focus_first(c):
			return true
	return false

func connect_button_sounds(node: Node):
	if node is Button or node is TextureButton:
		if not node.is_in_group("no_click_sound"):
			node.pressed.connect(Sound.play_click)
	if (node is Button and not node.disabled) or (node is LineEdit and node.editable) or node is Slider:
		if not node.is_in_group("no_click_sound"):
			node.mouse_entered.connect(Sound.play_hover)
	for c in node.get_children():
		connect_button_sounds(c)

func disable_context_menus(node: Node):
	if node is LineEdit:
		node.context_menu_enabled = false
	for c in node.get_children():
		disable_context_menus(c)

func update_parent_menu(node: Node):
	if node is Menu: parent_menu = node
	elif node.get_parent() != null: update_parent_menu(node.get_parent())

func _input(_event):
	if Input.is_action_just_pressed("menu"):
		exit_maybe()

func exit_maybe() -> void:
	# Exit menu if all conditions are met
	if popup != null: return
	var time := Time.get_ticks_msec()
	if time - open_since < 100: return
	Sound.play_click()
	exit()