Add a theme picker and an Original web theme (#42)
Build / test (push) Successful in 1m31s
Build / build (push) Successful in 1m13s

Settings has a Theme row listing Settings.THEMES: Classic (main_theme.tres,
still the default) and Original web (original_web_theme.tres), which looks like
MusicFrontend: orange-bordered buttons, a #333 header and popups, #424242
panels, #4e4e4e alternating rows, a yellow playing song and a light grey
player bar. Picking one sets the root window's theme at once and saves it as
theme_id in settings.cfg, and it is applied at start.

The popup backdrop and score graph follow a theme switch. The top bar has its
own TopBarBackground style. test_theme.gd checks that every theme has
everything main_theme.tres has. The screenshot tool takes a theme id.

Closes #42

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SansanandClaude Opus 5.5 committed 2026-10-12 20:50:12 +02:00
1 parent 70e970b24c
commit 94e8dfb602
15 files changed
+2497 -586

No files matched your search

+35 -1
View File
@@ -3,6 +3,9 @@ extends Node
##
## Registered as the [code]Settings[/code] autoload.
## Emitted when another theme is used, for code that reads theme colours itself.
signal theme_changed
const MAX_NUMBER_OF_PLAYERS: int = 7
## How many letters a search needs before it also finds names with the letters in order
## but apart, e.g. "lttp" for "A Link to the Past". Shorter searches only find names
@@ -26,8 +29,14 @@ const SAVED_SETTINGS: Dictionary[String, Array] = {
&"inspiration_list_speed",
],
"window": [&"fullscreen"],
"app": [&"last_seen_version"],
"app": [&"last_seen_version", &"theme_id"],
}
## The looks the game can have, picked in Settings: an id that is saved, the name shown
## and the theme file. The first is the default. See themes/README.md.
const THEMES: Array[Dictionary] = [
{"id": "classic", "name": "Classic", "path": "res://themes/main_theme.tres"},
{"id": "original_web", "name": "Original web", "path": "res://themes/original_web_theme.tres"},
]
## When this environment variable is set, the settings files are kept in that folder
## instead of the user's config folder. The tests set it so they never touch the real files.
const CONFIG_DIR_ENV: String = "MUSICPLAYER_CONFIG_DIR"
@@ -85,6 +94,8 @@ var queue_ids: Dictionary[String, String] = {}
## The version the game last showed the About popup for. When it is not [member version],
## this version is new and the main window opens the About popup to show what is new.
var last_seen_version: String = ""
## The id of the theme in use, one of [constant THEMES].
var theme_id: String = THEMES[0].id
## The folder songs are played from instead of the server, picked in the settings, or null
## to use the server. Kept for this session only.
var music_folder: MusicFolder = null
@@ -103,6 +114,7 @@ var version: String = ProjectSettings.get_setting("application/config/version",
func _ready() -> void:
apply_config(load_config())
load_saved_settings()
_use_theme(theme_id)
if fullscreen:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
@@ -246,6 +258,28 @@ func characters_dir() -> String:
return ""
## Switches the whole game to the theme [param id] from [constant THEMES] and saves the
## choice. Controls without a theme of their own take it from the root window.
func apply_theme(id: String) -> void:
_use_theme(id)
save_settings()
## The theme in [constant THEMES] with [param id], or the default one if there is none.
func theme_entry(id: String) -> Dictionary:
for entry: Dictionary in THEMES:
if entry.id == id:
return entry
return THEMES[0]
func _use_theme(id: String) -> void:
var entry: Dictionary = theme_entry(id)
theme_id = entry.id
get_tree().root.theme = load(entry.path)
theme_changed.emit()
func delete_children(node: Node) -> void:
for n: Node in node.get_children():
node.remove_child(n)