diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 26319581dc..eec6a8bb70 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -30,7 +30,8 @@ "/usr/include", "/usr/local/include", "${workspaceRoot}", - "${workspaceFolder}/libretro-common/include" + "${workspaceFolder}/libretro-common/include", + "${workspaceRoot}/libretro-common/include" ], "defines": [], "intelliSenseMode": "clang-x64", @@ -51,7 +52,8 @@ "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt", "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared", "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt", - "${workspaceRoot}" + "${workspaceRoot}", + "${workspaceFolder}/libretro-common/include" ], "defines": [ "_DEBUG", diff --git a/.vscode/settings.json b/.vscode/settings.json index 148f4b83ea..c08df32eb9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,11 @@ "ios": "c", "list": "c", "input_driver.h": "c", - "video_driver.h": "c" + "video_driver.h": "c", + "menu_driver.h": "c", + "file_path.h": "c", + "unordered_map": "c", + "unordered_set": "c" }, "C_Cpp.dimInactiveRegions": false, } \ No newline at end of file diff --git a/Makefile.common b/Makefile.common index ff6ff02411..73836d6fd1 100644 --- a/Makefile.common +++ b/Makefile.common @@ -677,12 +677,17 @@ ifeq ($(HW_CONTEXT_MENU_DRIVERS), 1) ifeq ($(HAVE_STRIPES),) HAVE_STRIPES = 1 endif + + ifeq ($(HAVE_OZONE),) + HAVE_OZONE = 1 + endif else HAVE_ZARCH ?= 0 HAVE_MATERIALUI ?= 0 #HAVE_NUKLEAR ?= 0 HAVE_XMB ?= 0 HAVE_STRIPES ?= 0 + HAVE_OZONE ?= 0 endif ifeq ($(HAVE_RGUI), 1) @@ -714,6 +719,12 @@ ifeq ($(HAVE_XMB), 1) HAVE_MENU_COMMON = 1 endif +ifeq ($(HAVE_OZONE), 1) + OBJ += menu/drivers/ozone.o + DEFINES += -DHAVE_OZONE + HAVE_MENU_COMMON = 1 +endif + ifeq ($(HAVE_STRIPES), 1) OBJ += menu/drivers/stripes.o DEFINES += -DHAVE_STRIPES diff --git a/Makefile.libnx b/Makefile.libnx index d417ee1a5e..709f03364c 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -58,6 +58,7 @@ ifeq ($(HAVE_OPENGL), 1) HAVE_ZARCH = 0 HAVE_XMB = 1 + HAVE_OZONE = 0 HAVE_STRIPES = 0 HAVE_OVERLAY = 1 @@ -67,6 +68,7 @@ else HAVE_ZARCH = 0 HAVE_MATERIALUI = 0 HAVE_XMB = 0 + HAVE_OZONE = 0 HAVE_STRIPES = 0 endif diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index e67af93c59..3539db7938 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -1743,7 +1743,10 @@ found: { settings_t *settings = config_get_ptr(); - if (!string_is_equal(settings->arrays.menu_driver, "xmb") || + if (!( + string_is_equal(settings->arrays.menu_driver, "xmb") || + !string_is_equal(settings->arrays.menu_driver, "ozone") + ) || !settings->bools.cheevos_badges_enable) CORO_RET(); } diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index d6d1b36325..134e7e6513 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -3229,7 +3229,10 @@ found: { settings_t *settings = config_get_ptr(); - if (!string_is_equal(settings->arrays.menu_driver, "xmb") || + if (!( + string_is_equal(settings->arrays.menu_driver, "xmb") || + !string_is_equal(settings->arrays.menu_driver, "ozone") + ) || !settings->bools.cheevos_badges_enable) CORO_RET(); } diff --git a/configuration.c b/configuration.c index ceac27d6c2..7dfa178c30 100644 --- a/configuration.c +++ b/configuration.c @@ -288,6 +288,7 @@ enum menu_driver_enum MENU_XMB, MENU_STRIPES, MENU_NUKLEAR, + MENU_OZONE, MENU_NULL }; @@ -534,6 +535,8 @@ static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL; static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_XUI; #elif defined(HAVE_MATERIALUI) && defined(RARCH_MOBILE) static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_MATERIALUI; +#elif defined(HAVE_OZONE) && defined(HAVE_LIBNX) +static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_OZONE; #elif defined(HAVE_XMB) && !defined(_XBOX) static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_XMB; #elif defined(HAVE_RGUI) @@ -1028,6 +1031,8 @@ const char *config_get_default_menu(void) return "rgui"; case MENU_XUI: return "xui"; + case MENU_OZONE: + return "ozone"; case MENU_MATERIALUI: return "glui"; case MENU_XMB: diff --git a/griffin/griffin.c b/griffin/griffin.c index d1be92b996..237ce3a9c5 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1264,6 +1264,9 @@ MENU #ifdef HAVE_XMB #include "../menu/drivers/xmb.c" #endif +#ifdef HAVE_OZONE +#include "../menu/drivers/ozone.c" +#endif #ifdef HAVE_STRIPES #include "../menu/drivers/stripes.c" diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 752dc1caa8..2c625ba881 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -183,14 +183,6 @@ typedef struct materialui_handle } materialui_handle_t; -static void hex32_to_rgba_normalized(uint32_t hex, float* rgba, float alpha) -{ - rgba[0] = rgba[4] = rgba[8] = rgba[12] = ((hex >> 16) & 0xFF) * (1.0f / 255.0f); /* r */ - rgba[1] = rgba[5] = rgba[9] = rgba[13] = ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f); /* g */ - rgba[2] = rgba[6] = rgba[10] = rgba[14] = ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f); /* b */ - rgba[3] = rgba[7] = rgba[11] = rgba[15] = alpha; -} - static const char *materialui_texture_path(unsigned id) { switch (id) diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c new file mode 100644 index 0000000000..a148d73112 --- /dev/null +++ b/menu/drivers/ozone.c @@ -0,0 +1,3038 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2018 - Alfredo Monclús + * Copyright (C) 2018 - natinusala + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include + +#include "menu_generic.h" +#include "../menu_driver.h" +#include "../menu_animation.h" + +#include "../../configuration.h" + +#include "../../cheevos/badges.h" +#include "../../content.h" + +#include "../../core_info.h" +#include "../../core.h" + +#include "../../retroarch.h" +#include "../../verbosity.h" + +//TODO Handle translation for hardcoded strings (footer...) + +#define FONT_SIZE_FOOTER 18 +#define FONT_SIZE_TITLE 36 +#define FONT_SIZE_TIME 22 +#define FONT_SIZE_ENTRIES_LABEL 24 +#define FONT_SIZE_ENTRIES_SUBLABEL 18 +#define FONT_SIZE_SIDEBAR 24 + +#define ANIMATION_PUSH_ENTRY_DURATION 10 +#define ANIMATION_CURSOR_DURATION 8 + +#define ENTRIES_START_Y 127 + +static float ozone_pure_white[16] = { + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, +}; + +enum OZONE_TEXTURE { + OZONE_TEXTURE_RETROARCH = 0, + + OZONE_TEXTURE_LAST +}; + +static char *OZONE_TEXTURES_FILES[OZONE_TEXTURE_LAST] = { + "retroarch" +}; + +enum OZONE_THEME_TEXTURES { + OZONE_THEME_TEXTURE_BUTTON_A = 0, + OZONE_THEME_TEXTURE_BUTTON_B, + OZONE_THEME_TEXTURE_SWITCH, + + OZONE_THEME_TEXTURE_LAST +}; + +static char* OZONE_THEME_TEXTURES_FILES[OZONE_THEME_TEXTURE_LAST] = { + "button_a", + "button_b", + "switch", +}; + +enum OZONE_TAB_TEXTURES { + OZONE_TAB_TEXTURE_MAIN_MENU = 0, + OZONE_TAB_TEXTURE_SETTINGS, + OZONE_TAB_TEXTURE_HISTORY, + OZONE_TAB_TEXTURE_FAVORITES, + OZONE_TAB_TEXTURE_MUSIC, + OZONE_TAB_TEXTURE_VIDEO, + OZONE_TAB_TEXTURE_IMAGE, + OZONE_TAB_TEXTURE_NETWORK, + OZONE_TAB_TEXTURE_SCAN_CONTENT, + + OZONE_TAB_TEXTURE_LAST +}; + +static char *OZONE_TAB_TEXTURES_FILES[OZONE_TAB_TEXTURE_LAST] = { + "retroarch", + "settings", + "history", + "favorites", + "music", + "video", + "image", + "netplay", + "add" +}; + +enum +{ + OZONE_SYSTEM_TAB_MAIN = 0, + OZONE_SYSTEM_TAB_SETTINGS, + OZONE_SYSTEM_TAB_HISTORY, + OZONE_SYSTEM_TAB_FAVORITES, + OZONE_SYSTEM_TAB_MUSIC, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_SYSTEM_TAB_VIDEO, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_SYSTEM_TAB_IMAGES, +#endif +#ifdef HAVE_NETWORKING + OZONE_SYSTEM_TAB_NETPLAY, +#endif + OZONE_SYSTEM_TAB_ADD, + + /* End of this enum - use the last one to determine num of possible tabs */ + OZONE_SYSTEM_TAB_LAST +}; + +static enum msg_hash_enums ozone_system_tabs_value[OZONE_SYSTEM_TAB_LAST] = { + MENU_ENUM_LABEL_VALUE_MAIN_MENU, + MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + MENU_ENUM_LABEL_VALUE_HISTORY_TAB, + MENU_ENUM_LABEL_VALUE_FAVORITES_TAB, + MENU_ENUM_LABEL_VALUE_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_ENUM_LABEL_VALUE_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_ENUM_LABEL_VALUE_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, +#endif + MENU_ENUM_LABEL_VALUE_ADD_TAB +}; + +static enum menu_settings_type ozone_system_tabs_type[OZONE_SYSTEM_TAB_LAST] = { + MENU_SETTINGS, + MENU_SETTINGS_TAB, + MENU_HISTORY_TAB, + MENU_FAVORITES_TAB, + MENU_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_NETPLAY_TAB, +#endif + MENU_ADD_TAB +}; + +static enum msg_hash_enums ozone_system_tabs_idx[OZONE_SYSTEM_TAB_LAST] = { + MENU_ENUM_LABEL_MAIN_MENU, + MENU_ENUM_LABEL_SETTINGS_TAB, + MENU_ENUM_LABEL_HISTORY_TAB, + MENU_ENUM_LABEL_FAVORITES_TAB, + MENU_ENUM_LABEL_MUSIC_TAB, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + MENU_ENUM_LABEL_VIDEO_TAB, +#endif +#ifdef HAVE_IMAGEVIEWER + MENU_ENUM_LABEL_IMAGES_TAB, +#endif +#ifdef HAVE_NETWORKING + MENU_ENUM_LABEL_NETPLAY_TAB, +#endif + MENU_ENUM_LABEL_ADD_TAB +}; + +enum +{ + OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU = 0, + OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS, + OZONE_ENTRIES_ICONS_TEXTURE_HISTORY, + OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES, + OZONE_ENTRIES_ICONS_TEXTURE_MUSICS, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_ENTRIES_ICONS_TEXTURE_MOVIES, +#endif +#ifdef HAVE_NETWORKING + OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN, + OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_ENTRIES_ICONS_TEXTURE_IMAGES, +#endif + OZONE_ENTRIES_ICONS_TEXTURE_SETTING, + OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING, + OZONE_ENTRIES_ICONS_TEXTURE_ARROW, + OZONE_ENTRIES_ICONS_TEXTURE_RUN, + OZONE_ENTRIES_ICONS_TEXTURE_CLOSE, + OZONE_ENTRIES_ICONS_TEXTURE_RESUME, + OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE, + OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE, + OZONE_ENTRIES_ICONS_TEXTURE_UNDO, + OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO, + OZONE_ENTRIES_ICONS_TEXTURE_WIFI, + OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS, + OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST, + OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT, + OZONE_ENTRIES_ICONS_TEXTURE_RELOAD, + OZONE_ENTRIES_ICONS_TEXTURE_RENAME, + OZONE_ENTRIES_ICONS_TEXTURE_FILE, + OZONE_ENTRIES_ICONS_TEXTURE_FOLDER, + OZONE_ENTRIES_ICONS_TEXTURE_ZIP, + OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE, + OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE, + OZONE_ENTRIES_ICONS_TEXTURE_MUSIC, + OZONE_ENTRIES_ICONS_TEXTURE_IMAGE, + OZONE_ENTRIES_ICONS_TEXTURE_MOVIE, + OZONE_ENTRIES_ICONS_TEXTURE_CORE, + OZONE_ENTRIES_ICONS_TEXTURE_RDB, + OZONE_ENTRIES_ICONS_TEXTURE_CURSOR, + OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON, + OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF, + OZONE_ENTRIES_ICONS_TEXTURE_CLOCK, + OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL, + OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING, + OZONE_ENTRIES_ICONS_TEXTURE_POINTER, + OZONE_ENTRIES_ICONS_TEXTURE_ADD, + OZONE_ENTRIES_ICONS_TEXTURE_KEY, + OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER, + OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE, + OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS, + OZONE_ENTRIES_ICONS_TEXTURE_AUDIO, + OZONE_ENTRIES_ICONS_TEXTURE_EXIT, + OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP, + OZONE_ENTRIES_ICONS_TEXTURE_INFO, + OZONE_ENTRIES_ICONS_TEXTURE_HELP, + OZONE_ENTRIES_ICONS_TEXTURE_NETWORK, + OZONE_ENTRIES_ICONS_TEXTURE_POWER, + OZONE_ENTRIES_ICONS_TEXTURE_SAVING, + OZONE_ENTRIES_ICONS_TEXTURE_UPDATER, + OZONE_ENTRIES_ICONS_TEXTURE_VIDEO, + OZONE_ENTRIES_ICONS_TEXTURE_RECORD, + OZONE_ENTRIES_ICONS_TEXTURE_INPUT, + OZONE_ENTRIES_ICONS_TEXTURE_MIXER, + OZONE_ENTRIES_ICONS_TEXTURE_LOG, + OZONE_ENTRIES_ICONS_TEXTURE_OSD, + OZONE_ENTRIES_ICONS_TEXTURE_UI, + OZONE_ENTRIES_ICONS_TEXTURE_USER, + OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY, + OZONE_ENTRIES_ICONS_TEXTURE_LATENCY, + OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS, + OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST, + OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU, + OZONE_ENTRIES_ICONS_TEXTURE_REWIND, + OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY, + OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE, + OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS, + OZONE_ENTRIES_ICONS_TEXTURE_STREAM, + OZONE_ENTRIES_ICONS_TEXTURE_LAST +}; + +static unsigned ozone_system_tabs_icons[OZONE_SYSTEM_TAB_LAST] = { + OZONE_TAB_TEXTURE_MAIN_MENU, + OZONE_TAB_TEXTURE_SETTINGS, + OZONE_TAB_TEXTURE_HISTORY, + OZONE_TAB_TEXTURE_FAVORITES, + OZONE_TAB_TEXTURE_MUSIC, +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + OZONE_TAB_TEXTURE_VIDEO, +#endif +#ifdef HAVE_IMAGEVIEWER + OZONE_TAB_TEXTURE_IMAGE, +#endif +#ifdef HAVE_NETWORKING + OZONE_TAB_TEXTURE_NETWORK, +#endif + OZONE_TAB_TEXTURE_SCAN_CONTENT +}; + +#define HEX_R(hex) ((hex >> 16) & 0xFF) * (1.0f / 255.0f) +#define HEX_G(hex) ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f) +#define HEX_B(hex) ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f) + +#define COLOR_HEX_TO_FLOAT(hex, alpha) { \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha \ +} + +#define COLOR_BACKGROUND(hex) hex, HEX_R(hex), HEX_G(hex), HEX_B(hex) + +static float ozone_sidebar_background_light[16] = { + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, +}; + +static float ozone_sidebar_gradient_top_light[16] = { + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.922, 0.922, 0.922, 1.00, + 0.922, 0.922, 0.922, 1.00, +}; + +static float ozone_sidebar_gradient_bottom_light[16] = { + 0.922, 0.922, 0.922, 1.00, + 0.922, 0.922, 0.922, 1.00, + 0.94, 0.94, 0.94, 1.00, + 0.94, 0.94, 0.94, 1.00, +}; + +static float ozone_sidebar_background_dark[16] = { + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, +}; + +static float ozone_sidebar_gradient_top_dark[16] = { + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.18, 0.18, 0.18, 1.00, + 0.18, 0.18, 0.18, 1.00, +}; + +static float ozone_sidebar_gradient_bottom_dark[16] = { + 0.18, 0.18, 0.18, 1.00, + 0.18, 0.18, 0.18, 1.00, + 0.2, 0.2, 0.2, 1.00, + 0.2, 0.2, 0.2, 1.00, +}; + +typedef struct ozone_theme +{ + //Background color + uint32_t background_rgb; + float background_r; + float background_g; + float background_b; + + //Float colors for quads and icons + float header_footer_separator[16]; + float text[16]; + float selection[16]; + float selection_border[16]; + float entries_border[16]; + float entries_icon[16]; + float text_selected[16]; + + //RGBA colors for text + uint32_t text_rgba; + uint32_t text_selected_rgba; + uint32_t text_sublabel_rgba; + + //Sidebar color + float *sidebar_background; + float *sidebar_top_gradient; + float *sidebar_bottom_gradient; + + const char *name; +} ozone_theme_t; + +ozone_theme_t ozone_theme_light = { + COLOR_BACKGROUND(0xEBEBEB), + + COLOR_HEX_TO_FLOAT(0x2B2B2B, 1.00), + COLOR_HEX_TO_FLOAT(0x333333, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x10BEC5, 1.00), + COLOR_HEX_TO_FLOAT(0xCDCDCD, 1.00), + COLOR_HEX_TO_FLOAT(0x333333, 1.00), + COLOR_HEX_TO_FLOAT(0x374CFF, 1.00), + + 0x333333FF, + 0x374CFFFF, + 0x878787FF, + + ozone_sidebar_background_light, + ozone_sidebar_gradient_top_light, + ozone_sidebar_gradient_bottom_light, + + "light" +}; + +ozone_theme_t ozone_theme_dark = { + COLOR_BACKGROUND(0x2D2D2D), + + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x212227, 1.00), + COLOR_HEX_TO_FLOAT(0x2DA3CB, 1.00), + COLOR_HEX_TO_FLOAT(0x51514F, 1.00), + COLOR_HEX_TO_FLOAT(0xFFFFFF, 1.00), + COLOR_HEX_TO_FLOAT(0x00D9AE, 1.00), + + 0xFFFFFFFF, + 0x00FFC5FF, + 0x9F9FA1FF, + + ozone_sidebar_background_dark, + ozone_sidebar_gradient_top_dark, + ozone_sidebar_gradient_bottom_dark, + + "dark" +}; + +static ozone_theme_t *ozone_default_theme = &ozone_theme_light; + +typedef struct ozone_handle +{ + uint64_t frame_count; + + struct + { + font_data_t *footer; + font_data_t *title; + font_data_t *time; + font_data_t *entries_label; + font_data_t *entries_sublabel; + font_data_t *sidebar; + } fonts; + + struct + { + video_font_raster_block_t footer; + video_font_raster_block_t title; + video_font_raster_block_t time; + video_font_raster_block_t entries_label; + video_font_raster_block_t entries_sublabel; + video_font_raster_block_t sidebar; + } raster_blocks; + + menu_texture_item textures[OZONE_THEME_TEXTURE_LAST]; + menu_texture_item theme_textures[OZONE_THEME_TEXTURE_LAST]; + menu_texture_item icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LAST]; + menu_texture_item tab_textures[OZONE_TAB_TEXTURE_LAST]; + + char title[PATH_MAX_LENGTH]; + + char assets_path[PATH_MAX_LENGTH]; + char png_path[PATH_MAX_LENGTH]; + char icons_path[PATH_MAX_LENGTH]; + char tab_path[PATH_MAX_LENGTH]; + char theme_path[PATH_MAX_LENGTH]; + + uint8_t system_tab_end; + uint8_t tabs[OZONE_SYSTEM_TAB_LAST]; + + size_t categories_selection_ptr; //active tab id + size_t categories_active_idx_old; + + bool cursor_in_sidebar; + bool cursor_in_sidebar_old; + + struct + { + float cursor_alpha; + float scroll_y; + + float list_alpha; + } animations; + + bool fade_direction; //false = left to right, true = right to left + + size_t selection; //currently selected entry + size_t selection_old; //previously selected entry (for fancy animation) + size_t selection_old_list; + + unsigned entries_height; + + int depth; + + bool draw_sidebar; + float sidebar_offset; + + unsigned title_font_glyph_width; + unsigned entry_font_glyph_width; + + ozone_theme_t *theme; + + struct { + float selection_border[16]; + float selection[16]; + float entries_border[16]; + float entries_icon[16]; + } theme_dynamic; + + bool need_compute; + + file_list_t *selection_buf_old; + + unsigned action; + bool draw_old_list; + float scroll_old; + + bool want_horizontal_animation; +} ozone_handle_t; + +/* If you change this struct, also + change ozone_alloc_node and + ozone_copy_node */ +typedef struct ozone_node +{ + unsigned height; + unsigned position_y; +} ozone_node_t; + +static const char *ozone_entries_icon_texture_path(ozone_handle_t *ozone, unsigned id) +{ + char *icon_name; + + switch (id) + { + case OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU: +#if defined(HAVE_LAKKA) + icon_name = "lakka.png"; + break; +#else + icon_name = "retroarch.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_SETTINGS: + icon_name = "settings.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_HISTORY: + icon_name = "history.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES: + icon_name = "favorites.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE: + icon_name = "add-favorite.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MUSICS: + icon_name = "musics.png"; + break; +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + case OZONE_ENTRIES_ICONS_TEXTURE_MOVIES: + icon_name = "movies.png"; + break; +#endif +#ifdef HAVE_IMAGEVIEWER + case OZONE_ENTRIES_ICONS_TEXTURE_IMAGES: + icon_name = "images.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_SETTING: + icon_name = "setting.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING: + icon_name = "subsetting.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ARROW: + icon_name = "arrow.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RUN: + icon_name = "run.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CLOSE: + icon_name = "close.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RESUME: + icon_name = "resume.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CLOCK: + icon_name = "clock.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL: + icon_name = "battery-full.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING: + icon_name = "battery-charging.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_POINTER: + icon_name = "pointer.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE: + icon_name = "savestate.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE: + icon_name = "loadstate.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UNDO: + icon_name = "undo.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO: + icon_name = "core-infos.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_WIFI: + icon_name = "wifi.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS: + icon_name = "core-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS: + icon_name = "core-input-remapping-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS: + icon_name = "core-cheat-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS: + icon_name = "core-disk-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS: + icon_name = "core-shader-options.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST: + icon_name = "achievement-list.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT: + icon_name = "screenshot.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RELOAD: + icon_name = "reload.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RENAME: + icon_name = "rename.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FILE: + icon_name = "file.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FOLDER: + icon_name = "folder.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ZIP: + icon_name = "zip.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MUSIC: + icon_name = "music.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE: + icon_name = "favorites-content.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_IMAGE: + icon_name = "image.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MOVIE: + icon_name = "movie.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CORE: + icon_name = "core.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RDB: + icon_name = "database.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_CURSOR: + icon_name = "cursor.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_ON: + icon_name = "on.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SWITCH_OFF: + icon_name = "off.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ADD: + icon_name = "add.png"; + break; +#ifdef HAVE_NETWORKING + case OZONE_ENTRIES_ICONS_TEXTURE_NETPLAY: + icon_name = "netplay.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM: + icon_name = "menu_room.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN: + icon_name = "menu_room_lan.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY: + icon_name = "menu_room_relay.png"; + break; +#endif + case OZONE_ENTRIES_ICONS_TEXTURE_KEY: + icon_name = "key.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_KEY_HOVER: + icon_name = "key-hover.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE: + icon_name = "dialog-slice.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS: + icon_name = "menu_achievements.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_AUDIO: + icon_name = "menu_audio.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS: + icon_name = "menu_drivers.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_EXIT: + icon_name = "menu_exit.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP: + icon_name = "menu_frameskip.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_HELP: + icon_name = "menu_help.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INFO: + icon_name = "menu_info.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_INPUT: + icon_name = "Libretro - Pad.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LATENCY: + icon_name = "menu_latency.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_NETWORK: + icon_name = "menu_network.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_POWER: + icon_name = "menu_power.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_RECORD: + icon_name = "menu_record.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_SAVING: + icon_name = "menu_saving.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UPDATER: + icon_name = "menu_updater.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_VIDEO: + icon_name = "menu_video.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_MIXER: + icon_name = "menu_mixer.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_LOG: + icon_name = "menu_log.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OSD: + icon_name = "menu_osd.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_UI: + icon_name = "menu_ui.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_USER: + icon_name = "menu_user.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY: + icon_name = "menu_privacy.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST: + icon_name = "menu_playlist.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU: + icon_name = "menu_quickmenu.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_REWIND: + icon_name = "menu_rewind.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY: + icon_name = "menu_overlay.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE: + icon_name = "menu_override.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS: + icon_name = "menu_notifications.png"; + break; + case OZONE_ENTRIES_ICONS_TEXTURE_STREAM: + icon_name = "menu_stream.png"; + break; + } + + char icon_fullpath[255]; + + fill_pathname_join( + icon_fullpath, + ozone->icons_path, + icon_name, + sizeof(icon_fullpath) + ); + + if (!filestream_exists(icon_fullpath)) + { + return "subsetting.png"; + } + else + return icon_name; +} + +static unsigned ozone_entries_icon_get_id(ozone_handle_t *ozone, + enum msg_hash_enums enum_idx, unsigned type, bool active) +{ + switch (enum_idx) + { + case MENU_ENUM_LABEL_CORE_OPTIONS: + case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS; + case MENU_ENUM_LABEL_ADD_TO_FAVORITES: + case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: + return OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE; + case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: + return OZONE_ENTRIES_ICONS_TEXTURE_UNDO; + case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS; + case MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; + case MENU_ENUM_LABEL_DISK_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS; + case MENU_ENUM_LABEL_SHADER_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; + case MENU_ENUM_LABEL_ACHIEVEMENT_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST; + case MENU_ENUM_LABEL_ACHIEVEMENT_LIST_HARDCORE: + return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENT_LIST; + case MENU_ENUM_LABEL_SAVE_STATE: + return OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE; + case MENU_ENUM_LABEL_LOAD_STATE: + return OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE; + case MENU_ENUM_LABEL_PARENT_DIRECTORY: + case MENU_ENUM_LABEL_UNDO_LOAD_STATE: + case MENU_ENUM_LABEL_UNDO_SAVE_STATE: + return OZONE_ENTRIES_ICONS_TEXTURE_UNDO; + case MENU_ENUM_LABEL_TAKE_SCREENSHOT: + return OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT; + case MENU_ENUM_LABEL_DELETE_ENTRY: + return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; + case MENU_ENUM_LABEL_RESTART_CONTENT: + return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; + case MENU_ENUM_LABEL_RENAME_ENTRY: + return OZONE_ENTRIES_ICONS_TEXTURE_RENAME; + case MENU_ENUM_LABEL_RESUME_CONTENT: + return OZONE_ENTRIES_ICONS_TEXTURE_RESUME; + case MENU_ENUM_LABEL_FAVORITES: + case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; + case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR: + return OZONE_ENTRIES_ICONS_TEXTURE_RDB; + + + /* Menu collection submenus*/ + case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_ZIP; + case MENU_ENUM_LABEL_GOTO_FAVORITES: + return OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE; + case MENU_ENUM_LABEL_GOTO_IMAGES: + return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; + case MENU_ENUM_LABEL_GOTO_VIDEO: + return OZONE_ENTRIES_ICONS_TEXTURE_MOVIE; + case MENU_ENUM_LABEL_GOTO_MUSIC: + return OZONE_ENTRIES_ICONS_TEXTURE_MUSIC; + case MENU_ENUM_LABEL_CONTENT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_ASSETS: + return OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU; + case MENU_ENUM_LABEL_START_CORE: + return OZONE_ENTRIES_ICONS_TEXTURE_RUN; + case MENU_ENUM_LABEL_CORE_LIST: + case MENU_ENUM_LABEL_CORE_SETTINGS: + case MENU_ENUM_LABEL_CORE_UPDATER_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE; + case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: + case MENU_ENUM_LABEL_SCAN_FILE: + return OZONE_ENTRIES_ICONS_TEXTURE_FILE; + case MENU_ENUM_LABEL_ONLINE_UPDATER: + case MENU_ENUM_LABEL_UPDATER_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_UPDATER; + case MENU_ENUM_LABEL_UPDATE_LAKKA: + return OZONE_ENTRIES_ICONS_TEXTURE_MAIN_MENU; + case MENU_ENUM_LABEL_UPDATE_CHEATS: + return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; + case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; + case MENU_ENUM_LABEL_UPDATE_OVERLAYS: + case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_OVERLAY; + case MENU_ENUM_LABEL_UPDATE_CG_SHADERS: + case MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS: + case MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS: + return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; + case MENU_ENUM_LABEL_INFORMATION: + case MENU_ENUM_LABEL_INFORMATION_LIST: + case MENU_ENUM_LABEL_SYSTEM_INFORMATION: + case MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES: + return OZONE_ENTRIES_ICONS_TEXTURE_INFO; + case MENU_ENUM_LABEL_UPDATE_DATABASES: + case MENU_ENUM_LABEL_DATABASE_MANAGER_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_RDB; + case MENU_ENUM_LABEL_CURSOR_MANAGER_LIST: + return OZONE_ENTRIES_ICONS_TEXTURE_CURSOR; + case MENU_ENUM_LABEL_HELP_LIST: + case MENU_ENUM_LABEL_HELP_CONTROLS: + case MENU_ENUM_LABEL_HELP_LOADING_CONTENT: + case MENU_ENUM_LABEL_HELP_SCANNING_CONTENT: + case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: + case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: + case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + return OZONE_ENTRIES_ICONS_TEXTURE_HELP; + case MENU_ENUM_LABEL_QUIT_RETROARCH: + return OZONE_ENTRIES_ICONS_TEXTURE_EXIT; + /* Settings icons*/ + case MENU_ENUM_LABEL_DRIVER_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS; + case MENU_ENUM_LABEL_VIDEO_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_VIDEO; + case MENU_ENUM_LABEL_AUDIO_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_AUDIO; + case MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_MIXER; + case MENU_ENUM_LABEL_INPUT_SETTINGS: + case MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES: + return OZONE_ENTRIES_ICONS_TEXTURE_INPUT; + case MENU_ENUM_LABEL_LATENCY_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_LATENCY; + case MENU_ENUM_LABEL_SAVING_SETTINGS: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR: + case MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME: + return OZONE_ENTRIES_ICONS_TEXTURE_SAVING; + case MENU_ENUM_LABEL_LOGGING_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_LOG; + case MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP; + case MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING: + case MENU_ENUM_LABEL_RECORDING_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_RECORD; + case MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING: + return OZONE_ENTRIES_ICONS_TEXTURE_STREAM; + case MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING: + case MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING: + return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; + case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_OSD; + case MENU_ENUM_LABEL_SHOW_WIMP: + case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_UI; +#ifdef HAVE_LAKKA_SWITCH + case MENU_ENUM_LABEL_SWITCH_GPU_PROFILE: + case MENU_ENUM_LABEL_SWITCH_CPU_PROFILE: +#endif + case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_POWER; + case MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS; + case MENU_ENUM_LABEL_NETWORK_INFORMATION: + case MENU_ENUM_LABEL_NETWORK_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_NETWORK; + case MENU_ENUM_LABEL_PLAYLIST_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST; + case MENU_ENUM_LABEL_USER_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_USER; + case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: + case MENU_ENUM_LABEL_SCAN_DIRECTORY: + return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; + case MENU_ENUM_LABEL_PRIVACY_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_PRIVACY; + + case MENU_ENUM_LABEL_REWIND_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_REWIND; + case MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_OVERRIDE; + case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: + return OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS; +#ifdef HAVE_NETWORKING + case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: + return OZONE_ENTRIES_ICONS_TEXTURE_RUN; + case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: + return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; + case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: + return OZONE_ENTRIES_ICONS_TEXTURE_ROOM; + case MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS: + return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; +#endif + default: + break; + } + + switch(type) + { + case FILE_TYPE_DIRECTORY: + return OZONE_ENTRIES_ICONS_TEXTURE_FOLDER; + case FILE_TYPE_PLAIN: + case FILE_TYPE_IN_CARCHIVE: + return OZONE_ENTRIES_ICONS_TEXTURE_FILE; + case FILE_TYPE_RPL_ENTRY: + return OZONE_ENTRIES_ICONS_TEXTURE_FILE; + case FILE_TYPE_SHADER: + case FILE_TYPE_SHADER_PRESET: + return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; + case FILE_TYPE_CARCHIVE: + return OZONE_ENTRIES_ICONS_TEXTURE_ZIP; + case FILE_TYPE_MUSIC: + return OZONE_ENTRIES_ICONS_TEXTURE_MUSIC; + case FILE_TYPE_IMAGE: + case FILE_TYPE_IMAGEVIEWER: + return OZONE_ENTRIES_ICONS_TEXTURE_IMAGE; + case FILE_TYPE_MOVIE: + return OZONE_ENTRIES_ICONS_TEXTURE_MOVIE; + case FILE_TYPE_CORE: + case FILE_TYPE_DIRECT_LOAD: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE; + case FILE_TYPE_RDB: + return OZONE_ENTRIES_ICONS_TEXTURE_RDB; + case FILE_TYPE_CURSOR: + return OZONE_ENTRIES_ICONS_TEXTURE_CURSOR; + case FILE_TYPE_PLAYLIST_ENTRY: + case MENU_SETTING_ACTION_RUN: + return OZONE_ENTRIES_ICONS_TEXTURE_RUN; + case MENU_SETTING_ACTION_CLOSE: + return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; + case MENU_SETTING_ACTION_SAVESTATE: + return OZONE_ENTRIES_ICONS_TEXTURE_SAVESTATE; + case MENU_SETTING_ACTION_LOADSTATE: + return OZONE_ENTRIES_ICONS_TEXTURE_LOADSTATE; + case FILE_TYPE_RDB_ENTRY: + case MENU_SETTING_ACTION_CORE_INFORMATION: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; + case MENU_SETTING_ACTION_CORE_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE_OPTIONS; + case MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS; + case MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS; + case MENU_SETTING_ACTION_CORE_DISK_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_DISK_OPTIONS; + case MENU_SETTING_ACTION_CORE_SHADER_OPTIONS: + return OZONE_ENTRIES_ICONS_TEXTURE_SHADER_OPTIONS; + case MENU_SETTING_ACTION_SCREENSHOT: + return OZONE_ENTRIES_ICONS_TEXTURE_SCREENSHOT; + case MENU_SETTING_ACTION_DELETE_ENTRY: + return OZONE_ENTRIES_ICONS_TEXTURE_CLOSE; + case MENU_SETTING_ACTION_RESET: + return OZONE_ENTRIES_ICONS_TEXTURE_RELOAD; + case MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS: + return OZONE_ENTRIES_ICONS_TEXTURE_RESUME; + case MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS: + return OZONE_ENTRIES_ICONS_TEXTURE_RUN; + + case MENU_SETTING_GROUP: +#ifdef HAVE_LAKKA_SWITCH + case MENU_SET_SWITCH_BRIGHTNESS: +#endif + return OZONE_ENTRIES_ICONS_TEXTURE_SETTING; + case MENU_INFO_MESSAGE: + return OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; + case MENU_WIFI: + return OZONE_ENTRIES_ICONS_TEXTURE_WIFI; +#ifdef HAVE_NETWORKING + case MENU_ROOM: + return OZONE_ENTRIES_ICONS_TEXTURE_ROOM; + case MENU_ROOM_LAN: + return OZONE_ENTRIES_ICONS_TEXTURE_ROOM_LAN; + case MENU_ROOM_RELAY: + return OZONE_ENTRIES_ICONS_TEXTURE_ROOM_RELAY; +#endif + case MENU_SETTING_ACTION: + if (ozone->depth <= 3) + return OZONE_ENTRIES_ICONS_TEXTURE_SETTING; + default: + return OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING; + } + +#ifdef HAVE_CHEEVOS + if ( + (type >= MENU_SETTINGS_CHEEVOS_START) && + (type < MENU_SETTINGS_NETPLAY_ROOMS_START) + ) + { + int new_id = type - MENU_SETTINGS_CHEEVOS_START; + if (get_badge_texture(new_id) != 0) + return get_badge_texture(new_id); + /* Should be replaced with placeholder badge icon. */ + return OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING; + } +#endif + + return OZONE_ENTRIES_ICONS_TEXTURE_SUBSETTING; +} + +static void ozone_draw_text( + video_frame_info_t *video_info, + ozone_handle_t *ozone, + const char *str, float x, + float y, + enum text_alignment text_align, + unsigned width, unsigned height, font_data_t* font, + uint32_t color) +{ + if ((color & 0x000000FF) == 0) + return; + + menu_display_draw_text(font, str, x, y, + width, height, color, text_align, 1.0f, + false, + 1.0); +} + +static void ozone_set_theme(ozone_handle_t *ozone, ozone_theme_t *theme) +{ + ozone->theme = theme; + + memcpy(ozone->theme_dynamic.selection_border, ozone->theme->selection_border, sizeof(ozone->theme_dynamic.selection_border)); + memcpy(ozone->theme_dynamic.selection, ozone->theme->selection, sizeof(ozone->theme_dynamic.selection)); + memcpy(ozone->theme_dynamic.entries_border, ozone->theme->entries_border, sizeof(ozone->theme_dynamic.entries_border)); + memcpy(ozone->theme_dynamic.entries_icon, ozone->theme->entries_icon, sizeof(ozone->theme_dynamic.entries_icon)); +} + +static void *ozone_init(void **userdata, bool video_is_threaded) +{ + unsigned width, height; + ozone_handle_t *ozone = NULL; + settings_t *settings = config_get_ptr(); + menu_handle_t *menu = (menu_handle_t*)calloc(1, sizeof(*menu)); + + if (!menu) + goto error; + + if (!menu_display_init_first_driver(video_is_threaded)) + goto error; + + video_driver_get_size(&width, &height); + + ozone = (ozone_handle_t*)calloc(1, sizeof(ozone_handle_t)); + + if (!ozone) + goto error; + + *userdata = ozone; + ozone->selection_buf_old = (file_list_t*)calloc(1, sizeof(file_list_t)); + ozone->want_horizontal_animation = false; + + ozone->system_tab_end = 0; + ozone->tabs[ozone->system_tab_end] = OZONE_SYSTEM_TAB_MAIN; + if (settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_SETTINGS; + if (settings->bools.menu_content_show_favorites) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_FAVORITES; + if (settings->bools.menu_content_show_history) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_HISTORY; +#ifdef HAVE_IMAGEVIEWERe + if (settings->bools.menu_content_show_images) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_IMAGES; +#endif + if (settings->bools.menu_content_show_music) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_MUSIC; +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + if (settings->bools.menu_content_show_video) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_VIDEO; +#endif +#ifdef HAVE_NETWORKING + if (settings->bools.menu_content_show_netplay) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_NETPLAY; +#endif +#ifdef HAVE_LIBRETRODB + if (settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_ADD; +#endif + + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + + menu_display_set_width(width); + menu_display_set_height(height); + + menu_display_allocate_white_texture(); + + //Theme + //TODO Add theme override in settings +#ifdef HAVE_LIBNX + ColorSetId theme; + Result rc = setsysInitialize(); + + if (R_SUCCEEDED(rc)) + { + setsysGetColorSetId(&theme); + ozone_set_theme(ozone, theme == ColorSetId_Dark ? &ozone_theme_dark : &ozone_theme_light); + setsysExit(); + } + else + { + ozone_set_theme(ozone, ozone_default_theme); + } +#else + ozone_set_theme(ozone, ozone_default_theme); +#endif + + ozone->need_compute = false; + ozone->animations.scroll_y = 0.0f; + + //Assets path + fill_pathname_join( + ozone->assets_path, + settings->paths.directory_assets, + "ozone", + sizeof(ozone->assets_path) + ); + + //PNG path + fill_pathname_join( + ozone->png_path, + ozone->assets_path, + "png", + sizeof(ozone->png_path) + ); + + //Icons path + fill_pathname_join( + ozone->icons_path, + ozone->png_path, + "icons", + sizeof(ozone->icons_path) + ); + + //Sidebar path + fill_pathname_join( + ozone->tab_path, + ozone->png_path, + "sidebar", + sizeof(ozone->tab_path) + ); + + //Theme path + fill_pathname_join( + ozone->theme_path, + ozone->png_path, + ozone->theme->name, + sizeof(ozone->theme_path) + ); + + return menu; + +error: + if (menu) + free(menu); + + return NULL; +} + +static void ozone_free_node(ozone_node_t *node) +{ + if (!node) + return; + + free(node); +} + +static void ozone_free_list_nodes(file_list_t *list, bool actiondata) +{ + unsigned i, size = (unsigned)file_list_get_size(list); + + for (i = 0; i < size; ++i) + { + ozone_free_node((ozone_node_t*)file_list_get_userdata_at_offset(list, i)); + + /* file_list_set_userdata() doesn't accept NULL */ + list->list[i].userdata = NULL; + + if (actiondata) + file_list_free_actiondata(list, i); + } +} + +static void ozone_free(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (ozone) + { + video_coord_array_free(&ozone->raster_blocks.footer.carr); + video_coord_array_free(&ozone->raster_blocks.title.carr); + video_coord_array_free(&ozone->raster_blocks.time.carr); + video_coord_array_free(&ozone->raster_blocks.entries_label.carr); + video_coord_array_free(&ozone->raster_blocks.entries_sublabel.carr); + video_coord_array_free(&ozone->raster_blocks.sidebar.carr); + + font_driver_bind_block(NULL, NULL); + + if (ozone->selection_buf_old) + { + ozone_free_list_nodes(ozone->selection_buf_old, false); + file_list_free(ozone->selection_buf_old); + } + } +} + +static void ozone_context_reset(void *data, bool is_threaded) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (ozone) + { + //Fonts init + char font_path[PATH_MAX_LENGTH]; + + fill_pathname_join(font_path, ozone->assets_path, "Inter-UI-Regular.ttf", sizeof(font_path)); + ozone->fonts.footer = menu_display_font_file(font_path, FONT_SIZE_FOOTER, is_threaded); + ozone->fonts.entries_label = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_LABEL, is_threaded); + ozone->fonts.entries_sublabel = menu_display_font_file(font_path, FONT_SIZE_ENTRIES_SUBLABEL, is_threaded); + ozone->fonts.time = menu_display_font_file(font_path, FONT_SIZE_TIME, is_threaded); + ozone->fonts.sidebar = menu_display_font_file(font_path, FONT_SIZE_SIDEBAR, is_threaded); + + fill_pathname_join(font_path, ozone->assets_path, "Inter-UI-Bold.ttf", sizeof(font_path)); + ozone->fonts.title = menu_display_font_file(font_path, FONT_SIZE_TITLE, is_threaded); + + ozone->title_font_glyph_width = font_driver_get_message_width(ozone->fonts.title, "a", 1, 1); + ozone->entry_font_glyph_width = font_driver_get_message_width(ozone->fonts.entries_label, "a", 1, 1); + + //Textures init + for (int i = 0; i < OZONE_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strcpy(filename, OZONE_TEXTURES_FILES[i]); + strcat(filename, ".png"); + + menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR); + } + + //Sidebar textures + for (int i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strcpy(filename, OZONE_TAB_TEXTURES_FILES[i]); + strcat(filename, ".png"); + + menu_display_reset_textures_list(filename, ozone->tab_path, &ozone->tab_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR); + } + + //Theme textures + for (int i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) + { + char filename[PATH_MAX_LENGTH]; + strcpy(filename, OZONE_THEME_TEXTURES_FILES[i]); + strcat(filename, ".png"); + + menu_display_reset_textures_list(filename, ozone->theme_path, &ozone->theme_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR); + } + + //Icons textures init + for (int i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) + { + menu_display_reset_textures_list(ozone_entries_icon_texture_path(ozone, i), ozone->icons_path, &ozone->icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR); + } + + menu_display_allocate_white_texture(); + + //State reset + ozone->frame_count = 0; + ozone->fade_direction = false; + ozone->cursor_in_sidebar = false; + ozone->cursor_in_sidebar_old = false; + ozone->draw_sidebar = true; + ozone->sidebar_offset = 0; + ozone->draw_old_list = false; + + //Animations + ozone->animations.cursor_alpha = 1.0f; + ozone->animations.scroll_y = 0.0f; + ozone->animations.list_alpha = 1.0f; + } +} + +static void ozone_collapse_end(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone->draw_sidebar = false; +} + +static void ozone_context_destroy(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return; + + //Theme + for (int i = 0; i < OZONE_THEME_TEXTURE_LAST; i++) + { + video_driver_texture_unload(&ozone->theme_textures[i]); + } + + //Icons + for (int i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) + { + video_driver_texture_unload(&ozone->icons_textures[i]); + } + + //Textures + for (int i = 0; i < OZONE_TEXTURE_LAST; i++) + { + video_driver_texture_unload(&ozone->textures[i]); + } + + //Icons + for (int i = 0; i < OZONE_TAB_TEXTURE_LAST; i++) + { + video_driver_texture_unload(&ozone->tab_textures[i]); + } + + video_driver_texture_unload(&menu_display_white_texture); + + menu_display_font_free(ozone->fonts.footer); + menu_display_font_free(ozone->fonts.title); + menu_display_font_free(ozone->fonts.time); + menu_display_font_free(ozone->fonts.entries_label); + menu_display_font_free(ozone->fonts.entries_sublabel); + menu_display_font_free(ozone->fonts.sidebar); + + ozone->fonts.footer = NULL; + ozone->fonts.title = NULL; + ozone->fonts.time = NULL; + ozone->fonts.entries_label = NULL; + ozone->fonts.entries_sublabel = NULL; + ozone->fonts.sidebar = NULL; +} + +static void *ozone_list_get_entry(void *data, + enum menu_list_type type, unsigned i) +{ + size_t list_size = 0; + + switch (type) + { + case MENU_LIST_PLAIN: + { + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + list_size = menu_entries_get_stack_size(0); + if (i < list_size) + return (void*)&menu_stack->list[i]; + } + break; + case MENU_LIST_HORIZONTAL: + //TODO Sidebar + break; + default: + break; + } + + return NULL; +} + +static unsigned ozone_get_system_tab(ozone_handle_t *ozone, unsigned i) +{ + if (i <= ozone->system_tab_end) + { + return ozone->tabs[i]; + } + return UINT_MAX; +} + +static size_t ozone_list_get_size(void *data, enum menu_list_type type) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return 0; + + switch (type) + { + case MENU_LIST_PLAIN: + return menu_entries_get_stack_size(0); + case MENU_LIST_HORIZONTAL: + //TODO Return horizontal list size + return 0; + case MENU_LIST_TABS: + return ozone->system_tab_end; + } + + return 0; +} + +static int ozone_list_push(void *data, void *userdata, + menu_displaylist_info_t *info, unsigned type) +{ + menu_displaylist_ctx_parse_entry_t entry; + int ret = -1; + unsigned i = 0; + core_info_list_t *list = NULL; + menu_handle_t *menu = (menu_handle_t*)data; + + switch (type) + { + case DISPLAYLIST_LOAD_CONTENT_LIST: + { + settings_t *settings = config_get_ptr(); + + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), + MENU_ENUM_LABEL_FAVORITES, + MENU_SETTING_ACTION, 0, 0); + + core_info_get_list(&list); + if (core_info_list_num_info_files(list)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0); + } + +#ifdef HAVE_LIBRETRODB + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST), + MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST, + MENU_SETTING_ACTION, 0, 0); +#endif + + if (frontend_driver_parse_drive_list(info->list, true) != 0) + menu_entries_append_enum(info->list, "/", + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, + MENU_SETTING_ACTION, 0, 0); + + if (!settings->bools.kiosk_mode_enable) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0); + } + + info->need_push = true; + info->need_refresh = true; + ret = 0; + } + break; + case DISPLAYLIST_MAIN_MENU: + { + settings_t *settings = config_get_ptr(); + rarch_system_info_t *system = runloop_get_system_info(); + menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); + + entry.data = menu; + entry.info = info; + entry.parse_type = PARSE_ACTION; + entry.add_empty_entry = false; + + if (!string_is_empty(system->info.library_name) && + !string_is_equal(system->info.library_name, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE))) + { + entry.enum_idx = MENU_ENUM_LABEL_CONTENT_SETTINGS; + menu_displaylist_setting(&entry); + } + + if (system->load_no_content) + { + entry.enum_idx = MENU_ENUM_LABEL_START_CORE; + menu_displaylist_setting(&entry); + } + +#ifndef HAVE_DYNAMIC + if (frontend_driver_has_fork()) +#endif + { + if (settings->bools.menu_show_load_core) + { + entry.enum_idx = MENU_ENUM_LABEL_CORE_LIST; + menu_displaylist_setting(&entry); + } + } + + if (settings->bools.menu_show_load_content) + { + const struct retro_subsystem_info* subsystem = NULL; + + entry.enum_idx = MENU_ENUM_LABEL_LOAD_CONTENT_LIST; + menu_displaylist_setting(&entry); + + subsystem = system->subsystem.data; + + if (subsystem) + { + for (i = 0; i < (unsigned)system->subsystem.size; i++, subsystem++) + { + char s[PATH_MAX_LENGTH]; + if (content_get_subsystem() == i) + { + if (content_get_subsystem_rom_id() < subsystem->num_roms) + { + snprintf(s, sizeof(s), + "Load %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), + MENU_ENUM_LABEL_SUBSYSTEM_ADD, + MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); + } + else + { + snprintf(s, sizeof(s), + "Start %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_LOAD), + MENU_ENUM_LABEL_SUBSYSTEM_LOAD, + MENU_SETTINGS_SUBSYSTEM_LOAD, 0, 0); + } + } + else + { + snprintf(s, sizeof(s), + "Load %s %s", + subsystem->desc, + i == content_get_subsystem() + ? "\u2605" : " "); + menu_entries_append_enum(info->list, + s, + msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD), + MENU_ENUM_LABEL_SUBSYSTEM_ADD, + MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0); + } + } + } + } + + entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; + menu_displaylist_setting(&entry); +#ifdef HAVE_QT + if (settings->bools.desktop_menu_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_SHOW_WIMP; + menu_displaylist_setting(&entry); + } +#endif +#if defined(HAVE_NETWORKING) + if (settings->bools.menu_show_online_updater && !settings->bools.kiosk_mode_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_ONLINE_UPDATER; + menu_displaylist_setting(&entry); + } +#endif + if (!settings->bools.menu_content_show_settings && !string_is_empty(settings->paths.menu_content_show_settings_password)) + { + entry.enum_idx = MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS; + menu_displaylist_setting(&entry); + } + + if (settings->bools.kiosk_mode_enable && !string_is_empty(settings->paths.kiosk_mode_password)) + { + entry.enum_idx = MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_information) + { + entry.enum_idx = MENU_ENUM_LABEL_INFORMATION_LIST; + menu_displaylist_setting(&entry); + } + +#ifdef HAVE_LAKKA_SWITCH + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_CPU_PROFILE; + menu_displaylist_setting(&entry); + + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_GPU_PROFILE; + menu_displaylist_setting(&entry); + + entry.enum_idx = MENU_ENUM_LABEL_SWITCH_BACKLIGHT_CONTROL; + menu_displaylist_setting(&entry); +#endif + +#ifndef HAVE_DYNAMIC + entry.enum_idx = MENU_ENUM_LABEL_RESTART_RETROARCH; + menu_displaylist_setting(&entry); +#endif + + if (settings->bools.menu_show_configurations && !settings->bools.kiosk_mode_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_CONFIGURATIONS_LIST; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_help) + { + entry.enum_idx = MENU_ENUM_LABEL_HELP_LIST; + menu_displaylist_setting(&entry); + } + +#if !defined(IOS) + if (settings->bools.menu_show_quit_retroarch) + { + entry.enum_idx = MENU_ENUM_LABEL_QUIT_RETROARCH; + menu_displaylist_setting(&entry); + } +#endif + + if (settings->bools.menu_show_reboot) + { + entry.enum_idx = MENU_ENUM_LABEL_REBOOT; + menu_displaylist_setting(&entry); + } + + if (settings->bools.menu_show_shutdown) + { + entry.enum_idx = MENU_ENUM_LABEL_SHUTDOWN; + menu_displaylist_setting(&entry); + } + + info->need_push = true; + ret = 0; + } + break; + } + return ret; +} + +static size_t ozone_list_get_selection(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + + if (!ozone) + return 0; + + return ozone->categories_selection_ptr; +} + +static void ozone_list_clear(file_list_t *list) +{ + menu_animation_ctx_tag tag = (uintptr_t)list; + menu_animation_kill_by_tag(&tag); + + size_t i; + size_t size = list ? list->size : 0; + + ozone_free_list_nodes(list, false); +} + +static void ozone_list_free(file_list_t *list, size_t a, size_t b) +{ + ozone_list_clear(list); +} + +/* Compute new scroll position + * If the center of the currently selected entry is not in the middle + * And if we can scroll so that it's in the middle + * Then scroll + */ +static void ozone_update_scroll(ozone_handle_t *ozone, bool allow_animation, ozone_node_t *node) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_animation_ctx_tag tag = (uintptr_t) selection_buf; + menu_animation_ctx_entry_t entry; + float new_scroll = 0; + + unsigned video_info_height; + video_driver_get_size(NULL, &video_info_height); + + float currentSelectionMiddleOnScreen = ENTRIES_START_Y + ozone->animations.scroll_y + node->position_y + node->height/2; + float bottom_boundary = video_info_height - 87 - 78; + float entries_middle = video_info_height/2; + + if (currentSelectionMiddleOnScreen != entries_middle) + { + new_scroll = ozone->animations.scroll_y - (currentSelectionMiddleOnScreen - entries_middle); + } + + if (new_scroll + ozone->entries_height < bottom_boundary) + new_scroll = -(78 + ozone->entries_height - bottom_boundary); + + if (new_scroll > 0) + new_scroll = 0; + + if (allow_animation) + { + //Cursor animation + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + //Scroll animation + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.scroll_y; + entry.tag = tag; + entry.target_value = new_scroll; + entry.userdata = NULL; + + menu_animation_push(&entry); + } + else + { + ozone->selection_old = ozone->selection; + ozone->animations.cursor_alpha = 1.0f; + ozone->animations.scroll_y = new_scroll; + } +} + +static void ozone_compute_entries_position(ozone_handle_t *ozone) +{ + //Compute entries height and adjust scrolling if needed + size_t i; + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + size_t entries_end = menu_entries_get_size(); + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + + unsigned video_info_height; + video_driver_get_size(NULL, &video_info_height); + + ozone->entries_height = 0; + + for (i = 0; i < entries_end; i++) + { + //Entry + menu_entry_t entry; + char entry_value[255]; + + entry_value[0] = '\0'; + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, (unsigned)i, NULL, true); + menu_entry_get_value(&entry, entry_value, sizeof(entry_value)); + + //Cache node + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + if (!node) + continue; + + node->height = (entry.sublabel ? 100 : 60-8); + node->position_y = ozone->entries_height; + + ozone->entries_height += node->height; + + menu_entry_free(&entry); + } + + //Update scrolling + ozone->selection = menu_navigation_get_selection(); + ozone_update_scroll(ozone, false, (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, ozone->selection)); +} + +static void ozone_render(void *data, bool is_idle) +{ + size_t i; + unsigned end = (unsigned)menu_entries_get_size(); + menu_animation_ctx_delta_t delta; + + if (!data) + return; + + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (ozone->need_compute) + { + ozone_compute_entries_position(ozone); + ozone->need_compute = false; + } + + ozone->selection = menu_navigation_get_selection(); + + delta.current = menu_animation_get_delta_time(); + + if (menu_animation_get_ideal_delta_time(&delta)) + menu_animation_update(delta.ideal); + + //TODO Handle pointer & mouse + + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + if (i >= end) + { + i = 0; + menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &i); + } + + menu_animation_ctl(MENU_ANIMATION_CTL_CLEAR_ACTIVE, NULL); +} + +static void ozone_draw_icon( + video_frame_info_t *video_info, + unsigned icon_width, + unsigned icon_height, + uintptr_t texture, + float x, float y, + unsigned width, unsigned height, + float rotation, float scale_factor, + float *color) +{ + menu_display_ctx_rotate_draw_t rotate_draw; + menu_display_ctx_draw_t draw; + struct video_coords coords; + math_matrix_4x4 mymat; + + rotate_draw.matrix = &mymat; + rotate_draw.rotation = rotation; + rotate_draw.scale_x = scale_factor; + rotate_draw.scale_y = scale_factor; + rotate_draw.scale_z = 1; + rotate_draw.scale_enable = true; + + menu_display_rotate_z(&rotate_draw, video_info); + + coords.vertices = 4; + coords.vertex = NULL; + coords.tex_coord = NULL; + coords.lut_tex_coord = NULL; + coords.color = color ? (const float*)color : ozone_pure_white; + + draw.x = x; + draw.y = height - y - icon_height; + draw.width = icon_width; + draw.height = icon_height; + draw.scale_factor = scale_factor; + draw.rotation = rotation; + draw.coords = &coords; + draw.matrix_data = &mymat; + draw.texture = texture; + draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP; + draw.pipeline.id = 0; + + menu_display_draw(&draw, video_info); +} + +static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_info) +{ + //Separator + menu_display_draw_quad(video_info, 30, 87, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); + + //Title + char title[255]; + + menu_animation_ctx_ticker_t ticker; + + ticker.s = title; + ticker.len = (video_info->width - 128 - 47 - 130) / ozone->title_font_glyph_width; + ticker.idx = ozone->frame_count / 20; + ticker.str = ozone->title; + ticker.selected = true; + + menu_animation_ticker(&ticker); + + ozone_draw_text(video_info, ozone, title, 128, 20 + FONT_SIZE_TITLE, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.title, ozone->theme->text_rgba); + + //Icon + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_RETROARCH], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + menu_display_blend_end(video_info); + + //Timedate + if (video_info->timedate_enable) + { + menu_display_ctx_datetime_t datetime; + char timedate[255]; + + timedate[0] = '\0'; + + datetime.s = timedate; + datetime.time_mode = 4; + datetime.len = sizeof(timedate); + + menu_display_timedate(&datetime); + + ozone_draw_text(video_info, ozone, timedate, video_info->width - 60, 30 + FONT_SIZE_TIME, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba); + } +} + +static void ozone_color_alpha(float *color, float alpha) +{ + color[3] = color[7] = color[11] = color[15] = alpha; +} + +static void ozone_draw_footer(ozone_handle_t *ozone, video_frame_info_t *video_info, settings_t *settings) +{ + //Separator + menu_display_draw_quad(video_info, 23, video_info->height - 78, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); + + //Core title or Switch icon + char core_title[255]; + if (settings->bools.menu_core_enable && menu_entries_get_core_title(core_title, sizeof(core_title)) == 0) + { + ozone_draw_text(video_info, ozone, core_title, 59, video_info->height - 49 + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba); + } + else + { + ozone_draw_icon(video_info, 69, 30, ozone->theme_textures[OZONE_THEME_TEXTURE_SWITCH], 59, video_info->height - 52, video_info->width,video_info->height, 0, 1, NULL); + } + + //Buttons + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 25, 25, ozone->theme_textures[OZONE_THEME_TEXTURE_BUTTON_B], video_info->width - 251, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + ozone_draw_icon(video_info, 25, 25, ozone->theme_textures[OZONE_THEME_TEXTURE_BUTTON_A], video_info->width - 133, video_info->height - 49, video_info->width,video_info->height, 0, 1, NULL); + menu_display_blend_end(video_info); + + ozone_draw_text(video_info, ozone, "Back", video_info->width - 215, video_info->height - 49 + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba); + ozone_draw_text(video_info, ozone, "OK", video_info->width - 96, video_info->height - 49 + FONT_SIZE_FOOTER, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.footer, ozone->theme->text_rgba); + + menu_display_blend_end(video_info); +} + +//TODO Reduce sidebar width ? + +static void ozone_draw_cursor(ozone_handle_t *ozone, video_frame_info_t *video_info, unsigned x_offset, unsigned entry_width, size_t y, float alpha) +{ + ozone_color_alpha(ozone->theme_dynamic.selection_border, alpha); + ozone_color_alpha(ozone->theme_dynamic.selection, alpha); + + //Fill + menu_display_draw_quad(video_info, x_offset, y, entry_width, 70 - 10 - 10 - 3, video_info->width, video_info->height, ozone->theme_dynamic.selection); + + //Borders (can't do one single quad because of alpha) + menu_display_draw_quad(video_info, x_offset -3, y - 3, entry_width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + menu_display_draw_quad(video_info, x_offset -3, y + 70 - 10 - 10 - 3, entry_width + 6, 3, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + menu_display_draw_quad(video_info, x_offset -3, y, 3, 70 - 10 - 3 - 6 - 4, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); + menu_display_draw_quad(video_info, x_offset + entry_width, y, 3, 70 - 10 - 3 - 6 - 4, video_info->width, video_info->height, ozone->theme_dynamic.selection_border); +} + +static void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info) +{ + if (!ozone->draw_sidebar) + return; + + menu_display_scissor_begin(video_info, 0, 87, 408, video_info->height - 87 - 78); + + //Background + unsigned sidebar_height = video_info->height - 87 - 55 - 78; + + menu_display_draw_quad(video_info, ozone->sidebar_offset, 88, 408, 55/2, video_info->width, video_info->height, ozone->theme->sidebar_top_gradient); + menu_display_draw_quad(video_info, ozone->sidebar_offset, 88 + 55/2, 408, sidebar_height, video_info->width, video_info->height, ozone->theme->sidebar_background); + menu_display_draw_quad(video_info, ozone->sidebar_offset, 55*2 + sidebar_height, 408, 55/2 + 1, video_info->width, video_info->height, ozone->theme->sidebar_bottom_gradient); + + //Tabs + //TODO Scroll + unsigned selection_y = 0; + unsigned selection_old_y = 0; + + //y offset computation + size_t y = ENTRIES_START_Y - 10; + for (int i = 0; i < OZONE_SYSTEM_TAB_LAST; i++) + { + if (i == ozone->categories_selection_ptr) + selection_y = y; + if (i == ozone->categories_active_idx_old) + selection_old_y = y; + y += 65; + } + + //Cursor + if (ozone->cursor_in_sidebar) + ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408-81, selection_y-8, ozone->animations.cursor_alpha); + + if (ozone->cursor_in_sidebar_old && ozone->categories_selection_ptr != ozone->categories_active_idx_old) + ozone_draw_cursor(ozone, video_info, ozone->sidebar_offset + 41, 408-81, selection_old_y-8, 1-ozone->animations.cursor_alpha); + + //Icons + y = ENTRIES_START_Y - 10; + menu_display_blend_begin(video_info); + //TODO Cache all the tabs data + for (int i = 0; i < OZONE_SYSTEM_TAB_LAST; i++) + { + bool selected = (ozone->categories_selection_ptr == i); + unsigned icon = ozone_system_tabs_icons[i]; + + //Icon + ozone_draw_icon(video_info, 40, 40, ozone->tab_textures[icon], ozone->sidebar_offset + 41 + 10, y - 5, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); + + enum msg_hash_enums value_idx = ozone_system_tabs_value[i]; + const char *title = msg_hash_to_str(value_idx); + + //Text + ozone_draw_text(video_info, ozone, title, ozone->sidebar_offset + 115 - 10, y + FONT_SIZE_SIDEBAR, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.sidebar, (selected ? ozone->theme->text_selected_rgba : ozone->theme->text_rgba)); + + y += 65; + } + menu_display_blend_end(video_info); + + font_driver_flush(video_info->width, video_info->height, ozone->fonts.sidebar, video_info); + + menu_display_scissor_end(video_info); +} + +static void ozone_draw_entry_value(ozone_handle_t *ozone, video_frame_info_t *video_info, char *value, unsigned x, unsigned y, uint32_t alpha_uint32) +{ + if (string_is_empty(value)) + return; + + bool switch_is_on = true; + bool do_draw_text = false; + enum msg_file_type hash_type = msg_hash_to_file_type(msg_hash_calculate(value)); + + /* set switch_is_on */ + if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || + (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))) + { + switch_is_on = false; + do_draw_text = false; + } + else if (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || + (string_is_equal(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)))) + { + switch_is_on = true; + do_draw_text = false; + } + else + { + switch (hash_type) + { + case FILE_TYPE_IN_CARCHIVE: + case FILE_TYPE_COMPRESSED: + case FILE_TYPE_MORE: + case FILE_TYPE_CORE: + case FILE_TYPE_DIRECT_LOAD: + case FILE_TYPE_RDB: + case FILE_TYPE_CURSOR: + case FILE_TYPE_PLAIN: + case FILE_TYPE_DIRECTORY: + case FILE_TYPE_MUSIC: + case FILE_TYPE_IMAGE: + case FILE_TYPE_MOVIE: + return; + default: + do_draw_text = true; + break; + } + } + + if (do_draw_text) + { + ozone_draw_text(video_info, ozone, value, x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, (ozone->theme->text_selected_rgba & 0xFFFFFF00) | alpha_uint32); + } + else + { + ozone_draw_text(video_info, ozone, (switch_is_on ? "On" : "Off"), x, y, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.entries_label, ((switch_is_on ? ozone->theme->text_selected_rgba : ozone->theme->text_sublabel_rgba) & 0xFFFFFF00) | alpha_uint32); + } +} + +static void ozone_draw_entries(ozone_handle_t *ozone, video_frame_info_t *video_info, + unsigned selection, unsigned selection_old, + file_list_t *selection_buf, float alpha, float scroll_y) +{ + size_t i; + menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); + + size_t entries_end = file_list_get_size(selection_buf); + unsigned x_offset = 0; + + bool old_list = selection_buf == ozone->selection_buf_old; + + size_t y = ENTRIES_START_Y; + size_t selection_y = 0; + size_t old_selection_y = 0; + + float sidebar_offset = ozone->sidebar_offset/2.0f; + unsigned entry_width = video_info->width - 548; + + unsigned video_info_height; + video_driver_get_size(NULL, &video_info_height); + + float bottom_boundary = video_info_height - 87 - 78; + + float invert = (ozone->fade_direction) ? -1 : 1; + + float alpha_anim = old_list ? alpha : 1.0f - alpha; + + if (old_list) + alpha = 1.0f - alpha; + + if (alpha != 1.0f) + { + if (old_list) + x_offset = invert * -(alpha_anim * 120); //left + else + x_offset = invert * (alpha_anim * 120); //right + } + + x_offset += (unsigned) sidebar_offset; + + uint32_t alpha_uint32 = (uint32_t)(alpha*255.0f); + + //Borders layer + for (i = 0; i < entries_end; i++) + { + bool entry_selected = selection == i; + bool entry_old_selected = selection_old == i; + + if (entry_selected) + selection_y = y; + + if (entry_old_selected) + old_selection_y = y; + + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + if (!node) + continue; + + if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) + goto text_iterate; + else if (y + scroll_y - node->height - 20 > bottom_boundary) + goto text_iterate; + + ozone_color_alpha(ozone->theme_dynamic.entries_border, alpha); + + //Borders + menu_display_draw_quad(video_info, x_offset + 456-3, y - 3 + scroll_y, entry_width + 10 - 3 -1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); + menu_display_draw_quad(video_info, x_offset + 456-3, y - 5 + 70 + 10 - 10 - 10 - 3 - 3 + scroll_y, entry_width + 10 - 3-1, 1, video_info->width, video_info->height, ozone->theme_dynamic.entries_border); + +text_iterate: + y += node->height; + } + + //Cursor(s) layer + if (!ozone->cursor_in_sidebar) + ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, selection_y + scroll_y, ozone->animations.cursor_alpha * alpha); + + if (!ozone->cursor_in_sidebar_old && ozone->selection != ozone->selection_old) + ozone_draw_cursor(ozone, video_info, x_offset + 456, entry_width, old_selection_y + scroll_y, 1-ozone->animations.cursor_alpha * alpha); + + //Icons + text + y = ENTRIES_START_Y; + for (i = 0; i < entries_end; i++) + { + menu_entry_t entry; + char entry_value[255]; + + entry_value[0] = '\0'; + + bool entry_selected = selection == i; + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, (unsigned)i, selection_buf, true); + menu_entry_get_value(&entry, entry_value, sizeof(entry_value)); + + if (!node) + continue; + + if (y + scroll_y + node->height + 20 < ENTRIES_START_Y) + goto icons_iterate; + else if (y + scroll_y - node->height - 20 > bottom_boundary) + goto icons_iterate; + + //Icon + unsigned icon = ozone_entries_icon_get_id(ozone, entry.enum_idx, entry.type, entry_selected); + + ozone_color_alpha(ozone->theme_dynamic.entries_icon, alpha); + + menu_display_blend_begin(video_info); + ozone_draw_icon(video_info, 46, 46, ozone->icons_textures[icon], x_offset + 451+5+10, y + scroll_y, video_info->width, video_info->height, 0, 1, ozone->theme_dynamic.entries_icon); + menu_display_blend_end(video_info); + + char *entry_rich_label = NULL; + char rich_label[255]; + + entry_rich_label = menu_entry_get_rich_label(&entry); + + menu_animation_ctx_ticker_t ticker; + + ticker.idx = ozone->frame_count / 20; + ticker.s = rich_label; + ticker.str = entry_rich_label; + ticker.selected = entry_selected && !ozone->cursor_in_sidebar; + ticker.len = (entry_width - 60) / ozone->entry_font_glyph_width; + + menu_animation_ticker(&ticker); + + //Text + ozone_draw_text(video_info, ozone, rich_label, x_offset + 521, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, (ozone->theme->text_rgba & 0xFFFFFF00) | alpha_uint32); + ozone_draw_text(video_info, ozone, entry.sublabel, x_offset + 470, y + FONT_SIZE_ENTRIES_SUBLABEL + 80 - 20 - 3 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_sublabel, (ozone->theme->text_sublabel_rgba & 0xFFFFFF00) | alpha_uint32); + + //Value + char entry_value_ticker[255]; + + ticker.idx = ozone->frame_count / 20; + ticker.s = entry_value_ticker; + ticker.str = entry_value; + ticker.selected = entry_selected && !ozone->cursor_in_sidebar; + ticker.len = (entry_width - 60 - ((int)utf8len(entry_rich_label) * ozone->entry_font_glyph_width)) / ozone->entry_font_glyph_width; + + menu_animation_ticker(&ticker); + ozone_draw_entry_value(ozone, video_info, entry_value_ticker, x_offset + 426 + entry_width, y + FONT_SIZE_ENTRIES_LABEL + 8 - 1 + scroll_y,alpha_uint32); + + free(entry_rich_label); + +icons_iterate: + y += node->height; + menu_entry_free(&entry); + } + + //Text layer + font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_label, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.entries_sublabel, video_info); +} + +static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_animation_ctx_tag tag = (uintptr_t) selection_buf; + + size_t new_selection = menu_navigation_get_selection(); + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, new_selection); + + if (!node) + return; + + if (ozone->selection != new_selection) + { + ozone->selection_old = ozone->selection; + ozone->selection = new_selection; + + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + + menu_animation_kill_by_tag(&tag); + + ozone_update_scroll(ozone, allow_animation, node); + } +} + +static void ozone_navigation_clear(void *data, bool pending_push) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + if (!pending_push) + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_pointer_changed(void *data) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_set(void *data, bool scroll) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_navigation_alphabet(void *data, size_t *unused) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + ozone_selection_changed(ozone, true); +} + +static void ozone_frame(void *data, video_frame_info_t *video_info) +{ + ozone_handle_t* ozone = (ozone_handle_t*) data; + + if (!ozone) + return; + + settings_t *settings = config_get_ptr(); + + ozone->frame_count++; + + menu_display_set_viewport(video_info->width, video_info->height); + + //Clear first layer of text + font_driver_bind_block(ozone->fonts.footer, &ozone->raster_blocks.footer); + font_driver_bind_block(ozone->fonts.title, &ozone->raster_blocks.title); + font_driver_bind_block(ozone->fonts.time, &ozone->raster_blocks.time); + font_driver_bind_block(ozone->fonts.entries_label, &ozone->raster_blocks.entries_label); + font_driver_bind_block(ozone->fonts.entries_sublabel, &ozone->raster_blocks.entries_sublabel); + font_driver_bind_block(ozone->fonts.sidebar, &ozone->raster_blocks.sidebar); + + ozone->raster_blocks.footer.carr.coords.vertices = 0; + ozone->raster_blocks.title.carr.coords.vertices = 0; + ozone->raster_blocks.time.carr.coords.vertices = 0; + ozone->raster_blocks.entries_label.carr.coords.vertices = 0; + ozone->raster_blocks.entries_sublabel.carr.coords.vertices = 0; + ozone->raster_blocks.sidebar.carr.coords.vertices = 0; + + //Background + menu_display_ctx_clearcolor_t clearcolor; + + clearcolor.r = ozone->theme->background_r; + clearcolor.g = ozone->theme->background_g; + clearcolor.b = ozone->theme->background_b; + clearcolor.a = 1.0f; + + menu_display_clear_color(&clearcolor, video_info); + + //Header, footer + ozone_draw_header(ozone, video_info); + ozone_draw_footer(ozone, video_info, settings); + + //Sidebar + ozone_draw_sidebar(ozone, video_info); + + //Menu entries + menu_display_scissor_begin(video_info, ozone->sidebar_offset + 408, 87, video_info->width - 408 + (-ozone->sidebar_offset), video_info->height - 87 - 78); + + //Current list + ozone_draw_entries(ozone, video_info, ozone->selection, ozone->selection_old, menu_entries_get_selection_buf_ptr(0), ozone->animations.list_alpha, ozone->animations.scroll_y); + + //Old list + if (ozone->draw_old_list) + ozone_draw_entries(ozone, video_info, ozone->selection_old_list, ozone->selection_old_list, ozone->selection_buf_old, ozone->animations.list_alpha, ozone->scroll_old); + + menu_display_scissor_end(video_info); + + //Flush first layer of text + font_driver_flush(video_info->width, video_info->height, ozone->fonts.footer, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.title, video_info); + font_driver_flush(video_info->width, video_info->height, ozone->fonts.time, video_info); + + font_driver_bind_block(ozone->fonts.footer, NULL); + font_driver_bind_block(ozone->fonts.title, NULL); + font_driver_bind_block(ozone->fonts.time, NULL); + font_driver_bind_block(ozone->fonts.entries_label, NULL); + + menu_display_unset_viewport(video_info->width, video_info->height); +} + +static void ozone_set_header(ozone_handle_t *ozone) +{ + //TODO Set title of playlist if in a playlist + + menu_entries_get_title(ozone->title, sizeof(ozone->title)); +} + +static void ozone_animation_end(void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone->draw_old_list = false; +} + +static void ozone_list_open(ozone_handle_t *ozone) +{ + if (!ozone->want_horizontal_animation) + { + ozone->want_horizontal_animation = true; + return; + } + ozone->draw_old_list = true; + + struct menu_animation_ctx_entry entry; + + //Left/right animation + ozone->animations.list_alpha = 0.0f; + + entry.cb = ozone_animation_end; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.list_alpha; + entry.tag = (uintptr_t) NULL; + entry.target_value = 1.0f; + entry.userdata = ozone; + + menu_animation_push(&entry); + + //Sidebar animation + if (ozone->depth == 1) + { + ozone->draw_sidebar = true; + + entry.cb = NULL; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->sidebar_offset; + entry.tag = (uintptr_t) NULL; + entry.target_value = 0.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + } + else if (ozone->depth > 1) + { + struct menu_animation_ctx_entry entry; + + entry.cb = ozone_collapse_end; + entry.duration = ANIMATION_PUSH_ENTRY_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->sidebar_offset; + entry.tag = (uintptr_t) NULL; + entry.target_value = -408.0f; + entry.userdata = (void*) ozone; + + menu_animation_push(&entry); + } +} + +static void ozone_populate_entries(void *data, const char *path, const char *label, unsigned k) +{ + ozone_handle_t *ozone = (ozone_handle_t*) data; + + if (!ozone) + return; + + ozone_set_header(ozone); + + if (menu_driver_ctl(RARCH_MENU_CTL_IS_PREVENT_POPULATE, NULL)) + { + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + //TODO Update thumbnails + ozone_selection_changed(ozone, false); + return; + } + + ozone->need_compute = true; + ozone->fade_direction = ozone->action == MENU_ACTION_CANCEL; + + ozone->depth = (int)ozone_list_get_size(ozone, MENU_LIST_PLAIN); + + if (ozone->categories_selection_ptr == ozone->categories_active_idx_old) + { + ozone_list_open(ozone); + } +} + +static void ozone_change_tab(ozone_handle_t *ozone, enum msg_hash_enums tab, enum menu_settings_type type) +{ + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + size_t stack_size; + menu_ctx_list_t list_info; + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + size_t selection = menu_navigation_get_selection(); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)file_list_get_actiondata_at_offset(selection_buf, + selection) : NULL; + + list_info.type = MENU_LIST_HORIZONTAL; + list_info.action = MENU_ACTION_LEFT; + + stack_size = menu_stack->size; + + if (menu_stack->list[stack_size - 1].label) + free(menu_stack->list[stack_size - 1].label); + menu_stack->list[stack_size - 1].label = NULL; + + menu_stack->list[stack_size - 1].label = + strdup(msg_hash_to_str(tab)); + menu_stack->list[stack_size - 1].type = + type; + + menu_driver_list_cache(&list_info); + + if (cbs && cbs->action_content_list_switch) + cbs->action_content_list_switch(selection_buf, menu_stack, "", "", 0); +} + +static void ozone_go_to_sidebar(ozone_handle_t *ozone, uintptr_t tag) +{ + ozone->selection_old = ozone->selection; + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + ozone->cursor_in_sidebar = true; + + //Cursor animation + ozone->animations.cursor_alpha = 0.0f; + + struct menu_animation_ctx_entry entry; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +static void ozone_leave_sidebar(ozone_handle_t *ozone, uintptr_t tag) +{ + ozone->categories_active_idx_old = ozone->categories_selection_ptr; + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + ozone->cursor_in_sidebar = false; + + //Cursor animation + ozone->animations.cursor_alpha = 0.0f; + + struct menu_animation_ctx_entry entry; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +static int ozone_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_action action) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + if (!ozone) + return generic_menu_iterate(menu, userdata, action); + + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + + menu_animation_ctx_tag tag = (uintptr_t)selection_buf; + int new_selection; + struct menu_animation_ctx_entry entry; + + enum menu_action new_action = action; + + //Inputs override + switch (action) + { + case MENU_ACTION_DOWN: + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + + new_selection = (ozone->categories_selection_ptr + 1); + + if (new_selection >= ozone->system_tab_end + 2) //TODO Check against actual tabs count and not just system tabs + new_selection = 0; + + if (ozone->categories_selection_ptr != new_selection) + { + ozone->categories_active_idx_old = ozone->categories_selection_ptr; + ozone->categories_selection_ptr = new_selection; + + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + + menu_animation_kill_by_tag(&tag); + } + + //Cursor animation + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + ozone_change_tab(ozone, ozone_system_tabs_idx[new_selection], ozone_system_tabs_type[new_selection]); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_UP: + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + + new_selection = ozone->categories_selection_ptr - 1; + + if (new_selection < 0) + new_selection = ozone->system_tab_end + 1; //TODO Set this to actual tabs count and not just system tabs + + if (ozone->categories_selection_ptr != new_selection) + { + ozone->categories_active_idx_old = ozone->categories_selection_ptr; + ozone->categories_selection_ptr = new_selection; + + ozone->cursor_in_sidebar_old = ozone->cursor_in_sidebar; + + menu_animation_kill_by_tag(&tag); + } + + //Cursor animation + ozone->animations.cursor_alpha = 0.0f; + + entry.cb = NULL; + entry.duration = ANIMATION_CURSOR_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &ozone->animations.cursor_alpha; + entry.tag = tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + ozone_change_tab(ozone, ozone_system_tabs_idx[new_selection], ozone_system_tabs_type[new_selection]); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_LEFT: + if (ozone->cursor_in_sidebar) + { + new_action = MENU_ACTION_NOOP; + break; + } + else if (ozone->depth > 1) + { + break; + } + + + ozone_go_to_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_RIGHT: + if (!ozone->cursor_in_sidebar) + { + if (ozone->depth == 1) + new_action = MENU_ACTION_NOOP; + break; + } + + ozone_leave_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_OK: + if (ozone->cursor_in_sidebar) + { + ozone_leave_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + break; + } + + break; + case MENU_ACTION_CANCEL: + if (ozone->cursor_in_sidebar) + { + new_action = MENU_ACTION_NOOP; + break; + } + + if (menu_entries_get_stack_size(0) == 1) + { + ozone_go_to_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + } + break; + default: + break; + } + + ozone->action = new_action; + + return generic_menu_iterate(menu, userdata, new_action); +} + +//TODO Fancy toggle animation + +static void ozone_toggle(void *userdata, bool menu_on) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + if (!menu_on) + { + menu_display_ctx_clearcolor_t clearcolor; + + clearcolor.r = 0.0f; + clearcolor.g = 0.0f; + clearcolor.b = 0.0f; + clearcolor.a = 1.0f; + + menu_display_clear_color(&clearcolor, NULL); + } + + bool tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL); + + if (tmp) + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + else + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); + + if (ozone->depth == 1) + { + ozone->draw_sidebar = true; + ozone->sidebar_offset = 0.0f; + } +} + +static bool ozone_menu_init_list(void *data) +{ + menu_displaylist_info_t info; + + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + + menu_displaylist_info_init(&info); + + info.label = strdup( + msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)); + info.exts = + strdup(file_path_str(FILE_PATH_LPL_EXTENSION_NO_DOT)); + info.type_default = FILE_TYPE_PLAIN; + info.enum_idx = MENU_ENUM_LABEL_MAIN_MENU; + + menu_entries_append_enum(menu_stack, info.path, + info.label, + MENU_ENUM_LABEL_MAIN_MENU, + info.type, info.flags, 0); + + info.list = selection_buf; + + if (!menu_displaylist_ctl(DISPLAYLIST_MAIN_MENU, &info)) + goto error; + + info.need_push = true; + + if (!menu_displaylist_process(&info)) + goto error; + + menu_displaylist_info_free(&info); + return true; + +error: + menu_displaylist_info_free(&info); + return false; +} + +static ozone_node_t *ozone_alloc_node() +{ + ozone_node_t *node = (ozone_node_t*)malloc(sizeof(*node)); + + node->height = 0; + node->position_y = 0; + + return node; +} + +static ozone_node_t *ozone_copy_node(const ozone_node_t *old_node) +{ + ozone_node_t *new_node = (ozone_node_t*)malloc(sizeof(*new_node)); + + *new_node = *old_node; + + return new_node; +} + +static void ozone_list_insert(void *userdata, + file_list_t *list, + const char *path, + const char *fullpath, + const char *label, + size_t list_size, + unsigned type) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + ozone_node_t *node = NULL; + int i = (int)list_size; + + if (!ozone || !list) + return; + + ozone->need_compute = true; + + node = (ozone_node_t*)file_list_get_userdata_at_offset(list, i); + + if (!node) + node = ozone_alloc_node(); + + if (!node) + { + RARCH_ERR("ozone node could not be allocated.\n"); + return; + } + + file_list_set_userdata(list, i, node); +} + +static void ozone_list_deep_copy(const file_list_t *src, file_list_t *dst, + size_t first, size_t last) +{ + size_t i, j = 0; + menu_animation_ctx_tag tag = (uintptr_t)dst; + + menu_animation_kill_by_tag(&tag); + + /* use true here because file_list_copy() doesn't free actiondata */ + ozone_free_list_nodes(dst, true); + + file_list_clear(dst); + file_list_reserve(dst, (last + 1) - first); + + for (i = first; i <= last; ++i) + { + struct item_file *d = &dst->list[j]; + struct item_file *s = &src->list[i]; + + void *src_udata = s->userdata; + void *src_adata = s->actiondata; + + *d = *s; + d->alt = string_is_empty(d->alt) ? NULL : strdup(d->alt); + d->path = string_is_empty(d->path) ? NULL : strdup(d->path); + d->label = string_is_empty(d->label) ? NULL : strdup(d->label); + + if (src_udata) + file_list_set_userdata(dst, j, (void*)ozone_copy_node((const ozone_node_t*)src_udata)); + + if (src_adata) + { + void *data = malloc(sizeof(menu_file_list_cbs_t)); + memcpy(data, src_adata, sizeof(menu_file_list_cbs_t)); + file_list_set_actiondata(dst, j, data); + } + + ++j; + } + + dst->size = j; +} + +static void ozone_list_cache(void *data, + enum menu_list_type type, unsigned action) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + + if (!ozone) + return; + + ozone->need_compute = true; + + ozone->selection_old_list = ozone->selection; + ozone->scroll_old = ozone->animations.scroll_y; + + //Deep copy visible elements + unsigned first = 0; + unsigned last = 0; + + unsigned video_info_height; + video_driver_get_size(NULL, &video_info_height); + size_t y = ENTRIES_START_Y; + int i; + size_t entries_end = menu_entries_get_size(); + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + float bottom_boundary = video_info_height - 87 - 78; + for (i = 0; i < entries_end; i++) + { + ozone_node_t *node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i); + + if (!node) + continue; + + if (y + ozone->animations.scroll_y + node->height + 20 < ENTRIES_START_Y) + { + first++; + goto text_iterate; + } + else if (y + ozone->animations.scroll_y - node->height - 20 > bottom_boundary) + { + goto text_iterate; + } + + last++; +text_iterate: + y += node->height; + } + + last -= 1; + + ozone_list_deep_copy(selection_buf, ozone->selection_buf_old, first, last); +} + +static void ozone_refresh_consoles_list(ozone_handle_t *ozone) +{ + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + //TODO Refresh consoles list (= horizontal list) +} + +static int ozone_environ_cb(enum menu_environ_cb type, void *data, void *userdata) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + if (!ozone) + return -1; + + switch (type) + { + case MENU_ENVIRON_RESET_HORIZONTAL_LIST: + ozone_refresh_consoles_list(ozone); + break; + default: + return -1; + } + + return 0; +} + +menu_ctx_driver_t menu_ctx_ozone = { + NULL, //set_texture + NULL, //render_messagebox + ozone_menu_iterate, + ozone_render, + ozone_frame, + ozone_init, + ozone_free, + ozone_context_reset, + ozone_context_destroy, + ozone_populate_entries, + ozone_toggle, + ozone_navigation_clear, + ozone_navigation_pointer_changed, + ozone_navigation_pointer_changed, + ozone_navigation_set, + ozone_navigation_pointer_changed, + ozone_navigation_alphabet, + ozone_navigation_alphabet, + ozone_menu_init_list, + ozone_list_insert, + NULL, //list_prepend + ozone_list_free, + ozone_list_clear, + ozone_list_cache, + ozone_list_push, + ozone_list_get_selection, + ozone_list_get_size, + ozone_list_get_entry, + NULL, //list_set_selection, + NULL, //bind_init + NULL, //load_image + "ozone", + ozone_environ_cb, + NULL, //pointer_tap + NULL, //update_thumbnail_path + NULL, //update_thumbnail_image + NULL, //set_thumbnail_system + NULL, //set_thumbnail_content + menu_display_osk_ptr_at_pos, + NULL, //update_savestate_thumbnail_path + NULL //update_savestate_thumbnail_image +}; \ No newline at end of file diff --git a/menu/menu_animation.c b/menu/menu_animation.c index 8cd9d140f8..68c6260fbb 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -40,6 +40,7 @@ struct tween uintptr_t tag; easing_cb easing; tween_cb cb; + void *userdata; }; struct menu_animation @@ -326,6 +327,7 @@ bool menu_animation_push(menu_animation_ctx_entry_t *entry) t.subject = entry->subject; t.tag = entry->tag; t.cb = entry->cb; + t.userdata = entry->userdata; t.easing = NULL; switch (entry->easing_enum) @@ -519,7 +521,7 @@ bool menu_animation_update(float delta_time) anim.need_defrag = true; if (tween->cb) - tween->cb(); + tween->cb(tween->userdata); } if (tween->running_since < tween->duration) diff --git a/menu/menu_animation.h b/menu/menu_animation.h index 71f31e9c6d..6983237719 100644 --- a/menu/menu_animation.h +++ b/menu/menu_animation.h @@ -26,7 +26,7 @@ RETRO_BEGIN_DECLS typedef float (*easing_cb) (float, float, float, float); -typedef void (*tween_cb) (void); +typedef void (*tween_cb) (void*); enum menu_animation_ctl_state { @@ -106,6 +106,7 @@ typedef struct menu_animation_ctx_entry float target_value; float *subject; tween_cb cb; + void *userdata; } menu_animation_ctx_entry_t; typedef struct menu_animation_ctx_ticker diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 0ec43c8325..d8331f51a8 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -78,6 +78,9 @@ typedef struct menu_ctx_load_image /* Menu drivers */ static const menu_ctx_driver_t *menu_ctx_drivers[] = { +#if defined(HAVE_OZONE) + &menu_ctx_ozone, +#endif #if defined(HAVE_XUI) &menu_ctx_xui, #endif @@ -445,7 +448,6 @@ font_data_t *menu_display_font( bool is_threaded) { char fontpath[PATH_MAX_LENGTH]; - font_data_t *font_data = NULL; if (!menu_disp) return NULL; @@ -455,6 +457,16 @@ font_data_t *menu_display_font( fill_pathname_application_special( fontpath, sizeof(fontpath), type); + return menu_display_font_file(fontpath, font_size, is_threaded); +} + +font_data_t *menu_display_font_file(char* fontpath, float font_size, bool is_threaded) +{ + if (!menu_disp) + return NULL; + + font_data_t *font_data = NULL; + if (!menu_disp->font_init_first((void**)&font_data, video_driver_get_ptr(false), fontpath, font_size, is_threaded)) @@ -2626,3 +2638,11 @@ void menu_navigation_set_selection(size_t val) { menu_driver_selection_ptr = val; } + +void hex32_to_rgba_normalized(uint32_t hex, float* rgba, float alpha) +{ + rgba[0] = rgba[4] = rgba[8] = rgba[12] = ((hex >> 16) & 0xFF) * (1.0f / 255.0f); /* r */ + rgba[1] = rgba[5] = rgba[9] = rgba[13] = ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f); /* g */ + rgba[2] = rgba[6] = rgba[10] = rgba[14] = ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f); /* b */ + rgba[3] = rgba[7] = rgba[11] = rgba[15] = alpha; +} diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 0110f9ef21..917265740f 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -812,6 +812,8 @@ font_data_t *menu_display_font( float font_size, bool video_is_threaded); +font_data_t *menu_display_font_file(char* fontpath, float font_size, bool is_threaded); + void menu_display_reset_textures_list( const char *texture_path, const char *iconpath, @@ -826,6 +828,8 @@ bool menu_display_driver_exists(const char *s); void menu_driver_destroy(void); +void hex32_to_rgba_normalized(uint32_t hex, float* rgba, float alpha); + extern uintptr_t menu_display_white_texture; extern menu_display_ctx_driver_t menu_display_ctx_gl; @@ -846,6 +850,7 @@ extern menu_display_ctx_driver_t menu_display_ctx_switch; extern menu_display_ctx_driver_t menu_display_ctx_sixel; extern menu_display_ctx_driver_t menu_display_ctx_null; +extern menu_ctx_driver_t menu_ctx_ozone; extern menu_ctx_driver_t menu_ctx_xui; extern menu_ctx_driver_t menu_ctx_rgui; extern menu_ctx_driver_t menu_ctx_mui; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 59e5e4527f..5361a70302 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -3530,7 +3530,7 @@ static bool setting_append_list( parent_group); } - if (string_is_not_equal(settings->arrays.menu_driver, "xmb")) + if (string_is_not_equal(settings->arrays.menu_driver, "xmb") && string_is_not_equal(settings->arrays.menu_driver, "ozone")) { CONFIG_ACTION( list, list_info, @@ -7616,7 +7616,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); - if (string_is_equal(settings->arrays.menu_driver, "xmb")) + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) { CONFIG_BOOL( list, list_info, @@ -8055,8 +8055,8 @@ static bool setting_append_list( SD_FLAG_NONE); #endif -#ifdef HAVE_XMB - if (string_is_equal(settings->arrays.menu_driver, "xmb")) +#if defined(HAVE_XMB) || defined(HAVE_OZONE) + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) { CONFIG_BOOL( list, list_info, @@ -8302,7 +8302,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_ADVANCED); - if (string_is_equal(settings->arrays.menu_driver, "xmb")) + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) { CONFIG_UINT( list, list_info, @@ -9040,7 +9040,7 @@ static bool setting_append_list( SD_FLAG_NONE ); - if (string_is_equal(settings->arrays.menu_driver, "xmb")) + if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone")) CONFIG_BOOL( list, list_info, &settings->bools.cheevos_badges_enable, diff --git a/qb/config.libs.sh b/qb/config.libs.sh index d0d94da004..a679058d35 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -518,7 +518,8 @@ if [ "$HAVE_MATERIALUI" != 'no' ] || [ "$HAVE_XMB" != 'no' ] || [ "$HAVE_ZARCH" HAVE_XMB=no HAVE_STRIPES=no HAVE_ZARCH=no - die : 'Notice: RGUI not available, MaterialUI, XMB and ZARCH will also be disabled.' + HAVE_OZONE=no + die : 'Notice: RGUI not available, MaterialUI, XMB, Ozone and ZARCH will also be disabled.' elif [ "$HAVE_OPENGL" = 'no' ] && [ "$HAVE_OPENGLES" = 'no' ] && [ "$HAVE_VULKAN" = 'no' ]; then if [ "$OS" = 'Win32' ]; then HAVE_SHADERPIPELINE=no @@ -531,7 +532,8 @@ if [ "$HAVE_MATERIALUI" != 'no' ] || [ "$HAVE_XMB" != 'no' ] || [ "$HAVE_ZARCH" HAVE_XMB=no HAVE_STRIPES=no HAVE_ZARCH=no - die : 'Notice: Hardware rendering context not available, XMB, MaterialUI and ZARCH will also be disabled.' + HAVE_OZONE=no + die : 'Notice: Hardware rendering context not available, XMB, MaterialUI, Ozone and ZARCH will also be disabled.' fi fi fi diff --git a/qb/config.params.sh b/qb/config.params.sh index 1e097b8f0c..34a83081ca 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -10,6 +10,7 @@ HAVE_LIBRETRODB=yes # Libretrodb support HAVE_RGUI=yes # RGUI menu HAVE_MATERIALUI=auto # MaterialUI menu HAVE_XMB=auto # XMB menu +HAVE_OZONE=no # Ozone menu HAVE_STRIPES=no # Stripes menu HAVE_ZARCH=no # Zarch menu HAVE_NUKLEAR=no # Nuklear menu