diff --git a/config.def.h b/config.def.h index 70564d37e7..7ae77928c6 100644 --- a/config.def.h +++ b/config.def.h @@ -571,6 +571,7 @@ static const bool rgui_shadows = false; static const unsigned rgui_particle_effect = RGUI_PARTICLE_EFFECT_NONE; #define DEFAULT_RGUI_PARTICLE_EFFECT_SPEED 1.0f static const bool rgui_extended_ascii = false; +#define DEFAULT_RGUI_SWITCH_ICONS true #endif #ifdef HAVE_MENU diff --git a/configuration.c b/configuration.c index 042378cfbb..d721e7006f 100644 --- a/configuration.c +++ b/configuration.c @@ -1635,6 +1635,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("rgui_inline_thumbnails", &settings->bools.menu_rgui_inline_thumbnails, true, rgui_inline_thumbnails, false); SETTING_BOOL("rgui_swap_thumbnails", &settings->bools.menu_rgui_swap_thumbnails, true, rgui_swap_thumbnails, false); SETTING_BOOL("rgui_extended_ascii", &settings->bools.menu_rgui_extended_ascii, true, rgui_extended_ascii, false); + SETTING_BOOL("rgui_switch_icons", &settings->bools.menu_rgui_switch_icons, true, DEFAULT_RGUI_SWITCH_ICONS, false); #endif #ifdef HAVE_XMB SETTING_BOOL("xmb_shadows_enable", &settings->bools.menu_xmb_shadows_enable, true, DEFAULT_XMB_SHADOWS_ENABLE, false); diff --git a/configuration.h b/configuration.h index 5836115473..fc4617cb71 100644 --- a/configuration.h +++ b/configuration.h @@ -219,6 +219,7 @@ typedef struct settings bool menu_rgui_inline_thumbnails; bool menu_rgui_swap_thumbnails; bool menu_rgui_extended_ascii; + bool menu_rgui_switch_icons; bool menu_xmb_shadows_enable; bool menu_xmb_vertical_thumbnails; bool menu_content_show_settings; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 91107f61f9..87b2cc95e7 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -3894,6 +3894,10 @@ MSG_HASH( MENU_ENUM_LABEL_MENU_RGUI_EXTENDED_ASCII, "rgui_extended_ascii" ) +MSG_HASH( + MENU_ENUM_LABEL_MENU_RGUI_SWITCH_ICONS, + "rgui_switch_icons" + ) MSG_HASH( MENU_ENUM_LABEL_CONTENT_SHOW_REWIND, "menu_show_rewind_settings" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 2164a93f3a..1cdbfbfc17 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -7624,6 +7624,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_RGUI_EXTENDED_ASCII, "Enable display of non-standard ASCII characters. Required for compatibility with certain non-English Western languages. Has a moderate performance impact." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_RGUI_SWITCH_ICONS, + "Show Switch Icons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_RGUI_SWITCH_ICONS, + "Use icons instead of ON/OFF text to represent 'toggle switch' menu settings entries." + ) /* RGUI: Settings Options */ diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index b527d241f1..002c77f9fd 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -852,6 +852,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_use_old_format, DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_compression, MENU_ENUM_SUBLABEL_PLAYLIST_COMPRESSION) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_full_width_layout, MENU_ENUM_SUBLABEL_MENU_RGUI_FULL_WIDTH_LAYOUT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_extended_ascii, MENU_ENUM_SUBLABEL_MENU_RGUI_EXTENDED_ASCII) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_switch_icons, MENU_ENUM_SUBLABEL_MENU_RGUI_SWITCH_ICONS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_thumbnails_updater_list, MENU_ENUM_SUBLABEL_THUMBNAILS_UPDATER_LIST) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pl_thumbnails_updater_list, MENU_ENUM_SUBLABEL_PL_THUMBNAILS_UPDATER_LIST) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_help_send_debug_info, MENU_ENUM_SUBLABEL_HELP_SEND_DEBUG_INFO) @@ -3822,6 +3823,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_MENU_RGUI_EXTENDED_ASCII: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_extended_ascii); break; + case MENU_ENUM_LABEL_MENU_RGUI_SWITCH_ICONS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_switch_icons); + break; case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_thumbnails_updater_list); break; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 6865fb285e..9bc466f6fc 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -550,6 +550,20 @@ typedef struct float d; } rgui_particle_t; +/* Defines all possible entry value types + * > Note: These are not necessarily 'values', + * but they correspond to the object drawn in + * the 'value' location when rendering + * menu lists */ +enum rgui_entry_value_type +{ + RGUI_ENTRY_VALUE_NONE = 0, + RGUI_ENTRY_VALUE_TEXT, + RGUI_ENTRY_VALUE_SWITCH_ON, + RGUI_ENTRY_VALUE_SWITCH_OFF, + RGUI_ENTRY_VALUE_CHECKMARK +}; + typedef struct { bool bg_modified; @@ -625,7 +639,13 @@ enum rgui_symbol_type RGUI_SYMBOL_BATTERY_60, RGUI_SYMBOL_BATTERY_40, RGUI_SYMBOL_BATTERY_20, - RGUI_SYMBOL_CHECKMARK + RGUI_SYMBOL_CHECKMARK, + RGUI_SYMBOL_SWITCH_ON_LEFT, + RGUI_SYMBOL_SWITCH_ON_CENTRE, + RGUI_SYMBOL_SWITCH_ON_RIGHT, + RGUI_SYMBOL_SWITCH_OFF_LEFT, + RGUI_SYMBOL_SWITCH_OFF_CENTRE, + RGUI_SYMBOL_SWITCH_OFF_RIGHT }; /* All custom symbols must have dimensions @@ -789,6 +809,78 @@ static const uint8_t rgui_symbol_data_checkmark[FONT_WIDTH * FONT_HEIGHT] = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}; +static const uint8_t rgui_symbol_data_switch_on_left[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_switch_on_centre[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_switch_on_right[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_switch_off_left[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_switch_off_centre[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, + 0, 1, 0, 0, 0, + 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + +static const uint8_t rgui_symbol_data_switch_off_right[FONT_WIDTH * FONT_HEIGHT] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* Baseline */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + /* ============================== * Custom Symbols (glyphs) END * ============================== */ @@ -2638,6 +2730,18 @@ static const uint8_t *rgui_get_symbol_data(enum rgui_symbol_type symbol) return rgui_symbol_data_battery_20; case RGUI_SYMBOL_CHECKMARK: return rgui_symbol_data_checkmark; + case RGUI_SYMBOL_SWITCH_ON_LEFT: + return rgui_symbol_data_switch_on_left; + case RGUI_SYMBOL_SWITCH_ON_CENTRE: + return rgui_symbol_data_switch_on_centre; + case RGUI_SYMBOL_SWITCH_ON_RIGHT: + return rgui_symbol_data_switch_on_right; + case RGUI_SYMBOL_SWITCH_OFF_LEFT: + return rgui_symbol_data_switch_off_left; + case RGUI_SYMBOL_SWITCH_OFF_CENTRE: + return rgui_symbol_data_switch_off_centre; + case RGUI_SYMBOL_SWITCH_OFF_RIGHT: + return rgui_symbol_data_switch_off_right; default: break; } @@ -3228,6 +3332,58 @@ static void rgui_render_osk( } } +static void rgui_render_toggle_switch(unsigned fb_width, int x, int y, + bool on, uint16_t color, uint16_t shadow_color) +{ + int x_current = x; + + /* Toggle switch is just 3 adjacent symbols + * > Note that we indent the left/right symbols + * by 1 pixel, to avoid the gap that is normally + * present between symbols/characters */ + blit_symbol(fb_width, x_current + 1, y, + on ? RGUI_SYMBOL_SWITCH_ON_LEFT : RGUI_SYMBOL_SWITCH_OFF_LEFT, + color, shadow_color); + x_current += FONT_WIDTH_STRIDE; + + blit_symbol(fb_width, x_current, y, + on ? RGUI_SYMBOL_SWITCH_ON_CENTRE : RGUI_SYMBOL_SWITCH_OFF_CENTRE, + color, shadow_color); + x_current += FONT_WIDTH_STRIDE; + + blit_symbol(fb_width, x_current - 1, y, + on ? RGUI_SYMBOL_SWITCH_ON_RIGHT : RGUI_SYMBOL_SWITCH_OFF_RIGHT, + color, shadow_color); +} + +static enum rgui_entry_value_type rgui_get_entry_value_type( + const char *entry_value, bool entry_checked, + bool switch_icons_enabled) +{ + enum rgui_entry_value_type value_type = RGUI_ENTRY_VALUE_NONE; + + if (!string_is_empty(entry_value)) + { + value_type = RGUI_ENTRY_VALUE_TEXT; + + if (switch_icons_enabled) + { + /* Toggle switch off */ + if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || + string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + value_type = RGUI_ENTRY_VALUE_SWITCH_OFF; + /* Toggle switch on */ + else if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || + string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))) + value_type = RGUI_ENTRY_VALUE_SWITCH_ON; + } + } + else if (entry_checked) + value_type = RGUI_ENTRY_VALUE_CHECKMARK; + + return value_type; +} + #if defined(GEKKO) /* Need to forward declare this for the Wii build * (I'm not going to reorder the functions and mess @@ -3262,6 +3418,7 @@ static void rgui_render(void *data, bool use_smooth_ticker = settings->bools.menu_ticker_smooth; bool rgui_swap_thumbnails = settings->bools.menu_rgui_swap_thumbnails; bool rgui_full_width_layout = settings->bools.menu_rgui_full_width_layout; + bool rgui_switch_icons = settings->bools.menu_rgui_switch_icons; bool menu_show_sublabels = settings->bools.menu_show_sublabels; bool video_fullscreen = settings->bools.video_fullscreen; bool menu_mouse_enable = settings->bools.menu_mouse_enable; @@ -3656,12 +3813,13 @@ static void rgui_render(void *data, char entry_title_buf[255]; char type_str_buf[255]; menu_entry_t entry; - const char *entry_label = NULL; - const char *entry_value = NULL; - size_t entry_title_max_len = 0; - unsigned entry_value_len = 0; - bool entry_selected = (i == selection); - uint16_t entry_color = entry_selected ? + const char *entry_label = NULL; + const char *entry_value = NULL; + size_t entry_title_max_len = 0; + unsigned entry_value_len = 0; + enum rgui_entry_value_type entry_value_type = RGUI_ENTRY_VALUE_NONE; + bool entry_selected = (i == selection); + uint16_t entry_color = entry_selected ? rgui->colors.hover_color : rgui->colors.normal_color; if (i > (selection + 100)) @@ -3721,23 +3879,45 @@ static void rgui_render(void *data, entry_title_max_len -= (thumbnail_width / FONT_WIDTH_STRIDE) + 1; } - /* Determine whether entry has a value component */ - if (!string_is_empty(entry_value)) - { - if (rgui_full_width_layout) - { - /* Resize fields according to actual length of value string */ - entry_value_len = (unsigned)strlen(entry_value); - entry_value_len = (entry_value_len - > rgui_term_layout.value_maxlen) - ? rgui_term_layout.value_maxlen - : entry_value_len; - } - else /* Use classic fixed width layout */ - entry_value_len = entry.spacing; + /* Get 'type' of entry value component */ + entry_value_type = rgui_get_entry_value_type( + entry_value, entry.checked, rgui_switch_icons); - /* Update width of entry title field */ - entry_title_max_len -= entry_value_len + 2; + switch (entry_value_type) + { + case RGUI_ENTRY_VALUE_TEXT: + /* Resize fields according to actual length + * of value string */ + if (rgui_full_width_layout) + { + entry_value_len = (unsigned)strlen(entry_value); + entry_value_len = (entry_value_len + > rgui_term_layout.value_maxlen) ? + rgui_term_layout.value_maxlen : + entry_value_len; + } + /* Use classic fixed width layout */ + else + entry_value_len = entry.spacing; + + /* Update width of entry title field */ + entry_title_max_len -= entry_value_len + 2; + break; + case RGUI_ENTRY_VALUE_SWITCH_ON: + case RGUI_ENTRY_VALUE_SWITCH_OFF: + /* Switch icon is 3 characters wide + * (if using classic fixed width layout, + * set maximum width to ensure icon is + * aligned with left hand edge of values + * column) */ + entry_value_len = rgui_full_width_layout ? + 3 : RGUI_ENTRY_VALUE_MAXLEN; + + /* Update width of entry title field */ + entry_title_max_len -= entry_value_len + 2; + break; + default: + break; } /* Format entry title string */ @@ -3769,41 +3949,59 @@ static void rgui_render(void *data, entry_color, rgui->colors.shadow_color); /* Print entry value, if required */ - if (entry_value_len > 0) + switch (entry_value_type) { - /* Format entry value string */ - if (use_smooth_ticker) - { - ticker_smooth.field_width = entry_value_len * FONT_WIDTH_STRIDE; - ticker_smooth.src_str = entry_value; - ticker_smooth.dst_str = type_str_buf; - ticker_smooth.dst_str_len = sizeof(type_str_buf); - ticker_smooth.x_offset = &ticker_x_offset; + case RGUI_ENTRY_VALUE_TEXT: + /* Format entry value string */ + if (use_smooth_ticker) + { + ticker_smooth.field_width = entry_value_len * FONT_WIDTH_STRIDE; + ticker_smooth.src_str = entry_value; + ticker_smooth.dst_str = type_str_buf; + ticker_smooth.dst_str_len = sizeof(type_str_buf); + ticker_smooth.x_offset = &ticker_x_offset; - gfx_animation_ticker_smooth(&ticker_smooth); - } - else - { - ticker.s = type_str_buf; - ticker.len = entry_value_len; - ticker.str = entry_value; + gfx_animation_ticker_smooth(&ticker_smooth); + } + else + { + ticker.s = type_str_buf; + ticker.len = entry_value_len; + ticker.str = entry_value; - gfx_animation_ticker(&ticker); - } + gfx_animation_ticker(&ticker); + } - /* Print entry value */ - blit_line(rgui, - fb_width, - ticker_x_offset + term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), - y, - type_str_buf, - entry_color, rgui->colors.shadow_color); + /* Print entry value */ + blit_line(rgui, + fb_width, + ticker_x_offset + term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), + y, + type_str_buf, + entry_color, rgui->colors.shadow_color); + break; + case RGUI_ENTRY_VALUE_SWITCH_ON: + rgui_render_toggle_switch(fb_width, + term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), y, + true, + entry_color, rgui->colors.shadow_color); + break; + case RGUI_ENTRY_VALUE_SWITCH_OFF: + rgui_render_toggle_switch(fb_width, + term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), y, + false, + entry_color, rgui->colors.shadow_color); + break; + case RGUI_ENTRY_VALUE_CHECKMARK: + /* Print marker for currently selected + * item in drop-down lists */ + blit_symbol(fb_width, x + FONT_WIDTH_STRIDE, y, + RGUI_SYMBOL_CHECKMARK, + entry_color, rgui->colors.shadow_color); + break; + default: + break; } - /* Print marker for currently selected item in - * drop down lists, if required */ - else if (entry.checked) - blit_symbol(fb_width, x + FONT_WIDTH_STRIDE, y, RGUI_SYMBOL_CHECKMARK, - entry_color, rgui->colors.shadow_color); /* Print selection marker, if required */ if (entry_selected) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 6040266448..9133e32d3f 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -8572,6 +8572,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_MENU_TICKER_SMOOTH, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_OZONE_SCROLL_CONTENT_METADATA, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_MENU_RGUI_EXTENDED_ASCII, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_MENU_RGUI_SWITCH_ICONS, PARSE_ONLY_BOOL, true}, }; for (i = 0; i < ARRAY_SIZE(build_list); i++) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 0cfec76b40..31a06b5899 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -13471,6 +13471,21 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); + + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_rgui_switch_icons, + MENU_ENUM_LABEL_MENU_RGUI_SWITCH_ICONS, + MENU_ENUM_LABEL_VALUE_MENU_RGUI_SWITCH_ICONS, + DEFAULT_RGUI_SWITCH_ICONS, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); } if (string_is_equal(settings->arrays.menu_driver, "xmb")) diff --git a/msg_hash.h b/msg_hash.h index 4ef2ee8de1..c8fdf33222 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1050,6 +1050,7 @@ enum msg_hash_enums MENU_LABEL(MENU_RGUI_PARTICLE_EFFECT), MENU_LABEL(MENU_RGUI_PARTICLE_EFFECT_SPEED), MENU_LABEL(MENU_RGUI_EXTENDED_ASCII), + MENU_LABEL(MENU_RGUI_SWITCH_ICONS), MENU_LABEL(MENU_LINEAR_FILTER), MENU_LABEL(MENU_HORIZONTAL_ANIMATION), MENU_LABEL(NAVIGATION_WRAPAROUND),