Skip to content

Commit 08f16b5

Browse files
committed
Added scrolling to strings in buttons to prevent overflow.
1 parent 0f3540e commit 08f16b5

File tree

6 files changed

+108
-53
lines changed

6 files changed

+108
-53
lines changed

source/game/menu/level_complete_menu.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66
// Initialise the menu.
77

88
LevelCompleteMenu::LevelCompleteMenu(int index, std::string_view name)
9-
: Menu(3),
10-
completedIndex(index)
9+
: completedIndex(index)
1110
{
12-
AddWidget(0.0f, 1.25f, 1, nullptr, Level::FormatName(std::string(name)) + '\n' + Level::TimeToString(pLevel->GetTime()), 0.0f);
11+
std::string text[2] = {Level::FormatName(std::string(name)), Level::TimeToString(pLevel->GetTime())};
12+
AddLargeButton(0.0f, 1.25f, nullptr, text, 0.0f);
1313

1414
bool hasNext = (index < levelCount - 1);
1515

1616
if (hasNext)
1717
{
18-
AddWidget(0.0f, -0.5f, 0, std::bind(&LevelCompleteMenu::OnPressNext, this), "Next");
18+
AddSmallButton(0.0f, -0.5f, std::bind(&LevelCompleteMenu::OnPressNext, this), "Next", 0.5f);
1919
}
2020

21-
AddWidget(0.0f, hasNext ? -1.75f : -0.5f, 0, std::bind(&LevelCompleteMenu::OnPressRetry, this), "Retry");
22-
AddWidget(0.0f, hasNext ? -3.0f : -1.75f, 0, std::bind(&LevelCompleteMenu::OnPressQuit, this), "Quit");
21+
AddSmallButton(0.0f, hasNext ? -1.75f : -0.5f, std::bind(&LevelCompleteMenu::OnPressRetry, this), "Retry", 0.5f);
22+
AddSmallButton(0.0f, hasNext ? -3.0f : -1.75f, std::bind(&LevelCompleteMenu::OnPressQuit, this), "Quit", 0.5f);
2323
}
2424

2525
// Press next callback.

source/game/menu/level_select_menu.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
// Initialise the menu.
99

1010
LevelSelectMenu::LevelSelectMenu()
11-
: Menu(13),
12-
currentPage(0)
11+
: currentPage(0)
1312
{
1413
levels.reserve(levelCount);
1514

@@ -94,13 +93,13 @@ void LevelSelectMenu::RefreshMenu()
9493

9594
std::string pageText = "Page " + std::to_string(currentPage + 1) + " of " + std::to_string(totalPages);
9695

97-
AddWidget(-6.25f, 4.25f, 2, nullptr, std::move(pageText), 0.0f);
96+
AddString(-6.25f, 4.25f, pageText, 0.0f);
9897

9998
// Navigation buttons.
10099

101-
AddWidget(-4.25f, -4.25f, 0, std::bind(&LevelSelectMenu::OnPressBack, this), "Back");
102-
AddWidget( 0.0f, -4.25f, 0, std::bind(&LevelSelectMenu::OnPressPrevious, this), "Previous");
103-
AddWidget( 4.25f, -4.25f, 0, std::bind(&LevelSelectMenu::OnPressNext, this), "Next");
100+
AddSmallButton(-4.25f, -4.25f, std::bind(&LevelSelectMenu::OnPressBack, this), "Back", 0.5f);
101+
AddSmallButton( 0.0f, -4.25f, std::bind(&LevelSelectMenu::OnPressPrevious, this), "Previous", 0.5f);
102+
AddSmallButton( 4.25f, -4.25f, std::bind(&LevelSelectMenu::OnPressNext, this), "Next", 0.5f);
104103

105104
// Generate the level list.
106105

@@ -113,23 +112,23 @@ void LevelSelectMenu::RefreshMenu()
113112
float y = (float) (i / 3 - 1) * -2.25f;
114113

115114
std::string name = levels[beginning + i];
116-
std::string text = Level::FormatName(name) + '\n';
115+
std::string text[2] = {Level::FormatName(name), ""};
117116

118117
// Level status.
119118

120119
if (pSave->IsLevelCompleted(name))
121120
{
122-
text += Level::TimeToString(pSave->GetLevelTime(name));
121+
text[1] = Level::TimeToString(pSave->GetLevelTime(name));
123122
}
124123
else if (pSave->IsLevelUnlocked(name))
125124
{
126-
text += "No time";
125+
text[1] = "No time";
127126
}
128127
else
129128
{
130-
text += "Locked";
129+
text[1] = "Locked";
131130
}
132131

133-
AddWidget(x, y, 1, std::bind(&LevelSelectMenu::OnSelectLevel, this, i), std::move(text), 0.0f);
132+
AddLargeButton(x, y, std::bind(&LevelSelectMenu::OnSelectLevel, this, i), text, 0.0f);
134133
}
135134
}

source/game/menu/main_menu.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
// Initialise the menu.
66

77
MainMenu::MainMenu()
8-
: Menu(3)
98
{
10-
AddWidget(0.0f, 1.25f, 2, nullptr, "MAN OF DESTRUCTION");
9+
AddString(0.0f, 1.25f, "MAN OF DESTRUCTION", 0.5f);
1110

12-
AddWidget(0.0f, 0.0f, 0, std::bind(&MainMenu::OnPressPlay, this), "Play");
13-
AddWidget(0.0f, -1.25f, 0, std::bind(&MainMenu::OnPressQuit, this), "Quit");
11+
AddSmallButton(0.0f, 0.0f, std::bind(&MainMenu::OnPressPlay, this), "Play", 0.5f);
12+
AddSmallButton(0.0f, -1.25f, std::bind(&MainMenu::OnPressQuit, this), "Quit", 0.5f);
1413
}
1514

1615
// Press play callback.

source/game/menu/menu.cpp

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,11 @@ std::shared_ptr<Menu> pMenu;
88

99
// Initialise the menu.
1010

11-
Menu::Menu(int widgetCount)
11+
Menu::Menu()
1212
: hoveredWidget(-1), sprites(), hoverSound(), pressSound()
1313
{
1414
pMenu.reset(this);
1515

16-
widgets.reserve(widgetCount);
17-
18-
// Register the widget types.
19-
20-
widgetTypes[0] = {vector2f(4.0f, 1.0f), 0}; // Small button.
21-
widgetTypes[1] = {vector2f(4.0f, 2.0f), 2}; // Big button.
22-
widgetTypes[2] = {vector2f(0.0f, 1.0f), -1}; // String.
23-
2416
// Load the necessary resources.
2517

2618
SpriteSheet sheet = pRenderer->GetSheet("assets/sprites/widget/widget.bmp");
@@ -69,6 +61,23 @@ void Menu::Update(float delta)
6961
pSoundMixer->PlaySound(pressSound);
7062
pOnEscape();
7163
}
64+
65+
// Scroll the string widgets.
66+
67+
for (Widget& widget : widgets)
68+
{
69+
int stringLength = (int) widget.string.length();
70+
71+
if (widget.type == STRING && widget.maxLength != 0 && stringLength > widget.maxLength)
72+
{
73+
widget.scrollTime += delta * 2.0f;
74+
75+
if (widget.scrollTime >= (float) (stringLength - widget.maxLength + 1))
76+
{
77+
widget.scrollTime = 0.0f;
78+
}
79+
}
80+
}
7281
}
7382

7483
// Render the menu.
@@ -85,7 +94,7 @@ void Menu::Render() const
8594

8695
// Draw the widget's sprite if applicable.
8796

88-
if (widget.spriteIndex >= 0)
97+
if (widget.type == BUTTON)
8998
{
9099
const Sprite& sprite = sprites[i == hoveredWidget ? widget.spriteIndex + 1 : widget.spriteIndex];
91100

@@ -94,24 +103,64 @@ void Menu::Render() const
94103

95104
// Draw the widget's string.
96105

97-
float x = widget.position.x + Clamp(widget.bounds.x * widget.alignment, 0.25f, widget.bounds.x - 0.25f);
98-
float y = widget.position.y + widget.bounds.y - 0.25f;
106+
else
107+
{
108+
std::string string = widget.maxLength == 0 ? widget.string : widget.string.substr((int) widget.scrollTime, widget.maxLength);
109+
float x = widget.position.x + Clamp(widget.bounds.x * widget.alignment, 0.25f, widget.bounds.x - 0.25f);
110+
float y = widget.position.y + widget.bounds.y;
99111

100-
pRenderer->DrawString(widget.text, x, y, 4.0f, widget.alignment);
112+
pRenderer->DrawString(string, x, y, 4.0f, widget.alignment);
113+
}
101114
}
102115
}
103116

104-
// Add a widget to the menu;
105-
// Alignment: 0.0 = left, 0.5 = centred, 1.0 = right.
117+
// Add a small button with a one-line string.
106118

107-
void Menu::AddWidget(float x, float y, int type, std::function<void(int)> pOnPress, std::string text, float alignment)
119+
void Menu::AddSmallButton(float x, float y, std::function<void(int)> pOnPress, std::string string, float alignment)
108120
{
109-
vector2f bounds = widgetTypes[type].bounds;
110121
vector2f position(x, y);
122+
vector2f bounds(4.0f, 1.0f);
123+
124+
widgets.reserve(2);
111125

112126
position -= bounds * 0.5f;
127+
widgets.push_back({BUTTON, position, bounds, std::move(pOnPress), 0, "", 0.0f, 0.0f, 0});
128+
129+
// One line of text.
130+
131+
position.y -= 0.25f;
132+
widgets.push_back({STRING, position, bounds, nullptr, 0, std::move(string), alignment, 0.0f, 9});
133+
}
134+
135+
// Add a large button with a two-line string.
136+
137+
void Menu::AddLargeButton(float x, float y, std::function<void(int)> pOnPress, std::string string[2], float alignment)
138+
{
139+
vector2f position(x, y);
140+
vector2f bounds(4.0f, 2.0f);
141+
142+
widgets.reserve(3);
143+
144+
position -= bounds * 0.5f;
145+
widgets.push_back({BUTTON, position, bounds, std::move(pOnPress), 2, "", 0.0f, 0.0f, 0});
146+
147+
// Two lines of text.
148+
149+
position.y -= 0.375f;
150+
widgets.push_back({STRING, position, bounds, nullptr, 0, std::move(string[0]), alignment, 0.0f, 9});
151+
152+
position.y -= 0.75f;
153+
widgets.push_back({STRING, position, bounds, nullptr, 0, std::move(string[1]), alignment, 0.0f, 9});
154+
}
155+
156+
// Add a string widget.
157+
158+
void Menu::AddString(float x, float y, std::string string, float alignment)
159+
{
160+
vector2f position(x, y - 0.25f);
161+
vector2f bounds(0.0f, 1.0f);
113162

114-
widgets.push_back({position, bounds, widgetTypes[type].spriteIndex, std::move(text), alignment, std::move(pOnPress)});
163+
widgets.push_back({STRING, position, bounds, nullptr, 0, std::move(string), alignment, 0.0f, 0});
115164
}
116165

117166
// Clear the menu widgets.

source/game/menu/menu.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,48 @@
77
#include <string>
88
#include <vector>
99

10-
struct WidgetType
10+
enum WidgetType
1111
{
12-
vector2f bounds;
13-
14-
int spriteIndex;
12+
BUTTON,
13+
STRING
1514
};
1615

1716
struct Widget
1817
{
18+
WidgetType type;
1919
vector2f position;
2020
vector2f bounds;
2121

22-
int spriteIndex;
23-
std::string text;
24-
float alignment;
22+
// Button widget.
2523

2624
std::function<void(int)> pOnPress;
25+
26+
int spriteIndex;
27+
28+
// String widget.
29+
30+
std::string string;
31+
32+
float alignment;
33+
float scrollTime;
34+
int maxLength;
2735
};
2836

2937
extern std::shared_ptr<class Menu> pMenu;
3038

3139
class Menu
3240
{
3341
public:
34-
Menu(int widgetCount);
42+
Menu();
3543
virtual ~Menu() = default;
3644

3745
void Update(float delta);
3846
void Render() const;
3947

4048
protected:
41-
void AddWidget(float x, float y, int type, std::function<void(int)> pOnPress, std::string text, float alignment = 0.5f);
49+
void AddSmallButton(float x, float y, std::function<void(int)> pOnPress, std::string string, float alignment);
50+
void AddLargeButton(float x, float y, std::function<void(int)> pOnPress, std::string string[2], float alignment);
51+
void AddString(float x, float y, std::string string, float alignment);
4252
void ClearWidgets();
4353
void SetEscapeCallback(std::function<void()> pCallback);
4454

@@ -51,7 +61,6 @@ class Menu
5161

5262
protected:
5363
std::vector<Widget> widgets;
54-
WidgetType widgetTypes[3];
5564
std::function<void()> pOnEscape;
5665

5766
int hoveredWidget;

source/game/menu/pause_menu.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
// Initialise the menu.
77

88
PauseMenu::PauseMenu()
9-
: Menu(3)
109
{
11-
AddWidget(0.0f, 1.25f, 0, std::bind(&PauseMenu::OnPressResume, this), "Resume");
12-
AddWidget(0.0f, 0.0f, 0, std::bind(&PauseMenu::OnPressRetry, this), "Retry");
13-
AddWidget(0.0f, -1.25f, 0, std::bind(&PauseMenu::OnPressQuit, this), "Quit");
10+
AddSmallButton(0.0f, 1.25f, std::bind(&PauseMenu::OnPressResume, this), "Resume", 0.5f);
11+
AddSmallButton(0.0f, 0.0f, std::bind(&PauseMenu::OnPressRetry, this), "Retry", 0.5f);
12+
AddSmallButton(0.0f, -1.25f, std::bind(&PauseMenu::OnPressQuit, this), "Quit", 0.5f);
1413

1514
// Pressing escape resumes the game.
1615

0 commit comments

Comments
 (0)