nsnake
Classic snake game for the terminal
Toggle main menu visibility
Loading...
Searching...
No Matches
src
Interface
Menu
Menu.cpp
1
#include <Interface/Menu/Menu.hpp>
2
#include <Misc/Utils.hpp>
3
#include <Config/Globals.hpp>
4
#include <Flow/InputManager.hpp>
5
6
Menu::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
{ }
16
Menu::~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
}
23
void
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
}
43
void
Menu::addBlank()
44
{
45
this->
item
.push_back(NULL);
46
}
47
void
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
}
71
void
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
}
95
void
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
}
183
void
Menu::handleInput
()
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
}
226
void
Menu::goNext
()
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
}
259
void
Menu::goPrevious
()
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
}
286
void
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
}
304
void
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
}
322
void
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
}
330
bool
Menu::willQuit
()
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
}
336
std::string
Menu::currentLabel
()
337
{
338
if
(! this->
current
)
339
this->
goNext
();
340
341
return
(this->
current
->label);
342
}
343
int
Menu::currentID
()
344
{
345
if
(! this->
current
)
346
this->
goNext
();
347
348
return
(this->
current
->id);
349
}
350
bool
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
}
372
int
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
}
394
std::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
}
424
void
Menu::reset
()
425
{
426
this->
selected
=
false
;
427
this->
selectedItem
= NULL;
428
}
429
430
MenuItemTextlist
A list of selectable text.
Definition
MenuItemTextlist.hpp:11
Menu::goPrevious
void goPrevious()
Makes the menu select the previous item.
Definition
Menu.cpp:259
Menu::draw
void draw(Window *window)
Draws the whole Menu on window.
Definition
Menu.cpp:95
Menu::currentIndex
unsigned int currentIndex
Index of the currently selected item.
Definition
Menu.hpp:119
Menu::currentLabel
std::string currentLabel()
Returns the label of the currently selected item.
Definition
Menu.cpp:336
Menu::getBool
bool getBool(int id)
Returns the bool internal value of item that has id.
Definition
Menu.cpp:350
Menu::willQuit
bool willQuit()
Tells if the user selected an item that quits the menu.
Definition
Menu.cpp:330
Menu::handleInput
void handleInput()
Makes the menu react to input, as seen on the global InputManager.
Definition
Menu.cpp:183
Menu::item
std::vector< MenuItem * > item
Container of all the options inside the menu.
Definition
Menu.hpp:109
Menu::currentID
int currentID()
Returns the user-specified id of the selected item.
Definition
Menu.cpp:343
Menu::selected
bool selected
Tells if the user selected an item (pressed Enter).
Definition
Menu.hpp:127
Menu::getInt
int getInt(int id)
Returns the integer value of the item that has id.
Definition
Menu.cpp:372
Menu::selectedItem
MenuItem * selectedItem
Specifies which item the user pressed Enter on.
Definition
Menu.hpp:130
Menu::getString
std::string getString(int id)
Returns the string value of the item that has id.
Definition
Menu.cpp:394
Menu::current
MenuItem * current
Current item selected.
Definition
Menu.hpp:115
Menu::Menu
Menu(int x, int y, int width, int height)
Creates a menu at x and y with width and height.
Definition
Menu.cpp:6
Menu::removeByID
void removeByID(int id)
Removes the menu item with id.
Definition
Menu.cpp:47
Menu::removeByLabel
void removeByLabel(std::string label)
Removes the menu item with label.
Definition
Menu.cpp:71
Menu::reset
void reset()
Makes the menu able to be selected again.
Definition
Menu.cpp:424
Menu::goNext
void goNext()
Makes the menu select the next item.
Definition
Menu.cpp:226
Window
A segment of the terminal screen (2D char matrix).
Definition
Window.hpp:17
Window::printChar
void printChar(int c, int x, int y, ColorPair pair=0)
Shows c at x y with color pair.
Definition
Window.cpp:105
Window::print
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
Utils::Random::between
int between(int min, int max)
Random number between min and max.
Definition
Utils.cpp:48
MenuItemCheckbox
A little box that can be checked or not.
Definition
MenuItemCheckbox.hpp:10
MenuItemNumberbox
Allows to select a number, kinda like a slider.
Definition
MenuItemNumberbox.hpp:18
MenuItemTextbox
Place where you can input characters.
Definition
MenuItemTextbox.hpp:10
MenuItem
Simplest type of item possible, with a label and user-defined id.
Definition
MenuItem.hpp:12
MenuItem::draw
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
Generated on
for nsnake by
1.17.0