/* * filesel.c * * ROM File Browser * * Copyright Eke-Eke (2009-2011) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: * * - Redistributions may not be sold, nor may they be used in a commercial * product or activity. * * - Redistributions that are modified from the original source must include the * complete source code, including the source code for all components used by a * binary built from the modified sources. However, as a special exception, the * source code distributed need not include anything that is normally distributed * (in either source or binary form) with the major components (compiler, kernel, * and so on) of the operating system on which the executable runs, unless that * component itself accompanies the executable. * * - Redistributions must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************************/ #include "shared.h" #include "filesel.h" #include "font.h" #include "gui.h" #include "file_load.h" #ifdef HW_RVL #include #endif #define BG_COLOR_1 {0x49,0x49,0x49,0xff} #define BG_COLOR_2 {0x66,0x66,0x66,0xff} #define SCROLL_SPEED 10 extern const u8 Browser_dir_png[]; extern const u8 Snap_empty_png[]; extern const u8 Snap_frame_png[]; FILEENTRIES filelist[MAXFILES]; static int offset = 0; static int selection = 0; static int maxfiles = 0; static int string_offset = 0; static char prev_folder[MAXJOLIET]; static void selector_cb(void); /*****************************************************************************/ /* GUI Buttons data */ /*****************************************************************************/ static butn_data arrow_up_data = { {NULL,NULL}, {Button_up_png,Button_up_over_png} }; static butn_data arrow_down_data = { {NULL,NULL}, {Button_down_png,Button_down_over_png} }; /*****************************************************************************/ /* GUI Arrows button */ /*****************************************************************************/ static gui_butn arrow_up = {&arrow_up_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX,{0,0,0,0},14,76,360,32}; static gui_butn arrow_down = {&arrow_down_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX,{0,0,0,0},14,368,360,32}; /*****************************************************************************/ /* GUI helpers */ /*****************************************************************************/ static gui_item action_cancel = { NULL,Key_B_png,"","Previous Directory",10,422,28,28 }; static gui_item action_select = { NULL,Key_A_png,"","Load ROM file",602,422,28,28 }; /*****************************************************************************/ /* GUI Background images */ /*****************************************************************************/ static gui_image bg_filesel[10] = { {NULL,Bg_main_png,IMAGE_VISIBLE,374,140,284,288,255}, {NULL,Bg_overlay_png,IMAGE_VISIBLE|IMAGE_REPEAT,0,0,640,480,255}, {NULL,Banner_top_png,IMAGE_VISIBLE,0,0,640,108,255}, {NULL,Banner_bottom_png,IMAGE_VISIBLE,0,380,640,100,255}, {NULL,Main_logo_png,IMAGE_VISIBLE,466,40,152,44,255}, /*{NULL,Frame_s1_png,IMAGE_VISIBLE,8,70,372,336,152}, {NULL,Frame_s2_png,0,384,264,248,140,152}, {NULL,Snap_empty_png,IMAGE_VISIBLE,422,114,164,116,255}, {NULL,NULL,0,424,116,160,112,255}, {NULL,Snap_frame_png,IMAGE_VISIBLE,388,112,236,148,255}*/ // wiimpathy : Display covers instead of screenshots, values may be adjusted. // Snap_empty_png and Snap_frame_png are transparent png for the quick test. {NULL,Frame_s1_png,IMAGE_VISIBLE,8,70,72,36,150}, {NULL,Frame_s2_png,0,384,264,248,140,200}, {NULL,Snap_empty_png,IMAGE_VISIBLE,422,114,164,116,255}, {NULL,NULL,0,434,126,176,248,255}, {NULL,Snap_frame_png,IMAGE_VISIBLE,600,112,236,148,150} }; /*****************************************************************************/ /* GUI Descriptor */ /*****************************************************************************/ static gui_menu menu_selector = { "Game Selection", -1,-1, 0,0,10,0, NULL, NULL, bg_filesel, {&action_cancel, &action_select}, {&arrow_up,&arrow_down}, selector_cb }; static void selector_cb(void) { int i; char text[MAXPATHLEN]; int yoffset = 108; /* Initialize directory icon */ gui_image dir_icon; dir_icon.texture = gxTextureOpenPNG(Browser_dir_png,0); dir_icon.w = dir_icon.texture->width; dir_icon.h = dir_icon.texture->height; dir_icon.x = 26; dir_icon.y = (26 - dir_icon.h)/2; /* Initialize selection bar */ gui_image bar_over; bar_over.texture = gxTextureOpenPNG(Overlay_bar_png,0); bar_over.w = bar_over.texture->width; bar_over.h = bar_over.texture->height; bar_over.x = 16; bar_over.y = (26 - bar_over.h)/2; /* Draw browser array */ gxDrawRectangle(15, 108, 358, 26, 127, (GXColor)BG_COLOR_1); gxDrawRectangle(15, 134, 358, 26, 127, (GXColor)BG_COLOR_2); gxDrawRectangle(15, 160, 358, 26, 127, (GXColor)BG_COLOR_1); gxDrawRectangle(15, 186, 358, 26, 127, (GXColor)BG_COLOR_2); gxDrawRectangle(15, 212, 358, 26, 127, (GXColor)BG_COLOR_1); gxDrawRectangle(15, 238, 358, 26, 127, (GXColor)BG_COLOR_2); gxDrawRectangle(15, 264, 358, 26, 127, (GXColor)BG_COLOR_1); gxDrawRectangle(15, 290, 358, 26, 127, (GXColor)BG_COLOR_2); gxDrawRectangle(15, 316, 358, 26, 127, (GXColor)BG_COLOR_1); gxDrawRectangle(15, 342, 358, 26, 127, (GXColor)BG_COLOR_2); /* Draw Files list */ for (i = offset; (i < (offset + 10)) && (i < maxfiles); i++) { if (i == selection) { /* selection bar */ gxDrawTexture(bar_over.texture,bar_over.x,yoffset+bar_over.y,bar_over.w,bar_over.h,255); /* scrolling text */ if ((string_offset/SCROLL_SPEED) >= strlen(filelist[i].filename)) { string_offset = 0; } if (string_offset) { sprintf(text,"%s ",filelist[i].filename+string_offset/SCROLL_SPEED); strncat(text, filelist[i].filename, string_offset/SCROLL_SPEED); } else { strcpy(text, filelist[i].filename); } /* print text */ if (filelist[i].flags) { /* directory icon */ gxDrawTexture(dir_icon.texture,dir_icon.x,yoffset+dir_icon.y,dir_icon.w,dir_icon.h,255); if (FONT_write(text,18,dir_icon.x+dir_icon.w+6,yoffset+22,bar_over.w-dir_icon.w-26,(GXColor)WHITE)) { /* text scrolling */ string_offset ++; } } else { if (FONT_write(text,18,dir_icon.x,yoffset+22,bar_over.w-20,(GXColor)WHITE)) { /* text scrolling */ string_offset ++; } } } else { if (filelist[i].flags) { /* directory icon */ gxDrawTexture(dir_icon.texture,dir_icon.x,yoffset+dir_icon.y,dir_icon.w,dir_icon.h,255); FONT_write(filelist[i].filename,18,dir_icon.x+dir_icon.w+6,yoffset+22,bar_over.w-dir_icon.w-26,(GXColor)WHITE); } else { FONT_write(filelist[i].filename,18,dir_icon.x,yoffset+22,bar_over.w-20,(GXColor)WHITE); } } yoffset += 26; } gxTextureClose(&bar_over.texture); gxTextureClose(&dir_icon.texture); } /**************************************************************************** * FileSelector * * Browse directories and select a file from the file listing * return ROM size * ****************************************************************************/ int FileSelector(void) { short p; int i; int old = -1; char fname[MAXPATHLEN]; FILE *snap; gui_menu *m = &menu_selector; #ifdef HW_RVL int x,y; gui_butn *button; #endif /* background type */ if (config.bg_type > 0) { bg_filesel[0].state &= ~IMAGE_REPEAT; bg_filesel[0].data = (config.bg_type > 1) ? Bg_main_png : Bg_main_2_png; bg_filesel[0].x = 374; bg_filesel[0].y = 140; bg_filesel[0].w = 284; bg_filesel[0].h = 288; } else { bg_filesel[0].state |= IMAGE_REPEAT; bg_filesel[0].data = Bg_layer_png; bg_filesel[0].x = 0; bg_filesel[0].y = 0; bg_filesel[0].w = 640; bg_filesel[0].h = 480; } /* background overlay */ if (config.bg_overlay) { bg_filesel[1].state |= IMAGE_VISIBLE; } else { bg_filesel[1].state &= ~IMAGE_VISIBLE; } /* Initialize Menu */ GUI_InitMenu(m); string_offset = 0; while (1) { /* ROM file snapshot/database */ if (old != selection) { /* close any existing texture first */ gxTextureClose(&bg_filesel[8].texture); bg_filesel[8].state &= ~IMAGE_VISIBLE; old = selection; string_offset = 0; if (!filelist[selection].flags) { /* get compressed file name */ sprintf(fname, "%s/%s", GetCurrentDirectory(selection), filelist[selection].filename); get_zipfilename(fname); /* auto-detect file type */ if (!strnicmp(".sms", &fname[strlen(fname) - 4], 4)) { /* Master System ROM file */ sprintf(fname, "%s/snaps/ms/%s", DEFAULT_PATH, filelist[selection].filename); } else if (!strnicmp(".gg", &fname[strlen(fname) - 3], 3)) { /* Game Gear ROM file */ sprintf(fname, "%s/snaps/gg/%s", DEFAULT_PATH, filelist[selection].filename); } else if (!strnicmp(".sg", &fname[strlen(fname) - 3], 3)) { /* SG-1000 ROM file */ sprintf(fname, "%s/snaps/sg/%s", DEFAULT_PATH, filelist[selection].filename); } else if ((!strnicmp(".md", &fname[strlen(fname) - 3], 3)) || (!strnicmp(".gen", &fname[strlen(fname) - 4], 4)) || (!strnicmp(".bin", &fname[strlen(fname) - 4], 4)) || (!strnicmp(".mdx", &fname[strlen(fname) - 4], 4)) || (!strnicmp(".smd", &fname[strlen(fname) - 4], 4))) { /* Genesis ROM file */ sprintf(fname, "%s/snaps/md/%s", DEFAULT_PATH, filelist[selection].filename); } else { fname[0] = 0; } } else { fname[0] = 0; } /* Supported ROM file found ? */ if (fname[0]) { /* remove original file extension */ i = strlen(fname) - 1; while ((i > 0) && (fname[i] != '.')) i--; if (i > 0) fname[i] = 0; /* add PNG file extension */ strcat(fname, ".png"); /* try to load screenshot */ snap = fopen(fname, "rb"); if (snap) { bg_filesel[8].texture = gxTextureOpenPNG(0,snap); if (bg_filesel[8].texture) { bg_filesel[8].state |= IMAGE_VISIBLE; } fclose(snap); } } } /* update helper */ if (m->selected != -1) { /* out of focus */ strcpy(action_select.comment,""); } else if (filelist[selection].flags) { /* this is a directory */ strcpy(action_select.comment,"Open Directory"); } else { /* this is a ROM file */ strcpy(action_select.comment,"Load ROM File"); } /* Draw menu*/ GUI_DrawMenu(m); #ifdef HW_RVL if (Shutdown) { gxTextureClose(&w_pointer); GUI_DeleteMenu(m); GUI_FadeOut(); shutdown(); SYS_ResetSystem(SYS_POWEROFF, 0, 0); } else if (m_input.ir.valid) { /* get cursor position */ x = m_input.ir.x; y = m_input.ir.y; /* draw wiimote pointer */ gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255); /* ensure we are in the selectable area */ if ((x < 380) && (y >= 108) && (y <= 368)) { /* find selected item */ selection = (y - 108) / 26; if (selection > 9) selection = 9; selection += offset; if (selection >= maxfiles) selection = old; /* reset selection */ m->selected = -1; } else { /* disable selection */ m->selected = m->max_buttons + 2; /* find selected button */ for (i=0; i<2; i++) { button = m->arrows[i]; if (button) { if (button->state & BUTTON_VISIBLE) { if ((x>=button->x)&&(x<=(button->x+button->w))&&(y>=button->y)&&(y<=(button->y+button->h))) { m->selected = m->max_buttons + i; break; } } } } } } else { /* reset selection */ m->selected = -1; } #endif /* copy EFB to XFB */ gxSetScreen(); p = m_input.keys; /* highlight next item */ if (p & PAD_BUTTON_DOWN) { selection++; if (selection == maxfiles) selection = offset = 0; if ((selection - offset) >= 10) offset += 10; } /* highlight previous item */ else if (p & PAD_BUTTON_UP) { selection--; if (selection < 0) { selection = maxfiles - 1; offset = selection - 10 + 1; } if (selection < offset) offset -= 10; if (offset < 0) offset = 0; } /* go back one page */ else if (p & PAD_TRIGGER_L) { selection -= 10; if (selection < 0) { selection = maxfiles - 1; offset = selection - 10 + 1; } if (selection < offset) offset -= 10; if (offset < 0) offset = 0; } /* go forward one page */ else if (p & PAD_TRIGGER_R) { selection += 10; if (selection > maxfiles - 1) selection = offset = 0; if ((selection - offset) >= 10) offset += 10; } /* quit */ else if (p & PAD_TRIGGER_Z) { GUI_DeleteMenu(m); return 0; } /* previous directory */ else if (p & PAD_BUTTON_B) { string_offset = 0; /* update browser directory (and get current folder)*/ if (UpdateDirectory(1, prev_folder)) { /* get directory entries */ maxfiles = ParseDirectory(); /* clear selection by default */ selection = offset = 0; old = -1; /* select previous directory */ for (i=0; iselected < m->max_buttons) { if (filelist[selection].flags) { /* get new directory */ UpdateDirectory(0, filelist[selection].filename); /* get directory entries */ maxfiles = ParseDirectory(); /* clear selection by default */ selection = offset = 0; old = -1; } else if (fname[0]) { /* load ROM file from device */ int ret = LoadFile(selection); /* exit menu */ GUI_DeleteMenu(m); /* return ROM size (or zero if an error occured) */ return ret; } else { /* Unsupported ROM file */ GUI_WaitPrompt("Error","Unsupported ROM type !"); } } #ifdef HW_RVL /* arrow buttons selected */ else if (m->selected == m->max_buttons) { /* up arrow */ selection--; if (selection < 0) { selection = maxfiles - 1; offset = selection - 10 + 1; } if (selection < offset) offset -= 10; if (offset < 0) offset = 0; } else if (m->selected == (m->max_buttons+1)) { /* down arrow */ selection++; if (selection == maxfiles) selection = offset = 0; if ((selection - offset) >= 10) offset += 10; } #endif } } } void ClearSelector(u32 max) { maxfiles = max; offset = 0; selection = 0; }