straywild/ui/message_bottle_reader.gd

119 lines
3.2 KiB
GDScript

class_name MessageBottleReader
extends Control
signal closed
const MAX_PARCHMENT_SIZE := Vector2(640.0, 480.0)
const FALLBACK_PARCHMENT_ASPECT: float = 4.0 / 3.0
const VIEWPORT_MARGIN := Vector2(32.0, 32.0)
@export var parchment_texture: Texture2D:
set(value):
parchment_texture = value
_apply_parchment_texture()
@onready var _parchment_surface: Control = %ParchmentSurface
@onready var _fallback_panel: Control = %FallbackPanel
@onready var _parchment_art: TextureRect = %ParchmentArt
@onready var _message_label: Label = %MessageLabel
@onready var _close_button: Button = %CloseButton
var _previous_focus: WeakRef
func _ready() -> void:
_close_button.pressed.connect(dismiss)
_close_button.focus_neighbor_left = _close_button.get_path_to(_close_button)
_close_button.focus_neighbor_right = _close_button.get_path_to(_close_button)
_close_button.focus_neighbor_top = _close_button.get_path_to(_close_button)
_close_button.focus_neighbor_bottom = _close_button.get_path_to(_close_button)
_apply_parchment_texture()
_resize_parchment()
hide()
func present(message_text: String) -> void:
if not is_node_ready():
call_deferred("present", message_text)
return
if not is_open():
var focus_owner: Control = get_viewport().gui_get_focus_owner()
_previous_focus = weakref(focus_owner) if focus_owner != null else null
_message_label.text = message_text
show()
_close_button.call_deferred("grab_focus")
func dismiss() -> void:
if not is_open():
return
hide()
_restore_previous_focus.call_deferred()
closed.emit()
func is_open() -> bool:
return visible
func consume_escape() -> bool:
if not is_open():
return false
dismiss()
return true
func _unhandled_input(event: InputEvent) -> void:
if not is_open() or not event.is_action_pressed(&"ui_cancel"):
return
if consume_escape():
get_viewport().set_input_as_handled()
func _notification(what: int) -> void:
if what == NOTIFICATION_RESIZED and is_node_ready():
_resize_parchment()
func _resize_parchment() -> void:
var available_size: Vector2 = (
get_viewport_rect().size - VIEWPORT_MARGIN
).max(Vector2.ONE)
var target_size: Vector2 = MAX_PARCHMENT_SIZE.min(available_size)
var aspect: float = FALLBACK_PARCHMENT_ASPECT
if parchment_texture != null:
var texture_size: Vector2 = parchment_texture.get_size()
if texture_size.x > 0.0 and texture_size.y > 0.0:
aspect = texture_size.x / texture_size.y
if target_size.x / target_size.y > aspect:
target_size.x = target_size.y * aspect
else:
target_size.y = target_size.x / aspect
_parchment_surface.custom_minimum_size = target_size.floor()
func _apply_parchment_texture() -> void:
if _parchment_art == null:
return
_parchment_art.texture = parchment_texture
_parchment_art.visible = parchment_texture != null
if _fallback_panel != null:
_fallback_panel.visible = parchment_texture == null
_resize_parchment()
func _restore_previous_focus() -> void:
if _previous_focus == null:
get_viewport().gui_release_focus()
return
var previous: Control = _previous_focus.get_ref() as Control
_previous_focus = null
if (
is_instance_valid(previous)
and previous.is_inside_tree()
and previous.is_visible_in_tree()
and previous.focus_mode != Control.FOCUS_NONE
):
previous.grab_focus()
else:
get_viewport().gui_release_focus()