R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
RaylibMenu.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** r-type
4** File description:
5** RaylibMenu - Raylib implementation of IMenu
6*/
7
9#include <raylib.h>
10#include <cstddef> // For std::ptrdiff_t
11#include "Input/KeyBindings.hpp"
12#include "UI/IButton.hpp"
13
14namespace UI {
15 RaylibMenu::RaylibMenu(Graphics::IGraphics &graphics) : _graphics(graphics) {}
16
18 if (!_visible) {
19 return;
20 }
21
22 // Handle keyboard navigation
24
25 // Update all buttons
26 for (auto &button : _buttons) {
27 if (button) {
28 button->Update();
29 }
30 }
31 }
32
34 if (!_visible) {
35 return;
36 }
37
38 // Render all buttons
39 for (auto &button : _buttons) {
40 if (button) {
41 button->Render();
42 }
43 }
44 }
45
46 void RaylibMenu::AddButton(std::shared_ptr<IButton> button) {
47 if (button) {
48 _buttons.push_back(std::move(button));
49 }
50 }
51
52 void RaylibMenu::RemoveButton(size_t index) {
53 if (index < _buttons.size()) {
54 // Adjust selected index if needed
55 if (static_cast<int>(index) == _selectedIndex) {
56 _selectedIndex = -1; // Clear selection if removed button was selected
57 } else if (static_cast<int>(index) < _selectedIndex) {
58 _selectedIndex--; // Adjust index if button before selected was removed
59 }
60 _buttons.erase(_buttons.begin() + static_cast<std::ptrdiff_t>(index));
61 }
62 }
63
64 std::shared_ptr<IButton> RaylibMenu::GetButton(size_t index) {
65 if (index < _buttons.size()) {
66 return _buttons[index];
67 }
68 return nullptr;
69 }
70
72 return _buttons.size();
73 }
74
76 _buttons.clear();
77 _selectedIndex = -1; // Reset selection when clearing
78 }
79
80 void RaylibMenu::SetVisible(bool visible) {
81 _visible = visible;
82 // Reset selection when hiding menu
83 if (!visible) {
85 }
86 }
87
88 bool RaylibMenu::IsVisible() const {
89 return _visible;
90 }
91
93 if (_buttons.empty()) {
94 return;
95 }
96
97 auto &bindings = Input::KeyBindings::getInstance();
98
99 // Helper to check if a binding (keyboard or gamepad) is pressed
100 auto isBindingPressed = [this](int binding) {
101 if (binding == KEY_NULL) {
102 return false;
103 }
104 if (Input::IsGamepadBinding(binding)) {
105 int button = Input::BindingToGamepadButton(binding);
106 // Check all connected gamepads
107 for (int gp = 0; gp < 4; ++gp) {
109 return true;
110 }
111 }
112 return false;
113 }
114 return _graphics.IsKeyPressed(binding);
115 };
116
117 // Helper to check if any binding for an action is pressed
118 auto isActionPressed = [&bindings, &isBindingPressed](Input::GameAction action) {
119 int primary = bindings.GetPrimaryKey(action);
120 int secondary = bindings.GetSecondaryKey(action);
121 return isBindingPressed(primary) || isBindingPressed(secondary);
122 };
123
124 // Check for menu navigation actions using configurable bindings
125 bool shiftDown = _graphics.IsKeyDown(KEY_LEFT_SHIFT) || _graphics.IsKeyDown(KEY_RIGHT_SHIFT);
126
127 // Menu Next (Tab by default, but now configurable)
128 if (isActionPressed(Input::GameAction::MENU_NEXT)) {
129 SelectNext();
130 }
131
132 // Menu Previous (Up/Shift+Tab by default, but now configurable)
133 if (isActionPressed(Input::GameAction::MENU_PREVIOUS) ||
134 (shiftDown && _graphics.IsKeyPressed(KEY_TAB))) {
136 }
137
138 // Menu Confirm (Enter by default, but now configurable)
139 if (isActionPressed(Input::GameAction::MENU_CONFIRM)) {
141 }
142 }
143
145 if (_buttons.empty()) {
146 return;
147 }
148
149 // Clear focus from current selection
150 if (_selectedIndex >= 0 && _selectedIndex < static_cast<int>(_buttons.size())) {
152 _buttons[_selectedIndex]->SetFocused(false);
153 }
154 }
155
156 // Find next enabled button
157 int startIndex = _selectedIndex;
158 int buttonsCount = static_cast<int>(_buttons.size());
159
160 do {
161 _selectedIndex = (_selectedIndex + 1) % buttonsCount;
162 if (_buttons[_selectedIndex] && _buttons[_selectedIndex]->IsEnabled()) {
163 _buttons[_selectedIndex]->SetFocused(true);
164 return;
165 }
166 } while (_selectedIndex != startIndex);
167
168 // No enabled buttons found
169 _selectedIndex = -1;
170 }
171
173 if (_buttons.empty()) {
174 return;
175 }
176
177 // Clear focus from current selection
178 if (_selectedIndex >= 0 && _selectedIndex < static_cast<int>(_buttons.size())) {
180 _buttons[_selectedIndex]->SetFocused(false);
181 }
182 }
183
184 // Find previous enabled button
185 int startIndex = _selectedIndex;
186 int buttonsCount = static_cast<int>(_buttons.size());
187
188 // Handle -1 case (no selection)
189 if (_selectedIndex < 0) {
190 _selectedIndex = buttonsCount;
191 }
192
193 do {
194 _selectedIndex = (_selectedIndex - 1 + buttonsCount) % buttonsCount;
195 if (_buttons[_selectedIndex] && _buttons[_selectedIndex]->IsEnabled()) {
196 _buttons[_selectedIndex]->SetFocused(true);
197 return;
198 }
199 } while (_selectedIndex != startIndex);
200
201 // No enabled buttons found
202 _selectedIndex = -1;
203 }
204
206 if (_selectedIndex >= 0 && _selectedIndex < static_cast<int>(_buttons.size())) {
208 _buttons[_selectedIndex]->TriggerClick();
209 }
210 }
211 }
212
214 return _selectedIndex;
215 }
216
218 // Clear previous selection
219 if (_selectedIndex >= 0 && _selectedIndex < static_cast<int>(_buttons.size())) {
221 _buttons[_selectedIndex]->SetFocused(false);
222 }
223 }
224
225 // Set new selection
226 if (index >= 0 && index < static_cast<int>(_buttons.size())) {
227 _selectedIndex = index;
229 _buttons[_selectedIndex]->SetFocused(true);
230 }
231 } else {
232 _selectedIndex = -1;
233 }
234 }
235} // namespace UI
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 bool IsGamepadAvailable(int gamepad) const =0
Check if a gamepad is available/connected.
virtual bool IsGamepadButtonPressed(int gamepad, int button) const =0
Check if a gamepad button was pressed this frame.
virtual bool IsKeyDown(int key) const =0
Check if a key is currently being held down.
static KeyBindings & getInstance()
Get the singleton instance.
void SetVisible(bool visible) override
Set menu visibility.
void Clear() override
Remove all buttons from the menu.
void SelectNext() override
Select the next navigable element.
void AddButton(std::shared_ptr< IButton > button) override
Add a button to the menu.
void Render() override
Render all menu elements.
int _selectedIndex
Currently selected button index (-1 = none)
void HandleKeyboardNavigation() override
Handle keyboard navigation input.
int GetSelectedIndex() const override
Get the index of the currently selected element.
void SetSelectedIndex(int index) override
Set the selected element by index.
bool _visible
Menu visibility state.
RaylibMenu(Graphics::IGraphics &graphics)
Construct a new RaylibMenu.
void RemoveButton(size_t index) override
Remove a button from the menu by index.
void Update() override
Update all menu elements.
void SelectPrevious() override
Select the previous navigable element.
size_t GetButtonCount() const override
Get the number of buttons in the menu.
bool IsVisible() const override
Check menu visibility.
void TriggerSelected() override
Trigger the currently selected element (simulate click).
std::vector< std::shared_ptr< IButton > > _buttons
Collection of buttons.
Graphics::IGraphics & _graphics
Graphics dependency.
std::shared_ptr< IButton > GetButton(size_t index) override
Get a button by index.
GameAction
Enumeration of all bindable game actions.
int BindingToGamepadButton(int binding)
Extract gamepad button from a binding value.
bool IsGamepadBinding(int binding)
Check if a binding value represents a gamepad button.
Definition IButton.hpp:13