mirror of
https://github.com/libretro/RetroArch
synced 2025-02-07 12:39:54 +00:00
Merge pull request #11235 from jdgleaver/generic-message-widget
Improve appearance of 'generic_message' widget
This commit is contained in:
commit
513909a581
@ -40,7 +40,6 @@
|
||||
#define TASK_FINISHED_DURATION 3000
|
||||
#define HOURGLASS_INTERVAL 5000
|
||||
#define HOURGLASS_DURATION 1000
|
||||
#define GENERIC_MESSAGE_DURATION 3000
|
||||
|
||||
/* TODO: Colors for warning, error and success */
|
||||
|
||||
@ -371,7 +370,9 @@ void gfx_widgets_push_achievement(const char *title, const char *badge);
|
||||
#endif
|
||||
|
||||
/* Warning: not thread safe! */
|
||||
void gfx_widget_set_message(char *message);
|
||||
void gfx_widget_set_generic_message(
|
||||
void *data,
|
||||
const char *message, unsigned duration);
|
||||
|
||||
/* Warning: not thread safe! */
|
||||
void gfx_widget_set_libretro_message(
|
||||
|
@ -20,118 +20,540 @@
|
||||
#include "../gfx_display.h"
|
||||
#include "../../retroarch.h"
|
||||
|
||||
#define GENERIC_MESSAGE_FADE_DURATION MSG_QUEUE_ANIMATION_DURATION
|
||||
|
||||
/* Widget state */
|
||||
|
||||
enum gfx_widget_generic_message_status
|
||||
{
|
||||
GFX_WIDGET_GENERIC_MESSAGE_IDLE = 0,
|
||||
GFX_WIDGET_GENERIC_MESSAGE_SLIDE_IN,
|
||||
GFX_WIDGET_GENERIC_MESSAGE_FADE_IN,
|
||||
GFX_WIDGET_GENERIC_MESSAGE_WAIT,
|
||||
GFX_WIDGET_GENERIC_MESSAGE_FADE_OUT
|
||||
};
|
||||
|
||||
struct gfx_widget_generic_message_state
|
||||
{
|
||||
unsigned bg_min_width;
|
||||
unsigned bg_width;
|
||||
unsigned bg_height;
|
||||
unsigned frame_width;
|
||||
unsigned text_padding;
|
||||
unsigned text_color;
|
||||
|
||||
unsigned message_duration;
|
||||
|
||||
gfx_timer_t timer; /* float alignment */
|
||||
|
||||
float bg_x;
|
||||
float bg_y_start;
|
||||
float bg_y_end;
|
||||
float text_x;
|
||||
float text_y_start;
|
||||
float text_y_end;
|
||||
|
||||
float alpha;
|
||||
char message[256];
|
||||
|
||||
float bg_color[16];
|
||||
float frame_color[16];
|
||||
|
||||
enum gfx_widget_generic_message_status status;
|
||||
|
||||
char message[512];
|
||||
bool message_updated;
|
||||
};
|
||||
|
||||
typedef struct gfx_widget_generic_message_state gfx_widget_generic_message_state_t;
|
||||
|
||||
static gfx_widget_generic_message_state_t p_w_generic_message_st = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
{'\0'}
|
||||
|
||||
0, /* bg_min_width */
|
||||
0, /* bg_width */
|
||||
0, /* bg_height */
|
||||
0, /* frame_width */
|
||||
0, /* text_padding */
|
||||
0xFFFFFFFF, /* text_color */
|
||||
|
||||
0, /* message_duration */
|
||||
|
||||
0.0f, /* timer */
|
||||
|
||||
0.0f, /* bg_x */
|
||||
0.0f, /* bg_y_start */
|
||||
0.0f, /* bg_y_end */
|
||||
0.0f, /* text_x */
|
||||
0.0f, /* text_y_start */
|
||||
0.0f, /* text_y_end */
|
||||
|
||||
0.0f, /* alpha */
|
||||
|
||||
COLOR_HEX_TO_FLOAT(0x3A3A3A, 1.0f), /* bg_color */
|
||||
COLOR_HEX_TO_FLOAT(0x7A7A7A, 1.0f), /* frame_color */
|
||||
|
||||
GFX_WIDGET_GENERIC_MESSAGE_IDLE, /* status */
|
||||
|
||||
{'\0'}, /* message */
|
||||
false /* message_updated */
|
||||
};
|
||||
|
||||
static gfx_widget_generic_message_state_t* gfx_widget_generic_message_get_ptr(void)
|
||||
static gfx_widget_generic_message_state_t* gfx_widget_generic_message_get_state(void)
|
||||
{
|
||||
return &p_w_generic_message_st;
|
||||
}
|
||||
|
||||
static void gfx_widget_generic_message_fadeout(void *userdata)
|
||||
/* Utilities */
|
||||
|
||||
static void gfx_widget_generic_message_reset(bool cancel_pending)
|
||||
{
|
||||
gfx_animation_ctx_entry_t entry;
|
||||
gfx_widget_generic_message_state_t* state =
|
||||
gfx_widget_generic_message_get_ptr();
|
||||
uintptr_t tag = (uintptr_t) &state->timer;
|
||||
gfx_widget_generic_message_state_t *state = gfx_widget_generic_message_get_state();
|
||||
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
||||
|
||||
/* Start fade out animation */
|
||||
entry.cb = NULL;
|
||||
entry.duration = MSG_QUEUE_ANIMATION_DURATION;
|
||||
entry.easing_enum = EASING_OUT_QUAD;
|
||||
entry.subject = &state->alpha;
|
||||
entry.tag = tag;
|
||||
entry.target_value = 0.0f;
|
||||
entry.userdata = NULL;
|
||||
/* Kill any existing timers/animations */
|
||||
gfx_timer_kill(&state->timer);
|
||||
gfx_animation_kill_by_tag(&alpha_tag);
|
||||
|
||||
gfx_animation_push(&entry);
|
||||
/* Reset status */
|
||||
state->status = GFX_WIDGET_GENERIC_MESSAGE_IDLE;
|
||||
if (cancel_pending)
|
||||
state->message_updated = false;
|
||||
}
|
||||
|
||||
void gfx_widget_set_message(char *msg)
|
||||
/* Callbacks */
|
||||
|
||||
static void gfx_widget_generic_message_fade_out_cb(void *userdata)
|
||||
{
|
||||
gfx_widget_generic_message_reset(false);
|
||||
}
|
||||
|
||||
static void gfx_widget_generic_message_wait_cb(void *userdata)
|
||||
{
|
||||
gfx_widget_generic_message_state_t *state = (gfx_widget_generic_message_state_t*)userdata;
|
||||
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
||||
gfx_animation_ctx_entry_t animation_entry;
|
||||
|
||||
/* Trigger fade out */
|
||||
state->alpha = 1.0f;
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = alpha_tag;
|
||||
animation_entry.duration = GENERIC_MESSAGE_FADE_DURATION;
|
||||
animation_entry.target_value = 0.0f;
|
||||
animation_entry.subject = &state->alpha;
|
||||
animation_entry.cb = gfx_widget_generic_message_fade_out_cb;
|
||||
animation_entry.userdata = NULL;
|
||||
|
||||
gfx_animation_push(&animation_entry);
|
||||
state->status = GFX_WIDGET_GENERIC_MESSAGE_FADE_OUT;
|
||||
}
|
||||
|
||||
static void gfx_widget_generic_message_slide_in_cb(void *userdata)
|
||||
{
|
||||
gfx_widget_generic_message_state_t *state = (gfx_widget_generic_message_state_t*)userdata;
|
||||
gfx_timer_ctx_entry_t timer;
|
||||
gfx_widget_generic_message_state_t* state =
|
||||
gfx_widget_generic_message_get_ptr();
|
||||
uintptr_t tag = (uintptr_t) &state->timer;
|
||||
|
||||
strlcpy(state->message, msg, sizeof(state->message));
|
||||
|
||||
state->alpha = DEFAULT_BACKDROP;
|
||||
|
||||
/* Kill and restart the timer / animation */
|
||||
gfx_timer_kill(&state->timer);
|
||||
gfx_animation_kill_by_tag(&tag);
|
||||
|
||||
timer.cb = gfx_widget_generic_message_fadeout;
|
||||
timer.duration = GENERIC_MESSAGE_DURATION;
|
||||
timer.userdata = NULL;
|
||||
/* Start wait timer */
|
||||
state->alpha = 1.0f;
|
||||
timer.duration = state->message_duration;
|
||||
timer.cb = gfx_widget_generic_message_wait_cb;
|
||||
timer.userdata = state;
|
||||
|
||||
gfx_timer_start(&state->timer, &timer);
|
||||
state->status = GFX_WIDGET_GENERIC_MESSAGE_WAIT;
|
||||
}
|
||||
|
||||
static void gfx_widget_generic_message_frame(void* data, void *user_data)
|
||||
/* Widget interface */
|
||||
|
||||
void gfx_widget_set_generic_message(void *data,
|
||||
const char *msg, unsigned duration)
|
||||
{
|
||||
gfx_widget_generic_message_state_t* state =
|
||||
gfx_widget_generic_message_get_ptr();
|
||||
dispgfx_widget_t *p_dispwidget = (dispgfx_widget_t*)data;
|
||||
gfx_widget_generic_message_state_t *state = gfx_widget_generic_message_get_state();
|
||||
unsigned last_video_width = gfx_widgets_get_last_video_width(p_dispwidget);
|
||||
int text_width = 0;
|
||||
gfx_widget_font_data_t *font_msg_queue = gfx_widgets_get_font_msg_queue(p_dispwidget);
|
||||
|
||||
if (state->alpha > 0.0f)
|
||||
/* Ensure we have a valid message string */
|
||||
if (string_is_empty(msg))
|
||||
return;
|
||||
|
||||
/* Cache message parameters */
|
||||
strlcpy(state->message, msg, sizeof(state->message));
|
||||
state->message_duration = duration;
|
||||
|
||||
/* Get background width */
|
||||
text_width = font_driver_get_message_width(
|
||||
font_msg_queue->font, state->message,
|
||||
(unsigned)strlen(state->message), 1.0f);
|
||||
text_width = (text_width < 0) ?
|
||||
0 : text_width;
|
||||
state->bg_width = (state->text_padding * 2) + (unsigned)text_width;
|
||||
|
||||
state->bg_width = (state->bg_width < state->bg_min_width) ?
|
||||
state->bg_min_width : state->bg_width;
|
||||
state->bg_width = (state->bg_width > last_video_width) ?
|
||||
last_video_width : state->bg_width;
|
||||
|
||||
/* Update x draw positions */
|
||||
state->bg_x = ((float)last_video_width - (float)state->bg_width) * 0.5f;
|
||||
state->text_x = ((float)last_video_width - (float)text_width) * 0.5f;
|
||||
state->text_x = (state->text_x < (float)state->text_padding) ?
|
||||
(float)state->text_padding : state->text_x;
|
||||
|
||||
/* If a 'slide in' animation is already in
|
||||
* progress, no further action is required;
|
||||
* just let animation continue with the updated
|
||||
* message text */
|
||||
if (state->status == GFX_WIDGET_GENERIC_MESSAGE_SLIDE_IN)
|
||||
return;
|
||||
|
||||
/* Signal that message has been updated
|
||||
* > Note that we have to defer the triggering
|
||||
* of any animation changes until the next
|
||||
* call of gfx_widget_generic_message_iterate().
|
||||
* This is because cores will often send messages
|
||||
* during initialisation - i.e. during processes
|
||||
* that take a non-trivial amount of time. In these
|
||||
* cases, updating the animation state here would
|
||||
* result in the following:
|
||||
* - Core starts initialisation/load content
|
||||
* - Message is set, animation is triggered
|
||||
* - Core finishes initialisation/load content,
|
||||
* taking multiple 100's of ms
|
||||
* - On next runloop iterate, animation status
|
||||
* is checked - but because initialisation
|
||||
* took so long, the animation duration has
|
||||
* already elapsed
|
||||
* - Animation 'finishes' immediately, and the
|
||||
* user never sees it... */
|
||||
state->message_updated = true;
|
||||
}
|
||||
|
||||
/* Widget layout() */
|
||||
|
||||
static void gfx_widget_generic_message_layout(
|
||||
void *data,
|
||||
bool is_threaded, const char *dir_assets, char *font_path)
|
||||
{
|
||||
dispgfx_widget_t *p_dispwidget = (dispgfx_widget_t*)data;
|
||||
gfx_widget_generic_message_state_t *state = gfx_widget_generic_message_get_state();
|
||||
|
||||
unsigned last_video_width = gfx_widgets_get_last_video_width(p_dispwidget);
|
||||
unsigned last_video_height = gfx_widgets_get_last_video_height(p_dispwidget);
|
||||
unsigned divider_width = gfx_widgets_get_divider_width(p_dispwidget);
|
||||
unsigned widget_padding = 0;
|
||||
int text_width = 0;
|
||||
const float base_aspect = 4.0f / 3.0f;
|
||||
float widget_margin = 0.0f;
|
||||
gfx_widget_font_data_t *font_msg_queue = gfx_widgets_get_font_msg_queue(p_dispwidget);
|
||||
|
||||
/* Set padding values */
|
||||
state->text_padding = (unsigned)(((float)font_msg_queue->line_height * (2.0f / 3.0f)) + 0.5f);
|
||||
widget_padding = state->text_padding * 2;
|
||||
|
||||
/* Set frame width */
|
||||
state->frame_width = divider_width * 2;
|
||||
|
||||
/* Set minimum background width
|
||||
* > Widget nominally occupies the full width
|
||||
* of a 4:3 region at the centre of the screen,
|
||||
* minus padding (it may expand if the text is
|
||||
* too long to fit within these bounds) */
|
||||
widget_margin = (float)last_video_width -
|
||||
(base_aspect * (float)last_video_height);
|
||||
widget_margin = (widget_margin < 0.0f) ?
|
||||
0.0f : widget_margin;
|
||||
|
||||
state->bg_min_width = last_video_width - (unsigned)widget_margin -
|
||||
((widget_padding + state->frame_width) * 2);
|
||||
state->bg_min_width = (state->bg_min_width > last_video_width) ?
|
||||
last_video_width : state->bg_min_width;
|
||||
|
||||
/* Set background width */
|
||||
state->bg_width = state->text_padding * 2;
|
||||
|
||||
if (!string_is_empty(state->message))
|
||||
{
|
||||
video_frame_info_t* video_info = (video_frame_info_t*)data;
|
||||
void* userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
unsigned height = gfx_widgets_get_generic_message_height(user_data);
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(user_data);
|
||||
size_t msg_queue_size = gfx_widgets_get_msg_queue_size(user_data);
|
||||
text_width = font_driver_get_message_width(
|
||||
font_msg_queue->font, state->message,
|
||||
(unsigned)strlen(state->message), 1.0f);
|
||||
text_width = (text_width < 0) ?
|
||||
0 : text_width;
|
||||
|
||||
gfx_display_set_alpha(gfx_widgets_get_backdrop_orig(), state->alpha);
|
||||
state->bg_width += (unsigned)text_width;
|
||||
}
|
||||
|
||||
gfx_display_draw_quad(userdata,
|
||||
video_width, video_height,
|
||||
0, video_height - height,
|
||||
video_width, height,
|
||||
video_width, video_height,
|
||||
gfx_widgets_get_backdrop_orig());
|
||||
state->bg_width = (state->bg_width < state->bg_min_width) ?
|
||||
state->bg_min_width : state->bg_width;
|
||||
state->bg_width = (state->bg_width > last_video_width) ?
|
||||
last_video_width : state->bg_width;
|
||||
|
||||
gfx_widgets_draw_text(font_regular, state->message,
|
||||
video_width/2,
|
||||
video_height - height/2.0f + font_regular->line_centre_offset,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
false);
|
||||
/* Set background height */
|
||||
state->bg_height = font_msg_queue->line_height * 2;
|
||||
|
||||
/* 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);
|
||||
/* Set background draw positions */
|
||||
state->bg_x = ((float)last_video_width - (float)state->bg_width) * 0.5f;
|
||||
state->bg_y_start = (float)last_video_height + (float)state->frame_width;
|
||||
state->bg_y_end = (float)last_video_height - (float)state->bg_height;
|
||||
|
||||
/* Set text draw positions
|
||||
* > Text is drawn at the horizontal centre
|
||||
* of the screen - unless it is too long to
|
||||
* fit within the bounds of the window, in
|
||||
* which case we shift it to the right such
|
||||
* that the start of the string can be seen */
|
||||
state->text_x = ((float)last_video_width - (float)text_width) * 0.5f;
|
||||
state->text_x = (state->text_x < (float)state->text_padding) ?
|
||||
(float)state->text_padding : state->text_x;
|
||||
state->text_y_start = state->bg_y_start + ((float)state->bg_height * 0.5f) +
|
||||
(float)font_msg_queue->line_centre_offset;
|
||||
state->text_y_end = state->bg_y_end + ((float)state->bg_height * 0.5f) +
|
||||
(float)font_msg_queue->line_centre_offset;
|
||||
}
|
||||
|
||||
/* Widget iterate() */
|
||||
|
||||
static void gfx_widget_generic_message_iterate(void *user_data,
|
||||
unsigned width, unsigned height, bool fullscreen,
|
||||
const char *dir_assets, char *font_path,
|
||||
bool is_threaded)
|
||||
{
|
||||
gfx_widget_generic_message_state_t *state = gfx_widget_generic_message_get_state();
|
||||
|
||||
if (state->message_updated)
|
||||
{
|
||||
enum gfx_widget_generic_message_status current_status = state->status;
|
||||
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
||||
gfx_animation_ctx_entry_t animation_entry;
|
||||
|
||||
/* In all cases, reset any existing animation */
|
||||
gfx_widget_generic_message_reset(false);
|
||||
|
||||
/* If an animation was already in progress,
|
||||
* have to continue from the last active
|
||||
* animation phase */
|
||||
switch (current_status)
|
||||
{
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_IDLE:
|
||||
/* Trigger 'slide in' animation */
|
||||
state->alpha = 0.0f;
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = alpha_tag;
|
||||
animation_entry.duration = GENERIC_MESSAGE_FADE_DURATION;
|
||||
animation_entry.target_value = 1.0f;
|
||||
animation_entry.subject = &state->alpha;
|
||||
animation_entry.cb = gfx_widget_generic_message_slide_in_cb;
|
||||
animation_entry.userdata = state;
|
||||
|
||||
gfx_animation_push(&animation_entry);
|
||||
state->status = GFX_WIDGET_GENERIC_MESSAGE_SLIDE_IN;
|
||||
break;
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_FADE_IN:
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_FADE_OUT:
|
||||
{
|
||||
/* If we are fading in or out, start
|
||||
* a new fade in animation (transitioning
|
||||
* from the current alpha value to 1.0) */
|
||||
unsigned fade_duration = (unsigned)(((1.0f - state->alpha) *
|
||||
(float)GENERIC_MESSAGE_FADE_DURATION) + 0.5f);
|
||||
fade_duration = (fade_duration > GENERIC_MESSAGE_FADE_DURATION) ?
|
||||
GENERIC_MESSAGE_FADE_DURATION : fade_duration;
|
||||
|
||||
/* > If current and final alpha values are the
|
||||
* same, or fade duration is zero, skip
|
||||
* straight to the wait phase */
|
||||
if ((state->alpha >= 1.0f) || (fade_duration < 1))
|
||||
gfx_widget_generic_message_slide_in_cb(state);
|
||||
else
|
||||
{
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = alpha_tag;
|
||||
animation_entry.duration = fade_duration;
|
||||
animation_entry.target_value = 1.0f;
|
||||
animation_entry.subject = &state->alpha;
|
||||
/* Note that 'slide in' and 'fade in' share
|
||||
* the same callback */
|
||||
animation_entry.cb = gfx_widget_generic_message_slide_in_cb;
|
||||
animation_entry.userdata = state;
|
||||
|
||||
gfx_animation_push(&animation_entry);
|
||||
state->status = GFX_WIDGET_GENERIC_MESSAGE_FADE_IN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_WAIT:
|
||||
/* If we are currently waiting, just
|
||||
* 'reset' the wait timer */
|
||||
gfx_widget_generic_message_slide_in_cb(state);
|
||||
break;
|
||||
default:
|
||||
/* The only remaining case is
|
||||
* GFX_WIDGET_GENERIC_MESSAGE_SLIDE_IN,
|
||||
* which can never happen (state->message_updated
|
||||
* will be false if it is, so this code will
|
||||
* not be invoked). If we reach this point, an
|
||||
* unknown error has occurred. We have already
|
||||
* reset any existing animation, so no further
|
||||
* action is required */
|
||||
break;
|
||||
}
|
||||
|
||||
state->message_updated = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Widget frame() */
|
||||
|
||||
static void gfx_widget_generic_message_frame(void *data, void *user_data)
|
||||
{
|
||||
gfx_widget_generic_message_state_t *state = gfx_widget_generic_message_get_state();
|
||||
|
||||
if (state->status != GFX_WIDGET_GENERIC_MESSAGE_IDLE)
|
||||
{
|
||||
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_widget_font_data_t *font_msg_queue = gfx_widgets_get_font_msg_queue(p_dispwidget);
|
||||
size_t msg_queue_size = gfx_widgets_get_msg_queue_size(p_dispwidget);
|
||||
|
||||
unsigned text_color;
|
||||
float widget_alpha;
|
||||
float bg_y;
|
||||
float text_y;
|
||||
|
||||
/* Determine status-dependent opacity/position
|
||||
* values */
|
||||
switch (state->status)
|
||||
{
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_SLIDE_IN:
|
||||
widget_alpha = state->alpha;
|
||||
/* Use 'alpha' to determine the draw offset
|
||||
* > Saves having to trigger two animations */
|
||||
bg_y = state->bg_y_start + (state->alpha *
|
||||
(state->bg_y_end - state->bg_y_start));
|
||||
text_y = state->text_y_start + (state->alpha *
|
||||
(state->text_y_end - state->text_y_start));
|
||||
break;
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_FADE_IN:
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_FADE_OUT:
|
||||
widget_alpha = state->alpha;
|
||||
bg_y = state->bg_y_end;
|
||||
text_y = state->text_y_end;
|
||||
break;
|
||||
case GFX_WIDGET_GENERIC_MESSAGE_WAIT:
|
||||
widget_alpha = 1.0f;
|
||||
bg_y = state->bg_y_end;
|
||||
text_y = state->text_y_end;
|
||||
break;
|
||||
default:
|
||||
widget_alpha = 0.0f;
|
||||
bg_y = state->bg_y_start;
|
||||
text_y = state->text_y_start;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Draw widget */
|
||||
if (widget_alpha > 0.0f)
|
||||
{
|
||||
/* Set opacity */
|
||||
gfx_display_set_alpha(state->bg_color, widget_alpha);
|
||||
gfx_display_set_alpha(state->frame_color, widget_alpha);
|
||||
text_color = COLOR_TEXT_ALPHA(state->text_color,
|
||||
(unsigned)(widget_alpha * 255.0f));
|
||||
|
||||
/* Background */
|
||||
gfx_display_draw_quad(
|
||||
userdata,
|
||||
video_width,
|
||||
video_height,
|
||||
state->bg_x,
|
||||
bg_y,
|
||||
state->bg_width,
|
||||
state->bg_height,
|
||||
video_width,
|
||||
video_height,
|
||||
state->bg_color);
|
||||
|
||||
/* Frame */
|
||||
|
||||
/* > Top */
|
||||
gfx_display_draw_quad(
|
||||
userdata,
|
||||
video_width,
|
||||
video_height,
|
||||
state->bg_x - (float)state->frame_width,
|
||||
bg_y - (float)state->frame_width,
|
||||
state->bg_width + (state->frame_width * 2),
|
||||
state->frame_width,
|
||||
video_width,
|
||||
video_height,
|
||||
state->frame_color);
|
||||
|
||||
/* > Left */
|
||||
gfx_display_draw_quad(
|
||||
userdata,
|
||||
video_width,
|
||||
video_height,
|
||||
state->bg_x - (float)state->frame_width,
|
||||
bg_y,
|
||||
state->frame_width,
|
||||
state->bg_height,
|
||||
video_width,
|
||||
video_height,
|
||||
state->frame_color);
|
||||
|
||||
/* > Right */
|
||||
gfx_display_draw_quad(
|
||||
userdata,
|
||||
video_width,
|
||||
video_height,
|
||||
state->bg_x + (float)state->bg_width,
|
||||
bg_y,
|
||||
state->frame_width,
|
||||
state->bg_height,
|
||||
video_width,
|
||||
video_height,
|
||||
state->frame_color);
|
||||
|
||||
/* Message */
|
||||
gfx_widgets_draw_text(
|
||||
font_msg_queue,
|
||||
state->message,
|
||||
state->text_x,
|
||||
text_y,
|
||||
video_width,
|
||||
video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
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_msg_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Widget free() */
|
||||
|
||||
static void gfx_widget_generic_message_free(void)
|
||||
{
|
||||
gfx_widget_generic_message_state_t* state = gfx_widget_generic_message_get_ptr();
|
||||
state->alpha = 0.0f;
|
||||
gfx_widget_generic_message_reset(true);
|
||||
}
|
||||
|
||||
/* Widget definition */
|
||||
|
||||
const gfx_widget_t gfx_widget_generic_message = {
|
||||
NULL, /* init */
|
||||
gfx_widget_generic_message_free,
|
||||
NULL, /* context_reset*/
|
||||
NULL, /* context_destroy */
|
||||
NULL, /* layout */
|
||||
NULL, /* iterate */
|
||||
gfx_widget_generic_message_layout,
|
||||
gfx_widget_generic_message_iterate,
|
||||
gfx_widget_generic_message_frame
|
||||
};
|
||||
|
@ -98,7 +98,7 @@ static gfx_widget_libretro_message_state_t* gfx_widget_libretro_message_get_stat
|
||||
|
||||
/* Utilities */
|
||||
|
||||
static void gfx_widget_libretro_message_reset(void)
|
||||
static void gfx_widget_libretro_message_reset(bool cancel_pending)
|
||||
{
|
||||
gfx_widget_libretro_message_state_t *state = gfx_widget_libretro_message_get_state();
|
||||
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
||||
@ -108,15 +108,16 @@ static void gfx_widget_libretro_message_reset(void)
|
||||
gfx_animation_kill_by_tag(&alpha_tag);
|
||||
|
||||
/* Reset status */
|
||||
state->status = GFX_WIDGET_LIBRETRO_MESSAGE_IDLE;
|
||||
state->message_updated = false;
|
||||
state->status = GFX_WIDGET_LIBRETRO_MESSAGE_IDLE;
|
||||
if (cancel_pending)
|
||||
state->message_updated = false;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
static void gfx_widget_libretro_message_fade_out_cb(void *userdata)
|
||||
{
|
||||
gfx_widget_libretro_message_reset();
|
||||
gfx_widget_libretro_message_reset(false);
|
||||
}
|
||||
|
||||
static void gfx_widget_libretro_message_wait_cb(void *userdata)
|
||||
@ -257,10 +258,8 @@ static void gfx_widget_libretro_message_iterate(void *user_data,
|
||||
uintptr_t alpha_tag = (uintptr_t)&state->alpha;
|
||||
gfx_animation_ctx_entry_t animation_entry;
|
||||
|
||||
/* In all cases, reset any existing animation
|
||||
* > Note that this sets state->message_updated
|
||||
* to 'false' */
|
||||
gfx_widget_libretro_message_reset();
|
||||
/* In all cases, reset any existing animation */
|
||||
gfx_widget_libretro_message_reset(false);
|
||||
|
||||
/* If an animation was already in progress,
|
||||
* have to continue from the last active
|
||||
@ -301,7 +300,7 @@ static void gfx_widget_libretro_message_iterate(void *user_data,
|
||||
{
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = alpha_tag;
|
||||
animation_entry.duration = LIBRETRO_MESSAGE_FADE_DURATION;
|
||||
animation_entry.duration = fade_duration;
|
||||
animation_entry.target_value = 1.0f;
|
||||
animation_entry.subject = &state->alpha;
|
||||
/* Note that 'slide in' and 'fade in' share
|
||||
@ -330,6 +329,8 @@ static void gfx_widget_libretro_message_iterate(void *user_data,
|
||||
* action is required */
|
||||
break;
|
||||
}
|
||||
|
||||
state->message_updated = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,7 +475,7 @@ static void gfx_widget_libretro_message_frame(void *data, void *user_data)
|
||||
|
||||
static void gfx_widget_libretro_message_free(void)
|
||||
{
|
||||
gfx_widget_libretro_message_reset();
|
||||
gfx_widget_libretro_message_reset(true);
|
||||
}
|
||||
|
||||
/* Widget definition */
|
||||
|
@ -12852,7 +12852,8 @@ bool retroarch_apply_shader(
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE));
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
if (p_rarch->widgets_active)
|
||||
gfx_widget_set_message(msg);
|
||||
gfx_widget_set_generic_message(&p_rarch->dispwidget_st,
|
||||
msg, 2000);
|
||||
else
|
||||
#endif
|
||||
runloop_msg_queue_push(msg, 1, 120, true, NULL,
|
||||
|
Loading…
x
Reference in New Issue
Block a user