aboutsummaryrefslogtreecommitdiff
path: root/client/gui/menus/menu.gd
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-04 23:47:24 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-05 23:07:07 +0200
commit81deaf81c800900e30046cb927be1c9d91ae61b8 (patch)
tree20ce9898465e8d4c49eeff12a9ea55572517ea7b /client/gui/menus/menu.gd
parentfd80142282fcef628466a18e3ea62f0d1372d807 (diff)
downloadhurrycurry-81deaf81c800900e30046cb927be1c9d91ae61b8.tar
hurrycurry-81deaf81c800900e30046cb927be1c9d91ae61b8.tar.bz2
hurrycurry-81deaf81c800900e30046cb927be1c9d91ae61b8.tar.zst
reorganize client gui files
Diffstat (limited to 'client/gui/menus/menu.gd')
-rw-r--r--client/gui/menus/menu.gd151
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()