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