1 /*---------------------------------------------------------------------------*
2 
3   Copyright (C) 2010-2012 Nintendo.  All rights reserved.
4 
5   These coded instructions, statements, and computer programs contain
6   proprietary information of Nintendo of America Inc. and/or Nintendo
7   Company Ltd., and are protected by Federal copyright law.  They may
8   not be disclosed to third parties or copied or duplicated in any form,
9   in whole or in part, without the prior written consent of Nintendo.
10 
11  *---------------------------------------------------------------------------*/
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <math.h>
17 #include <vector>
18 #include <list>
19 #include <hash_map>
20 
21 #include <cafe/os.h>
22 
23 #include <cafe/gx2.h>
24 
25 #include <cafe/demo/demowin.h>
26 
27 namespace DEMOWin
28 {
29 
30 #include "demowin/demowin_tabbing.cpp"
31 #include "demowin/demowin_helpers.cpp"
32 
33 #include "demowin/demowin_manager.cpp"
34 
35 #include "demowin/demowin_tab_window.cpp"
36 
37 #include "demowin/demowin_button.cpp"
38 #include "demowin/demowin_held_button.cpp"
39 
40 #include "demowin/demowin_scroll_bar.cpp"
41 #include "demowin/demowin_slider_bar.cpp"
42 #include "demowin/demowin_slider_bar_float.cpp"
43 
44 #include "demowin/demowin_combo_box.cpp"
45 #include "demowin/demowin_double_combo_box.cpp"
46 
47 #include "demowin/demowin_text.cpp"
48 #include "demowin/demowin_text_center.cpp"
49 #include "demowin/demowin_text_right.cpp"
50 #include "demowin/demowin_text_multi.cpp"
51 
52     // A very special flag to ignore window bounds for input (i.e. for combo boxes)
53 bool gIgnoreBounds = false;
54 
ComboCustom(WindowManager * manager,const char * name,const AutoList<int> & start,const AutoList<const char * > & names,const AutoList<AutoList<const char * >> & option)55 ComboCustom::ComboCustom(WindowManager* manager, const char* name, const AutoList<int>& start, const AutoList<const char*>& names, const AutoList<AutoList<const char*> >& option)
56     : Window(manager, name, CVec2(0, 0), CVec2(1.4, 0.1 + start.count * 0.1))
57 {
58     ASSERT(start.count == names.count && names.count == option.count);
59 
60     int count = start.count;
61 
62         // Set up the counts array
63     std::vector<int> counts;
64     counts.resize(count);
65 
66     for (int i = 0; i < counts.size(); ++i)
67         counts[i] = option.args[i].count;
68 
69         // Set up the option array
70     std::vector<const char* const*> optionArray;
71     optionArray.resize(count);
72 
73     for (int i = 0; i < optionArray.size(); ++i)
74         optionArray[i] = option.args[i].args;
75 
76     Init(count, &counts[0], start.args, names.args, &optionArray[0]);
77 }
78 
ComboCustom(WindowManager * manager,const char * name,const AutoList<int> & start,const AutoList<const char * > & names,const AutoList<std::vector<const char * >> & option)79 ComboCustom::ComboCustom(WindowManager* manager, const char* name, const AutoList<int>& start, const AutoList<const char*>& names, const AutoList<std::vector<const char*> >& option)
80     : Window(manager, name, CVec2(0, 0), CVec2(1.4, 0.1 + start.count * 0.1))
81 {
82     ASSERT(start.count == names.count && names.count == option.count);
83 
84     int count = start.count;
85 
86         // Set up the counts array
87     std::vector<int> counts;
88     counts.resize(count);
89 
90     for (int i = 0; i < counts.size(); ++i)
91         counts[i] = option.args[i].size();
92 
93         // Set up the option array
94     std::vector<const char* const*> optionArray;
95     optionArray.resize(count);
96 
97     for (int i = 0; i < optionArray.size(); ++i)
98         optionArray[i] = &option.args[i][0];
99 
100     Init(count, &counts[0], start.args, names.args, &optionArray[0]);
101 }
102 
ComboCustom(WindowManager * manager,const char * name,const std::vector<int> & start,const std::vector<const char * > & names,const std::vector<std::vector<const char * >> & option)103 ComboCustom::ComboCustom(WindowManager* manager, const char* name, const std::vector<int>& start, const std::vector<const char*>& names, const std::vector<std::vector<const char*> >& option)
104     : Window(manager, name, CVec2(0, 0), CVec2(1.4, 0.1 + option.size() * 0.1))
105 {
106     ASSERT(start.size() == names.size());
107     ASSERT(names.size() == option.size());
108     ASSERT(option.size() <= 10);
109 
110     int count = start.size();
111 
112         // Set up the counts array
113     std::vector<int> counts;
114     counts.resize(count);
115 
116     for (int i = 0; i < counts.size(); ++i)
117         counts[i] = option[i].size();
118 
119         // Set up the option array
120     std::vector<const char* const*> optionArray;
121     optionArray.resize(count);
122 
123     for (int i = 0; i < optionArray.size(); ++i)
124         optionArray[i] = &option[i][0];
125 
126     Init(count, &counts[0], &start[0], &names[0], &optionArray[0]);
127 }
128 
Init(int num,const int * counts,const int * start,const char * const * names,const char * const * const * option)129 void ComboCustom::Init(int num, const int* counts, const int* start, const char* const* names, const char* const* const* option)
130 {
131     MenuText text(this, CVec3(0, 0, 0.1), CVec2(1.0, 0.07), "", CVec4(1.0, 1.0, 1.0));
132     ComboBox box(this, CVec3(0.4, 0, 0.1), CVec2(0.4, 0.09), NULL, 0, NULL);
133 
134     for (int j = 0; j < num; ++j)
135     {
136         choice[j] = start[j];
137 
138         int count = counts[j];
139 
140         options[j].resize(count);
141         optionsList[j].resize(count);
142 
143             // Figure out how many options we actually have (no limit)
144         for (int i = 0; i < count; ++i)
145         {
146             options[j][i] = option[j][i];
147             optionsList[j][i] = &options[j][i];
148         }
149 
150         text.text = names[j];
151         text.y = -0.1 - j * 0.1;
152         MenuText::Add(text);
153 
154         box.data = &optionsList[j][0];
155         box.count = count;
156         box.target = &choice[j];
157         box.y = -0.1 - j * 0.1;
158         ComboBox::Add(box);
159     }
160 }
161 
162     // Constructs the window
Window(WindowManager * manager,const char * _name,CVec2 _position,CVec2 _size,CVec2 _maxSize,bool _canKill)163 Window::Window(WindowManager* manager, const char* _name, CVec2 _position, CVec2 _size, CVec2 _maxSize, bool _canKill)
164     : name(_name), position(_position), size(_size), maxSize(_maxSize), x(position.x), y(position.y), width(size.x), height(size.y), maxWidth(maxSize.x), maxHeight(maxSize.y), canKill(_canKill), deleteFlag(false), offY(0), visible(false), enabled(true), master(NULL), child(NULL), dummyTab(this), manager(NULL)
165 {
166     if (maxHeight <= 0)
167         maxHeight = height;
168 
169     ASSERT(width >= 0);
170     ASSERT(height >= 0);
171     ASSERT(maxHeight >= height);
172 
173     manager->AddToWindowList(this);
174 
175     scrollBar = new ScrollBar(this, CVec3(width / 2 - SCROLLBAR_WIDTH / 2, -height / 2, 0.9), CVec2(SCROLLBAR_WIDTH, height), maxHeight, height);
176     menu = new MenuItem(this);
177 }
178 
179     // Not that this would ever be called, but...
~Window()180 Window::~Window()
181 {
182     for (std::list<MenuItem*>::iterator iter = this->menuItems.begin(); iter != this->menuItems.end(); ++iter)
183         delete (*iter);
184 
185     this->menuItems.clear();
186     this->tabItems.clear();
187 
188     delete scrollBar;
189     delete menu;
190 
191     this->manager->RemoveFromWindowList(this);
192 }
193 
194     // Returns the top
GetOffY()195 float& Window::GetOffY()
196 {
197         // Master knows best!
198     if (this->master)
199         return this->master->GetOffY();
200 
201     return this->offY;
202 }
203 
204     // Returns the top
GetTop()205 float Window::GetTop()
206 {
207         // Master knows best!
208     if (this->master)
209         return this->master->GetTop();
210 
211     return this->y;
212 }
213 
214     // Returns the width
GetWidth()215 float Window::GetWidth()
216 {
217         // Master knows best!
218     if (this->master)
219         return this->master->GetWidth();
220 
221     float ret = this->width;
222 
223     Window* custom = this->child;
224     while (custom)
225     {
226         if (custom->width > ret)
227             ret = custom->width;
228 
229         custom = custom->child;
230     }
231 
232     return ret;
233 }
234 
235     // Returns the height
GetHeight()236 float Window::GetHeight()
237 {
238         // Master knows best!
239     if (this->master)
240         return this->master->GetHeight();
241 
242     float ret = this->height;
243 
244     Window* custom = this->child;
245     while (custom)
246     {
247         ret += custom->height;
248         custom = custom->child;
249     }
250 
251     return ret;
252 }
253 
254     // Returns the maximum height
GetMaxHeight()255 float Window::GetMaxHeight()
256 {
257         // Master knows best!
258     if (this->master)
259         return this->master->GetMaxHeight();
260 
261     float ret = this->maxHeight;
262 
263     Window* custom = this->child;
264     while (custom)
265     {
266         ret += custom->maxHeight;
267         custom = custom->child;
268     }
269 
270     return ret;
271 }
272 
273     // Returns the ultimate master of this window
GetMaster()274 Window* Window::GetMaster()
275 {
276         // We're the ultimate master!
277     if (!this->master)
278         return this;
279 
280     return this->master->GetMaster();
281 }
282 
283     // Determines if the cursor is over this window
CursorOver()284 bool Window::CursorOver()
285 {
286     if (manager->peripheral->CursorColliding(this->GetX(), this->GetTop() - this->GetHeight() / 2, this->GetWidth(), this->GetHeight()))
287         return true;
288 
289     for (std::list<MenuItem*>::iterator iter = this->menuItems.begin(); iter != this->menuItems.end(); ++iter)
290     {
291         if ((*iter)->CursorOver())
292             return true;
293     }
294 
295         // Don't forget the child's menu items!
296     if (this->child)
297         return this->child->CursorOver();
298 
299     return false;
300 }
301 
302     // Resets the items in the window
Reset()303 void Window::Reset()
304 {
305     for (std::list<MenuItem*>::iterator iter = this->menuItems.begin(); iter != this->menuItems.end(); ++iter)
306         (*iter)->Reset();
307 
308     scrollBar->Reset();
309 }
310 
311     // Causes a window to become hidden
Hide()312 void Window::Hide()
313 {
314     this->visible = false;
315 
316         // Cut all our ties!
317     DetachWindow();
318     if (this->master)
319         this->master->DetachWindow();
320 }
321 
322     // Causes a window to become visible
Show()323 void Window::Show()
324 {
325     this->visible = true;
326 }
327 
328     // Determines if this window is in front
InFront()329 bool Window::InFront()
330 {
331     return (this == manager->GetWindowList()[manager->GetWindowOrder()[0]]);
332 }
333 
334     // Determines if this window is enabled
Enabled()335 bool Window::Enabled()
336 {
337     return this->GetMaster()->enabled;
338 }
339 
340     // Determines if this window is visible
Visible()341 bool Window::Visible()
342 {
343     return this->GetMaster()->visible;
344 }
345 
346     // Brings a window to the front
BringToFront()347 void Window::BringToFront()
348 {
349     if (this->InFront())
350         return;
351 
352     this->manager->BringWindowToFront(this);
353 
354     menu->TabIndex() = NULL;
355     menu->TabSubIndex() = -1;
356 }
357 
358     // Brings a window to the front
ClearItems()359 void Window::ClearItems()
360 {
361     for (std::list<MenuItem*>::iterator iter = menuItems.begin(); iter != menuItems.end(); ++iter)
362         delete *iter;
363 
364     menuItems.clear();
365     tabItems.clear();
366     sortedItems.clear();
367     sortedDrawItems.clear();
368 }
369 
370     // Anything special the window updates beforehand
PreUpdate(bool canUpdate)371 bool Window::PreUpdate(bool canUpdate)
372 {
373     this->offY = 0;
374 
375     if (canUpdate)
376     {
377         float height = this->GetHeight();
378         scrollBar->count = this->GetMaxHeight();
379         scrollBar->max = height;
380         scrollBar->x = (this->GetWidth() - SCROLLBAR_WIDTH) / 2;
381         scrollBar->y = -height / 2;
382         scrollBar->height = height;
383         canUpdate = scrollBar->Update();
384     }
385     else
386         scrollBar->Reset();
387 
388     this->offY = scrollBar->pos;
389 
390     return canUpdate;
391 }
392 
393     // Anything special the window draws beforehand
PreDraw()394 void Window::PreDraw()
395 {
396     float temp = this->offY;
397     this->offY = 0;
398 
399     float height = this->GetHeight();
400     scrollBar->count = this->GetMaxHeight();
401     scrollBar->max = height;
402     scrollBar->x = (this->GetWidth() - SCROLLBAR_WIDTH) / 2;
403     scrollBar->y = -height / 2;
404     scrollBar->height = height;
405     scrollBar->Draw();
406 
407     this->offY = temp;
408 }
409 
410     // Attaches a window (replaces the old one)
AttachWindow(Window * window)411 void Window::AttachWindow(Window* window)
412 {
413     DetachWindow();
414 
415         // Could be NULL!
416     if (!window)
417         return;
418 
419         // Make sure the old master of this child isn't the master anymore!
420     if (window->master)
421         window->master->DetachWindow();
422 
423     this->child = window;
424     window->master = this;
425     window->visible = true;
426 }
427 
428     // Detaches the current child window
DetachWindow()429 void Window::DetachWindow()
430 {
431     if (!this->child)
432         return;
433 
434     this->child->master = NULL;
435     this->child->Hide();
436     this->child = NULL;
437 
438         // Reset the master's offset!
439     Window* master = this;
440     while (master->master)
441         master = master->master;
442     master->offY = 0;
443 }
444 
445     // Detaches the current child window
AddTabbing(MenuItem * item)446 void Window::AddTabbing(MenuItem* item)
447 {
448     tabItems.push_back(TabObject());
449     TabObject& tab = tabItems.back();
450     tab.Add(this, item, true);
451 }
452 
453 }
454