diff --git a/locale/en.properties b/locale/en.properties
index d83907a..a99ff8b 100644
--- a/locale/en.properties
+++ b/locale/en.properties
@@ -26,6 +26,11 @@ menu/play/status_mismatch = Incompatible versions: {0}
menu/play/status_problems = Problems in the game composition: {0}
menu/play/status_install = To install: {0}, to enable: {1}
menu/load/empty = No saves yet
+menu/save/new_slot = + New save
+menu/load/hint = Click a save to load it
+menu/save/hint = Click a slot to save the game; a used slot is overwritten after a confirmation
+menu/play/hint_warming = The games' mods are being prepared in the background — starting will be quick afterwards
+menu/play/hint_ready = The games' mods are ready, starting takes a few seconds
menu/load/legacy_group = Saves without a game
menu/load/legacy_title = Save without a game
menu/load/legacy_text = This save was made before game collections existed. Choose the game it belongs to — the file moves into that game's saves.
diff --git a/locale/ru.properties b/locale/ru.properties
index be52afa..f2a3128 100644
--- a/locale/ru.properties
+++ b/locale/ru.properties
@@ -26,6 +26,11 @@ menu/play/status_mismatch = Несовместимые версии: {0}
menu/play/status_problems = Ошибки в составе игры: {0}
menu/play/status_install = Нужно установить: {0}, включить: {1}
menu/load/empty = Сохранений пока нет
+menu/save/new_slot = + Новое сохранение
+menu/load/hint = Нажмите на сохранение, чтобы загрузить его
+menu/save/hint = Нажмите на слот, чтобы сохранить игру; занятый слот перезапишется после подтверждения
+menu/play/hint_warming = Моды игр готовятся в фоне — запуск после этого будет быстрым
+menu/play/hint_ready = Моды игр готовы, запуск займёт несколько секунд
menu/load/legacy_group = Сохранения без игры
menu/load/legacy_title = Сохранение без игры
menu/load/legacy_text = Это сохранение сделано до появления игр-коллекций. Выберите игру, к которой оно относится, — файл переедет в её сохранения.
diff --git a/scenes/menu/game_picker.tscn b/scenes/menu/game_picker.tscn
new file mode 100644
index 0000000..3a19a94
--- /dev/null
+++ b/scenes/menu/game_picker.tscn
@@ -0,0 +1,111 @@
+[gd_scene format=3]
+
+[ext_resource type="Script" path="src/GamePickerPanel.cs" id="GamePickerScript"]
+
+[node name="GamePickerPanel" type="Control" unique_id=352232428]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("GamePickerScript")
+
+[node name="Backdrop" type="ColorRect" parent="." unique_id=1612952176]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0, 0, 0, 0.9)
+
+[node name="Window" type="PanelContainer" parent="." unique_id=788680784]
+layout_mode = 1
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -520.0
+offset_top = -360.0
+offset_right = 520.0
+offset_bottom = 360.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Column" type="VBoxContainer" parent="Window" unique_id=1513362382]
+layout_mode = 2
+theme_override_constants/separation = 0
+
+[node name="Header" type="MarginContainer" parent="Window/Column" unique_id=1901680926]
+layout_mode = 2
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 16
+theme_override_constants/margin_right = 16
+theme_override_constants/margin_bottom = 16
+
+[node name="Row" type="HBoxContainer" parent="Window/Column/Header" unique_id=897579862]
+layout_mode = 2
+theme_override_constants/separation = 24
+
+[node name="Title" type="Label" parent="Window/Column/Header/Row" unique_id=1589586692]
+layout_mode = 2
+size_flags_vertical = 4
+text = "Choose a game"
+uppercase = true
+
+[node name="Spacer" type="Control" parent="Window/Column/Header/Row" unique_id=1565293582]
+layout_mode = 2
+size_flags_horizontal = 3
+mouse_filter = 2
+
+[node name="CloseButton" type="Button" parent="Window/Column/Header/Row" unique_id=392870380]
+layout_mode = 2
+custom_minimum_size = Vector2(38, 38)
+size_flags_vertical = 4
+focus_mode = 0
+text = "✕"
+
+[node name="RuleHeader" type="ColorRect" parent="Window/Column" unique_id=1522041891]
+custom_minimum_size = Vector2(0, 1)
+layout_mode = 2
+
+[node name="Body" type="MarginContainer" parent="Window/Column" unique_id=897575893]
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 20
+theme_override_constants/margin_right = 24
+theme_override_constants/margin_bottom = 20
+
+[node name="Scroll" type="ScrollContainer" parent="Window/Column/Body" unique_id=1648576427]
+layout_mode = 2
+size_flags_vertical = 3
+horizontal_scroll_mode = 0
+
+[node name="List" type="VBoxContainer" parent="Window/Column/Body/Scroll" unique_id=355317885]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_constants/separation = 10
+
+[node name="RuleFooter" type="ColorRect" parent="Window/Column" unique_id=866559016]
+custom_minimum_size = Vector2(0, 1)
+layout_mode = 2
+
+[node name="Footer" type="MarginContainer" parent="Window/Column" unique_id=508767107]
+layout_mode = 2
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 12
+theme_override_constants/margin_right = 24
+theme_override_constants/margin_bottom = 12
+
+[node name="Row" type="HBoxContainer" parent="Window/Column/Footer" unique_id=1496801409]
+custom_minimum_size = Vector2(0, 38)
+layout_mode = 2
+theme_override_constants/separation = 12
+
+[node name="Hint" type="Label" parent="Window/Column/Footer/Row" unique_id=1150953277]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
diff --git a/scenes/menu/save_load_menu.tscn b/scenes/menu/save_load_menu.tscn
index dcb2601..90a6eea 100644
--- a/scenes/menu/save_load_menu.tscn
+++ b/scenes/menu/save_load_menu.tscn
@@ -1,84 +1,131 @@
-[gd_scene load_steps=3 format=3]
+[gd_scene format=3]
[ext_resource type="Script" path="src/SaveLoadMenu.cs" id="SaveLoadMenuScript"]
[ext_resource type="Script" path="src/SaveSlotList.cs" id="SaveSlotListScript"]
-[node name="SaveLoadMenu" type="Control"]
+[node name="SaveLoadMenu" type="Control" unique_id=1300922993]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-mouse_filter = 1
script = ExtResource("SaveLoadMenuScript")
-[node name="Bg" type="ColorRect" parent="."]
+[node name="Backdrop" type="ColorRect" parent="." unique_id=1957446002]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-color = Color(0, 0, 0, 0.65)
+color = Color(0, 0, 0, 0.9)
-[node name="Panel" type="Panel" parent="."]
+[node name="Window" type="PanelContainer" parent="." unique_id=1214442353]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
-offset_left = -420.0
-offset_top = -280.0
-offset_right = 420.0
-offset_bottom = 280.0
+offset_left = -500.0
+offset_top = -350.0
+offset_right = 500.0
+offset_bottom = 350.0
grow_horizontal = 2
grow_vertical = 2
-[node name="Margin" type="MarginContainer" parent="Panel"]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_left = 28
-theme_override_constants/margin_top = 20
-theme_override_constants/margin_right = 28
-theme_override_constants/margin_bottom = 20
-
-[node name="VBox" type="VBoxContainer" parent="Panel/Margin"]
+[node name="Column" type="VBoxContainer" parent="Window" unique_id=154632647]
layout_mode = 2
-theme_override_constants/separation = 14
+theme_override_constants/separation = 0
-[node name="Title" type="Label" parent="Panel/Margin/VBox"]
+[node name="Header" type="MarginContainer" parent="Window/Column" unique_id=255743212]
layout_mode = 2
-text = "Save/Load"
-horizontal_alignment = 1
-theme_override_font_sizes/font_size = 24
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 16
+theme_override_constants/margin_right = 16
+theme_override_constants/margin_bottom = 16
-[node name="GameSelect" type="OptionButton" parent="Panel/Margin/VBox"]
+[node name="Row" type="HBoxContainer" parent="Window/Column/Header" unique_id=1566510433]
layout_mode = 2
+theme_override_constants/separation = 24
-[node name="Scroll" type="ScrollContainer" parent="Panel/Margin/VBox"]
+[node name="Title" type="Label" parent="Window/Column/Header/Row" unique_id=1345868865]
+layout_mode = 2
+size_flags_vertical = 4
+text = "Load"
+uppercase = true
+
+[node name="GameSelect" type="OptionButton" parent="Window/Column/Header/Row" unique_id=1531297566]
+custom_minimum_size = Vector2(280, 0)
+layout_mode = 2
+size_flags_vertical = 4
+
+[node name="Spacer" type="Control" parent="Window/Column/Header/Row" unique_id=739525391]
layout_mode = 2
size_flags_horizontal = 3
+mouse_filter = 2
+
+[node name="CloseButton" type="Button" parent="Window/Column/Header/Row" unique_id=1063180782]
+layout_mode = 2
+custom_minimum_size = Vector2(38, 38)
+size_flags_vertical = 4
+focus_mode = 0
+text = "✕"
+
+[node name="RuleHeader" type="ColorRect" parent="Window/Column" unique_id=1844886327]
+custom_minimum_size = Vector2(0, 1)
+layout_mode = 2
+
+[node name="Body" type="MarginContainer" parent="Window/Column" unique_id=280231313]
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 20
+theme_override_constants/margin_right = 24
+theme_override_constants/margin_bottom = 20
+
+[node name="Content" type="VBoxContainer" parent="Window/Column/Body" unique_id=1998936353]
+layout_mode = 2
+theme_override_constants/separation = 12
+
+[node name="Scroll" type="ScrollContainer" parent="Window/Column/Body/Content" unique_id=131125275]
+layout_mode = 2
size_flags_vertical = 3
-custom_minimum_size = Vector2(0, 380)
horizontal_scroll_mode = 0
-[node name="SlotGrid" type="Control" parent="Panel/Margin/VBox/Scroll"]
+[node name="SlotGrid" type="Control" parent="Window/Column/Body/Content/Scroll" unique_id=702369365]
layout_mode = 2
size_flags_horizontal = 3
script = ExtResource("SaveSlotListScript")
+ColumnCount = 3
+RowCount = 2
+SlotPadding = 14.0
-[node name="EmptyLabel" type="Label" parent="Panel/Margin/VBox"]
+[node name="EmptyLabel" type="Label" parent="Window/Column/Body/Content" unique_id=1909778806]
layout_mode = 2
+size_flags_vertical = 3
horizontal_alignment = 1
+vertical_alignment = 1
visible = false
-[node name="BackBtn" type="Button" parent="Panel/Margin/VBox"]
+[node name="RuleFooter" type="ColorRect" parent="Window/Column" unique_id=225368463]
+custom_minimum_size = Vector2(0, 1)
layout_mode = 2
-text = "Back"
-size_flags_horizontal = 8
+
+[node name="Footer" type="MarginContainer" parent="Window/Column" unique_id=775810662]
+layout_mode = 2
+theme_override_constants/margin_left = 24
+theme_override_constants/margin_top = 12
+theme_override_constants/margin_right = 24
+theme_override_constants/margin_bottom = 12
+
+[node name="Row" type="HBoxContainer" parent="Window/Column/Footer" unique_id=1592632905]
+custom_minimum_size = Vector2(0, 38)
+layout_mode = 2
+theme_override_constants/separation = 12
+
+[node name="Hint" type="Label" parent="Window/Column/Footer/Row" unique_id=1935428591]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
diff --git a/scenes/menu/save_slot_item.tscn b/scenes/menu/save_slot_item.tscn
index 9fd4abf..ce17cb1 100644
--- a/scenes/menu/save_slot_item.tscn
+++ b/scenes/menu/save_slot_item.tscn
@@ -2,88 +2,86 @@
[ext_resource type="Script" path="src/SaveSlotItem.cs" id="SaveSlotItemScript"]
-[node name="SaveSlotItem" type="Control" unique_id=2135443384]
-custom_minimum_size = Vector2(120, 120)
+[node name="SaveSlotItem" type="Control" unique_id=1515573353]
+custom_minimum_size = Vector2(160, 140)
layout_mode = 3
anchors_preset = 0
script = ExtResource("SaveSlotItemScript")
-[node name="Background" type="ColorRect" parent="." unique_id=255218239]
+[node name="Card" type="PanelContainer" parent="." unique_id=368114590]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-color = Color(0.12, 0.12, 0.12, 0.9)
+mouse_filter = 2
-[node name="ScreenshotRect" type="TextureRect" parent="." unique_id=1290008068]
-layout_mode = 1
-anchors_preset = -1
-anchor_right = 1.0
-anchor_bottom = 0.55
-grow_horizontal = 2
-grow_vertical = 2
+[node name="Column" type="VBoxContainer" parent="Card" unique_id=1588140578]
+layout_mode = 2
+mouse_filter = 2
+theme_override_constants/separation = 0
+
+[node name="Shot" type="PanelContainer" parent="Card/Column" unique_id=1733920571]
+layout_mode = 2
+size_flags_vertical = 3
+mouse_filter = 2
+
+[node name="ScreenshotRect" type="TextureRect" parent="Card/Column/Shot" unique_id=1172880873]
+layout_mode = 2
+mouse_filter = 2
expand_mode = 1
-stretch_mode = 5
+stretch_mode = 6
-[node name="DateLabel" type="Label" parent="." unique_id=408317888]
-layout_mode = 1
-anchors_preset = -1
-anchor_left = 0.02
-anchor_top = 0.57
-anchor_right = 0.98
-anchor_bottom = 0.68
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 12
+[node name="Info" type="MarginContainer" parent="Card/Column" unique_id=288868314]
+layout_mode = 2
+mouse_filter = 2
+theme_override_constants/margin_left = 12
+theme_override_constants/margin_top = 8
+theme_override_constants/margin_right = 12
+theme_override_constants/margin_bottom = 10
-[node name="SceneLabel" type="Label" parent="." unique_id=1968956898]
-layout_mode = 1
-anchors_preset = -1
-anchor_left = 0.02
-anchor_top = 0.70
-anchor_right = 0.98
-anchor_bottom = 0.80
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 11
+[node name="Column" type="VBoxContainer" parent="Card/Column/Info" unique_id=700616276]
+layout_mode = 2
+mouse_filter = 2
+theme_override_constants/separation = 2
-[node name="TimeLabel" type="Label" parent="." unique_id=698436659]
-layout_mode = 1
-anchors_preset = -1
-anchor_left = 0.02
-anchor_top = 0.83
-anchor_right = 0.56
-anchor_bottom = 0.95
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 10
+[node name="DateLabel" type="Label" parent="Card/Column/Info/Column" unique_id=931970274]
+layout_mode = 2
+clip_text = true
-[node name="StatsLabel" type="Label" parent="." unique_id=400000001]
-layout_mode = 1
-anchors_preset = -1
-anchor_left = 0.58
-anchor_top = 0.83
-anchor_right = 0.98
-anchor_bottom = 0.95
-grow_horizontal = 2
-theme_override_font_sizes/font_size = 10
+[node name="SceneLabel" type="Label" parent="Card/Column/Info/Column" unique_id=1597878703]
+layout_mode = 2
+clip_text = true
+
+[node name="Meta" type="HBoxContainer" parent="Card/Column/Info/Column" unique_id=1948773627]
+layout_mode = 2
+mouse_filter = 2
+
+[node name="TimeLabel" type="Label" parent="Card/Column/Info/Column/Meta" unique_id=729436693]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="StatsLabel" type="Label" parent="Card/Column/Info/Column/Meta" unique_id=381078225]
+layout_mode = 2
horizontal_alignment = 2
-[node name="EmptyLabel" type="Label" parent="." unique_id=1262712091]
+[node name="EmptyLabel" type="Label" parent="." unique_id=1904510000]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-theme_override_font_sizes/font_size = 14
horizontal_alignment = 1
vertical_alignment = 1
-[node name="SlotButton" type="Button" parent="." unique_id=1877010914]
+[node name="SlotButton" type="Button" parent="." unique_id=1369022409]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
+focus_mode = 0
flat = true
diff --git a/src/GamePickerPanel.cs b/src/GamePickerPanel.cs
index 3b765b2..ac7f2c6 100644
--- a/src/GamePickerPanel.cs
+++ b/src/GamePickerPanel.cs
@@ -17,11 +17,17 @@ namespace Cthangover.BaseMenu
/// readiness (what is missing and what can be installed), saves and the
/// last play date — with New game / Continue / Saves / Install / Configure.
/// Data comes from against all installed mods, so
- /// it works from the front-end where only the menu is loaded.
+ /// it works from the front-end where only the menu is loaded. The window is
+ /// the menu shell (, scene game_picker.tscn);
+ /// its footer says whether the games' mods are still compiled in the
+ /// background () or a start is quick.
///
public partial class GamePickerPanel : Control
{
+ private const float HintRefreshSeconds = 0.5f;
+
private VBoxContainer _list;
+ private Label _hint;
private readonly HashSet _sessionInstalled = new(StringComparer.OrdinalIgnoreCase);
/// Raised when the player opens a game's saves; the menu shows its save browser.
@@ -31,58 +37,29 @@ namespace Cthangover.BaseMenu
public override void _Ready()
{
- SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect);
- MouseFilter = MouseFilterEnum.Stop;
+ MenuWindowShell.Style(this, Close);
+ GetNode