center loaded background image in larger screen
[libpicofe.git] / menu.c
diff --git a/menu.c b/menu.c
index bf5c864..e91f84a 100644 (file)
--- a/menu.c
+++ b/menu.c
 #include "plat.h"\r
 #include "posix.h"\r
 \r
+#if defined(__GNUC__) && __GNUC__ >= 7\r
+#pragma GCC diagnostic ignored "-Wformat-truncation"\r
+#endif\r
+\r
 static char static_buff[64];\r
 static int  menu_error_time = 0;\r
 char menu_error_msg[64] = { 0, };\r
+// g_menuscreen is the current output buffer the menu is rendered to.\r
 void *g_menuscreen_ptr;\r
-void *g_menubg_src_ptr;\r
+// g_menubg is the menu background and has the same w/h as g_menuscreen, but\r
+// pp=w. It is filled on menu entry from file or from g_menubg_src if available.\r
 void *g_menubg_ptr;\r
+// g_menubg_src points to a buffer containing a bg image. This is usually either\r
+// the emulator screen buffer or the host frame buffer.\r
+void *g_menubg_src_ptr;\r
 \r
 int g_menuscreen_w;\r
 int g_menuscreen_h;\r
 int g_menuscreen_pp;\r
+int g_menubg_src_w;\r
+int g_menubg_src_h;\r
+int g_menubg_src_pp;\r
 \r
 int g_autostateld_opt;\r
 \r
@@ -264,14 +276,14 @@ void menu_init_base(void)
                for (l = 0; l < 8; l++)\r
                {\r
                        unsigned char fd8x8 = fontdata8x8[c*8+l];\r
-                       if (fd8x8&0x80) *fd  = 0xf0;\r
-                       if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x20) *fd  = 0xf0;\r
-                       if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x08) *fd  = 0xf0;\r
-                       if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
-                       if (fd8x8&0x02) *fd  = 0xf0;\r
-                       if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
+                       if (fd8x8&0x80) { *fd  = 0xf0; }\r
+                       if (fd8x8&0x40) { *fd |= 0x0f; }; fd++;\r
+                       if (fd8x8&0x20) { *fd  = 0xf0; }\r
+                       if (fd8x8&0x10) { *fd |= 0x0f; }; fd++;\r
+                       if (fd8x8&0x08) { *fd  = 0xf0; }\r
+                       if (fd8x8&0x04) { *fd |= 0x0f; }; fd++;\r
+                       if (fd8x8&0x02) { *fd  = 0xf0; }\r
+                       if (fd8x8&0x01) { *fd |= 0x0f; }; fd++;\r
                }\r
                fd += 8*2/2; // 2 empty lines\r
        }\r
@@ -429,12 +441,12 @@ static void menu_draw_begin(int need_bg, int no_borders)
                if (g_border_style && no_borders) {\r
                        for (y = 0; y < g_menuscreen_h; y++)\r
                                menu_darken_bg((short *)g_menuscreen_ptr + g_menuscreen_pp * y,\r
-                                       g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w, 1);\r
+                                       (short *)g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w, 1);\r
                }\r
                else {\r
                        for (y = 0; y < g_menuscreen_h; y++)\r
                                memcpy((short *)g_menuscreen_ptr + g_menuscreen_pp * y,\r
-                                       g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w * 2);\r
+                                       (short *)g_menubg_ptr + g_menuscreen_w * y, g_menuscreen_w * 2);\r
                }\r
        }\r
 }\r
@@ -875,7 +887,6 @@ static void draw_dirlist(char *curdir, struct dirent **namelist,
 \r
        max_cnt = g_menuscreen_h / me_sfont_h;\r
        start = max_cnt / 2 - sel;\r
-       n--; // exclude current dir (".")\r
 \r
        menu_draw_begin(1, 1);\r
 \r
@@ -892,12 +903,12 @@ static void draw_dirlist(char *curdir, struct dirent **namelist,
                pos = start + i;\r
                if (pos < 0)  continue;\r
                if (pos >= max_cnt) break;\r
-               if (namelist[i+1]->d_type == DT_DIR) {\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+1]->d_name, 0xfff6);\r
+                       smalltext_out16(x + me_sfont_w, pos * me_sfont_h, namelist[i]->d_name, 0xfff6);\r
                } else {\r
-                       unsigned short color = fname2color(namelist[i+1]->d_name);\r
-                       smalltext_out16(x, pos * me_sfont_h, namelist[i+1]->d_name, color);\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
@@ -930,10 +941,15 @@ static int scandir_cmp(const void *p1, const void *p2)
 {\r
        const struct dirent **d1 = (const struct dirent **)p1;\r
        const struct dirent **d2 = (const struct dirent **)p2;\r
+       const char *p;\r
+       if ((p = (*d1)->d_name)[0] == '.' && p[1] == '.' && p[2] == 0)\r
+               return -1;      // ".." first\r
+       if ((p = (*d2)->d_name)[0] == '.' && p[1] == '.' && p[2] == 0)\r
+               return 1;\r
        if ((*d1)->d_type == (*d2)->d_type)\r
                return alphasort(d1, d2);\r
        if ((*d1)->d_type == DT_DIR)\r
-               return -1; // put before\r
+               return -1;      // directories before files/links\r
        if ((*d2)->d_type == DT_DIR)\r
                return  1;\r
 \r
@@ -953,7 +969,8 @@ static int scandir_filter(const struct dirent *ent)
 \r
        switch (ent->d_type) {\r
        case DT_DIR:\r
-               return 1;\r
+               // leave out useless reference to current directory\r
+               return strcmp(ent->d_name, ".") != 0;\r
        case DT_LNK:\r
        case DT_UNKNOWN:\r
                // could be a dir, deal with it later..\r
@@ -1002,7 +1019,6 @@ static const char *menu_loop_romsel(char *curr_path, int len,
        int n = 0, inp = 0, sel = 0, show_help = 0;\r
        char *curr_path_restore = NULL;\r
        const char *ret = NULL;\r
-       int changed;\r
        char cinp;\r
        int r, i;\r
 \r
@@ -1036,13 +1052,10 @@ rescan:
 \r
        n = scandir(curr_path, &namelist, filter, (void *)scandir_cmp);\r
        if (n < 0) {\r
-               char *t;\r
                lprintf("menu_loop_romsel failed, dir: %s\n", curr_path);\r
 \r
-               // try root\r
-               t = getcwd(curr_path, len);\r
-               if (t == NULL)\r
-                       plat_get_root_dir(curr_path, len);\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
                        // oops, we failed\r
@@ -1052,43 +1065,40 @@ rescan:
        }\r
 \r
        // try to resolve DT_UNKNOWN and symlinks\r
-       changed = 0;\r
        for (i = 0; i < n; i++) {\r
                struct stat st;\r
+               char *slash;\r
 \r
                if (namelist[i]->d_type == DT_REG || namelist[i]->d_type == DT_DIR)\r
                        continue;\r
 \r
+               r = strlen(curr_path);\r
+               slash = (r && curr_path[r-1] == '/') ? "" : "/";\r
                snprintf(rom_fname_reload, sizeof(rom_fname_reload),\r
-                       "%s/%s", curr_path, namelist[i]->d_name);\r
+                       "%s%s%s", curr_path, slash, namelist[i]->d_name);\r
                r = stat(rom_fname_reload, &st);\r
                if (r == 0)\r
                {\r
-                       if (S_ISREG(st.st_mode)) {\r
+                       if (S_ISREG(st.st_mode))\r
                                namelist[i]->d_type = DT_REG;\r
-                               changed = 1;\r
-                       }\r
-                       else if (S_ISDIR(st.st_mode)) {\r
+                       else if (S_ISDIR(st.st_mode))\r
                                namelist[i]->d_type = DT_DIR;\r
-                               changed = 1;\r
-                       }\r
                }\r
        }\r
 \r
        if (!g_menu_filter_off && extra_filter != NULL)\r
                n = extra_filter(namelist, n, curr_path);\r
 \r
-       if (n > 1 && changed)\r
+       if (n > 1)\r
                qsort(namelist, n, sizeof(namelist[0]), scandir_cmp);\r
 \r
        // try to find selected file\r
-       // note: we don't show '.' so sel is namelist index - 1\r
        sel = 0;\r
        if (sel_fname[0] != 0) {\r
-               for (i = 1; i < n; i++) {\r
+               for (i = 0; i < n; i++) {\r
                        char *dname = namelist[i]->d_name;\r
                        if (dname[0] == sel_fname[0] && strcmp(dname, sel_fname) == 0) {\r
-                               sel = i - 1;\r
+                               sel = i;\r
                                break;\r
                        }\r
                }\r
@@ -1108,52 +1118,54 @@ rescan:
                if (inp & PBTN_MA3)   {\r
                        g_menu_filter_off = !g_menu_filter_off;\r
                        snprintf(sel_fname, sizeof(sel_fname), "%s",\r
-                               namelist[sel+1]->d_name);\r
+                               namelist[sel]->d_name);\r
                        goto rescan;\r
                }\r
-               if (inp & PBTN_UP  )  { sel--;   if (sel < 0)   sel = n-2; }\r
-               if (inp & PBTN_DOWN)  { sel++;   if (sel > n-2) sel = 0; }\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-2) sel = n-2; }\r
-               if (inp & PBTN_R)     { sel+=24; if (sel > n-2) sel = n-2; }\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
                {\r
-                       if (namelist[sel+1]->d_type == DT_REG)\r
+                       if (namelist[sel]->d_type == DT_REG)\r
                        {\r
+                               int l = strlen(curr_path);\r
+                               char *slash = l && curr_path[l-1] == '/' ? "" : "/";\r
                                snprintf(rom_fname_reload, sizeof(rom_fname_reload),\r
-                                       "%s/%s", curr_path, namelist[sel+1]->d_name);\r
+                                       "%s%s%s", curr_path, slash, namelist[sel]->d_name);\r
                                if (inp & PBTN_MOK) { // return sel\r
                                        ret = rom_fname_reload;\r
                                        break;\r
                                }\r
-                               do_delete(rom_fname_reload, namelist[sel+1]->d_name);\r
+                               do_delete(rom_fname_reload, namelist[sel]->d_name);\r
                                goto rescan;\r
                        }\r
-                       else if (namelist[sel+1]->d_type == DT_DIR)\r
+                       else if (namelist[sel]->d_type == DT_DIR)\r
                        {\r
                                int newlen;\r
                                char *p, *newdir;\r
                                if (!(inp & PBTN_MOK))\r
                                        continue;\r
-                               newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
+                               newlen = strlen(curr_path) + strlen(namelist[sel]->d_name) + 2;\r
                                newdir = malloc(newlen);\r
                                if (newdir == NULL)\r
                                        break;\r
-                               if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
+                               if (strcmp(namelist[sel]->d_name, "..") == 0) {\r
                                        char *start = curr_path;\r
                                        p = start + strlen(start) - 1;\r
                                        while (*p == '/' && p > start) p--;\r
                                        while (*p != '/' && p > start) p--;\r
-                                       if (p <= start) strcpy(newdir, "/");\r
+                                       if (p <= start) plat_get_data_dir(newdir, newlen);\r
                                        else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
                                } else {\r
                                        strcpy(newdir, curr_path);\r
                                        p = newdir + strlen(newdir) - 1;\r
                                        while (*p == '/' && p >= newdir) *p-- = 0;\r
                                        strcat(newdir, "/");\r
-                                       strcat(newdir, namelist[sel+1]->d_name);\r
+                                       strcat(newdir, namelist[sel]->d_name);\r
                                }\r
                                ret = menu_loop_romsel(newdir, newlen, filter_exts, extra_filter);\r
                                free(newdir);\r