1 /****************************************************************************
2 * gui.c
3 *
4 * generic GUI Engine (using GX rendering)
5 *
6 * Copyright Eke-Eke (2009-2014)
7 *
8 * Redistribution and use of this code or any derivative works are permitted
9 * provided that the following conditions are met:
10 *
11 * - Redistributions may not be sold, nor may they be used in a commercial
12 * product or activity.
13 *
14 * - Redistributions that are modified from the original source must include the
15 * complete source code, including the source code for all components used by a
16 * binary built from the modified sources. However, as a special exception, the
17 * source code distributed need not include anything that is normally distributed
18 * (in either source or binary form) with the major components (compiler, kernel,
19 * and so on) of the operating system on which the executable runs, unless that
20 * component itself accompanies the executable.
21 *
22 * - Redistributions must reproduce the above copyright notice, this list of
23 * conditions and the following disclaimer in the documentation and/or other
24 * materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 ****************************************************************************************/
39
40 #include "shared.h"
41 #include "gui.h"
42 #include "font.h"
43
44 #ifdef HW_RVL
45 gx_texture *w_pointer;
46 #endif
47
48 u8 SILENT = 0;
49
50 /* message box */
51 static gui_message message_box;
52 static lwp_t msgboxthread;
53
54 /* background color (black) */
55 static const GXColor bg_color = {0x00,0x00,0x00,0xff};
56
57 /****************************************************************************/
58 /* Generic GUI routines */
59 /*****************************************************************************/
60
61 /* Allocate Menu texture images data */
GUI_InitMenu(gui_menu * menu)62 void GUI_InitMenu(gui_menu *menu)
63 {
64 int i;
65 gui_item *item;
66 gui_butn *button;
67 gui_image *image;
68
69 /* background elements */
70 for (i=0; i<menu->max_images; i++)
71 {
72 image = &menu->bg_images[i];
73 image->texture = gxTextureOpenPNG(image->data,0);
74 }
75
76 for (i=0; i<2; i++)
77 {
78 /* key helpers */
79 item = menu->helpers[i];
80 if (item)
81 item->texture = gxTextureOpenPNG(item->data,0);
82
83 /* arrows */
84 button = menu->arrows[i];
85 if (button)
86 {
87 if (!button->data->texture[0])
88 button->data->texture[0] = gxTextureOpenPNG(button->data->image[0],0);
89 if (!button->data->texture[1])
90 button->data->texture[1] = gxTextureOpenPNG(button->data->image[1],0);
91
92 /* initial state */
93 button->state &= ~BUTTON_VISIBLE;
94 if (((i==0) && (menu->offset != 0)) || ((i==1) && (menu->offset + menu->max_buttons) < menu->max_items))
95 button->state |= BUTTON_VISIBLE;
96 }
97 }
98
99 /* menu buttons */
100 for (i=0; i<menu->max_buttons; i++)
101 {
102 button = &menu->buttons[i];
103 if (button->data)
104 {
105 if (!button->data->texture[0])
106 button->data->texture[0] = gxTextureOpenPNG(button->data->image[0],0);
107 if (!button->data->texture[1])
108 button->data->texture[1] = gxTextureOpenPNG(button->data->image[1],0);
109 }
110 }
111
112 /* menu items */
113 for (i=0; i<menu->max_items; i++)
114 {
115 item = &menu->items[i];
116 if (item->data)
117 item->texture = gxTextureOpenPNG(item->data,0);
118 }
119
120 /* update message box */
121 message_box.parent = menu;
122 }
123
124 /* Release Menu allocated memory */
GUI_DeleteMenu(gui_menu * menu)125 void GUI_DeleteMenu(gui_menu *menu)
126 {
127 int i;
128 gui_butn *button;
129 gui_item *item;
130 gui_image *image;
131
132 /* background elements */
133 for (i=0; i<menu->max_images; i++)
134 {
135 image = &menu->bg_images[i];
136 gxTextureClose(&image->texture);
137 }
138
139 for (i=0; i<2; i++)
140 {
141 /* key helpers */
142 item = menu->helpers[i];
143 if (item)
144 gxTextureClose(&item->texture);
145
146 /* arrows */
147 button = menu->arrows[i];
148 if (button)
149 {
150 gxTextureClose(&button->data->texture[0]);
151 gxTextureClose(&button->data->texture[1]);
152 }
153 }
154
155 /* menu buttons */
156 for (i=0; i<menu->max_buttons; i++)
157 {
158 button = &menu->buttons[i];
159 if (button->data)
160 {
161 gxTextureClose(&button->data->texture[0]);
162 gxTextureClose(&button->data->texture[1]);
163 }
164 }
165
166 /* menu items */
167 for (i=0; i<menu->max_items; i++)
168 {
169 item = &menu->items[i];
170 gxTextureClose(&item->texture);
171 }
172 }
173
174 extern void gxSnapshot(void);
175
176 /* Draw Menu */
GUI_DrawMenu(gui_menu * menu)177 void GUI_DrawMenu(gui_menu *menu)
178 {
179 int i;
180 gui_item *item;
181 gui_butn *button;
182 gui_image *image;
183
184 /* background color */
185 if (menu->screenshot)
186 {
187 gxClearScreen((GXColor)BLACK);
188 gxDrawScreenshot(menu->screenshot);
189 }
190 else
191 {
192 gxClearScreen(bg_color);
193 }
194
195 /* background elements */
196 for (i=0; i<menu->max_images; i++)
197 {
198 image = &menu->bg_images[i];
199 if (image->state & IMAGE_VISIBLE)
200 {
201 if (image->state & IMAGE_REPEAT)
202 gxDrawTextureRepeat(image->texture,image->x,image->y,image->w,image->h,image->alpha);
203 else
204 gxDrawTexture(image->texture,image->x,image->y,image->w,image->h,image->alpha);
205 }
206 }
207
208 /* menu title */
209 FONT_write(menu->title, 22,10,56,640,(GXColor)WHITE);
210
211 /* draw buttons + items */
212 for (i=0; i<menu->max_buttons; i++)
213 {
214 button = &menu->buttons[i];
215
216 if (button->state & BUTTON_VISIBLE)
217 {
218 /* item select (text or image) */
219 item = (menu->items) ? (&menu->items[menu->offset + i]) : NULL;
220
221 /* draw button + items */
222 if ((i == menu->selected) || (button->state & BUTTON_SELECTED))
223 {
224 if (button->data)
225 gxDrawTexture(button->data->texture[1],button->x-4,button->y-4,button->w+8,button->h+8,255);
226
227 if (item)
228 {
229 if (item->texture)
230 {
231 gxDrawTexture(item->texture, item->x-4,item->y-4,item->w+8,item->h+8,255);
232 FONT_writeCenter(item->text,18,button->x+4,item->x-4,button->y+(button->h - 36)/2+18,(GXColor)DARK_GREY);
233 }
234 else
235 {
236 FONT_writeCenter(item->text,18,item->x-4,item->x+item->w+4,button->y+(button->h-18)/2+18,(GXColor)DARK_GREY);
237 }
238 }
239 }
240 else
241 {
242 if (button->data)
243 gxDrawTexture(button->data->texture[0],button->x,button->y,button->w, button->h,255);
244
245 if (item)
246 {
247 if (item->texture)
248 {
249 gxDrawTexture(item->texture,item->x,item->y,item->w,item->h,255);
250 FONT_writeCenter(item->text,16,button->x+8,item->x,button->y+(button->h - 32)/2+16,(GXColor)DARK_GREY);
251 }
252 else
253 {
254 FONT_writeCenter(item->text,16,item->x,item->x+item->w,button->y+(button->h - 16)/2+16,(GXColor)DARK_GREY);
255 }
256 }
257 }
258 }
259 }
260
261 /* draw arrow */
262 for (i=0; i<2; i++)
263 {
264 button = menu->arrows[i];
265 if (button)
266 {
267 if (button->state & BUTTON_VISIBLE)
268 {
269 if (menu->selected == (menu->max_buttons + i))
270 gxDrawTexture(button->data->texture[1],button->x-2,button->y-2,button->w+4,button->h+4,255);
271 else
272 gxDrawTexture(button->data->texture[0],button->x,button->y,button->w, button->h,255);
273 }
274 }
275 }
276
277 /* left comment */
278 item = menu->helpers[0];
279 if (item)
280 {
281 if (item->data && strlen(item->comment))
282 {
283 gxDrawTexture(item->texture,item->x,item->y,item->w,item->h,255);
284 FONT_write(item->comment,16,item->x+item->w+6,item->y+(item->h-16)/2 + 16,640,(GXColor)WHITE);
285 }
286 }
287
288 /* right comment */
289 item = menu->helpers[1];
290 if (item)
291 {
292 if (item->data && strlen(item->comment))
293 {
294 gxDrawTexture(item->texture,item->x,item->y,item->w,item->h,255);
295 FONT_alignRight(item->comment,16,item->x-6,item->y+(item->h-16)/2+16,(GXColor)WHITE);
296 }
297 }
298
299 if (menu->cb)
300 menu->cb();
301 }
302
303 /* Draw Menu with transitions effects */
GUI_DrawMenuFX(gui_menu * menu,u8 speed,u8 out)304 void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out)
305 {
306 int i,temp,xoffset,yoffset;
307 int max_offset = 0;
308 u8 item_alpha = 255;
309 GXColor text_color = DARK_GREY;
310 gui_item *item;
311 gui_butn *button;
312 gui_image *image;
313
314 /* find maximal offset */
315 for (i=0; i<menu->max_images; i++)
316 {
317 image = &menu->bg_images[i];
318
319 if (image->state & IMAGE_SLIDE_LEFT)
320 {
321 temp = image->x + image->w;
322 if (max_offset < temp)
323 max_offset = temp;
324 }
325 else if (image->state & IMAGE_SLIDE_RIGHT)
326 {
327 temp = 640 - image->x;
328 if (max_offset < temp)
329 max_offset = temp;
330 }
331
332 if (image->state & IMAGE_SLIDE_TOP)
333 {
334 temp = image->y + image->h;
335 if (max_offset < temp)
336 max_offset = temp;
337 }
338 else if (image->state & IMAGE_SLIDE_BOTTOM)
339 {
340 temp = 480 - image->y;
341 if (max_offset < temp)
342 max_offset = temp;
343 }
344 }
345
346 temp = max_offset;
347
348 /* Alpha steps */
349 int alpha = 0;
350 int alpha_step = (255 * speed) / max_offset;
351 if (out)
352 {
353 alpha = 255;
354 alpha_step = -alpha_step;
355 }
356
357 /* Let's loop until final position has been reached */
358 while (temp > 0)
359 {
360 /* background color */
361 if (menu->screenshot)
362 {
363 gxClearScreen((GXColor)BLACK);
364 if (alpha >= menu->screenshot)
365 gxDrawScreenshot(menu->screenshot);
366 else
367 gxDrawScreenshot(255 - alpha);
368 }
369 else
370 {
371 gxClearScreen(bg_color);
372 }
373
374 /* background images */
375 for (i=0; i<menu->max_images; i++)
376 {
377 image = &menu->bg_images[i];
378
379 /* X offset */
380 if (image->state & IMAGE_SLIDE_LEFT)
381 xoffset = out ? (temp - max_offset) : (-temp);
382 else if (image->state & IMAGE_SLIDE_RIGHT)
383 xoffset = out ? (max_offset - temp) : (temp);
384 else
385 xoffset = 0;
386
387 /* Y offset */
388 if (image->state & IMAGE_SLIDE_TOP)
389 yoffset = out ? (temp - max_offset) : (-temp);
390 else if (image->state & IMAGE_SLIDE_BOTTOM)
391 yoffset = out ? (max_offset - temp) : (temp);
392 else
393 yoffset = 0;
394
395 /* draw image */
396 if ((image->state & IMAGE_FADE) && ((out && (image->alpha > alpha)) || (!out && (image->alpha < alpha))))
397 {
398 /* FADE In-Out */
399 if (image->state & IMAGE_VISIBLE)
400 {
401 if (image->state & IMAGE_REPEAT)
402 gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha);
403 else
404 gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha);
405 }
406 }
407 else
408 {
409 if (image->state & IMAGE_VISIBLE)
410 {
411 if (image->state & IMAGE_REPEAT)
412 gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha);
413 else
414 gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha);
415 }
416 }
417 }
418
419 /* menu title */
420 if ((menu->bg_images[2].state & IMAGE_SLIDE_TOP) || (menu->bg_images[3].state & IMAGE_SLIDE_TOP))
421 FONT_write(menu->title, 22,10,out ? (56 + temp - max_offset) : (56 - temp),640,(GXColor)WHITE);
422 else
423 FONT_write(menu->title, 22,10,56,640,(GXColor)WHITE);
424
425 /* draw buttons + items */
426 for (i=0; i<menu->max_buttons; i++)
427 {
428 button = &menu->buttons[i];
429
430 if (button->state & BUTTON_VISIBLE)
431 {
432 /* X offset */
433 if (button->state & BUTTON_SLIDE_LEFT)
434 xoffset = out ? (temp - max_offset) : (-temp);
435 else if (button->state & BUTTON_SLIDE_RIGHT)
436 xoffset = out ? (max_offset - temp) : (temp);
437 else
438 xoffset = 0;
439
440 /* Y offset */
441 if (button->state & BUTTON_SLIDE_TOP)
442 yoffset = out ? (temp - max_offset) : (-temp);
443 else if (button->state & BUTTON_SLIDE_BOTTOM)
444 yoffset = out ? (max_offset - temp) : (temp);
445 else
446 yoffset = 0;
447
448 /* Alpha transparency */
449 if (button->state & BUTTON_FADE)
450 {
451 item_alpha = alpha;
452 text_color.a = alpha;
453 }
454 else
455 {
456 item_alpha = 255;
457 text_color.a = 255;
458 }
459
460 /* item select (text or image) */
461 item = (menu->items) ? (&menu->items[menu->offset + i]) : NULL;
462
463 /* draw button + items */
464 if ((i == menu->selected) || (button->state & BUTTON_SELECTED))
465 {
466 if (button->data)
467 gxDrawTexture(button->data->texture[1],button->x+xoffset-4,button->y+yoffset-4,button->w+8,button->h+8,item_alpha);
468
469 if (item)
470 {
471 if (item->texture)
472 {
473 gxDrawTexture(item->texture, item->x+xoffset-4,item->y+yoffset-4,item->w+8,item->h+8,item_alpha);
474 FONT_writeCenter(item->text,18,button->x+xoffset+4,item->x+xoffset-4,button->y+yoffset+(button->h - 36)/2+18,text_color);
475 }
476 else
477 {
478 FONT_writeCenter(item->text,18,item->x+xoffset+2,item->x+item->w+xoffset+2,button->y+yoffset+(button->h-18)/2+18,text_color);
479 }
480 }
481 }
482 else
483 {
484 if (button->data)
485 gxDrawTexture(button->data->texture[0],button->x+xoffset,button->y+yoffset,button->w, button->h,item_alpha);
486
487 if (item)
488 {
489 if (item->texture)
490 {
491 gxDrawTexture(item->texture,item->x+xoffset,item->y+yoffset,item->w,item->h,item_alpha);
492 FONT_writeCenter(item->text,16,button->x+xoffset+8,item->x+xoffset,button->y+yoffset+(button->h - 32)/2+16,text_color);
493 }
494 else
495 {
496 FONT_writeCenter(item->text,16,item->x+xoffset,item->x+item->w+xoffset,button->y+yoffset+(button->h - 16)/2+16,text_color);
497 }
498 }
499 }
500 }
501 }
502
503 /* draw arrow */
504 for (i=0; i<2; i++)
505 {
506 button = menu->arrows[i];
507 if (button)
508 {
509 if (button->state & BUTTON_VISIBLE)
510 {
511 if (menu->selected == (menu->max_buttons + i))
512 gxDrawTexture(button->data->texture[1],button->x-2,button->y-2,button->w+4,button->h+4,255);
513 else
514 gxDrawTexture(button->data->texture[0],button->x,button->y,button->w, button->h,255);
515 }
516 }
517 }
518
519 if (!(menu->bg_images[3].state & IMAGE_SLIDE_BOTTOM) && !(menu->bg_images[4].state & IMAGE_SLIDE_BOTTOM))
520 {
521 /* left comment */
522 item = menu->helpers[0];
523 if (item)
524 {
525 if (item->data && strlen(item->comment))
526 {
527 gxDrawTexture(item->texture,item->x,item->y,item->w,item->h,255);
528 FONT_write(item->comment,16,item->x+item->w+6,item->y+(item->h-16)/2 + 16,640,(GXColor)WHITE);
529 }
530 }
531
532 /* right comment */
533 item = menu->helpers[1];
534 if (item)
535 {
536 if (item->data && strlen(item->comment))
537 {
538 gxDrawTexture(item->texture,item->x,item->y,item->w,item->h,255);
539 FONT_alignRight(item->comment,16,item->x-6,item->y+(item->h-16)/2+16,(GXColor)WHITE);
540 }
541 }
542 }
543
544 if (menu->cb)
545 menu->cb();
546
547 /* update offset */
548 temp -= speed;
549
550 /* update alpha */
551 alpha += alpha_step;
552 if (alpha > 255)
553 alpha = 255;
554 else if (alpha < 0)
555 alpha = 0;
556
557
558 /* copy EFB to XFB */
559 gxSetScreen();
560 }
561
562 /* final position */
563 if (!out)
564 {
565 GUI_DrawMenu(menu);
566 gxSetScreen();
567 }
568 else if (menu->screenshot)
569 {
570 gxClearScreen((GXColor)BLACK);
571 gxDrawScreenshot(255);
572 gxSetScreen();
573 }
574 }
575
576 /* Basic menu title slide effect */
GUI_SlideMenuTitle(gui_menu * m,int title_offset)577 void GUI_SlideMenuTitle(gui_menu *m, int title_offset)
578 {
579 #ifdef HW_RVL
580 gui_butn *button;
581 int i,x,y;
582 #endif
583
584 char title[64];
585 strcpy(title,m->title);
586
587 while (title_offset > 0)
588 {
589 /* update title */
590 strcpy(m->title,title+title_offset);
591 m->title[strlen(title)-title_offset-1] = 0;
592
593 /* draw menu */
594 GUI_DrawMenu(m);
595
596 #ifdef HW_RVL
597 /* keep pointer active */
598 if (m_input.ir.valid)
599 {
600 /* get cursor position */
601 x = m_input.ir.x;
602 y = m_input.ir.y;
603
604 /* draw wiimote pointer */
605 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
606
607 /* check for valid buttons */
608 m->selected = m->max_buttons + 2;
609 for (i=0; i<m->max_buttons; i++)
610 {
611 button = &m->buttons[i];
612 if ((button->state & BUTTON_ACTIVE)&&(x>=button->x)&&(x<=(button->x+button->w))&&(y>=button->y)&&(y<=(button->y+button->h)))
613 {
614 m->selected = i;
615 break;
616 }
617 }
618
619 for (i=0; i<2; i++)
620 {
621 button = m->arrows[i];
622 if (button)
623 {
624 if (button->state & BUTTON_VISIBLE)
625 {
626 if ((x<=(button->x+button->w))&&(y>=button->y)&&(y<=(button->y+button->h)))
627 {
628 m->selected = m->max_buttons + i;
629 break;
630 }
631 }
632 }
633 }
634 }
635 #endif
636 gxSetScreen();
637 usleep(6000);
638 title_offset--;
639 }
640 strcpy(m->title,title);
641 }
642
643 /* Update current menu */
GUI_UpdateMenu(gui_menu * menu)644 int GUI_UpdateMenu(gui_menu *menu)
645 {
646 u16 p;
647 int ret = 0;
648 int selected = menu->selected;
649 int max_items = menu->max_items;
650 int max_buttons = menu->max_buttons;
651 gui_butn *button;
652
653 #ifdef HW_RVL
654 if (Shutdown)
655 {
656 GUI_DeleteMenu(menu);
657 GUI_FadeOut();
658 shutdown();
659 SYS_ResetSystem(SYS_POWEROFF, 0, 0);
660 }
661 else if (m_input.ir.valid)
662 {
663 /* get cursor position */
664 int x = m_input.ir.x;
665 int y = m_input.ir.y;
666
667 /* draw wiimote pointer */
668 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
669
670 /* check for valid buttons */
671 selected = max_buttons + 2;
672 int i;
673 for (i=0; i<max_buttons; i++)
674 {
675 button = &menu->buttons[i];
676 if ((button->state & BUTTON_ACTIVE) && (button->state & BUTTON_VISIBLE))
677 {
678 if((x>=button->x)&&(x<=(button->x+button->w))&&(y>=button->y)&&(y<=(button->y+button->h)))
679 {
680 selected = i;
681 break;
682 }
683 }
684 }
685
686 for (i=0; i<2; i++)
687 {
688 button = menu->arrows[i];
689 if (button)
690 {
691 if ((button->state & BUTTON_ACTIVE) && (button->state & BUTTON_VISIBLE))
692 {
693 if ((x<=(button->x+button->w))&&(y>=button->y)&&(y<=(button->y+button->h)))
694 {
695 selected = max_buttons + i;
696 break;
697 }
698 }
699 }
700 }
701 }
702 else
703 {
704 /* reinitialize selection */
705 if (selected >= menu->max_buttons)
706 {
707 selected = 0;
708 while ((selected < (menu->max_buttons + 2)) &&
709 (!(menu->buttons[selected].state & BUTTON_ACTIVE) ||
710 !(menu->buttons[selected].state & BUTTON_VISIBLE)))
711 selected++;
712 }
713 }
714 #endif
715
716 /* update screen */
717 gxSetScreen();
718
719 /* update menu */
720 p = m_input.keys;
721
722 if (selected < max_buttons)
723 {
724 button = &menu->buttons[selected];
725 if (p & PAD_BUTTON_UP)
726 {
727 selected -= button->shift[0];
728 if (selected < 0)
729 {
730 selected = 0;
731 if (menu->offset)
732 menu->offset --;
733 }
734 }
735 else if (p & PAD_BUTTON_DOWN)
736 {
737 selected += button->shift[1];
738 if (selected >= max_buttons)
739 {
740 selected = max_buttons - 1;
741 if ((menu->offset + selected) < (max_items - 1))
742 menu->offset ++;
743 }
744 }
745 else if (p & PAD_BUTTON_LEFT)
746 {
747 selected -= button->shift[2];
748 if (selected < 0)
749 {
750 selected = 0;
751 if (menu->offset)
752 menu->offset --;
753 }
754 }
755 else if (p & PAD_BUTTON_RIGHT)
756 {
757 selected += button->shift[3];
758 if (selected >= max_buttons)
759 {
760 selected = max_buttons - 1;
761 if ((menu->offset + selected) < (max_items - 1))
762 menu->offset ++;
763 }
764 }
765 }
766
767 if (p & PAD_BUTTON_A)
768 {
769 if (selected < max_buttons)
770 ret = 1; /* menu clicked */
771 else if (selected == max_buttons)
772 menu->offset --; /* up arrow */
773 else if (selected == (max_buttons+1))
774 menu->offset ++; /* down arrow */
775 }
776 else if ((p & PAD_BUTTON_B) || (p & PAD_TRIGGER_Z))
777 {
778 /* quit menu */
779 ret = -1;
780 }
781
782 /* selected item has changed ? */
783 if (menu->selected != selected)
784 {
785 if (selected < max_buttons)
786 {
787 /* sound fx */
788 button = &menu->buttons[selected];
789 if (button->state & BUTTON_OVER_SFX)
790 {
791 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size,
792 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
793 }
794 }
795 else if (selected < (max_buttons + 2))
796 {
797 /* sound fx */
798 button = menu->arrows[selected-max_buttons];
799 if (button->state & BUTTON_OVER_SFX)
800 {
801 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size,
802 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
803 }
804 }
805
806 /* update selection */
807 menu->selected = selected;
808 }
809
810 /* update helper comment */
811 if (menu->helpers[1])
812 {
813 if ((menu->offset + selected) < max_items)
814 {
815 gui_item *item = &menu->items[menu->offset + selected];
816 strcpy(menu->helpers[1]->comment,item->comment);
817 }
818 else
819 {
820 strcpy(menu->helpers[1]->comment,"");
821 }
822 }
823
824 if (ret > 0)
825 {
826 if (selected < max_buttons)
827 {
828 /* sound fx */
829 button = &menu->buttons[selected];
830 if (button->state & BUTTON_SELECT_SFX)
831 {
832 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_select_pcm,button_select_pcm_size,
833 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
834 }
835 }
836 }
837
838 return ret;
839 }
840
841 /* Generic routine to render & update menus */
GUI_RunMenu(gui_menu * menu)842 int GUI_RunMenu(gui_menu *menu)
843 {
844 int update = 0;
845
846 /* update menu */
847 while (!update)
848 {
849 GUI_DrawMenu(menu);
850 update = GUI_UpdateMenu(menu);
851
852 /* update arrows buttons status (items list) */
853 if (menu->arrows[0])
854 {
855 if (menu->offset > 0)
856 menu->arrows[0]->state |= BUTTON_VISIBLE;
857 else
858 menu->arrows[0]->state &= ~BUTTON_VISIBLE;
859 }
860
861 if (menu->arrows[1])
862 {
863 if ((menu->offset + menu->max_buttons) < menu->max_items)
864 menu->arrows[1]->state |= BUTTON_VISIBLE;
865 else
866 menu->arrows[1]->state &= ~BUTTON_VISIBLE;
867 }
868 }
869
870 if (update == 2)
871 return (-2-menu->offset-menu->selected);
872 else if (update == 1)
873 return (menu->offset + menu->selected);
874 else
875 return -1;
876 }
877
878 /* Text Window */
GUI_TextWindow(gui_menu * parent,char * title,char items[][64],u8 nb_items,u8 fontsize)879 void GUI_TextWindow(gui_menu *parent, char *title, char items[][64], u8 nb_items, u8 fontsize)
880 {
881 int i, quit = 0;
882
883 #ifdef HW_RVL
884 int x,y;
885 #endif
886
887 /* initialize window */
888 gx_texture *window = gxTextureOpenPNG(Frame_s1_png,0);
889 gx_texture *top = gxTextureOpenPNG(Frame_s1_title_png,0);
890
891 /* window position */
892 int xwindow = (640 - window->width) /2;
893 int ywindow = (480 - window->height)/2;
894
895 /* text position */
896 int ypos = ywindow + top->height + (window->height - top->height - fontsize*nb_items) / 2 + fontsize/2;
897
898 /* disable helper comment */
899 const u8 *data = NULL;
900 if (parent->helpers[1])
901 {
902 data = parent->helpers[1]->data;
903 parent->helpers[1]->data = NULL;
904 }
905
906 /* slide in */
907 int yoffset = ywindow + window->height;
908 while (yoffset > 0)
909 {
910 /* draw parent menu */
911 GUI_DrawMenu(parent);
912
913 /* draw window */
914 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230);
915 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
916
917 /* draw title */
918 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
919
920 /* draw text */
921 for (i=0; i<nb_items; i++)
922 FONT_writeCenter(items[i],fontsize,xwindow,xwindow+window->width,ypos+i*fontsize-yoffset,(GXColor)WHITE);
923
924 /* update display */
925 gxSetScreen();
926
927 /* slide speed */
928 yoffset -= 60;
929 }
930
931 /* draw menu + text window */
932 while (quit == 0)
933 {
934 /* draw parent menu */
935 GUI_DrawMenu(parent);
936
937 /* draw window */
938 gxDrawTexture(window,xwindow,ywindow,window->width,window->height,230);
939 gxDrawTexture(top,xwindow,ywindow,top->width,top->height,255);
940
941 /* draw title */
942 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20,(GXColor)WHITE);
943
944 /* draw text */
945 for (i=0; i<nb_items; i++)
946 {
947 FONT_writeCenter(items[i],fontsize,xwindow,xwindow+window->width,ypos+i*fontsize,(GXColor)WHITE);
948 }
949
950 #ifdef HW_RVL
951 if (Shutdown)
952 {
953 gxTextureClose(&window);
954 gxTextureClose(&top);
955 gxTextureClose(&w_pointer);
956 GUI_DeleteMenu(parent);
957 GUI_FadeOut();
958 shutdown();
959 SYS_ResetSystem(SYS_POWEROFF, 0, 0);
960 }
961 else if (m_input.ir.valid)
962 {
963 /* get cursor position */
964 x = m_input.ir.x;
965 y = m_input.ir.y;
966
967 /* draw wiimote pointer */
968 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
969 }
970 #endif
971
972 /* update screen */
973 gxSetScreen();
974
975 /* wait for exit buttons */
976 if (m_input.keys)
977 quit = 1;
978 }
979
980 /* reset initial vertical offset */
981
982 /* slide out */
983 yoffset = 0;
984 while (yoffset < (ywindow + window->height))
985 {
986 /* draw parent menu */
987 GUI_DrawMenu(parent);
988
989 /* draw window */
990 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230);
991 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
992
993 /* draw title */
994 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
995
996 /* draw text */
997 for (i=0; i<nb_items; i++)
998 FONT_writeCenter(items[i],fontsize,xwindow,xwindow+window->width,ypos+i*fontsize-yoffset,(GXColor)WHITE);
999
1000 /* update display */
1001 gxSetScreen();
1002
1003 /* slide speed */
1004 yoffset += 60;
1005 }
1006
1007 /* restore helper comment */
1008 if (parent->helpers[1])
1009 parent->helpers[1]->data = data;
1010
1011 /* final position */
1012 GUI_DrawMenu(parent);
1013 gxSetScreen();
1014
1015 /* close textures */
1016 gxTextureClose(&window);
1017 gxTextureClose(&top);
1018 }
1019
1020 /* Option Window (returns selected item) */
GUI_OptionWindow(gui_menu * parent,char * title,char * infos,char * items[],u8 nb_items)1021 int GUI_OptionWindow(gui_menu *parent, char *title, char *infos, char *items[], u8 nb_items)
1022 {
1023 int i, ret, quit = 0;
1024 int old, selected = 0;
1025 s16 p;
1026 butn_data button;
1027
1028 #ifdef HW_RVL
1029 int x,y;
1030 #endif
1031
1032 /* initialize buttons data */
1033 button.texture[0] = gxTextureOpenPNG(Button_text_png,0);
1034 button.texture[1] = gxTextureOpenPNG(Button_text_over_png,0);
1035
1036 /* initialize texture window */
1037 gx_texture *window = gxTextureOpenPNG(Frame_s1_png,0);
1038 gx_texture *top = gxTextureOpenPNG(Frame_s1_title_png,0);
1039
1040 /* get initial positions */
1041 int w = button.texture[0]->width;
1042 int h = button.texture[0]->height;
1043 int xwindow = (640 - window->width)/2;
1044 int ywindow = (480 - window->height)/2;
1045 int xpos = xwindow + (window->width - w)/2;
1046 int ypos = (window->height - top->height - (h*nb_items) - (nb_items-1)*20)/2;
1047 ypos = ypos + ywindow + top->height;
1048
1049 /* disable helper comment */
1050 const u8 *data = NULL;
1051 if (parent->helpers[1])
1052 {
1053 data = parent->helpers[1]->data;
1054 parent->helpers[1]->data = 0;
1055 }
1056
1057 /* slide in */
1058 int yoffset = ywindow + window->height;
1059 while (yoffset > 0)
1060 {
1061 /* draw parent menu */
1062 GUI_DrawMenu(parent);
1063
1064 /* draw window */
1065 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230);
1066 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
1067
1068 /* draw title */
1069 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
1070
1071 /* draw buttons + text */
1072 for (i=0; i<nb_items; i++)
1073 {
1074 gxDrawTexture(button.texture[0],xpos,ypos+i*(20 + h)-yoffset,w,h,255);
1075 FONT_writeCenter(items[i],18,xpos,xpos+w,ypos+i*(20 + h)+(h + 18)/2- yoffset,(GXColor)DARK_GREY);
1076 }
1077
1078 /* draw infos */
1079 FONT_writeCenter(infos,16,xwindow,xwindow+window->width,ywindow+window->height-16-yoffset,(GXColor)WHITE);
1080
1081 /* update display */
1082 gxSetScreen();
1083
1084 /* slide speed */
1085 yoffset -= 60;
1086 }
1087
1088 /* draw menu */
1089 while (quit == 0)
1090 {
1091 /* draw parent menu (should have been initialized first) */
1092 GUI_DrawMenu(parent);
1093
1094 /* draw window */
1095 gxDrawTexture(window,xwindow,ywindow,window->width,window->height,230);
1096 gxDrawTexture(top,xwindow,ywindow,top->width,top->height,255);
1097
1098 /* draw title */
1099 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20,(GXColor)WHITE);
1100
1101 /* draw infos */
1102 FONT_writeCenter(infos,16,xwindow,xwindow+window->width,ywindow+window->height-16,(GXColor)WHITE);
1103
1104 /* draw buttons + text */
1105 for (i=0; i<nb_items; i++)
1106 {
1107 if (i==selected)
1108 {
1109 gxDrawTexture(button.texture[1],xpos-4,ypos+i*(20+h)-4,w+8,h+8,255);
1110 FONT_writeCenter(items[i],22,xpos,xpos+w,ypos+i*(20+h)+(h+22)/2,(GXColor)DARK_GREY);
1111 }
1112 else
1113 {
1114 gxDrawTexture(button.texture[0],xpos,ypos+i*(20 + h),w,h,255);
1115 FONT_writeCenter(items[i],18,xpos,xpos+w,ypos+i*(20+h)+(h+18)/2,(GXColor)DARK_GREY);
1116 }
1117 }
1118
1119 old = selected;
1120 p = m_input.keys;
1121
1122 #ifdef HW_RVL
1123 if (Shutdown)
1124 {
1125 gxTextureClose(&window);
1126 gxTextureClose(&top);
1127 gxTextureClose(&button.texture[0]);
1128 gxTextureClose(&button.texture[1]);
1129 gxTextureClose(&w_pointer);
1130 GUI_DeleteMenu(parent);
1131 GUI_FadeOut();
1132 shutdown();
1133 SYS_ResetSystem(SYS_POWEROFF, 0, 0);
1134 }
1135 else if (m_input.ir.valid)
1136 {
1137 /* get cursor position */
1138 x = m_input.ir.x;
1139 y = m_input.ir.y;
1140
1141 /* draw wiimote pointer */
1142 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
1143
1144 /* check for valid buttons */
1145 selected = -1;
1146 for (i=0; i<nb_items; i++)
1147 {
1148 if ((x>=xpos)&&(x<=(xpos+w))&&(y>=ypos+i*(20 + h))&&(y<=(ypos+i*(20+h)+h)))
1149 {
1150 selected = i;
1151 break;
1152 }
1153 }
1154 }
1155 else
1156 {
1157 /* reinitialize selection */
1158 if (selected == -1)
1159 selected = 0;
1160 }
1161 #endif
1162
1163 /* update screen */
1164 gxSetScreen();
1165
1166 /* update selection */
1167 if (p & PAD_BUTTON_UP)
1168 {
1169 if (selected > 0)
1170 selected --;
1171 }
1172 else if (p & PAD_BUTTON_DOWN)
1173 {
1174 if (selected < (nb_items -1))
1175 selected ++;
1176 }
1177
1178 /* sound fx */
1179 if (selected != old)
1180 {
1181 if (selected >= 0)
1182 {
1183 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size,
1184 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
1185 }
1186 }
1187
1188 if (p & PAD_BUTTON_A)
1189 {
1190 if (selected >= 0)
1191 {
1192 quit = 1;
1193 ret = selected;
1194 }
1195 }
1196 else if (p & PAD_BUTTON_B)
1197 {
1198 quit = 1;
1199 ret = -1;
1200 }
1201 }
1202
1203 /* slide out */
1204 yoffset = 0;
1205 while (yoffset < (ywindow + window->height))
1206 {
1207 /* draw parent menu */
1208 GUI_DrawMenu(parent);
1209
1210 /* draw window + header */
1211 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230);
1212 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
1213
1214 /* draw title */
1215 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
1216
1217 /* draw infos */
1218 FONT_writeCenter(infos,16,xwindow,xwindow+window->width,ywindow+window->height-16-yoffset,(GXColor)WHITE);
1219
1220 /* draw buttons + text */
1221 for (i=0; i<nb_items; i++)
1222 {
1223 gxDrawTexture(button.texture[0],xpos,ypos+i*(20+h)-yoffset,w,h,255);
1224 FONT_writeCenter(items[i],18,xpos,xpos+w,ypos+i*(20+h)+(h+18)/2-yoffset,(GXColor)WHITE);
1225 }
1226
1227 /* update display */
1228 gxSetScreen();
1229
1230 /* slide speed */
1231 yoffset += 60;
1232 }
1233
1234 /* restore helper comment */
1235 if (parent->helpers[1])
1236 parent->helpers[1]->data = data;
1237
1238 /* final position */
1239 GUI_DrawMenu(parent);
1240 gxSetScreen();
1241
1242 /* close textures */
1243 gxTextureClose(&window);
1244 gxTextureClose(&top);
1245 gxTextureClose(&button.texture[0]);
1246 gxTextureClose(&button.texture[1]);
1247
1248 return ret;
1249 }
1250
1251 /* Option Box */
GUI_OptionBox(gui_menu * parent,optioncallback cb,char * title,void * option,float step,float min,float max,u8 type)1252 void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *option, float step, float min, float max, u8 type)
1253 {
1254 gx_texture *arrow[2];
1255 arrow[0] = gxTextureOpenPNG(Button_arrow_png,0);
1256 arrow[1] = gxTextureOpenPNG(Button_arrow_over_png,0);
1257 gx_texture *window = gxTextureOpenPNG(Frame_s2_png,0);
1258 gx_texture *top = gxTextureOpenPNG(Frame_s2_title_png,0);
1259
1260 /* window position */
1261 int xwindow = 166;
1262 int ywindow = 160;
1263
1264 /* arrows position */
1265 int xleft = 206;
1266 int xright = 392;
1267 int yleft = 238;
1268 int yright = 238;
1269
1270 /* disable action button helper */
1271 if (parent->helpers[1])
1272 parent->helpers[1]->data = 0;
1273
1274 /* slide in */
1275 char msg[16];
1276 int yoffset = ywindow + window->height;
1277 while (yoffset > 0)
1278 {
1279 /* draw parent menu */
1280 GUI_DrawMenu(parent);
1281
1282 /* draw window */
1283 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,225);
1284 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
1285
1286 /* display title */
1287 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
1288
1289 /* update display */
1290 gxSetScreen();
1291
1292 /* slide speed */
1293 yoffset -= 60;
1294 }
1295
1296 /* display option box */
1297 int quit = 0;
1298 int modified = 0;
1299 int selected = -1;
1300 s16 p;
1301 #ifdef HW_RVL
1302 int x,y;
1303 #endif
1304
1305 while (!quit)
1306 {
1307 /* draw parent menu */
1308 GUI_DrawMenu(parent);
1309
1310 /* draw window */
1311 gxDrawTexture(window,xwindow,ywindow,window->width,window->height,225);
1312 gxDrawTexture(top,xwindow,ywindow,top->width,top->height,255);
1313
1314 /* display title */
1315 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20,(GXColor)WHITE);
1316
1317 /* option type */
1318 if (type)
1319 {
1320 /* integer type */
1321 if (*(s16 *)option < 0)
1322 sprintf(msg,"-%d",abs(*(s16 *)option));
1323 else
1324 sprintf(msg,"%d",abs(*(s16 *)option));
1325 }
1326 else
1327 {
1328 /* float type */
1329 if (*(float *)option < 0.0)
1330 sprintf(msg,"-%1.2f",fabs(*(float *)option));
1331 else
1332 sprintf(msg,"%1.2f",fabs(*(float *)option));
1333 }
1334
1335 /* draw option text */
1336 FONT_writeCenter(msg,24,xwindow,xwindow+window->width,272,(GXColor)WHITE);
1337
1338 /* update inputs */
1339 p = m_input.keys;
1340
1341 /* draw buttons */
1342 if (selected < 0)
1343 {
1344 /* nothing selected */
1345 gxDrawTexture(arrow[0],xleft,yleft,arrow[0]->width,arrow[0]->height,255);
1346 gxDrawTextureRotate(arrow[0],xright,yright,arrow[0]->width,arrow[0]->height,180.0,255);
1347 }
1348
1349 #ifdef HW_RVL
1350 else if (selected)
1351 {
1352 /* right button selected */
1353 gxDrawTexture(arrow[0],xleft,yleft,arrow[0]->width,arrow[0]->height,255);
1354 gxDrawTextureRotate(arrow[1],xright-4,yright-4,arrow[1]->width+8,arrow[1]->height+8,180.0,255);
1355 }
1356 else
1357 {
1358 /* left button selected */
1359 gxDrawTexture(arrow[1],xleft-4,yleft-4,arrow[1]->width+8,arrow[1]->height+8,255);
1360 gxDrawTextureRotate(arrow[0],xright,yright,arrow[0]->width,arrow[0]->height,180.0,255);
1361 }
1362
1363 selected = -1;
1364 if (Shutdown)
1365 {
1366 gxTextureClose(&arrow[0]);
1367 gxTextureClose(&arrow[1]);
1368 gxTextureClose(&window);
1369 gxTextureClose(&top);
1370 gxTextureClose(&w_pointer);
1371 GUI_DeleteMenu(parent);
1372 GUI_FadeOut();
1373 shutdown();
1374 SYS_ResetSystem(SYS_POWEROFF, 0, 0);
1375 }
1376 else if (m_input.ir.valid)
1377 {
1378 /* get cursor position */
1379 x = m_input.ir.x;
1380 y = m_input.ir.y;
1381
1382 /* draw wiimote pointer */
1383 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
1384
1385 /* check for valid buttons */
1386 if ((x>=xleft)&&(x<=(xleft+arrow[0]->width))&&(y>=yleft)&&(y<=(yleft+arrow[0]->height)))
1387 {
1388 selected = 0;
1389 if (p & PAD_BUTTON_A)
1390 p |= PAD_BUTTON_LEFT;
1391 }
1392 else if ((x>=xright)&&(x<=(xright+arrow[0]->width))&&(y>=yright)&&(y<=(yright+arrow[0]->height)))
1393 {
1394 selected = 1;
1395 if (p & PAD_BUTTON_A)
1396 p |= PAD_BUTTON_RIGHT;
1397 }
1398 }
1399 #endif
1400
1401 /* update screen */
1402 gxSetScreen();
1403
1404 /* check input */
1405 if (p&PAD_BUTTON_LEFT)
1406 {
1407 /* decrement option value */
1408 if (type)
1409 {
1410 /* integer type */
1411 *(s16 *)option -= (s16)step;
1412 if (*(s16 *)option < (s16)min)
1413 *(s16 *)option = (s16)max;
1414 }
1415 else
1416 {
1417 /* float type */
1418 *(float *)option -= step;
1419 if (*(float *)option < min)
1420 *(float *)option = max;
1421 }
1422
1423 modified = 1;
1424 }
1425 else if (p&PAD_BUTTON_RIGHT)
1426 {
1427 /* increment option value */
1428 if (type)
1429 {
1430 /* integer type */
1431 *(s16 *)option += (s16)step;
1432 if (*(s16 *)option > (s16)max)
1433 *(s16 *)option = (s16)min;
1434 }
1435 else
1436 {
1437 /* float type */
1438 *(float *)option += step;
1439 if (*(float *)option > max)
1440 *(float *)option = min;
1441 }
1442
1443 modified = 1;
1444 }
1445 else if (p & PAD_BUTTON_B)
1446 {
1447 quit = 1;
1448 }
1449
1450 if (modified)
1451 {
1452 modified = 0;
1453
1454 /* play sound effect */
1455 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size,
1456 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
1457
1458 /* option callback */
1459 if (cb)
1460 cb();
1461 }
1462 }
1463
1464 /* slide out */
1465 yoffset = 0; ;
1466 while (yoffset < (ywindow + window->height))
1467 {
1468 /* draw parent menu */
1469 GUI_DrawMenu(parent);
1470
1471 /* draw window */
1472 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,225);
1473 gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255);
1474
1475 /* display title */
1476 FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE);
1477
1478 /* update display */
1479 gxSetScreen();
1480
1481 /* slide speed */
1482 yoffset += 60;
1483 }
1484
1485 /* restore action button helper */
1486 if (parent->helpers[1])
1487 parent->helpers[1]->data = Key_A_png;
1488
1489 /* final position */
1490 GUI_DrawMenu(parent);
1491 gxSetScreen();
1492
1493 /* close textures */
1494 gxTextureClose(&arrow[0]);
1495 gxTextureClose(&arrow[1]);
1496 gxTextureClose(&window);
1497 gxTextureClose(&top);
1498 }
1499
1500 /* Option Box with two parameters */
GUI_OptionBox2(gui_menu * parent,char * text_1,char * text_2,s16 * option_1,s16 * option_2,s16 step,s16 min,s16 max)1501 void GUI_OptionBox2(gui_menu *parent, char *text_1, char *text_2, s16 *option_1, s16 *option_2, s16 step, s16 min, s16 max)
1502 {
1503 gx_texture *arrow[2];
1504 arrow[0] = gxTextureOpenPNG(Button_arrow_png,0);
1505 arrow[1] = gxTextureOpenPNG(Button_arrow_over_png,0);
1506 gx_texture *window = gxTextureOpenPNG(Frame_s2_png,0);
1507
1508 /* window position */
1509 int xwindow = 166;
1510 int ywindow = 160;
1511
1512 /* arrows position */
1513 int arrow_pos[4][2] =
1514 {
1515 {144,218},
1516 {452,218},
1517 {298,138},
1518 {298,298}
1519 };
1520
1521 /* disable action button helper */
1522 if (parent->helpers[1])
1523 parent->helpers[1]->data = 0;
1524
1525 /* slide in */
1526 char msg[16];
1527 int yoffset = ywindow + window->height;
1528 while (yoffset > 0)
1529 {
1530 /* draw parent menu */
1531 GUI_DrawMenu(parent);
1532
1533 /* draw window */
1534 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,225);
1535
1536 /* update display */
1537 gxSetScreen();
1538
1539 /* slide speed */
1540 yoffset -= 60;
1541 }
1542
1543 /* display option box */
1544 int quit = 0;
1545 int modified = 0;
1546 s16 p;
1547 #ifdef HW_RVL
1548 int selected = -1;
1549 int i,x,y;
1550 #endif
1551
1552 while (!quit)
1553 {
1554 /* draw parent menu */
1555 GUI_DrawMenu(parent);
1556
1557 /* draw window */
1558 gxDrawTexture(window,xwindow,ywindow,window->width,window->height,225);
1559
1560 /* draw options text */
1561 if (*option_1 < 0)
1562 sprintf(msg,"%s: -%02d",text_1,abs(*option_1));
1563 else
1564 sprintf(msg,"%s: +%02d",text_1,abs(*option_1));
1565 FONT_writeCenter(msg,24,xwindow,xwindow+window->width,240,(GXColor)WHITE);
1566 if (*option_2 < 0)
1567 sprintf(msg,"%s: -%02d",text_2,abs(*option_2));
1568 else
1569 sprintf(msg,"%s: +%02d",text_2,abs(*option_2));
1570 FONT_writeCenter(msg,24,xwindow,xwindow+window->width,264,(GXColor)WHITE);
1571
1572 /* update inputs */
1573 p = m_input.keys;
1574
1575 /* draw buttons */
1576 #ifdef HW_RVL
1577 switch (selected)
1578 {
1579 case 0: /* left button */
1580 gxDrawTexture(arrow[1],arrow_pos[0][0]-4,arrow_pos[0][1]-4,arrow[0]->width+8,arrow[0]->height+8,255);
1581 gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255);
1582 gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255);
1583 gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255);
1584 if (p & PAD_BUTTON_A) p |= PAD_BUTTON_LEFT;
1585 break;
1586
1587 case 1: /* right button */
1588 gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255);
1589 gxDrawTextureRotate(arrow[1],arrow_pos[1][0]-4,arrow_pos[1][1]-4,arrow[0]->width+8,arrow[0]->height+8,180.0,255);
1590 gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255);
1591 gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255);
1592 if (p & PAD_BUTTON_A) p |= PAD_BUTTON_RIGHT;
1593 break;
1594
1595 case 2: /* up button */
1596 gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255);
1597 gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255);
1598 gxDrawTextureRotate(arrow[1],arrow_pos[2][0]-4,arrow_pos[2][1]-4,arrow[0]->width+8,arrow[0]->height+8,90.0,255);
1599 gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255);
1600 if (p & PAD_BUTTON_A) p |= PAD_BUTTON_UP;
1601 break;
1602
1603 case 3: /* down button */
1604 gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255);
1605 gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255);
1606 gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255);
1607 gxDrawTextureRotate(arrow[1],arrow_pos[3][0]-4,arrow_pos[3][1]-4,arrow[0]->width+8,arrow[0]->height+8,270.0,255);
1608 if (p & PAD_BUTTON_A) p |= PAD_BUTTON_DOWN;
1609 break;
1610
1611 default: /* nothing selected */
1612 gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255);
1613 gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255);
1614 gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255);
1615 gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255);
1616 break;
1617 }
1618
1619 if (Shutdown)
1620 {
1621 gxTextureClose(&arrow[0]);
1622 gxTextureClose(&arrow[1]);
1623 gxTextureClose(&window);
1624 gxTextureClose(&w_pointer);
1625 GUI_DeleteMenu(parent);
1626 GUI_FadeOut();
1627 shutdown();
1628 SYS_ResetSystem(SYS_POWEROFF, 0, 0);
1629 }
1630
1631 /* update selection */
1632 selected = -1;
1633 if (m_input.ir.valid)
1634 {
1635 /* get cursor position */
1636 x = m_input.ir.x;
1637 y = m_input.ir.y;
1638
1639 /* draw wiimote pointer */
1640 gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255);
1641
1642 /* check for valid buttons */
1643 for (i=0; i<4; i++)
1644 {
1645 if ((x>=arrow_pos[i][0])&&(x<=(arrow_pos[i][0]+arrow[0]->width))&&(y>=arrow_pos[i][1])&&(y<=(arrow_pos[i][1]+arrow[0]->height)))
1646 selected = i;
1647 }
1648 }
1649 #else
1650 gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255);
1651 gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255);
1652 gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255);
1653 gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255);
1654 #endif
1655
1656 /* update screen */
1657 gxSetScreen();
1658
1659 if (p&PAD_BUTTON_LEFT)
1660 {
1661 /* decrement option 1 value */
1662 *option_1 -= step;
1663 if (*option_1 < min)
1664 *option_1 = max;
1665 modified = 1;
1666 }
1667 else if (p&PAD_BUTTON_RIGHT)
1668 {
1669 /* decrement option 1 value */
1670 *option_1 += step;
1671 if (*option_1 > max)
1672 *option_1 = min;
1673 modified = 1;
1674 }
1675 else if (p&PAD_BUTTON_UP)
1676 {
1677 /* decrement option 2 value */
1678 *option_2 -= step;
1679 if (*option_2 < min)
1680 *option_2 = max;
1681 modified = 1;
1682 }
1683 else if (p&PAD_BUTTON_DOWN)
1684 {
1685 /* increment option 2 value */
1686 *option_2 += step;
1687 if (*option_2 > max)
1688 *option_2 = min;
1689 modified = 1;
1690 }
1691 else if (p & PAD_BUTTON_B)
1692 {
1693 quit = 1;
1694 }
1695
1696 if (modified)
1697 {
1698 modified = 0;
1699 /* play sound effect */
1700 ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size,
1701 ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL);
1702 }
1703 }
1704
1705 /* slide out */
1706 yoffset = 0; ;
1707 while (yoffset < (ywindow + window->height))
1708 {
1709 /* draw parent menu */
1710 GUI_DrawMenu(parent);
1711
1712 /* draw window */
1713 gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,225);
1714
1715 /* update display */
1716 gxSetScreen();
1717
1718 /* slide speed */
1719 yoffset += 60;
1720 }
1721
1722 /* restore action button helper */
1723 if (parent->helpers[1])
1724 parent->helpers[1]->data = Key_A_png;
1725
1726 /* final position */
1727 GUI_DrawMenu(parent);
1728 gxSetScreen();
1729
1730 /* close textures */
1731 gxTextureClose(&arrow[0]);
1732 gxTextureClose(&arrow[1]);
1733 gxTextureClose(&window);
1734 }
1735
1736 /* Interactive Message Box */
1737 /* Message Box displays a message until a specific action is completed */
1738
1739 /* Message Box LWP Thread */
MsgBox_Thread(gui_message * message_box)1740 static void *MsgBox_Thread(gui_message *message_box)
1741 {
1742 while (message_box->refresh)
1743 {
1744 /* draw parent menu */
1745 if (message_box->parent)
1746 {
1747 GUI_DrawMenu(message_box->parent);
1748 }
1749 else
1750 {
1751 gxClearScreen(bg_color);
1752 }
1753
1754 /* draw window */
1755 gxDrawTexture(message_box->window,166,160,message_box->window->width,message_box->window->height,230);
1756 gxDrawTexture(message_box->top,166,160,message_box->top->width,message_box->top->height,255);
1757
1758 /* draw title */
1759 if (message_box->title)
1760 FONT_writeCenter(message_box->title,20,166,166+message_box->window->width,160+(message_box->top->height-20)/2+20,(GXColor)WHITE);
1761
1762 /* draw box message */
1763 if (message_box->msg)
1764 FONT_writeCenter(message_box->msg,18,166,166+message_box->window->width,248,(GXColor)WHITE);
1765
1766 /* draw throbber */
1767 if (message_box->throbber)
1768 gxDrawTextureRotate(message_box->throbber,166+(message_box->window->width-message_box->throbber->width)/2,160+message_box->window->height-message_box->throbber->height-20,message_box->throbber->width,message_box->throbber->height,(message_box->progress * 360.0) / 100.0, 255);
1769
1770 /* draw exit message */
1771 if (message_box->buttonA)
1772 {
1773 if (message_box->buttonB)
1774 {
1775 FONT_writeCenter(" Confirm Cancel ",18,166,166+message_box->window->width,248+18+8,(GXColor)WHITE);
1776 gxDrawTexture(message_box->buttonA, 166+56, 248+8+(18-message_box->buttonA->height)/2,message_box->buttonA->width, message_box->buttonA->height,255);
1777 gxDrawTexture(message_box->buttonB, 166+166, 248+8+(18-message_box->buttonB->height)/2,message_box->buttonB->width, message_box->buttonB->height,255);
1778 }
1779 else
1780 {
1781 FONT_writeCenter("Press to continue.",18,166,166+message_box->window->width,248+18+4,(GXColor)WHITE);
1782 gxDrawTexture(message_box->buttonA, 166+116, 248+4+(18-message_box->buttonA->height)/2,message_box->buttonA->width, message_box->buttonA->height,255);
1783 }
1784 }
1785
1786 /* update display */
1787 gxSetScreen();
1788
1789 /* update progression */
1790 message_box->progress++;
1791 if (message_box->progress > 100)
1792 message_box->progress = 0;
1793 usleep(10);
1794 }
1795
1796 return 0;
1797 }
1798
1799 /* update current Message Box */
GUI_MsgBoxUpdate(char * title,char * msg)1800 void GUI_MsgBoxUpdate(char *title, char *msg)
1801 {
1802 if (title)
1803 strncpy(message_box.title,title,64);
1804 if (msg)
1805 strncpy(message_box.msg,msg,64);
1806 }
1807
1808 /* setup current Message Box */
GUI_MsgBoxOpen(char * title,char * msg,bool throbber)1809 void GUI_MsgBoxOpen(char *title, char *msg, bool throbber)
1810 {
1811 if (SILENT)
1812 return;
1813
1814 /* update text */
1815 GUI_MsgBoxUpdate(title,msg);
1816
1817 /* ensure we are not already running */
1818 if (!message_box.refresh)
1819 {
1820 /* initialize default textures */
1821 message_box.window = gxTextureOpenPNG(Frame_s2_png,0);
1822 message_box.top = gxTextureOpenPNG(Frame_s2_title_png,0);
1823 if (throbber)
1824 message_box.throbber = gxTextureOpenPNG(Frame_throbber_png,0);
1825
1826 /* window position */
1827 int xwindow = 166;
1828 int ywindow = 160;
1829 int ypos = 248;
1830
1831 /* disable helper comments */
1832 if (message_box.parent)
1833 {
1834 if (message_box.parent->helpers[0])
1835 message_box.parent->helpers[0]->data = 0;
1836 if (message_box.parent->helpers[1])
1837 message_box.parent->helpers[1]->data = 0;
1838 }
1839
1840 /* slide in */
1841 int yoffset = ywindow + message_box.window->height;
1842 while (yoffset > 0)
1843 {
1844 /* draw parent menu */
1845 if (message_box.parent)
1846 {
1847 GUI_DrawMenu(message_box.parent);
1848 }
1849 else
1850 {
1851 gxClearScreen(bg_color);
1852 }
1853
1854 /* draw window */
1855 gxDrawTexture(message_box.window,xwindow,ywindow-yoffset,message_box.window->width,message_box.window->height,230);
1856 gxDrawTexture(message_box.top,xwindow,ywindow-yoffset,message_box.top->width,message_box.top->height,255);
1857
1858 /* draw title */
1859 if (title)
1860 FONT_writeCenter(title,20,xwindow,xwindow+message_box.window->width,ywindow+(message_box.top->height-20)/2+20-yoffset,(GXColor)WHITE);
1861
1862 /* draw box message */
1863 if (msg)
1864 FONT_writeCenter(msg,18,xwindow,xwindow+message_box.window->width,ypos-yoffset,(GXColor)WHITE);
1865
1866 /* update display */
1867 gxSetScreen();
1868
1869 /* slide speed */
1870 yoffset -= 60;
1871 }
1872
1873 /* create LWP thread for MessageBox refresh */
1874 message_box.refresh = TRUE;
1875 LWP_CreateThread (&msgboxthread, (void *)MsgBox_Thread, &message_box, NULL, 0, 70);
1876 }
1877 }
1878
1879 /* Close current messagebox */
GUI_MsgBoxClose(void)1880 void GUI_MsgBoxClose(void)
1881 {
1882 if (message_box.refresh)
1883 {
1884 /* suspend MessageBox refresh */
1885 message_box.refresh = FALSE;
1886 LWP_JoinThread(msgboxthread, NULL);
1887
1888 /* window position */
1889 int xwindow = 166;
1890 int ywindow = 160;
1891 int ypos = 248;
1892
1893 /* slide out */
1894 int yoffset = 0;
1895 while (yoffset < (ywindow + message_box.window->height))
1896 {
1897 /* draw parent menu */
1898 if (message_box.parent)
1899 {
1900 GUI_DrawMenu(message_box.parent);
1901 }
1902 else
1903 {
1904 gxClearScreen(bg_color);
1905 }
1906
1907 /* draw window */
1908 gxDrawTexture(message_box.window,xwindow,ywindow-yoffset,message_box.window->width,message_box.window->height,230);
1909 gxDrawTexture(message_box.top,xwindow,ywindow-yoffset,message_box.top->width,message_box.top->height,255);
1910
1911 /* draw title */
1912 if (message_box.title)
1913 FONT_writeCenter(message_box.title,20,xwindow,xwindow+message_box.window->width,ywindow+(message_box.top->height-20)/2+20-yoffset,(GXColor)WHITE);
1914
1915 /* draw text */
1916 if (message_box.msg)
1917 FONT_writeCenter(message_box.msg,18,xwindow,xwindow+message_box.window->width,ypos-yoffset,(GXColor)WHITE);
1918
1919 /* update display */
1920 gxSetScreen();
1921
1922 /* slide speed */
1923 yoffset += 60;
1924 }
1925
1926 if (message_box.parent)
1927 {
1928 /* restore helper comment */
1929 if (message_box.parent->helpers[0])
1930 message_box.parent->helpers[0]->data = Key_B_png;
1931 if (message_box.parent->helpers[1])
1932 message_box.parent->helpers[1]->data = Key_A_png;
1933
1934 /* final position */
1935 GUI_DrawMenu(message_box.parent);
1936 }
1937 else
1938 {
1939 gxClearScreen(bg_color);
1940 }
1941
1942 gxSetScreen();
1943
1944 /* clear all textures */
1945 gxTextureClose(&message_box.window);
1946 gxTextureClose(&message_box.top);
1947 gxTextureClose(&message_box.buttonA);
1948 gxTextureClose(&message_box.buttonB);
1949 gxTextureClose(&message_box.throbber);
1950 }
1951 }
1952
GUI_WaitPrompt(char * title,char * msg)1953 void GUI_WaitPrompt(char *title, char *msg)
1954 {
1955 if (SILENT)
1956 return;
1957
1958 /* clear unused texture */
1959 gxTextureClose(&message_box.throbber);
1960
1961 /* open or update message box */
1962 GUI_MsgBoxOpen(title, msg, 0);
1963
1964 /* allocate texture */
1965 message_box.buttonA = gxTextureOpenPNG(Key_A_png,0);
1966
1967 /* wait for button A */
1968 while (m_input.keys & PAD_BUTTON_A)
1969 VIDEO_WaitVSync();
1970 while (!(m_input.keys & PAD_BUTTON_A))
1971 VIDEO_WaitVSync();
1972
1973 /* always close message box */
1974 GUI_MsgBoxClose();
1975 }
1976
GUI_WaitConfirm(char * title,char * msg)1977 int GUI_WaitConfirm(char *title, char *msg)
1978 {
1979 /* clear unused texture */
1980 gxTextureClose(&message_box.throbber);
1981
1982 /* open or update message box */
1983 GUI_MsgBoxOpen(title, msg, 0);
1984
1985 /* allocate texture */
1986 message_box.buttonA = gxTextureOpenPNG(Key_A_png,0);
1987 message_box.buttonB = gxTextureOpenPNG(Key_B_png,0);
1988
1989 /* wait for button A or Button B*/
1990 while (m_input.keys & (PAD_BUTTON_A | PAD_BUTTON_B))
1991 VIDEO_WaitVSync();
1992 while (!(m_input.keys & (PAD_BUTTON_A | PAD_BUTTON_B)))
1993 VIDEO_WaitVSync();
1994
1995 int ret = m_input.keys & PAD_BUTTON_A;
1996
1997 /* always close message box */
1998 GUI_MsgBoxClose();
1999
2000 return ret;
2001 }
2002
2003 /* Basic Fading */
GUI_FadeOut()2004 void GUI_FadeOut()
2005 {
2006 int alpha = 0;
2007 while (alpha < 256)
2008 {
2009 gxDrawRectangle(0, 0, 640, 480, alpha, (GXColor)BLACK);
2010 gxSetScreen();
2011 alpha +=3;
2012 }
2013 }
2014