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