X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=menu.c;h=5d96b7e3ed773426ad9c5784a7e577f440a206d7;hb=HEAD;hp=640f9b78ba57f5ab2179fddcabbc3d62d0fac55d;hpb=7b0a298567dcd67b1efde214b24a18d83b8be1d1;p=libpicofe.git diff --git a/menu.c b/menu.c index 640f9b7..5d96b7e 100644 --- a/menu.c +++ b/menu.c @@ -24,18 +24,30 @@ #include "plat.h" #include "posix.h" +#if defined(__GNUC__) && __GNUC__ >= 7 +#pragma GCC diagnostic ignored "-Wformat-truncation" +#endif + static char static_buff[64]; static int menu_error_time = 0; char menu_error_msg[64] = { 0, }; +// g_menuscreen is the current output buffer the menu is rendered to. void *g_menuscreen_ptr; -void *g_menubg_src_ptr; +// g_menubg is the menu background and has the same w/h as g_menuscreen, but +// pp=w. It is filled on menu entry from file or from g_menubg_src if available. void *g_menubg_ptr; -static char rom_fname_reload[256]; +// g_menubg_src points to a buffer containing a bg image. This is usually either +// the emulator screen buffer or the host frame buffer. +void *g_menubg_src_ptr; -#if !MSCREEN_SIZE_FIXED int g_menuscreen_w; int g_menuscreen_h; -#endif +int g_menuscreen_pp; +int g_menubg_src_w; +int g_menubg_src_h; +int g_menubg_src_pp; + +int g_autostateld_opt; static unsigned char *menu_font_data = NULL; static int menu_text_color = 0xfffe; // default to white @@ -50,14 +62,21 @@ static const int me_mfont_w = 8, me_mfont_h = 10; static const int me_sfont_w = 6, me_sfont_h = 10; #endif +static int g_menu_filter_off; static int g_border_style; static int border_left, border_right, border_top, border_bottom; +void menuscreen_memset_lines(unsigned short *dst, int c, int l) +{ + for (; l > 0; l--, dst += g_menuscreen_pp) + memset(dst, c, g_menuscreen_w * 2); +} + // draws text to current bbp16 screen static void text_out16_(int x, int y, const char *text, int color) { int i, lh, tr, tg, tb, len; - unsigned short *dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w; + unsigned short *dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_pp; tr = (color & 0xf800) >> 8; tg = (color & 0x07e0) >> 3; tb = (color & 0x001f) << 3; @@ -86,7 +105,7 @@ static void text_out16_(int x, int y, const char *text, int color) unsigned short *dst = dest; int u, l; - for (l = 0; l < lh; l++, dst += g_menuscreen_w - me_mfont_w) + for (l = 0; l < lh; l++, dst += g_menuscreen_pp - me_mfont_w) { for (u = me_mfont_w / 2; u > 0; u--, src++) { @@ -159,7 +178,7 @@ static void smalltext_out16_(int x, int y, const char *texto, int color) break; src = fontdata6x8[c]; - dst = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w; + dst = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_pp; while (h--) { @@ -174,7 +193,7 @@ static void smalltext_out16_(int x, int y, const char *texto, int color) dst += multiplier; } - dst += g_menuscreen_w - me_sfont_w; + dst += g_menuscreen_pp - me_sfont_w; } src++; } @@ -188,10 +207,10 @@ static void smalltext_out16(int x, int y, const char *texto, int color) if (maxw < 0) return; - - strncpy(buffer, texto, sizeof(buffer)); if (maxw > sizeof(buffer) - 1) maxw = sizeof(buffer) - 1; + + strncpy(buffer, texto, maxw); buffer[maxw] = 0; smalltext_out16_(x, y, buffer, color); @@ -207,13 +226,13 @@ static void menu_draw_selection(int x, int y, int w) if (menu_sel_color < 0) return; // no selection hilight if (y > 0) y--; - dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_w + me_mfont_w * 2 - 2; + dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_pp + me_mfont_w * 2 - 2; for (h = me_mfont_h + 1; h > 0; h--) { dst = dest; for (i = w - (me_mfont_w * 2 - 2); i > 0; i--) *dst++ = menu_sel_color; - dest += g_menuscreen_w; + dest += g_menuscreen_pp; } } @@ -239,7 +258,7 @@ static char tolower_simple(char c) void menu_init_base(void) { - int i, c, l; + int i, c, l, pos; unsigned char *fd, *fds; char buff[256]; FILE *f; @@ -252,19 +271,19 @@ void menu_init_base(void) return; // generate default 8x10 font from fontdata8x8 - for (c = 0, fd = menu_font_data; c < 256; c++) + for (c = 0, fd = menu_font_data; c < 128; c++) { for (l = 0; l < 8; l++) { unsigned char fd8x8 = fontdata8x8[c*8+l]; - if (fd8x8&0x80) *fd = 0xf0; - if (fd8x8&0x40) *fd |= 0x0f; fd++; - if (fd8x8&0x20) *fd = 0xf0; - if (fd8x8&0x10) *fd |= 0x0f; fd++; - if (fd8x8&0x08) *fd = 0xf0; - if (fd8x8&0x04) *fd |= 0x0f; fd++; - if (fd8x8&0x02) *fd = 0xf0; - if (fd8x8&0x01) *fd |= 0x0f; fd++; + if (fd8x8&0x80) { *fd = 0xf0; } + if (fd8x8&0x40) { *fd |= 0x0f; }; fd++; + if (fd8x8&0x20) { *fd = 0xf0; } + if (fd8x8&0x10) { *fd |= 0x0f; }; fd++; + if (fd8x8&0x08) { *fd = 0xf0; } + if (fd8x8&0x04) { *fd |= 0x0f; }; fd++; + if (fd8x8&0x02) { *fd = 0xf0; } + if (fd8x8&0x01) { *fd |= 0x0f; }; fd++; } fd += 8*2/2; // 2 empty lines } @@ -294,17 +313,18 @@ void menu_init_base(void) } // load custom font and selector (stored as 1st symbol in font table) - emu_make_path(buff, "skin/font.png", sizeof(buff)); + pos = plat_get_skin_dir(buff, sizeof(buff)); + strcpy(buff + pos, "font.png"); readpng(menu_font_data, buff, READPNG_FONT, MENU_X2 ? 256 : 128, MENU_X2 ? 320 : 160); // default selector symbol is '>' memcpy(menu_font_data, menu_font_data + ((int)'>') * me_mfont_w * me_mfont_h / 2, me_mfont_w * me_mfont_h / 2); - emu_make_path(buff, "skin/selector.png", sizeof(buff)); + strcpy(buff + pos, "selector.png"); readpng(menu_font_data, buff, READPNG_SELECTOR, me_mfont_w, me_mfont_h); // load custom colors - emu_make_path(buff, "skin/skin.txt", sizeof(buff)); + strcpy(buff + pos, "skin.txt"); f = fopen(buff, "r"); if (f != NULL) { @@ -380,10 +400,10 @@ static void menu_darken_text_bg(void) ymax = g_menuscreen_h - 1; for (x = xmin; x <= xmax; x++) - screen[y * g_menuscreen_w + x] = 0xa514; + screen[y * g_menuscreen_pp + x] = 0xa514; for (y++; y < ymax; y++) { - ls = y * g_menuscreen_w; + ls = y * g_menuscreen_pp; screen[ls + xmin] = 0xffff; for (x = xmin + 1; x < xmax; x++) { @@ -393,7 +413,7 @@ static void menu_darken_text_bg(void) } screen[ls + xmax] = 0xffff; } - ls = y * g_menuscreen_w; + ls = y * g_menuscreen_pp; for (x = xmin; x <= xmax; x++) screen[ls + x] = 0xffff; } @@ -410,6 +430,8 @@ static void menu_reset_borders(void) static void menu_draw_begin(int need_bg, int no_borders) { + int y; + plat_video_menu_begin(); menu_reset_borders(); @@ -417,12 +439,14 @@ static void menu_draw_begin(int need_bg, int no_borders) if (need_bg) { if (g_border_style && no_borders) { - menu_darken_bg(g_menuscreen_ptr, g_menubg_ptr, - g_menuscreen_w * g_menuscreen_h, 1); + for (y = 0; y < g_menuscreen_h; y++) + menu_darken_bg((short *)g_menuscreen_ptr + g_menuscreen_pp * y, + (short *)g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w, 1); } else { - memcpy(g_menuscreen_ptr, g_menubg_ptr, - g_menuscreen_w * g_menuscreen_h * 2); + for (y = 0; y < g_menuscreen_h; y++) + memcpy((short *)g_menuscreen_ptr + g_menuscreen_pp * y, + (short *)g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w * 2); } } } @@ -470,24 +494,12 @@ static int me_count(const menu_entry *ent) static unsigned int me_read_onoff(const menu_entry *ent) { - // guess var size based on mask to avoid reading too much - if (ent->mask & 0xffff0000) - return *(unsigned int *)ent->var & ent->mask; - else if (ent->mask & 0xff00) - return *(unsigned short *)ent->var & ent->mask; - else - return *(unsigned char *)ent->var & ent->mask; + return *(unsigned int *)ent->var & ent->mask; } static void me_toggle_onoff(menu_entry *ent) { - // guess var size based on mask to avoid reading too much - if (ent->mask & 0xffff0000) - *(unsigned int *)ent->var ^= ent->mask; - else if (ent->mask & 0xff00) - *(unsigned short *)ent->var ^= ent->mask; - else - *(unsigned char *)ent->var ^= ent->mask; + *(unsigned int *)ent->var ^= ent->mask; } static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) @@ -589,7 +601,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) name = ent->generate_name(ent->id, &offs); } if (name != NULL) { - text_out16(x, y, name); + text_out16(x, y, "%s", name); leftname_end = x + (strlen(name) + 1) * me_mfont_w; } @@ -597,7 +609,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) case MB_NONE: break; case MB_OPT_ONOFF: - text_out16(x + col2_offs, y, me_read_onoff(ent) ? "ON" : "OFF"); + text_out16(x + col2_offs, y, "%s", me_read_onoff(ent) ? "ON" : "OFF"); break; case MB_OPT_RANGE: text_out16(x + col2_offs, y, "%i", *(int *)ent->var); @@ -618,10 +630,10 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) offs = x + col2_offs; len = strlen(names[i]); if (len > 10) - offs += (10 - len - 2) * me_mfont_w; + offs += (10 - len) * me_mfont_w; if (offs < leftname_end) offs = leftname_end; - if (i == *(unsigned char *)ent->var) { + if (i == *(int *)ent->var) { text_out16(offs, y, "%s", names[i]); break; } @@ -638,7 +650,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) h = (g_menuscreen_h - h) / 2; // bottom area height if (menu_error_msg[0] != 0) { if (h >= me_mfont_h + 4) - text_out16(5, g_menuscreen_h - me_mfont_h - 4, menu_error_msg); + text_out16(5, g_menuscreen_h - me_mfont_h - 4, "%s", menu_error_msg); else lprintf("menu msg doesn't fit!\n"); @@ -686,11 +698,11 @@ static int me_process(menu_entry *entry, int is_next, int is_lr) names = (const char **)entry->data; for (c = 0; names[c] != NULL; c++) ; - *(signed char *)entry->var += is_next ? 1 : -1; - if (*(signed char *)entry->var < 0) - *(signed char *)entry->var = 0; - if (*(signed char *)entry->var >= c) - *(signed char *)entry->var = c - 1; + *(int *)entry->var += is_next ? 1 : -1; + if (*(int *)entry->var < 0) + *(int *)entry->var = 0; + if (*(int *)entry->var >= c) + *(int *)entry->var = c - 1; return 1; default: return 0; @@ -801,7 +813,7 @@ static void draw_menu_message(const char *msg, void (*draw_more)(void)) menu_draw_begin(1, 0); for (p = msg; *p != 0 && y <= g_menuscreen_h - me_mfont_h; y += me_mfont_h) { - text_out16(x, y, p); + text_out16(x, y, "%s", p); for (; *p != 0 && *p != '\n'; p++) ; @@ -843,7 +855,7 @@ static void do_delete(const char *fpath, const char *fname) snprintf(tmp + len, sizeof(tmp) - len, "%s - cancel)", nm); len = strlen(tmp); - text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, tmp); + text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, "%s", tmp); menu_draw_end(); while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MA2)); @@ -854,22 +866,23 @@ static void do_delete(const char *fpath, const char *fname) // -------------- ROM selector -------------- -static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel) +static void draw_dirlist(char *curdir, struct dirent **namelist, + int n, int sel, int show_help) { int max_cnt, start, i, x, pos; void *darken_ptr; + char buff[64]; max_cnt = g_menuscreen_h / me_sfont_h; start = max_cnt / 2 - sel; - n--; // exclude current dir (".") menu_draw_begin(1, 1); // if (!rom_loaded) // menu_darken_bg(gp2x_screen, 320*240, 0); - darken_ptr = (short *)g_menuscreen_ptr + g_menuscreen_w * max_cnt/2 * me_sfont_h; - menu_darken_bg(darken_ptr, darken_ptr, g_menuscreen_w * me_sfont_h * 8 / 10, 0); + darken_ptr = (short *)g_menuscreen_ptr + g_menuscreen_pp * max_cnt/2 * me_sfont_h; + menu_darken_bg(darken_ptr, darken_ptr, g_menuscreen_pp * me_sfont_h * 8 / 10, 0); x = 5 + me_mfont_w + 1; if (start - 2 >= 0) @@ -878,15 +891,37 @@ static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel) pos = start + i; if (pos < 0) continue; if (pos >= max_cnt) break; - if (namelist[i+1]->d_type == DT_DIR) { + if (namelist[i]->d_type == DT_DIR) { smalltext_out16(x, pos * me_sfont_h, "/", 0xfff6); - smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i+1]->d_name, 0xfff6); + smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i]->d_name, 0xfff6); } else { - unsigned short color = fname2color(namelist[i+1]->d_name); - smalltext_out16(x, pos * me_sfont_h, namelist[i+1]->d_name, color); + unsigned short color = fname2color(namelist[i]->d_name); + smalltext_out16(x, pos * me_sfont_h, namelist[i]->d_name, color); } } smalltext_out16(5, max_cnt/2 * me_sfont_h, ">", 0xffff); + + if (show_help) { + darken_ptr = (short *)g_menuscreen_ptr + + g_menuscreen_pp * (g_menuscreen_h - me_sfont_h * 5 / 2); + menu_darken_bg(darken_ptr, darken_ptr, + g_menuscreen_pp * (me_sfont_h * 5 / 2), 1); + + snprintf(buff, sizeof(buff), "%s - select, %s - back", + in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK)); + smalltext_out16(x, g_menuscreen_h - me_sfont_h * 3 - 2, buff, 0xe78c); + + snprintf(buff, sizeof(buff), g_menu_filter_off ? + "%s - hide unknown files" : "%s - show all files", + in_get_key_name(-1, -PBTN_MA3)); + smalltext_out16(x, g_menuscreen_h - me_sfont_h * 2 - 2, buff, 0xe78c); + + snprintf(buff, sizeof(buff), g_autostateld_opt ? + "%s - autoload save is ON" : "%s - autoload save is OFF", + in_get_key_name(-1, -PBTN_MA2)); + smalltext_out16(x, g_menuscreen_h - me_sfont_h * 1 - 2, buff, 0xe78c); + } + menu_draw_end(); } @@ -894,197 +929,278 @@ static int scandir_cmp(const void *p1, const void *p2) { const struct dirent **d1 = (const struct dirent **)p1; const struct dirent **d2 = (const struct dirent **)p2; + const char *p; + if ((p = (*d1)->d_name)[0] == '.' && p[1] == '.' && p[2] == 0) + return -1; // ".." first + if ((p = (*d2)->d_name)[0] == '.' && p[1] == '.' && p[2] == 0) + return 1; if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2); if ((*d1)->d_type == DT_DIR) - return -1; // put before + return -1; // directories before files/links if ((*d2)->d_type == DT_DIR) return 1; return alphasort(d1, d2); } +static const char **filter_exts_internal; + static int scandir_filter(const struct dirent *ent) { - const char *p; + const char **filter = filter_exts_internal; + const char *ext; int i; - if (ent == NULL || ent->d_name == NULL) return 0; - if (strlen(ent->d_name) < 5) return 1; + if (ent == NULL) + return 0; - p = ent->d_name + strlen(ent->d_name) - 4; + switch (ent->d_type) { + case DT_DIR: + // leave out useless reference to current directory + return strcmp(ent->d_name, ".") != 0; + case DT_LNK: + case DT_UNKNOWN: + // could be a dir, deal with it later.. + return 1; + } - for (i = 0; i < array_size(filter_exts); i++) - if (strcmp(p, filter_exts[i]) == 0) - return 0; + ext = strrchr(ent->d_name, '.'); + if (ext == NULL) + return 0; + + ext++; + for (i = 0; filter[i] != NULL; i++) + if (strcasecmp(ext, filter[i]) == 0) + return 1; - return 1; + return 0; } static int dirent_seek_char(struct dirent **namelist, int len, int sel, char c) { int i; - sel++; - for (i = sel + 1; i != sel; i++) { + for (i = sel + 1; ; i++) { if (i >= len) - i = 1; + i = 0; + if (i == sel) + break; if (tolower_simple(namelist[i]->d_name[0]) == c) break; } - return i - 1; + return i; } -static char *menu_loop_romsel(char *curr_path, int len) +static const char *menu_loop_romsel_d(char *curr_path, int len, + const char **filter_exts, + int (*extra_filter)(struct dirent **namelist, int count, + const char *basedir), + void (*draw_prep)(void)) { - struct dirent **namelist; - int n, inp, sel = 0; - char *ret = NULL, *fname = NULL; + static char rom_fname_reload[256]; // used for scratch and return + char sel_fname[256]; + int (*filter)(const struct dirent *); + struct dirent **namelist = NULL; + int n = 0, inp = 0, sel = 0, show_help = 0; + char *curr_path_restore = NULL; + const char *ret = NULL; char cinp; + int r, i; + + filter_exts_internal = filter_exts; + sel_fname[0] = 0; -rescan: // is this a dir or a full path? if (!plat_is_dir(curr_path)) { - char *p = curr_path + strlen(curr_path) - 1; - for (; p > curr_path && *p != '/'; p--) - ; - *p = 0; - fname = p+1; + char *p = strrchr(curr_path, '/'); + if (p != NULL) { + *p = 0; + curr_path_restore = p; + snprintf(sel_fname, sizeof(sel_fname), "%s", p + 1); + } } + show_help = 2; - n = scandir(curr_path, &namelist, scandir_filter, (void *)scandir_cmp); - if (n < 0) { - char *t; +rescan: + if (namelist != NULL) { + n += !n; + while (n-- > 0) + free(namelist[n]); + free(namelist); + namelist = NULL; + } + + filter = NULL; + if (!g_menu_filter_off) + filter = scandir_filter; + + n = scandir(curr_path, &namelist, filter, (void *)scandir_cmp); + if (n < 0 || !namelist) { lprintf("menu_loop_romsel failed, dir: %s\n", curr_path); - // try root - t = getcwd(curr_path, len); - if (t == NULL) - plat_get_root_dir(curr_path, len); - n = scandir(curr_path, &namelist, scandir_filter, (void *)scandir_cmp); - if (n < 0) { + // try data root + plat_get_data_dir(curr_path, len); + n = scandir(curr_path, &namelist, filter, (void *)scandir_cmp); + if (n < 0 || !namelist) { // oops, we failed lprintf("menu_loop_romsel failed, dir: %s\n", curr_path); - return NULL; + namelist = malloc(sizeof(*namelist)); + namelist[0] = calloc(1, sizeof(**namelist)); } } - // try to find sel - // note: we don't show '.' so sel is namelist index - 1 - if (fname != NULL) { - int i; - for (i = 1; i < n; i++) { + // try to resolve DT_UNKNOWN and symlinks + for (i = 0; i < n; i++) { + struct stat st; + char *slash; + + if (namelist[i]->d_type == DT_REG || namelist[i]->d_type == DT_DIR) + continue; + + r = strlen(curr_path); + slash = (r && curr_path[r-1] == '/') ? "" : "/"; + snprintf(rom_fname_reload, sizeof(rom_fname_reload), + "%s%s%s", curr_path, slash, namelist[i]->d_name); + r = stat(rom_fname_reload, &st); + if (r == 0) + { + if (S_ISREG(st.st_mode)) + namelist[i]->d_type = DT_REG; + else if (S_ISDIR(st.st_mode)) + namelist[i]->d_type = DT_DIR; + } + } + + if (!g_menu_filter_off && extra_filter != NULL) + n = extra_filter(namelist, n, curr_path); + + if (n > 1) + qsort(namelist, n, sizeof(namelist[0]), scandir_cmp); + + // try to find selected file + sel = 0; + if (sel_fname[0] != 0) { + for (i = 0; i < n; i++) { char *dname = namelist[i]->d_name; - if (dname[0] == fname[0] && strcmp(dname, fname) == 0) { - sel = i - 1; + if (dname[0] == sel_fname[0] && strcmp(dname, sel_fname) == 0) { + sel = i; break; } } } /* make sure action buttons are not pressed on entering menu */ - draw_dirlist(curr_path, namelist, n, sel); + draw_dirlist(curr_path, namelist, n, sel, show_help); while (in_menu_wait_any(NULL, 50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU)) ; for (;;) { - draw_dirlist(curr_path, namelist, n, sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT| - PBTN_L|PBTN_R|PBTN_MA2|PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_CHAR, &cinp, 33); - if (inp & PBTN_UP ) { sel--; if (sel < 0) sel = n-2; } - if (inp & PBTN_DOWN) { sel++; if (sel > n-2) sel = 0; } - if (inp & PBTN_LEFT) { sel-=10; if (sel < 0) sel = 0; } - if (inp & PBTN_L) { sel-=24; if (sel < 0) sel = 0; } - if (inp & PBTN_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; } - if (inp & PBTN_R) { sel+=24; if (sel > n-2) sel = n-2; } - if (inp & PBTN_CHAR) sel = dirent_seek_char(namelist, n, sel, cinp); - if ((inp & PBTN_MOK) || (inp & (PBTN_MENU|PBTN_MA2)) == (PBTN_MENU|PBTN_MA2)) + if (draw_prep != NULL) + draw_prep(); + draw_dirlist(curr_path, namelist, n, sel, show_help); + inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT + | PBTN_L|PBTN_R|PBTN_MA2|PBTN_MA3|PBTN_MOK|PBTN_MBACK + | PBTN_MENU|PBTN_CHAR, &cinp, 33); + if (inp & PBTN_MA3) { + g_menu_filter_off = !g_menu_filter_off; + snprintf(sel_fname, sizeof(sel_fname), "%s", + namelist[sel]->d_name); + show_help = 2; + goto rescan; + } + int last = n ? n-1 : 0; + if (inp & PBTN_UP ) { sel--; if (sel < 0) sel = last; } + else if (inp & PBTN_DOWN) { sel++; if (sel > n-1) sel = 0; } + else if (inp & PBTN_LEFT) { sel-=10; if (sel < 0) sel = 0; } + else if (inp & PBTN_RIGHT) { sel+=10; if (sel > n-1) sel = last; } + else if (inp & PBTN_L) { sel-=24; if (sel < 0) sel = 0; } + else if (inp & PBTN_R) { sel+=24; if (sel > n-1) sel = last; } + + else if ((inp & PBTN_MOK) || (inp & (PBTN_MENU|PBTN_MA2)) == (PBTN_MENU|PBTN_MA2)) { - again: - if (namelist[sel+1]->d_type == DT_REG) + if (namelist[sel]->d_type == DT_REG) { - strcpy(rom_fname_reload, curr_path); - strcat(rom_fname_reload, "/"); - strcat(rom_fname_reload, namelist[sel+1]->d_name); + int l = strlen(curr_path); + char *slash = l && curr_path[l-1] == '/' ? "" : "/"; + snprintf(rom_fname_reload, sizeof(rom_fname_reload), + "%s%s%s", curr_path, slash, namelist[sel]->d_name); if (inp & PBTN_MOK) { // return sel ret = rom_fname_reload; break; } - do_delete(rom_fname_reload, namelist[sel+1]->d_name); - if (n > 0) { - while (n--) free(namelist[n]); - free(namelist); - } + do_delete(rom_fname_reload, namelist[sel]->d_name); goto rescan; } - else if (namelist[sel+1]->d_type == DT_DIR) + else if (namelist[sel]->d_type == DT_DIR) { int newlen; char *p, *newdir; if (!(inp & PBTN_MOK)) continue; - newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2; + newlen = strlen(curr_path) + strlen(namelist[sel]->d_name) + 2; newdir = malloc(newlen); if (newdir == NULL) break; - if (strcmp(namelist[sel+1]->d_name, "..") == 0) { + if (strcmp(namelist[sel]->d_name, "..") == 0) { char *start = curr_path; p = start + strlen(start) - 1; while (*p == '/' && p > start) p--; while (*p != '/' && p > start) p--; - if (p <= start) strcpy(newdir, "/"); + if (p <= start) plat_get_data_dir(newdir, newlen); else { strncpy(newdir, start, p-start); newdir[p-start] = 0; } } else { strcpy(newdir, curr_path); p = newdir + strlen(newdir) - 1; while (*p == '/' && p >= newdir) *p-- = 0; strcat(newdir, "/"); - strcat(newdir, namelist[sel+1]->d_name); + strcat(newdir, namelist[sel]->d_name); } - ret = menu_loop_romsel(newdir, newlen); + ret = menu_loop_romsel_d(newdir, newlen, filter_exts, extra_filter, draw_prep); free(newdir); break; } - else - { - // unknown file type, happens on NTFS mounts. Try to guess. - FILE *tstf; int tmp; - strcpy(rom_fname_reload, curr_path); - strcat(rom_fname_reload, "/"); - strcat(rom_fname_reload, namelist[sel+1]->d_name); - tstf = fopen(rom_fname_reload, "rb"); - if (tstf != NULL) - { - if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0) - namelist[sel+1]->d_type = DT_REG; - else namelist[sel+1]->d_type = DT_DIR; - fclose(tstf); - goto again; - } - } } + else if (inp & PBTN_MA2) { + g_autostateld_opt = !g_autostateld_opt; + show_help = 3; + } + else if (inp & PBTN_CHAR) { + // must be last + sel = dirent_seek_char(namelist, n, sel, cinp); + } + if (inp & PBTN_MBACK) break; + + if (show_help > 0) + show_help--; } if (n > 0) { - while (n--) free(namelist[n]); + while (n-- > 0) + free(namelist[n]); free(namelist); } // restore curr_path - if (fname != NULL) { - n = strlen(curr_path); - if (curr_path + n + 1 == fname) - curr_path[n] = '/'; - } + if (curr_path_restore != NULL) + *curr_path_restore = '/'; return ret; } +static const char *menu_loop_romsel(char *curr_path, int len, + const char **filter_exts, + int (*extra_filter)(struct dirent **namelist, int count, + const char *basedir)) +{ + return menu_loop_romsel_d(curr_path, len, filter_exts, extra_filter, NULL); +} + // ------------ savestate loader ------------ #define STATE_SLOT_COUNT 10 @@ -1215,10 +1331,10 @@ static char *action_binds(int player_idx, int action_mask, int dev_id) type = IN_BINDTYPE_EMU; if (player_idx >= 0) { can_combo = 0; - type = IN_BINDTYPE_PLAYER12; + type = IN_BINDTYPE_PLAYER12 + (player_idx >> 1); + if (player_idx & 1) + action_mask <<= 16; } - if (player_idx == 1) - action_mask <<= 16; if (dev_id >= 0) dev = dev_last = dev_id; @@ -1288,7 +1404,8 @@ static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_ y = (g_menuscreen_h - 4 * me_mfont_h) / 2 - (2 + opt_cnt) * me_mfont_h / 2; if (x < me_mfont_w * 2) x = me_mfont_w * 2; - + if (y < 0) + y = 0; menu_draw_begin(1, 0); if (player_idx >= 0) text_out16(x, y, "Player %i controls", player_idx + 1); @@ -1307,7 +1424,7 @@ static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_ if (dev_id < 0) dev_name = "(all devices)"; else - dev_name = in_get_dev_name(dev_id, 1, 1); + dev_name = in_get_dev_name(dev_id, 0, 1); w = strlen(dev_name) * me_mfont_w; if (w < 30 * me_mfont_w) w = 30 * me_mfont_w; @@ -1320,13 +1437,13 @@ static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_ snprintf(buff2, sizeof(buff2), "%s", in_get_key_name(-1, -PBTN_MOK)); snprintf(buff, sizeof(buff), "%s - bind, %s - clear", buff2, in_get_key_name(-1, -PBTN_MA2)); - text_out16(x, g_menuscreen_h - 4 * me_mfont_h, buff); + text_out16(x, g_menuscreen_h - 4 * me_mfont_h, "%s", buff); } else text_out16(x, g_menuscreen_h - 4 * me_mfont_h, "Press a button to bind/unbind"); if (dev_count > 1) { - text_out16(x, g_menuscreen_h - 3 * me_mfont_h, dev_name); + text_out16(x, g_menuscreen_h - 3 * me_mfont_h, "%s", dev_name); text_out16(x, g_menuscreen_h - 2 * me_mfont_h, "Press left/right for other devs"); } @@ -1354,9 +1471,12 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ dev_id = -1; // show all mask_shift = 0; - if (player_idx == 1) - mask_shift = 16; - bindtype = player_idx >= 0 ? IN_BINDTYPE_PLAYER12 : IN_BINDTYPE_EMU; + if (player_idx >= 0) { + if (player_idx & 1) + mask_shift = 16; + bindtype = IN_BINDTYPE_PLAYER12 + (player_idx >> 1); + } else + bindtype = IN_BINDTYPE_EMU; for (;;) { @@ -1370,7 +1490,7 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ for (i = 0, dev_id--; i < IN_MAX_DEVS + 1; i++, dev_id--) { if (dev_id < -1) dev_id = IN_MAX_DEVS - 1; - if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL) + if (dev_id == -1 || in_get_dev_name(dev_id, 0, 0) != NULL) break; } continue; @@ -1378,7 +1498,7 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ for (i = 0, dev_id++; i < IN_MAX_DEVS; i++, dev_id++) { if (dev_id >= IN_MAX_DEVS) dev_id = -1; - if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL) + if (dev_id == -1 || in_get_dev_name(dev_id, 0, 0) != NULL) break; } continue; @@ -1414,6 +1534,10 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ in_unbind_all(bind_dev_id, opts[sel].mask << mask_shift, bindtype); in_bind_key(bind_dev_id, kc, opts[sel].mask << mask_shift, bindtype, 0); + + // make sure bind change is displayed + if (dev_id != -1) + dev_id = bind_dev_id; } }