R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
LoginMenu.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2026
3** r-type
4** File description:
5** LoginMenu.cpp
6*/
7
8#include "LoginMenu.hpp"
9#include "UI/TextUtils.hpp" // For text measurement if needed
10#include "raylib.h" // For KEY_TAB, KEY_ENTER
11
12namespace Game {
13
15 : BaseMenu(uiFactory), _graphics(graphics) {}
16
17 void LoginMenu::SetOnBack(std::function<void()> onBack) {
18 _onBack = std::move(onBack);
19 }
20
22 if (!_menu) {
23 return;
24 }
25 _menu->Clear();
26
27 const float startY = _graphics.GetScreenHeight() / 2.0f - 100.0f;
28 float currentY = startY;
29
30 // --- Username Input ---
34 _usernameInput->ApplyAlignment();
35
36 float x, y;
37 _usernameInput->GetPosition(x, y);
38 _usernameInput->SetPosition(x, currentY);
39
40 _usernameInput->SetPlaceholder("Username");
41 _usernameInput->SetMaxLength(20);
42 _usernameInput->SetValidationRegex("[a-zA-Z0-9_-]+");
43 _usernameInput->SetBackgroundColor(0xFFFFFFFF);
44 _usernameInput->SetBorderColor(0xFF808080);
45 _usernameInput->SetActiveBorderColor(0xFF0000FF); // Blue when active
46 _usernameInput->SetTextColor(0xFF000000);
47 _usernameInput->SetPlaceholderColor(0xFF808080);
48
49 currentY += INPUT_HEIGHT + SPACING;
50
51 // --- Password Input ---
55 _passwordInput->ApplyAlignment();
56
57 _passwordInput->GetPosition(x, y);
58 _passwordInput->SetPosition(x, currentY);
59
60 _passwordInput->SetPlaceholder("Password");
61 _passwordInput->SetMaxLength(20);
62 _passwordInput->SetPasswordMode(true); // Mask password characters with asterisks
63 _passwordInput->SetValidationRegex("[a-zA-Z0-9_-]+");
64
65 _passwordInput->SetBackgroundColor(0xFFFFFFFF);
66 _passwordInput->SetBorderColor(0xFF808080);
67 _passwordInput->SetActiveBorderColor(0xFF0000FF);
68 _passwordInput->SetTextColor(0xFF000000);
69 _passwordInput->SetPlaceholderColor(0xFF808080);
70
71 currentY += INPUT_HEIGHT + SPACING * 2.0f;
72
73 // --- Buttons ---
74 const float btnWidth = 100.0f;
75 const float btnHeight = 40.0f;
76 const float btnSpacing = 10.0f;
77
78 // Helper to place buttons horizontally centered
79 auto createBtn = [&](const char *label, float xOffset, unsigned int color, unsigned int hover,
80 auto cb) {
81 // Convert unique_ptr to shared_ptr explicitly for IMenu::AddButton
82 std::shared_ptr<UI::IButton> btn = _uiFactory.CreateButton();
83
84 btn->SetSize(btnWidth, btnHeight);
85 btn->SetAlign(UI::Align::CENTER_HORIZONTAL);
86 btn->ApplyAlignment();
87
88 float bx, by;
89 btn->GetPosition(bx, by);
90 // xOffset is relative to center
91 btn->SetPosition(bx + xOffset, currentY);
92
93 btn->SetText(label);
94 btn->SetBackgroundColor(color);
95 btn->SetHoverColor(hover);
96 btn->SetTextColor(0xFFFFFFFF);
97 btn->SetCallback(WrapWithClickSound(cb));
98
99 _menu->AddButton(btn);
100 };
101
102 // Login (Left)
103 createBtn("LOGIN", -(btnWidth + btnSpacing), 0xFF006400, 0xFF008000, [this]() { OnLoginClicked(); });
104
105 // Register (Center)
106 createBtn("REGISTER", 0, 0xFF00008B, 0xFF0000FF, [this]() { OnRegisterClicked(); });
107
108 // Guest (Right)
109 createBtn("GUEST", (btnWidth + btnSpacing), 0xFF646464, 0xFF808080, [this]() { OnGuestClicked(); });
110
111 // Back (Bottom)
112 std::shared_ptr<UI::IButton> backBtn = _uiFactory.CreateButton();
113 backBtn->SetSize(btnWidth, btnHeight);
114 backBtn->SetAlign(UI::Align::CENTER_HORIZONTAL);
115 backBtn->ApplyAlignment();
116
117 float bx, by;
118 backBtn->GetPosition(bx, by);
119 backBtn->SetPosition(bx, currentY + btnHeight + SPACING);
120
121 backBtn->SetText("BACK");
122 backBtn->SetBackgroundColor(0xFF424242);
123 backBtn->SetHoverColor(0xFF616161);
124 backBtn->SetTextColor(0xFFFFFFFF);
125 backBtn->SetCallback(WrapWithClickSound([this]() {
126 if (_onBack)
127 _onBack();
128 }));
129 _menu->AddButton(backBtn);
130 }
131
134
135 if (_usernameInput)
136 _usernameInput->Update();
137 if (_passwordInput)
138 _passwordInput->Update();
139
141
142 // Handle Enter key for submission
143 if (_graphics.IsKeyPressed(KEY_ENTER)) {
145 }
146 }
147
149 // Draw background
152 0xFFF5F5F5); // RAYWHITE-ish
153
154 // Draw Title
155 const char *title = "R-TYPE LOGIN";
156 int titleFontSize = 40;
157 int titleWidth = UI::TextUtils::EstimateTextWidth(title, titleFontSize);
158 _graphics.DrawText(-1, title, (_graphics.GetScreenWidth() - titleWidth) / 2,
159 _graphics.GetScreenHeight() / 2 - 160, titleFontSize, 0xFF00008B); // DARKBLUE
160
161 // Draw Inputs
162 if (_usernameInput)
163 _usernameInput->Render();
164 if (_passwordInput)
165 _passwordInput->Render();
166
167 // Draw Buttons
169
170 // Draw Messages
171 if (!_errorMessage.empty()) {
174 _graphics.GetScreenHeight() / 2 + 150, 20, 0xFFFF0000); // RED
175 }
176 if (!_successMessage.empty()) {
179 _graphics.GetScreenHeight() / 2 + 150, 20, 0xFF008000); // GREEN
180 }
181
182 // Hint
183 const char *hint = "Tab to switch fields | Enter to login";
184 int hintW = UI::TextUtils::EstimateTextWidth(hint, 15);
185 _graphics.DrawText(-1, hint, (_graphics.GetScreenWidth() - hintW) / 2,
186 _graphics.GetScreenHeight() - 40, 15, 0xFF808080);
187 }
188
190 if (_graphics.IsKeyPressed(KEY_TAB)) {
192 if (_usernameInput->IsFocused()) {
193 _usernameInput->SetFocused(false);
194 _passwordInput->SetFocused(true);
195 } else {
196 // Default to username if password focused or neither
197 _usernameInput->SetFocused(true);
198 _passwordInput->SetFocused(false);
199 }
200 }
201 }
202 }
203
205 if (GetUsername().empty() || GetPassword().empty()) {
206 SetErrorMessage("Please enter username and password");
207 return;
208 }
209 ResetMessages(); // Clear previous messages when submitting
210 _loginSubmitted = true;
211 }
212
214 if (GetUsername().empty() || GetPassword().empty()) {
215 SetErrorMessage("Please enter username and password");
216 return;
217 }
218 ResetMessages(); // Clear previous messages when submitting
219 _registerSubmitted = true;
220 }
221
223 _guestSubmitted = true;
224 }
225
226 // Getters
228 return _loginSubmitted;
229 }
231 return _registerSubmitted;
232 }
234 return _guestSubmitted;
235 }
236
237 std::string LoginMenu::GetUsername() const {
238 return _usernameInput ? _usernameInput->GetText() : "";
239 }
240
241 std::string LoginMenu::GetPassword() const {
242 return _passwordInput ? _passwordInput->GetText() : "";
243 }
244
245 void LoginMenu::SetErrorMessage(const std::string &message) {
246 _errorMessage = message;
247 _successMessage.clear();
248 }
249
250 void LoginMenu::SetSuccessMessage(const std::string &message) {
251 _successMessage = message;
252 _errorMessage.clear();
253 }
254
256 _errorMessage.clear();
257 _successMessage.clear();
258 }
259
261 if (_usernameInput)
262 _usernameInput->Clear();
263 if (_passwordInput)
264 _passwordInput->Clear();
265 _loginSubmitted = false;
266 _registerSubmitted = false;
267 _guestSubmitted = false;
269
270 // Focus username by default
271 if (_usernameInput)
272 _usernameInput->SetFocused(true);
273 if (_passwordInput)
274 _passwordInput->SetFocused(false);
275 }
276
277} // namespace Game
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
virtual void Render()
Render menu (should be called every frame).
Definition BaseMenu.cpp:22
std::function< void()> WrapWithClickSound(std::function< void()> callback)
Wrap a callback to play click sound before executing.
Definition BaseMenu.cpp:48
UI::IUIFactory & _uiFactory
Definition BaseMenu.hpp:100
void OnRegisterClicked()
void SetErrorMessage(const std::string &message)
bool _registerSubmitted
Definition LoginMenu.hpp:59
std::string GetUsername() const
void Update() override
Update menu state (should be called every frame).
std::shared_ptr< UI::ITextInput > _usernameInput
Definition LoginMenu.hpp:54
void SetOnBack(std::function< void()> onBack)
Definition LoginMenu.cpp:17
const float INPUT_WIDTH
Definition LoginMenu.hpp:70
void HandleTabNavigation()
void Render() override
Render menu (should be called every frame).
const float SPACING
Definition LoginMenu.hpp:72
Graphics::IGraphics & _graphics
Definition LoginMenu.hpp:51
std::function< void()> _onBack
Definition LoginMenu.hpp:63
const float INPUT_HEIGHT
Definition LoginMenu.hpp:71
bool IsGuestSubmitted() const
std::string _errorMessage
Definition LoginMenu.hpp:66
bool IsLoginSubmitted() const
LoginMenu(UI::IUIFactory &uiFactory, Graphics::IGraphics &graphics)
Constructor.
Definition LoginMenu.cpp:14
std::string GetPassword() const
bool IsRegisterSubmitted() const
void SetSuccessMessage(const std::string &message)
std::shared_ptr< UI::ITextInput > _passwordInput
Definition LoginMenu.hpp:55
std::string _successMessage
Definition LoginMenu.hpp:67
void Initialize() override
Initialize menu (must be implemented by derived classes).
Definition LoginMenu.cpp:21
void OnLoginClicked()
void OnGuestClicked()
Abstract interface for graphics rendering operations.
Definition IGraphics.hpp:32
virtual bool IsKeyPressed(int key) const =0
Check if a key was pressed (triggered once when key goes down)
virtual void ClearWindow()=0
Clear the window with the current clear color.
virtual void DrawRectFilled(int x, int y, int width, int height, unsigned int color)=0
Draw a filled rectangle.
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 GetScreenHeight() const =0
Get the screen height (same as window height)
virtual int GetScreenWidth() const =0
Get the screen width (same as window width)
Abstract factory interface for creating UI elements.
virtual std::unique_ptr< ITextInput > CreateTextInput()=0
Create a text input instance.
virtual std::unique_ptr< IButton > CreateButton()=0
Create a button instance.
int EstimateTextWidth(const std::string &text, int fontSize)
Estimate the width of text in pixels.
Definition TextUtils.hpp:27
@ CENTER_HORIZONTAL
Center on the X axis.