1 /*---------------------------------------------------------------------------*
2
3 Copyright (C) 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 // Creates a window manager
WindowManager(Peripheral * peripheral,GX2Texture ** textureList,float screenWidth)14 WindowManager::WindowManager(Peripheral* peripheral, GX2Texture** textureList, float screenWidth)
15 : dummyWindow(this, "", CVec2(0, 0), CVec2(0, 0)), windowOver(-1), windowActive(-1), windowDragging(false), oldWindowX(0), oldWindowY(0), cursorTime(0), tabIndex(NULL), tabSubIndex(-1), tabX(0), tabY(0)
16 {
17 this->peripheral = peripheral;
18
19 // Get all the textures
20 if (textureList)
21 memcpy(this->textureList, textureList, sizeof(this->textureList));
22 else
23 memset(this->textureList, NULL, sizeof(this->textureList));
24
25 this->screenWidth = screenWidth;
26 }
27
28 // Initialization in case we want to reinitialize something
SetPeripheral(Peripheral * peripheral)29 void WindowManager::SetPeripheral(Peripheral* peripheral)
30 {
31 this->peripheral = peripheral;
32 }
33
34 // Initialization in case we want to reinitialize something
SetTextureList(GX2Texture ** textureList)35 void WindowManager::SetTextureList(GX2Texture** textureList)
36 {
37 memcpy(this->textureList, textureList, sizeof(this->textureList));
38 }
39
40 // Initialization in case we want to reinitialize something
SetScreenWidth(float screenWidth)41 void WindowManager::SetScreenWidth(float screenWidth)
42 {
43 this->screenWidth = screenWidth;
44 }
45
46 // Updates the input for this window manager
UpdateInput()47 void WindowManager::UpdateInput()
48 {
49 tabX = 0;
50 tabY = 0;
51
52 // This is all we need for held functionality
53 cursorTime ++;
54
55 if (peripheral->PositiveTriggered())
56 cursorTime = 0;
57
58 // +Control Pad
59 int dX = peripheral->RightPressed() - peripheral->LeftPressed();
60 int dY = peripheral->UpPressed() - peripheral->DownPressed();
61
62 if ((dX || dY) && tabSubIndex == -1)
63 {
64 if (!peripheral->UsingPad())
65 {
66 peripheral->CursorX() = 0;
67 peripheral->CursorY() = 0;
68
69 peripheral->UsingPad() = true;
70 }
71
72 peripheral->CursorX() += dX * CURSOR_SPEED;
73 peripheral->CursorY() += dY * CURSOR_SPEED;
74
75 if (peripheral->CursorX() < -screenWidth)
76 peripheral->CursorX() = -screenWidth;
77 else if (peripheral->CursorX() > screenWidth)
78 peripheral->CursorX() = screenWidth;
79
80 if (peripheral->CursorY() < -1.0)
81 peripheral->CursorY() = -1.0;
82 else if (peripheral->CursorY() > 1.0)
83 peripheral->CursorY() = 1.0;
84
85 tabIndex = NULL;
86 tabSubIndex = -1;
87
88 return;
89 }
90
91 if (!peripheral->UsingPad())
92 {
93 tabIndex = NULL;
94 tabSubIndex = -1;
95 }
96
97 // Tabbing controls
98 if (tabIndex)
99 {
100 if (peripheral->TabRightTriggered())
101 {
102 tabIndex = tabIndex->next;
103 tabSubIndex = -1;
104 ForceValidTabForward();
105 return;
106 }
107 if (peripheral->TabLeftTriggered())
108 {
109 tabIndex = tabIndex->prev;
110 tabSubIndex = -1;
111 ForceValidTabBack();
112 return;
113 }
114
115 }
116 else
117 {
118 if (peripheral->TabRightTriggered() || peripheral->TabLeftTriggered())
119 {
120 tabIndex = &dummyWindow.dummyTab;
121 tabSubIndex = -1;
122 ForceValidTabForward();
123 peripheral->UsingPad() = true;
124 peripheral->UsingWiimote() = false;
125 return;
126 }
127 }
128
129 // Special tabbing controls
130 if (dX || dY)
131 {
132 // Can't be handled here, so let something else (combo box) handle it
133 tabX = dX;
134 tabY = dY;
135
136 peripheral->UsingPad() = true;
137
138 return;
139 }
140 }
141
142 // Constants for the close button
143 const float CLOSEBUTTON_X = WINDOW_HANDLE_HEIGHT / 2;
144 const float CLOSEBUTTON_Y = WINDOW_HANDLE_HEIGHT / 2;
145 const float CLOSEBUTTON_WIDTH = WINDOW_HANDLE_HEIGHT * 0.8;
146 const float CLOSEBUTTON_HEIGHT = WINDOW_HANDLE_HEIGHT * 0.8;
147
148 // A special update for the close button
UpdateCloseButton(Window * window)149 bool WindowManager::UpdateCloseButton(Window* window)
150 {
151 if (!window->canKill)
152 return false;
153
154 int status;
155
156 // We don't care as much if the cursor isn't being triggered
157 if (peripheral->PositiveTriggered())
158 status = 2;
159 else
160 status = 1;
161
162 // See if we just hit something
163 if (peripheral->CursorColliding(window, window->GetWidth() / 2 - CLOSEBUTTON_X, window->GetTop() + CLOSEBUTTON_Y - window->GetY(), CLOSEBUTTON_WIDTH, CLOSEBUTTON_HEIGHT, true))
164 window->closeStatus = status;
165 else
166 window->closeStatus = 0;
167
168 if (window->closeStatus == 2)
169 return true;
170
171 return false;
172 }
173
174 // A special draw for the close button
DrawCloseButton(Window * window)175 void WindowManager::DrawCloseButton(Window* window)
176 {
177 if (!window->canKill)
178 return;
179
180 CVec4 color = BlackLighter(window->closeStatus);
181 CVec4 color2 = WhiteDarker(window->closeStatus);
182
183 peripheral->DrawBox(CVec3(window->GetX() + window->GetWidth() / 2 - CLOSEBUTTON_X, window->GetTop() + CLOSEBUTTON_Y, 0.999), CVec2(CLOSEBUTTON_WIDTH, CLOSEBUTTON_HEIGHT), color);
184 peripheral->DrawTextCenter("X", CVec3(window->GetX() + window->GetWidth() / 2 - CLOSEBUTTON_X, window->GetTop() + CLOSEBUTTON_Y, 0.9991), CVec2(CLOSEBUTTON_WIDTH, CLOSEBUTTON_HEIGHT), color2);
185 }
186
187 // Sorts the list by z value
SortList(std::list<MenuItem * > & list)188 void SortList(std::list<MenuItem*>& list)
189 {
190 // Bubble sort!
191 for (std::list<MenuItem*>::iterator iter = list.begin(); iter != list.end(); ++iter)
192 {
193 std::list<MenuItem*>::iterator iter2 = iter;
194 ++iter2;
195
196 for (; iter2 != list.end(); ++iter2)
197 {
198 if ((*iter)->z < (*iter2)->z)
199 {
200 MenuItem* temp = *iter2;
201 *iter2 = *iter;
202 *iter = temp;
203 }
204 }
205 }
206 }
207
208 // Draws the windows
Draw()209 void WindowManager::Draw()
210 {
211 // This is how the manager typically draws!
212 GX2SetDepthOnlyControl(GX2_ENABLE,
213 GX2_ENABLE,
214 GX2_COMPARE_LESS);
215
216 for (int i = windowList.size() - 1; i >= 0; --i)
217 {
218 Window* window = windowList[windowOrder[i]];
219 if (window->visible && !window->master)
220 {
221 // First, draw the window quad and title
222 peripheral->DrawWindowQuad(CVec2(window->GetX(), window->GetTop()), CVec2(window->GetWidth(), window->GetHeight()), i == 0, window->Enabled(), CVec3(0.1, 0.1, 0.1), window->GetName());
223
224 // Then draw the close button
225 DrawCloseButton(window);
226
227 // Sort them by z!
228 window->sortedDrawItems = window->menuItems;
229 SortList(window->sortedDrawItems);
230
231 // Then draw the window and its items
232 window->PreDraw();
233 window->Draw();
234 for (std::list<MenuItem*>::reverse_iterator iter = window->sortedDrawItems.rbegin(); iter != window->sortedDrawItems.rend(); ++iter)
235 {
236 if ((*iter)->visible)
237 (*iter)->Draw();
238 }
239
240 // Then draw the child window
241 float y = window->y - window->height;
242 Window* custom = window->child;
243 while (custom)
244 {
245 // Sort them by z!
246 custom->sortedDrawItems = custom->menuItems;
247 SortList(custom->sortedDrawItems);
248
249 // Drawn at an offset!
250 custom->x = window->x;
251 custom->y = y;
252 custom->offY = window->offY;
253 custom->Draw();
254 for (std::list<MenuItem*>::reverse_iterator iter = custom->sortedDrawItems.rbegin(); iter != custom->sortedDrawItems.rend(); ++iter)
255 {
256 if ((*iter)->visible)
257 (*iter)->Draw();
258 }
259
260 y -= custom->maxHeight;
261 custom = custom->child;
262 }
263 }
264 }
265
266 // The cursor!
267 peripheral->DrawTexQuad(*GetTexture(CW_TEXTURE_CURSOR), CVec3(peripheral->CursorX(), peripheral->CursorY(), 1.0), CVec2(0.25, 0.25), CVec4(1.0, 1.0, 1.0, 1.0));
268 }
269
270 // Updates the windows
Update(bool canBeOver)271 void WindowManager::Update(bool canBeOver)
272 {
273 this->canBeOver = canBeOver;
274
275 UpdateInput();
276
277 if (tabIndex)
278 BringWindowToFront(tabIndex->window);
279
280 bool overCore[MAX_WINDOWS] = {0};
281 bool overHandle[MAX_WINDOWS] = {0};
282
283 if (!peripheral->PositivePressed() || tabIndex)
284 windowDragging = false;
285
286 int oldWindowActive = windowActive;
287
288 // Drag the window!
289 if (windowDragging)
290 {
291 Window* window = windowList[windowOrder[0]];
292
293 window->x += peripheral->CursorX() - oldWindowX;
294 window->y += peripheral->CursorY() - oldWindowY;
295
296 oldWindowX = peripheral->CursorX();
297 oldWindowY = peripheral->CursorY();
298 }
299
300 // Figure out which window we're over
301 windowOver = -1;
302 for (int i = 0; i < windowList.size(); ++i)
303 {
304 Window* window = windowList[windowOrder[i]];
305 if (!window->visible || window->master)
306 continue;
307
308 overCore[windowOrder[i]] = window->CursorOver();
309 overHandle[windowOrder[i]] = peripheral->CursorColliding(window, window->x - window->GetX(), window->y + WINDOW_HANDLE_HEIGHT / 2 - window->GetY(), window->GetWidth(), WINDOW_HANDLE_HEIGHT, true);
310 if (overCore[windowOrder[i]] || overHandle[windowOrder[i]])
311 {
312 windowOver = windowOrder[i];
313
314 if (!window->enabled)
315 windowOver = -1;
316
317 break;
318 }
319 }
320
321 // Move the window to the front!
322 if (peripheral->PositiveTriggered())
323 {
324 BringWindowToFront();
325
326 if (windowActive != -1 && !overCore[windowActive] && windowList[windowActive]->Active())
327 {
328 oldWindowX = peripheral->CursorX();
329 oldWindowY = peripheral->CursorY();
330 windowDragging = true;
331 }
332 }
333
334 if (windowActive != oldWindowActive && oldWindowActive != -1)
335 windowList[oldWindowActive]->Reset();
336
337 bool canUpdate = true;
338
339
340 std::vector<Window*> windows(windowList.size());
341 std::vector<bool> bools(windowList.size());
342
343 for (int i = 0; i < windowList.size(); ++i)
344 {
345 windows[i] = windowList[windowOrder[i]];
346 bools[i] = (overCore[windowOrder[i]] || overHandle[windowOrder[i]]);
347 }
348
349 for (int i = 0; i < windows.size(); ++i)
350 {
351 Window* window = windows[i];
352 if (window->Active() && !window->master)
353 {
354 // Check for close button activity
355 if (canUpdate && UpdateCloseButton(window))
356 {
357 window->Hide();
358 windowDragging = false;
359 canUpdate = false;
360 continue;
361 }
362
363 // Then update the window and its items
364 canUpdate = window->Update(canUpdate);
365
366 // Sort them by z!
367 window->sortedItems = window->menuItems;
368 SortList(window->sortedItems);
369
370 // Then update the child windows
371 float y = window->y - window->height;
372 Window* custom = window->child;
373 while (custom)
374 {
375 // Update at an offset!
376 custom->x = window->x;
377 custom->y = y;
378 custom->offY = window->offY;
379 canUpdate = custom->Update(canUpdate);
380
381 // Sort them by z!
382 custom->sortedItems = custom->menuItems;
383 SortList(custom->sortedItems);
384
385 y -= custom->maxHeight;
386 custom = custom->child;
387 }
388
389 if (canUpdate)
390 {
391 Window* custom = window;
392
393 while (custom)
394 {
395 std::list<MenuItem*>::iterator iter = custom->sortedItems.begin();
396 std::list<MenuItem*>::iterator preiter = custom->sortedItems.begin();
397
398 // If an object has priority, it can block the ones after it!
399 for ( ; preiter != custom->sortedItems.end(); ++preiter)
400 {
401 if ((*preiter)->status >= 2 && (*preiter)->visible)
402 {
403 canUpdate = (*preiter)->Update();
404 goto HIGH_PRIORITY_OBJECT_DONE;
405 }
406 }
407
408 custom = custom->child;
409 }
410
411 // We're done with the focused object!
412 HIGH_PRIORITY_OBJECT_DONE:
413
414 canUpdate = window->PreUpdate(canUpdate);
415
416 custom = window;
417 while (custom)
418 {
419 std::list<MenuItem*>::iterator iter = custom->sortedItems.begin();
420
421 if (canUpdate)
422 {
423 // If the cursor is over an object, it can block the ones after it!
424 for ( ; iter != custom->sortedItems.end(); ++iter)
425 {
426 if ((*iter)->status < 2 && (*iter)->status != -1 && (*iter)->visible && !(*iter)->Update())
427 {
428 canUpdate = false;
429 ++iter;
430 break;
431 }
432 }
433 }
434
435 // The rest just get reset
436 for ( ; iter != custom->sortedItems.end(); ++iter)
437 {
438 if ((*iter)->status < 2)
439 (*iter)->Reset();
440 }
441
442 custom = custom->child;
443 }
444 }
445 else
446 {
447 // Do the PreUpdate, but with false instead of true!
448 window->PreUpdate(false);
449
450 // Reset all the objects...
451 std::list<MenuItem*>::iterator iter = window->sortedItems.begin();
452 for ( ; iter != window->sortedItems.end(); ++iter)
453 (*iter)->Reset();
454
455 // Including the ones in child windows!
456 Window* custom = window->child;
457 while (custom)
458 {
459 std::list<MenuItem*>::iterator iter = custom->sortedItems.begin();
460 for ( ; iter != custom->sortedItems.end(); ++iter)
461 (*iter)->Reset();
462
463 custom = custom->child;
464 }
465 }
466
467 if (bools[i])
468 canUpdate = false;
469 }
470 }
471
472 // Clean up any windows that need deleted
473 for (int i = 0; i < windowList.size(); ++i)
474 {
475 if (windowList[i]->Deleted())
476 {
477 delete windowList[i];
478 --i;
479 }
480 }
481
482 // Now update the tabbing!
483 UpdateTabbing();
484 }
485
486 // Brings a specific window to the front
BringWindowToFront(Window * window)487 void WindowManager::BringWindowToFront(Window* window)
488 {
489 while (window->master)
490 window = window->master;
491
492 windowOver = window->number;
493 BringWindowToFront();
494 }
495
496 // Actually reorders the windows to put the active one in front
BringWindowToFront()497 void WindowManager::BringWindowToFront()
498 {
499 windowActive = windowOver;
500
501 for (int i = windowList.size() - 2; i >= 0; --i)
502 {
503 if (windowOver == windowOrder[i + 1])
504 {
505 windowOrder[i + 1] = windowOrder[i];
506 windowOrder[i] = windowOver;
507 }
508 }
509 }
510
511 // Adds the window to the list of windows
AddToWindowList(Window * window)512 void WindowManager::AddToWindowList(Window* window)
513 {
514 if (window->manager)
515 window->manager->RemoveFromWindowList(window);
516
517 window->number = windowList.size();
518
519 windowList.push_back(window);
520
521 windowOrder.push_back(window->number);
522
523 window->manager = this;
524 }
525
526 // Removes the window from the list of windows
RemoveFromWindowList(Window * window)527 void WindowManager::RemoveFromWindowList(Window* window)
528 {
529 if (!window || window->manager != this)
530 return;
531
532 window->Hide();
533
534 windowList.erase(windowList.begin() + window->number);
535
536 for (int i = 0; i < windowOrder.size(); ++i)
537 {
538 if (windowOrder[i] > window->number)
539 windowOrder[i] --;
540 else if (windowOrder[i] == window->number)
541 {
542 windowOrder.erase(windowOrder.begin() + i);
543 --i;
544 }
545 }
546
547 for (int i = window->number; i < windowList.size(); ++i)
548 windowList[i]->number --;
549
550 window->manager = NULL;
551
552 if (windowActive == window->number)
553 {
554 windowActive = -1;
555 windowOver = -1;
556
557 tabIndex = NULL;
558 tabSubIndex = -1;
559 }
560 if (windowOver == window->number)
561 {
562 windowOver = -1;
563
564 tabIndex = NULL;
565 tabSubIndex = -1;
566 }
567 }
568
569 // A function to get the texture, in case it changes at some point
GetTexture(CWTextures num)570 GX2Texture** WindowManager::GetTexture(CWTextures num)
571 {
572 return &this->textureList[num];
573 }
574
575 // A function to get the texture list itself
GetTextureList()576 GX2Texture** WindowManager::GetTextureList()
577 {
578 return this->textureList;
579 }
580