class_name MainMenuController extends RefCounted const UiMotionScript := preload("res://scripts/ui/common/ui_motion.gd") const ACTION_SHOP := "shop" const ACTION_WAREHOUSE := "warehouse" const ACTION_FRIEND := "friend" const HOME_POSITION := Vector2(24.0, 34.0) const HOME_SIZE := Vector2(155.0, 145.0) const WAVE_CENTER := Vector2(77.5, 72.5) const WAVE_RADIUS := 155.0 const HIDDEN_POSITION := Vector2(1000.0, 1000.0) var _owner: Control var _menu: Control var _home_art: TextureRect var _home_texture: Texture2D var _item_textures: Dictionary = {} var _style_menu_title: Callable var _hide_selection: Callable var _action_pressed: Callable var _dismiss_button: Button var _home_hit: Button var _buttons: Array[TextureButton] = [] var _tween: Tween var _open := false func setup(owner: Control, menu: Control, home_art: TextureRect, home_texture: Texture2D, item_textures: Dictionary, style_menu_title: Callable, hide_selection: Callable, action_pressed: Callable) -> void: _owner = owner _menu = menu _home_art = home_art _home_texture = home_texture _item_textures = item_textures _style_menu_title = style_menu_title _hide_selection = hide_selection _action_pressed = action_pressed _setup() func toggle() -> void: if _open: hide(true) return if _hide_selection.is_valid(): _hide_selection.call() show() func hide(animated := false) -> void: if _menu == null: return if not _open and not animated: _finish_hide() return if _tween != null: _tween.kill() _open = false if animated: for button in _buttons: button.disabled = true _tween = _owner.create_tween() _tween.tween_method(Callable(self, "_apply_wave_angle"), 275.0, 135.0, 0.35) _tween.tween_callback(_finish_hide) return _finish_hide() func is_open() -> bool: return _open func handle_direct_hit(screen_position: Vector2) -> bool: if _menu == null: return false if _control_contains(_home_hit, screen_position): toggle() return true if not _open: return false for button in _buttons: if button == null or not button.visible or button.disabled: continue if _control_contains(button, screen_position): _on_item_pressed(str(button.get_meta("action", ""))) return true hide(true) return true func _setup() -> void: if _owner == null or _menu == null: return if _home_art != null: _home_art.texture = _home_texture _home_art.size = HOME_SIZE _home_art.pivot_offset = HOME_SIZE * 0.5 _home_art.mouse_filter = Control.MOUSE_FILTER_IGNORE _dismiss_button = Button.new() _dismiss_button.name = "MainMenuDismissHit" _dismiss_button.set_anchors_preset(Control.PRESET_FULL_RECT) _dismiss_button.focus_mode = Control.FOCUS_NONE _dismiss_button.text = "" _dismiss_button.visible = false UiMotionScript.apply_empty_button_style(_dismiss_button) _dismiss_button.pressed.connect(func() -> void: hide(true)) _owner.add_child(_dismiss_button) _owner.move_child(_dismiss_button, _owner.get_child_count() - 1) _owner.move_child(_menu, _owner.get_child_count() - 1) _create_item(ACTION_SHOP, _item_textures.get(ACTION_SHOP), 0) _create_item(ACTION_WAREHOUSE, _item_textures.get(ACTION_WAREHOUSE), 1) _create_item(ACTION_FRIEND, _item_textures.get(ACTION_FRIEND), 3) _finish_hide() _home_hit = Button.new() _home_hit.name = "HomeMenuHit" _home_hit.position = HOME_POSITION _home_hit.size = HOME_SIZE _home_hit.focus_mode = Control.FOCUS_NONE _home_hit.text = "" UiMotionScript.apply_empty_button_style(_home_hit) _home_hit.pressed.connect(toggle) if _home_art != null: _home_hit.button_down.connect(func() -> void: UiMotionScript.play_press_scale(_owner, _home_art)) _home_hit.button_up.connect(func() -> void: UiMotionScript.play_release_scale(_owner, _home_art)) _menu.add_child(_home_hit) func _create_item(action: String, texture: Texture2D, wave_index: int) -> void: if texture == null: return var button := TextureButton.new() button.name = "MainMenu%s" % action.capitalize() button.texture_normal = texture button.size = texture.get_size() button.pivot_offset = button.size * 0.5 button.focus_mode = Control.FOCUS_NONE button.visible = false button.disabled = true button.position = HIDDEN_POSITION button.set_meta("wave_index", wave_index) button.set_meta("action", action) button.pressed.connect(_on_item_pressed.bind(action)) button.button_down.connect(func() -> void: UiMotionScript.play_press_scale(_owner, button)) button.button_up.connect(func() -> void: UiMotionScript.play_release_scale(_owner, button)) _add_item_title(button, action) _menu.add_child(button) _buttons.append(button) func _add_item_title(button: TextureButton, action: String) -> void: var title_text := _item_title(action) if title_text.is_empty(): return var title := Label.new() title.name = "Title" title.text = title_text var label_width := 118.0 if action == ACTION_WAREHOUSE else 98.0 title.position = Vector2((button.size.x - label_width) * 0.5, button.size.y - 27.0) title.size = Vector2(label_width, 30.0) title.mouse_filter = Control.MOUSE_FILTER_IGNORE title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.vertical_alignment = VERTICAL_ALIGNMENT_CENTER title.clip_text = false if _style_menu_title.is_valid(): _style_menu_title.call(title, 18 if action == ACTION_WAREHOUSE else 20) button.add_child(title) func _item_title(action: String) -> String: match action: ACTION_SHOP: return "Store" ACTION_WAREHOUSE: return "Storage" ACTION_FRIEND: return "Friends" _: return "" func show() -> void: if _menu == null: return if _tween != null: _tween.kill() _open = true if _dismiss_button != null: _dismiss_button.visible = true for button in _buttons: button.visible = true button.disabled = false button.scale = Vector2.ONE button.modulate = Color.WHITE _apply_wave_angle(180.0) _tween = _owner.create_tween() _tween.tween_method(Callable(self, "_apply_wave_angle"), 180.0, 280.0, 0.25) func _finish_hide() -> void: if _dismiss_button != null: _dismiss_button.visible = false for button in _buttons: button.visible = false button.disabled = true button.position = HIDDEN_POSITION button.scale = Vector2.ONE button.modulate = Color.WHITE func _apply_wave_angle(angle: float) -> void: for button in _buttons: var wave_index := int(button.get_meta("wave_index", 0)) var radians := deg_to_rad(angle - 36.0 * float(wave_index)) button.position = Vector2( WAVE_RADIUS * cos(radians) + WAVE_CENTER.x, WAVE_RADIUS * sin(radians) + WAVE_CENTER.y ) func _on_item_pressed(action: String) -> void: if action.is_empty(): return hide(true) if _action_pressed.is_valid(): _action_pressed.call(action) func _control_contains(control: Control, screen_position: Vector2) -> bool: return control != null and control.is_visible_in_tree() and control.get_global_rect().has_point(screen_position)