mirror of
https://github.com/libretro/RetroArch
synced 2025-01-31 15:32:59 +00:00
1007 lines
30 KiB
C
1007 lines
30 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
|
* Copyright (C) 2014-2017 - Jean-André Santoni
|
|
* Copyright (C) 2016-2019 - Brad Parker
|
|
* Copyright (C) 2018 - Alfredo Monclús
|
|
* Copyright (C) 2018-2020 - 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "ozone.h"
|
|
#include "ozone_display.h"
|
|
#include "ozone_theme.h"
|
|
|
|
#include <string/stdstring.h>
|
|
#include <file/file_path.h>
|
|
#include <encodings/utf.h>
|
|
#include <lists/string_list.h>
|
|
|
|
#include "../../../gfx/gfx_animation.h"
|
|
|
|
#include "../../../input/input_osk.h"
|
|
|
|
static void ozone_cursor_animation_cb(void *userdata);
|
|
|
|
static void ozone_animate_cursor(ozone_handle_t *ozone,
|
|
float *dst, float *target)
|
|
{
|
|
int i;
|
|
gfx_animation_ctx_entry_t entry;
|
|
|
|
entry.easing_enum = EASING_OUT_QUAD;
|
|
entry.tag = (uintptr_t)&ozone_default_theme;
|
|
entry.duration = ANIMATION_CURSOR_PULSE;
|
|
entry.userdata = ozone;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
if (i == 3 || i == 7 || i == 11 || i == 15)
|
|
continue;
|
|
|
|
if (i == 14)
|
|
entry.cb = ozone_cursor_animation_cb;
|
|
else
|
|
entry.cb = NULL;
|
|
|
|
entry.subject = &dst[i];
|
|
entry.target_value = target[i];
|
|
|
|
gfx_animation_push(&entry);
|
|
}
|
|
}
|
|
|
|
static void ozone_cursor_animation_cb(void *userdata)
|
|
{
|
|
float *target = NULL;
|
|
ozone_handle_t *ozone = (ozone_handle_t*) userdata;
|
|
|
|
switch (ozone->theme_dynamic_cursor_state)
|
|
{
|
|
case 0:
|
|
target = ozone->theme->cursor_border_1;
|
|
break;
|
|
case 1:
|
|
target = ozone->theme->cursor_border_0;
|
|
break;
|
|
}
|
|
|
|
ozone->theme_dynamic_cursor_state =
|
|
(ozone->theme_dynamic_cursor_state + 1) % 2;
|
|
|
|
ozone_animate_cursor(ozone, ozone->theme_dynamic.cursor_border, target);
|
|
}
|
|
|
|
static void ozone_draw_cursor_slice(
|
|
ozone_handle_t *ozone,
|
|
gfx_display_t *p_disp,
|
|
void *userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
int x_offset,
|
|
unsigned width, unsigned height,
|
|
size_t y, float alpha)
|
|
{
|
|
float scale_factor = ozone->last_scale_factor;
|
|
int slice_x = x_offset - 12 * scale_factor;
|
|
int slice_y = (int)y + 8 * scale_factor;
|
|
unsigned slice_new_w = width + (24 + 1) * scale_factor;
|
|
unsigned slice_new_h = height + 20 * scale_factor;
|
|
gfx_display_ctx_driver_t
|
|
*dispctx = p_disp->dispctx;
|
|
static float
|
|
last_alpha = 0.0f;
|
|
|
|
if (alpha != last_alpha)
|
|
{
|
|
gfx_display_set_alpha(ozone->theme_dynamic.cursor_alpha, alpha);
|
|
gfx_display_set_alpha(ozone->theme_dynamic.cursor_border, alpha);
|
|
last_alpha = alpha;
|
|
}
|
|
|
|
if (dispctx && dispctx->blend_begin)
|
|
dispctx->blend_begin(userdata);
|
|
|
|
/* Cursor without border */
|
|
gfx_display_draw_texture_slice(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
slice_x,
|
|
slice_y,
|
|
80, 80,
|
|
slice_new_w,
|
|
slice_new_h,
|
|
video_width, video_height,
|
|
ozone->theme_dynamic.cursor_alpha,
|
|
20, scale_factor,
|
|
ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_NO_BORDER]
|
|
);
|
|
|
|
/* Tainted border */
|
|
gfx_display_draw_texture_slice(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
slice_x,
|
|
slice_y,
|
|
80, 80,
|
|
slice_new_w,
|
|
slice_new_h,
|
|
video_width, video_height,
|
|
ozone->theme_dynamic.cursor_border,
|
|
20, scale_factor,
|
|
ozone->textures[OZONE_TEXTURE_CURSOR_BORDER]
|
|
);
|
|
|
|
if (dispctx && dispctx->blend_end)
|
|
dispctx->blend_end(userdata);
|
|
}
|
|
|
|
static void ozone_draw_cursor_fallback(
|
|
ozone_handle_t *ozone,
|
|
gfx_display_t *p_disp,
|
|
void *userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
int x_offset,
|
|
unsigned width, unsigned height,
|
|
size_t y, float alpha)
|
|
{
|
|
static float last_alpha = 0.0f;
|
|
|
|
if (alpha != last_alpha)
|
|
{
|
|
gfx_display_set_alpha(ozone->theme_dynamic.selection_border, alpha);
|
|
gfx_display_set_alpha(ozone->theme_dynamic.selection, alpha);
|
|
last_alpha = alpha;
|
|
}
|
|
|
|
/* Fill */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
x_offset,
|
|
(int)y,
|
|
width,
|
|
height - ozone->dimensions.spacer_3px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme_dynamic.selection);
|
|
|
|
/* Borders (can't do one single quad because of alpha) */
|
|
|
|
/* Top */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
x_offset - ozone->dimensions.spacer_3px,
|
|
(int)(y - ozone->dimensions.spacer_3px),
|
|
width + ozone->dimensions.spacer_3px * 2,
|
|
ozone->dimensions.spacer_3px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme_dynamic.selection_border);
|
|
|
|
/* Bottom */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
x_offset - ozone->dimensions.spacer_3px,
|
|
(int)(y + height - ozone->dimensions.spacer_3px),
|
|
width + ozone->dimensions.spacer_3px * 2,
|
|
ozone->dimensions.spacer_3px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme_dynamic.selection_border);
|
|
|
|
/* Left */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
(int)(x_offset - ozone->dimensions.spacer_3px),
|
|
(int)y,
|
|
ozone->dimensions.spacer_3px,
|
|
height - ozone->dimensions.spacer_3px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme_dynamic.selection_border);
|
|
|
|
/* Right */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
x_offset + width,
|
|
(int)y,
|
|
ozone->dimensions.spacer_3px,
|
|
height - ozone->dimensions.spacer_3px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme_dynamic.selection_border);
|
|
}
|
|
|
|
|
|
|
|
void ozone_restart_cursor_animation(ozone_handle_t *ozone)
|
|
{
|
|
uintptr_t tag = (uintptr_t) &ozone_default_theme;
|
|
|
|
if (!ozone->has_all_assets)
|
|
return;
|
|
|
|
ozone->theme_dynamic_cursor_state = 1;
|
|
memcpy(ozone->theme_dynamic.cursor_border,
|
|
ozone->theme->cursor_border_0,
|
|
sizeof(ozone->theme_dynamic.cursor_border));
|
|
gfx_animation_kill_by_tag(&tag);
|
|
|
|
ozone_animate_cursor(ozone,
|
|
ozone->theme_dynamic.cursor_border,
|
|
ozone->theme->cursor_border_1);
|
|
}
|
|
|
|
void ozone_draw_cursor(
|
|
ozone_handle_t *ozone,
|
|
gfx_display_t *p_disp,
|
|
void *userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
int x_offset,
|
|
unsigned width, unsigned height,
|
|
size_t y, float alpha)
|
|
{
|
|
int new_x = x_offset;
|
|
size_t new_y = y;
|
|
|
|
/* Apply wiggle animation if needed */
|
|
if (ozone->cursor_wiggle_state.wiggling)
|
|
ozone_apply_cursor_wiggle_offset(ozone, &new_x, &new_y);
|
|
|
|
/* Draw the cursor */
|
|
if (ozone->has_all_assets)
|
|
ozone_draw_cursor_slice(ozone,
|
|
p_disp,
|
|
userdata,
|
|
video_width, video_height,
|
|
new_x, width, height, new_y, alpha);
|
|
else
|
|
ozone_draw_cursor_fallback(ozone,
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
new_x, width, height, new_y, alpha);
|
|
}
|
|
|
|
void ozone_draw_icon(
|
|
gfx_display_t *p_disp,
|
|
void *userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
unsigned icon_width,
|
|
unsigned icon_height,
|
|
uintptr_t texture,
|
|
float x, float y,
|
|
unsigned width, unsigned height,
|
|
float rotation, float scale_factor,
|
|
float *color)
|
|
{
|
|
gfx_display_ctx_rotate_draw_t rotate_draw;
|
|
gfx_display_ctx_draw_t draw;
|
|
struct video_coords coords;
|
|
math_matrix_4x4 mymat;
|
|
gfx_display_ctx_driver_t
|
|
*dispctx = p_disp->dispctx;
|
|
|
|
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;
|
|
|
|
gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
|
|
|
|
coords.vertices = 4;
|
|
coords.vertex = NULL;
|
|
coords.tex_coord = NULL;
|
|
coords.lut_tex_coord = NULL;
|
|
coords.color = (const float*)color;
|
|
|
|
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 = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
|
|
draw.pipeline_id = 0;
|
|
|
|
if (draw.height > 0 && draw.width > 0)
|
|
dispctx->draw(&draw, userdata, video_width, video_height);
|
|
}
|
|
|
|
void ozone_draw_backdrop(
|
|
void *userdata,
|
|
void *disp_data,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
float alpha)
|
|
{
|
|
static float ozone_backdrop[16] = {
|
|
0.00, 0.00, 0.00, 0.75,
|
|
0.00, 0.00, 0.00, 0.75,
|
|
0.00, 0.00, 0.00, 0.75,
|
|
0.00, 0.00, 0.00, 0.75,
|
|
};
|
|
static float last_alpha = 0.0f;
|
|
|
|
/* TODO: Replace this backdrop by a blur shader
|
|
* on the whole screen if available */
|
|
if (alpha != last_alpha)
|
|
{
|
|
gfx_display_set_alpha(ozone_backdrop, alpha);
|
|
last_alpha = alpha;
|
|
}
|
|
|
|
gfx_display_draw_quad(
|
|
(gfx_display_t*)disp_data,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
0,
|
|
0,
|
|
video_width,
|
|
video_height,
|
|
video_width,
|
|
video_height,
|
|
ozone_backdrop);
|
|
}
|
|
|
|
void ozone_draw_osk(ozone_handle_t *ozone,
|
|
void *userdata,
|
|
void *disp_userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
const char *label, const char *str)
|
|
{
|
|
unsigned i;
|
|
char message[2048];
|
|
gfx_display_t *p_disp = (gfx_display_t*)disp_userdata;
|
|
const char *text = str;
|
|
unsigned text_color = 0xffffffff;
|
|
static float ozone_osk_backdrop[16] = {
|
|
0.00, 0.00, 0.00, 0.15,
|
|
0.00, 0.00, 0.00, 0.15,
|
|
0.00, 0.00, 0.00, 0.15,
|
|
0.00, 0.00, 0.00, 0.15,
|
|
};
|
|
static retro_time_t last_time = 0;
|
|
struct string_list list = {0};
|
|
float scale_factor = ozone->last_scale_factor;
|
|
unsigned margin = 75 * scale_factor;
|
|
unsigned padding = 10 * scale_factor;
|
|
unsigned bottom_end = video_height / 2;
|
|
unsigned y_offset = 0;
|
|
bool draw_placeholder = string_is_empty(str);
|
|
retro_time_t current_time = menu_driver_get_current_time();
|
|
|
|
if (current_time - last_time >= INTERVAL_OSK_CURSOR)
|
|
{
|
|
ozone->osk_cursor = !ozone->osk_cursor;
|
|
last_time = current_time;
|
|
}
|
|
|
|
/* Border */
|
|
/* Top */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
margin,
|
|
margin,
|
|
video_width - margin*2,
|
|
ozone->dimensions.spacer_1px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme->entries_border);
|
|
|
|
/* Bottom */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
margin,
|
|
bottom_end - margin,
|
|
video_width - margin*2,
|
|
ozone->dimensions.spacer_1px,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme->entries_border);
|
|
|
|
/* Left */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
margin,
|
|
margin,
|
|
ozone->dimensions.spacer_1px,
|
|
bottom_end - margin*2,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme->entries_border);
|
|
|
|
/* Right */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
video_width - margin,
|
|
margin,
|
|
ozone->dimensions.spacer_1px,
|
|
bottom_end - margin*2,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme->entries_border);
|
|
|
|
/* Backdrop */
|
|
/* TODO: Remove the backdrop if blur shader is available */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
margin + ozone->dimensions.spacer_1px,
|
|
margin + ozone->dimensions.spacer_1px,
|
|
video_width - margin*2 - ozone->dimensions.spacer_2px,
|
|
bottom_end - margin*2 - ozone->dimensions.spacer_2px,
|
|
video_width,
|
|
video_height,
|
|
ozone_osk_backdrop);
|
|
|
|
/* Placeholder & text*/
|
|
if (draw_placeholder)
|
|
{
|
|
text = label;
|
|
text_color = ozone_theme_light.text_sublabel_rgba;
|
|
}
|
|
|
|
(ozone->word_wrap)(message, sizeof(message), text,
|
|
(video_width - margin*2 - padding*2) / ozone->fonts.entries_label.glyph_width,
|
|
ozone->fonts.entries_label.wideglyph_width, 0);
|
|
|
|
string_list_initialize(&list);
|
|
string_split_noalloc(&list, message, "\n");
|
|
|
|
for (i = 0; i < list.size; i++)
|
|
{
|
|
const char *msg = list.elems[i].data;
|
|
|
|
gfx_display_draw_text(
|
|
ozone->fonts.entries_label.font,
|
|
msg,
|
|
margin + padding * 2, /* x */
|
|
margin + padding +
|
|
ozone->fonts.entries_label.line_height
|
|
+ y_offset, /* y */
|
|
video_width, video_height,
|
|
text_color,
|
|
TEXT_ALIGN_LEFT,
|
|
1.0f,
|
|
false,
|
|
1.0f,
|
|
false);
|
|
|
|
/* Cursor */
|
|
if (i == list.size - 1)
|
|
{
|
|
if (ozone->osk_cursor)
|
|
{
|
|
unsigned cursor_x = draw_placeholder
|
|
? 0
|
|
: font_driver_get_message_width(
|
|
ozone->fonts.entries_label.font, msg,
|
|
(unsigned)strlen(msg), 1);
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
margin
|
|
+ padding * 2
|
|
+ cursor_x,
|
|
margin
|
|
+ padding
|
|
+ y_offset
|
|
+ ozone->fonts.entries_label.line_height
|
|
- ozone->fonts.entries_label.line_ascender
|
|
+ ozone->dimensions.spacer_3px,
|
|
ozone->dimensions.spacer_1px,
|
|
ozone->fonts.entries_label.line_ascender,
|
|
video_width,
|
|
video_height,
|
|
ozone->pure_white);
|
|
}
|
|
}
|
|
else
|
|
y_offset += 25 * scale_factor;
|
|
}
|
|
|
|
/* Keyboard */
|
|
gfx_display_draw_keyboard(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
ozone->theme->textures[OZONE_THEME_TEXTURE_CURSOR_STATIC],
|
|
ozone->fonts.entries_label.font,
|
|
input_event_get_osk_grid(),
|
|
input_event_get_osk_ptr(),
|
|
ozone->theme->text_rgba);
|
|
|
|
string_list_deinitialize(&list);
|
|
}
|
|
|
|
void ozone_draw_messagebox(
|
|
ozone_handle_t *ozone,
|
|
gfx_display_t *p_disp,
|
|
void *userdata,
|
|
unsigned video_width,
|
|
unsigned video_height,
|
|
const char *message)
|
|
{
|
|
unsigned i, y_position;
|
|
char wrapped_message[MENU_SUBLABEL_MAX_LENGTH];
|
|
int x, y, longest_width = 0;
|
|
int usable_width = 0;
|
|
struct string_list list = {0};
|
|
float scale_factor = 0.0f;
|
|
unsigned width = video_width;
|
|
unsigned height = video_height;
|
|
gfx_display_ctx_driver_t
|
|
*dispctx = p_disp->dispctx;
|
|
|
|
wrapped_message[0] = '\0';
|
|
|
|
/* Sanity check */
|
|
if (string_is_empty(message) ||
|
|
!ozone->fonts.footer.font)
|
|
return;
|
|
|
|
scale_factor = ozone->last_scale_factor;
|
|
usable_width = (int)width - (48 * 8 * scale_factor);
|
|
|
|
if (usable_width < 1)
|
|
return;
|
|
|
|
/* Split message into lines */
|
|
(ozone->word_wrap)(
|
|
wrapped_message, sizeof(wrapped_message), message,
|
|
usable_width / (int)ozone->fonts.footer.glyph_width,
|
|
ozone->fonts.footer.wideglyph_width, 0);
|
|
|
|
string_list_initialize(&list);
|
|
if (
|
|
!string_split_noalloc(&list, wrapped_message, "\n")
|
|
|| list.elems == 0)
|
|
{
|
|
string_list_deinitialize(&list);
|
|
return;
|
|
}
|
|
|
|
y_position = height / 2;
|
|
if (menu_input_dialog_get_display_kb())
|
|
y_position = height / 4;
|
|
|
|
x = width / 2;
|
|
y = y_position - (list.size
|
|
* ozone->fonts.footer.line_height) / 2;
|
|
|
|
/* find the longest line width */
|
|
for (i = 0; i < list.size; i++)
|
|
{
|
|
const char *msg = list.elems[i].data;
|
|
|
|
if (!string_is_empty(msg))
|
|
{
|
|
int width = font_driver_get_message_width(
|
|
ozone->fonts.footer.font, msg, (unsigned)strlen(msg), 1);
|
|
|
|
if (width > longest_width)
|
|
longest_width = width;
|
|
}
|
|
}
|
|
|
|
gfx_display_set_alpha(ozone->theme_dynamic.message_background, ozone->animations.messagebox_alpha);
|
|
|
|
if (dispctx && dispctx->blend_begin)
|
|
dispctx->blend_begin(userdata);
|
|
|
|
/* Avoid drawing a black box if there's no assets */
|
|
if (ozone->has_all_assets)
|
|
{
|
|
/* Note: The fact that we use a texture slice here
|
|
* makes things very messy
|
|
* > The actual size and offset of a texture slice
|
|
* is quite 'loose', and depends upon source image
|
|
* size, draw size and scale factor... */
|
|
unsigned slice_new_w = longest_width + 48 * 2 * scale_factor;
|
|
unsigned slice_new_h = ozone->fonts.footer.line_height * (list.size + 2);
|
|
int slice_x = x - longest_width/2 - 48 * scale_factor;
|
|
int slice_y = y - ozone->fonts.footer.line_height +
|
|
((slice_new_h >= 256)
|
|
? (16.0f * scale_factor)
|
|
: (16.0f * ((float)slice_new_h / 256.0f)));
|
|
|
|
gfx_display_draw_texture_slice(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
slice_x,
|
|
slice_y,
|
|
256, 256,
|
|
slice_new_w,
|
|
slice_new_h,
|
|
width, height,
|
|
ozone->theme_dynamic.message_background,
|
|
16, scale_factor,
|
|
ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DIALOG_SLICE]
|
|
);
|
|
}
|
|
|
|
for (i = 0; i < list.size; i++)
|
|
{
|
|
const char *msg = list.elems[i].data;
|
|
|
|
if (msg)
|
|
gfx_display_draw_text(
|
|
ozone->fonts.footer.font,
|
|
msg,
|
|
x - longest_width/2.0,
|
|
y + (i * ozone->fonts.footer.line_height) +
|
|
ozone->fonts.footer.line_ascender,
|
|
width,
|
|
height,
|
|
COLOR_TEXT_ALPHA(ozone->theme->text_rgba, (uint32_t)(ozone->animations.messagebox_alpha*255.0f)),
|
|
TEXT_ALIGN_LEFT,
|
|
1.0f,
|
|
false,
|
|
1.0f,
|
|
false);
|
|
}
|
|
|
|
string_list_deinitialize(&list);
|
|
}
|
|
|
|
void ozone_draw_fullscreen_thumbnails(
|
|
ozone_handle_t *ozone,
|
|
void *userdata,
|
|
void *disp_userdata,
|
|
unsigned video_width,
|
|
unsigned video_height)
|
|
{
|
|
/* Check whether fullscreen thumbnails are visible */
|
|
if (ozone->animations.fullscreen_thumbnail_alpha > 0.0f)
|
|
{
|
|
/* Note: right thumbnail is drawn at the top
|
|
* in the sidebar, so it becomes the *left*
|
|
* thumbnail when viewed fullscreen */
|
|
gfx_thumbnail_t *right_thumbnail = &ozone->thumbnails.left;
|
|
gfx_thumbnail_t *left_thumbnail = &ozone->thumbnails.right;
|
|
unsigned width = video_width;
|
|
unsigned height = video_height;
|
|
int view_width = (int)width;
|
|
gfx_display_t *p_disp = (gfx_display_t*)disp_userdata;
|
|
|
|
int view_height = (int)height - ozone->dimensions.header_height - ozone->dimensions.footer_height - ozone->dimensions.spacer_1px;
|
|
int thumbnail_margin = ozone->dimensions.fullscreen_thumbnail_padding;
|
|
bool show_right_thumbnail = false;
|
|
bool show_left_thumbnail = false;
|
|
unsigned num_thumbnails = 0;
|
|
float right_thumbnail_draw_width = 0.0f;
|
|
float right_thumbnail_draw_height = 0.0f;
|
|
float left_thumbnail_draw_width = 0.0f;
|
|
float left_thumbnail_draw_height = 0.0f;
|
|
float background_alpha = 0.85f;
|
|
static float background_color[16] = {
|
|
0.0f, 0.0f, 0.0f, 1.0f,
|
|
0.0f, 0.0f, 0.0f, 1.0f,
|
|
0.0f, 0.0f, 0.0f, 1.0f,
|
|
0.0f, 0.0f, 0.0f, 1.0f,
|
|
};
|
|
int frame_width = (int)((float)thumbnail_margin / 3.0f);
|
|
float frame_color[16];
|
|
float separator_color[16];
|
|
int thumbnail_box_width;
|
|
int thumbnail_box_height;
|
|
int right_thumbnail_x;
|
|
int left_thumbnail_x;
|
|
int thumbnail_y;
|
|
|
|
/* Sanity check: Return immediately if this is
|
|
* a menu without thumbnails and we are not currently
|
|
* 'fading out' the fullscreen thumbnail view */
|
|
if (!ozone->fullscreen_thumbnails_available &&
|
|
ozone->show_fullscreen_thumbnails)
|
|
goto error;
|
|
|
|
/* Safety check: ensure that current
|
|
* selection matches the entry selected when
|
|
* fullscreen thumbnails were enabled
|
|
* > Note that we exclude this check if we are
|
|
* currently viewing the quick menu and the
|
|
* thumbnail view is fading out. This enables
|
|
* a smooth transition if the user presses
|
|
* RetroPad A or keyboard 'return' to enter the
|
|
* quick menu while fullscreen thumbnails are
|
|
* being displayed */
|
|
if (((size_t)ozone->selection != ozone->fullscreen_thumbnail_selection) &&
|
|
(!ozone->is_quick_menu || ozone->show_fullscreen_thumbnails))
|
|
goto error;
|
|
|
|
/* Sanity check: Return immediately if the view
|
|
* width/height is < 1 */
|
|
if ((view_width < 1) || (view_height < 1))
|
|
goto error;
|
|
|
|
/* Get number of 'active' thumbnails */
|
|
show_right_thumbnail = (right_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE);
|
|
show_left_thumbnail = (left_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE);
|
|
|
|
if (show_right_thumbnail)
|
|
num_thumbnails++;
|
|
|
|
if (show_left_thumbnail)
|
|
num_thumbnails++;
|
|
|
|
/* Do nothing if both thumbnails are missing
|
|
* > Note: Baring inexplicable internal errors, this
|
|
* can never happen... */
|
|
if (num_thumbnails < 1)
|
|
goto error;
|
|
|
|
/* Get base thumbnail dimensions + draw positions */
|
|
|
|
/* > Thumbnail bounding box height + y position
|
|
* are fixed */
|
|
thumbnail_box_height = view_height - (thumbnail_margin * 2);
|
|
thumbnail_y = ozone->dimensions.header_height + thumbnail_margin + ozone->dimensions.spacer_1px;
|
|
|
|
/* Thumbnail bounding box width and x position
|
|
* depend upon number of active thumbnails */
|
|
if (num_thumbnails == 2)
|
|
{
|
|
thumbnail_box_width = (view_width - (thumbnail_margin * 3) - frame_width) >> 1;
|
|
left_thumbnail_x = thumbnail_margin;
|
|
right_thumbnail_x = left_thumbnail_x + thumbnail_box_width + frame_width + thumbnail_margin;
|
|
}
|
|
else
|
|
{
|
|
thumbnail_box_width = view_width - (thumbnail_margin * 2);
|
|
left_thumbnail_x = thumbnail_margin;
|
|
right_thumbnail_x = left_thumbnail_x;
|
|
}
|
|
|
|
/* Sanity check */
|
|
if ((thumbnail_box_width < 1) ||
|
|
(thumbnail_box_height < 1))
|
|
goto error;
|
|
|
|
/* Get thumbnail draw dimensions
|
|
* > Note: The following code is a bit awkward, since
|
|
* we have to do things in a very specific order
|
|
* - i.e. we cannot determine proper thumbnail
|
|
* layout until we have thumbnail draw dimensions.
|
|
* and we cannot get draw dimensions until we have
|
|
* the bounding box dimensions... */
|
|
if (show_right_thumbnail)
|
|
{
|
|
gfx_thumbnail_get_draw_dimensions(
|
|
right_thumbnail,
|
|
thumbnail_box_width, thumbnail_box_height, 1.0f,
|
|
&right_thumbnail_draw_width, &right_thumbnail_draw_height);
|
|
|
|
/* Sanity check */
|
|
if ((right_thumbnail_draw_width <= 0.0f) ||
|
|
(right_thumbnail_draw_height <= 0.0f))
|
|
goto error;
|
|
}
|
|
|
|
if (show_left_thumbnail)
|
|
{
|
|
gfx_thumbnail_get_draw_dimensions(
|
|
left_thumbnail,
|
|
thumbnail_box_width, thumbnail_box_height, 1.0f,
|
|
&left_thumbnail_draw_width, &left_thumbnail_draw_height);
|
|
|
|
/* Sanity check */
|
|
if ((left_thumbnail_draw_width <= 0.0f) ||
|
|
(left_thumbnail_draw_height <= 0.0f))
|
|
goto error;
|
|
}
|
|
|
|
/* Adjust thumbnail draw positions to achieve
|
|
* uniform appearance (accounting for actual
|
|
* draw dimensions...) */
|
|
if (num_thumbnails == 2)
|
|
{
|
|
int left_padding = (thumbnail_box_width - (int)left_thumbnail_draw_width) >> 1;
|
|
int right_padding = (thumbnail_box_width - (int)right_thumbnail_draw_width) >> 1;
|
|
|
|
/* Move thumbnails as close together as possible,
|
|
* and horizontally centre the resultant 'block'
|
|
* of images */
|
|
left_thumbnail_x += right_padding;
|
|
right_thumbnail_x -= left_padding;
|
|
}
|
|
|
|
/* Set colour values */
|
|
|
|
/* > Background */
|
|
gfx_display_set_alpha(
|
|
background_color,
|
|
background_alpha * ozone->animations.fullscreen_thumbnail_alpha);
|
|
|
|
/* > Separators */
|
|
memcpy(separator_color, ozone->theme->header_footer_separator, sizeof(separator_color));
|
|
gfx_display_set_alpha(
|
|
separator_color, ozone->animations.fullscreen_thumbnail_alpha);
|
|
|
|
/* > Thumbnail frame */
|
|
memcpy(frame_color, ozone->theme->sidebar_background, sizeof(frame_color));
|
|
gfx_display_set_alpha(
|
|
frame_color, ozone->animations.fullscreen_thumbnail_alpha);
|
|
|
|
/* Darken background */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
0,
|
|
ozone->dimensions.header_height + ozone->dimensions.spacer_1px,
|
|
width,
|
|
(unsigned)view_height,
|
|
width,
|
|
height,
|
|
background_color);
|
|
|
|
/* Draw full-width separators */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
0,
|
|
ozone->dimensions.header_height,
|
|
width,
|
|
ozone->dimensions.spacer_1px,
|
|
width,
|
|
height,
|
|
separator_color);
|
|
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
0,
|
|
height - ozone->dimensions.footer_height,
|
|
width,
|
|
ozone->dimensions.spacer_1px,
|
|
width,
|
|
height,
|
|
separator_color);
|
|
|
|
/* Draw thumbnails */
|
|
|
|
/* > Right */
|
|
if (show_right_thumbnail)
|
|
{
|
|
/* Background */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
right_thumbnail_x - frame_width +
|
|
((thumbnail_box_width - (int)right_thumbnail_draw_width) >> 1),
|
|
thumbnail_y - frame_width +
|
|
((thumbnail_box_height - (int)right_thumbnail_draw_height) >> 1),
|
|
(unsigned)right_thumbnail_draw_width + (frame_width << 1),
|
|
(unsigned)right_thumbnail_draw_height + (frame_width << 1),
|
|
width,
|
|
height,
|
|
frame_color);
|
|
|
|
/* Thumbnail */
|
|
gfx_thumbnail_draw(
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
right_thumbnail,
|
|
right_thumbnail_x,
|
|
thumbnail_y,
|
|
(unsigned)thumbnail_box_width,
|
|
(unsigned)thumbnail_box_height,
|
|
GFX_THUMBNAIL_ALIGN_CENTRE,
|
|
ozone->animations.fullscreen_thumbnail_alpha,
|
|
1.0f,
|
|
NULL);
|
|
}
|
|
|
|
/* > Left */
|
|
if (show_left_thumbnail)
|
|
{
|
|
/* Background */
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
left_thumbnail_x - frame_width +
|
|
((thumbnail_box_width - (int)left_thumbnail_draw_width) >> 1),
|
|
thumbnail_y - frame_width +
|
|
((thumbnail_box_height - (int)left_thumbnail_draw_height) >> 1),
|
|
(unsigned)left_thumbnail_draw_width + (frame_width << 1),
|
|
(unsigned)left_thumbnail_draw_height + (frame_width << 1),
|
|
width,
|
|
height,
|
|
frame_color);
|
|
|
|
/* Thumbnail */
|
|
gfx_thumbnail_draw(
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
left_thumbnail,
|
|
left_thumbnail_x,
|
|
thumbnail_y,
|
|
(unsigned)thumbnail_box_width,
|
|
(unsigned)thumbnail_box_height,
|
|
GFX_THUMBNAIL_ALIGN_CENTRE,
|
|
ozone->animations.fullscreen_thumbnail_alpha,
|
|
1.0f,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
/* If fullscreen thumbnails are enabled at
|
|
* this point, must disable them immediately... */
|
|
if (ozone->show_fullscreen_thumbnails)
|
|
ozone_hide_fullscreen_thumbnails(ozone, false);
|
|
}
|