libgui 3.00
libgui is a GUI library for the GameCube, Wii, and Wii U
 
Loading...
Searching...
No Matches
GuiWindow.cpp
1/****************************************************************************
2 * libgui
3 * Daryl Borth 2009-2026
4 * GuiWindow.cpp
5 ***************************************************************************/
6
7#include "Gui.h"
8
10{
11 width = 0;
12 height = 0;
13 focus = 0; // allow focus
14}
15
17{
18 width = w;
19 height = h;
20 focus = 0; // allow focus
21}
22
24{
25 // Orphan all children if the window is destroyed first to prevent dangling pointer
26 for (GuiElement* e : _elements) {
27 e->setParent(nullptr);
28 }
29}
30
32{
33 if (e == nullptr)
34 return;
35
36 remove(e);
37 _elements.push_back(e);
38 e->setParent(this);
39}
40
42{
43 if (e == nullptr) return;
44 append(e);
45 e->setRemoveOnDestroy(true);
46}
47
48void GuiWindow::insert(GuiElement* e, uint32_t index)
49{
50 if (e == nullptr || index > (_elements.size() - 1))
51 return;
52
53 remove(e);
54 _elements.insert(_elements.begin()+index, e);
55 e->setParent(this);
56}
57
59{
60 if (e == nullptr)
61 return;
62
63 uint32_t elemSize = _elements.size();
64 for (uint32_t i = 0; i < elemSize; ++i)
65 {
66 if(e == _elements.at(i))
67 {
68 e->setParent(nullptr);
69 _elements.erase(_elements.begin()+i);
70 break;
71 }
72 }
73}
74
76{
77 uint32_t elemSize = _elements.size();
78 for (uint32_t i = 0; i < elemSize; ++i)
79 {
80 _elements.at(i)->setParent(nullptr);
81 }
82 _elements.clear();
83}
84
86{
87 if (e == nullptr)
88 return false;
89
90 uint32_t elemSize = _elements.size();
91 for (uint32_t i = 0; i < elemSize; ++i)
92 if(e == _elements.at(i))
93 return true;
94 return false;
95}
96
98{
99 if (index >= _elements.size())
100 return nullptr;
101 return _elements.at(index);
102}
103
105{
106 return _elements.size();
107}
108
110{
111 if(_elements.size() == 0 || !this->isVisible())
112 return;
113
114 // A disabled window (and everything inside it) is washed over, once: the wash goes on after the last of a run of
115 // disabled child windows, before whatever is drawn over them (a dialog opened above a disabled screen)
116 const bool washed = parentElement && state == STATE::DISABLED;
117 bool washPending = false;
118 uint32_t elemSize = _elements.size();
119 for (uint32_t i = 0; i < elemSize; ++i)
120 {
121 GuiElement * e = _elements.at(i);
122 GuiWindow * child = e->getAsWindow();
123 const bool disabledChild = child && child->getState() == STATE::DISABLED && child->isVisible();
124 if(washPending && !disabledChild)
125 {
126 drawWash();
127 washPending = false;
128 }
129 e->draw();
130 if(disabledChild && !washed)
131 washPending = true;
132 }
133 if(washPending)
134 drawWash();
135
136 this->updateEffects();
137}
138
141{
142 platform->getVideo()->getImageRenderer()->drawRectangle(0, 0, platform->getVideo()->getScreenWidth(), platform->getVideo()->getScreenHeight(), (PixelColor){0xbe, 0xca, 0xd5, 0x70});
143}
144
146{
147 if(state != STATE::DISABLED)
148 state = STATE::DEFAULT;
149
150 uint32_t elemSize = _elements.size();
151 for (uint32_t i = 0; i < elemSize; ++i)
152 {
153 _elements.at(i)->resetState();
154 }
155}
156
158{
159 state = s;
160
161 uint32_t elemSize = _elements.size();
162 for (uint32_t i = 0; i < elemSize; ++i)
163 {
164 _elements.at(i)->setState(s, c);
165 }
166}
167
169{
170 visible = v;
171
172 uint32_t elemSize = _elements.size();
173 for (uint32_t i = 0; i < elemSize; ++i)
174 {
175 _elements.at(i)->setVisible(v);
176 }
177}
178
180{
181 focus = f;
182
183 if(f == 1)
184 this->moveSelectionVert(1);
185 else
186 this->resetState();
187}
188
190{
191 if(parentElement)
192 return; // this is only intended for the main window
193
194 uint32_t elemSize = _elements.size();
195 for (uint32_t i = 0; i < elemSize; ++i)
196 {
197 if(e == _elements.at(i))
198 _elements.at(i)->setFocus(1);
199 else if(_elements.at(i)->isFocused() == 1)
200 _elements.at(i)->setFocus(0);
201 }
202}
203
205{
206 if(parentElement)
207 return; // this is only intended for the main window
208
209 int found = -1;
210 int newfocus = -1;
211 int i;
212
213 int elemSize = _elements.size();
214
215 // look for currently in focus element
216 for (i = 0; i < elemSize; ++i)
217 {
218 if(_elements.at(i)->isFocused() == 1)
219 {
220 found = i;
221 break;
222 }
223 }
224
225 // element with focus not found, try to give focus
226 if(found == -1)
227 {
228 for (i = 0; i < elemSize; ++i)
229 {
230 if(_elements.at(i)->isFocused() == 0 && _elements.at(i)->getState() != STATE::DISABLED) // focus is possible (but not set)
231 {
232 _elements.at(i)->setFocus(1); // give this element focus
233 break;
234 }
235 }
236 }
237
238 // change focus
239 else if(controller->isSecondaryPressed())
240 {
241 for (i = found; i < elemSize; ++i)
242 {
243 if(_elements.at(i)->isFocused() == 0 && _elements.at(i)->getState() != STATE::DISABLED) // focus is possible (but not set)
244 {
245 newfocus = i;
246 _elements.at(i)->setFocus(1); // give this element focus
247 _elements.at(found)->setFocus(0); // disable focus on other element
248 break;
249 }
250 }
251
252 if(newfocus == -1)
253 {
254 for (i = 0; i < found; ++i)
255 {
256 if(_elements.at(i)->isFocused() == 0 && _elements.at(i)->getState() != STATE::DISABLED) // focus is possible (but not set)
257 {
258 _elements.at(i)->setFocus(1); // give this element focus
259 _elements.at(found)->setFocus(0); // disable focus on other element
260 break;
261 }
262 }
263 }
264 }
265}
266
268{
269 // find selected element
270 int found = -1;
271 uint32_t elemSize = _elements.size();
272 for (uint32_t i = 0; i < elemSize; ++i)
273 {
274 if(_elements.at(i)->getState() == STATE::SELECTED)
275 {
276 found = int(i);
277 break;
278 }
279 }
280 return found;
281}
282
283// set element to left/right as selected
284// there's probably a more clever way to do this, but this way works
285bool GuiWindow::collectNavigation(std::vector<GuiElement*>& out)
286{
287 bool nested = false;
288 for (GuiElement* e : _elements)
289 {
290 size_t before = out.size();
291 e->collectNavigable(out);
292 if(!(out.size() == before + 1 && out.back() == e))
293 nested = true; // the element contributed its children, not itself
294 }
295 return nested;
296}
297
298void GuiWindow::moveSelectionIn(std::vector<GuiElement*>& list, NAV_DIR d)
299{
300 int current = -1;
301 std::vector<GuiNavItem> items(list.size());
302 for (size_t i = 0; i < list.size(); ++i)
303 {
304 if(current < 0 && list[i]->getState() == STATE::SELECTED)
305 current = int(i);
306 items[i].r.x = (float)list[i]->getLeft();
307 items[i].r.y = (float)list[i]->getTop();
308 items[i].r.w = (float)list[i]->getWidth();
309 items[i].r.h = (float)list[i]->getHeight();
310 items[i].selectable = list[i]->isSelectable() && list[i]->isVisible() && list[i]->getState() != STATE::DISABLED;
311 }
312
313 int next = GuiNavigate(items, current, d);
314 if(next >= 0 && next != current)
315 {
316 list[next]->setState(STATE::SELECTED);
317 if(current >= 0)
318 list[current]->resetState();
319 }
320}
321
323{
324 std::vector<GuiElement*> nav;
325 if(this->collectNavigation(nav))
326 {
327 this->moveSelectionIn(nav, dir > 0 ? NAV_DIR::RIGHT : NAV_DIR::LEFT);
328 return;
329 }
330
331 int found = -1;
332 uint16_t left = 0;
333 uint16_t top = 0;
334 uint32_t i;
335 uint32_t elemSize = _elements.size();
336
337 int selected = this->getSelected();
338
339 if(selected >= 0)
340 {
341 left = _elements.at(selected)->getLeft();
342 top = _elements.at(selected)->getTop();
343 }
344
345
346 // look for a button on the same row, to the left/right
347 for (i = 0; i < elemSize; ++i)
348 {
349 if(_elements.at(i)->isSelectable())
350 {
351 if(_elements.at(i)->getLeft()*dir > left*dir && _elements.at(i)->getTop() == top)
352 {
353 if(found == -1)
354 found = int(i);
355 else if(_elements.at(i)->getLeft()*dir < _elements.at(found)->getLeft()*dir)
356 found = int(i); // this is a better match
357 }
358 }
359 }
360 if(found >= 0)
361 goto matchfound;
362
363 // match still not found, let's try the first button in the next row
364 for (i = 0; i < elemSize; ++i)
365 {
366 if(_elements.at(i)->isSelectable())
367 {
368 if(_elements.at(i)->getTop()*dir > top*dir)
369 {
370 if(found == -1)
371 found = i;
372 else if(_elements.at(i)->getTop()*dir < _elements.at(found)->getTop()*dir)
373 found = i; // this is a better match
374 else if(_elements.at(i)->getTop()*dir == _elements.at(found)->getTop()*dir
375 &&
376 _elements.at(i)->getLeft()*dir < _elements.at(found)->getLeft()*dir)
377 found = i; // this is a better match
378 }
379 }
380 }
381
382 // match found
383 matchfound:
384 if(found >= 0)
385 {
386 _elements.at(found)->setState(STATE::SELECTED);
387 if(selected >= 0)
388 _elements.at(selected)->resetState();
389 }
390}
391
393{
394 std::vector<GuiElement*> nav;
395 if(this->collectNavigation(nav))
396 {
397 this->moveSelectionIn(nav, dir > 0 ? NAV_DIR::DOWN : NAV_DIR::UP);
398 return;
399 }
400
401 int found = -1;
402 uint16_t left = 0;
403 uint16_t top = 0;
404
405 int selected = this->getSelected();
406
407 if(selected >= 0)
408 {
409 left = _elements.at(selected)->getLeft();
410 top = _elements.at(selected)->getTop();
411 }
412
413 // look for a button above/below, with the least horizontal difference
414 uint32_t elemSize = _elements.size();
415 for (uint32_t i = 0; i < elemSize; ++i)
416 {
417 if(_elements.at(i)->isSelectable())
418 {
419 if(_elements.at(i)->getTop()*dir > top*dir)
420 {
421 if(found == -1)
422 found = i;
423 else if(_elements.at(i)->getTop()*dir < _elements.at(found)->getTop()*dir)
424 found = i; // this is a better match
425 else if(_elements.at(i)->getTop()*dir == _elements.at(found)->getTop()*dir
426 &&
427 abs(_elements.at(i)->getLeft() - left) <
428 abs(_elements.at(found)->getLeft() - left))
429 found = i;
430 }
431 }
432 }
433 if(found >= 0)
434 goto matchfound;
435
436 // match found
437 matchfound:
438 if(found >= 0)
439 {
440 _elements.at(found)->setState(STATE::SELECTED);
441 if(selected >= 0)
442 _elements.at(selected)->resetState();
443 }
444}
445
447{
448 uint32_t elemSize = _elements.size();
449 for (uint32_t i = 0; i < elemSize; i++)
450 {
451 _elements.at(i)->resetText();
452 }
453}
454
456{
457 if(_elements.size() == 0 || (state == STATE::DISABLED && parentElement))
458 return;
459
460 uint32_t elemSize = _elements.size();
461 for (uint32_t i = 0; i < elemSize; ++i)
462 {
463 _elements.at(i)->update(controller);
464 }
465
466 this->toggleFocus(controller);
467
468 if(focus) // only send actions to this window if it's in focus
469 {
470 // pad/joystick navigation
471 if(controller->right())
472 this->moveSelectionHor(1);
473 else if(controller->left())
474 this->moveSelectionHor(-1);
475 else if(controller->down())
476 this->moveSelectionVert(1);
477 else if(controller->up())
478 this->moveSelectionVert(-1);
479 }
480
481 if(updateCB)
482 updateCB(this);
483}
Umbrella header for the platform-agnostic libgui core.
bool isVisible()
Checks whether or not the element is visible.
int getTop()
Gets the current topmost coordinate of the element Considers vertical alignment, y offset,...
void setRemoveOnDestroy(bool autoRemove)
Whether to notify parent on destruction to allow removal.
Definition GuiElement.h:77
STATE getState()
Gets the element's current state.
int width
Element width.
Definition GuiElement.h:273
UpdateCallback updateCB
Callback function to call when this element is updated.
Definition GuiElement.h:269
int height
Element height.
Definition GuiElement.h:274
GuiElement * parentElement
Parent element.
Definition GuiElement.h:270
void updateEffects()
Updates the element's effects (dynamic values) Called by Draw(), used for animation purposes.
int getWidth()
Gets the current width of the element.
GuiElement()
Constructor.
Definition GuiElement.cpp:9
bool visible
Visibility of the element.
Definition GuiElement.h:301
int getLeft()
Gets the current leftmost coordinate of the element Considers horizontal alignment,...
void setParent(GuiElement *e)
Set the element's parent.
virtual void draw()=0
Called constantly to redraw the element.
int focus
Element focus (-1 = focus disabled, 0 = not focused, 1 = focused)
Definition GuiElement.h:272
STATE state
Element state (DEFAULT, SELECTED, CLICKED, DISABLED)
Definition GuiElement.h:296
virtual GuiWindow * getAsWindow()
Attempts to cast this element as a GuiWindow (default implementation returns nullptr)
Definition GuiElement.h:266
int getHeight()
Gets the height of the element.
void moveSelectionIn(std::vector< GuiElement * > &list, NAV_DIR d)
Moves the selection within a collected list by on-screen geometry.
uint32_t getSize()
Returns the size of the list of elements.
void toggleFocus(InputController *c)
Changes window focus to the next focusable window or element If no element is in focus,...
bool collectNavigation(std::vector< GuiElement * > &out)
Gathers the elements selection can move between, looking inside layout containers.
void append(GuiElement *e)
Appends a GuiElement to the GuiWindow.
Definition GuiWindow.cpp:31
bool find(GuiElement *e)
Looks for the specified GuiElement.
Definition GuiWindow.cpp:85
void setFocus(int f)
Sets the window focus.
void setVisible(bool v)
Sets the visibility of the window.
void moveSelectionVert(int d)
Moves the selected element to the element above or below.
void resetState()
Resets the window's state to STATE::DEFAULT.
GuiElement * getGuiElementAt(uint32_t index) const
Returns the GuiElement at the specified index.
Definition GuiWindow.cpp:97
void appendWithAutoRemove(GuiElement *e)
Appends a GuiElement to the GuiWindow, and instructs the GuiElement to inform its parent on destructi...
Definition GuiWindow.cpp:41
void removeAll()
Removes all GuiElements.
Definition GuiWindow.cpp:75
GuiWindow()
Constructor.
Definition GuiWindow.cpp:9
int getSelected()
Gets the index of the GuiElement inside the window that is currently selected.
void draw()
Draws all the elements in this GuiWindow.
void setState(STATE s, int c=-1)
Sets the window state, propagated to every child element.
~GuiWindow()
Destructor.
Definition GuiWindow.cpp:23
void resetText()
Resets the text for all contained elements.
void update(InputController *c)
Updates the window and all elements contains within Allows the GuiWindow and all elements to respond ...
void insert(GuiElement *e, uint32_t i)
Inserts a GuiElement into the GuiWindow at the specified index.
Definition GuiWindow.cpp:48
void remove(GuiElement *e)
Removes the specified GuiElement from the GuiWindow.
Definition GuiWindow.cpp:58
std::vector< GuiElement * > _elements
Contains all elements within the GuiWindow.
Definition GuiWindow.h:96
void changeFocus(GuiElement *e)
Change the focus to the specified element This is intended for the primary GuiWindow only.
void drawWash()
Draws the dimming over a disabled screen: the one place that colour is set.
void moveSelectionHor(int d)
Moves the selected element to the element to the left or right.
Logical controller for one input channel.
STATE
Interaction state of a GuiElement (default, selected, clicked, held, disabled).
Definition GuiElement.h:37
NAV_DIR
Directions for moving the selection.
int GuiNavigate(const std::vector< GuiNavItem > &items, int current, NAV_DIR dir)
Picks which item the selection moves to.
8-bit-per-channel RGBA color used by the video interfaces.
Definition Mesh.h:16