in_sdl: give names to gamepad buttons
[libpicofe.git] / menu.c
diff --git a/menu.c b/menu.c
index 6c6392a..27c72bf 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -55,11 +55,11 @@ static int menu_sel_color = -1; // disabled
 \r
 /* note: these might become non-constant in future */\r
 #if MENU_X2\r
-static const int me_mfont_w = 16, me_mfont_h = 20;\r
-static const int me_sfont_w = 12, me_sfont_h = 20;\r
+const int me_mfont_w = 16, me_mfont_h = 20;\r
+const int me_sfont_w = 12, me_sfont_h = 20;\r
 #else\r
-static const int me_mfont_w = 8, me_mfont_h = 10;\r
-static const int me_sfont_w = 6, me_sfont_h = 10;\r
+const int me_mfont_w = 8, me_mfont_h = 10;\r
+const int me_sfont_w = 6, me_sfont_h = 10;\r
 #endif\r
 \r
 static int g_menu_filter_off;\r
@@ -77,9 +77,9 @@ static void text_out16_(int x, int y, const char *text, int color)
 {\r
        int i, lh, tr, tg, tb, len;\r
        unsigned short *dest = (unsigned short *)g_menuscreen_ptr + x + y * g_menuscreen_pp;\r
-       tr = (color & 0xf800) >> 8;\r
-       tg = (color & 0x07e0) >> 3;\r
-       tb = (color & 0x001f) << 3;\r
+       tr = PXGETR(color);\r
+       tg = PXGETG(color);\r
+       tb = PXGETB(color);\r
 \r
        if (text == (void *)1)\r
        {\r
@@ -111,21 +111,21 @@ static void text_out16_(int x, int y, const char *text, int color)
                        {\r
                                int c, r, g, b;\r
                                c = *src >> 4;\r
-                               r = (*dst & 0xf800) >> 8;\r
-                               g = (*dst & 0x07e0) >> 3;\r
-                               b = (*dst & 0x001f) << 3;\r
+                               r = PXGETR(*dst);\r
+                               g = PXGETG(*dst);\r
+                               b = PXGETB(*dst);\r
                                r = (c^0xf)*r/15 + c*tr/15;\r
                                g = (c^0xf)*g/15 + c*tg/15;\r
                                b = (c^0xf)*b/15 + c*tb/15;\r
-                               *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
+                               *dst++ = PXMAKE(r, g, b);\r
                                c = *src & 0xf;\r
-                               r = (*dst & 0xf800) >> 8;\r
-                               g = (*dst & 0x07e0) >> 3;\r
-                               b = (*dst & 0x001f) << 3;\r
+                               r = PXGETR(*dst);\r
+                               g = PXGETG(*dst);\r
+                               b = PXGETB(*dst);\r
                                r = (c^0xf)*r/15 + c*tr/15;\r
                                g = (c^0xf)*g/15 + c*tg/15;\r
                                b = (c^0xf)*b/15 + c*tb/15;\r
-                               *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
+                               *dst++ = PXMAKE(r, g, b);\r
                        }\r
                }\r
                dest += me_mfont_w;\r
@@ -200,17 +200,17 @@ static void smalltext_out16_(int x, int y, const char *texto, int color)
        }\r
 }\r
 \r
-static void smalltext_out16(int x, int y, const char *texto, int color)\r
+void smalltext_out16(int x, int y, const char *texto, int color)\r
 {\r
        char buffer[128];\r
        int maxw = (g_menuscreen_w - x) / me_sfont_w;\r
 \r
        if (maxw < 0)\r
                return;\r
-\r
-       strncpy(buffer, texto, sizeof(buffer));\r
        if (maxw > sizeof(buffer) - 1)\r
                maxw = sizeof(buffer) - 1;\r
+\r
+       strncpy(buffer, texto, maxw);\r
        buffer[maxw] = 0;\r
 \r
        smalltext_out16_(x, y, buffer, color);\r
@@ -241,11 +241,7 @@ static int parse_hex_color(char *buff)
        char *endp = buff;\r
        int t = (int) strtoul(buff, &endp, 16);\r
        if (endp != buff)\r
-#ifdef PSP\r
-               return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r
-#else\r
-               return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
-#endif\r
+               return PXMAKE((t>>16)&0xff, (t>>8)&0xff,t&0xff);\r
        return -1;\r
 }\r
 \r
@@ -367,7 +363,7 @@ static void menu_darken_bg(void *dst, void *src, int pixels, int darker)
                while (pixels--)\r
                {\r
                        unsigned int p = *sorc++;\r
-                       *dest++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
+                       *dest++ = (PXMASKH(p,1)>>1) - (PXMASKH(p,3)>>3);\r
                }\r
        }\r
        else\r
@@ -375,7 +371,7 @@ static void menu_darken_bg(void *dst, void *src, int pixels, int darker)
                while (pixels--)\r
                {\r
                        unsigned int p = *sorc++;\r
-                       *dest++ = (p&0xf79ef79e)>>1;\r
+                       *dest++ = (PXMASKH(p,1)>>1);\r
                }\r
        }\r
 }\r
@@ -400,7 +396,7 @@ static void menu_darken_text_bg(void)
                ymax = g_menuscreen_h - 1;\r
 \r
        for (x = xmin; x <= xmax; x++)\r
-               screen[y * g_menuscreen_pp + x] = 0xa514;\r
+               screen[y * g_menuscreen_pp + x] = PXMAKE(0xa0, 0xa0, 0xa0);\r
        for (y++; y < ymax; y++)\r
        {\r
                ls = y * g_menuscreen_pp;\r
@@ -409,7 +405,7 @@ static void menu_darken_text_bg(void)
                {\r
                        unsigned int p = screen[ls + x];\r
                        if (p != menu_text_color)\r
-                               screen[ls + x] = ((p&0xf79e)>>1) - ((p&0xc618)>>3);\r
+                               screen[ls + x] = (PXMASKH(p,1)>>1) - (PXMASKH(p,3)>>3);\r
                }\r
                screen[ls + xmax] = 0xffff;\r
        }\r
@@ -479,7 +475,7 @@ static int me_id2offset(const menu_entry *ent, menu_id id)
 static void me_enable(menu_entry *entries, menu_id id, int enable)\r
 {\r
        int i = me_id2offset(entries, id);\r
-       entries[i].enabled = enable;\r
+       entries[i].enabled = !!enable;\r
 }\r
 \r
 static int me_count(const menu_entry *ent)\r
@@ -601,7 +597,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void))
                                name = ent->generate_name(ent->id, &offs);\r
                }\r
                if (name != NULL) {\r
-                       text_out16(x, y, name);\r
+                       text_out16(x, y, "%s", name);\r
                        leftname_end = x + (strlen(name) + 1) * me_mfont_w;\r
                }\r
 \r
@@ -609,7 +605,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void))
                case MB_NONE:\r
                        break;\r
                case MB_OPT_ONOFF:\r
-                       text_out16(x + col2_offs, y, me_read_onoff(ent) ? "ON" : "OFF");\r
+                       text_out16(x + col2_offs, y, "%s", me_read_onoff(ent) ? "ON" : "OFF");\r
                        break;\r
                case MB_OPT_RANGE:\r
                        text_out16(x + col2_offs, y, "%i", *(int *)ent->var);\r
@@ -650,7 +646,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void))
        h = (g_menuscreen_h - h) / 2; // bottom area height\r
        if (menu_error_msg[0] != 0) {\r
                if (h >= me_mfont_h + 4)\r
-                       text_out16(5, g_menuscreen_h - me_mfont_h - 4, menu_error_msg);\r
+                       text_out16(5, g_menuscreen_h - me_mfont_h - 4, "%s", menu_error_msg);\r
                else\r
                        lprintf("menu msg doesn't fit!\n");\r
 \r
@@ -664,7 +660,7 @@ static void me_draw(const menu_entry *entries, int sel, void (*draw_more)(void))
                        tmp = strchr(tmp + 1, '\n');\r
                if (h >= l * me_sfont_h + 4)\r
                        for (tmp = ent_sel->help; l > 0; l--, tmp = strchr(tmp, '\n') + 1)\r
-                               smalltext_out16(5, g_menuscreen_h - (l * me_sfont_h + 4), tmp, 0xffff);\r
+                               smalltext_out16(5, g_menuscreen_h - (l * me_sfont_h + 4), tmp, PXMAKE(0xff, 0xff, 0xff));\r
        }\r
 \r
        menu_separation();\r
@@ -813,7 +809,7 @@ static void draw_menu_message(const char *msg, void (*draw_more)(void))
        menu_draw_begin(1, 0);\r
 \r
        for (p = msg; *p != 0 && y <= g_menuscreen_h - me_mfont_h; y += me_mfont_h) {\r
-               text_out16(x, y, p);\r
+               text_out16(x, y, "%s", p);\r
 \r
                for (; *p != 0 && *p != '\n'; p++)\r
                        ;\r
@@ -845,7 +841,7 @@ static void do_delete(const char *fpath, const char *fname)
 \r
        mid = g_menuscreen_w / 2;\r
        text_out16(mid - me_mfont_w * 15 / 2,  8 * me_mfont_h, "About to delete");\r
-       smalltext_out16(mid - len * me_sfont_w / 2, 9 * me_mfont_h + 5, fname, 0xbdff);\r
+       smalltext_out16(mid - len * me_sfont_w / 2, 9 * me_mfont_h + 5, fname, PXMAKE(0xbf, 0xbf, 0xff));\r
        text_out16(mid - me_mfont_w * 13 / 2, 11 * me_mfont_h, "Are you sure?");\r
 \r
        nm = in_get_key_name(-1, -PBTN_MA3);\r
@@ -855,7 +851,7 @@ static void do_delete(const char *fpath, const char *fname)
        snprintf(tmp + len, sizeof(tmp) - len, "%s - cancel)", nm);\r
        len = strlen(tmp);\r
 \r
-       text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, tmp);\r
+       text_out16(mid - me_mfont_w * len / 2, 12 * me_mfont_h, "%s", tmp);\r
        menu_draw_end();\r
 \r
        while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MA2));\r
@@ -886,20 +882,20 @@ static void draw_dirlist(char *curdir, struct dirent **namelist,
 \r
        x = 5 + me_mfont_w + 1;\r
        if (start - 2 >= 0)\r
-               smalltext_out16(14, (start - 2) * me_sfont_h, curdir, 0xffff);\r
+               smalltext_out16(14, (start - 2) * me_sfont_h, curdir, PXMAKE(0xff, 0xff, 0xff));\r
        for (i = 0; i < n; i++) {\r
                pos = start + i;\r
                if (pos < 0)  continue;\r
                if (pos >= max_cnt) break;\r
                if (namelist[i]->d_type == DT_DIR) {\r
-                       smalltext_out16(x, pos * me_sfont_h, "/", 0xfff6);\r
-                       smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i]->d_name, 0xfff6);\r
+                       smalltext_out16(x, pos * me_sfont_h, "/", PXMAKE(0xff, 0xff, 0xb0));\r
+                       smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i]->d_name, PXMAKE(0xff, 0xff, 0xb0));\r
                } else {\r
                        unsigned short color = fname2color(namelist[i]->d_name);\r
                        smalltext_out16(x, pos * me_sfont_h, namelist[i]->d_name, color);\r
                }\r
        }\r
-       smalltext_out16(5, max_cnt/2 * me_sfont_h, ">", 0xffff);\r
+       smalltext_out16(5, max_cnt/2 * me_sfont_h, ">", PXMAKE(0xff, 0xff, 0xff));\r
 \r
        if (show_help) {\r
                darken_ptr = (short *)g_menuscreen_ptr\r
@@ -909,17 +905,17 @@ static void draw_dirlist(char *curdir, struct dirent **namelist,
 \r
                snprintf(buff, sizeof(buff), "%s - select, %s - back",\r
                        in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));\r
-               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 3 - 2, buff, 0xe78c);\r
+               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 3 - 2, buff, PXMAKE(0xe0, 0xf0, 0x60));\r
 \r
                snprintf(buff, sizeof(buff), g_menu_filter_off ?\r
                         "%s - hide unknown files" : "%s - show all files",\r
                        in_get_key_name(-1, -PBTN_MA3));\r
-               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 2 - 2, buff, 0xe78c);\r
+               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 2 - 2, buff, PXMAKE(0xe0, 0xf0, 0x60));\r
 \r
                snprintf(buff, sizeof(buff), g_autostateld_opt ?\r
                         "%s - autoload save is ON" : "%s - autoload save is OFF",\r
                        in_get_key_name(-1, -PBTN_MA2));\r
-               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 1 - 2, buff, 0xe78c);\r
+               smalltext_out16(x, g_menuscreen_h - me_sfont_h * 1 - 2, buff, PXMAKE(0xe0, 0xf0, 0x60));\r
        }\r
 \r
        menu_draw_end();\r
@@ -981,10 +977,9 @@ static int dirent_seek_char(struct dirent **namelist, int len, int sel, char c)
 {\r
        int i;\r
 \r
-       sel++;\r
        for (i = sel + 1; ; i++) {\r
                if (i >= len)\r
-                       i = 1;\r
+                       i = 0;\r
                if (i == sel)\r
                        break;\r
 \r
@@ -992,13 +987,14 @@ static int dirent_seek_char(struct dirent **namelist, int len, int sel, char c)
                        break;\r
        }\r
 \r
-       return i - 1;\r
+       return i;\r
 }\r
 \r
-static const char *menu_loop_romsel(char *curr_path, int len,\r
+static const char *menu_loop_romsel_d(char *curr_path, int len,\r
        const char **filter_exts,\r
        int (*extra_filter)(struct dirent **namelist, int count,\r
-                           const char *basedir))\r
+                           const char *basedir),\r
+       void (*draw_prep)(void))\r
 {\r
        static char rom_fname_reload[256]; // used for scratch and return\r
        char sel_fname[256];\r
@@ -1021,13 +1017,12 @@ static const char *menu_loop_romsel(char *curr_path, int len,
                        curr_path_restore = p;\r
                        snprintf(sel_fname, sizeof(sel_fname), "%s", p + 1);\r
                }\r
-\r
-               if (rom_fname_reload[0] == 0)\r
-                       show_help = 2;\r
        }\r
+       show_help = 2;\r
 \r
 rescan:\r
        if (namelist != NULL) {\r
+               n += !n;\r
                while (n-- > 0)\r
                        free(namelist[n]);\r
                free(namelist);\r
@@ -1039,16 +1034,17 @@ rescan:
                filter = scandir_filter;\r
 \r
        n = scandir(curr_path, &namelist, filter, (void *)scandir_cmp);\r
-       if (n < 0) {\r
+       if (n < 0 || !namelist) {\r
                lprintf("menu_loop_romsel failed, dir: %s\n", curr_path);\r
 \r
                // try data root\r
                plat_get_data_dir(curr_path, len);\r
                n = scandir(curr_path, &namelist, filter, (void *)scandir_cmp);\r
-               if (n < 0) {\r
+               if (n < 0 || !namelist) {\r
                        // oops, we failed\r
                        lprintf("menu_loop_romsel failed, dir: %s\n", curr_path);\r
-                       return NULL;\r
+                       namelist = malloc(sizeof(*namelist));\r
+                       namelist[0] = calloc(1, sizeof(**namelist));\r
                }\r
        }\r
 \r
@@ -1080,6 +1076,16 @@ rescan:
        if (n > 1)\r
                qsort(namelist, n, sizeof(namelist[0]), scandir_cmp);\r
 \r
+       // add ".." if it's somehow not there\r
+       if (n == 0 || strcmp(namelist[0]->d_name, "..")) {\r
+               struct dirent *dotdot = malloc(sizeof(*dotdot));\r
+               *dotdot = (struct dirent) { .d_name="..", .d_type=DT_DIR };\r
+               namelist = realloc(namelist, (n+1)*sizeof(*namelist));\r
+               memmove(namelist+1, namelist, n*sizeof(*namelist));\r
+               namelist[0] = dotdot;\r
+               n++;\r
+       }\r
+\r
        // try to find selected file\r
        sel = 0;\r
        if (sel_fname[0] != 0) {\r
@@ -1099,6 +1105,8 @@ rescan:
 \r
        for (;;)\r
        {\r
+               if (draw_prep != NULL)\r
+                       draw_prep();\r
                draw_dirlist(curr_path, namelist, n, sel, show_help);\r
                inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT\r
                        | PBTN_L|PBTN_R|PBTN_MA2|PBTN_MA3|PBTN_MOK|PBTN_MBACK\r
@@ -1107,16 +1115,18 @@ rescan:
                        g_menu_filter_off = !g_menu_filter_off;\r
                        snprintf(sel_fname, sizeof(sel_fname), "%s",\r
                                namelist[sel]->d_name);\r
+                       show_help = 2;\r
                        goto rescan;\r
                }\r
-               if (inp & PBTN_UP  )  { sel--;   if (sel < 0)   sel = n-1; }\r
-               if (inp & PBTN_DOWN)  { sel++;   if (sel > n-1) sel = 0; }\r
-               if (inp & PBTN_LEFT)  { sel-=10; if (sel < 0)   sel = 0; }\r
-               if (inp & PBTN_L)     { sel-=24; if (sel < 0)   sel = 0; }\r
-               if (inp & PBTN_RIGHT) { sel+=10; if (sel > n-1) sel = n-1; }\r
-               if (inp & PBTN_R)     { sel+=24; if (sel > n-1) sel = n-1; }\r
-\r
-               if ((inp & PBTN_MOK) || (inp & (PBTN_MENU|PBTN_MA2)) == (PBTN_MENU|PBTN_MA2))\r
+               int last = n ? n-1 : 0;\r
+               if      (inp & PBTN_UP  )  { sel--;   if (sel < 0)   sel = last; }\r
+               else if (inp & PBTN_DOWN)  { sel++;   if (sel > n-1) sel = 0; }\r
+               else if (inp & PBTN_LEFT)  { sel-=10; if (sel < 0)   sel = 0; }\r
+               else if (inp & PBTN_RIGHT) { sel+=10; if (sel > n-1) sel = last; }\r
+               else if (inp & PBTN_L)     { sel-=24; if (sel < 0)   sel = 0; }\r
+               else if (inp & PBTN_R)     { sel+=24; if (sel > n-1) sel = last; }\r
+\r
+               else if ((inp & PBTN_MOK) || (inp & (PBTN_MENU|PBTN_MA2)) == (PBTN_MENU|PBTN_MA2))\r
                {\r
                        if (namelist[sel]->d_type == DT_REG)\r
                        {\r
@@ -1151,11 +1161,11 @@ rescan:
                                } else {\r
                                        strcpy(newdir, curr_path);\r
                                        p = newdir + strlen(newdir) - 1;\r
-                                       while (*p == '/' && p >= newdir) *p-- = 0;\r
+                                       while (p >= newdir && *p == '/') *p-- = 0;\r
                                        strcat(newdir, "/");\r
                                        strcat(newdir, namelist[sel]->d_name);\r
                                }\r
-                               ret = menu_loop_romsel(newdir, newlen, filter_exts, extra_filter);\r
+                               ret = menu_loop_romsel_d(newdir, newlen, filter_exts, extra_filter, draw_prep);\r
                                free(newdir);\r
                                break;\r
                        }\r
@@ -1189,6 +1199,14 @@ rescan:
        return ret;\r
 }\r
 \r
+static const char *menu_loop_romsel(char *curr_path, int len,\r
+       const char **filter_exts,\r
+       int (*extra_filter)(struct dirent **namelist, int count,\r
+                           const char *basedir))\r
+{\r
+       return menu_loop_romsel_d(curr_path, len, filter_exts, extra_filter, NULL);\r
+}\r
+\r
 // ------------ savestate loader ------------\r
 \r
 #define STATE_SLOT_COUNT 10\r
@@ -1319,10 +1337,10 @@ static char *action_binds(int player_idx, int action_mask, int dev_id)
        type = IN_BINDTYPE_EMU;\r
        if (player_idx >= 0) {\r
                can_combo = 0;\r
-               type = IN_BINDTYPE_PLAYER12;\r
+               type = IN_BINDTYPE_PLAYER12 + (player_idx >> 1);\r
+               if (player_idx & 1)\r
+                       action_mask <<= 16;\r
        }\r
-       if (player_idx == 1)\r
-               action_mask <<= 16;\r
 \r
        if (dev_id >= 0)\r
                dev = dev_last = dev_id;\r
@@ -1425,13 +1443,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));\r
                snprintf(buff, sizeof(buff), "%s - bind, %s - clear", buff2,\r
                                in_get_key_name(-1, -PBTN_MA2));\r
-               text_out16(x, g_menuscreen_h - 4 * me_mfont_h, buff);\r
+               text_out16(x, g_menuscreen_h - 4 * me_mfont_h, "%s", buff);\r
        }\r
        else\r
                text_out16(x, g_menuscreen_h - 4 * me_mfont_h, "Press a button to bind/unbind");\r
 \r
        if (dev_count > 1) {\r
-               text_out16(x, g_menuscreen_h - 3 * me_mfont_h, dev_name);\r
+               text_out16(x, g_menuscreen_h - 3 * me_mfont_h, "%s", dev_name);\r
                text_out16(x, g_menuscreen_h - 2 * me_mfont_h, "Press left/right for other devs");\r
        }\r
 \r
@@ -1459,9 +1477,12 @@ static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_
 \r
        dev_id = -1; // show all\r
        mask_shift = 0;\r
-       if (player_idx == 1)\r
-               mask_shift = 16;\r
-       bindtype = player_idx >= 0 ? IN_BINDTYPE_PLAYER12 : IN_BINDTYPE_EMU;\r
+       if (player_idx >= 0) {\r
+               if (player_idx & 1)\r
+                       mask_shift = 16;\r
+               bindtype = IN_BINDTYPE_PLAYER12 + (player_idx >> 1);\r
+       } else\r
+               bindtype = IN_BINDTYPE_EMU;\r
 \r
        for (;;)\r
        {\r