Skip to content

Commit bcd01c9

Browse files
committed
Better save/load GUI:
* Show "..." when saving * Keep the save box menu list highlighted * Show "Game saved successfully!" briefly afer saving * Ask the user for a savegame name if they're not entered one while an activity is running
1 parent 24d5c26 commit bcd01c9

File tree

7 files changed

+78
-10
lines changed

7 files changed

+78
-10
lines changed

Data/Base.rte/GUIs/SaveLoadMenuGUI.ini

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ Anchor = Left, Top
171171
ToolTip = None
172172
Text = Delete Save
173173

174-
[ActivityCannotBeSavedWarning]
174+
[DescriptionLabel]
175175
ControlType = LABEL
176176
Parent = CollectionBoxSaveGameMenu
177177
X = 7
@@ -180,9 +180,8 @@ Width = 287
180180
Height = 20
181181
Visible = True
182182
Enabled = True
183-
Name = ActivityCannotBeSavedWarning
183+
Name = DescriptionLabel
184184
Anchor = Left, Top
185-
Text = The currently played activity does not allow saving.
186185
HAlignment = Centre
187186
VAlignment = Centre
188187

Source/GUI/GUIListBox.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ void GUIListBox::Create(GUIProperties* Props) {
6161
bool Multi = false;
6262
Props->GetValue("MultiSelect", &Multi);
6363
SetMultiSelect(Multi);
64+
65+
bool highlightAsIfAlwaysFocused = false;
66+
Props->GetValue("HighlightAsIfAlwaysFocused", &highlightAsIfAlwaysFocused);
67+
SetHighlightAsIfAlwaysFocused(highlightAsIfAlwaysFocused);
6468
}
6569

6670
void GUIListBox::Destroy() {
@@ -128,6 +132,10 @@ void GUIListBox::ApplyProperties(GUIProperties* Props) {
128132
m_Properties.GetValue("MultiSelect", &Multi);
129133
SetMultiSelect(Multi);
130134

135+
bool highlightAsIfAlwaysFocused = false;
136+
m_Properties.GetValue("HighlightAsIfAlwaysFocused", &highlightAsIfAlwaysFocused);
137+
SetHighlightAsIfAlwaysFocused(highlightAsIfAlwaysFocused);
138+
131139
// Rebuild the bitmap
132140
BuildBitmap(true, true);
133141
}

Source/GUI/GUIListPanel.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ GUIListPanel::GUIListPanel(GUIManager* Manager) :
2626
m_CapturedHorz = false;
2727
m_CapturedVert = false;
2828
m_ExternalCapture = false;
29+
m_HighlightAsIfAlwaysFocused = false;
2930
m_HotTracking = false;
3031
m_HorzScrollEnabled = true;
3132
m_VertScrollEnabled = true;
@@ -55,6 +56,7 @@ GUIListPanel::GUIListPanel() :
5556
m_CapturedHorz = false;
5657
m_CapturedVert = false;
5758
m_ExternalCapture = false;
59+
m_HighlightAsIfAlwaysFocused = false;
5860
m_HotTracking = false;
5961
m_HorzScrollEnabled = true;
6062
m_VertScrollEnabled = true;
@@ -340,7 +342,7 @@ void GUIListPanel::BuildDrawBitmap() {
340342
}
341343

342344
// Selected item
343-
if (I->m_Selected && m_GotFocus) {
345+
if (I->m_Selected && (m_GotFocus || m_HighlightAsIfAlwaysFocused)) {
344346
m_DrawBitmap->DrawLine(4, itemY + 1, m_Width - (m_VertScroll->_GetVisible() ? m_VertScroll->GetWidth() + 2 : 5), itemY + 1, m_SelectedColorIndex);
345347
m_DrawBitmap->DrawLine(4, itemY + itemHeight, m_Width - (m_VertScroll->_GetVisible() ? m_VertScroll->GetWidth() + 2 : 5), itemY + itemHeight, m_SelectedColorIndex);
346348
m_Font->SetColor(m_FontSelectColor);
@@ -369,10 +371,10 @@ void GUIListPanel::BuildDrawBitmap() {
369371
// Selected item
370372
if (I->m_Selected) {
371373
m_Font->SetColor(m_SelectedColorIndex);
372-
m_DrawBitmap->DrawRectangle(1, itemY, itemWidth - 2, m_Font->GetFontHeight(), m_SelectedColorIndex, m_GotFocus); // Filled if we have focus
374+
m_DrawBitmap->DrawRectangle(1, itemY, itemWidth - 2, m_Font->GetFontHeight(), m_SelectedColorIndex, (m_GotFocus || m_HighlightAsIfAlwaysFocused)); // Filled if we have focus
373375
}
374376

375-
if (I->m_Selected && m_GotFocus) {
377+
if (I->m_Selected && (m_GotFocus || m_HighlightAsIfAlwaysFocused)) {
376378
m_Font->SetColor(m_FontSelectColor);
377379
m_Font->DrawAligned(m_DrawBitmap, itemX - 3 + itemWidth - (m_VertScroll->_GetVisible() ? m_VertScroll->GetWidth() : 0), itemY, I->m_RightText, GUIFont::Right);
378380
m_Font->Draw(m_DrawBitmap, 4 - itemX, itemY, I->m_Name);

Source/GUI/GUIListPanel.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ namespace RTE {
155155
/// Gets the multi-selection value.
156156
bool GetMultiSelect() const;
157157

158+
/// Sets the highlight as if always focused value.
159+
/// @param highlightAsIfAlwaysFocused Whether to highlight as if always focused.
160+
void SetHighlightAsIfAlwaysFocused(bool value) { m_HighlightAsIfAlwaysFocused = value; }
161+
162+
/// Gets the multi-selection value.
163+
/// @return Whether to highlight as if always selected.
164+
bool GetHighlightAsIfAlwaysFocused() const { return m_HighlightAsIfAlwaysFocused; }
165+
158166
/// Sets the hot tracking value.
159167
/// @param HotTrack HotTrack.
160168
void SetHotTracking(bool HotTrack);
@@ -295,6 +303,7 @@ namespace RTE {
295303
bool m_CapturedHorz;
296304
bool m_CapturedVert;
297305
bool m_ExternalCapture;
306+
bool m_HighlightAsIfAlwaysFocused; //!< Whether the panel should be highlighted as if it was always focused, even if it doesn't have focus.
298307

299308
int m_LargestWidth;
300309
bool m_MultiSelect;

Source/Menus/SaveLoadMenuGUI.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@ SaveLoadMenuGUI::SaveLoadMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiI
5959
m_SaveGamesListBox->SetMouseScrolling(true);
6060
m_SaveGamesListBox->SetScrollBarThickness(15);
6161
m_SaveGamesListBox->SetScrollBarPadding(2);
62+
m_SaveGamesListBox->SetHighlightAsIfAlwaysFocused(true);
6263

6364
m_SaveGameName = dynamic_cast<GUITextBox*>(m_GUIControlManager->GetControl("SaveGameName"));
6465
m_LoadButton = dynamic_cast<GUIButton*>(m_GUIControlManager->GetControl("ButtonLoad"));
6566
m_CreateButton = dynamic_cast<GUIButton*>(m_GUIControlManager->GetControl("ButtonCreate"));
6667
m_OverwriteButton = dynamic_cast<GUIButton*>(m_GUIControlManager->GetControl("ButtonOverwrite"));
6768
m_DeleteButton = dynamic_cast<GUIButton*>(m_GUIControlManager->GetControl("ButtonDelete"));
68-
m_ActivityCannotBeSavedLabel = dynamic_cast<GUILabel*>(m_GUIControlManager->GetControl("ActivityCannotBeSavedWarning"));
69+
m_DescriptionLabel = dynamic_cast<GUILabel*>(m_GUIControlManager->GetControl("DescriptionLabel"));
6970

7071
m_ConfirmationBox = dynamic_cast<GUICollectionBox*>(m_GUIControlManager->GetControl("ConfirmDialog"));
7172
m_ConfirmationBox->CenterInParent(true, true);
@@ -75,6 +76,8 @@ SaveLoadMenuGUI::SaveLoadMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiI
7576
m_CancelButton = dynamic_cast<GUIButton*>(m_GUIControlManager->GetControl("CancelButton"));
7677

7778
m_SaveGamesFetched = false;
79+
m_WasSaving = false;
80+
m_SavingBlinkTimer.SetRealTimeLimitS(1.5f);
7881

7982
SwitchToConfirmDialogMode(ConfirmDialogMode::None);
8083
}
@@ -85,7 +88,6 @@ void SaveLoadMenuGUI::PopulateSaveGamesList() {
8588
}
8689

8790
m_SaveGames.clear();
88-
m_SaveGameName->SetText("");
8991

9092
m_GUIControlManager->GetManager()->SetFocus(nullptr);
9193

@@ -253,8 +255,41 @@ void SaveLoadMenuGUI::UpdateButtonEnabledStates() {
253255

254256
m_LoadButton->SetEnabled(saveExists);
255257
m_DeleteButton->SetEnabled(saveExists);
258+
259+
m_DescriptionLabel->SetText("");
260+
261+
bool isSaving = g_ActivityMan.IsCurrentlySaving();
262+
if (isSaving != m_WasSaving) {
263+
m_SavingBlinkTimer.Reset();
264+
}
265+
266+
if (g_ActivityMan.GetActivity()) {
267+
if (isSaving) {
268+
const char* saveText = "";
269+
switch (m_SavingBlinkTimer.StepReal(500, 3)) {
270+
case 0:
271+
saveText = "Saving game, please wait. ";
272+
break;
273+
case 1:
274+
saveText = "Saving game, please wait.. ";
275+
break;
276+
case 2:
277+
saveText = "Saving game, please wait...";
278+
break;
279+
}
280+
281+
m_DescriptionLabel->SetText(saveText);
282+
} else if (!m_SavingBlinkTimer.IsPastRealTimeLimit()) {
283+
// Show "Saved!" for a little while after saving
284+
m_DescriptionLabel->SetText("Game saved successfully!");
285+
} else if (!g_ActivityMan.GetActivity()->GetAllowsUserSaving()) {
286+
m_DescriptionLabel->SetText("The currently played activity does not allow saving.");
287+
} else if (m_SaveGameName->GetText().empty()) {
288+
m_DescriptionLabel->SetText("Enter a name for your savegame.");
289+
}
290+
}
256291

257-
m_ActivityCannotBeSavedLabel->SetVisible(g_ActivityMan.GetActivity() && !g_ActivityMan.GetActivity()->GetAllowsUserSaving());
292+
m_WasSaving = isSaving;
258293
}
259294

260295
void SaveLoadMenuGUI::SwitchToConfirmDialogMode(ConfirmDialogMode mode) {

Source/Menus/SaveLoadMenuGUI.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "Timer.h"
4+
35
#include <filesystem>
46
#include <vector>
57
#include <string>
@@ -63,8 +65,11 @@ namespace RTE {
6365

6466
std::vector<SaveRecord> m_SaveGames; //!< Contains all SaveGames.
6567

68+
bool m_WasSaving; //!< Whether we were just saving or not.
6669
bool m_SaveGamesFetched; //!< Whether the savegames list has been fetched.
6770

71+
Timer m_SavingBlinkTimer; //!< Save text blink timer, to increment text (i.e "Saving...")
72+
6873
/// GUI elements that compose the Mod Manager menu screen.
6974
GUICollectionBox* m_SaveGameMenuBox;
7075
GUIButton* m_BackToMainButton;
@@ -74,7 +79,7 @@ namespace RTE {
7479
GUIButton* m_OverwriteButton;
7580
GUIButton* m_DeleteButton;
7681
GUIListBox* m_SaveGamesListBox;
77-
GUILabel* m_ActivityCannotBeSavedLabel;
82+
GUILabel* m_DescriptionLabel;
7883
GUIComboBox* m_OrderByComboBox;
7984

8085
// The confirmation box and its controls

Source/System/Timer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ namespace RTE {
144144
/// @param period An int with the alternating period in ms. The time specified here is how long it will take for the switch to alternate.
145145
/// @return Whether the elapsed time is in the first state or not.
146146
bool AlternateReal(int period) const { return (static_cast<int>(GetElapsedRealTimeMS()) % (period * 2)) > period; }
147+
148+
/// Returns an incrementing int, depending on whether the elapsed time falls in repeating intervals which divide it.
149+
/// This is useful for blink animations etc, for example ".", "..", "...", etc.
150+
/// @param period An int with the period in ms. The time specified here is how long it will take for the int to increment
151+
/// @param steps The number of steps to increment the int by. For example, if period is 1000 and steps is 5, then the int will increment every 200 ms.
152+
/// @return Whether the elapsed time is in the first state or not.
153+
int StepReal(int period, int steps) const {
154+
int elapsed = static_cast<int>(GetElapsedRealTimeMS());
155+
return (elapsed / period) % steps;
156+
}
147157
#pragma endregion
148158

149159
#pragma region Simulation Time

0 commit comments

Comments
 (0)