class_name SongRow extends PanelContainer ## One song in the music list: its number, soundtrack and title, and the character of ## each player who got a point for it. ## ## The pictures are on the right and the text takes the room they leave, wrapping only ## when it does not fit on one line. With many pictures they go on more lines, as even as ## possible and at most [constant MAX_PICTURES_PER_LINE] on each, so the text keeps most ## of the row. Every line ends at the row's right edge. The row is as tall as the taller ## of the text and the pictures. ## The most pictures on one line before they go on another. const MAX_PICTURES_PER_LINE: int = 4 ## The size of each picture. Characters are twice as wide as they are tall. const PICTURE_SIZE: Vector2 = Vector2(56, 28) var song_object: SongObject ## The row's place in the list, for the alternating background. var index: int = 0 var _hovered: bool = false @onready var song_list_label: Label = %SongListLabel ## The lines of pictures, top to bottom, each an HBoxContainer. @onready var song_list_players: VBoxContainer = %SongListPlayers func _ready() -> void: mouse_entered.connect(_set_hovered.bind(true)) mouse_exited.connect(_set_hovered.bind(false)) set_label() update_players() ## The pictures shown, line by line. func pictures() -> Array[TextureRect]: var shown: Array[TextureRect] = [] for line: Node in song_list_players.get_children(): shown.append_array(line.get_children()) return shown ## The number of pictures on a full line for [param pictures] pictures: as few lines as ## [constant MAX_PICTURES_PER_LINE] allows, with the pictures spread evenly over them, ## e.g. 3 and 2 for five pictures instead of 4 and 1. static func picture_columns(pictures: int) -> int: if pictures <= 0: return 1 var lines: int = ceili(float(pictures) / MAX_PICTURES_PER_LINE) return ceili(float(pictures) / lines) func set_label() -> void: if song_object != null: song_list_label.theme_type_variation = &"SongRowLabelPlaying" \ if song_object.is_playing else &"SongRowLabel" song_list_label.text = song_object.get_song_info() _update_style() func update_players() -> void: Settings.delete_children(song_list_players) var scorers: Array[PlayerObject] = [] if song_object != null: # Show players in the same order as the player list for player: PlayerObject in Settings.player_array: if song_object.players_given_point.has(player.id): scorers.append(player) var per_line: int = picture_columns(scorers.size()) var line: HBoxContainer = null for i: int in scorers.size(): if i % per_line == 0: line = HBoxContainer.new() line.theme_type_variation = &"SongRowPictureLine" line.alignment = BoxContainer.ALIGNMENT_END line.mouse_filter = Control.MOUSE_FILTER_IGNORE song_list_players.add_child(line) line.add_child(_make_picture(scorers[i])) song_list_players.visible = !scorers.is_empty() func _make_picture(player: PlayerObject) -> TextureRect: var picture: TextureRect = TextureRect.new() picture.texture = player.character picture.expand_mode = TextureRect.EXPAND_IGNORE_SIZE picture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED picture.custom_minimum_size = PICTURE_SIZE picture.tooltip_text = player.player_name # Clicks on a picture still click the row picture.mouse_filter = Control.MOUSE_FILTER_PASS return picture func _set_hovered(hovered: bool) -> void: _hovered = hovered _update_style() func _update_style() -> void: if _hovered: theme_type_variation = &"SongRowHover" elif song_object != null && song_object.is_playing: theme_type_variation = &"SongRowPlaying" else: theme_type_variation = &"SongRowOdd" if index % 2 != 0 else &"SongRow"