mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 00:20:01 +00:00
346 lines
12 KiB
C
346 lines
12 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2014-2017 - Jean-André Santoni
|
|
* Copyright (C) 2015-2018 - Andre Leiradella
|
|
* 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 "../gfx_widgets.h"
|
|
#include "../gfx_animation.h"
|
|
#include "../gfx_display.h"
|
|
|
|
/* Widget state */
|
|
|
|
struct gfx_widget_progress_message_state
|
|
{
|
|
unsigned widget_width;
|
|
unsigned widget_height;
|
|
unsigned text_width;
|
|
unsigned bar_bg_width;
|
|
unsigned bar_bg_height;
|
|
|
|
unsigned bar_max_width;
|
|
unsigned bar_height;
|
|
|
|
unsigned priority;
|
|
|
|
float timer; /* float alignment */
|
|
float alpha;
|
|
float widget_x;
|
|
float widget_y;
|
|
float text_x;
|
|
float text_y;
|
|
float bar_bg_x;
|
|
float bar_bg_y;
|
|
float bar_x;
|
|
float bar_y;
|
|
float bar_bg_color[16];
|
|
float bar_color[16];
|
|
float bar_disabled_color[16];
|
|
|
|
int8_t progress;
|
|
char message[256];
|
|
bool active;
|
|
};
|
|
|
|
typedef struct gfx_widget_progress_message_state gfx_widget_progress_message_state_t;
|
|
|
|
static gfx_widget_progress_message_state_t p_w_progress_message_st = {
|
|
|
|
0, /* widget_width */
|
|
0, /* widget_height */
|
|
0, /* text_width */
|
|
0, /* bar_bg_width */
|
|
0, /* bar_bg_height */
|
|
|
|
0, /* bar_max_width */
|
|
0, /* bar_height */
|
|
|
|
0, /* priority */
|
|
|
|
0.0f, /* timer */
|
|
0.0f, /* alpha */
|
|
0.0f, /* widget_x */
|
|
0.0f, /* widget_y */
|
|
|
|
0.0f, /* text_x */
|
|
0.0f, /* text_y */
|
|
|
|
0.0f, /* bar_bg_x */
|
|
0.0f, /* bar_bg_y */
|
|
|
|
0.0f, /* bar_x */
|
|
0.0f, /* bar_y */
|
|
|
|
COLOR_HEX_TO_FLOAT(0x3A3A3A, 1.0f), /* bar_bg_color */
|
|
COLOR_HEX_TO_FLOAT(0x198AC6, 1.0f), /* bar_color */
|
|
COLOR_HEX_TO_FLOAT(0x000000, 1.0f), /* bar_disabled_color */
|
|
|
|
-1, /* progress */
|
|
{'\0'}, /* message */
|
|
false, /* active */
|
|
};
|
|
|
|
/* Callbacks */
|
|
|
|
static void gfx_widget_progress_message_fadeout_cb(void *userdata)
|
|
{
|
|
gfx_widget_progress_message_state_t *state = (gfx_widget_progress_message_state_t*)userdata;
|
|
|
|
/* Deactivate widget */
|
|
state->active = false;
|
|
}
|
|
|
|
static void gfx_widget_progress_message_fadeout(void *userdata)
|
|
{
|
|
gfx_animation_ctx_entry_t animation_entry;
|
|
gfx_widget_progress_message_state_t *state = (gfx_widget_progress_message_state_t*)userdata;
|
|
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
|
|
|
/* Trigger fade out animation */
|
|
animation_entry.easing_enum = EASING_OUT_QUAD;
|
|
animation_entry.tag = alpha_tag;
|
|
animation_entry.duration = MSG_QUEUE_ANIMATION_DURATION;
|
|
animation_entry.target_value = 0.0f;
|
|
animation_entry.subject = &state->alpha;
|
|
animation_entry.cb = gfx_widget_progress_message_fadeout_cb;
|
|
animation_entry.userdata = state;
|
|
|
|
gfx_animation_push(&animation_entry);
|
|
}
|
|
|
|
/* Widget interface */
|
|
|
|
void gfx_widget_set_progress_message(
|
|
const char *message, unsigned duration,
|
|
unsigned priority, int8_t progress)
|
|
{
|
|
size_t _len;
|
|
gfx_timer_ctx_entry_t timer;
|
|
dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
|
|
gfx_widget_progress_message_state_t *state = &p_w_progress_message_st;
|
|
gfx_widget_font_data_t *font_regular = &p_dispwidget->gfx_widget_fonts.regular;
|
|
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
|
uintptr_t timer_tag = (uintptr_t)&state->timer;
|
|
|
|
/* Ensure we have a valid message string */
|
|
if (string_is_empty(message))
|
|
return;
|
|
|
|
/* If widget is currently active, ignore new
|
|
* message if it has a lower priority */
|
|
if (state->active && (state->priority > priority))
|
|
return;
|
|
|
|
/* Cache message parameters */
|
|
_len = strlcpy(state->message, message, sizeof(state->message));
|
|
state->priority = priority;
|
|
state->progress = progress;
|
|
|
|
/* Cache text width */
|
|
state->text_width = font_driver_get_message_width(
|
|
font_regular->font,
|
|
state->message, _len,
|
|
1.0f);
|
|
|
|
/* Kill any existing timer/animation */
|
|
gfx_animation_kill_by_tag(&timer_tag);
|
|
gfx_animation_kill_by_tag(&alpha_tag);
|
|
|
|
/* Start new message timer */
|
|
timer.duration = duration;
|
|
timer.cb = gfx_widget_progress_message_fadeout;
|
|
timer.userdata = state;
|
|
|
|
gfx_animation_timer_start(&state->timer, &timer);
|
|
|
|
/* Set initial widget opacity */
|
|
state->alpha = 1.0f;
|
|
|
|
/* Set 'active' flag */
|
|
state->active = true;
|
|
}
|
|
|
|
/* Widget layout() */
|
|
|
|
static void gfx_widget_progress_message_layout(
|
|
void *data,
|
|
bool is_threaded, const char *dir_assets, char *font_path)
|
|
{
|
|
float bar_padding;
|
|
dispgfx_widget_t *p_dispwidget = (dispgfx_widget_t*)data;
|
|
gfx_widget_progress_message_state_t *state = &p_w_progress_message_st;
|
|
unsigned last_video_width = p_dispwidget->last_video_width;
|
|
unsigned last_video_height = p_dispwidget->last_video_height;
|
|
unsigned widget_padding = p_dispwidget->simple_widget_padding;
|
|
gfx_widget_font_data_t *font_regular = &p_dispwidget->gfx_widget_fonts.regular;
|
|
|
|
/* Base widget layout */
|
|
state->widget_width = last_video_width;
|
|
state->widget_height = (unsigned)(((float)font_regular->line_height * 3.3f) + 0.5f);
|
|
state->widget_x = 0.0f;
|
|
state->widget_y = (float)(last_video_height - state->widget_height);
|
|
|
|
/* Text layout */
|
|
state->text_x = (float)last_video_width / 2.0f;
|
|
state->text_y = (float)(last_video_height -
|
|
font_regular->line_height + font_regular->line_centre_offset);
|
|
|
|
/* Progress bar layout */
|
|
state->bar_bg_width = last_video_width - (2 * widget_padding);
|
|
state->bar_bg_height = (unsigned)(((float)font_regular->line_height * 0.7f) + 0.5f);
|
|
state->bar_bg_x = (float)widget_padding;
|
|
state->bar_bg_y = (float)last_video_height -
|
|
(float)state->widget_height +
|
|
(((float)state->widget_height - (font_regular->line_height * 1.5f)) * 0.5f) -
|
|
((float)state->bar_bg_height * 0.5f);
|
|
|
|
state->bar_height = (unsigned)(((float)font_regular->line_height * 0.5f) + 0.5f);
|
|
bar_padding = (float)(state->bar_bg_height - state->bar_height) * 0.5f;
|
|
state->bar_max_width = state->bar_bg_width - (unsigned)((bar_padding * 2.0f) + 0.5f);
|
|
state->bar_x = state->bar_bg_x + bar_padding;
|
|
state->bar_y = state->bar_bg_y + bar_padding;
|
|
}
|
|
|
|
/* Widget frame() */
|
|
|
|
static void gfx_widget_progress_message_frame(void *data, void *user_data)
|
|
{
|
|
gfx_widget_progress_message_state_t *state = &p_w_progress_message_st;
|
|
|
|
if (state->active)
|
|
{
|
|
video_frame_info_t *video_info = (video_frame_info_t*)data;
|
|
dispgfx_widget_t *p_dispwidget = (dispgfx_widget_t*)user_data;
|
|
|
|
unsigned video_width = video_info->width;
|
|
unsigned video_height = video_info->height;
|
|
void *userdata = video_info->userdata;
|
|
gfx_display_t *p_disp = (gfx_display_t*)video_info->disp_userdata;
|
|
|
|
float *backdrop_color = p_dispwidget->backdrop_orig;
|
|
unsigned text_color = COLOR_TEXT_ALPHA(0xFFFFFFFF, (unsigned)(state->alpha * 255.0f));
|
|
|
|
gfx_widget_font_data_t *font_regular = &p_dispwidget->gfx_widget_fonts.regular;
|
|
size_t msg_queue_size = p_dispwidget->current_msgs_size;
|
|
unsigned bar_width = state->bar_max_width;
|
|
float *bar_color = state->bar_disabled_color;
|
|
|
|
/* Draw backdrop */
|
|
gfx_display_set_alpha(backdrop_color, state->alpha * DEFAULT_BACKDROP);
|
|
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
state->widget_x,
|
|
state->widget_y,
|
|
state->widget_width,
|
|
state->widget_height,
|
|
video_width,
|
|
video_height,
|
|
backdrop_color,
|
|
NULL);
|
|
|
|
/* Draw progress bar background */
|
|
gfx_display_set_alpha(state->bar_bg_color, state->alpha);
|
|
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
state->bar_bg_x,
|
|
state->bar_bg_y,
|
|
state->bar_bg_width,
|
|
state->bar_bg_height,
|
|
video_width,
|
|
video_height,
|
|
state->bar_bg_color,
|
|
NULL);
|
|
|
|
/* Draw progress bar */
|
|
if (state->progress >= 0)
|
|
{
|
|
bar_width = (unsigned)((((float)state->progress / 100.0f) * (float)state->bar_max_width) + 0.5f);
|
|
if (bar_width > state->bar_max_width)
|
|
bar_width = state->bar_max_width;
|
|
|
|
bar_color = state->bar_color;
|
|
}
|
|
|
|
gfx_display_set_alpha(bar_color, state->alpha);
|
|
|
|
gfx_display_draw_quad(
|
|
p_disp,
|
|
userdata,
|
|
video_width,
|
|
video_height,
|
|
state->bar_x,
|
|
state->bar_y,
|
|
bar_width,
|
|
state->bar_height,
|
|
video_width,
|
|
video_height,
|
|
bar_color,
|
|
NULL);
|
|
|
|
/* Draw message text */
|
|
gfx_widgets_draw_text(
|
|
font_regular,
|
|
state->message,
|
|
state->text_x,
|
|
state->text_y,
|
|
video_width,
|
|
video_height,
|
|
text_color,
|
|
TEXT_ALIGN_CENTER,
|
|
true);
|
|
|
|
/* If the message queue is active, must flush the
|
|
* text here to avoid overlaps */
|
|
if (msg_queue_size > 0)
|
|
gfx_widgets_flush_text(video_width, video_height, font_regular);
|
|
}
|
|
}
|
|
|
|
/* Widget free() */
|
|
|
|
static void gfx_widget_progress_message_free(void)
|
|
{
|
|
gfx_widget_progress_message_state_t *state = &p_w_progress_message_st;
|
|
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
|
uintptr_t timer_tag = (uintptr_t)&state->timer;
|
|
|
|
/* Kill any existing timer / animation */
|
|
gfx_animation_kill_by_tag(&timer_tag);
|
|
gfx_animation_kill_by_tag(&alpha_tag);
|
|
|
|
/* Deactivate widget */
|
|
state->alpha = 0.0f;
|
|
state->active = false;
|
|
}
|
|
|
|
/* Widget definition */
|
|
|
|
const gfx_widget_t gfx_widget_progress_message = {
|
|
NULL, /* init */
|
|
gfx_widget_progress_message_free,
|
|
NULL, /* context_reset*/
|
|
NULL, /* context_destroy */
|
|
gfx_widget_progress_message_layout,
|
|
NULL, /* iterate */
|
|
gfx_widget_progress_message_frame
|
|
};
|