R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
SettingsMenu.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2026
3** r-type
4** File description:
5** SettingsMenu - Settings menu (business logic)
6*/
7
9#include <cstring>
10#include "../common/Logger/Logger.hpp"
11
12namespace Game {
14 : BaseMenu(uiFactory), _graphics(graphics) {
16 }
17
19 if (!_menu) {
20 return;
21 }
22
23 _menu->Clear();
24
25 const float buttonWidth = 360.0f;
26 const float buttonHeight = 50.0f;
27 const float spacing = 18.0f;
28
29 const bool showMainMenuButton = (_mode == Mode::OVERLAY);
30 const int buttonCount = showMainMenuButton ? 6 : 5;
31
32 // Center buttons vertically as a stack
33 const float totalHeight = (buttonHeight * static_cast<float>(buttonCount)) +
34 (spacing * static_cast<float>(buttonCount - 1));
35
36 auto offsetForIndex = [&](int idx) {
37 // idx in [0..buttonCount-1], centered stack
38 const float start = -(totalHeight / 2.0f) + (buttonHeight / 2.0f);
39 return start + (buttonHeight + spacing) * static_cast<float>(idx);
40 };
41
42 // Initialize volume slider (after offsetForIndex is defined)
43 const float sliderWidth = 300.0f;
44 const float sliderHeight = 20.0f;
45 const float sliderTopMargin = 120.0f; // Distance from top of screen
46
47 if (_volumeSlider) {
48 _volumeSlider->SetSize(sliderWidth, sliderHeight);
49 _volumeSlider->SetMinValue(0.0f);
50 _volumeSlider->SetMaxValue(100.0f);
51 _volumeSlider->SetValue(_volume);
52 _volumeSlider->SetTrackColor(0xFF505050);
53 _volumeSlider->SetFilledColor(0xFF4CAF50);
54 _volumeSlider->SetHandleColor(0xFFFFFFFF);
55 _volumeSlider->SetHandleHoverColor(0xFFE0E0E0);
57 _volumeSlider->ApplyAlignment();
58
59 // Position slider at fixed position from top of screen
60 float sliderX, sliderY;
61 _volumeSlider->GetPosition(sliderX, sliderY);
62 _volumeSlider->SetPosition(sliderX, sliderTopMargin);
63
64 _volumeSlider->SetOnValueChanged([this](float value) {
65 _volume = value;
66 LOG_INFO("[SettingsMenu] Volume changed: ", static_cast<int>(value), "%");
67 if (_onVolumeChanged) {
68 _onVolumeChanged(value);
69 }
70 });
71 }
72
73 // Toggle Ping button
74 _menu->AddButton(CreateCenteredButton("PING: ON", offsetForIndex(0), buttonWidth, buttonHeight,
75 0xFF424242, 0xFF616161, [this]() { SetShowPing(!_showPing); }));
76
77 // Toggle FPS display button
78 _menu->AddButton(CreateCenteredButton("FPS: ON", offsetForIndex(1), buttonWidth, buttonHeight,
79 0xFF424242, 0xFF616161, [this]() { SetShowFps(!_showFps); }));
80
81 // Toggle Chat button
82 _menu->AddButton(CreateCenteredButton("CHAT: ON", offsetForIndex(2), buttonWidth, buttonHeight,
83 0xFF424242, 0xFF616161, [this]() { SetShowChat(!_showChat); }));
84
85 // Toggle Auto-Matchmaking button
86 _menu->AddButton(CreateCenteredButton("AUTO-MM: OFF", offsetForIndex(3), buttonWidth, buttonHeight,
87 0xFF424242, 0xFF616161,
88 [this]() { SetAutoMatchmaking(!_autoMatchmaking); }));
89
90 // Target FPS selection button (cycles)
91 _menu->AddButton(CreateCenteredButton("TARGET FPS: 60", offsetForIndex(4), buttonWidth, buttonHeight,
92 0xFF424242, 0xFF616161,
93 [this]() { SetTargetFps(NextTargetFps(_targetFps)); }));
94
95 // Accessibility button
96 _menu->AddButton(CreateCenteredButton("ACCESSIBILITY", offsetForIndex(4), buttonWidth, buttonHeight,
97 0xFF6A1B9A, 0xFF8E24AA, [this]() {
98 if (_onAccessibility) {
100 }
101 }));
102
103 // Back (closes settings)
104 _menu->AddButton(CreateCenteredButton("BACK", offsetForIndex(5), buttonWidth, buttonHeight,
105 0xFF1976D2, 0xFF1E88E5, [this]() {
106 if (_onBack) {
107 _onBack();
108 } else {
109 Hide();
110 }
111 }));
112
113 // Main menu (only in overlay)
114 if (showMainMenuButton) {
115 _menu->AddButton(CreateCenteredButton("MAIN MENU", offsetForIndex(6), buttonWidth, buttonHeight,
116 0xFF5D4037, 0xFF6D4C41, [this]() {
117 if (_onMainMenu) {
118 _onMainMenu();
119 }
120 }));
121 }
122
124 }
125
128 if (_volumeSlider && _menu && _menu->IsVisible()) {
129 _volumeSlider->Update();
130 }
131 }
132
134 if (!_menu || !_menu->IsVisible()) {
135 return;
136 }
137
138 // Draw volume settings section
139 if (_volumeSlider) {
140 float sliderX, sliderY;
141 _volumeSlider->GetPosition(sliderX, sliderY);
142
143 int screenWidth = _graphics.GetScreenWidth();
144
145 // Draw "VOLUME SETTINGS" title at the very top
146 const char *title = "VOLUME SETTINGS";
147 int titleFontSize = 24;
148 int titleWidth = static_cast<int>(strlen(title) * titleFontSize * 0.6f);
149 int titleX = (screenWidth - titleWidth) / 2;
150 int titleY = static_cast<int>(sliderY) - 65; // Above the "VOLUME:" label
151
152 _graphics.DrawText(title, titleX, titleY, titleFontSize, 0xFF4CAF50); // Green color
153
154 // Draw "VOLUME:" label above slider
155 const char *label = "VOLUME:";
156 int fontSize = 18;
157 int labelWidth = static_cast<int>(strlen(label) * fontSize * 0.6f);
158 int labelX = (screenWidth - labelWidth) / 2;
159 int labelY = static_cast<int>(sliderY) - 30; // Closer to slider
160
161 _graphics.DrawText(label, labelX, labelY, fontSize, 0xFFFFFFFF);
162
163 // Draw volume percentage below slider
164 int volumePercent = static_cast<int>(_volume);
165 std::string valueText = std::to_string(volumePercent) + "%";
166 int valueWidth = static_cast<int>(valueText.length() * fontSize * 0.6f);
167 int valueX = (screenWidth - valueWidth) / 2;
168 int valueY = static_cast<int>(sliderY) + 30;
169
170 _graphics.DrawText(valueText.c_str(), valueX, valueY, fontSize, 0xFFFFFFFF);
171
172 // Render slider
173 _volumeSlider->Render();
174 }
175
177 }
178
180 _mode = mode;
181 }
182
184 return _mode;
185 }
186
187 void SettingsMenu::SetShowPing(bool enabled) {
188 _showPing = enabled;
190 if (_onShowPingChanged) {
192 }
193 LOG_INFO("[SettingsMenu] showPing=", _showPing ? "true" : "false");
194 }
195
197 return _showPing;
198 }
199
200 void SettingsMenu::SetOnShowPingChanged(std::function<void(bool)> cb) {
201 _onShowPingChanged = std::move(cb);
202 }
203
204 void SettingsMenu::SetOnBack(std::function<void()> cb) {
205 _onBack = std::move(cb);
206 }
207
208 void SettingsMenu::SetOnMainMenu(std::function<void()> cb) {
209 _onMainMenu = std::move(cb);
210 }
211
212 void SettingsMenu::SetOnAccessibility(std::function<void()> cb) {
213 _onAccessibility = std::move(cb);
214 }
215
216 void SettingsMenu::SetShowFps(bool enabled) {
217 _showFps = enabled;
219 if (_onShowFpsChanged) {
221 }
222 LOG_INFO("[SettingsMenu] showFps=", _showFps ? "true" : "false");
223 }
224
226 return _showFps;
227 }
228
229 void SettingsMenu::SetOnShowFpsChanged(std::function<void(bool)> cb) {
230 _onShowFpsChanged = std::move(cb);
231 }
232
233 uint32_t SettingsMenu::NextTargetFps(uint32_t current) const {
234 switch (current) {
235 case 30:
236 return 60;
237 case 60:
238 return 120;
239 case 120:
240 return 144;
241 case 144:
242 return 240;
243 default:
244 return 30;
245 }
246 }
247
248 uint32_t SettingsMenu::ValidateTargetFps(uint32_t targetFps) const {
249 switch (targetFps) {
250 case 30:
251 case 60:
252 case 120:
253 case 144:
254 case 240:
255 return targetFps;
256 default:
257 return 60;
258 }
259 }
260
268
270 _showPing = enabled;
272 }
273
275 _showFps = enabled;
277 }
278
279 void SettingsMenu::SetTargetFpsSilent(uint32_t targetFps) {
280 _targetFps = ValidateTargetFps(targetFps);
282 }
283
284 void SettingsMenu::SetTargetFps(uint32_t targetFps) {
285 _targetFps = ValidateTargetFps(targetFps);
286
290 }
291 LOG_INFO("[SettingsMenu] targetFps=", _targetFps);
292 }
293
294 uint32_t SettingsMenu::GetTargetFps() const {
295 return _targetFps;
296 }
297
298 void SettingsMenu::SetOnTargetFpsChanged(std::function<void(uint32_t)> callback) {
299 _onTargetFpsChanged = std::move(callback);
300 }
301
303 if (!_menu) {
304 return;
305 }
306 auto toggleBtn = _menu->GetButton(TOGGLE_PING_INDEX);
307 if (!toggleBtn) {
308 return;
309 }
310
311 if (_showPing) {
312 toggleBtn->SetText("PING: ON");
313 toggleBtn->SetBackgroundColor(0xFF2E7D32);
314 toggleBtn->SetHoverColor(0xFF388E3C);
315 } else {
316 toggleBtn->SetText("PING: OFF");
317 toggleBtn->SetBackgroundColor(0xFFB71C1C);
318 toggleBtn->SetHoverColor(0xFFD32F2F);
319 }
320 toggleBtn->SetTextColor(0xFFFFFFFF);
321 }
322
324 if (!_menu) {
325 return;
326 }
327 auto toggleBtn = _menu->GetButton(TOGGLE_FPS_INDEX);
328 if (!toggleBtn) {
329 return;
330 }
331
332 if (_showFps) {
333 toggleBtn->SetText("FPS: ON");
334 toggleBtn->SetBackgroundColor(0xFF2E7D32);
335 toggleBtn->SetHoverColor(0xFF388E3C);
336 } else {
337 toggleBtn->SetText("FPS: OFF");
338 toggleBtn->SetBackgroundColor(0xFFB71C1C);
339 toggleBtn->SetHoverColor(0xFFD32F2F);
340 }
341 toggleBtn->SetTextColor(0xFFFFFFFF);
342 }
343
345 if (!_menu) {
346 return;
347 }
348 auto targetBtn = _menu->GetButton(TARGET_FPS_INDEX);
349 if (!targetBtn) {
350 return;
351 }
352
353 targetBtn->SetText("TARGET FPS: " + std::to_string(_targetFps));
354 targetBtn->SetBackgroundColor(0xFF424242);
355 targetBtn->SetHoverColor(0xFF616161);
356 targetBtn->SetTextColor(0xFFFFFFFF);
357 }
358
359 void SettingsMenu::SetOverlayDimColor(unsigned int color) {
360 _overlayDimColor = color;
361 }
362
363 unsigned int SettingsMenu::GetOverlayDimColor() const {
364 return _overlayDimColor;
365 }
366
368 return _mode == Mode::OVERLAY && IsVisible();
369 }
370
371 void SettingsMenu::SetVolume(float volume) {
372 _volume = std::max(0.0f, std::min(100.0f, volume));
373 if (_volumeSlider) {
374 _volumeSlider->SetValue(_volume);
375 }
376 LOG_INFO("[SettingsMenu] Volume set to: ", static_cast<int>(_volume), "%");
377 if (_onVolumeChanged) {
379 }
380 }
381
383 return _volume;
384 }
385
386 void SettingsMenu::SetOnVolumeChanged(std::function<void(float)> callback) {
387 _onVolumeChanged = std::move(callback);
388 }
389
390 void SettingsMenu::SetVolumeSilent(float volume) {
391 _volume = std::max(0.0f, std::min(100.0f, volume));
392 if (_volumeSlider) {
393 _volumeSlider->SetValue(_volume);
394 }
395 }
396
397 void SettingsMenu::SetShowChat(bool enabled) {
398 _showChat = enabled;
400 if (_onShowChatChanged) {
402 }
403 LOG_INFO("[SettingsMenu] showChat=", _showChat ? "true" : "false");
404 }
405
407 return _showChat;
408 }
409
410 void SettingsMenu::SetOnShowChatChanged(std::function<void(bool)> cb) {
411 _onShowChatChanged = std::move(cb);
412 }
413
415 _showChat = enabled;
417 }
418
420 if (!_menu) {
421 return;
422 }
423 auto toggleBtn = _menu->GetButton(TOGGLE_CHAT_INDEX);
424 if (!toggleBtn) {
425 return;
426 }
427
428 if (_showChat) {
429 toggleBtn->SetText("CHAT: ON");
430 toggleBtn->SetBackgroundColor(0xFF2E7D32);
431 toggleBtn->SetHoverColor(0xFF388E3C);
432 } else {
433 toggleBtn->SetText("CHAT: OFF");
434 toggleBtn->SetBackgroundColor(0xFFB71C1C);
435 toggleBtn->SetHoverColor(0xFFD32F2F);
436 }
437 toggleBtn->SetTextColor(0xFFFFFFFF);
438 }
439
441 _autoMatchmaking = enabled;
445 }
446 LOG_INFO("[SettingsMenu] Auto-matchmaking=", _autoMatchmaking ? "true" : "false",
447 " (notifying server)");
448 }
449
451 // Apply preference silently without triggering callback
452 // This is used when loading preference from server after login
453 _autoMatchmaking = enabled;
455 LOG_INFO("[SettingsMenu] Auto-matchmaking preference applied from server: ",
456 _autoMatchmaking ? "ON" : "OFF", " (no server notification)");
457 }
458
460 return _autoMatchmaking;
461 }
462
463 void SettingsMenu::SetOnAutoMatchmakingChanged(std::function<void(bool)> cb) {
464 _onAutoMatchmakingChanged = std::move(cb);
465 }
466
468 if (!_menu) {
469 return;
470 }
471 auto toggleBtn = _menu->GetButton(AUTO_MATCHMAKING_INDEX);
472 if (!toggleBtn) {
473 return;
474 }
475
476 if (_autoMatchmaking) {
477 toggleBtn->SetText("AUTO-MM: ON");
478 toggleBtn->SetBackgroundColor(0xFF2E7D32);
479 toggleBtn->SetHoverColor(0xFF388E3C);
480 } else {
481 toggleBtn->SetText("AUTO-MM: OFF");
482 toggleBtn->SetBackgroundColor(0xFFB71C1C);
483 toggleBtn->SetHoverColor(0xFFD32F2F);
484 }
485 toggleBtn->SetTextColor(0xFFFFFFFF);
486 }
487} // namespace Game
#define LOG_INFO(...)
Definition Logger.hpp:181
Base class for all menu implementations.
Definition BaseMenu.hpp:26
virtual void Update()
Update menu state (should be called every frame).
Definition BaseMenu.cpp:16
std::shared_ptr< UI::IMenu > _menu
Definition BaseMenu.hpp:101
std::shared_ptr< UI::IButton > CreateCenteredButton(const char *label, float offsetY, float width, float height, unsigned int backgroundColor, unsigned int hoverColor, std::function< void()> callback)
Create a button with standard styling and positioning.
Definition BaseMenu.cpp:60
virtual void Render()
Render menu (should be called every frame).
Definition BaseMenu.cpp:22
virtual void Hide()
Hide the menu.
Definition BaseMenu.cpp:34
virtual bool IsVisible() const
Check if menu is currently visible.
Definition BaseMenu.cpp:40
UI::IUIFactory & _uiFactory
Definition BaseMenu.hpp:100
void SetShowFps(bool enabled)
Toggle whether FPS should be displayed.
void Initialize() override
Initialize UI elements.
void SetTargetFpsSilent(uint32_t targetFps)
Set targetFps without emitting callbacks/logs.
void SetOnShowFpsChanged(std::function< void(bool)> cb)
Set callback invoked when the FPS toggle changes.
bool GetShowPing() const
bool GetAutoMatchmaking() const
void SetShowChat(bool enabled)
Set chat visibility.
uint32_t GetTargetFps() const
Get the target FPS for the client.
void SetTargetFps(uint32_t targetFps)
Set the target FPS for the client.
void SetAutoMatchmaking(bool enabled)
Toggle auto-matchmaking feature. This triggers the callback to notify the server.
std::function< void(bool)> _onAutoMatchmakingChanged
unsigned int GetOverlayDimColor() const
Get the dim color used when this menu is displayed in overlay mode.
void SetOverlayDimColor(unsigned int color)
Set the dim color used when this menu is displayed in overlay mode.
std::function< void(bool)> _onShowPingChanged
void SetShowPingSilent(bool enabled)
Set showPing without emitting callbacks/logs.
SettingsMenu(UI::IUIFactory &uiFactory, Graphics::IGraphics &graphics)
Construct a new SettingsMenu.
static constexpr size_t AUTO_MATCHMAKING_INDEX
void SetShowPing(bool enabled)
Toggle whether ping should be displayed.
bool GetShowChat() const
Get chat visibility.
void SetShowChatSilent(bool enabled)
Set chat visibility without emitting callbacks/logs.
void UpdateAutoMatchmakingVisuals()
unsigned int _overlayDimColor
void RefreshVisuals()
Refresh button labels/colors to match current internal state.
Graphics::IGraphics & _graphics
void SetVolume(float volume)
Set the volume level (0-100).
void SetVolumeSilent(float volume)
Set volume without emitting callbacks/logs.
void SetMode(Mode mode)
Set display mode (fullscreen or overlay).
static constexpr size_t TOGGLE_FPS_INDEX
static constexpr size_t TOGGLE_PING_INDEX
void SetOnShowPingChanged(std::function< void(bool)> cb)
Set callback invoked when the ping toggle changes.
std::unique_ptr< UI::ISlider > _volumeSlider
std::function< void()> _onMainMenu
float GetVolume() const
Get the current volume level.
void SetOnShowChatChanged(std::function< void(bool)> cb)
Set callback invoked when the chat visibility changes.
void UpdateChatToggleVisuals()
Updates the visuals of the chat toggle button.
void Render() override
Render menu (should be called every frame).
void ApplyAutoMatchmakingPreference(bool enabled)
Apply auto-matchmaking preference silently (without triggering callback). Used when loading preferenc...
uint32_t NextTargetFps(uint32_t current) const
static constexpr size_t TARGET_FPS_INDEX
void SetShowFpsSilent(bool enabled)
Set showFps without emitting callbacks/logs.
uint32_t ValidateTargetFps(uint32_t targetFps) const
void SetOnTargetFpsChanged(std::function< void(uint32_t)> callback)
Set callback invoked when the target FPS changes.
std::function< void()> _onAccessibility
void SetOnAutoMatchmakingChanged(std::function< void(bool)> cb)
void SetOnAccessibility(std::function< void()> cb)
Set callback invoked when "Accessibility" button is clicked.
void Update() override
Update menu state (should be called every frame).
std::function< void(bool)> _onShowFpsChanged
bool ShouldDimBackground() const
Whether the background should be dimmed when the menu is visible.
void SetOnBack(std::function< void()> cb)
Set callback invoked when Back is clicked.
std::function< void()> _onBack
Mode
Display mode for the settings menu.
@ OVERLAY
Displays over the game with a dimmed background.
bool GetShowFps() const
static constexpr size_t TOGGLE_CHAT_INDEX
std::function< void(uint32_t)> _onTargetFpsChanged
std::function< void(bool)> _onShowChatChanged
void SetOnVolumeChanged(std::function< void(float)> callback)
Set callback invoked when the volume changes.
std::function< void(float)> _onVolumeChanged
void SetOnMainMenu(std::function< void()> cb)
Set callback invoked when "Main Menu" is clicked.
Abstract interface for graphics rendering operations.
Definition IGraphics.hpp:32
virtual void DrawText(int fontHandle, const char *text, int x, int y, int fontSize, unsigned int color)=0
Draw text using a loaded font.
virtual int GetScreenWidth() const =0
Get the screen width (same as window width)
Abstract factory interface for creating UI elements.
virtual std::unique_ptr< ISlider > CreateSlider()=0
Create a slider instance.
@ CENTER_HORIZONTAL
Center on the X axis.