class_name NowPlaying extends HBoxContainer ## The soundtrack and song that are playing, in large text at the top of the quiz. They ## fade in when they change. Once the answer is shown, the soundtrack's cover shows on ## their left, when it has one, and the cover and titles are centered together. Both are ## centered up and down too, so the titles only move sideways when a cover comes. Each ## title has at most two lines. ## The covers on disk. No cover is shown without it. var covers: CoverCache: set(value): covers = value if covers != null: covers.cover_times_changed.connect(_load_cover) _load_cover() # The soundtrack whose cover is shown or on its way, and the cover time asked for var _cover_uuid: String = "" var _cover_time: int = 0 @onready var soundtrack_label: Label = %SoundtrackLabel @onready var song_label: Label = %SongLabel @onready var cover_frame: Panel = %CoverFrame @onready var cover_picture: TextureRect = %CoverPicture @onready var titles: VBoxContainer = %Titles func _ready() -> void: resized.connect(_fit_titles) _fit_titles() ## Shows [param soundtrack_title] and [param song_title]. The playlist hides them as ## question marks until the answer is shown, and only then gives the ## [param soundtrack_uuid] whose cover is shown. func show_song(soundtrack_title: String, song_title: String, soundtrack_uuid: String = "") -> void: var changed: bool = soundtrack_label.text != soundtrack_title \ || song_label.text != song_title soundtrack_label.text = soundtrack_title song_label.text = song_title _fit_titles() if soundtrack_uuid != _cover_uuid: _cover_uuid = soundtrack_uuid _cover_time = 0 _show_cover(null) _load_cover() # A new song, or the answer being shown, fades in if changed: Anim.fade_in(self, Anim.SLOW) ## Whether a cover is shown. func has_cover() -> bool: return cover_frame.visible # Asks for the cover, again when its time changed, e.g. once the soundtrack list loaded func _load_cover() -> void: if covers == null || _cover_uuid.is_empty() || !is_node_ready(): return var time: int = covers.cover_time(_cover_uuid) if time == _cover_time: return _cover_time = time if time <= 0: _show_cover(null) return covers.fetch_cover(_cover_uuid, time, _show_cover_of.bind(_cover_uuid, time)) # Covers arrive later; one for a song no longer shown is left out func _show_cover_of(cover: Image, uuid: String, time: int) -> void: if uuid == _cover_uuid && time == _cover_time: _show_cover(cover) func _show_cover(cover: Image) -> void: var was_shown: bool = cover_frame.visible cover_picture.texture = ImageTexture.create_from_image(cover) if cover != null else null cover_frame.visible = cover != null _fit_titles() if cover_frame.visible && !was_shown: Anim.fade_in(cover_frame, Anim.SLOW) # The titles take the width of the longer one, so they stay next to the cover, but no # more than there is room for; longer titles wrap. Beside a cover they line up with it # on the left. func _fit_titles() -> void: var room: float = size.x if cover_frame.visible: room -= cover_frame.custom_minimum_size.x + get_theme_constant(&"separation") var widest: float = maxf(_text_width(soundtrack_label), _text_width(song_label)) titles.custom_minimum_size.x = clampf(ceilf(widest), 1.0, maxf(room, 1.0)) var alignment: HorizontalAlignment = HORIZONTAL_ALIGNMENT_LEFT if cover_frame.visible \ else HORIZONTAL_ALIGNMENT_CENTER soundtrack_label.horizontal_alignment = alignment song_label.horizontal_alignment = alignment static func _text_width(label: Label) -> float: var font: Font = label.get_theme_font(&"font") return font.get_string_size(label.text, HORIZONTAL_ALIGNMENT_LEFT, -1, label.get_theme_font_size(&"font_size")).x