Make the buttons consistent and rework the player list
Build / test (push) Successful in 1m30s
Build / build (push) Successful in 1m17s

Buttons get 12 px of side padding. The top bar buttons, the quiz toolbar and
Show answer/Next are laid out in rows with 12 px gaps and are all 36 px tall,
and the ±1 buttons use a compact StepButton style. "Randomize new track" is now
"Next song".

Player rows show the name and the score apart, alternate like the other lists
and highlight the character under the mouse. The name field is a LineEdit with
a 10-letter limit; blank and duplicate names are refused, and a full list says
"Up to 7 players". Remove buttons update when editing is switched instead of
every frame, and the spacer panels are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SansanandClaude Opus 5.5 committed 2026-10-11 21:35:24 +02:00
1 parent e4352a9f34
commit 70e970b24c
39 files changed
+2054 -2177

No files matched your search

+94 -4
View File
@@ -118,7 +118,7 @@ func test_remove_button_removes_the_player_and_row() -> void:
var crono: PlayerObject = Settings.player_array[0]
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
(_rows()[0].get_node("HBoxContainer/RemovePlayer") as BaseButton).pressed.emit()
(_rows()[0].get_node("%RemovePlayer") as BaseButton).pressed.emit()
await signals.is_emitted("player_removed", [crono])
assert_array(Settings.player_array.map(
@@ -132,7 +132,7 @@ func test_character_button_asks_for_a_new_character() -> void:
var row: PlayerRow = _rows()[0]
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_panel))
(row.get_node("HBoxContainer/Character") as BaseButton).pressed.emit()
(row.get_node("%Character") as BaseButton).pressed.emit()
await signals.is_emitted("change_character_requested", [row, "Crono"])
@@ -143,5 +143,95 @@ func test_reload_shows_new_scores() -> void:
_panel.reload()
assert_str(((_rows()[0] as PlayerRow).get_node("HBoxContainer/Name") as Label).text) \
.ends_with("Crono: 3")
assert_str((_rows()[0] as PlayerRow).score_label.text).is_equal("3")
func test_row_shows_the_name_and_the_score_apart() -> void:
_add("Crono")
var row: PlayerRow = _rows()[0]
row.add_point()
row.add_point()
assert_str(row.player_name_field.text).is_equal("Crono")
assert_str(row.score_label.text).is_equal("2")
func test_names_are_trimmed_and_blank_ones_refused() -> void:
_add(" Crono ")
_add(" ")
assert_array(Settings.player_array.map(
func(p: PlayerObject) -> String: return p.player_name)).contains_exactly(["Crono"])
func test_a_name_can_only_be_used_once() -> void:
_add("Crono")
_add("crono")
assert_int(Settings.player_array.size()).is_equal(1)
assert_str(_panel.new_player_name_field.text).is_equal("crono")
func test_name_field_takes_at_most_ten_letters() -> void:
_panel.new_player_name_field.insert_text_at_caret("Abcdefghijklmnop")
assert_str(_panel.new_player_name_field.text).is_equal("Abcdefghij")
func test_full_list_says_so_instead_of_offering_the_name_field() -> void:
await _click(_panel.add_players_button)
for i: int in Settings.MAX_NUMBER_OF_PLAYERS:
_add("Player %d" % i)
assert_bool(_panel.add_player_hint.visible).is_true()
assert_str(_panel.add_player_hint.text).is_equal("Up to 7 players")
assert_bool(_panel.new_player_name_field.visible).is_false()
(_rows()[0].get_node("%RemovePlayer") as BaseButton).pressed.emit()
assert_bool(_panel.add_player_hint.visible).is_false()
assert_bool(_panel.new_player_name_field.visible).is_true()
func test_remove_buttons_show_only_while_editing() -> void:
_add("Crono")
var remove: Control = _rows()[0].get_node("%RemovePlayer")
assert_bool(remove.visible).is_false()
await _click(_panel.add_players_button)
assert_bool((_rows()[0].get_node("%RemovePlayer") as Control).visible).is_true()
await _click(_panel.add_players_button)
assert_bool((_rows()[0].get_node("%RemovePlayer") as Control).visible).is_false()
func test_rows_alternate_like_the_other_lists() -> void:
_add("Crono")
_add("Marle")
_add("Lucca")
assert_array(_rows().map(func(row: PlayerRow) -> String: return row.theme_type_variation)) \
.contains_exactly(["ListRowEven", "ListRowOdd", "ListRowEven"])
func test_character_is_highlighted_under_the_mouse() -> void:
_add("Crono")
var row: PlayerRow = _rows()[0]
row.character.mouse_entered.emit()
assert_str(row.character_frame.theme_type_variation).is_equal("PlayerCharacterHover")
row.character.mouse_exited.emit()
assert_str(row.character_frame.theme_type_variation).is_equal("PlayerCharacter")
assert_str(row.character.tooltip_text).is_equal("Change character")
func test_seven_players_fit_without_scrolling_while_adding() -> void:
await _click(_panel.add_players_button)
for i: int in Settings.MAX_NUMBER_OF_PLAYERS:
_add("Player %d" % i)
await _runner.simulate_frames(2)
var panel: Rect2 = _panel.get_global_rect()
var last: Rect2 = (_rows().back() as Control).get_global_rect()
assert_bool(panel.encloses(last)).is_true()