X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=frontend%2Fcommon%2Fmenu.c;h=3acab62c34ffdb2f685e55bb84bd14596707c5ba;hp=a571ddd15a71205345bdeefc45a8a365bd57b174;hb=61f97bb0518cde50b243fba8ce2e8a907a0fc2e9;hpb=9564e73db83552dd7992c633362b0d99e14a4453 diff --git a/frontend/common/menu.c b/frontend/common/menu.c index a571ddd1..3acab62c 100644 --- a/frontend/common/menu.c +++ b/frontend/common/menu.c @@ -1,12 +1,19 @@ -// (c) Copyright 2006-2010 notaz, All rights reserved. -// Free for non-commercial use. - -// For commercial use, separate licencing terms must be obtained. +/* + * (C) Gražvydas "notaz" Ignotas, 2006-2011 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ #include #include #include #include +#include +#include // savestate date #include "menu.h" #include "fonts.h" @@ -209,6 +216,13 @@ static int parse_hex_color(char *buff) return -1; } +static char tolower_simple(char c) +{ + if ('A' <= c && c <= 'Z') + c = c - 'A' + 'a'; + return c; +} + void menu_init(void) { int i, c, l; @@ -304,6 +318,9 @@ void menu_init(void) } fclose(f); } + + // use user's locale for savestate date display + setlocale(LC_TIME, ""); } static void menu_draw_begin(int need_bg) @@ -341,26 +358,6 @@ static void menu_darken_bg(void *dst, void *src, int pixels, int darker) } } -static void menu_enter(int is_rom_loaded) -{ - if (is_rom_loaded) - { - // darken the active framebuffer - menu_darken_bg(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h, 1); - } - else - { - char buff[256]; - - // should really only happen once, on startup.. - emu_make_path(buff, "skin/background.png", sizeof(buff)); - if (readpng(g_menubg_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h) < 0) - memset(g_menubg_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2); - } - - plat_video_menu_enter(is_rom_loaded); -} - static int me_id2offset(const menu_entry *ent, menu_id id) { int i; @@ -387,6 +384,28 @@ static int me_count(const menu_entry *ent) return ret; } +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; +} + +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; +} + static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) { const menu_entry *ent, *ent_sel = entries; @@ -461,8 +480,11 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) h = g_menuscreen_h; } - x = g_menuscreen_w / 2 - w / 2; + x = g_menuscreen_w / 2 - w / 2; y = g_menuscreen_h / 2 - h / 2; +#ifdef MENU_ALIGN_LEFT + if (x > 12) x = 12; +#endif /* draw */ menu_draw_begin(1); @@ -472,7 +494,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) for (ent = entries; ent->name; ent++) { const char **names; - int len; + int len, leftname_end = 0; if (!ent->enabled) continue; @@ -482,14 +504,16 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) if (ent->generate_name) name = ent->generate_name(ent->id, &offs); } - if (name != NULL) + if (name != NULL) { text_out16(x, y, name); + leftname_end = x + (strlen(name) + 1) * me_mfont_w; + } switch (ent->beh) { case MB_NONE: break; case MB_OPT_ONOFF: - text_out16(x + col2_offs, y, (*(int *)ent->var & ent->mask) ? "ON" : "OFF"); + text_out16(x + col2_offs, y, me_read_onoff(ent) ? "ON" : "OFF"); break; case MB_OPT_RANGE: text_out16(x + col2_offs, y, "%i", *(int *)ent->var); @@ -506,13 +530,15 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void)) break; case MB_OPT_ENUM: names = (const char **)ent->data; - offs = 0; for (i = 0; names[i] != NULL; i++) { + offs = x + col2_offs; len = strlen(names[i]); if (len > 10) - offs = 10 - len - 2; - if (i == *(int *)ent->var) { - text_out16(x + col2_offs + offs * me_mfont_w, y, "%s", names[i]); + offs += (10 - len - 2) * me_mfont_w; + if (offs < leftname_end) + offs = leftname_end; + if (i == *(unsigned char *)ent->var) { + text_out16(offs, y, "%s", names[i]); break; } } @@ -557,7 +583,7 @@ static int me_process(menu_entry *entry, int is_next, int is_lr) { case MB_OPT_ONOFF: case MB_OPT_CUSTONOFF: - *(int *)entry->var ^= entry->mask; + me_toggle_onoff(entry); return 1; case MB_OPT_RANGE: case MB_OPT_CUSTRANGE: @@ -572,11 +598,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++) ; - *(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; + *(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; return 1; default: return 0; @@ -585,14 +611,14 @@ static int me_process(menu_entry *entry, int is_next, int is_lr) static void debug_menu_loop(void); -static void me_loop(menu_entry *menu, int *menu_sel, void (*draw_more)(void)) +static int me_loop_d(menu_entry *menu, int *menu_sel, void (*draw_prep)(void), void (*draw_more)(void)) { - int ret, inp, sel = *menu_sel, menu_sel_max; + int ret = 0, inp, sel = *menu_sel, menu_sel_max; menu_sel_max = me_count(menu) - 1; if (menu_sel_max < 0) { lprintf("no enabled menu entries\n"); - return; + return 0; } while ((!menu[sel].enabled || !menu[sel].selectable) && sel < menu_sel_max) @@ -600,13 +626,16 @@ static void me_loop(menu_entry *menu, int *menu_sel, void (*draw_more)(void)) /* make sure action buttons are not pressed on entering menu */ me_draw(menu, sel, NULL); - while (in_menu_wait_any(50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU)); + while (in_menu_wait_any(NULL, 50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU)); for (;;) { + if (draw_prep != NULL) + draw_prep(); + me_draw(menu, sel, draw_more); inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT| - PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_L|PBTN_R, 70); + PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_L|PBTN_R, NULL, 70); if (inp & (PBTN_MENU|PBTN_MBACK)) break; @@ -648,17 +677,23 @@ static void me_loop(menu_entry *menu, int *menu_sel, void (*draw_more)(void)) } } *menu_sel = sel; + + return ret; +} + +static int me_loop(menu_entry *menu, int *menu_sel) +{ + return me_loop_d(menu, menu_sel, NULL, NULL); } /* ***************************************** */ -static void draw_menu_credits(void (*draw_more)(void)) +static void draw_menu_message(const char *msg, void (*draw_more)(void)) { - const char *creds, *p; int x, y, h, w, wt; + const char *p; - p = creds = plat_get_credits(); - + p = msg; for (h = 1, w = 0; *p != 0; h++) { for (wt = 0; *p != 0 && *p != '\n'; p++) wt++; @@ -670,14 +705,14 @@ static void draw_menu_credits(void (*draw_more)(void)) p++; } - x = g_menuscreen_w / 2 - w * me_mfont_w / 2; + x = g_menuscreen_w / 2 - w * me_mfont_w / 2; y = g_menuscreen_h / 2 - h * me_mfont_h / 2; if (x < 0) x = 0; if (y < 0) y = 0; menu_draw_begin(1); - for (p = creds; *p != 0 && y <= g_menuscreen_h - me_mfont_h; y += me_mfont_h) { + for (p = msg; *p != 0 && y <= g_menuscreen_h - me_mfont_h; y += me_mfont_h) { text_out16(x, y, p); for (; *p != 0 && *p != '\n'; p++) @@ -721,8 +756,8 @@ static void do_delete(const char *fpath, const char *fname) text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, tmp); menu_draw_end(); - while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MA2)); - inp = in_menu_wait(PBTN_MA3|PBTN_MBACK, 100); + while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MA2)); + inp = in_menu_wait(PBTN_MA3|PBTN_MBACK, NULL, 100); if (inp & PBTN_MA3) remove(fpath); } @@ -779,11 +814,6 @@ static int scandir_cmp(const void *p1, const void *p2) return alphasort(d1, d2); } -static const char *filter_exts[] = { - ".mp3", ".MP3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html", - ".jpg", ".gpe" -}; - static int scandir_filter(const struct dirent *ent) { const char *p; @@ -801,11 +831,28 @@ static int scandir_filter(const struct dirent *ent) return 1; } +static int dirent_seek_char(struct dirent **namelist, int len, int sel, char c) +{ + int i; + + sel++; + for (i = sel + 1; i != sel; i++) { + if (i >= len) + i = 1; + + if (tolower_simple(namelist[i]->d_name[0]) == c) + break; + } + + return i - 1; +} + static char *menu_loop_romsel(char *curr_path, int len) { struct dirent **namelist; int n, inp, sel = 0; char *ret = NULL, *fname = NULL; + char cinp; rescan: // is this a dir or a full path? @@ -835,10 +882,12 @@ rescan: } // 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++) { - if (strcmp(namelist[i]->d_name, fname) == 0) { + char *dname = namelist[i]->d_name; + if (dname[0] == fname[0] && strcmp(dname, fname) == 0) { sel = i - 1; break; } @@ -847,20 +896,21 @@ rescan: /* make sure action buttons are not pressed on entering menu */ draw_dirlist(curr_path, namelist, n, sel); - while (in_menu_wait_any(50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU)) + 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, 33); + 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)) { again: @@ -884,9 +934,12 @@ rescan: { int newlen; char *p, *newdir; - if (!(inp & PBTN_MOK)) continue; + if (!(inp & PBTN_MOK)) + continue; newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2; newdir = malloc(newlen); + if (newdir == NULL) + break; if (strcmp(namelist[sel+1]->d_name, "..") == 0) { char *start = curr_path; p = start + strlen(start) - 1; @@ -932,12 +985,22 @@ rescan: free(namelist); } + // restore curr_path + if (fname != NULL) { + n = strlen(curr_path); + if (curr_path + n + 1 == fname) + curr_path[n] = '/'; + } + return ret; } // ------------ savestate loader ------------ +#define STATE_SLOT_COUNT 10 + static int state_slot_flags = 0; +static int state_slot_times[STATE_SLOT_COUNT]; static void state_check_slots(void) { @@ -945,8 +1008,9 @@ static void state_check_slots(void) state_slot_flags = 0; - for (slot = 0; slot < 10; slot++) { - if (emu_check_save_file(slot)) + for (slot = 0; slot < STATE_SLOT_COUNT; slot++) { + state_slot_times[slot] = 0; + if (emu_check_save_file(slot, &state_slot_times[slot])) state_slot_flags |= 1 << slot; } } @@ -956,28 +1020,44 @@ static void draw_savestate_bg(int slot); static void draw_savestate_menu(int menu_sel, int is_loading) { int i, x, y, w, h; + char time_buf[32]; if (state_slot_flags & (1 << menu_sel)) draw_savestate_bg(menu_sel); w = (13 + 2) * me_mfont_w; - h = (1+2+10+1) * me_mfont_h; + h = (1+2+STATE_SLOT_COUNT+1) * me_mfont_h; x = g_menuscreen_w / 2 - w / 2; if (x < 0) x = 0; y = g_menuscreen_h / 2 - h / 2; if (y < 0) y = 0; +#ifdef MENU_ALIGN_LEFT + if (x > 12 + me_mfont_w * 2) + x = 12 + me_mfont_w * 2; +#endif menu_draw_begin(1); text_out16(x, y, is_loading ? "Load state" : "Save state"); y += 3 * me_mfont_h; - menu_draw_selection(x - me_mfont_w * 2, y + menu_sel * me_mfont_h, (13 + 2) * me_mfont_w + 4); + menu_draw_selection(x - me_mfont_w * 2, y + menu_sel * me_mfont_h, (23 + 2) * me_mfont_w + 4); - /* draw all 10 slots */ - for (i = 0; i < 10; i++, y += me_mfont_h) + /* draw all slots */ + for (i = 0; i < STATE_SLOT_COUNT; i++, y += me_mfont_h) { - text_out16(x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free"); + if (!(state_slot_flags & (1 << i))) + strcpy(time_buf, "free"); + else { + strcpy(time_buf, "USED"); + if (state_slot_times[i] != 0) { + time_t time = state_slot_times[i]; + struct tm *t = localtime(&time); + strftime(time_buf, sizeof(time_buf), "%x %R", t); + } + } + + text_out16(x, y, "SLOT %i (%s)", i, time_buf); } text_out16(x, y, "back"); @@ -986,8 +1066,8 @@ static void draw_savestate_menu(int menu_sel, int is_loading) static int menu_loop_savestate(int is_loading) { - static int menu_sel = 10; - int menu_sel_max = 10; + static int menu_sel = STATE_SLOT_COUNT; + int menu_sel_max = STATE_SLOT_COUNT; unsigned long inp = 0; int ret = 0; @@ -999,7 +1079,7 @@ static int menu_loop_savestate(int is_loading) for (;;) { draw_savestate_menu(menu_sel, is_loading); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_MOK|PBTN_MBACK, 100); + inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_MOK|PBTN_MBACK, NULL, 100); if (inp & PBTN_UP) { do { menu_sel--; @@ -1015,7 +1095,7 @@ static int menu_loop_savestate(int is_loading) } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading); } if (inp & PBTN_MOK) { // save/load - if (menu_sel < 10) { + if (menu_sel < STATE_SLOT_COUNT) { state_slot = menu_sel; if (emu_save_load_game(is_loading, 0)) { me_update_msg(is_loading ? "Load failed" : "Save failed"); @@ -1037,18 +1117,11 @@ static int menu_loop_savestate(int is_loading) static char *action_binds(int player_idx, int action_mask, int dev_id) { - int k, count = 0, can_combo = 0, type; - const int *binds; + int dev = 0, dev_last = IN_MAX_DEVS - 1; + int can_combo = 1, type; static_buff[0] = 0; - binds = in_get_dev_binds(dev_id); - if (binds == NULL) - return static_buff; - - in_get_config(dev_id, IN_CFG_BIND_COUNT, &count); - in_get_config(dev_id, IN_CFG_DOES_COMBOS, &can_combo); - type = IN_BINDTYPE_EMU; if (player_idx >= 0) { can_combo = 0; @@ -1057,22 +1130,37 @@ static char *action_binds(int player_idx, int action_mask, int dev_id) if (player_idx == 1) action_mask <<= 16; - for (k = 0; k < count; k++) - { - const char *xname; - int len; + if (dev_id >= 0) + dev = dev_last = dev_id; + + for (; dev <= dev_last; dev++) { + int k, count = 0, combo = 0; + const int *binds; - if (!(binds[IN_BIND_OFFS(k, type)] & action_mask)) + binds = in_get_dev_binds(dev); + if (binds == NULL) continue; - xname = in_get_key_name(dev_id, k); - len = strlen(static_buff); - if (len) { - strncat(static_buff, can_combo ? " + " : ", ", - sizeof(static_buff) - len - 1); - len += can_combo ? 3 : 2; + in_get_config(dev, IN_CFG_BIND_COUNT, &count); + in_get_config(dev, IN_CFG_DOES_COMBOS, &combo); + combo = combo && can_combo; + + for (k = 0; k < count; k++) { + const char *xname; + int len; + + if (!(binds[IN_BIND_OFFS(k, type)] & action_mask)) + continue; + + xname = in_get_key_name(dev, k); + len = strlen(static_buff); + if (len) { + strncat(static_buff, combo ? " + " : ", ", + sizeof(static_buff) - len - 1); + len += combo ? 3 : 2; + } + strncat(static_buff, xname, sizeof(static_buff) - len - 1); } - strncat(static_buff, xname, sizeof(static_buff) - len - 1); } return static_buff; @@ -1124,7 +1212,10 @@ static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_ text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask, dev_id)); - dev_name = in_get_dev_name(dev_id, 1, 1); + if (dev_id < 0) + dev_name = "(all devices)"; + else + dev_name = in_get_dev_name(dev_id, 1, 1); w = strlen(dev_name) * me_mfont_w; if (w < 30 * me_mfont_w) w = 30 * me_mfont_w; @@ -1153,7 +1244,7 @@ static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx) { int i, sel = 0, menu_sel_max = opt_cnt - 1, does_combos = 0; - int dev_id, dev_count, kc, is_down, mkey; + int dev_id, bind_dev_id, dev_count, kc, is_down, mkey; int unbind, bindtype, mask_shift; for (i = 0, dev_id = -1, dev_count = 0; i < IN_MAX_DEVS; i++) { @@ -1169,6 +1260,7 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ return; } + dev_id = -1; // show all mask_shift = 0; if (player_idx == 1) mask_shift = 16; @@ -1177,23 +1269,24 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ for (;;) { draw_key_config(opts, opt_cnt, player_idx, sel, dev_id, dev_count, 0); - mkey = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_MBACK|PBTN_MOK|PBTN_MA2, 100); + mkey = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT + |PBTN_MBACK|PBTN_MOK|PBTN_MA2, NULL, 100); switch (mkey) { case PBTN_UP: sel--; if (sel < 0) sel = menu_sel_max; continue; case PBTN_DOWN: sel++; if (sel > menu_sel_max) sel = 0; continue; case PBTN_LEFT: - for (i = 0, dev_id--; i < IN_MAX_DEVS; i++, dev_id--) { - if (dev_id < 0) + for (i = 0, dev_id--; i < IN_MAX_DEVS + 1; i++, dev_id--) { + if (dev_id < -1) dev_id = IN_MAX_DEVS - 1; - if (in_get_dev_name(dev_id, 1, 0) != NULL) + if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL) break; } continue; case PBTN_RIGHT: for (i = 0, dev_id++; i < IN_MAX_DEVS; i++, dev_id++) { if (dev_id >= IN_MAX_DEVS) - dev_id = 0; - if (in_get_dev_name(dev_id, 1, 0) != NULL) + dev_id = -1; + if (dev_id == -1 || in_get_dev_name(dev_id, 1, 0) != NULL) break; } continue; @@ -1202,7 +1295,7 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ case PBTN_MOK: if (sel >= opt_cnt) return; - while (in_menu_wait_any(30) & PBTN_MOK) + while (in_menu_wait_any(NULL, 30) & PBTN_MOK) ; break; case PBTN_MA2: @@ -1215,20 +1308,20 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_ /* wait for some up event */ for (is_down = 1; is_down; ) - kc = in_update_keycode(&dev_id, &is_down, -1); + kc = in_update_keycode(&bind_dev_id, &is_down, NULL, -1); - i = count_bound_keys(dev_id, opts[sel].mask << mask_shift, bindtype); + i = count_bound_keys(bind_dev_id, opts[sel].mask << mask_shift, bindtype); unbind = (i > 0); /* allow combos if device supports them */ - in_get_config(dev_id, IN_CFG_DOES_COMBOS, &does_combos); + in_get_config(bind_dev_id, IN_CFG_DOES_COMBOS, &does_combos); if (i == 1 && bindtype == IN_BINDTYPE_EMU && does_combos) unbind = 0; if (unbind) - in_unbind_all(dev_id, opts[sel].mask << mask_shift, bindtype); + in_unbind_all(bind_dev_id, opts[sel].mask << mask_shift, bindtype); - in_bind_key(dev_id, kc, opts[sel].mask << mask_shift, bindtype, 0); + in_bind_key(bind_dev_id, kc, opts[sel].mask << mask_shift, bindtype, 0); } }