diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index c3a90c9208..bdf6aececb 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -39,18 +39,20 @@ #endif #include "../../screenshot.h" +#include "../../gfx/fonts/bitmap.h" #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) #define HAVE_SHADER_MANAGER #endif -unsigned RGUI_WIDTH = 320; -unsigned RGUI_HEIGHT = 240; -uint16_t menu_framebuf[400 * 240]; +static unsigned RGUI_WIDTH = 320; +static unsigned RGUI_HEIGHT = 240; +static uint16_t menu_framebuf[400 * 240]; -#ifdef HAVE_SHADER_MANAGER -static int shader_manager_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action); -#endif +#define TERM_START_X 15 +#define TERM_START_Y 27 +#define TERM_WIDTH (((RGUI_WIDTH - TERM_START_X - 15) / (FONT_WIDTH_STRIDE))) +#define TERM_HEIGHT (((RGUI_HEIGHT - TERM_START_Y - 15) / (FONT_HEIGHT_STRIDE)) - 1) static void rgui_flush_menu_stack_type(rgui_handle_t *rgui, unsigned final_type) { @@ -64,7 +66,468 @@ static void rgui_flush_menu_stack_type(rgui_handle_t *rgui, unsigned final_type) } } -#include "rguidisp.c" +static void rgui_copy_glyph(uint8_t *glyph, const uint8_t *buf) +{ + int y, x; + for (y = 0; y < FONT_HEIGHT; y++) + { + for (x = 0; x < FONT_WIDTH; x++) + { + uint32_t col = + ((uint32_t)buf[3 * (-y * 256 + x) + 0] << 0) | + ((uint32_t)buf[3 * (-y * 256 + x) + 1] << 8) | + ((uint32_t)buf[3 * (-y * 256 + x) + 2] << 16); + + uint8_t rem = 1 << ((x + y * FONT_WIDTH) & 7); + unsigned offset = (x + y * FONT_WIDTH) >> 3; + + if (col != 0xff) + glyph[offset] |= rem; + } + } +} + +static uint16_t gray_filler(unsigned x, unsigned y) +{ + x >>= 1; + y >>= 1; + unsigned col = ((x + y) & 1) + 1; +#ifdef GEKKO + return (6 << 12) | (col << 8) | (col << 4) | (col << 0); +#else + return (col << 13) | (col << 9) | (col << 5) | (12 << 0); +#endif +} + +static uint16_t green_filler(unsigned x, unsigned y) +{ + x >>= 1; + y >>= 1; + unsigned col = ((x + y) & 1) + 1; +#ifdef GEKKO + return (6 << 12) | (col << 8) | (col << 5) | (col << 0); +#else + return (col << 13) | (col << 10) | (col << 5) | (12 << 0); +#endif +} + +static void fill_rect(uint16_t *buf, unsigned pitch, + unsigned x, unsigned y, + unsigned width, unsigned height, + uint16_t (*col)(unsigned x, unsigned y)) +{ + unsigned j, i; + for (j = y; j < y + height; j++) + for (i = x; i < x + width; i++) + buf[j * (pitch >> 1) + i] = col(i, j); +} + +static void blit_line(rgui_handle_t *rgui, + int x, int y, const char *message, bool green) +{ + int j, i; + while (*message) + { + for (j = 0; j < FONT_HEIGHT; j++) + { + for (i = 0; i < FONT_WIDTH; i++) + { + uint8_t rem = 1 << ((i + j * FONT_WIDTH) & 7); + int offset = (i + j * FONT_WIDTH) >> 3; + bool col = (rgui->font[FONT_OFFSET((unsigned char)*message) + offset] & rem); + + if (col) + { + rgui->frame_buf[(y + j) * (rgui->frame_buf_pitch >> 1) + (x + i)] = green ? +#ifdef GEKKO + (3 << 0) | (10 << 4) | (3 << 8) | (7 << 12) : 0x7FFF; +#else + (15 << 0) | (7 << 4) | (15 << 8) | (7 << 12) : 0xFFFF; +#endif + } + } + } + + x += FONT_WIDTH_STRIDE; + message++; + } +} + +static void init_font(rgui_handle_t *rgui, const uint8_t *font_bmp_buf) +{ + unsigned i; + uint8_t *font = (uint8_t *) calloc(1, FONT_OFFSET(256)); + rgui->alloc_font = true; + for (i = 0; i < 256; i++) + { + unsigned y = i / 16; + unsigned x = i % 16; + rgui_copy_glyph(&font[FONT_OFFSET(i)], + font_bmp_buf + 54 + 3 * (256 * (255 - 16 * y) + 16 * x)); + } + + rgui->font = font; +} + +static bool rguidisp_init_font(void *data) +{ + rgui_handle_t *rgui = (rgui_handle_t*)data; + + const uint8_t *font_bmp_buf = NULL; + const uint8_t *font_bin_buf = bitmap_bin; + bool ret = true; + + if (font_bmp_buf) + init_font(rgui, font_bmp_buf); + else if (font_bin_buf) + rgui->font = font_bin_buf; + else + ret = false; + + return ret; +} + +static void render_background(rgui_handle_t *rgui) +{ + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + 0, 0, RGUI_WIDTH, RGUI_HEIGHT, gray_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + 5, 5, RGUI_WIDTH - 10, 5, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + 5, RGUI_HEIGHT - 10, RGUI_WIDTH - 10, 5, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + 5, 5, 5, RGUI_HEIGHT - 10, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + RGUI_WIDTH - 10, 5, 5, RGUI_HEIGHT - 10, green_filler); +} + +static void render_messagebox(rgui_handle_t *rgui, const char *message) +{ + size_t i; + + if (!message || !*message) + return; + + struct string_list *list = string_split(message, "\n"); + if (!list) + return; + if (list->elems == 0) + { + string_list_free(list); + return; + } + + unsigned width = 0; + unsigned glyphs_width = 0; + for (i = 0; i < list->size; i++) + { + char *msg = list->elems[i].data; + unsigned msglen = strlen(msg); + if (msglen > TERM_WIDTH) + { + msg[TERM_WIDTH - 2] = '.'; + msg[TERM_WIDTH - 1] = '.'; + msg[TERM_WIDTH - 0] = '.'; + msg[TERM_WIDTH + 1] = '\0'; + msglen = TERM_WIDTH; + } + + unsigned line_width = msglen * FONT_WIDTH_STRIDE - 1 + 6 + 10; + width = max(width, line_width); + glyphs_width = max(glyphs_width, msglen); + } + + unsigned height = FONT_HEIGHT_STRIDE * list->size + 6 + 10; + int x = (RGUI_WIDTH - width) / 2; + int y = (RGUI_HEIGHT - height) / 2; + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + x + 5, y + 5, width - 10, height - 10, gray_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + x, y, width - 5, 5, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + x + width - 5, y, 5, height - 5, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + x + 5, y + height - 5, width - 5, 5, green_filler); + + fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, + x, y + 5, 5, height - 5, green_filler); + + for (i = 0; i < list->size; i++) + { + const char *msg = list->elems[i].data; + int offset_x = FONT_WIDTH_STRIDE * (glyphs_width - strlen(msg)) / 2; + int offset_y = FONT_HEIGHT_STRIDE * i; + blit_line(rgui, x + 8 + offset_x, y + 8 + offset_y, msg, false); + } + + string_list_free(list); +} + +static void render_text(void *data) +{ + rgui_handle_t *rgui = (rgui_handle_t*)data; + + if (rgui->need_refresh && + (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) + && !rgui->msg_force) + return; + + size_t begin = rgui->selection_ptr >= TERM_HEIGHT / 2 ? + rgui->selection_ptr - TERM_HEIGHT / 2 : 0; + size_t end = rgui->selection_ptr + TERM_HEIGHT <= rgui->selection_buf->size ? + rgui->selection_ptr + TERM_HEIGHT : rgui->selection_buf->size; + + // Do not scroll if all items are visible. + if (rgui->selection_buf->size <= TERM_HEIGHT) + begin = 0; + + if (end - begin > TERM_HEIGHT) + end = begin + TERM_HEIGHT; + + render_background(rgui); + + char title[256]; + const char *dir = NULL; + unsigned menu_type = 0; + rgui_list_get_last(rgui->menu_stack, &dir, &menu_type); + + if (menu_type == RGUI_SETTINGS_CORE) + snprintf(title, sizeof(title), "CORE SELECTION %s", dir); + else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) + snprintf(title, sizeof(title), "DETECTED CORES %s", dir); + else if (menu_type == RGUI_SETTINGS_CONFIG) + snprintf(title, sizeof(title), "CONFIG %s", dir); + else if (menu_type == RGUI_SETTINGS_DISK_APPEND) + snprintf(title, sizeof(title), "DISK APPEND %s", dir); + else if (menu_type == RGUI_SETTINGS_VIDEO_OPTIONS) + strlcpy(title, "VIDEO OPTIONS", sizeof(title)); + else if (menu_type == RGUI_SETTINGS_DRIVERS) + strlcpy(title, "DRIVER OPTIONS", sizeof(title)); +#ifdef HAVE_SHADER_MANAGER + else if (menu_type == RGUI_SETTINGS_SHADER_OPTIONS) + strlcpy(title, "SHADER OPTIONS", sizeof(title)); +#endif + else if (menu_type == RGUI_SETTINGS_AUDIO_OPTIONS) + strlcpy(title, "AUDIO OPTIONS", sizeof(title)); + else if (menu_type == RGUI_SETTINGS_DISK_OPTIONS) + strlcpy(title, "DISK OPTIONS", sizeof(title)); + else if (menu_type == RGUI_SETTINGS_CORE_OPTIONS) + strlcpy(title, "CORE OPTIONS", sizeof(title)); +#ifdef HAVE_SHADER_MANAGER + else if (menu_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS) + snprintf(title, sizeof(title), "SHADER %s", dir); +#endif + else if ((menu_type == RGUI_SETTINGS_INPUT_OPTIONS) || + (menu_type == RGUI_SETTINGS_PATH_OPTIONS) || + (menu_type == RGUI_SETTINGS_OPTIONS) || + (menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT || menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT_2) || + menu_type == RGUI_SETTINGS_CUSTOM_BIND || + menu_type == RGUI_START_SCREEN || + menu_type == RGUI_SETTINGS) + snprintf(title, sizeof(title), "MENU %s", dir); + else if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) + strlcpy(title, "LOAD HISTORY", sizeof(title)); +#ifdef HAVE_OVERLAY + else if (menu_type == RGUI_SETTINGS_OVERLAY_PRESET) + snprintf(title, sizeof(title), "OVERLAY %s", dir); +#endif + else if (menu_type == RGUI_BROWSER_DIR_PATH) + snprintf(title, sizeof(title), "BROWSER DIR %s", dir); +#ifdef HAVE_SCREENSHOTS + else if (menu_type == RGUI_SCREENSHOT_DIR_PATH) + snprintf(title, sizeof(title), "SCREENSHOT DIR %s", dir); +#endif + else if (menu_type == RGUI_SHADER_DIR_PATH) + snprintf(title, sizeof(title), "SHADER DIR %s", dir); + else if (menu_type == RGUI_SAVESTATE_DIR_PATH) + snprintf(title, sizeof(title), "SAVESTATE DIR %s", dir); +#ifdef HAVE_DYNAMIC + else if (menu_type == RGUI_LIBRETRO_DIR_PATH) + snprintf(title, sizeof(title), "LIBRETRO DIR %s", dir); +#endif + else if (menu_type == RGUI_CONFIG_DIR_PATH) + snprintf(title, sizeof(title), "CONFIG DIR %s", dir); + else if (menu_type == RGUI_SAVEFILE_DIR_PATH) + snprintf(title, sizeof(title), "SAVEFILE DIR %s", dir); +#ifdef HAVE_OVERLAY + else if (menu_type == RGUI_OVERLAY_DIR_PATH) + snprintf(title, sizeof(title), "OVERLAY DIR %s", dir); +#endif + else if (menu_type == RGUI_SYSTEM_DIR_PATH) + snprintf(title, sizeof(title), "SYSTEM DIR %s", dir); + else + { + if (rgui->defer_core) + snprintf(title, sizeof(title), "GAME %s", dir); + else + { + const char *core_name = rgui->info.library_name; + if (!core_name) + core_name = g_extern.system.info.library_name; + if (!core_name) + core_name = "No Core"; + snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir); + } + } + + char title_buf[256]; + menu_ticker_line(title_buf, TERM_WIDTH - 3, g_extern.frame_count / 15, title, true); + blit_line(rgui, TERM_START_X + 15, 15, title_buf, true); + + char title_msg[64]; + const char *core_name = rgui->info.library_name; + if (!core_name) + core_name = g_extern.system.info.library_name; + if (!core_name) + core_name = "No Core"; + + const char *core_version = rgui->info.library_version; + if (!core_version) + core_version = g_extern.system.info.library_version; + if (!core_version) + core_version = ""; + + snprintf(title_msg, sizeof(title_msg), "%s - %s %s", PACKAGE_VERSION, core_name, core_version); + blit_line(rgui, TERM_START_X + 15, (TERM_HEIGHT * FONT_HEIGHT_STRIDE) + TERM_START_Y + 2, title_msg, true); + + unsigned x, y; + size_t i; + + x = TERM_START_X; + y = TERM_START_Y; + + for (i = begin; i < end; i++, y += FONT_HEIGHT_STRIDE) + { + const char *path = 0; + unsigned type = 0; + rgui_list_get_at_offset(rgui->selection_buf, i, &path, &type); + char message[256]; + char type_str[256]; + + unsigned w = 19; + if (menu_type == RGUI_SETTINGS_INPUT_OPTIONS || menu_type == RGUI_SETTINGS_CUSTOM_BIND) + w = 21; + else if (menu_type == RGUI_SETTINGS_PATH_OPTIONS) + w = 24; + +#ifdef HAVE_SHADER_MANAGER + if (type >= RGUI_SETTINGS_SHADER_FILTER && + type <= RGUI_SETTINGS_SHADER_LAST) + { + // HACK. Work around that we're using the menu_type as dir type to propagate state correctly. + if ((menu_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS) + && (menu_type_is(type) == RGUI_SETTINGS_SHADER_OPTIONS)) + { + type = RGUI_FILE_DIRECTORY; + strlcpy(type_str, "(DIR)", sizeof(type_str)); + w = 5; + } + else if (type == RGUI_SETTINGS_SHADER_OPTIONS || type == RGUI_SETTINGS_SHADER_PRESET) + strlcpy(type_str, "...", sizeof(type_str)); + else if (type == RGUI_SETTINGS_SHADER_FILTER) + snprintf(type_str, sizeof(type_str), "%s", + g_settings.video.smooth ? "Linear" : "Nearest"); + else + shader_manager_get_str(&rgui->shader, type_str, sizeof(type_str), type); + } + else +#endif + // Pretty-print libretro cores from menu. + if (menu_type == RGUI_SETTINGS_CORE || menu_type == RGUI_SETTINGS_DEFERRED_CORE) + { + if (type == RGUI_FILE_PLAIN) + { + strlcpy(type_str, "(CORE)", sizeof(type_str)); + rgui_list_get_alt_at_offset(rgui->selection_buf, i, &path); + w = 6; + } + else + { + strlcpy(type_str, "(DIR)", sizeof(type_str)); + type = RGUI_FILE_DIRECTORY; + w = 5; + } + } + else if (menu_type == RGUI_SETTINGS_CONFIG || +#ifdef HAVE_OVERLAY + menu_type == RGUI_SETTINGS_OVERLAY_PRESET || +#endif + menu_type == RGUI_SETTINGS_DISK_APPEND || + menu_type_is(menu_type) == RGUI_FILE_DIRECTORY) + { + if (type == RGUI_FILE_PLAIN) + { + strlcpy(type_str, "(FILE)", sizeof(type_str)); + w = 6; + } + else if (type == RGUI_FILE_USE_DIRECTORY) + { + *type_str = '\0'; + w = 0; + } + else + { + strlcpy(type_str, "(DIR)", sizeof(type_str)); + type = RGUI_FILE_DIRECTORY; + w = 5; + } + } + else if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) + { + *type_str = '\0'; + w = 0; + } + else if (type >= RGUI_SETTINGS_CORE_OPTION_START) + strlcpy(type_str, + core_option_get_val(g_extern.system.core_options, type - RGUI_SETTINGS_CORE_OPTION_START), + sizeof(type_str)); + else + menu_set_settings_label(type_str, sizeof(type_str), &w, type); + + char entry_title_buf[256]; + char type_str_buf[64]; + bool selected = i == rgui->selection_ptr; + + strlcpy(entry_title_buf, path, sizeof(entry_title_buf)); + strlcpy(type_str_buf, type_str, sizeof(type_str_buf)); + + if ((type == RGUI_FILE_PLAIN || type == RGUI_FILE_DIRECTORY)) + menu_ticker_line(entry_title_buf, TERM_WIDTH - (w + 1 + 2), g_extern.frame_count / 15, path, selected); + else + menu_ticker_line(type_str_buf, w, g_extern.frame_count / 15, type_str, selected); + + snprintf(message, sizeof(message), "%c %-*.*s %-*s", + selected ? '>' : ' ', + TERM_WIDTH - (w + 1 + 2), TERM_WIDTH - (w + 1 + 2), + entry_title_buf, + w, + type_str_buf); + + blit_line(rgui, x, y, message, selected); + } + +#ifdef GEKKO + const char *message_queue; + + if (rgui->msg_force) + { + message_queue = msg_queue_pull(g_extern.msg_queue); + rgui->msg_force = false; + } + else + message_queue = driver.current_msg; + + render_messagebox(rgui, message_queue); +#endif +} static void *rgui_init(void) { @@ -122,18 +585,6 @@ static int rgui_core_setting_toggle(unsigned setting, rgui_action_t action) return 0; } -static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action, unsigned menu_type) -{ -#ifdef HAVE_SHADER_MANAGER - if (setting >= RGUI_SETTINGS_SHADER_FILTER && setting <= RGUI_SETTINGS_SHADER_LAST) - return shader_manager_toggle_setting(rgui, setting, action); -#endif - if (setting >= RGUI_SETTINGS_CORE_OPTION_START) - return rgui_core_setting_toggle(setting, action); - - return menu_set_settings(setting, action); -} - #ifdef HAVE_SHADER_MANAGER static int shader_manager_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action) { @@ -238,6 +689,18 @@ static int shader_manager_toggle_setting(rgui_handle_t *rgui, unsigned setting, } #endif +static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action, unsigned menu_type) +{ +#ifdef HAVE_SHADER_MANAGER + if (setting >= RGUI_SETTINGS_SHADER_FILTER && setting <= RGUI_SETTINGS_SHADER_LAST) + return shader_manager_toggle_setting(rgui, setting, action); +#endif + if (setting >= RGUI_SETTINGS_CORE_OPTION_START) + return rgui_core_setting_toggle(setting, action); + + return menu_set_settings(setting, action); +} + // This only makes sense for PC so far. // Consoles use set_keybind callbacks instead. static int rgui_custom_bind_iterate(rgui_handle_t *rgui, rgui_action_t action) diff --git a/frontend/menu/rgui.h b/frontend/menu/rgui.h index 026b48af2d..d6ea5cb17a 100644 --- a/frontend/menu/rgui.h +++ b/frontend/menu/rgui.h @@ -34,11 +34,7 @@ typedef void (*rgui_file_enum_cb_t)(void *ctx, typedef bool (*rgui_folder_enum_cb_t)(const char *directory, rgui_file_enum_cb_t file_cb, void *userdata, void *ctx); -extern unsigned RGUI_WIDTH; -extern unsigned RGUI_HEIGHT; - #ifdef __cplusplus } #endif #endif - diff --git a/frontend/menu/rguidisp.c b/frontend/menu/rguidisp.c deleted file mode 100644 index 66143dade6..0000000000 --- a/frontend/menu/rguidisp.c +++ /dev/null @@ -1,469 +0,0 @@ -#include "../../gfx/fonts/bitmap.h" - -#define TERM_START_X 15 -#define TERM_START_Y 27 -#define TERM_WIDTH (((RGUI_WIDTH - TERM_START_X - 15) / (FONT_WIDTH_STRIDE))) -#define TERM_HEIGHT (((RGUI_HEIGHT - TERM_START_Y - 15) / (FONT_HEIGHT_STRIDE)) - 1) - -static void rgui_copy_glyph(uint8_t *glyph, const uint8_t *buf) -{ - int y, x; - for (y = 0; y < FONT_HEIGHT; y++) - { - for (x = 0; x < FONT_WIDTH; x++) - { - uint32_t col = - ((uint32_t)buf[3 * (-y * 256 + x) + 0] << 0) | - ((uint32_t)buf[3 * (-y * 256 + x) + 1] << 8) | - ((uint32_t)buf[3 * (-y * 256 + x) + 2] << 16); - - uint8_t rem = 1 << ((x + y * FONT_WIDTH) & 7); - unsigned offset = (x + y * FONT_WIDTH) >> 3; - - if (col != 0xff) - glyph[offset] |= rem; - } - } -} - -static uint16_t gray_filler(unsigned x, unsigned y) -{ - x >>= 1; - y >>= 1; - unsigned col = ((x + y) & 1) + 1; -#ifdef GEKKO - return (6 << 12) | (col << 8) | (col << 4) | (col << 0); -#else - return (col << 13) | (col << 9) | (col << 5) | (12 << 0); -#endif -} - -static uint16_t green_filler(unsigned x, unsigned y) -{ - x >>= 1; - y >>= 1; - unsigned col = ((x + y) & 1) + 1; -#ifdef GEKKO - return (6 << 12) | (col << 8) | (col << 5) | (col << 0); -#else - return (col << 13) | (col << 10) | (col << 5) | (12 << 0); -#endif -} - -static void fill_rect(uint16_t *buf, unsigned pitch, - unsigned x, unsigned y, - unsigned width, unsigned height, - uint16_t (*col)(unsigned x, unsigned y)) -{ - unsigned j, i; - for (j = y; j < y + height; j++) - for (i = x; i < x + width; i++) - buf[j * (pitch >> 1) + i] = col(i, j); -} - -static void blit_line(rgui_handle_t *rgui, - int x, int y, const char *message, bool green) -{ - int j, i; - while (*message) - { - for (j = 0; j < FONT_HEIGHT; j++) - { - for (i = 0; i < FONT_WIDTH; i++) - { - uint8_t rem = 1 << ((i + j * FONT_WIDTH) & 7); - int offset = (i + j * FONT_WIDTH) >> 3; - bool col = (rgui->font[FONT_OFFSET((unsigned char)*message) + offset] & rem); - - if (col) - { - rgui->frame_buf[(y + j) * (rgui->frame_buf_pitch >> 1) + (x + i)] = green ? -#ifdef GEKKO - (3 << 0) | (10 << 4) | (3 << 8) | (7 << 12) : 0x7FFF; -#else - (15 << 0) | (7 << 4) | (15 << 8) | (7 << 12) : 0xFFFF; -#endif - } - } - } - - x += FONT_WIDTH_STRIDE; - message++; - } -} - -static void init_font(rgui_handle_t *rgui, const uint8_t *font_bmp_buf) -{ - unsigned i; - uint8_t *font = (uint8_t *) calloc(1, FONT_OFFSET(256)); - rgui->alloc_font = true; - for (i = 0; i < 256; i++) - { - unsigned y = i / 16; - unsigned x = i % 16; - rgui_copy_glyph(&font[FONT_OFFSET(i)], - font_bmp_buf + 54 + 3 * (256 * (255 - 16 * y) + 16 * x)); - } - - rgui->font = font; -} - -static bool rguidisp_init_font(void *data) -{ - rgui_handle_t *rgui = (rgui_handle_t*)data; - - const uint8_t *font_bmp_buf = NULL; - const uint8_t *font_bin_buf = bitmap_bin; - bool ret = true; - - if (font_bmp_buf) - init_font(rgui, font_bmp_buf); - else if (font_bin_buf) - rgui->font = font_bin_buf; - else - ret = false; - - return ret; -} - -static void render_background(rgui_handle_t *rgui) -{ - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - 0, 0, RGUI_WIDTH, RGUI_HEIGHT, gray_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - 5, 5, RGUI_WIDTH - 10, 5, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - 5, RGUI_HEIGHT - 10, RGUI_WIDTH - 10, 5, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - 5, 5, 5, RGUI_HEIGHT - 10, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - RGUI_WIDTH - 10, 5, 5, RGUI_HEIGHT - 10, green_filler); -} - -static void render_messagebox(rgui_handle_t *rgui, const char *message) -{ - size_t i; - - if (!message || !*message) - return; - - struct string_list *list = string_split(message, "\n"); - if (!list) - return; - if (list->elems == 0) - { - string_list_free(list); - return; - } - - unsigned width = 0; - unsigned glyphs_width = 0; - for (i = 0; i < list->size; i++) - { - char *msg = list->elems[i].data; - unsigned msglen = strlen(msg); - if (msglen > TERM_WIDTH) - { - msg[TERM_WIDTH - 2] = '.'; - msg[TERM_WIDTH - 1] = '.'; - msg[TERM_WIDTH - 0] = '.'; - msg[TERM_WIDTH + 1] = '\0'; - msglen = TERM_WIDTH; - } - - unsigned line_width = msglen * FONT_WIDTH_STRIDE - 1 + 6 + 10; - width = max(width, line_width); - glyphs_width = max(glyphs_width, msglen); - } - - unsigned height = FONT_HEIGHT_STRIDE * list->size + 6 + 10; - int x = (RGUI_WIDTH - width) / 2; - int y = (RGUI_HEIGHT - height) / 2; - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - x + 5, y + 5, width - 10, height - 10, gray_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - x, y, width - 5, 5, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - x + width - 5, y, 5, height - 5, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - x + 5, y + height - 5, width - 5, 5, green_filler); - - fill_rect(rgui->frame_buf, rgui->frame_buf_pitch, - x, y + 5, 5, height - 5, green_filler); - - for (i = 0; i < list->size; i++) - { - const char *msg = list->elems[i].data; - int offset_x = FONT_WIDTH_STRIDE * (glyphs_width - strlen(msg)) / 2; - int offset_y = FONT_HEIGHT_STRIDE * i; - blit_line(rgui, x + 8 + offset_x, y + 8 + offset_y, msg, false); - } - - string_list_free(list); -} - -static void render_text(void *data) -{ - rgui_handle_t *rgui = (rgui_handle_t*)data; - - if (rgui->need_refresh && - (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) - && !rgui->msg_force) - return; - - size_t begin = rgui->selection_ptr >= TERM_HEIGHT / 2 ? - rgui->selection_ptr - TERM_HEIGHT / 2 : 0; - size_t end = rgui->selection_ptr + TERM_HEIGHT <= rgui->selection_buf->size ? - rgui->selection_ptr + TERM_HEIGHT : rgui->selection_buf->size; - - // Do not scroll if all items are visible. - if (rgui->selection_buf->size <= TERM_HEIGHT) - begin = 0; - - if (end - begin > TERM_HEIGHT) - end = begin + TERM_HEIGHT; - - render_background(rgui); - - char title[256]; - const char *dir = NULL; - unsigned menu_type = 0; - rgui_list_get_last(rgui->menu_stack, &dir, &menu_type); - - if (menu_type == RGUI_SETTINGS_CORE) - snprintf(title, sizeof(title), "CORE SELECTION %s", dir); - else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE) - snprintf(title, sizeof(title), "DETECTED CORES %s", dir); - else if (menu_type == RGUI_SETTINGS_CONFIG) - snprintf(title, sizeof(title), "CONFIG %s", dir); - else if (menu_type == RGUI_SETTINGS_DISK_APPEND) - snprintf(title, sizeof(title), "DISK APPEND %s", dir); - else if (menu_type == RGUI_SETTINGS_VIDEO_OPTIONS) - strlcpy(title, "VIDEO OPTIONS", sizeof(title)); - else if (menu_type == RGUI_SETTINGS_DRIVERS) - strlcpy(title, "DRIVER OPTIONS", sizeof(title)); -#ifdef HAVE_SHADER_MANAGER - else if (menu_type == RGUI_SETTINGS_SHADER_OPTIONS) - strlcpy(title, "SHADER OPTIONS", sizeof(title)); -#endif - else if (menu_type == RGUI_SETTINGS_AUDIO_OPTIONS) - strlcpy(title, "AUDIO OPTIONS", sizeof(title)); - else if (menu_type == RGUI_SETTINGS_DISK_OPTIONS) - strlcpy(title, "DISK OPTIONS", sizeof(title)); - else if (menu_type == RGUI_SETTINGS_CORE_OPTIONS) - strlcpy(title, "CORE OPTIONS", sizeof(title)); -#ifdef HAVE_SHADER_MANAGER - else if (menu_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS) - snprintf(title, sizeof(title), "SHADER %s", dir); -#endif - else if ((menu_type == RGUI_SETTINGS_INPUT_OPTIONS) || - (menu_type == RGUI_SETTINGS_PATH_OPTIONS) || - (menu_type == RGUI_SETTINGS_OPTIONS) || - (menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT || menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT_2) || - menu_type == RGUI_SETTINGS_CUSTOM_BIND || - menu_type == RGUI_START_SCREEN || - menu_type == RGUI_SETTINGS) - snprintf(title, sizeof(title), "MENU %s", dir); - else if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) - strlcpy(title, "LOAD HISTORY", sizeof(title)); -#ifdef HAVE_OVERLAY - else if (menu_type == RGUI_SETTINGS_OVERLAY_PRESET) - snprintf(title, sizeof(title), "OVERLAY %s", dir); -#endif - else if (menu_type == RGUI_BROWSER_DIR_PATH) - snprintf(title, sizeof(title), "BROWSER DIR %s", dir); -#ifdef HAVE_SCREENSHOTS - else if (menu_type == RGUI_SCREENSHOT_DIR_PATH) - snprintf(title, sizeof(title), "SCREENSHOT DIR %s", dir); -#endif - else if (menu_type == RGUI_SHADER_DIR_PATH) - snprintf(title, sizeof(title), "SHADER DIR %s", dir); - else if (menu_type == RGUI_SAVESTATE_DIR_PATH) - snprintf(title, sizeof(title), "SAVESTATE DIR %s", dir); -#ifdef HAVE_DYNAMIC - else if (menu_type == RGUI_LIBRETRO_DIR_PATH) - snprintf(title, sizeof(title), "LIBRETRO DIR %s", dir); -#endif - else if (menu_type == RGUI_CONFIG_DIR_PATH) - snprintf(title, sizeof(title), "CONFIG DIR %s", dir); - else if (menu_type == RGUI_SAVEFILE_DIR_PATH) - snprintf(title, sizeof(title), "SAVEFILE DIR %s", dir); -#ifdef HAVE_OVERLAY - else if (menu_type == RGUI_OVERLAY_DIR_PATH) - snprintf(title, sizeof(title), "OVERLAY DIR %s", dir); -#endif - else if (menu_type == RGUI_SYSTEM_DIR_PATH) - snprintf(title, sizeof(title), "SYSTEM DIR %s", dir); - else - { - if (rgui->defer_core) - snprintf(title, sizeof(title), "GAME %s", dir); - else - { - const char *core_name = rgui->info.library_name; - if (!core_name) - core_name = g_extern.system.info.library_name; - if (!core_name) - core_name = "No Core"; - snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir); - } - } - - char title_buf[256]; - menu_ticker_line(title_buf, TERM_WIDTH - 3, g_extern.frame_count / 15, title, true); - blit_line(rgui, TERM_START_X + 15, 15, title_buf, true); - - char title_msg[64]; - const char *core_name = rgui->info.library_name; - if (!core_name) - core_name = g_extern.system.info.library_name; - if (!core_name) - core_name = "No Core"; - - const char *core_version = rgui->info.library_version; - if (!core_version) - core_version = g_extern.system.info.library_version; - if (!core_version) - core_version = ""; - - snprintf(title_msg, sizeof(title_msg), "%s - %s %s", PACKAGE_VERSION, core_name, core_version); - blit_line(rgui, TERM_START_X + 15, (TERM_HEIGHT * FONT_HEIGHT_STRIDE) + TERM_START_Y + 2, title_msg, true); - - unsigned x, y; - size_t i; - - x = TERM_START_X; - y = TERM_START_Y; - - for (i = begin; i < end; i++, y += FONT_HEIGHT_STRIDE) - { - const char *path = 0; - unsigned type = 0; - rgui_list_get_at_offset(rgui->selection_buf, i, &path, &type); - char message[256]; - char type_str[256]; - - unsigned w = 19; - if (menu_type == RGUI_SETTINGS_INPUT_OPTIONS || menu_type == RGUI_SETTINGS_CUSTOM_BIND) - w = 21; - else if (menu_type == RGUI_SETTINGS_PATH_OPTIONS) - w = 24; - -#ifdef HAVE_SHADER_MANAGER - if (type >= RGUI_SETTINGS_SHADER_FILTER && - type <= RGUI_SETTINGS_SHADER_LAST) - { - // HACK. Work around that we're using the menu_type as dir type to propagate state correctly. - if ((menu_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS) - && (menu_type_is(type) == RGUI_SETTINGS_SHADER_OPTIONS)) - { - type = RGUI_FILE_DIRECTORY; - strlcpy(type_str, "(DIR)", sizeof(type_str)); - w = 5; - } - else if (type == RGUI_SETTINGS_SHADER_OPTIONS || type == RGUI_SETTINGS_SHADER_PRESET) - strlcpy(type_str, "...", sizeof(type_str)); - else if (type == RGUI_SETTINGS_SHADER_FILTER) - snprintf(type_str, sizeof(type_str), "%s", - g_settings.video.smooth ? "Linear" : "Nearest"); - else - shader_manager_get_str(&rgui->shader, type_str, sizeof(type_str), type); - } - else -#endif - // Pretty-print libretro cores from menu. - if (menu_type == RGUI_SETTINGS_CORE || menu_type == RGUI_SETTINGS_DEFERRED_CORE) - { - if (type == RGUI_FILE_PLAIN) - { - strlcpy(type_str, "(CORE)", sizeof(type_str)); - rgui_list_get_alt_at_offset(rgui->selection_buf, i, &path); - w = 6; - } - else - { - strlcpy(type_str, "(DIR)", sizeof(type_str)); - type = RGUI_FILE_DIRECTORY; - w = 5; - } - } - else if (menu_type == RGUI_SETTINGS_CONFIG || -#ifdef HAVE_OVERLAY - menu_type == RGUI_SETTINGS_OVERLAY_PRESET || -#endif - menu_type == RGUI_SETTINGS_DISK_APPEND || - menu_type_is(menu_type) == RGUI_FILE_DIRECTORY) - { - if (type == RGUI_FILE_PLAIN) - { - strlcpy(type_str, "(FILE)", sizeof(type_str)); - w = 6; - } - else if (type == RGUI_FILE_USE_DIRECTORY) - { - *type_str = '\0'; - w = 0; - } - else - { - strlcpy(type_str, "(DIR)", sizeof(type_str)); - type = RGUI_FILE_DIRECTORY; - w = 5; - } - } - else if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) - { - *type_str = '\0'; - w = 0; - } - else if (type >= RGUI_SETTINGS_CORE_OPTION_START) - strlcpy(type_str, - core_option_get_val(g_extern.system.core_options, type - RGUI_SETTINGS_CORE_OPTION_START), - sizeof(type_str)); - else - menu_set_settings_label(type_str, sizeof(type_str), &w, type); - - char entry_title_buf[256]; - char type_str_buf[64]; - bool selected = i == rgui->selection_ptr; - - strlcpy(entry_title_buf, path, sizeof(entry_title_buf)); - strlcpy(type_str_buf, type_str, sizeof(type_str_buf)); - - if ((type == RGUI_FILE_PLAIN || type == RGUI_FILE_DIRECTORY)) - menu_ticker_line(entry_title_buf, TERM_WIDTH - (w + 1 + 2), g_extern.frame_count / 15, path, selected); - else - menu_ticker_line(type_str_buf, w, g_extern.frame_count / 15, type_str, selected); - - snprintf(message, sizeof(message), "%c %-*.*s %-*s", - selected ? '>' : ' ', - TERM_WIDTH - (w + 1 + 2), TERM_WIDTH - (w + 1 + 2), - entry_title_buf, - w, - type_str_buf); - - blit_line(rgui, x, y, message, selected); - } - -#ifdef GEKKO - const char *message_queue; - - if (rgui->msg_force) - { - message_queue = msg_queue_pull(g_extern.msg_queue); - rgui->msg_force = false; - } - else - message_queue = driver.current_msg; - - render_messagebox(rgui, message_queue); -#endif -}