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 ////////////////////////////////////////////////////
14 //
15 // Double Combo Box functions
16 //
17 ////////////////////////////////////////////////////
18
Add(const DoubleComboBox & item)19 DoubleComboBox* DoubleComboBox::Add(const DoubleComboBox& item)
20 {
21 ASSERT(item.count > 0 && "Double combo boxes cannot be empty!");
22
23 DoubleComboBox* pItem = new DoubleComboBox(item);
24 item.window->menuItems.push_back(pItem);
25 item.window->AddTabbing(pItem);
26 return pItem;
27 }
28
29 // Determines if the cursor is over this combo box
CursorOver()30 bool DoubleComboBox::CursorOver()
31 {
32 if (CursorColliding(this->x, this->y, this->width, this->height))
33 return true;
34
35 ////////////////////////////////////////////////////////////////////////////////////////////////////
36 if (this->status < 2)
37 return false;
38
39 if (this->bar1.status == 2)
40 return true;
41
42 int visibleCount = this->count - this->bar1.pos;
43 if (visibleCount > COMBOBOX_COUNT)
44 visibleCount = COMBOBOX_COUNT;
45
46 float flipMul = 1.0;
47 if (this->flipped)
48 flipMul = -1.0;
49
50 if (CursorColliding(this->x, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2, this->height * visibleCount, true))
51 return true;
52
53 ////////////////////////////////////////////////////////////////////////////////////////////////////
54 if (this->status < 3)
55 return false;
56
57 if (this->bar2.status == 2)
58 return true;
59
60 visibleCount = this->data[this->pos1]->GetCount() - this->bar2.pos;
61 if (visibleCount > COMBOBOX_COUNT)
62 visibleCount = COMBOBOX_COUNT;
63
64 float lOffset = (this->height + this->off * this->height) * flipMul - this->offset;
65
66 if (CursorColliding(this->x + this->width / 2, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2, this->height * visibleCount, true))
67 return true;
68
69 return false;
70 }
71
72 // Updates the combo box
Update()73 bool DoubleComboBox::Update()
74 {
75 // Going back
76 if (NegativeTriggered())
77 {
78 if (status >= 2)
79 TabSubIndex() = -1;
80
81 if (this->status >= 3)
82 {
83 this->status = 2;
84 TabSubIndex() = this->pos1 - this->bar1.pos;
85 }
86 else
87 {
88 this->pos1 = (*this->target1);
89 this->pos2 = (*this->target2);
90 this->status = 0;
91 }
92 }
93
94 // Also going back
95 if (TabIndex() && TabIndex()->object == this && this->status >= 3 && LeftTriggered())
96 {
97 this->status = 2;
98 TabSubIndex() = this->pos1 - this->bar1.pos;
99 }
100
101 // Activate tabbing if we're in PAD mode
102 if (this->status >= 2 && !TabIndex() && UsingPad())
103 {
104 this->bar1.Reset();
105 this->bar2.Reset();
106
107 TabIndex() = window->DummyTab();
108 TabSubIndex() = 0;
109
110 while (TabIndex()->object != this)
111 TabIndex() = TabIndex()->next;
112 }
113
114 float flipMul = 1.0;
115 if (this->flipped)
116 flipMul = -1.0;
117
118 bool overSecond = false;
119
120 // The second list of options
121 if (this->status >= 3)
122 {
123 int count = this->data[this->pos1]->GetCount();
124 float lOffset = (this->height + this->off * this->height) * flipMul - this->offset;
125
126 int pos = this->pos1;
127 if (this->status == 2)
128 pos = this->over1;
129
130 int position = this->bar1.pos + 0.5;
131
132 gIgnoreBounds = true;
133 this->bar2.x = this->x + size.x * 3 / 4 - SCROLLBAR_WIDTH / 2;
134 this->bar2.y = this->y - (5.5 + pos - position) * this->height;
135 this->bar2.count = count;
136 this->bar2.Update();
137 gIgnoreBounds = false;
138
139 float widthOffset = 0;
140
141 int visibleCount = count - this->bar2.pos;
142 if (visibleCount > COMBOBOX_COUNT)
143 visibleCount = COMBOBOX_COUNT;
144
145 if (count > COMBOBOX_COUNT)
146 widthOffset = this->bar2.width / 2;
147
148 // Combo boxes deal specially with tabbing
149 if (TabIndex())
150 {
151 // Tabbed away from us!
152 if (TabIndex()->object != this)
153 {
154 this->pos1 = (*this->target1);
155 this->pos2 = (*this->target2);
156 this->status = 0;
157
158 this->over1 = -1;
159 this->over2 = -1;
160 return true;
161 }
162
163 bool downTriggered = false;
164 bool upTriggered = false;
165
166 downTriggered = DownTriggered();
167 upTriggered = UpTriggered();
168
169 if (downTriggered)
170 {
171 TabSubIndex() ++;
172 if (TabSubIndex() > visibleCount - 1)
173 {
174 TabSubIndex() = visibleCount - 1;
175
176 this->bar2.pos ++;
177
178 if (this->bar2.pos > count - COMBOBOX_COUNT)
179 this->bar2.pos --;
180 }
181 }
182
183 if (upTriggered)
184 {
185 TabSubIndex() --;
186 if (TabSubIndex() < 0)
187 {
188 TabSubIndex() = 0;
189
190 this->bar2.pos --;
191
192 if (this->bar2.pos < 0)
193 this->bar2.pos ++;
194 }
195 }
196
197 CursorY() = window->GetY() + this->y - this->height * TabSubIndex() - lOffset;
198 CursorX() = window->GetX() + this->x + this->width / 2 - widthOffset;
199 }
200
201 // See if we're over one of the choices
202 if (CursorColliding(this->x + this->width / 2 - widthOffset, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2 - widthOffset * 2, this->height * visibleCount, true))
203 {
204 int choice = (window->GetY() + this->y + this->height / 2 - CursorY() - lOffset) / this->height;
205
206 if (choice < 0)
207 choice = 0;
208
209 // We've found our choice!
210 this->over2 = this->bar2.pos + choice;
211
212 if (PositiveTriggered())
213 {
214 this->pos2 = this->bar2.pos + choice;
215 this->status = 0;
216 (*this->target1) = this->pos1;
217 (*this->target2) = this->pos2;
218
219 TabSubIndex() = -1;
220
221 this->func(this->funcExtra);
222
223 return false;
224 }
225 }
226 else
227 {
228 this->over2 = -1;
229 }
230
231 if (CursorColliding(this->x + this->width / 2, this->y + this->height / 2 - this->height * visibleCount / 2 - lOffset, this->width / 2, this->height * visibleCount, true))
232 overSecond = true;
233 }
234
235 // The first list of options
236 if (this->status >= 2)
237 {
238 gIgnoreBounds = true;
239 this->bar1.x = this->x + size.x / 4 - SCROLLBAR_WIDTH / 2;
240 this->bar1.y = this->y - this->height * 5.5;
241 this->bar1.count = this->count;
242 this->bar1.Update();
243 gIgnoreBounds = false;
244
245 float widthOffset = 0;
246
247 int visibleCount = this->count - this->bar1.pos;
248 if (visibleCount > COMBOBOX_COUNT)
249 visibleCount = COMBOBOX_COUNT;
250
251 if (this->count > COMBOBOX_COUNT)
252 widthOffset = this->bar1.width / 2;
253
254 // Combo boxes deal specially with tabbing
255 if (status == 2 && TabIndex())
256 {
257 // Tabbed away from us!
258 if (TabIndex()->object != this)
259 {
260 this->pos1 = (*this->target1);
261 this->pos2 = (*this->target2);
262 this->status = 0;
263 return true;
264 }
265
266 // Just started
267 if (TabSubIndex() == -1)
268 TabSubIndex() = 0;
269
270 bool downTriggered = false;
271 bool upTriggered = false;
272
273 if (this->flipped)
274 {
275 downTriggered = UpTriggered();
276 upTriggered = DownTriggered();
277 }
278 else
279 {
280 downTriggered = DownTriggered();
281 upTriggered = UpTriggered();
282 }
283
284 if (downTriggered)
285 {
286 TabSubIndex() ++;
287 if (TabSubIndex() > visibleCount - 1)
288 {
289 TabSubIndex() = visibleCount - 1;
290
291 this->bar1.pos ++;
292
293 if (this->bar1.pos > this->count - COMBOBOX_COUNT)
294 this->bar1.pos --;
295 }
296 }
297
298 if (upTriggered)
299 {
300 TabSubIndex() --;
301 if (TabSubIndex() < 0)
302 {
303 TabSubIndex() = 0;
304
305 this->bar1.pos --;
306
307 if (this->bar1.pos < 0)
308 this->bar1.pos ++;
309 }
310 }
311
312 CursorY() = window->GetY() + this->y - (this->height + this->height * TabSubIndex()) * flipMul;
313 CursorX() = window->GetX() + this->x;
314 }
315
316 // See if we're over one of the choices
317 if (CursorColliding(this->x - widthOffset, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2 - widthOffset * 2, this->height * visibleCount, true))
318 {
319 int choice = (window->GetY() + this->y - (this->height / 2) * flipMul - CursorY()) / this->height * flipMul;
320
321 if (choice < 0)
322 choice = 0;
323
324 // We've found our choice!
325 this->over1 = this->bar1.pos + choice;
326
327 this->bar2.pos = 0;
328 this->bar2.wasMax = false;
329
330 if (PositiveTriggered() || (TabIndex() && RightTriggered()))
331 {
332 int old = this->pos1;
333 this->off = choice;
334 this->pos1 = this->bar1.pos + choice;
335 this->pos2 = -1;
336 this->over2 = -1;
337
338 if (this->status == 4 && old == this->pos1)
339 this->status = 3;
340 else
341 this->status = 4;
342
343 if (TabIndex())
344 TabSubIndex() = 0;
345
346 return false;
347 }
348
349 if (this->status == 3)
350 {
351 this->status = 2;
352 this->over2 = -1;
353 this->pos2 = -1;
354 }
355 }
356 else if (status >= 3) {}
357 // If we moved to the right, select the choice anyway!
358 else if (this->over1 >= 0 && CursorColliding(this->x + this->width / 2 - widthOffset, this->y - (this->height / 2 + this->height * COMBOBOX_COUNT / 2 + this->over1 * this->height) * flipMul, this->width / 2 - widthOffset * 2, this->height * COMBOBOX_COUNT, true))
359 {
360 this->off = this->over1 - this->bar1.pos + 0.5;
361 this->pos1 = this->over1;
362 this->pos2 = -1;
363 this->status = 3;
364
365 return Update();
366 }
367 else
368 {
369 this->over1 = -1;
370 this->over2 = -1;
371 }
372
373 if (overSecond || CursorColliding(this->x, this->y - (this->height / 2 + this->height * visibleCount / 2) * flipMul, this->width / 2, this->height * visibleCount, true))
374 return false;
375
376 if (PositiveTriggered())
377 {
378 this->pos1 = (*this->target1);
379 this->pos2 = (*this->target2);
380 this->status = 0;
381 }
382
383 if (this->CursorOver())
384 return false;
385
386 return true;
387 }
388
389 this->pos1 = (*this->target1);
390 this->pos2 = (*this->target2);
391
392 this->bar1.Reset();
393 this->bar2.Reset();
394
395 int status;
396
397 // We don't care as much if the cursor isn't being triggered
398 if (!PositiveTriggered())
399 status = 1;
400 else
401 status = 2;
402
403 // See if we just hit something
404 if (CursorColliding(this->x, this->y, this->width, this->height))
405 this->status = status;
406 else
407 this->status = 0;
408
409 this->over1 = -1;
410 this->over2 = -1;
411
412 return (this->status == 0);
413 }
414
415 // Draws the combo box
Draw()416 void DoubleComboBox::Draw()
417 {
418 float arrowWidth = this->height;
419
420 // The main box itself
421 if (this->status == 1)
422 {
423 DrawBox(CVec3(this->x, this->y, this->z + 0.003), size, CVec4(0.13, 0.13, 0.13));
424 DrawBox(CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.0035), CVec2(arrowWidth, this->height), CVec4(0.1, 0.1, 0.1));
425 }
426 else
427 {
428 DrawBox(CVec3(this->x, this->y, this->z + 0.003), size, CVec4(0.03, 0.03, 0.03));
429 DrawBox(CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.0035), CVec2(arrowWidth, this->height), CVec4(0.0, 0.0, 0.0));
430 }
431
432 // The "selected" text
433 char buffer[50];
434 sprintf(buffer, "%s - %s", this->data[(*this->target1)]->GetName(), this->data[(*this->target1)]->GetPointers()[(*this->target2)]->GetName());
435
436 DrawText(buffer, CVec3(this->x - arrowWidth / 2, this->y, this->z + 0.01), CVec2(this->width - arrowWidth, this->height * 0.7), CVec4(1.0, 1.0, 1.0));
437
438 // The arrow on the right
439 DrawTexQuad(*GetTexture(CW_TEXTURE_COMBODOWNARROW), CVec3(this->x + (this->width - arrowWidth) / 2, this->y, this->z + 0.005), CVec2(arrowWidth / 2, this->height / 2), CVec4(0.8, 0.8, 0.8));
440
441 // If the combo box is selected...
442 if (this->status >= 2)
443 {
444 // Draw regardless of depth
445 GX2SetDepthOnlyControl(GX2_ENABLE,
446 GX2_ENABLE,
447 GX2_COMPARE_ALWAYS);
448
449 float widthOffset = 0;
450
451 if (this->count > COMBOBOX_COUNT)
452 widthOffset = this->bar1.width / 2;
453
454 int count = COMBOBOX_COUNT;
455 if (count > this->count)
456 count = this->count;
457
458 this->flipped = false;
459 if (window->GetY() + this->y - this->height / 2 - this->height * count < -1.0 && window->GetY() + this->y + this->height / 2 + this->height * count < 1.0)
460 this->flipped = true;
461
462 float flipMul = 1.0;
463 if (this->flipped)
464 flipMul = -1.0;
465
466 DrawBox(CVec3(this->x, this->y - (this->height / 2 + this->height * count / 2) * flipMul, this->z + 0.5), CVec2(this->width / 2, this->height * count), CVec4(0.0, 0.0, 0.0));
467
468 int position = this->bar1.pos + 0.5;
469
470 float startY = this->y - this->height * flipMul;
471
472 // Draw a "highlight" if a choice is over
473 if (this->over1 >= position && this->over1 < position + COMBOBOX_COUNT)
474 DrawQuad(CVec3(this->x, startY - (this->over1 - position) * this->height * flipMul, this->z + 0.51), CVec2(this->width / 2, this->height), CVec4(0.2, 0.2, 0.2));
475
476 // Draw a "highlight" if a choice is selected
477 if (this->pos1 >= position && this->pos1 < position + COMBOBOX_COUNT && status >= 3)
478 DrawQuad(CVec3(this->x - widthOffset, startY - (this->pos1 - position) * this->height * flipMul, this->z + 0.52), CVec2(this->width / 2 - widthOffset * 2, this->height), CVec4(0.3, 0.3, 0.3));
479
480 if (count > position + COMBOBOX_COUNT)
481 count = position + COMBOBOX_COUNT;
482
483 // Figure out what color most of them will be
484 float color = 0.4;
485 if (this->status == 2)
486 color = 1.0;
487
488 // Draw only the elements we want to see!
489 for (int i = 0; i < count; ++i)
490 {
491 float tempColor = color;
492 if (i + position == this->over1 || i + position == this->pos1)
493 tempColor = 1.0;
494
495 DrawText(this->data[i + position]->GetName(), CVec3(this->x - this->bar1.width / 2, startY, this->z + 0.53), CVec2(this->width / 2 - this->bar1.width, this->height * 0.5), CVec4(tempColor, tempColor, tempColor));
496
497 startY -= this->height * flipMul;
498 }
499 // Draw regardless of depth
500 GX2SetDepthOnlyControl(GX2_ENABLE,
501 GX2_ENABLE,
502 GX2_COMPARE_ALWAYS);
503
504 this->bar1.x = this->x + size.x / 4 - SCROLLBAR_WIDTH / 2;
505 this->bar1.y = this->y - this->height * 5.5 * flipMul;
506 this->bar1.count = this->count;
507 this->bar1.Draw();
508
509 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
510 // If an option in the first combo box is selected...
511 int pos = this->pos1;
512 if (this->status == 2)
513 pos = this->over1;
514
515 if (pos >= 0)
516 {
517 float widthOffset = 0;
518
519 int count = this->data[pos]->GetCount();
520
521 if (count > COMBOBOX_COUNT)
522 {
523 widthOffset = this->bar2.width / 2;
524 count = COMBOBOX_COUNT;
525 }
526
527 int position = this->bar1.pos + 0.5;
528 int position2 = this->bar2.pos + 0.5;
529
530 float startY = this->y - (this->height + (pos - position) * this->height) * flipMul;
531
532 this->offset = 0;
533 if (window->GetY() + startY - this->height / 2 - this->height * count < -1.0)
534 this->offset = -window->GetY() - startY - this->height / 2 + this->height * count - 1.0;
535
536 startY += this->offset;
537
538 DrawBox(CVec3(this->x + this->width / 2, this->y + this->height / 2 - this->height * count / 2 - (this->height + (pos - position) * this->height) * flipMul + this->offset, this->z + 0.5), CVec2(this->width / 2, this->height * count), CVec4(0.0, 0.0, 0.0));
539
540 // Draw a "highlight" if a choice is over or selected
541 if (this->status >= 3)
542 {
543 if (this->over2 >= position2 && this->over2 < position2 + COMBOBOX_COUNT)
544 DrawQuad(CVec3(this->x - widthOffset + this->width / 2, startY - (this->over2 - position2) * this->height, this->z + 0.51), CVec2(this->width / 2 - widthOffset * 2, this->height), CVec4(0.2, 0.2, 0.2));
545 }
546
547 //float arrowY = startY;
548
549 // Draw only the elements we want to see!
550 SubCombo** pointers = this->data[pos]->GetPointers();
551 for (int i = 0; i < count; ++i)
552 {
553 DrawText(pointers[i + position2]->GetName(), CVec3(this->x + this->width / 2 - this->bar2.width / 2, startY, this->z + 0.52), CVec2(this->width / 2 - this->bar2.width, this->height * 0.5), CVec4(1.0, 1.0, 1.0));
554
555 startY -= this->height;
556 }
557
558 // Display a helpful arrow to point at the other box!
559 //DrawTexQuad(arrowTex[RIGHTARROW], this->x + this->width / 4, arrowY, this->z + 0.53, this->height * 0.7, this->height * 0.7, 0.8, 0.8, 0.8);
560
561 this->bar2.count = this->data[pos]->GetCount();
562 this->bar2.x = this->x + size.x * 3 / 4 - SCROLLBAR_WIDTH / 2;
563 this->bar2.y = startY + this->height / 2 + this->height * count / 2;
564 this->bar2.Draw();
565 }
566
567 // Draw normally again
568 GX2SetDepthOnlyControl(GX2_ENABLE,
569 GX2_ENABLE,
570 GX2_COMPARE_LESS);
571 }
572 }
573
Reset()574 void DoubleComboBox::Reset()
575 {
576 if (this->status > 0)
577 this->status = 0;
578 this->bar1.Reset();
579 this->bar2.Reset();
580 }
581