diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index 3c00fbd932..a48813f3ca 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -52,7 +52,6 @@ #include "../../../core_info.h" #include "../../../core.h" #include "../../../verbosity.h" -#include "../../../tasks/task_powerstate.h" #include "../../../tasks/tasks_internal.h" #include "../../../dynamic.h" @@ -1003,34 +1002,24 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i /* Battery */ if (video_info->battery_level_enable) { + menu_display_ctx_powerstate_t powerstate; char msg[12]; - static retro_time_t last_time = 0; - bool charging = false; - retro_time_t current_time = cpu_features_get_time_usec(); - int percent = 0; - enum frontend_powerstate state = get_last_powerstate(&percent); - if (state == FRONTEND_POWERSTATE_CHARGING) - charging = true; + msg[0] = '\0'; - if (current_time - last_time >= INTERVAL_BATTERY_LEVEL_CHECK) - { - last_time = current_time; - task_push_get_powerstate(); - } + powerstate.s = msg; + powerstate.len = sizeof(msg); - *msg = '\0'; + menu_display_powerstate(&powerstate); - if (percent > 0) + if (powerstate.battery_enabled) { timedate_offset = 95; - snprintf(msg, sizeof(msg), "%d%%", percent); - ozone_draw_text(video_info, ozone, msg, video_info->width - 85, ozone->dimensions.header_height / 2 + FONT_SIZE_TIME * 3/8, TEXT_ALIGN_RIGHT, video_info->width, video_info->height, ozone->fonts.time, ozone->theme->text_rgba, false); menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[charging ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL], video_info->width - 60 - 56, ozone->dimensions.header_height / 2 - 42, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + ozone_draw_icon(video_info, 92, 92, ozone->icons_textures[powerstate.charging ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL], video_info->width - 60 - 56, ozone->dimensions.header_height / 2 - 42, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); menu_display_blend_end(video_info); } } diff --git a/menu/drivers/ozone/ozone.h b/menu/drivers/ozone/ozone.h index 3448669d9b..5e10b37d7b 100644 --- a/menu/drivers/ozone/ozone.h +++ b/menu/drivers/ozone/ozone.h @@ -61,7 +61,6 @@ typedef struct ozone_handle ozone_handle_t; #define CURSOR_SIZE 64 -#define INTERVAL_BATTERY_LEVEL_CHECK (30 * 1000000) #define INTERVAL_OSK_CURSOR (0.5f * 1000000) #if defined(__APPLE__) diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 389f521ea4..9af1ab48da 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -86,6 +86,8 @@ #define PI 3.14159265359f #endif +#define BATTERY_WARN_THRESHOLD 20 + typedef struct { unsigned start_x; @@ -589,7 +591,11 @@ enum rgui_symbol_type RGUI_SYMBOL_SHIFT_UP, RGUI_SYMBOL_SHIFT_DOWN, RGUI_SYMBOL_NEXT, - RGUI_SYMBOL_TEXT_CURSOR + RGUI_SYMBOL_TEXT_CURSOR, + RGUI_SYMBOL_CHARGING, + RGUI_SYMBOL_BATTERY_100, + RGUI_SYMBOL_BATTERY_66, + RGUI_SYMBOL_BATTERY_33 }; /* All custom symbols must have dimensions @@ -666,6 +672,54 @@ static const uint8_t rgui_symbol_data_text_cursor[FONT_WIDTH * FONT_HEIGHT] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +static const uint8_t rgui_symbol_data_charging[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_battery_100[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_battery_66[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, + 0, 1, 0, 0, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_battery_33[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, + 0, 1, 0, 0, 1, + 0, 1, 1, 1, 1, + 0, 1, 0, 0, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + /* ============================== * Custom Symbols (glyphs) END * ============================== */ @@ -1118,7 +1172,7 @@ static void rgui_render_particle_effect(rgui_t *rgui) if (rgui->particle_effect == RGUI_PARTICLE_EFFECT_SNOW_ALT) { /* Gives the following distribution: - * 1x1: 32 + * 1x1: 96 * 2x2: 128 * 3x3: 32 */ if (!(i & 0x2)) @@ -2276,6 +2330,14 @@ static const uint8_t *rgui_get_symbol_data(enum rgui_symbol_type symbol) return rgui_symbol_data_next; case RGUI_SYMBOL_TEXT_CURSOR: return rgui_symbol_data_text_cursor; + case RGUI_SYMBOL_CHARGING: + return rgui_symbol_data_charging; + case RGUI_SYMBOL_BATTERY_100: + return rgui_symbol_data_battery_100; + case RGUI_SYMBOL_BATTERY_66: + return rgui_symbol_data_battery_66; + case RGUI_SYMBOL_BATTERY_33: + return rgui_symbol_data_battery_33; default: break; } @@ -2948,14 +3010,19 @@ static void rgui_render(void *data, bool is_idle) /* Render usual text */ size_t selection = menu_navigation_get_selection(); char title_buf[255]; - unsigned timedate_x = (RGUI_TERM_START_X(fb_width) + (RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE)) - - (5 * FONT_WIDTH_STRIDE); + size_t title_max_len; + size_t title_len; + unsigned title_x; + unsigned title_y = RGUI_TERM_START_Y(fb_height) - FONT_HEIGHT_STRIDE; + unsigned term_end_x = RGUI_TERM_START_X(fb_width) + (RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE); + unsigned timedate_x = term_end_x - (5 * FONT_WIDTH_STRIDE); unsigned core_name_len = ((timedate_x - RGUI_TERM_START_X(fb_width)) / FONT_WIDTH_STRIDE) - 3; bool show_mini_thumbnails = rgui->is_playlist && settings->bools.menu_rgui_inline_thumbnails; bool show_thumbnail = false; bool show_left_thumbnail = false; unsigned thumbnail_panel_width = 0; unsigned term_mid_point = 0; + size_t powerstate_len = 0; /* Cache mini thumbnail related parameters, if required */ if (show_mini_thumbnails) @@ -2981,11 +3048,72 @@ static void rgui_render(void *data, bool is_idle) term_mid_point = (unsigned)((RGUI_TERM_HEIGHT(fb_height) * 0.5f) + 0.5f) - 1; } + /* Show battery indicator, if required */ + if (settings->bools.menu_battery_level_enable) + { + menu_display_ctx_powerstate_t powerstate; + char percent_str[12]; + + percent_str[0] = '\0'; + + powerstate.s = percent_str; + powerstate.len = sizeof(percent_str); + + menu_display_powerstate(&powerstate); + + if (powerstate.battery_enabled) + { + powerstate_len = strlen(percent_str); + + if (powerstate_len > 0) + { + unsigned powerstate_x; + enum rgui_symbol_type powerstate_symbol; + uint16_t powerstate_color = (powerstate.percent > BATTERY_WARN_THRESHOLD || powerstate.charging) ? + rgui->colors.title_color : rgui->colors.hover_color; + + if (powerstate.charging) + powerstate_symbol = RGUI_SYMBOL_CHARGING; + else + { + if (powerstate.percent > 66) + powerstate_symbol = RGUI_SYMBOL_BATTERY_100; + else if (powerstate.percent > 33) + powerstate_symbol = RGUI_SYMBOL_BATTERY_66; + else + powerstate_symbol = RGUI_SYMBOL_BATTERY_33; + } + + /* Note: percent symbol is particularly hideous when + * drawn using RGUI's bitmap font, so strip it off the + * end of the output string... */ + powerstate_len--; + percent_str[powerstate_len] = '\0'; + + powerstate_len += 2; + powerstate_x = term_end_x - (powerstate_len * FONT_WIDTH_STRIDE); + + /* Draw symbol */ + blit_symbol(powerstate_x, title_y, powerstate_symbol, + powerstate_color, rgui->colors.shadow_color); + + /* Print text */ + blit_line(powerstate_x + (2 * FONT_WIDTH_STRIDE), title_y, + percent_str, powerstate_color, rgui->colors.shadow_color); + + /* Final length of battery indicator is 'powerstate_len' + a + * spacer of 3 characters */ + powerstate_len += 3; + } + } + } + /* Print title */ + title_max_len = RGUI_TERM_WIDTH(fb_width) - 5 - (powerstate_len > 5 ? powerstate_len : 5); title_buf[0] = '\0'; ticker.s = title_buf; - ticker.len = RGUI_TERM_WIDTH(fb_width) - 10; + ticker.len = title_max_len; ticker.str = rgui->menu_title; ticker.selected = true; @@ -2993,10 +3121,18 @@ static void rgui_render(void *data, bool is_idle) string_to_upper(title_buf); - blit_line( - (int)(RGUI_TERM_START_X(fb_width) + (RGUI_TERM_WIDTH(fb_width) - - utf8len(title_buf)) * FONT_WIDTH_STRIDE / 2), - RGUI_TERM_START_Y(fb_height) - FONT_HEIGHT_STRIDE, + title_len = utf8len(title_buf); + title_x = RGUI_TERM_START_X(fb_width) + + (RGUI_TERM_WIDTH(fb_width) - title_len) * FONT_WIDTH_STRIDE / 2; + + /* Title is always centred, unless it is long enough + * to infringe upon the battery indicator, in which case + * we shift it to the left */ + if (powerstate_len > 5) + if (title_len > title_max_len - (powerstate_len - 5)) + title_x -= (powerstate_len - 5) * FONT_WIDTH_STRIDE / 2; + + blit_line(title_x, title_y, title_buf, rgui->colors.title_color, rgui->colors.shadow_color); /* Print menu entries */ diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 15d4b94afe..0d534a110f 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -61,7 +61,6 @@ #include "../../playlist.h" #include "../../retroarch.h" -#include "../../tasks/task_powerstate.h" #include "../../tasks/tasks_internal.h" #include "../../cheevos/badges.h" @@ -75,8 +74,6 @@ #define XMB_DELAY 166 #endif -#define BATTERY_LEVEL_CHECK_INTERVAL (30 * 1000000) - #if 0 #define XMB_DEBUG #endif @@ -3614,25 +3611,17 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) if (video_info->battery_level_enable) { + menu_display_ctx_powerstate_t powerstate; char msg[12]; - static retro_time_t last_time = 0; - bool charging = false; - retro_time_t current_time = cpu_features_get_time_usec(); - int percent = 0; - enum frontend_powerstate state = get_last_powerstate(&percent); - if (state == FRONTEND_POWERSTATE_CHARGING) - charging = true; + msg[0] = '\0'; - if (current_time - last_time >= BATTERY_LEVEL_CHECK_INTERVAL) - { - last_time = current_time; - task_push_get_powerstate(); - } + powerstate.s = msg; + powerstate.len = sizeof(msg); - *msg = '\0'; + menu_display_powerstate(&powerstate); - if (percent > 0) + if (powerstate.battery_enabled) { size_t x_pos = xmb->icon_size / 6; size_t x_pos_icon = xmb->margins_title_left; @@ -3641,7 +3630,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) xmb_draw_icon(video_info, xmb->icon_size, &mymat, - xmb->textures.list[charging + xmb->textures.list[powerstate.charging ? XMB_TEXTURE_BATTERY_CHARGING : XMB_TEXTURE_BATTERY_FULL], width - (xmb->icon_size / 2) - x_pos_icon, xmb->icon_size, @@ -3653,8 +3642,6 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) &item_color[0], xmb->shadow_offset); - snprintf(msg, sizeof(msg), "%d%%", percent); - percent_width = (unsigned) font_driver_get_message_width( xmb->font, msg, (unsigned)strlen(msg), 1); diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 32f803a60e..107773f6f3 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef WIIU #include @@ -65,11 +66,14 @@ #include "../tasks/tasks_internal.h" #include "../ui/ui_companion_driver.h" #include "../verbosity.h" +#include "../tasks/task_powerstate.h" #define SCROLL_INDEX_SIZE (2 * (26 + 2) + 1) #define PARTICLES_COUNT 100 +#define POWERSTATE_CHECK_INTERVAL (30 * 1000000) + typedef struct menu_ctx_load_image { void *data; @@ -222,6 +226,10 @@ static unsigned scroll_index_size = 0; static unsigned scroll_acceleration = 0; static size_t menu_driver_selection_ptr = 0; +/* Timers */ +static retro_time_t menu_driver_current_time_us = 0; +static retro_time_t menu_driver_powerstate_last_time_us = 0; + /* Returns the OSK key at a given position */ int menu_display_osk_ptr_at_pos(void *data, int x, int y, unsigned width, unsigned height) @@ -418,6 +426,43 @@ void menu_display_timedate(menu_display_ctx_datetime_t *datetime) } } +/* Display current (battery) power state */ +void menu_display_powerstate(menu_display_ctx_powerstate_t *powerstate) +{ + int percent = 0; + enum frontend_powerstate state = FRONTEND_POWERSTATE_NONE; + + if (!powerstate) + return; + + /* Trigger an update, if required */ + if (menu_driver_current_time_us - menu_driver_powerstate_last_time_us >= + POWERSTATE_CHECK_INTERVAL) + { + menu_driver_powerstate_last_time_us = menu_driver_current_time_us; + task_push_get_powerstate(); + } + + /* Get last recorded state */ + state = get_last_powerstate(&percent); + + /* Populate menu_display_ctx_powerstate_t */ + powerstate->battery_enabled = (state != FRONTEND_POWERSTATE_NONE) && + (state != FRONTEND_POWERSTATE_NO_SOURCE); + + if (powerstate->battery_enabled) + { + powerstate->charging = (state == FRONTEND_POWERSTATE_CHARGING); + powerstate->percent = percent > 0 ? (unsigned)percent : 0; + snprintf(powerstate->s, powerstate->len, "%u%%", powerstate->percent); + } + else + { + powerstate->charging = false; + powerstate->percent = 0; + } +} + /* Begin blending operation */ void menu_display_blend_begin(video_frame_info_t *video_info) { @@ -1977,6 +2022,9 @@ bool menu_driver_is_texture_set(void) /* Iterate the menu driver for one frame. */ bool menu_driver_iterate(menu_ctx_iterate_t *iterate) { + /* Get current time */ + menu_driver_current_time_us = cpu_features_get_time_usec(); + /* If the user had requested that the Quick Menu * be spawned during the previous frame, do this now * and exit the function to go to the next frame. diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 376ee2d29e..e95364a413 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -311,6 +311,15 @@ typedef struct menu_display_ctx_datetime unsigned time_mode; } menu_display_ctx_datetime_t; +typedef struct menu_display_ctx_powerstate +{ + char *s; + size_t len; + unsigned percent; + bool battery_enabled; + bool charging; +} menu_display_ctx_powerstate_t; + typedef struct menu_ctx_driver { /* Set a framebuffer texture. This is used for instance by RGUI. */ @@ -621,6 +630,7 @@ void menu_display_rotate_z(menu_display_ctx_rotate_draw_t *draw, bool menu_display_get_tex_coords(menu_display_ctx_coord_draw_t *draw); void menu_display_timedate(menu_display_ctx_datetime_t *datetime); +void menu_display_powerstate(menu_display_ctx_powerstate_t *powerstate); void menu_display_handle_wallpaper_upload(retro_task_t *task, void *task_data,