Lay out the song list's pictures and text to fit any number of players

The players' pictures sit on the right in even lines of at most four, each
ending at the row's right edge, so five pictures are 3 + 2 and seven 4 + 3.
The text takes the room they leave and wraps only when it does not fit, and
the row is as tall as the taller of the two, instead of a width fixed by
the number of pictures.

Rows are rounded and alternate like the other lists, are highlighted under
the mouse, and the playing song has an orange edge. Clicking a picture
clicks its song.
This commit is contained in:
Sansan committed 2026-10-09 17:25:38 +02:00
1 parent 84e137e16a
commit 78e1facaf0
10 files changed
+753 -361

No files matched your search

+224 -296
View File
@@ -1001,66 +1001,57 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
1068.0,
384.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
1000.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
384.0,
78.0,
394.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicPlayer": {
"rect": [
@@ -4603,111 +4594,93 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1": {
"rect": [
64.0,
422.0,
1088.0,
28.0
70.0,
430.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer": {
"rect": [
64.0,
422.0,
1088.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/Panel": {
"rect": [
1068.0,
422.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListLabel": {
"rect": [
64.0,
422.0,
1000.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
422.0,
78.0,
434.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
1068.0,
384.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
1000.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
384.0,
78.0,
394.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicPlayer": {
"rect": [
@@ -11454,66 +11427,57 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
1068.0,
384.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
1000.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
384.0,
78.0,
394.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicPlayer": {
"rect": [
@@ -15398,127 +15362,118 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1": {
"rect": [
64.0,
422.0,
1088.0,
28.0
70.0,
430.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer": {
"rect": [
64.0,
422.0,
1088.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/Panel": {
"rect": [
1068.0,
422.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListLabel": {
"rect": [
64.0,
422.0,
1000.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
422.0,
78.0,
434.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
968.0,
384.0,
75.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
900.0,
78.0,
394.0,
932.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1047.0,
384.0,
105.0,
25.0
1022.0,
394.0,
116.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0": {
"rect": [
1047.0,
384.0,
51.0,
25.0
1022.0,
394.0,
116.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#1": {
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0/#0": {
"rect": [
1102.0,
384.0,
50.0,
25.0
1022.0,
394.0,
56.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0/#1": {
"rect": [
1082.0,
394.0,
56.0,
28.0
],
"visible": true
},
@@ -23530,66 +23485,57 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
1068.0,
384.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
1000.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
384.0,
78.0,
394.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicPlayer": {
"rect": [
@@ -36583,127 +36529,118 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1": {
"rect": [
64.0,
422.0,
1088.0,
28.0
70.0,
430.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer": {
"rect": [
64.0,
422.0,
1088.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/Panel": {
"rect": [
1068.0,
422.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListLabel": {
"rect": [
64.0,
422.0,
1000.0,
78.0,
434.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/#1/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
422.0,
78.0,
434.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
968.0,
384.0,
75.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
900.0,
78.0,
394.0,
932.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1047.0,
384.0,
105.0,
25.0
1022.0,
394.0,
116.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0": {
"rect": [
1047.0,
384.0,
51.0,
25.0
1022.0,
394.0,
116.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#1": {
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0/#0": {
"rect": [
1102.0,
384.0,
50.0,
25.0
1022.0,
394.0,
56.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers/#0/#1": {
"rect": [
1082.0,
394.0,
56.0,
28.0
],
"visible": true
},
@@ -41251,66 +41188,57 @@
},
"Quiz/MusicListPanel/ScrollContainer": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList": {
"rect": [
64.0,
384.0,
1088.0,
512.0
70.0,
390.0,
1076.0,
500.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow": {
"rect": [
64.0,
384.0,
1088.0,
28.0
70.0,
390.0,
1076.0,
36.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer": {
"rect": [
64.0,
384.0,
1088.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/Panel": {
"rect": [
1068.0,
384.0,
80.0,
0.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListLabel": {
"rect": [
64.0,
384.0,
1000.0,
78.0,
394.0,
1060.0,
28.0
],
"visible": true
},
"Quiz/MusicListPanel/ScrollContainer/MusicList/SongRow/HBoxContainer/SongListPlayers": {
"rect": [
1152.0,
384.0,
78.0,
394.0,
0.0,
0.0
],
"visible": true
"visible": false
},
"Quiz/MusicPlayer": {
"rect": [
+365
View File
@@ -0,0 +1,365 @@
extends GdUnitTestSuite
## How a song in the music list is laid out: the players' pictures on the right in even
## lines of at most four, each ending at the row's right edge, the text in the room they leave, wrapping only when it does
## not fit, and the row as tall as the taller of the two. Checked for every number of
## players, with short, debug mode and very long song texts.
const SHORT: Array[String] = ["Chrono Trigger", "Corridors of Time"]
const LONG: Array[String] = [
"Final Fantasy Dissidia 012 Duodecim (Sista Fantasin Meningsskiljaktigheter 012 Tolv)",
"'Crystal Cave -arrange-' from FINAL FANTASY III",
]
## The row's padding, from the SongRow styles in the theme.
const PADDING: float = 8.0
var _snapshot: AutoloadSnapshot
var _runner: GdUnitSceneRunner
var _panel: MusicListPanel
# The panel's width in the quiz, which songs must never make wider
var _panel_width: float
func before_test() -> void:
_snapshot = AutoloadSnapshot.take([Settings, Playlist])
Settings.is_debug = false
Playlist.reset_playlist()
Settings.player_array.clear()
for i: int in Settings.MAX_NUMBER_OF_PLAYERS:
Settings.player_array.append(PlayerObject.new("Player %d" % (i + 1)))
_runner = scene_runner("res://quiz/MusicListPanel.tscn")
_panel = _runner.scene()
_panel_width = _panel.size.x
func after_test() -> void:
await await_idle_frame()
_snapshot.restore()
# Adds a played and answered song with points for the first [param players] players
func _add_song(title: Array[String], players: int) -> SongObject:
var song: SongObject = SongObject.new()
song.song_number = Playlist.song_object_array.size()
song.soundtrack_title = title[0]
song.song_title = title[1]
song.has_played = true
song.is_answered = true
for i: int in players:
song.add_point(Settings.player_array[i].id)
Playlist.add_to_playlist(song)
return song
func _show() -> void:
_panel.refresh()
await _runner.simulate_frames(3)
func _rows() -> Array[SongRow]:
var rows: Array[SongRow] = []
rows.assign(_panel.get_node("%MusicList").get_children())
return rows
func _pictures(row: SongRow) -> Array[TextureRect]:
return row.pictures()
# How wide the row's text would be on one line
func _text_width(row: SongRow) -> float:
var label: Label = row.song_list_label
return label.get_theme_font(&"font").get_string_size(label.text, HORIZONTAL_ALIGNMENT_LEFT,
-1, label.get_theme_font_size(&"font_size")).x
func _one_line_height() -> float:
_add_song(SHORT, 0)
await _show()
var height: float = _rows()[0].size.y
Playlist.reset_playlist()
return height
# Every number of players with every kind of text, in normal and debug mode
func _each_layout(check: Callable) -> void:
for debug: bool in [false, true]:
Settings.is_debug = debug
for title: Array[String] in [SHORT, LONG]:
Playlist.reset_playlist()
for players: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
_add_song(title, players)
await _show()
assert_float(_panel.size.x).override_failure_message(
"The songs made the list wider than its place in the quiz") \
.is_equal(_panel_width)
for row: SongRow in _rows():
check.call(row, "%d players, %s text%s" % [_pictures(row).size(),
"long" if title == LONG else "short", " (debug)" if debug else ""])
# Columns
func test_pictures_are_spread_evenly_over_as_few_lines_as_possible() -> void:
var columns: Array[int] = []
for pictures: int in range(0, 9):
columns.append(SongRow.picture_columns(pictures))
# 5 pictures are 3 + 2, not 4 + 1; 7 are 4 + 3
assert_array(columns).contains_exactly([1, 1, 2, 3, 4, 3, 3, 4, 4])
# Placement
func test_pictures_are_at_the_right_end_of_the_row() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
if _pictures(row).is_empty():
assert_bool(row.song_list_players.visible).override_failure_message(layout).is_false()
return
var pictures: Rect2 = row.song_list_players.get_global_rect()
assert_float(pictures.end.x).override_failure_message(layout) \
.is_equal_approx(row.get_global_rect().end.x - PADDING, 1.0))
func test_every_line_of_pictures_ends_at_the_right_edge() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
var right_edge: float = row.get_global_rect().end.x - PADDING
for line: HBoxContainer in row.song_list_players.get_children():
var last: TextureRect = line.get_child(line.get_child_count() - 1)
assert_float(last.get_global_rect().end.x).override_failure_message(layout) \
.is_equal_approx(right_edge, 1.0))
func test_text_and_pictures_never_overlap_and_stay_inside_the_row() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
var row_rect: Rect2 = row.get_global_rect().grow(0.5)
var text: Rect2 = row.song_list_label.get_global_rect()
assert_bool(row_rect.encloses(text)).override_failure_message(
"Text outside the row: " + layout).is_true()
for picture: TextureRect in _pictures(row):
var rect: Rect2 = picture.get_global_rect()
assert_bool(row_rect.encloses(rect)).override_failure_message(
"Picture outside the row: " + layout).is_true()
assert_float(rect.position.x).override_failure_message(
"Picture over the text: " + layout).is_greater_equal(text.end.x))
func test_text_gets_all_the_room_the_pictures_leave() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
var text: Rect2 = row.song_list_label.get_global_rect()
assert_float(text.position.x).override_failure_message(layout) \
.is_equal_approx(row.get_global_rect().position.x + PADDING, 1.0)
var right_end: float = row.get_global_rect().end.x - PADDING
if row.song_list_players.visible:
right_end = row.song_list_players.get_global_rect().position.x \
- row.get_node("HBoxContainer").get_theme_constant(&"separation")
assert_float(text.end.x).override_failure_message(layout) \
.is_equal_approx(right_end, 1.0))
func test_text_wraps_only_when_it_does_not_fit_on_one_line() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
var lines: int = row.song_list_label.get_line_count()
var room: float = row.song_list_label.size.x
if _text_width(row) <= room - 1:
assert_int(lines).override_failure_message("Wrapped though it fits: " + layout) \
.is_equal(1)
elif _text_width(row) > room + 1:
assert_int(lines).override_failure_message("Not wrapped: " + layout) \
.is_greater(1))
func test_every_layout_holds_in_a_narrower_list() -> void:
_panel.size.x = 640
_panel_width = 640
await _runner.simulate_frames(1)
await _each_layout(func(row: SongRow, layout: String) -> void:
var text: Rect2 = row.song_list_label.get_global_rect()
assert_bool(row.get_global_rect().grow(0.5).encloses(text)).override_failure_message(
"Text outside the row: " + layout).is_true()
if row.song_list_players.visible:
assert_float(row.song_list_players.get_global_rect().position.x) \
.override_failure_message("Pictures over the text: " + layout) \
.is_greater_equal(text.end.x))
func test_short_text_is_one_line_even_with_every_player() -> void:
_add_song(SHORT, Settings.MAX_NUMBER_OF_PLAYERS)
await _show()
assert_int(_rows()[0].song_list_label.get_line_count()).is_equal(1)
func test_long_text_wraps_and_keeps_every_word() -> void:
_add_song(LONG, 2)
await _show()
var label: Label = _rows()[0].song_list_label
assert_int(label.get_line_count()).is_greater(1)
assert_str(label.text).ends_with("FINAL FANTASY III")
assert_int(label.get_visible_line_count()).is_equal(label.get_line_count())
# Height
func test_row_is_one_line_high_with_up_to_four_pictures() -> void:
var one_line: float = await _one_line_height()
for players: int in range(0, SongRow.MAX_PICTURES_PER_LINE + 1):
_add_song(SHORT, players)
await _show()
for row: SongRow in _rows():
assert_float(row.size.y).override_failure_message(
"%d pictures" % _pictures(row).size()).is_equal_approx(one_line, 0.5)
func test_five_pictures_go_on_two_lines_of_three_and_two() -> void:
_add_song(SHORT, 5)
await _show()
assert_array(_lines_of_pictures(_rows()[0])).contains_exactly([3, 2])
func test_seven_pictures_go_on_two_lines_of_four_and_three() -> void:
_add_song(SHORT, 7)
await _show()
assert_array(_lines_of_pictures(_rows()[0])).contains_exactly([4, 3])
# How many pictures are on each line, top to bottom
func _lines_of_pictures(row: SongRow) -> Array[int]:
var by_top: Dictionary[float, int] = {}
for picture: TextureRect in _pictures(row):
var top: float = roundf(picture.global_position.y)
by_top[top] = by_top.get(top, 0) + 1
var tops: Array[float] = []
tops.assign(by_top.keys())
tops.sort()
var lines: Array[int] = []
for top: float in tops:
lines.append(by_top[top])
return lines
func test_row_grows_to_fit_two_lines_of_pictures_and_centres_the_text() -> void:
var one_line: float = await _one_line_height()
_add_song(SHORT, 5)
await _show()
var row: SongRow = _rows()[0]
var pictures: Rect2 = row.song_list_players.get_global_rect()
assert_float(row.size.y).is_greater(one_line)
assert_float(pictures.size.y).is_equal_approx(
SongRow.PICTURE_SIZE.y * 2 + row.song_list_players.get_theme_constant(
&"separation"), 0.5)
assert_bool(row.get_global_rect().encloses(pictures)).is_true()
# The single line of text is in the middle, beside the pictures
assert_int(row.song_list_label.vertical_alignment).is_equal(VERTICAL_ALIGNMENT_CENTER)
assert_float(row.song_list_label.get_global_rect().get_center().y) \
.is_equal_approx(pictures.get_center().y, 1.0)
func test_pictures_are_centred_beside_text_on_many_lines() -> void:
_add_song(LONG, 1)
await _show()
var row: SongRow = _rows()[0]
var text: Rect2 = row.song_list_label.get_global_rect()
var pictures: Rect2 = row.song_list_players.get_global_rect()
assert_int(row.song_list_label.get_line_count()).is_greater(1)
assert_float(pictures.size.y).is_less(text.size.y)
assert_float(pictures.get_center().y).is_equal_approx(text.get_center().y, 1.0)
func test_every_picture_has_the_same_size() -> void:
await _each_layout(func(row: SongRow, layout: String) -> void:
for picture: TextureRect in _pictures(row):
assert_vector(picture.size).override_failure_message(layout) \
.is_equal(SongRow.PICTURE_SIZE))
func test_rows_never_need_sideways_scrolling() -> void:
Settings.is_debug = true
for players: int in Settings.MAX_NUMBER_OF_PLAYERS + 1:
_add_song(LONG, players)
await _show()
var scroll: ScrollContainer = _panel.get_node("ScrollContainer")
assert_bool(scroll.get_h_scroll_bar().visible).is_false()
assert_float(_panel.size.x).is_equal(_panel_width)
for row: SongRow in _rows():
assert_float(row.get_global_rect().end.x) \
.is_less_equal(scroll.get_global_rect().end.x + 0.5)
# Pictures
func test_pictures_show_who_got_a_point_in_player_list_order() -> void:
var song: SongObject = _add_song(SHORT, 0)
# Points given in another order than the player list
song.add_point(Settings.player_array[2].id)
song.add_point(Settings.player_array[0].id)
await _show()
var names: Array[String] = []
for picture: TextureRect in _pictures(_rows()[0]):
names.append(picture.tooltip_text)
assert_array(names).contains_exactly(["Player 1", "Player 3"])
assert_object(_pictures(_rows()[0])[0].texture).is_same(Settings.player_array[0].character)
func test_pictures_are_redone_when_points_change() -> void:
var song: SongObject = _add_song(SHORT, 4)
await _show()
song.add_point(Settings.player_array[4].id)
_rows()[0].update_players()
await _runner.simulate_frames(2)
assert_array(_lines_of_pictures(_rows()[0])).contains_exactly([3, 2])
func test_clicking_a_picture_clicks_the_song() -> void:
_add_song(SHORT, 0)
_add_song(SHORT, 3)
await _show()
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
var picture: TextureRect = _pictures(_rows()[1])[1]
_runner.set_mouse_position(
_panel.get_viewport().get_final_transform() * picture.get_global_rect().get_center())
await _runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
await _runner.await_input_processed()
await signals.is_emitted("song_clicked", [1])
# Styles
func test_rows_alternate_and_the_playing_song_stands_out() -> void:
for i: int in 4:
_add_song(SHORT, 0)
Playlist.song_object_array[2].is_playing = true
await _show()
var styles: Array[StringName] = []
for row: SongRow in _rows():
styles.append(row.theme_type_variation)
assert_array(styles).contains_exactly(
[&"SongRow", &"SongRowOdd", &"SongRowPlaying", &"SongRowOdd"])
assert_str(_rows()[2].song_list_label.theme_type_variation).is_equal("SongRowLabelPlaying")
assert_str(_rows()[1].song_list_label.theme_type_variation).is_equal("SongRowLabel")
func test_hovering_a_row_highlights_it_until_the_mouse_leaves() -> void:
_add_song(SHORT, 0)
_add_song(SHORT, 0)
await _show()
var row: SongRow = _rows()[1]
row.mouse_entered.emit()
assert_str(row.theme_type_variation).is_equal("SongRowHover")
row.mouse_exited.emit()
assert_str(row.theme_type_variation).is_equal("SongRowOdd")
+1
View File
@@ -0,0 +1 @@
uid://dnggvrk5thb2v
+5
View File
@@ -32,6 +32,11 @@ const STYLES: Dictionary = {
"HighlightMedium": "Label",
"SongRowLabel": "Label",
"SongRowLabelPlaying": "Label",
"SongRowOdd": "PanelContainer",
"SongRowHover": "PanelContainer",
"SongRowPlaying": "PanelContainer",
"SongRowPictureLine": "HBoxContainer",
"SongRowPictureLines": "VBoxContainer",
"StatisticsCard": "PanelContainer",
"StatisticsCardHover": "PanelContainer",
"StatisticsGrid": "GridContainer",