diff --git a/CHANGES.md b/CHANGES.md index 0ddf01b29a..4adbdf50d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,8 @@ - MENU/QT/WIMP: Initial grid view. - MENU/QT/WIMP: Drag&drop to add new playlist items, add option to add/edit/delete playlists. - MENU/QT/WIMP: Add menu option to update RetroArch (Windows only for now). +- MENU/XMB: Add new icons for the settings +- MENU/XMB: Add an option to show the desktop ui - METAL: Initial work-in-progress video driver for Metal. macOS-only right now, and currently requires macOS 10.13. - METAL: Supports XMB/MaterialUI, has a menu display driver. Has a font rendering driver. - METAL/SLANG: Slang shaders should be compatible with Metal video driver. @@ -91,7 +93,7 @@ video drivers that implement it (D3D8/9/10/11/12/GL) - MENU/RGUI: D3D8/D3D9: Hookup Menu Linear Filter - MENU/XMB: Disable XMB shadow icons by default for PowerPC and ARM for performance reasons. - MENU/XMB: Left/right thumbnails are now automatically scaled according to layout. -- MENU/XMB: Add Left Thumbnails (additional to the right). +- MENU/XMB: Add Left Thumbnails (additional to the right). - MENU/XMB: Fixed left/right tab regression. - MENU/XMB: Fix scaling of tall images that were cut on bottom previously. - MENU/XMB: Menu scale factor setting now changes texts length, image scaling and margins. diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index d65ed9ec32..0e21e3687a 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1674,7 +1674,7 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set) shotname[sizeof(shotname) - 1] = '\0'; if (take_screenshot(shotname, true, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); else CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); @@ -2080,7 +2080,7 @@ void cheevos_populate_menu(void *data) cheevo_t *cheevo = cheevos_locals.core.cheevos; end = cheevo + cheevos_locals.core.count; - if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable + if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable && cheevos_loaded) { if (!cheevos_hardcore_paused) diff --git a/command.c b/command.c index 0d00d9168c..9a2f9a6879 100644 --- a/command.c +++ b/command.c @@ -1954,7 +1954,7 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_TAKE_SCREENSHOT: if (!take_screenshot(path_get(RARCH_PATH_BASENAME), false, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) return false; break; case CMD_EVENT_UNLOAD_CORE: diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 4eba0b39b9..69dbffa859 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -6417,6 +6417,14 @@ MSG_HASH( "
  • reiniciar RetroArch si actualizaste algo con el \"Actualizador en línea\"
  • \n" "Por último, el contenido debe coincidir las bases de datos existente de aquí. Si aún no funciona, considere enviar un reporte de error." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Mostrar el menú de escritorio" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Abre el menú de escritorio si fue cerrado" + ) #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 03fcce6c13..bd85f3783d 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -3768,3 +3768,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "下へ移動") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "上へ移動") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD, + "ロード") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SAVE, + "保存") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "取り除く") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_APPLY, + "適用") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "パスを追加") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "すべてのパスを取り除く") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "シェーダーパスはありません。") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 65c31d3097..10a184ead5 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3839,6 +3839,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SCAN_FINISHED, "
  • have \"Databases\" updated via Online Updater
  • \n" "
  • restart RetroArch if any of the above was just done
  • \n" "Finally, the content must match existing databases from here. If it is still not working, consider submitting a bug report.") +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + "Show Desktop Menu" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SHOW_WIMP, + "Opens the desktop menu if it was closed" + ) #endif MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN, "Don't show this again") @@ -4270,3 +4278,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, "Move Down") MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, "Move Up") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_LOAD, + "Load") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SAVE, + "Save") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_REMOVE, + "Remove") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_APPLY, + "Apply") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + "Add Pass") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + "Clear All Passes") +MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, + "No shader passes.") diff --git a/libretro-common/formats/png/rpng_encode.c b/libretro-common/formats/png/rpng_encode.c index 3500c3aaf4..42df8116aa 100644 --- a/libretro-common/formats/png/rpng_encode.c +++ b/libretro-common/formats/png/rpng_encode.c @@ -150,7 +150,10 @@ static unsigned count_sad(const uint8_t *data, size_t size) size_t i; unsigned cnt = 0; for (i = 0; i < size; i++) - cnt += abs((int8_t)data[i]); + { + if (data[i]) + cnt += abs((int8_t)data[i]); + } return cnt; } diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 5991b04d77..6135befeed 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -88,6 +88,9 @@ enum ACTION_OK_SET_PATH_VIDEO_FILTER, ACTION_OK_SET_PATH_OVERLAY, ACTION_OK_SET_DIRECTORY, +#ifdef HAVE_QT + ACTION_OK_SHOW_WIMP, +#endif ACTION_OK_LOAD_CHEAT_FILE_APPEND }; @@ -820,11 +823,11 @@ int generic_action_ok_displaylist_push(const char *path, case ACTION_OK_DL_DEFERRED_CORE_LIST_SET: info.directory_ptr = idx; menu->scratchpad.unsigned_var = (unsigned)idx; - info_path = + info_path = settings->paths.directory_libretro; info_label = msg_hash_to_str( MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET); - info.enum_idx = + info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET; dl_type = DISPLAYLIST_GENERIC; break; @@ -1525,7 +1528,7 @@ static int action_ok_file_load(const char *path, if (filebrowser_get_type() == FILEBROWSER_SELECT_FILE_SUBSYSTEM) { - /* TODO/FIXME - this path is triggered when we try to load a + /* TODO/FIXME - this path is triggered when we try to load a * file from an archive while inside the load subsystem * action */ menu_handle_t *menu = NULL; @@ -1676,7 +1679,7 @@ static int action_ok_playlist_entry_collection(const char *path, core_info.inf->display_name, NULL, NULL); - } + } else strlcpy(new_core_path, core_path, sizeof(new_core_path)); @@ -1750,7 +1753,7 @@ static int action_ok_playlist_entry(const char *path, core_info.inf->display_name, NULL, NULL); - + } else if (!string_is_empty(core_path)) strlcpy(new_core_path, core_path, sizeof(new_core_path)); @@ -1813,9 +1816,9 @@ static int action_ok_playlist_entry_start_content(const char *path, if (!core_info_find(&core_info, new_core_path)) found_associated_core = false; - /* TODO: figure out if this should refer to + /* TODO: figure out if this should refer to * the inner or outer entry_path. */ - /* TODO: make sure there's only one entry_path + /* TODO: make sure there's only one entry_path * in this function. */ if (!found_associated_core) return action_ok_file_load_with_detect_core(entry_path, @@ -2111,7 +2114,7 @@ static void menu_input_st_string_cb_rename_entry(void *userdata, NULL); } - + menu_input_dialog_end(); } @@ -2719,7 +2722,7 @@ static int action_ok_cheat_add_bottom(const char *path, cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO); msg[0] = '\0'; - strlcpy(msg, + strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_BOTTOM_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; @@ -3167,7 +3170,6 @@ static void cb_generic_dir_download(void *task_data, void *user_data, const char *err) { file_transfer_t *transf = (file_transfer_t*)user_data; - if (transf) { generic_action_ok_network(transf->path, transf->path, 0, 0, 0, @@ -3521,15 +3523,17 @@ int (func_name)(const char *path, const char *label, unsigned type, size_t idx, return generic_action_ok_command(cmd); \ } -default_action_ok_cmd_func(action_ok_cheat_apply_changes,CMD_EVENT_CHEATS_APPLY) -default_action_ok_cmd_func(action_ok_quit, CMD_EVENT_QUIT) -default_action_ok_cmd_func(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG) -default_action_ok_cmd_func(action_ok_resume_content, CMD_EVENT_RESUME) -default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) -default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) -default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE ) -default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES ) - +default_action_ok_cmd_func(action_ok_cheat_apply_changes, CMD_EVENT_CHEATS_APPLY) +default_action_ok_cmd_func(action_ok_quit, CMD_EVENT_QUIT) +default_action_ok_cmd_func(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG) +default_action_ok_cmd_func(action_ok_resume_content, CMD_EVENT_RESUME) +default_action_ok_cmd_func(action_ok_restart_content, CMD_EVENT_RESET) +default_action_ok_cmd_func(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT) +default_action_ok_cmd_func(action_ok_disk_cycle_tray_status, CMD_EVENT_DISK_EJECT_TOGGLE) +default_action_ok_cmd_func(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES) +#ifdef HAVE_QT +default_action_ok_cmd_func(action_ok_show_wimp, CMD_EVENT_UI_COMPANION_TOGGLE) +#endif static int action_ok_reset_core_association(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) @@ -3944,7 +3948,7 @@ void netplay_refresh_rooms_menu(file_list_t *list) char country[PATH_MAX_LENGTH] = {0}; if (*netplay_room_list[i].country) - string_add_between_pairs(country, netplay_room_list[i].country, + string_add_between_pairs(country, netplay_room_list[i].country, sizeof(country)); /* Uncomment this to debug mismatched room parameters*/ @@ -4739,6 +4743,11 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS: BIND_ACTION_OK(cbs, action_ok_enable_settings); break; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: + BIND_ACTION_OK(cbs, action_ok_show_wimp); + break; +#endif case MENU_ENUM_LABEL_QUIT_RETROARCH: BIND_ACTION_OK(cbs, action_ok_quit); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index d9fea4d60f..25ef29af8a 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -461,7 +461,9 @@ default_sublabel_macro(action_bind_sublabel_midi_output, default_sublabel_macro(action_bind_sublabel_midi_volume, MENU_ENUM_SUBLABEL_MIDI_VOLUME) default_sublabel_macro(action_bind_sublabel_onscreen_overlay_settings_list, MENU_ENUM_SUBLABEL_ONSCREEN_OVERLAY_SETTINGS) default_sublabel_macro(action_bind_sublabel_onscreen_notifications_settings_list, MENU_ENUM_SUBLABEL_ONSCREEN_NOTIFICATIONS_SETTINGS) - +#ifdef HAVE_QT +default_sublabel_macro(action_bind_sublabel_show_wimp, MENU_ENUM_SUBLABEL_SHOW_WIMP) +#endif static int action_bind_sublabel_cheevos_entry( file_list_t *list, @@ -1942,6 +1944,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_onscreen_notifications_settings_list); break; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_show_wimp); + break; +#endif default: case MSG_UNKNOWN: return -1; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 6584de207f..ceccd0aa8e 100755 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2359,6 +2359,9 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, return xmb->textures.list[XMB_TEXTURE_RECORD]; case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS: return xmb->textures.list[XMB_TEXTURE_OSD]; +#ifdef HAVE_QT + case MENU_ENUM_LABEL_SHOW_WIMP: +#endif case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: return xmb->textures.list[XMB_TEXTURE_UI]; case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS: @@ -5263,6 +5266,13 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); +#ifdef HAVE_QT + if (settings->bools.desktop_menu_enable) + { + entry.enum_idx = MENU_ENUM_LABEL_SHOW_WIMP; + menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); + } +#endif #if defined(HAVE_NETWORKING) { settings_t *settings = config_get_ptr(); @@ -5307,7 +5317,6 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_HELP_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } - #if !defined(IOS) if (settings->bools.menu_show_quit_retroarch) { diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 962eedebbf..1801b78e16 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4857,7 +4857,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) string_is_equal(core_path, path_get(RARCH_PATH_CORE))) { strlcpy(new_path_entry, core_path, sizeof(new_path_entry)); - snprintf(new_entry, sizeof(new_entry), "%s (%s)", + snprintf(new_entry, sizeof(new_entry), "%s (%s)", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE), core_name); new_lbl_entry[0] = '\0'; @@ -5538,7 +5538,11 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_HELP, PARSE_ONLY_BOOL, false); - +#ifdef HAVE_QT + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SHOW_WIMP, + PARSE_ONLY_UINT, false); +#endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_QUIT_RETROARCH, PARSE_ONLY_BOOL, false); @@ -6291,11 +6295,11 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SCREEN_RESOLUTION, PARSE_ACTION, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, PARSE_ONLY_BOOL, false); - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PAL60_ENABLE, @@ -6908,7 +6912,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) { settings_t *settings = config_get_ptr(); - if (settings->bools.quick_menu_show_save_core_overrides + if (settings->bools.quick_menu_show_save_core_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, @@ -6919,7 +6923,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) count++; } - if (settings->bools.quick_menu_show_save_content_dir_overrides + if (settings->bools.quick_menu_show_save_content_dir_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, @@ -6930,7 +6934,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) count++; } - if (settings->bools.quick_menu_show_save_game_overrides + if (settings->bools.quick_menu_show_save_game_overrides && !settings->bools.kiosk_mode_enable) { menu_entries_append_enum(info->list, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 4fb276be24..40f65a60a2 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -2468,7 +2468,16 @@ static bool setting_append_list( &subgroup_info, parent_group); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); - +#ifdef HAVE_QT + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_SHOW_WIMP, + MENU_ENUM_LABEL_VALUE_SHOW_WIMP, + &group_info, + &subgroup_info, + parent_group); + menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_UI_COMPANION_TOGGLE); +#endif #if !defined(IOS) /* Apple rejects iOS apps that let you forcibly quit them. */ CONFIG_ACTION( @@ -3497,7 +3506,7 @@ static bool setting_append_list( case SETTINGS_LIST_CHEAT_SEARCH: if ( ! cheat_manager_state.cheats ) break ; - + START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_SEARCH_SETTINGS), parent_group); parent_group = msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_SEARCH_SETTINGS); @@ -3764,9 +3773,9 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); - - - CONFIG_BOOL( + + + CONFIG_BOOL( list, list_info, &settings->bools.crt_switch_resolution, MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, @@ -3780,18 +3789,18 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_ADVANCED - ); - + ); + CONFIG_UINT( - list, list_info, - &settings->uints.crt_switch_resolution_super, - MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, - MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, - crt_switch_resolution_super, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, + list, list_info, + &settings->uints.crt_switch_resolution_super, + MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, + MENU_ENUM_LABEL_VALUE_CRT_SWITCH_RESOLUTION_SUPER, + crt_switch_resolution_super, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); diff --git a/msg_hash.h b/msg_hash.h index 3dcb368fbc..7a98eff7d0 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1504,6 +1504,9 @@ enum msg_hash_enums MENU_LABEL(BUILDBOT_ASSETS_URL), MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE), MENU_LABEL(CLOSE_CONTENT), +#ifdef HAVE_QT + MENU_LABEL(SHOW_WIMP), +#endif MENU_LABEL(QUIT_RETROARCH), MENU_LABEL(SHUTDOWN), MENU_LABEL(REBOOT), @@ -1990,6 +1993,13 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER, MENU_ENUM_LABEL_VALUE_QT_MOVE_DOWN, MENU_ENUM_LABEL_VALUE_QT_MOVE_UP, + MENU_ENUM_LABEL_VALUE_QT_LOAD, + MENU_ENUM_LABEL_VALUE_QT_SAVE, + MENU_ENUM_LABEL_VALUE_QT_REMOVE, + MENU_ENUM_LABEL_VALUE_QT_APPLY, + MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS, + MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES, + MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES, MENU_LABEL(MIDI_INPUT), MENU_LABEL(MIDI_OUTPUT), diff --git a/pkg/ctr/Makefile.cores b/pkg/ctr/Makefile.cores index 8fabdb8bd7..391fe18045 100644 --- a/pkg/ctr/Makefile.cores +++ b/pkg/ctr/Makefile.cores @@ -139,6 +139,14 @@ else ifeq ($(LIBRETRO), mame2003) APP_BANNER = pkg/ctr/assets/mame2003_banner.png APP_BIG_TEXT_SECTION = 1 +else ifeq ($(LIBRETRO), mame2003_plus) + APP_TITLE = MAME-2003-PLUS + APP_PRODUCT_CODE = RARCH-MAME2003-PLUS + APP_UNIQUE_ID = 0xBAC22 + APP_ICON = pkg/ctr/assets/mame2003_plus.png + APP_BANNER = pkg/ctr/assets/mame2003_plus_banner.png + APP_BIG_TEXT_SECTION = 1 + else ifeq ($(LIBRETRO), mednafen_pce_fast) APP_TITLE = Mednafen/Beetle PCE FAST APP_AUTHOR = Ryphecha diff --git a/pkg/ctr/assets/mame2003_plus.png b/pkg/ctr/assets/mame2003_plus.png new file mode 100644 index 0000000000..86509ec999 Binary files /dev/null and b/pkg/ctr/assets/mame2003_plus.png differ diff --git a/pkg/ctr/assets/mame2003_plus_banner.png b/pkg/ctr/assets/mame2003_plus_banner.png new file mode 100644 index 0000000000..6b73ffe5fd Binary files /dev/null and b/pkg/ctr/assets/mame2003_plus_banner.png differ diff --git a/retroarch.c b/retroarch.c index 5b2e655e3a..42c8fa24b6 100644 --- a/retroarch.c +++ b/retroarch.c @@ -165,7 +165,9 @@ enum RA_OPT_VERSION, RA_OPT_EOF_EXIT, RA_OPT_LOG_FILE, - RA_OPT_MAX_FRAMES + RA_OPT_MAX_FRAMES, + RA_OPT_MAX_FRAMES_SCREENSHOT, + RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }; enum runloop_state @@ -187,86 +189,88 @@ typedef struct runloop_ctx_msg_info } runloop_ctx_msg_info_t; static jmp_buf error_sjlj_context; -static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; -static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; -static char error_string[255] = {0}; +static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; +static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; +static char error_string[255] = {0}; static char runtime_shader_preset[255] = {0}; #ifdef HAVE_THREAD_STORAGE static sthread_tls_t rarch_tls; -const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; +const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; #endif static retro_bits_t has_set_libretro_device; -static bool has_set_core = false; -static bool has_set_username = false; +static bool has_set_core = false; +static bool has_set_username = false; #ifdef HAVE_DISCORD -static bool discord_is_inited = false; +static bool discord_is_inited = false; #endif -static bool rarch_is_inited = false; -static bool rarch_error_on_init = false; -static bool rarch_block_config_read = false; -static bool rarch_force_fullscreen = false; -static bool has_set_verbosity = false; -static bool has_set_libretro = false; -static bool has_set_libretro_directory = false; -static bool has_set_save_path = false; -static bool has_set_state_path = false; -static bool has_set_netplay_mode = false; -static bool has_set_netplay_ip_address = false; -static bool has_set_netplay_ip_port = false; -static bool has_set_netplay_stateless_mode = false; -static bool has_set_netplay_check_frames = false; -static bool has_set_ups_pref = false; -static bool has_set_bps_pref = false; -static bool has_set_ips_pref = false; +static bool rarch_is_inited = false; +static bool rarch_error_on_init = false; +static bool rarch_block_config_read = false; +static bool rarch_force_fullscreen = false; +static bool has_set_verbosity = false; +static bool has_set_libretro = false; +static bool has_set_libretro_directory = false; +static bool has_set_save_path = false; +static bool has_set_state_path = false; +static bool has_set_netplay_mode = false; +static bool has_set_netplay_ip_address = false; +static bool has_set_netplay_ip_port = false; +static bool has_set_netplay_stateless_mode = false; +static bool has_set_netplay_check_frames = false; +static bool has_set_ups_pref = false; +static bool has_set_bps_pref = false; +static bool has_set_ips_pref = false; -static bool rarch_is_sram_load_disabled = false; -static bool rarch_is_sram_save_disabled = false; -static bool rarch_use_sram = false; -static bool rarch_ups_pref = false; -static bool rarch_bps_pref = false; -static bool rarch_ips_pref = false; -static bool rarch_patch_blocked = false; -static bool rarch_first_start = true; +static bool rarch_is_sram_load_disabled = false; +static bool rarch_is_sram_save_disabled = false; +static bool rarch_use_sram = false; +static bool rarch_ups_pref = false; +static bool rarch_bps_pref = false; +static bool rarch_ips_pref = false; +static bool rarch_patch_blocked = false; +static bool rarch_first_start = true; -static bool runloop_force_nonblock = false; -static bool runloop_paused = false; -static bool runloop_idle = false; -static bool runloop_exec = false; -static bool runloop_slowmotion = false; -static bool runloop_fastmotion = false; -static bool runloop_shutdown_initiated = false; -static bool runloop_core_shutdown_initiated = false; -static bool runloop_perfcnt_enable = false; -static bool runloop_overrides_active = false; -static bool runloop_remaps_core_active = false; -static bool runloop_remaps_game_active = false; -static bool runloop_remaps_content_dir_active = false; -static bool runloop_game_options_active = false; -static bool runloop_missing_bios = false; -static bool runloop_autosave = false; +static bool runloop_force_nonblock = false; +static bool runloop_paused = false; +static bool runloop_idle = false; +static bool runloop_exec = false; +static bool runloop_slowmotion = false; +static bool runloop_fastmotion = false; +static bool runloop_shutdown_initiated = false; +static bool runloop_core_shutdown_initiated = false; +static bool runloop_perfcnt_enable = false; +static bool runloop_overrides_active = false; +static bool runloop_remaps_core_active = false; +static bool runloop_remaps_game_active = false; +static bool runloop_remaps_content_dir_active = false; +static bool runloop_game_options_active = false; +static bool runloop_missing_bios = false; +static bool runloop_autosave = false; #ifdef HAVE_DYNAMIC -static bool core_set_on_cmdline = false; +static bool core_set_on_cmdline = false; #endif static rarch_system_info_t runloop_system; static struct retro_frame_time_callback runloop_frame_time; -static retro_keyboard_event_t runloop_key_event = NULL; -static retro_keyboard_event_t runloop_frontend_key_event = NULL; -static core_option_manager_t *runloop_core_options = NULL; +static retro_keyboard_event_t runloop_key_event = NULL; +static retro_keyboard_event_t runloop_frontend_key_event = NULL; +static core_option_manager_t *runloop_core_options = NULL; #ifdef HAVE_THREADS -static slock_t *_runloop_msg_queue_lock = NULL; +static slock_t *_runloop_msg_queue_lock = NULL; #endif -static msg_queue_t *runloop_msg_queue = NULL; +static msg_queue_t *runloop_msg_queue = NULL; -static unsigned runloop_pending_windowed_scale = 0; -static unsigned runloop_max_frames = 0; -static unsigned fastforward_after_frames = 0; +static unsigned runloop_pending_windowed_scale = 0; +static unsigned runloop_max_frames = 0; +static bool runloop_max_frames_screenshot = false; +static char runloop_max_frames_screenshot_path[PATH_MAX_LENGTH] = {0}; +static unsigned fastforward_after_frames = 0; -static retro_usec_t runloop_frame_time_last = 0; -static retro_time_t frame_limit_minimum_time = 0.0; -static retro_time_t frame_limit_last_time = 0.0; +static retro_usec_t runloop_frame_time_last = 0; +static retro_time_t frame_limit_minimum_time = 0.0; +static retro_time_t frame_limit_last_time = 0.0; extern bool input_driver_flushing_input; @@ -593,7 +597,11 @@ static void retroarch_print_help(const char *arg0) "Not relevant for all platforms."); puts(" --max-frames=NUMBER\n" " Runs for the specified number of frames, " - "then exits.\n"); + "then exits."); + puts(" --max-frames-ss\n" + " Takes a screenshot at the end of max-frames."); + puts(" --max-frames-ss-path=FILE\n" + " Path to save the screenshot to at the end of max-frames.\n"); } #define FFMPEG_RECORD_ARG "r:" @@ -629,48 +637,50 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) const struct option opts[] = { #ifdef HAVE_DYNAMIC - { "libretro", 1, NULL, 'L' }, + { "libretro", 1, NULL, 'L' }, #endif - { "menu", 0, NULL, RA_OPT_MENU }, - { "help", 0, NULL, 'h' }, - { "save", 1, NULL, 's' }, - { "fullscreen", 0, NULL, 'f' }, - { "record", 1, NULL, 'r' }, - { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, - { "size", 1, NULL, RA_OPT_SIZE }, - { "verbose", 0, NULL, 'v' }, - { "config", 1, NULL, 'c' }, - { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, - { "nodevice", 1, NULL, 'N' }, - { "dualanalog", 1, NULL, 'A' }, - { "device", 1, NULL, 'd' }, - { "savestate", 1, NULL, 'S' }, - { "bsvplay", 1, NULL, 'P' }, - { "bsvrecord", 1, NULL, 'R' }, - { "sram-mode", 1, NULL, 'M' }, + { "menu", 0, NULL, RA_OPT_MENU }, + { "help", 0, NULL, 'h' }, + { "save", 1, NULL, 's' }, + { "fullscreen", 0, NULL, 'f' }, + { "record", 1, NULL, 'r' }, + { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, + { "size", 1, NULL, RA_OPT_SIZE }, + { "verbose", 0, NULL, 'v' }, + { "config", 1, NULL, 'c' }, + { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, + { "nodevice", 1, NULL, 'N' }, + { "dualanalog", 1, NULL, 'A' }, + { "device", 1, NULL, 'd' }, + { "savestate", 1, NULL, 'S' }, + { "bsvplay", 1, NULL, 'P' }, + { "bsvrecord", 1, NULL, 'R' }, + { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETWORKING - { "host", 0, NULL, 'H' }, - { "connect", 1, NULL, 'C' }, - { "stateless", 0, NULL, RA_OPT_STATELESS }, - { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, - { "port", 1, NULL, RA_OPT_PORT }, + { "host", 0, NULL, 'H' }, + { "connect", 1, NULL, 'C' }, + { "stateless", 0, NULL, RA_OPT_STATELESS }, + { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, + { "port", 1, NULL, RA_OPT_PORT }, #if defined(HAVE_NETWORK_CMD) - { "command", 1, NULL, RA_OPT_COMMAND }, + { "command", 1, NULL, RA_OPT_COMMAND }, #endif #endif - { "nick", 1, NULL, RA_OPT_NICK }, - { "ups", 1, NULL, 'U' }, - { "bps", 1, NULL, RA_OPT_BPS }, - { "ips", 1, NULL, RA_OPT_IPS }, - { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, - { "detach", 0, NULL, 'D' }, - { "features", 0, NULL, RA_OPT_FEATURES }, - { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, - { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, - { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, - { "version", 0, NULL, RA_OPT_VERSION }, + { "nick", 1, NULL, RA_OPT_NICK }, + { "ups", 1, NULL, 'U' }, + { "bps", 1, NULL, RA_OPT_BPS }, + { "ips", 1, NULL, RA_OPT_IPS }, + { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, + { "detach", 0, NULL, 'D' }, + { "features", 0, NULL, RA_OPT_FEATURES }, + { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, + { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, + { "max-frames-ss", 0, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT }, + { "max-frames-ss-path", 1, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }, + { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, + { "version", 0, NULL, RA_OPT_VERSION }, #ifdef HAVE_FILE_LOGGER - { "log-file", 1, NULL, RA_OPT_LOG_FILE }, + { "log-file", 1, NULL, RA_OPT_LOG_FILE }, #endif { NULL, 0, NULL, 0 } }; @@ -1088,6 +1098,14 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) runloop_max_frames = (unsigned)strtoul(optarg, NULL, 10); break; + case RA_OPT_MAX_FRAMES_SCREENSHOT: + runloop_max_frames_screenshot = true; + break; + + case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH: + strlcpy(runloop_max_frames_screenshot_path, optarg, sizeof(runloop_max_frames_screenshot_path)); + break; + case RA_OPT_SUBSYSTEM: path_set(RARCH_PATH_SUBSYSTEM, optarg); break; @@ -2631,6 +2649,32 @@ static enum runloop_state runloop_check_state( if (time_to_exit(trig_quit_key)) { + if ((runloop_max_frames != 0) && (frame_count >= runloop_max_frames)) + { + if (runloop_max_frames_screenshot) + { + const char *screenshot_path = NULL; + bool fullpath = false; + + if (string_is_empty(runloop_max_frames_screenshot_path)) + screenshot_path = path_get(RARCH_PATH_BASENAME); + else + { + fullpath = true; + screenshot_path = runloop_max_frames_screenshot_path; + } + + RARCH_LOG("Taking a screenshot before exiting...\n"); + + /* Take a screenshot before we exit. */ + if (!take_screenshot(screenshot_path, false, + video_driver_cached_frame_has_valid_framebuffer(), fullpath, false)) + { + RARCH_ERR("Could not take a screenshot before exiting.\n"); + } + } + } + if (runloop_exec) runloop_exec = false; diff --git a/tasks/task_save.c b/tasks/task_save.c index 556da1fde0..1b5d93be4e 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -1010,7 +1010,7 @@ static void save_state_cb(void *task_data, char *path = strdup(state->path); if (state->thumbnail_enable) - take_screenshot(path, true, state->has_valid_framebuffer); + take_screenshot(path, true, state->has_valid_framebuffer, false, true); free(path); } diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 42cc5d8d72..80c3b90cee 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -70,39 +70,17 @@ struct screenshot_task_state uint8_t *out_buffer; const void *frame; char filename[PATH_MAX_LENGTH]; - char shotname[256]; void *userbuf; struct scaler_ctx scaler; }; -/** - * task_screenshot_handler: - * @task : the task being worked on - * - * Saves a screenshot to disk. - **/ -static void task_screenshot_handler(retro_task_t *task) +static bool screenshot_dump_direct(screenshot_task_state_t *state) { + struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; + bool ret = false; #ifdef HAVE_RBMP enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE; -#endif - screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; - struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; - bool ret = false; - - if (task_get_progress(task) == 100) - { - task_set_finished(task, true); - - if (state->userbuf) - free(state->userbuf); - - free(state); - return; - } - -#ifdef HAVE_RBMP - (void)bmp_type; + (void)bmp_type; #endif #if defined(HAVE_RPNG) @@ -146,6 +124,33 @@ static void task_screenshot_handler(retro_task_t *task) bmp_type); #endif + return ret; +} + +/** + * task_screenshot_handler: + * @task : the task being worked on + * + * Saves a screenshot to disk. + **/ +static void task_screenshot_handler(retro_task_t *task) +{ + screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; + bool ret = false; + + if (task_get_progress(task) == 100) + { + task_set_finished(task, true); + + if (state->userbuf) + free(state->userbuf); + + free(state); + return; + } + + ret = screenshot_dump_direct(state); + #ifdef HAVE_IMAGEVIEWER if ( ret && !state->silence && @@ -178,7 +183,9 @@ static bool screenshot_dump( int pitch, bool bgr24, void *userbuf, bool savestate, bool is_idle, - bool is_paused) + bool is_paused, + bool fullpath, + bool use_thread) { char screenshot_path[PATH_MAX_LENGTH]; uint8_t *buf = NULL; @@ -187,14 +194,22 @@ static bool screenshot_dump( screenshot_task_state_t *state = (screenshot_task_state_t*) calloc(1, sizeof(*state)); const char *screenshot_dir = settings->paths.directory_screenshot; + char shotname[256]; + shotname[0] = '\0'; screenshot_path[0] = '\0'; - if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */ + if (fullpath) + strlcpy(state->filename, name_base, sizeof(state->filename)); + else { - fill_pathname_basedir(screenshot_path, name_base, - sizeof(screenshot_path)); - screenshot_dir = screenshot_path; + if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + { + fill_pathname_basedir(screenshot_path, name_base, + sizeof(screenshot_path)); + screenshot_dir = screenshot_path; + } } state->is_idle = is_idle; @@ -209,20 +224,23 @@ static bool screenshot_dump( state->history_list_enable = settings->bools.history_list_enable; state->pixel_format_type = video_driver_get_pixel_format(); - if (savestate) - snprintf(state->filename, - sizeof(state->filename), "%s.png", name_base); - else + if (!fullpath) { - if (settings->bools.auto_screenshot_filename) - fill_str_dated_filename(state->shotname, path_basename(name_base), - IMG_EXT, sizeof(state->shotname)); + if (savestate) + snprintf(state->filename, + sizeof(state->filename), "%s.png", name_base); else - snprintf(state->shotname, sizeof(state->shotname), - "%s.png", path_basename(name_base)); + { + if (settings->bools.auto_screenshot_filename) + fill_str_dated_filename(shotname, path_basename(name_base), + IMG_EXT, sizeof(shotname)); + else + snprintf(shotname, sizeof(shotname), + "%s.png", path_basename(name_base)); - fill_pathname_join(state->filename, screenshot_dir, - state->shotname, sizeof(state->filename)); + fill_pathname_join(state->filename, screenshot_dir, + shotname, sizeof(state->filename)); + } } #if defined(HAVE_RPNG) @@ -241,17 +259,22 @@ static bool screenshot_dump( task->state = state; task->handler = task_screenshot_handler; - if (!savestate) - task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); + if (use_thread) + return screenshot_dump_direct(state); + else + { + if (!savestate) + task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); - task_queue_push(task); + task_queue_push(task); + } return true; } #if !defined(VITA) static bool take_screenshot_viewport(const char *name_base, bool savestate, - bool is_idle, bool is_paused) + bool is_idle, bool is_paused, bool fullpath, bool use_thread) { struct video_viewport vp; uint8_t *buffer = NULL; @@ -280,7 +303,7 @@ static bool take_screenshot_viewport(const char *name_base, bool savestate, /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, buffer, vp.width, vp.height, - vp.width * 3, true, buffer, savestate, is_idle, is_paused)) + vp.width * 3, true, buffer, savestate, is_idle, is_paused, fullpath, use_thread)) goto error; return true; @@ -293,7 +316,7 @@ error: #endif static bool take_screenshot_raw(const char *name_base, void *userbuf, - bool savestate, bool is_idle, bool is_paused) + bool savestate, bool is_idle, bool is_paused, bool fullpath, bool use_thread) { size_t pitch; unsigned width, height; @@ -306,14 +329,14 @@ static bool take_screenshot_raw(const char *name_base, void *userbuf, */ if (!screenshot_dump(name_base, (const uint8_t*)data + (height - 1) * pitch, - width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused)) + width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused, fullpath, use_thread)) return false; return true; } static bool take_screenshot_choice(const char *name_base, bool savestate, - bool is_paused, bool is_idle, bool has_valid_framebuffer) + bool is_paused, bool is_idle, bool has_valid_framebuffer, bool fullpath, bool use_thread) { size_t old_pitch; unsigned old_width, old_height; @@ -335,14 +358,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (!is_idle) video_driver_cached_frame(); #if defined(VITA) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); #else - return take_screenshot_viewport(name_base, savestate, is_idle, is_paused); + return take_screenshot_viewport(name_base, savestate, is_idle, is_paused, fullpath, use_thread); #endif } if (!has_valid_framebuffer) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); if (!video_driver_supports_read_frame_raw()) return false; @@ -359,14 +382,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (frame_data) { video_driver_set_cached_frame_ptr(frame_data); - if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused)) + if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused, fullpath, use_thread)) ret = true; } return ret; } -bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer) +bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread) { bool is_paused = false; bool is_idle = false; @@ -377,7 +400,7 @@ bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebu runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); ret = take_screenshot_choice(name_base, silence, is_paused, is_idle, - has_valid_framebuffer); + has_valid_framebuffer, fullpath, use_thread); if (is_paused && !is_idle) video_driver_cached_frame(); diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index fe9bd41122..a2632e4ac8 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -223,7 +223,7 @@ void task_file_load_handler(retro_task_t *task); bool task_audio_mixer_load_handler(retro_task_t *task); -bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer); +bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread); bool event_load_save_files(void); diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index 23f2fc8c95..1891efccfa 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -11,18 +12,33 @@ #include #include #include +#include +#include #include "shaderparamsdialog.h" #include "../ui_qt.h" extern "C" { #include +#include +#include #include "../../../command.h" +#include "../../../configuration.h" +#include "../../../retroarch.h" +#include "../../../paths.h" #ifdef HAVE_MENU #include "../../../menu/menu_shader.h" #endif } +enum +{ + SHADER_PRESET_SAVE_CORE = 0, + SHADER_PRESET_SAVE_GAME, + SHADER_PRESET_SAVE_PARENT, + SHADER_PRESET_SAVE_NORMAL +}; + ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) : QDialog(parent) ,m_layout(NULL) @@ -75,6 +91,19 @@ void ShaderParamsDialog::closeEvent(QCloseEvent *event) emit closed(); } +void ShaderParamsDialog::paintEvent(QPaintEvent *event) +{ + QStyleOption o; + QPainter p; + o.initFrom(this); + p.begin(this); + style()->drawPrimitive( + QStyle::PE_Widget, &o, &p, this); + p.end(); + + QDialog::paintEvent(event); +} + QString ShaderParamsDialog::getFilterLabel(unsigned filter) { QString filterString; @@ -375,13 +404,265 @@ void ShaderParamsDialog::onShaderPassMoveUpClicked() command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); } +void ShaderParamsDialog::onShaderLoadPresetClicked() +{ +#ifdef HAVE_MENU + QString path; + QByteArray pathArray; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + const char *pathData = NULL; + settings_t *settings = config_get_ptr(); + enum rarch_shader_type type = RARCH_SHADER_NONE; + + if (!settings) + return; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + type = video_shader_parse_type(pathData, RARCH_SHADER_NONE); + + menu_shader_manager_set_preset(menu_shader, type, pathData); +#endif +} + +void ShaderParamsDialog::onShaderAddPassClicked() +{ +#ifdef HAVE_MENU + QString path; + QByteArray pathArray; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + struct video_shader_pass *shader_pass = NULL; + const char *pathData = NULL; + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + path = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + if (menu_shader->passes < GFX_MAX_SHADERS) + menu_shader_manager_increment_amount_passes(); + else + return; + + shader_pass = &menu_shader->pass[menu_shader->passes - 1]; + + if (!shader_pass) + return; + + strlcpy(shader_pass->source.path, pathData, sizeof(shader_pass->source.path)); + + video_shader_resolve_parameters(NULL, menu_shader); + + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +#endif +} + +void ShaderParamsDialog::onShaderSavePresetAsClicked() +{ +#ifdef HAVE_MENU + settings_t *settings = config_get_ptr(); + QString path; + QByteArray pathArray; + const char *pathData = NULL; + + path = QFileDialog::getSaveFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS), settings->paths.directory_video_shader); + + if (path.isEmpty()) + return; + + pathArray = path.toUtf8(); + pathData = pathArray.constData(); + + saveShaderPreset(pathData, SHADER_PRESET_SAVE_NORMAL); +#endif +} + +void ShaderParamsDialog::saveShaderPreset(const char *path, unsigned action_type) +{ + char directory[PATH_MAX_LENGTH]; + char file[PATH_MAX_LENGTH]; + char tmp[PATH_MAX_LENGTH]; + settings_t *settings = config_get_ptr(); + const char *core_name = NULL; + rarch_system_info_t *info = runloop_get_system_info(); + + directory[0] = file[0] = tmp[0] = '\0'; + + if (info) + core_name = info->info.library_name; + + if (!string_is_empty(core_name)) + { + fill_pathname_join( + tmp, + settings->paths.directory_video_shader, + "presets", + sizeof(tmp)); + fill_pathname_join( + directory, + tmp, + core_name, + sizeof(directory)); + } + + if (!filestream_exists(directory)) + path_mkdir(directory); + + switch (action_type) + { + case SHADER_PRESET_SAVE_CORE: + if (!string_is_empty(core_name)) + fill_pathname_join(file, directory, core_name, sizeof(file)); + break; + case SHADER_PRESET_SAVE_GAME: + { + const char *game_name = path_basename(path_get(RARCH_PATH_BASENAME)); + fill_pathname_join(file, directory, game_name, sizeof(file)); + break; + } + case SHADER_PRESET_SAVE_PARENT: + { + fill_pathname_parent_dir_name(tmp, path_get(RARCH_PATH_BASENAME), sizeof(tmp)); + fill_pathname_join(file, directory, tmp, sizeof(file)); + break; + } + case SHADER_PRESET_SAVE_NORMAL: + default: + if (!string_is_empty(path)) + strlcpy(file, path, sizeof(file)); + break; + } + + if (menu_shader_manager_save_preset(file, false, true)) + runloop_msg_queue_push( + msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY), + 1, 100, true); + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET), + 1, 100, true); +} + +void ShaderParamsDialog::onShaderSaveCorePresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_CORE); +} + +void ShaderParamsDialog::onShaderSaveParentPresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_PARENT); +} + +void ShaderParamsDialog::onShaderSaveGamePresetClicked() +{ + saveShaderPreset(NULL, SHADER_PRESET_SAVE_GAME); +} + +void ShaderParamsDialog::onShaderClearAllPassesClicked() +{ +#ifdef HAVE_MENU + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader) + return; + + while (menu_shader->passes > 0) + menu_shader_manager_decrement_amount_passes(); + + onShaderApplyClicked(); +#endif +} + +void ShaderParamsDialog::onShaderRemovePassClicked() +{ +#ifdef HAVE_MENU + QAction *action = qobject_cast(sender()); + QVariant passVariant; + struct video_shader *menu_shader = NULL; + struct video_shader *video_shader = NULL; + int pass = 0; + int i; + bool ok = false; + + getShaders(&menu_shader, &video_shader); + + if (!menu_shader || menu_shader->passes == 0 || !action) + return; + + passVariant = action->data(); + + if (!passVariant.isValid()) + return; + + pass = passVariant.toInt(&ok); + + if (!ok) + return; + + if (pass < 0 || pass > static_cast(menu_shader->passes)) + return; + + /* move selected pass to the bottom */ + for (i = pass; i < static_cast(menu_shader->passes) - 1; i++) + { + std::swap(menu_shader->pass[i], menu_shader->pass[i + 1]); + } + + menu_shader_manager_decrement_amount_passes(); + + onShaderApplyClicked(); +#endif +} + +void ShaderParamsDialog::onShaderApplyClicked() +{ + command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); +} + void ShaderParamsDialog::reload() { + QPushButton *loadButton = NULL; + QPushButton *saveButton = NULL; + QPushButton *removeButton = NULL; + QPushButton *applyButton = NULL; + QHBoxLayout *topButtonLayout = NULL; + QMenu *loadMenu = NULL; + QMenu *saveMenu = NULL; + QMenu *removeMenu = NULL; struct video_shader *menu_shader = NULL; struct video_shader *video_shader = NULL; const char *shader_path = NULL; int i; unsigned j; + bool hasPasses = false; getShaders(&menu_shader, &video_shader); @@ -409,6 +690,56 @@ void ShaderParamsDialog::reload() else setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS)); + loadButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_LOAD), this); + saveButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SAVE), this); + removeButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_REMOVE), this); + applyButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_APPLY), this); + + loadMenu = new QMenu(loadButton); + loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), this, SLOT(onShaderLoadPresetClicked())); + loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS), this, SLOT(onShaderAddPassClicked())); + + loadButton->setMenu(loadMenu); + + saveMenu = new QMenu(saveButton); + saveMenu->addAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS)) + "...", this, SLOT(onShaderSavePresetAsClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE), this, SLOT(onShaderSaveCorePresetClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT), this, SLOT(onShaderSaveParentPresetClicked())); + saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME), this, SLOT(onShaderSaveGamePresetClicked())); + + saveButton->setMenu(saveMenu); + + removeMenu = new QMenu(removeButton); + + /* When there are no passes, at least on first startup, it seems video_shader erroneously shows 1 pass, with an empty source file. + * So we use menu_shader instead for that. + */ + if (menu_shader) + { + for (i = 0; i < static_cast(menu_shader->passes); i++) + { + QFileInfo fileInfo(menu_shader->pass[i].source.path); + QString shaderBasename = fileInfo.completeBaseName(); + QAction *action = removeMenu->addAction(shaderBasename, this, SLOT(onShaderRemovePassClicked())); + + action->setData(i); + } + } + + removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES), this, SLOT(onShaderClearAllPassesClicked())); + + removeButton->setMenu(removeMenu); + + connect(applyButton, SIGNAL(clicked()), this, SLOT(onShaderApplyClicked())); + + topButtonLayout = new QHBoxLayout(); + topButtonLayout->addWidget(loadButton); + topButtonLayout->addWidget(saveButton); + topButtonLayout->addWidget(removeButton); + topButtonLayout->addWidget(applyButton); + + m_layout->addLayout(topButtonLayout); + /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */ for (i = 0; i < static_cast(video_shader->passes); i++) { @@ -417,20 +748,26 @@ void ShaderParamsDialog::reload() QFileInfo fileInfo(video_shader->pass[i].source.path); QString shaderBasename = fileInfo.completeBaseName(); QHBoxLayout *filterScaleHBoxLayout = NULL; - QComboBox *filterComboBox = new QComboBox(); - QComboBox *scaleComboBox = new QComboBox(); + QComboBox *filterComboBox = new QComboBox(this); + QComboBox *scaleComboBox = new QComboBox(this); QToolButton *moveDownButton = NULL; QToolButton *moveUpButton = NULL; unsigned j = 0; + /* Sometimes video_shader shows 1 pass with no source file, when there are really 0 passes. */ + if (shaderBasename.isEmpty()) + continue; + + hasPasses = true; + filterComboBox->setProperty("pass", i); scaleComboBox->setProperty("pass", i); - moveDownButton = new QToolButton(); + moveDownButton = new QToolButton(this); moveDownButton->setText("↓"); moveDownButton->setProperty("pass", i); - moveUpButton = new QToolButton(); + moveUpButton = new QToolButton(this); moveUpButton->setText("↑"); moveUpButton->setProperty("pass", i); @@ -488,9 +825,9 @@ void ShaderParamsDialog::reload() filterScaleHBoxLayout = new QHBoxLayout(); filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred)); - filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":")); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":", this)); filterScaleHBoxLayout->addWidget(filterComboBox); - filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":")); + filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":", this)); filterScaleHBoxLayout->addWidget(scaleComboBox); filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(20, 0, QSizePolicy::Preferred, QSizePolicy::Preferred)); @@ -513,6 +850,14 @@ void ShaderParamsDialog::reload() } } + if (!hasPasses) + { + QLabel *noParamsLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES), this); + noParamsLabel->setAlignment(Qt::AlignCenter); + + m_layout->addWidget(noParamsLabel); + } + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); end: diff --git a/ui/drivers/qt/shaderparamsdialog.h b/ui/drivers/qt/shaderparamsdialog.h index 8bd7ed8f3c..9e74d20c20 100644 --- a/ui/drivers/qt/shaderparamsdialog.h +++ b/ui/drivers/qt/shaderparamsdialog.h @@ -29,16 +29,27 @@ private slots: void onScaleComboBoxIndexChanged(int index); void onShaderPassMoveDownClicked(); void onShaderPassMoveUpClicked(); + void onShaderLoadPresetClicked(); + void onShaderAddPassClicked(); + void onShaderSavePresetAsClicked(); + void onShaderSaveCorePresetClicked(); + void onShaderSaveParentPresetClicked(); + void onShaderSaveGamePresetClicked(); + void onShaderClearAllPassesClicked(); + void onShaderRemovePassClicked(); + void onShaderApplyClicked(); private: QString getFilterLabel(unsigned filter); void addShaderParam(struct video_shader_parameter *param, int parameter, QFormLayout *form); void clearLayout(QLayout *layout); void getShaders(struct video_shader **menu_shader, struct video_shader **video_shader); + void saveShaderPreset(const char *path, unsigned action_type); QVBoxLayout *m_layout; protected: void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); }; #endif diff --git a/ui/drivers/qt/ui_qt_themes.h b/ui/drivers/qt/ui_qt_themes.h index 1844930c45..803cf8a37a 100644 --- a/ui/drivers/qt/ui_qt_themes.h +++ b/ui/drivers/qt/ui_qt_themes.h @@ -34,22 +34,18 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( QTextEdit, LogTextEdit { background-color:rgb(25,25,25); } - QSpinBox, QCheckBox { + QSpinBox, QDoubleSpinBox, QCheckBox { background-color:rgb(25,25,25); } QCheckBox:checked, QCheckBox:unchecked { background-color:rgb(53,53,53); } - QDialog#shaderParamsDialog { + QWidget#shaderParamsWidget { background-color:rgb(25,25,25); } - QDialog#shaderParamsDialog QGroupBox, QDialog#shaderParamsDialog QGroupBox QLabel, - QDialog#shaderParamsDialog QGroupBox QSlider, QDialog#shaderParamsDialog QGroupBox QCheckBox:checked, - QDialog#shaderParamsDialog QGroupBox QCheckBox:unchecked { - background-color:rgb(53,53,53); - } QDialog#shaderParamsDialog QGroupBox { - border-top-left-radius: 0px; + background-color:rgb(53,53,53); + border-top-left-radius:0px; } QDialog#shaderParamsDialog QGroupBox::title { margin-left:0px; @@ -58,7 +54,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( background-color:qlineargradient(x1:0,y1:1,x2:0,y2:0,stop:0 rgb(53,53,53),stop:1 rgba(125,125,125,127)); border:1px solid rgba(25,25,25,75); border-top:1px solid rgba(175,175,175,50%); - border-bottom: none transparent; + border-bottom:none transparent; } QToolTip { color:white; @@ -224,7 +220,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( } QComboBox { min-height:20px; - padding:1px 18px 1px 3px; + padding:1px 6px 1px 6px; } QComboBox::focus { background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); @@ -238,6 +234,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( } QComboBox::drop-down { background-color:transparent; + width:0px; } QComboBox::selected:on, QComboBox::selected:off { background-color:%1; @@ -262,6 +259,10 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( padding:1px 3px 1px 3px; outline:none; } + QPushButton::disabled, QToolButton::disabled { + color:grey; + background-color:rgb(25,25,25); + } QPushButton::focus, QToolButton::focus { background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgba(255,255,255,50), stop: 1 rgba(100,100,100,25)); border:1px solid %1; @@ -278,7 +279,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( border-radius:4px; } QPushButton[flat="true"] { - background-color: transparent; + background-color:transparent; } QRadioButton::indicator { width:18px; @@ -428,7 +429,7 @@ static const QString qt_theme_dark_stylesheet = QStringLiteral(R"( background-color:rgb(40,40,40); border:3px solid %1; } - QScrollArea QWidget { - background:rgb(25,25,25); + QWidget#gridLayoutWidget { + background-color:rgb(25,25,25); } )"); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 7134bcc2c2..9e64b80a69 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -370,6 +370,7 @@ MainWindow::MainWindow(QWidget *parent) : m_gridWidget->setLayout(new QVBoxLayout()); m_gridLayout = new FlowLayout(m_gridLayoutWidget); + m_gridLayoutWidget->setObjectName("gridLayoutWidget"); m_gridScrollArea->setAlignment(Qt::AlignCenter); m_gridScrollArea->setFrameShape(QFrame::NoFrame); @@ -839,7 +840,7 @@ void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&) QList actions; QScopedPointer scanAction; QDir dir; - QString currentDirString = m_dirModel->filePath(m_dirTree->currentIndex()); + QString currentDirString = QDir::toNativeSeparators(m_dirModel->filePath(m_dirTree->currentIndex())); settings_t *settings = config_get_ptr(); QByteArray dirArray; const char *fullpath = NULL; @@ -1398,7 +1399,7 @@ void MainWindow::selectBrowserDir(QString path) QString fileName = dirList.at(i); QTableWidgetItem *item = new QTableWidgetItem(fileName); QHash hash; - QString filePath(dir.absoluteFilePath(fileName)); + QString filePath(QDir::toNativeSeparators(dir.absoluteFilePath(fileName))); QFileInfo fileInfo(filePath); hash["path"] = filePath; diff --git a/ui/drivers/ui_qt.cpp b/ui/drivers/ui_qt.cpp index 067cf7b661..e17954bf5a 100644 --- a/ui/drivers/ui_qt.cpp +++ b/ui/drivers/ui_qt.cpp @@ -607,6 +607,11 @@ static void ui_companion_qt_toggle(void *data, bool force) #endif if (settings->bools.ui_companion_toggle || force) { + if (settings->bools.video_fullscreen) + command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); + + win_handle->qtWindow->activateWindow(); + win_handle->qtWindow->raise(); video_driver_show_mouse(); win_handle->qtWindow->show();