class_name BasePopup extends Control ## A window shown on top of the main window, such as Settings or About. ## ## Clicking outside [member panel] closes it. Popups that need to prepare or clean up ## override [method open] or [method close] and call [code]super()[/code]. ## ## The panel fades in while growing from [constant START_SCALE] of its size, and closing ## does the reverse; the popup is hidden once that has finished. See [Anim]. ## Emitted when the popup opens, also when it is opened again while closing. signal opening ## Emitted when the popup starts closing, before it is hidden, so the backdrop can fade ## out with it. signal closing ## How big the panel starts when it opens, and ends when it closes. const START_SCALE: float = 0.95 ## The visible part of the popup. Clicks outside it close the popup. @export var panel: Control ## True while the popup is fading out after [method close]. var is_closing: bool = false ## Shows the popup. func open() -> void: is_closing = false visible = true opening.emit() var open_tween: Tween = Anim.tween(panel, &"popup") panel.modulate.a = 1.0 panel.scale = Vector2.ONE if open_tween == null: return Anim.center_pivot(panel) panel.modulate.a = 0.0 panel.scale = Vector2.ONE * START_SCALE open_tween.set_parallel() open_tween.tween_property(panel, "modulate:a", 1.0, Anim.NORMAL) open_tween.tween_property(panel, "scale", Vector2.ONE, Anim.NORMAL) \ .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT) ## Hides the popup. func close() -> void: if !visible || is_closing: return is_closing = true closing.emit() var close_tween: Tween = Anim.tween(panel, &"popup") if close_tween == null: _hide() return Anim.center_pivot(panel) close_tween.set_parallel() close_tween.tween_property(panel, "modulate:a", 0.0, Anim.FAST) close_tween.tween_property(panel, "scale", Vector2.ONE * START_SCALE, Anim.FAST) close_tween.chain().tween_callback(_hide) ## Opens the popup if it is closed and closes it if it is open. func toggle() -> void: if visible && !is_closing: close() else: open() func _hide() -> void: is_closing = false visible = false panel.modulate.a = 1.0 panel.scale = Vector2.ONE func _input(event: InputEvent) -> void: if !visible || is_closing || !(event is InputEventMouseButton) || !event.pressed: return var click: InputEventMouseButton = panel.make_input_local(event) if !Rect2(Vector2.ZERO, panel.size).has_point(click.position): close() # The click only closes the popup; it must not also press what is behind it get_viewport().set_input_as_handled()