Add a theme picker and an Original web theme (#42)
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:
1 parent
70e970b24c
commit
94e8dfb602
15 files changed
+2497
-586
No files matched your search
+35
-1
@@ -3,6 +3,9 @@ extends Node
|
|||||||
##
|
##
|
||||||
## Registered as the [code]Settings[/code] autoload.
|
## 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
|
const MAX_NUMBER_OF_PLAYERS: int = 7
|
||||||
## How many letters a search needs before it also finds names with the letters in order
|
## 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
|
## 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",
|
&"inspiration_list_speed",
|
||||||
],
|
],
|
||||||
"window": [&"fullscreen"],
|
"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
|
## 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.
|
## 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"
|
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],
|
## 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.
|
## this version is new and the main window opens the About popup to show what is new.
|
||||||
var last_seen_version: String = ""
|
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
|
## 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.
|
## to use the server. Kept for this session only.
|
||||||
var music_folder: MusicFolder = null
|
var music_folder: MusicFolder = null
|
||||||
@@ -103,6 +114,7 @@ var version: String = ProjectSettings.get_setting("application/config/version",
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
apply_config(load_config())
|
apply_config(load_config())
|
||||||
load_saved_settings()
|
load_saved_settings()
|
||||||
|
_use_theme(theme_id)
|
||||||
if fullscreen:
|
if fullscreen:
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
||||||
|
|
||||||
@@ -246,6 +258,28 @@ func characters_dir() -> String:
|
|||||||
return ""
|
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:
|
func delete_children(node: Node) -> void:
|
||||||
for n: Node in node.get_children():
|
for n: Node in node.get_children():
|
||||||
node.remove_child(n)
|
node.remove_child(n)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ script = ExtResource("top_bar_script")
|
|||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 1920.0
|
offset_right = 1920.0
|
||||||
offset_bottom = 56.0
|
offset_bottom = 56.0
|
||||||
|
theme_type_variation = &"TopBarBackground"
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="." unique_id=1187907861]
|
[node name="Title" type="Label" parent="." unique_id=1187907861]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
|
|||||||
@@ -143,6 +143,21 @@ theme_type_variation = &"HighlightMedium"
|
|||||||
text = "No pictures found"
|
text = "No pictures found"
|
||||||
text_overrun_behavior = 3
|
text_overrun_behavior = 3
|
||||||
|
|
||||||
|
[node name="ThemeRow" type="HBoxContainer" parent="SettingsPanel/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="SettingsPanel/VBoxContainer/ThemeRow"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_type_variation = &"SettingsRowLabel"
|
||||||
|
text = "Theme"
|
||||||
|
|
||||||
|
[node name="ThemeButton" type="OptionButton" parent="SettingsPanel/VBoxContainer/ThemeRow"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(180, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
focus_mode = 0
|
||||||
|
|
||||||
[node name="FullscreenButton" type="CheckButton" parent="SettingsPanel/VBoxContainer" unique_id=400304684]
|
[node name="FullscreenButton" type="CheckButton" parent="SettingsPanel/VBoxContainer" unique_id=400304684]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|||||||
@@ -27,5 +27,11 @@ static func add_to(parent: Control, popups: Array[BasePopup]) -> PopupBackdrop:
|
|||||||
return backdrop
|
return backdrop
|
||||||
|
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
# The dimming colour comes from the theme, which can be switched in Settings
|
||||||
|
if what == NOTIFICATION_THEME_CHANGED:
|
||||||
|
color = get_theme_color(&"backdrop", &"Palette")
|
||||||
|
|
||||||
|
|
||||||
func _update() -> void:
|
func _update() -> void:
|
||||||
visible = _popups.any(func(popup: BasePopup) -> bool: return popup.visible)
|
visible = _popups.any(func(popup: BasePopup) -> bool: return popup.visible)
|
||||||
@@ -19,6 +19,12 @@ var _history: ScoreHistory
|
|||||||
var _winning_score: int = 0
|
var _winning_score: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
# The colours come from the theme, which can be switched in Settings
|
||||||
|
if what == NOTIFICATION_THEME_CHANGED:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
## Shows [param history]. The y axis goes up to [param winning_score], or higher if
|
## Shows [param history]. The y axis goes up to [param winning_score], or higher if
|
||||||
## someone has more points. A winning score of 0 draws no winning line.
|
## someone has more points. A winning score of 0 draws no winning line.
|
||||||
func show_history(history: ScoreHistory, winning_score: int) -> void:
|
func show_history(history: ScoreHistory, winning_score: int) -> void:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
class_name SettingsPopup
|
class_name SettingsPopup
|
||||||
extends BasePopup
|
extends BasePopup
|
||||||
## The application settings: which MusicServer or music folder to play from, fullscreen,
|
## The application settings: which MusicServer or music folder to play from, the theme,
|
||||||
## how many songs to download ahead, whether to prefer less played soundtracks and whether
|
## fullscreen, how many songs to download ahead, whether to prefer less played soundtracks
|
||||||
## plays count in the statistics, and a button that opens the folder the settings are
|
## and whether plays count in the statistics, and a button that opens the folder the
|
||||||
## kept in. Opened from the Settings button in the top bar.
|
## settings are kept in. Opened from the Settings button in the top bar.
|
||||||
##
|
##
|
||||||
## A music folder (see [MusicFolder]) is used instead of the server until Use server is
|
## A music folder (see [MusicFolder]) is used instead of the server until Use server is
|
||||||
## pressed or the game is closed. The settings that need the server are off meanwhile.
|
## pressed or the game is closed. The settings that need the server are off meanwhile.
|
||||||
@@ -25,6 +25,7 @@ const PADDING: Vector2 = Vector2(20, 12)
|
|||||||
@onready var settings_panel: Panel = %SettingsPanel
|
@onready var settings_panel: Panel = %SettingsPanel
|
||||||
@onready var select_server_button: OptionButton = %SelectServerButton
|
@onready var select_server_button: OptionButton = %SelectServerButton
|
||||||
@onready var fullscreen_button: CheckButton = %FullscreenButton
|
@onready var fullscreen_button: CheckButton = %FullscreenButton
|
||||||
|
@onready var theme_button: OptionButton = %ThemeButton
|
||||||
@onready var cache_label: Label = %CacheLabel
|
@onready var cache_label: Label = %CacheLabel
|
||||||
@onready var lower_cache_button: Button = %LowerCacheButton
|
@onready var lower_cache_button: Button = %LowerCacheButton
|
||||||
@onready var increase_cache_button: Button = %IncreaseCacheButton
|
@onready var increase_cache_button: Button = %IncreaseCacheButton
|
||||||
@@ -56,6 +57,10 @@ var _panel_middle_y: float = 0.0
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
for server: String in Settings.servers:
|
for server: String in Settings.servers:
|
||||||
select_server_button.add_item(server)
|
select_server_button.add_item(server)
|
||||||
|
for entry: Dictionary in Settings.THEMES:
|
||||||
|
theme_button.add_item(entry.name)
|
||||||
|
theme_button.select(Settings.THEMES.find(Settings.theme_entry(Settings.theme_id)))
|
||||||
|
theme_button.item_selected.connect(select_theme)
|
||||||
fullscreen_button.button_pressed = Settings.fullscreen
|
fullscreen_button.button_pressed = Settings.fullscreen
|
||||||
select_server_button.select(Settings.selected_server)
|
select_server_button.select(Settings.selected_server)
|
||||||
cache_label.text = str(Playlist.number_of_tracks_to_preload)
|
cache_label.text = str(Playlist.number_of_tracks_to_preload)
|
||||||
@@ -83,6 +88,11 @@ func _ready() -> void:
|
|||||||
_show_music_source()
|
_show_music_source()
|
||||||
|
|
||||||
|
|
||||||
|
## Switches to the theme at [param index] in [constant Settings.THEMES] at once.
|
||||||
|
func select_theme(index: int) -> void:
|
||||||
|
Settings.apply_theme(Settings.THEMES[index].id)
|
||||||
|
|
||||||
|
|
||||||
func fullscreen() -> void:
|
func fullscreen() -> void:
|
||||||
Settings.set_fullscreen(!Settings.fullscreen)
|
Settings.set_fullscreen(!Settings.fullscreen)
|
||||||
|
|
||||||
|
|||||||
+816
-573
File diff suppressed because it is too large.
Load diff
@@ -15,6 +15,7 @@ const STYLES: Dictionary = {
|
|||||||
"WindowBackground": "Panel",
|
"WindowBackground": "Panel",
|
||||||
"PopupBackground": "Panel",
|
"PopupBackground": "Panel",
|
||||||
"StepButton": "Button",
|
"StepButton": "Button",
|
||||||
|
"TopBarBackground": "PanelContainer",
|
||||||
"PlayerList": "PanelContainer",
|
"PlayerList": "PanelContainer",
|
||||||
"PlayerCharacter": "PanelContainer",
|
"PlayerCharacter": "PanelContainer",
|
||||||
"PlayerCharacterHover": "PanelContainer",
|
"PlayerCharacterHover": "PanelContainer",
|
||||||
@@ -171,3 +172,31 @@ func test_japanese_fallback_keeps_the_line_height_of_godots_font() -> void:
|
|||||||
assert_float(_theme.default_font.get_height(size)) \
|
assert_float(_theme.default_font.get_height(size)) \
|
||||||
.override_failure_message("Line height at size %d" % size) \
|
.override_failure_message("Line height at size %d" % size) \
|
||||||
.is_equal(builtin.get_height(size))
|
.is_equal(builtin.get_height(size))
|
||||||
|
|
||||||
|
|
||||||
|
func test_every_theme_has_everything_the_main_theme_has() -> void:
|
||||||
|
var data_types: Array[Theme.DataType] = [Theme.DATA_TYPE_COLOR, Theme.DATA_TYPE_CONSTANT,
|
||||||
|
Theme.DATA_TYPE_FONT, Theme.DATA_TYPE_FONT_SIZE, Theme.DATA_TYPE_ICON,
|
||||||
|
Theme.DATA_TYPE_STYLEBOX]
|
||||||
|
for entry: Dictionary in Settings.THEMES:
|
||||||
|
var other: Theme = load(entry.path)
|
||||||
|
assert_object(other).override_failure_message(entry.path + " is missing").is_not_null()
|
||||||
|
for theme_type: String in _theme.get_type_list():
|
||||||
|
assert_str(String(other.get_type_variation_base(theme_type))) \
|
||||||
|
.override_failure_message("%s: %s" % [entry.name, theme_type]) \
|
||||||
|
.is_equal(String(_theme.get_type_variation_base(theme_type)))
|
||||||
|
for data_type: Theme.DataType in data_types:
|
||||||
|
for item: String in _theme.get_theme_item_list(data_type, theme_type):
|
||||||
|
assert_bool(other.has_theme_item(data_type, item, theme_type)) \
|
||||||
|
.override_failure_message("%s has no %s/%s" % [entry.name,
|
||||||
|
theme_type, item]).is_true()
|
||||||
|
|
||||||
|
|
||||||
|
func test_every_theme_has_its_own_name_and_id() -> void:
|
||||||
|
var ids: Array = Settings.THEMES.map(func(entry: Dictionary) -> String: return entry.id)
|
||||||
|
var names: Array = Settings.THEMES.map(func(entry: Dictionary) -> String: return entry.name)
|
||||||
|
|
||||||
|
assert_str(Settings.THEMES[0].path).is_equal(THEME_PATH)
|
||||||
|
for list: Array in [ids, names]:
|
||||||
|
for value: String in list:
|
||||||
|
assert_int(list.count(value)).override_failure_message(value).is_equal(1)
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
extends MainWindowTestSuite
|
||||||
|
## Picking a theme in Settings switches the whole game's look at once and is saved.
|
||||||
|
|
||||||
|
var _settings: SettingsPopup
|
||||||
|
|
||||||
|
|
||||||
|
func before_test() -> void:
|
||||||
|
await super()
|
||||||
|
_settings = _window.get_node("SettingsPopup")
|
||||||
|
|
||||||
|
|
||||||
|
func after_test() -> void:
|
||||||
|
Settings.apply_theme(Settings.THEMES[0].id)
|
||||||
|
await super()
|
||||||
|
|
||||||
|
|
||||||
|
func _pick(theme_name: String) -> void:
|
||||||
|
var index: int = Settings.THEMES.map(
|
||||||
|
func(entry: Dictionary) -> String: return entry.name).find(theme_name)
|
||||||
|
_settings.theme_button.select(index)
|
||||||
|
_settings.theme_button.item_selected.emit(index)
|
||||||
|
await _runner.simulate_frames(1)
|
||||||
|
|
||||||
|
|
||||||
|
func test_picker_lists_every_theme_and_shows_the_one_in_use() -> void:
|
||||||
|
var names: Array[String] = []
|
||||||
|
for index: int in _settings.theme_button.item_count:
|
||||||
|
names.append(_settings.theme_button.get_item_text(index))
|
||||||
|
|
||||||
|
assert_array(names).contains_exactly(["Classic", "Original web"])
|
||||||
|
assert_str(_settings.theme_button.get_item_text(_settings.theme_button.selected)) \
|
||||||
|
.is_equal("Classic")
|
||||||
|
|
||||||
|
|
||||||
|
func test_picking_a_theme_switches_the_look_at_once() -> void:
|
||||||
|
var button: Button = _window.get_node("TopBar/%SyncButton")
|
||||||
|
var classic_text: Color = button.get_theme_color(&"font_color")
|
||||||
|
var panel: Panel = _window.get_node("SettingsPopup/SettingsPanel")
|
||||||
|
var popup_style: StyleBox = panel.get_theme_stylebox(&"panel")
|
||||||
|
|
||||||
|
await _pick("Original web")
|
||||||
|
|
||||||
|
assert_str(Settings.theme_id).is_equal("original_web")
|
||||||
|
assert_str(_window.get_tree().root.theme.resource_path) \
|
||||||
|
.is_equal("res://themes/original_web_theme.tres")
|
||||||
|
assert_object(panel.get_theme_stylebox(&"panel")).is_not_same(popup_style)
|
||||||
|
# The web version's buttons have orange text
|
||||||
|
assert_bool(button.get_theme_color(&"font_color") != classic_text).is_true()
|
||||||
|
|
||||||
|
|
||||||
|
func test_chosen_theme_is_saved() -> void:
|
||||||
|
await _pick("Original web")
|
||||||
|
|
||||||
|
var saved: ConfigFile = ConfigFile.new()
|
||||||
|
assert_int(saved.load(Settings.saved_settings_path())).is_equal(OK)
|
||||||
|
assert_str(saved.get_value("app", "theme_id")).is_equal("original_web")
|
||||||
|
|
||||||
|
|
||||||
|
func test_backdrop_and_graph_follow_the_theme() -> void:
|
||||||
|
var backdrop: PopupBackdrop = _window.get_node("PopupBackdrop")
|
||||||
|
var classic: Color = backdrop.color
|
||||||
|
|
||||||
|
await _pick("Original web")
|
||||||
|
|
||||||
|
assert_object(backdrop.color).is_equal(backdrop.get_theme_color(&"backdrop", &"Palette"))
|
||||||
|
assert_bool(backdrop.color != classic).is_true()
|
||||||
|
|
||||||
|
|
||||||
|
func test_unknown_theme_falls_back_to_the_default() -> void:
|
||||||
|
Settings.apply_theme("no_such_theme")
|
||||||
|
|
||||||
|
assert_str(Settings.theme_id).is_equal("classic")
|
||||||
|
assert_str(_window.get_tree().root.theme.resource_path) \
|
||||||
|
.is_equal("res://themes/main_theme.tres")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://de1hpddu212xs
|
||||||
@@ -6,7 +6,7 @@ const SAVED_VALUES: Dictionary = {
|
|||||||
&"auto_repeat_song": false, &"stop_after_current": false, &"hide_next_track": false,
|
&"auto_repeat_song": false, &"stop_after_current": false, &"hide_next_track": false,
|
||||||
&"hide_beginning": true, &"hide_for_seconds": 7.0, &"hide_length": true,
|
&"hide_beginning": true, &"hide_for_seconds": 7.0, &"hide_length": true,
|
||||||
&"hide_ticks": true, &"winning_score": 13, &"inspiration_list_speed": 4,
|
&"hide_ticks": true, &"winning_score": 13, &"inspiration_list_speed": 4,
|
||||||
&"fullscreen": true, &"last_seen_version": "1.2.3",
|
&"fullscreen": true, &"last_seen_version": "1.2.3", &"theme_id": "original_web",
|
||||||
}
|
}
|
||||||
|
|
||||||
var _snapshot: AutoloadSnapshot
|
var _snapshot: AutoloadSnapshot
|
||||||
|
|||||||
+29
-7
@@ -1,17 +1,35 @@
|
|||||||
# Themes
|
# Themes
|
||||||
|
|
||||||
The whole look of the game comes from one theme, `main_theme.tres`. It is the project
|
The whole look of the game comes from a theme. Scenes and scripts never set colours,
|
||||||
theme (Project Settings → GUI → Theme → Custom), so every scene uses it without setting
|
font sizes or style boxes themselves; they name one of the theme's styles instead, and
|
||||||
anything. Scenes and scripts never set colours, font sizes or style boxes themselves;
|
`tests/integration/test_theme.gd` checks that it stays that way.
|
||||||
they name one of the theme's styles instead, and `tests/integration/test_theme.gd`
|
|
||||||
checks that it stays that way.
|
| Theme | File | |
|
||||||
|
|---|---|---|
|
||||||
|
| Classic | `main_theme.tres` | The default. Also the project theme (Project Settings → GUI → Theme → Custom), which the editor shows |
|
||||||
|
| Original web | `original_web_theme.tres` | Looks like MusicFrontend, the web version: orange-bordered buttons, `#333` header and popups, `#424242` panels, `#4e4e4e` alternating rows, a yellow playing song and a light grey player bar |
|
||||||
|
|
||||||
|
## Picking a theme
|
||||||
|
|
||||||
|
The themes are listed in `Settings.THEMES` (`data/settings.gd`): an id, the name shown
|
||||||
|
and the file. The player picks one in Settings → Theme, and it applies at once.
|
||||||
|
`Settings.apply_theme()` sets the theme of the root window, which every control without a
|
||||||
|
theme of its own uses, and saves the id as `theme_id` in `settings.cfg`. The saved theme
|
||||||
|
is applied when the game starts.
|
||||||
|
|
||||||
|
Code that reads theme colours itself redraws on `NOTIFICATION_THEME_CHANGED`, e.g. the
|
||||||
|
score graph and the popup backdrop. `Settings.theme_changed` is emitted after a switch.
|
||||||
|
|
||||||
|
To see the pictures of the screenshot tour in another theme, pass its id:
|
||||||
|
`godot --path . -s tools/take_screenshots.gd -- <dir> original_web`.
|
||||||
|
|
||||||
## Making a new theme
|
## Making a new theme
|
||||||
|
|
||||||
1. Copy `main_theme.tres`, e.g. to `dark_blue_theme.tres`.
|
1. Copy `main_theme.tres`, e.g. to `dark_blue_theme.tres`.
|
||||||
2. Open the copy in Godot (double-click it) and change its colours, style boxes and font
|
2. Open the copy in Godot (double-click it) and change its colours, style boxes and font
|
||||||
sizes in the theme editor. Keep every style's name.
|
sizes in the theme editor. Keep every style's name.
|
||||||
3. Point Project Settings → GUI → Theme → Custom at the copy.
|
3. Add it to `Settings.THEMES`. `test_theme.gd` checks that it has every style, colour and
|
||||||
|
size that `main_theme.tres` has.
|
||||||
|
|
||||||
The **font** is the theme's default font, Godot's own Open Sans with Noto Sans JP for
|
The **font** is the theme's default font, Godot's own Open Sans with Noto Sans JP for
|
||||||
Japanese text; see `fonts/README.md`.
|
Japanese text; see `fonts/README.md`.
|
||||||
@@ -32,7 +50,11 @@ inspector or `theme_type_variation` in code:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `WindowBackground` | Panel | The background behind everything in the main window |
|
| `WindowBackground` | Panel | The background behind everything in the main window |
|
||||||
| `PopupBackground` | Panel | The panel of every popup: dark, bordered and rounded |
|
| `PopupBackground` | Panel | The panel of every popup: dark, bordered and rounded |
|
||||||
| `DarkSpacer` | Panel | The dark gaps in the player list and the add player row |
|
| `TopBarBackground` | PanelContainer | The bar along the top of the window |
|
||||||
|
| `PlayerList` | PanelContainer | The player list, with space around its rows |
|
||||||
|
| `PlayerScore` | Label | A player's points (24) |
|
||||||
|
| `PlayerCharacter`, `PlayerCharacterHover` | PanelContainer | The frame around a player's character, and the one under the mouse |
|
||||||
|
| `StepButton` | Button | The small +1 and -1 buttons, with less padding than other buttons |
|
||||||
| `CharacterCard` | Panel | A character in the character select popup |
|
| `CharacterCard` | Panel | A character in the character select popup |
|
||||||
| `MusicList` | PanelContainer | The list of songs in the quiz |
|
| `MusicList` | PanelContainer | The list of songs in the quiz |
|
||||||
| `SongRow`, `SongRowOdd` | PanelContainer | Alternating songs in that list |
|
| `SongRow`, `SongRowOdd` | PanelContainer | Alternating songs in that list |
|
||||||
|
|||||||
@@ -1331,6 +1331,8 @@ TitleLarge/base_type = &"Label"
|
|||||||
TitleLarge/font_sizes/font_size = 50
|
TitleLarge/font_sizes/font_size = 50
|
||||||
TitleMedium/base_type = &"Label"
|
TitleMedium/base_type = &"Label"
|
||||||
TitleMedium/font_sizes/font_size = 35
|
TitleMedium/font_sizes/font_size = 35
|
||||||
|
TopBarBackground/base_type = &"PanelContainer"
|
||||||
|
TopBarBackground/styles/panel = SubResource("StyleBoxFlat_wl3gy")
|
||||||
TooltipLabel/colors/font_color = Color(0.875, 0.875, 0.875, 1)
|
TooltipLabel/colors/font_color = Color(0.875, 0.875, 0.875, 1)
|
||||||
TooltipLabel/colors/font_outline_color = Color(0, 0, 0, 1)
|
TooltipLabel/colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
TooltipLabel/colors/font_shadow_color = Color(0, 0, 0, 0)
|
TooltipLabel/colors/font_shadow_color = Color(0, 0, 0, 0)
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -3,6 +3,7 @@ extends SceneTree
|
|||||||
##
|
##
|
||||||
## Usage:
|
## Usage:
|
||||||
## MUSICPLAYER_CONFIG_DIR=$(mktemp -d) godot --path . -s tools/take_screenshots.gd -- <dir>
|
## MUSICPLAYER_CONFIG_DIR=$(mktemp -d) godot --path . -s tools/take_screenshots.gd -- <dir>
|
||||||
|
## [<theme id>]
|
||||||
##
|
##
|
||||||
## Setting [code]MUSICPLAYER_CONFIG_DIR[/code] keeps your saved quiz settings out of the
|
## Setting [code]MUSICPLAYER_CONFIG_DIR[/code] keeps your saved quiz settings out of the
|
||||||
## pictures.
|
## pictures.
|
||||||
@@ -10,6 +11,9 @@ extends SceneTree
|
|||||||
## Writes [code]<state>.png[/code] for each state and [code]layout.json[/code] with where
|
## Writes [code]<state>.png[/code] for each state and [code]layout.json[/code] with where
|
||||||
## every node is in each state. With [code]--headless[/code] only the layout is written.
|
## every node is in each state. With [code]--headless[/code] only the layout is written.
|
||||||
## Compare two runs with [code]tools/compare_screenshots.py[/code].
|
## Compare two runs with [code]tools/compare_screenshots.py[/code].
|
||||||
|
##
|
||||||
|
## The pictures use the default theme, or the theme with the given id from
|
||||||
|
## [code]Settings.THEMES[/code], e.g. [code]original_web[/code].
|
||||||
|
|
||||||
const SIZE: Vector2i = Vector2i(1920, 1080)
|
const SIZE: Vector2i = Vector2i(1920, 1080)
|
||||||
|
|
||||||
@@ -37,6 +41,10 @@ func _take() -> void:
|
|||||||
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||||
root.add_child(viewport)
|
root.add_child(viewport)
|
||||||
var main: Control = load("res://main/MainWindow.tscn").instantiate()
|
var main: Control = load("res://main/MainWindow.tscn").instantiate()
|
||||||
|
if args.size() > 1:
|
||||||
|
# The game sets the root window's theme, which the viewport here is not under
|
||||||
|
var settings: Node = root.get_node("Settings")
|
||||||
|
main.theme = load(settings.theme_entry(args[1]).path)
|
||||||
viewport.add_child(main)
|
viewport.add_child(main)
|
||||||
|
|
||||||
var layout: Dictionary = {}
|
var layout: Dictionary = {}
|
||||||
|
|||||||
Reference in new issue
Block a user