diff options
Diffstat (limited to 'client/gui/menus/menu.gd')
-rw-r--r-- | client/gui/menus/menu.gd | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/client/gui/menus/menu.gd b/client/gui/menus/menu.gd new file mode 100644 index 00000000..0f6e0624 --- /dev/null +++ b/client/gui/menus/menu.gd @@ -0,0 +1,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) + await _menu_cover(false) + covered = 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() |