nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
Menu.cpp
1#include <Interface/Menu/Menu.hpp>
2#include <Misc/Utils.hpp>
3#include <Config/Globals.hpp>
4#include <Flow/InputManager.hpp>
5
6Menu::Menu(int x, int y, int width, int height):
7 current(NULL),
8 currentIndex(0),
9 x(x),
10 y(y),
11 width(width),
12 height(height),
13 selected(false),
14 selectedItem(NULL)
15{ }
16Menu::~Menu()
17{
18 for (unsigned int i = 0; i < (this->item.size()); i++)
19 SAFE_DELETE(this->item[i]);
20
21 this->item.clear();
22}
23void Menu::add(MenuItem* item)
24{
25 this->item.push_back(item);
26
27 // Means we're the first item being added!
28 if (this->item.size() == 1)
29 {
30 this->current = this->item.back();
31 this->currentIndex = this->item.size() - 1;
32 }
33
34 // Means we're the first non-nil item being added!
35 unsigned int i = 0;
36 for (i = 0; i < (this->item.size()); i++)
37 if (this->item[i])
38 break;
39
40 this->current = this->item[i];
41 this->currentIndex = i;
42}
43void Menu::addBlank()
44{
45 this->item.push_back(NULL);
46}
47void Menu::removeByID(int id)
48{
49 std::vector<MenuItem*>::iterator it = this->item.begin();
50
51 while (it != this->item.end())
52 {
53 if (!(*it))
54 ++it;
55
56 if ((*it)->id == id)
57 {
58 if (this->current == *it)
59 {
60 this->goNext();
61 this->currentIndex--;
62 }
63
64 this->item.erase(it);
65 return;
66 }
67 else
68 ++it;
69 }
70}
71void Menu::removeByLabel(std::string label)
72{
73 std::vector<MenuItem*>::iterator it = this->item.begin();
74
75 while (it != this->item.end())
76 {
77 if (!(*it))
78 ++it;
79
80 if ((*it)->label == label)
81 {
82 if (this->current == *it)
83 {
84 this->goNext();
85 this->currentIndex--;
86 }
87
88 this->item.erase(it);
89 return;
90 }
91 else
92 ++it;
93 }
94}
95void Menu::draw(Window* window)
96{
97 // If we have more Items than we can draw, we need to
98 // ask the user to scroll.
99
100 // So these are the indexes of the items we'll actually
101 // show on the screen.
102 unsigned int draw_begin = 0;
103 unsigned int draw_end = this->item.size();
104
105 if (this->height < (int)this->item.size())
106 {
107 if ((int)this->currentIndex <= this->height/2)
108 {
109 draw_end = this->height - 1;
110 }
111 else if ((int)this->currentIndex < ((int)this->item.size() - this->height/2) - 1)
112 {
113 draw_begin = this->currentIndex - this->height/2;
114 draw_end = this->currentIndex + this->height/2;
115 }
116 else
117 {
118 draw_begin = this->item.size() - this->height;
119 }
120 }
121
122 // `i` is the index of the item to draw
123 for (unsigned int curitem = draw_begin, yoffset = 0;
124 curitem < draw_end;
125 curitem++, yoffset++)
126 {
127 // Menu is big and needs scrolling,
128 // we need to show (more) on the top
129 if ((curitem == draw_begin) && (curitem != 0))
130 {
131 window->print("(more)",
132 this->x + this->width/2 - 3,
133 this->y + yoffset,
134 Colors::pair(COLOR_WHITE, COLOR_DEFAULT));
135 continue;
136 }
137 // Menu is big and needs scrolling,
138 // we need to show (more) on the end
139 if ((curitem == draw_end - 1) && (curitem != this->item.size() - 1))
140 {
141 window->print("(more)",
142 this->x + this->width/2 - 3,
143 this->y + yoffset + 1,
144 Colors::pair(COLOR_WHITE, COLOR_DEFAULT));
145 continue;
146 }
147
148 // <rant>
149 // THIS IS VERY UGLY
150 // HOW CAN I LAY DOWN A CLASS HIERARCHY
151 // AND OVERRIDE PARENT FUNCTIONS ON CHILD CLASSES
152 // IF WHEN I HAVE A PARENT POINTER I CANT LET THE
153 // COMPILER DECIDE WETHER TO CALL PARENT OR CHILD
154 // FUNCTIONS?
155 // </rant>
156
157// MenuItemCheckbox* pCheckbox = dynamic_cast<MenuItemCheckbox*>a
158
159 // Blank Menu Item, will show horizontal line
160 if (! this->item[curitem])
161 {
162 for (int j = 0; j < (this->width); j++)
163 window->printChar(((Globals::Screen::fancy_borders) ?
164 ACS_HLINE :
165 '-'),
166 this->x + j,
167 this->y + yoffset,
168 Colors::pair(COLOR_WHITE, COLOR_DEFAULT));
169 }
170 else
171 {
172 this->item[curitem]->draw(window,
173 this->x,
174 this->y + yoffset,
175 this->width,
176
177 // Highlighting current item if
178 // it's the current.
179 (this->item[curitem] == this->current));
180 }
181 }
182}
184{
185 if (InputManager::noKeyPressed())
186 return;
187
188 if (InputManager::isPressed("down") || // user-defined
189 InputManager::isPressed(KEY_DOWN) ||
190 InputManager::isPressed('\t'))
191 this->goNext();
192
193 else if (InputManager::isPressed("up") ||
194 InputManager::isPressed(KEY_UP) ||
195 InputManager::isPressed(KEY_BTAB))
196 this->goPrevious();
197
198 else if (InputManager::isPressed(KEY_HOME) ||
199 InputManager::isPressed(KEY_PPAGE))
200 this->goFirst();
201
202 else if (InputManager::isPressed(KEY_END) ||
203 InputManager::isPressed(KEY_NPAGE))
204 this->goLast();
205
206 else if (InputManager::isPressed(KEY_ENTER) ||
207 InputManager::isPressed('\n'))
208 {
209 // Will only quit if the selected item is a simple
210 // item or label - more complex ones doesn't quit.
211 if (this->current->type == MenuItem::ITEM ||
212 this->current->type == MenuItem::LABEL)
213 {
214 this->selected = true;
215 this->selectedItem = this->current;
216 }
217 else
218 this->current->handleInput();
219 }
220 else
221 {
222 if (this->current)
223 this->current->handleInput();
224 }
225}
227{
228 // Empty element, piece of cake
229 if (this->item.size() == 0)
230 return;
231
232 // Empty element, also piece of cake
233 if (this->item.size() == 1)
234 {
235 this->current = *(this->item.begin());
236 this->currentIndex = 0;
237 return;
238 }
239
240 // Last element...
241 // Well, if the last element is nil then we have
242 // a problem.
243 if (this->current == this->item.back())
244 {
245 // Assuming we're not nil, things will go smooth
246 if (this->currentIndex == (this->item.size() - 1))
247 {
248 this->goFirst();
249 return;
250 }
251 }
252
253 this->currentIndex++;
254 this->current = this->item[this->currentIndex];
255
256 if (! this->current)
257 this->goNext();
258}
260{
261 if (this->item.size() == 0)
262 return;
263
264 if (this->item.size() == 1)
265 {
266 this->current = this->item.front();
267 this->currentIndex = 0;
268 return;
269 }
270
271 if (this->current == this->item.front())
272 {
273 if (this->currentIndex == 0)
274 {
275 this->goLast();
276 return;
277 }
278 }
279
280 this->currentIndex--;
281 this->current = this->item[this->currentIndex];
282
283 if (! this->current)
284 this->goPrevious();
285}
286void Menu::goFirst()
287{
288 if (this->item.size() == 0)
289 return;
290
291 if (this->item.size() == 1)
292 {
293 this->current = this->item.front();
294 this->currentIndex = 0;
295 return;
296 }
297
298 this->current = this->item.front();
299 this->currentIndex = 0;
300
301 if (! this->current)
302 this->goNext();
303}
304void Menu::goLast()
305{
306 if (this->item.size() == 0)
307 return;
308
309 if (this->item.size() == 1)
310 {
311 this->current = this->item.front();
312 this->currentIndex = 0;
313 return;
314 }
315
316 this->current = this->item.back();
317 this->currentIndex = (this->item.size() - 1);
318
319 if (! this->current)
320 this->goPrevious();
321}
322void Menu::goRandom()
323{
324 if (this->item.size() == 0)
325 return;
326
327 this->currentIndex = Utils::Random::between(0, this->item.size() - 1);
328 this->current = this->item[this->currentIndex];
329}
331{
332 // Will only quit if the user selected an item
333 // and the item selected is valid.
334 return (this->selected && this->selectedItem);
335}
337{
338 if (! this->current)
339 this->goNext();
340
341 return (this->current->label);
342}
344{
345 if (! this->current)
346 this->goNext();
347
348 return (this->current->id);
349}
350bool Menu::getBool(int id)
351{
352 for (unsigned int i = 0; i < (this->item.size()); i++)
353 {
354 if (! this->item[i])
355 continue;
356
357 if (this->item[i]->id == id)
358 {
359 // Either the type got messed up or we have
360 // two items with the same id.
361 if (this->item[i]->type != MenuItem::CHECKBOX)
362 return false;
363
364 // This cast may be dangerous if the type was
365 // somehow changed.
366 MenuItemCheckbox* c = (MenuItemCheckbox*)this->item[i];
367 return c->isChecked();
368 }
369 }
370 return false;
371}
372int Menu::getInt(int id)
373{
374 for (unsigned int i = 0; i < (this->item.size()); i++)
375 {
376 if (! this->item[i])
377 continue;
378
379 if (this->item[i]->id == id)
380 {
381 // Either the type got messed up or we have
382 // two items with the same id.
383 if (this->item[i]->type != MenuItem::NUMBERBOX)
384 return -1;
385
386 // This cast may be dangerous if the type was
387 // somehow changed.
388 MenuItemNumberbox* c = (MenuItemNumberbox*)this->item[i];
389 return c->current;
390 }
391 }
392 return -1;
393}
394std::string Menu::getString(int id)
395{
396 for (unsigned int i = 0; i < (this->item.size()); i++)
397 {
398 if (! this->item[i])
399 continue;
400
401 if (this->item[i]->id == id)
402 {
403 // Either the type got messed up or we have
404 // two items with the same id.
405 if (this->item[i]->type == MenuItem::TEXTBOX)
406 {
407 MenuItemTextbox* c = (MenuItemTextbox*)this->item[i];
408 return c->currentText;
409 }
410 else if (this->item[i]->type == MenuItem::TEXTLIST)
411 {
412 MenuItemTextlist* c = (MenuItemTextlist*)this->item[i];
413 return c->currentText();
414 }
415 else
416 return "";
417
418 // This cast may be dangerous if the type was
419 // somehow changed.
420 }
421 }
422 return "";
423}
425{
426 this->selected = false;
427 this->selectedItem = NULL;
428}
429
430
A list of selectable text.
void goPrevious()
Makes the menu select the previous item.
Definition Menu.cpp:259
void draw(Window *window)
Draws the whole Menu on #window.
Definition Menu.cpp:95
unsigned int currentIndex
Index of the currently selected item.
Definition Menu.hpp:119
std::string currentLabel()
Returns the label of the currently selected item.
Definition Menu.cpp:336
bool getBool(int id)
Returns the bool internal value of item that has #id.
Definition Menu.cpp:350
bool willQuit()
Tells if the user selected an item that quits the menu.
Definition Menu.cpp:330
void handleInput()
Makes the menu react to input, as seen on the global InputManager.
Definition Menu.cpp:183
std::vector< MenuItem * > item
Container of all the options inside the menu.
Definition Menu.hpp:109
int currentID()
Returns the user-specified id of the selected item.
Definition Menu.cpp:343
bool selected
Tells if the user selected an item (pressed Enter).
Definition Menu.hpp:127
int getInt(int id)
Returns the integer value of the item that has #id.
Definition Menu.cpp:372
MenuItem * selectedItem
Specifies which item the user pressed Enter on.
Definition Menu.hpp:130
std::string getString(int id)
Returns the string value of the item that has #id.
Definition Menu.cpp:394
MenuItem * current
Current item selected.
Definition Menu.hpp:115
Menu(int x, int y, int width, int height)
Creates a menu at x and y with width and height.
Definition Menu.cpp:6
void removeByID(int id)
Removes the menu item with #id.
Definition Menu.cpp:47
void removeByLabel(std::string label)
Removes the menu item with #label.
Definition Menu.cpp:71
void reset()
Makes the menu able to be selected again.
Definition Menu.cpp:424
void goNext()
Makes the menu select the next item.
Definition Menu.cpp:226
A segment of the terminal screen (2D char matrix).
Definition Window.hpp:17
void printChar(int c, int x, int y, ColorPair pair=0)
Shows #c at x y with color #pair.
Definition Window.cpp:105
void print(std::string str, int x, int y, ColorPair pair=0)
Shows text #str at x y on the window with color #pair.
Definition Window.cpp:94
int between(int min, int max)
Random number between min and max.
Definition Utils.cpp:48
A little box that can be checked or not.
Allows to select a number, kinda like a slider.
Place where you can input characters.
Simplest type of item possible, with a label and user-defined id.
Definition MenuItem.hpp:12
virtual void draw(Window *window, int x, int y, int width, bool hilite=false)
Shows this item at #x, #y with #width.
Definition MenuItem.cpp:12
virtual void handleInput()
Makes the menu item react to input, as seen on the global InputManager.
Definition MenuItem.cpp:19
MenuItemType type
Specific type of this widget.
Definition MenuItem.hpp:51
std::string label
Text that will be shown on the screen.
Definition MenuItem.hpp:54
int id
User-defined id to identify this item.
Definition MenuItem.hpp:57