diff --git a/.vscode/settings.json b/.vscode/settings.json index 386e8341f9..95dbc02f0b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,9 +40,23 @@ "ozone_theme.h": "c", "ozone_texture.h": "c", "string_list.h": "c", - "core_info.h": "c" + "core_info.h": "c", "thread": "c", - "xlocale": "c" + "xlocale": "c", + "menu_widgets.h": "c", + "message_queue.h": "c", + "task_queue.h": "c", + "fifo_queue.h": "c", + "file_list.h": "c", + "strl.h": "c", + "configuration.h": "c", + "ozone_display.h": "c", + "verbosity.h": "c", + "retroarch.h": "c", + "menu_animation.h": "c", + "audio_driver.h": "c", + "netplay.h": "c", + "scaler.h": "c" }, "C_Cpp.dimInactiveRegions": false, } \ No newline at end of file diff --git a/Makefile.common b/Makefile.common index 9c9e03e329..c7b98f063c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -699,6 +699,10 @@ ifeq ($(HAVE_MENU), 1) DEFINES += -DHAVE_MENU HAVE_MENU_COMMON = 1 + ifeq ($(HAVE_MENU_WIDGETS), 1) + DEFINES += -DHAVE_MENU_WIDGETS + endif + ifeq ($(HAVE_RGUI), 1) OBJ += menu/drivers/rgui.o DEFINES += -DHAVE_RGUI @@ -782,6 +786,10 @@ ifeq ($(HAVE_MENU_COMMON), 1) ifeq ($(HAVE_MENU_COMMON),1) OBJ += menu/drivers_display/menu_display_null.o endif + + ifeq ($(HAVE_MENU_WIDGETS), 1) + OBJ += menu/widgets/menu_widgets.o + endif endif ifeq ($(HAVE_OVERLAY), 1) diff --git a/audio/audio_driver.c b/audio/audio_driver.c index b1746ebacc..7f1b331a34 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -1406,7 +1406,7 @@ static void audio_driver_mixer_play_stream_internal(unsigned i, unsigned type) audio_mixer_streams[i].state = (enum audio_mixer_state)type; } -static void audio_driver_load_menu_bgm_callback(void *task_data, void *user_data, const char *error) +static void audio_driver_load_menu_bgm_callback(retro_task_t *task, void *task_data, void *user_data, const char *error) { bool contentless = false; bool is_inited = false; diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 1d64363587..9fd2bcac3d 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -206,7 +206,8 @@ bool camera_driver_ctl(enum rarch_camera_ctl_state state, void *data) return camera_driver->start(camera_data); runloop_msg_queue_push( - "Camera is explicitly disabled.\n", 1, 180, false); + "Camera is explicitly disabled.\n", 1, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } break; case RARCH_CAMERA_CTL_SET_CB: diff --git a/cheevos-new/badges.c b/cheevos-new/badges.c index 4292204ae9..4fadc5520a 100644 --- a/cheevos-new/badges.c +++ b/cheevos-new/badges.c @@ -34,7 +34,7 @@ void set_badge_menu_texture(badges_ctx_t * badges, int i) #ifdef HAVE_MENU menu_display_reset_textures_list(badge_file, fullpath, - &badges->menu_texture_list[i],TEXTURE_FILTER_MIPMAP_LINEAR); + &badges->menu_texture_list[i],TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL); #endif } diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index 759e1d0277..3be5426451 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -493,8 +493,8 @@ static void cheevos_award(cheevos_cheevo_t* cheevo, int mode) /* Show the OSD message. */ snprintf(buffer, sizeof(buffer), "Achievement Unlocked: %s", cheevo->info->title); - runloop_msg_queue_push(buffer, 0, 2 * 60, false); - runloop_msg_queue_push(cheevo->info->description, 0, 3 * 60, false); + runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + runloop_msg_queue_push(cheevo->info->description, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Start the award task. */ if ((mode & CHEEVOS_ACTIVE_HARDCORE) != 0) @@ -633,7 +633,7 @@ static void cheevos_lboard_submit(cheevos_lboard_t* lboard) if (lboard->last_value == 0) { CHEEVOS_ERR(CHEEVOS_TAG "Leaderboard %s tried to submit 0\n", lboard->info->title); - runloop_msg_queue_push("Leaderboard attempt cancelled!", 0, 2 * 60, false); + runloop_msg_queue_push("Leaderboard attempt cancelled!", 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } @@ -642,7 +642,7 @@ static void cheevos_lboard_submit(cheevos_lboard_t* lboard) snprintf(buffer, sizeof(buffer), "Submitted %s for %s", value, lboard->info->title); - runloop_msg_queue_push(buffer, 0, 2 * 60, false); + runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Start the submit task. */ cheevos_lboard_submit_task(NULL, lboard, "no error, first try"); @@ -689,8 +689,8 @@ static void cheevos_test_leaderboards(void) snprintf(buffer, sizeof(buffer), "Leaderboard Active: %s", lboard->info->title); - runloop_msg_queue_push(buffer, 0, 2 * 60, false); - runloop_msg_queue_push(lboard->info->description, 0, 3 * 60, false); + runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + runloop_msg_queue_push(lboard->info->description, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } } @@ -958,7 +958,7 @@ bool cheevos_toggle_hardcore_mode(void) command_event(CMD_EVENT_REWIND_DEINIT, NULL); CHEEVOS_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 0, 3 * 60, true); + runloop_msg_queue_push(msg, 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { @@ -1328,7 +1328,7 @@ found: if (!coro->json) { - runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); + runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); CHEEVOS_ERR(CHEEVOS_TAG "error loading achievements\n"); CORO_STOP(); } @@ -1393,7 +1393,7 @@ found: "You have %d of %d achievements unlocked.", number_of_unlocked, cheevos_locals.patchdata.core_count); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 6 * 60, false); + runloop_msg_queue_push(msg, 0, 6 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } CORO_GOSUB(GET_BADGES); @@ -1792,7 +1792,7 @@ found: if (!coro->json) { - runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); + runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); CHEEVOS_ERR(CHEEVOS_TAG "error getting user token\n"); CORO_STOP(); @@ -1806,7 +1806,7 @@ found: snprintf(msg, sizeof(msg), "RetroAchievements: %s", tok); - runloop_msg_queue_push(msg, 0, 5 * 60, false); + runloop_msg_queue_push(msg, 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); *coro->settings->arrays.cheevos_token = 0; CHEEVOS_FREE(coro->json); @@ -1822,7 +1822,7 @@ found: "RetroAchievements: Logged in as \"%s\".", coro->settings->arrays.cheevos_username); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 3 * 60, false); + runloop_msg_queue_push(msg, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } strlcpy(cheevos_locals.token, tok, @@ -2047,7 +2047,7 @@ bool cheevos_load(const void *data) if (!coro) return false; - task = (retro_task_t*)calloc(1, sizeof(*task)); + task = task_init(); if (!task) { diff --git a/cheevos/badges.c b/cheevos/badges.c index 90383dd49f..3232a9d449 100644 --- a/cheevos/badges.c +++ b/cheevos/badges.c @@ -49,7 +49,7 @@ void set_badge_menu_texture(badges_ctx_t * badges, int i) #ifdef HAVE_MENU menu_display_reset_textures_list(badge_file, fullpath, - &badges->menu_texture_list[i],TEXTURE_FILTER_MIPMAP_LINEAR); + &badges->menu_texture_list[i],TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL); #endif } diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 17b41920be..bfdd4b030e 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include "../config.h" @@ -1589,7 +1590,7 @@ static void cheevos_make_unlock_url(const cheevo_t *cheevo, #endif } -static void cheevos_unlocked(void *task_data, void *user_data, +static void cheevos_unlocked(retro_task_t *task, void *task_data, void *user_data, const char *error) { cheevo_t *cheevo = (cheevo_t *)user_data; @@ -1657,8 +1658,8 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set) snprintf(msg, sizeof(msg), "Achievement Unlocked: %s", cheevo->title); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false); + runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); cheevos_make_unlock_url(cheevo, url, sizeof(url)); task_push_http_transfer(url, true, NULL, @@ -1818,7 +1819,7 @@ static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, #endif } -static void cheevos_lboard_submit(void *task_data, void *user_data, +static void cheevos_lboard_submit(retro_task_t *task, void *task_data, void *user_data, const char *error) { cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; @@ -1866,7 +1867,8 @@ static void cheevos_test_leaderboards(void) CHEEVOS_LOG("[CHEEVOS]: error: lboard %s tried to submit 0\n", lboard->title); runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); + 0, 2 * 60, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { @@ -1884,7 +1886,7 @@ static void cheevos_test_leaderboards(void) snprintf(msg, sizeof(msg), "Submitted %s for %s", formatted_value, lboard->title); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); + runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -1893,7 +1895,8 @@ static void cheevos_test_leaderboards(void) CHEEVOS_LOG("[CHEEVOS]: cancel lboard %s\n", lboard->title); lboard->active = 0; runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); + 0, 2 * 60, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } else @@ -1909,8 +1912,8 @@ static void cheevos_test_leaderboards(void) snprintf(msg, sizeof(msg), "Leaderboard Active: %s", lboard->title); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(lboard->description, 0, 3*60, false); + runloop_msg_queue_push(msg, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + runloop_msg_queue_push(lboard->description, 0, 3*60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } } @@ -2279,7 +2282,7 @@ bool cheevos_toggle_hardcore_mode(void) command_event(CMD_EVENT_REWIND_DEINIT, NULL); CHEEVOS_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 0, 3 * 60, true); + runloop_msg_queue_push(msg, 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { @@ -2810,7 +2813,7 @@ found: if (!coro->json) { - runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); + runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); CHEEVOS_ERR("[CHEEVOS]: error loading achievements.\n"); CORO_STOP(); } @@ -2839,7 +2842,8 @@ found: { runloop_msg_queue_push( "This game has no achievements.", - 0, 5 * 60, false); + 0, 5 * 60, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); cheevos_free_cheevo_set(&cheevos_locals.core); cheevos_free_cheevo_set(&cheevos_locals.unofficial); @@ -2887,7 +2891,7 @@ found: "You have %d of %d achievements unlocked.", number_of_unlocked, cheevos_locals.core.count); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 6 * 60, false); + runloop_msg_queue_push(msg, 0, 6 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } CORO_GOSUB(GET_BADGES); @@ -3292,10 +3296,12 @@ found: { runloop_msg_queue_push( "Missing RetroAchievements account information.", - 0, 5 * 60, false); + 0, 5 * 60, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); runloop_msg_queue_push( "Please fill in your account information in Settings.", - 0, 5 * 60, false); + 0, 5 * 60, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); CHEEVOS_ERR("[CHEEVOS]: login info not informed.\n"); CORO_STOP(); } @@ -3352,7 +3358,7 @@ found: "RetroAchievements: Logged in as \"%s\".", coro->settings->arrays.cheevos_username); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 3 * 60, false); + runloop_msg_queue_push(msg, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } /* Save token to config and clear pass on success */ @@ -3373,13 +3379,13 @@ found: "RetroAchievements: %s", error_response); error_message[sizeof(error_message) - 1] = 0; - runloop_msg_queue_push(error_message, 0, 5 * 60, false); + runloop_msg_queue_push(error_message, 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); *coro->settings->arrays.cheevos_token = '\0'; CORO_STOP(); } - runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); + runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); CHEEVOS_ERR("[CHEEVOS]: error getting user token.\n"); CORO_STOP(); @@ -3636,7 +3642,7 @@ bool cheevos_load(const void *data) if (!coro) return false; - task = (retro_task_t*)calloc(1, sizeof(*task)); + task = task_init(); if (!task) { diff --git a/command.c b/command.c index 4958167f00..a41e87b9a1 100644 --- a/command.c +++ b/command.c @@ -59,6 +59,9 @@ #include "menu/menu_content.h" #include "menu/menu_shader.h" #include "menu/widgets/menu_dialog.h" +#ifdef HAVE_MENU_WIDGETS +#include "menu/widgets/menu_widgets.h" +#endif #endif #ifdef HAVE_NETWORKING @@ -260,7 +263,7 @@ bool command_set_shader(const char *arg) return false; snprintf(msg, sizeof(msg), "Shader: \"%s\"", arg); - runloop_msg_queue_push(msg, 1, 120, true); + runloop_msg_queue_push(msg, 1, 120, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_APPLYING_SHADER), arg); @@ -788,7 +791,7 @@ static void command_event_disk_control_set_eject(bool new_state, bool print_log) /* Only noise in menu. */ if (print_log) - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -846,7 +849,7 @@ static void command_event_disk_control_set_index(unsigned idx) RARCH_ERR("%s\n", msg); else RARCH_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -887,7 +890,7 @@ static bool command_event_disk_control_append_image(const char *path) snprintf(msg, sizeof(msg), "%s: ", msg_hash_to_str(MSG_APPENDED_DISK)); strlcat(msg, path, sizeof(msg)); RARCH_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 0, 180, true); + runloop_msg_queue_push(msg, 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); command_event(CMD_EVENT_AUTOSAVE_DEINIT, NULL); @@ -996,7 +999,12 @@ static void command_event_set_volume(float gain) snprintf(msg, sizeof(msg), "%s: %.1f dB", msg_hash_to_str(MSG_AUDIO_VOLUME), new_volume); - runloop_msg_queue_push(msg, 1, 180, true); + +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_volume_update_and_show()) +#endif + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + RARCH_LOG("%s\n", msg); audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume); @@ -1023,7 +1031,7 @@ static void command_event_set_mixer_volume(float gain) snprintf(msg, sizeof(msg), "%s: %.1f dB", msg_hash_to_str(MSG_AUDIO_VOLUME), new_volume); - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); audio_set_float(AUDIO_ACTION_VOLUME_GAIN, new_volume); @@ -1502,7 +1510,7 @@ static bool command_event_save_core_config(void) if (string_is_empty(config_dir)) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("[Config]: %s\n", msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET)); free (config_dir); return false; @@ -1575,7 +1583,7 @@ static bool command_event_save_core_config(void) command_event_save_config(config_path, msg, sizeof(msg)); if (!string_is_empty(msg)) - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); if (overrides_active) rarch_ctl(RARCH_CTL_SET_OVERRIDES_ACTIVE, NULL); @@ -1630,7 +1638,7 @@ static void command_event_save_current_config(enum override_type type) } if (!string_is_empty(msg)) - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } static void command_event_undo_save_state(char *s, size_t len) @@ -1739,7 +1747,7 @@ static bool command_event_main_state(unsigned cmd) MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES), sizeof(msg)); if (push_msg) - runloop_msg_queue_push(msg, 2, 180, true); + runloop_msg_queue_push(msg, 2, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); free(state_path); @@ -1802,7 +1810,7 @@ bool command_event(enum event_command cmd, void *data) snprintf(msg, sizeof(msg),"%s: %dx%d", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION), width, height); - runloop_msg_queue_push(msg, 1, 100, true); + runloop_msg_queue_push(msg, 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } #endif @@ -1897,7 +1905,7 @@ bool command_event(enum event_command cmd, void *data) cheevos_hardcore_paused = false; #endif RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); - runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #ifdef HAVE_CHEEVOS cheevos_set_cheats(); @@ -2122,7 +2130,11 @@ TODO: Add a setting for these tweaks */ return false; } - runloop_msg_queue_push(msg, 1, 180, true); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_volume_update_and_show()) +#endif + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + RARCH_LOG("%s\n", msg); } break; @@ -2379,7 +2391,7 @@ TODO: Add a setting for these tweaks */ break; case CMD_EVENT_SHUTDOWN: #if defined(__linux__) && !defined(ANDROID) - runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_SHUTTING_DOWN), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_SHUTTING_DOWN), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL); command_event(CMD_EVENT_QUIT, NULL); system("shutdown -P now"); @@ -2387,7 +2399,7 @@ TODO: Add a setting for these tweaks */ break; case CMD_EVENT_REBOOT: #if defined(__linux__) && !defined(ANDROID) - runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_REBOOTING), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_VALUE_REBOOTING), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG, NULL); command_event(CMD_EVENT_QUIT, NULL); system("shutdown -r now"); @@ -2417,7 +2429,7 @@ TODO: Add a setting for these tweaks */ core_path, core_name ); - runloop_msg_queue_push(msg_hash_to_str(MSG_ADDED_TO_FAVORITES), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_ADDED_TO_FAVORITES), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); break; } @@ -2437,7 +2449,7 @@ TODO: Add a setting for these tweaks */ NULL, NULL); - runloop_msg_queue_push(msg_hash_to_str(MSG_RESET_CORE_ASSOCIATION), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RESET_CORE_ASSOCIATION), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); break; } @@ -2491,8 +2503,12 @@ TODO: Add a setting for these tweaks */ RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); command_event(CMD_EVENT_AUDIO_STOP, NULL); - runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1, - 1, true); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_set_paused(is_paused)) +#endif + runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1, + 1, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); if (!is_idle) video_driver_cached_frame(); @@ -2506,6 +2522,11 @@ TODO: Add a setting for these tweaks */ } else { +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (video_driver_has_widgets()) + menu_widgets_set_paused(is_paused); +#endif + RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); command_event(CMD_EVENT_AUDIO_START, NULL); } @@ -2760,7 +2781,8 @@ TODO: Add a setting for these tweaks */ else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), - 1, 120, true); + 1, 120, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } break; case CMD_EVENT_DISK_NEXT: @@ -2784,7 +2806,8 @@ TODO: Add a setting for these tweaks */ else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), - 1, 120, true); + 1, 120, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } break; case CMD_EVENT_DISK_PREV: @@ -2808,7 +2831,8 @@ TODO: Add a setting for these tweaks */ else runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS), - 1, 120, true); + 1, 120, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } break; case CMD_EVENT_RUMBLE_STOP: @@ -2875,7 +2899,8 @@ TODO: Add a setting for these tweaks */ input_driver_keyboard_mapping_set_block(1); if (mode != -1) runloop_msg_queue_push(msg_hash_to_str(MSG_GAME_FOCUS_ON), - 1, 120, true); + 1, 120, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { @@ -2885,7 +2910,8 @@ TODO: Add a setting for these tweaks */ input_driver_keyboard_mapping_set_block(0); if (mode != -1) runloop_msg_queue_push(msg_hash_to_str(MSG_GAME_FOCUS_OFF), - 1, 120, true); + 1, 120, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } diff --git a/configuration.c b/configuration.c index 57b6f5c2c1..0b24d3f877 100644 --- a/configuration.c +++ b/configuration.c @@ -3416,7 +3416,8 @@ bool config_load_override(void) * since it will be overwritten by the override when reloading. */ path_set(RARCH_PATH_CORE, buf); runloop_msg_queue_push(msg_hash_to_str(MSG_CONFIG_OVERRIDE_LOADED), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Reset save paths. */ retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_STATE_PATH, NULL); @@ -3554,7 +3555,8 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, game_path)) { runloop_msg_queue_push(msg_hash_to_str( - MSG_GAME_REMAP_FILE_LOADED), 1, 100, true); + MSG_GAME_REMAP_FILE_LOADED), 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); rarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL); goto success; } @@ -3575,7 +3577,8 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, content_path)) { runloop_msg_queue_push(msg_hash_to_str( - MSG_GAME_REMAP_FILE_LOADED), 1, 100, true); + MSG_GAME_REMAP_FILE_LOADED), 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); rarch_ctl(RARCH_CTL_SET_REMAPS_CONTENT_DIR_ACTIVE, NULL); goto success; } @@ -3596,7 +3599,8 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, core_path)) { runloop_msg_queue_push( - msg_hash_to_str(MSG_CORE_REMAP_FILE_LOADED), 1, 100, true); + msg_hash_to_str(MSG_CORE_REMAP_FILE_LOADED), 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); rarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL); goto success; } diff --git a/discord/discord.c b/discord/discord.c index a111177462..c27296408d 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -169,7 +169,7 @@ static void handle_discord_error(int errcode, const char* message) RARCH_LOG("[Discord] error (%d: %s)\n", errcode, message); } -static void handle_discord_join_cb(void *task_data, void *user_data, const char *err) +static void handle_discord_join_cb(retro_task_t *task, void *task_data, void *user_data, const char *err) { struct netplay_room *room; char tmp_hostname[32]; diff --git a/driver.c b/driver.c index 7614fb7e8e..a551074d34 100644 --- a/driver.c +++ b/driver.c @@ -26,6 +26,9 @@ #ifdef HAVE_MENU #include "menu/menu_driver.h" +#ifdef HAVE_MENU_WIDGETS +#include "menu/widgets/menu_widgets.h" +#endif #endif #include "dynamic.h" @@ -306,7 +309,8 @@ static bool driver_update_system_av_info(const struct retro_system_av_info *info { runloop_msg_queue_push( msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT), - 2, 180, false); + 2, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); command_event(CMD_EVENT_RECORD_DEINIT, NULL); command_event(CMD_EVENT_RECORD_INIT, NULL); } @@ -384,6 +388,14 @@ void drivers_init(int flags) core_info_init_current_core(); #ifdef HAVE_MENU +#ifdef HAVE_MENU_WIDGETS + if (video_driver_has_widgets()) + { + menu_widgets_init(video_is_threaded); + menu_widgets_context_reset(video_is_threaded); + } +#endif + if (flags & DRIVER_VIDEO_MASK) { if (flags & DRIVER_MENU_MASK) @@ -484,6 +496,15 @@ bool driver_ctl(enum driver_ctl_state state, void *data) switch (state) { case RARCH_DRIVER_CTL_DEINIT: +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + /* Tear down menu widgets no matter what + * in case the handle is lost in the threaded + * video driver in the meantime + * (breaking video_driver_has_widgets) */ + menu_widgets_context_destroy(); + menu_widgets_free(); + +#endif video_driver_destroy(); audio_driver_destroy(); input_driver_destroy(); diff --git a/dynamic.c b/dynamic.c index 8c2b61f14e..8b6f9b4aec 100644 --- a/dynamic.c +++ b/dynamic.c @@ -353,7 +353,7 @@ static bool load_dynamic_core(void) path_get(RARCH_PATH_CORE)); RARCH_ERR("Error(s): %s\n", dylib_error()); - runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return false; } @@ -1242,7 +1242,7 @@ bool rarch_environment_cb(unsigned cmd, void *data) { const struct retro_message *msg = (const struct retro_message*)data; RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); - runloop_msg_queue_push(msg->msg, 3, msg->frames, true); + runloop_msg_queue_push(msg->msg, 3, msg->frames, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); break; } diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index e302d5e6ac..f9314f765c 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -70,6 +70,9 @@ #ifdef HAVE_MENU #include "../../menu/menu_driver.h" +#ifdef HAVE_MENU_WIDGETS +#include "../../menu/widgets/menu_widgets.h" +#endif #endif #ifndef GL_UNSIGNED_INT_8_8_8_8_REV @@ -2721,6 +2724,10 @@ static bool gl2_frame(void *data, const void *frame, #endif } } + +#ifdef HAVE_MENU_WIDGETS + menu_widgets_frame(video_info); +#endif #endif if (!string_is_empty(msg)) @@ -3546,6 +3553,7 @@ static void *gl2_init(const video_info_t *video, } gl2_context_bind_hw_render(gl, true); + return gl; error: @@ -4140,6 +4148,14 @@ static void gl2_get_poke_interface(void *data, *iface = &gl2_poke_interface; } +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +static bool gl2_menu_widgets_enabled(void *data) +{ + (void)data; + return true; +} +#endif + video_driver_t video_gl2 = { gl2_init, gl2_frame, @@ -4171,4 +4187,7 @@ video_driver_t video_gl2 = { #endif gl2_get_poke_interface, gl2_wrap_type_to_enum, +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + gl2_menu_widgets_enabled +#endif }; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 8bd402afce..fff35f6fcb 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -33,6 +33,7 @@ #include "../audio/audio_driver.h" #include "../menu/menu_shader.h" +#include "../menu/menu_animation.h" #ifdef HAVE_CONFIG_H #include "../config.h" @@ -47,6 +48,9 @@ #ifdef HAVE_MENU #include "../menu/menu_driver.h" #include "../menu/menu_setting.h" +#ifdef HAVE_MENU_WIDGETS +#include "../menu/widgets/menu_widgets.h" +#endif #endif #include "video_thread_wrapper.h" @@ -852,7 +856,9 @@ static void video_driver_free_internal(void) && video_driver_data && current_video && current_video->free ) - current_video->free(video_driver_data); + { + current_video->free(video_driver_data); + } video_driver_pixel_converter_free(); video_driver_filter_free(); @@ -1278,7 +1284,7 @@ void video_monitor_set_refresh_rate(float hz) snprintf(msg, sizeof(msg), "Setting refresh rate to: %.3f Hz.", hz); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); configuration_set_float(settings, @@ -2647,7 +2653,10 @@ void video_driver_frame(const void *data, unsigned width, /* Display the FPS, with a higher priority. */ if (video_info.fps_show || video_info.framecount_show) - runloop_msg_queue_push(video_info.fps_text, 2, 1, true); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_set_fps_text(video_info.fps_text)) +#endif + runloop_msg_queue_push(video_info.fps_text, 2, 1, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* trigger set resolution*/ if (video_info.crt_switch_resolution) @@ -3566,3 +3575,11 @@ float video_driver_get_refresh_rate(void) return 0.0f; } + +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +bool video_driver_has_widgets(void) +{ + return current_video && current_video->menu_widgets_enabled + && current_video->menu_widgets_enabled(video_driver_data); +} +#endif \ No newline at end of file diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 370e58d8a6..6e745f9c8a 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -807,6 +807,12 @@ typedef struct video_driver #endif void (*poke_interface)(void *data, const video_poke_interface_t **iface); unsigned (*wrap_type_to_enum)(enum gfx_wrap_type type); + +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + /* if set to true, will use menu widgets when applicable + * if set to false, will use OSD as a fallback */ + bool (*menu_widgets_enabled)(void *data); +#endif } video_driver_t; extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END]; @@ -876,6 +882,10 @@ bool video_driver_get_viewport_info(struct video_viewport *viewport); void video_driver_set_title_buf(void); void video_driver_monitor_adjust_system_rates(void); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +bool video_driver_has_widgets(void); +#endif + /** * video_driver_find_handle: * @index : index of driver to get handle to. diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index 1093deae0a..c04a8b7d57 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -1282,6 +1282,18 @@ static void video_thread_get_poke_interface( *iface = NULL; } +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +static bool video_thread_wrapper_menu_widgets_enabled(void *data) +{ + thread_video_t *thr = (thread_video_t*)data; + + if (thr && thr->driver) + return thr->driver->menu_widgets_enabled(thr->driver_data); + + return false; +} +#endif + static const video_driver_t video_thread = { video_thread_init_never_call, /* Should never be called directly. */ video_thread_frame, @@ -1302,6 +1314,10 @@ static const video_driver_t video_thread = { video_thread_get_overlay_interface, /* get_overlay_interface */ #endif video_thread_get_poke_interface, + NULL, +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + video_thread_wrapper_menu_widgets_enabled +#endif }; static void video_thread_set_callbacks( diff --git a/griffin/griffin.c b/griffin/griffin.c index d9e08c34dd..38ab18dcc3 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1196,6 +1196,7 @@ MENU #include "../menu/widgets/menu_dialog.c" #include "../menu/widgets/menu_input_dialog.c" #include "../menu/widgets/menu_input_bind_dialog.c" +#include "../menu/widgets/menu_widgets.c" #include "../menu/widgets/menu_osk.c" #include "../menu/cbs/menu_cbs_ok.c" #include "../menu/cbs/menu_cbs_cancel.c" diff --git a/input/input_overlay.c b/input/input_overlay.c index fcf39cff5b..645fd806f9 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -34,6 +34,8 @@ #include "../gfx/video_driver.h" #include "input_overlay.h" +#include + #define OVERLAY_GET_KEY(state, key) (((state)->keys[(key) / 32] >> ((key) % 32)) & 1) #define OVERLAY_SET_KEY(state, key) (state)->keys[(key) / 32] |= 1 << ((key) % 32) @@ -595,7 +597,7 @@ void input_overlay_free(input_overlay_t *ol) } /* task_data = overlay_task_data_t* */ -void input_overlay_loaded(void *task_data, void *user_data, const char *err) +void input_overlay_loaded(retro_task_t *task, void *task_data, void *user_data, const char *err) { size_t i; overlay_task_data_t *data = (overlay_task_data_t*)task_data; diff --git a/input/input_overlay.h b/input/input_overlay.h index ed70af4cd6..907612dc5f 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "input_driver.h" @@ -256,7 +257,7 @@ bool input_overlay_key_pressed(input_overlay_t *ol, unsigned key); bool input_overlay_is_alive(input_overlay_t *ol); -void input_overlay_loaded(void *task_data, void *user_data, const char *err); +void input_overlay_loaded(retro_task_t *task, void *task_data, void *user_data, const char *err); void input_overlay_set_visibility(int overlay_idx,enum overlay_visibility vis); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index d73af9ee08..6e41fa8ae8 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4702,6 +4702,10 @@ MSG_HASH( MSG_TAKING_SCREENSHOT, "Taking screenshot." ) +MSG_HASH( + MSG_SCREENSHOT_SAVED, + "Screenshot saved" + ) MSG_HASH( MSG_TO, "to" diff --git a/libretro-common/include/lists/file_list.h b/libretro-common/include/lists/file_list.h index 587967d514..1c18bf226b 100644 --- a/libretro-common/include/lists/file_list.h +++ b/libretro-common/include/lists/file_list.h @@ -91,6 +91,12 @@ bool file_list_prepend(file_list_t *list, unsigned type, size_t directory_ptr, size_t entry_idx); +bool file_list_insert(file_list_t *list, + const char *path, const char *label, + unsigned type, size_t directory_ptr, + size_t entry_idx, + size_t idx); + void file_list_pop(file_list_t *list, size_t *directory_ptr); void file_list_clear(file_list_t *list); diff --git a/libretro-common/include/queues/message_queue.h b/libretro-common/include/queues/message_queue.h index 760ba279d8..43688369d0 100644 --- a/libretro-common/include/queues/message_queue.h +++ b/libretro-common/include/queues/message_queue.h @@ -29,6 +29,19 @@ RETRO_BEGIN_DECLS +enum message_queue_icon +{ + MESSAGE_QUEUE_ICON_DEFAULT = 0 /* default icon is tied to category */ +}; + +enum message_queue_category +{ + MESSAGE_QUEUE_CATEGORY_INFO = 0, + MESSAGE_QUEUE_CATEGORY_ERROR, + MESSAGE_QUEUE_CATEGORY_WARNING, + MESSAGE_QUEUE_CATEGORY_SUCCESS +}; + typedef struct msg_queue msg_queue_t; /** @@ -54,7 +67,9 @@ msg_queue_t *msg_queue_new(size_t size); * Push a new message onto the queue. **/ void msg_queue_push(msg_queue_t *queue, const char *msg, - unsigned prio, unsigned duration); + unsigned prio, unsigned duration, + char *title, + enum message_queue_icon icon, enum message_queue_category category); /** * msg_queue_pull: diff --git a/libretro-common/include/queues/task_queue.h b/libretro-common/include/queues/task_queue.h index c0965ecda5..aa7e8547ab 100644 --- a/libretro-common/include/queues/task_queue.h +++ b/libretro-common/include/queues/task_queue.h @@ -43,15 +43,16 @@ enum task_type }; typedef struct retro_task retro_task_t; -typedef void (*retro_task_callback_t)(void *task_data, - void *user_data, const char *error); +typedef void (*retro_task_callback_t)(retro_task_t *task, + void *task_data, void *user_data, + const char *error); typedef void (*retro_task_handler_t)(retro_task_t *task); typedef bool (*retro_task_finder_t)(retro_task_t *task, void *userdata); -typedef void (*retro_task_queue_msg_t)(const char *msg, +typedef void (*retro_task_queue_msg_t)(retro_task_t *task, const char *msg, unsigned prio, unsigned duration, bool flush); typedef bool (*retro_task_retriever_t)(retro_task_t *task, void *data); @@ -109,6 +110,13 @@ struct retro_task enum task_type type; + /* task identifier */ + uint32_t ident; + + /* frontend userdata + * (e.g. associate a sticky notification to a task) */ + void *frontend_userdata; + /* don't touch this. */ retro_task_t *next; }; @@ -231,6 +239,9 @@ void task_queue_deinit(void); * This must only be called from the main thread. */ void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push); +/* Allocs and inits a new retro_task_t */ +retro_task_t *task_init(); + RETRO_END_DECLS #endif diff --git a/libretro-common/lists/file_list.c b/libretro-common/lists/file_list.c index dcf03d4de6..dd0b9e1549 100644 --- a/libretro-common/lists/file_list.c +++ b/libretro-common/lists/file_list.c @@ -85,12 +85,25 @@ bool file_list_prepend(file_list_t *list, unsigned type, size_t directory_ptr, size_t entry_idx) { - unsigned i; + return file_list_insert(list, path, + label, type, + directory_ptr, entry_idx, + 0 + ); +} + +bool file_list_insert(file_list_t *list, + const char *path, const char *label, + unsigned type, size_t directory_ptr, + size_t entry_idx, + size_t idx) +{ + int i; if (!file_list_expand_if_needed(list)) return false; - for (i = (unsigned)list->size; i > 0; i--) + for (i = (unsigned)list->size; i > idx; i--) { struct item_file *copy = (struct item_file*) calloc(1, sizeof(struct item_file)); @@ -103,7 +116,7 @@ bool file_list_prepend(file_list_t *list, free(copy); } - file_list_add(list, 0, path, label, type, + file_list_add(list, idx, path, label, type, directory_ptr, entry_idx); return true; diff --git a/libretro-common/queues/message_queue.c b/libretro-common/queues/message_queue.c index f5af162f2d..2e036496ed 100644 --- a/libretro-common/queues/message_queue.c +++ b/libretro-common/queues/message_queue.c @@ -33,6 +33,10 @@ struct queue_elem unsigned duration; unsigned prio; char *msg; + + char *title; + enum message_queue_icon icon; + enum message_queue_category category; }; struct msg_queue @@ -105,7 +109,9 @@ void msg_queue_free(msg_queue_t *queue) * Push a new message onto the queue. **/ void msg_queue_push(msg_queue_t *queue, const char *msg, - unsigned prio, unsigned duration) + unsigned prio, unsigned duration, + char *title, + enum message_queue_icon icon, enum message_queue_category category) { size_t tmp_ptr = 0; struct queue_elem *new_elem = NULL; diff --git a/libretro-common/queues/task_queue.c b/libretro-common/queues/task_queue.c index 7ca188eefc..3071104307 100644 --- a/libretro-common/queues/task_queue.c +++ b/libretro-common/queues/task_queue.c @@ -62,6 +62,8 @@ static task_queue_t tasks_finished = {NULL, NULL}; static struct retro_task_impl *impl_current = NULL; static bool task_threaded_enable = false; +static uint32_t task_count = 0; + static void task_queue_msg_push(retro_task_t *task, unsigned prio, unsigned duration, bool flush, const char *fmt, ...) @@ -76,7 +78,7 @@ static void task_queue_msg_push(retro_task_t *task, va_end(ap); if (impl_current->msg_push) - impl_current->msg_push(buf, prio, duration, flush); + impl_current->msg_push(task, buf, prio, duration, flush); } static void task_queue_push_progress(retro_task_t *task) @@ -138,7 +140,7 @@ static void retro_task_internal_gather(void) task_queue_push_progress(task); if (task->callback) - task->callback(task->task_data, task->user_data, task->error); + task->callback(task, task->task_data, task->user_data, task->error); if (task->cleanup) task->cleanup(task); @@ -820,3 +822,18 @@ char* task_get_title(retro_task_t *task) return title; } + +static uint32_t task_get_next_ident() +{ + return task_count++; +} + +retro_task_t *task_init() +{ + retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + + task->ident = task_get_next_ident(); + task->frontend_userdata = NULL; + + return task; +} \ No newline at end of file diff --git a/location/location_driver.c b/location/location_driver.c index 7a85cbdcab..ae2c32fdb6 100644 --- a/location/location_driver.c +++ b/location/location_driver.c @@ -143,7 +143,7 @@ bool driver_location_start(void) if (settings->bools.location_allow) return location_driver->start(location_data); - runloop_msg_queue_push("Location is explicitly disabled.\n", 1, 180, true); + runloop_msg_queue_push("Location is explicitly disabled.\n", 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return false; } diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c index 6169e71c7f..9dec2d8ac0 100644 --- a/managers/cheat_manager.c +++ b/managers/cheat_manager.c @@ -94,7 +94,7 @@ void cheat_manager_apply_cheats(void) if (cheat_manager_state.size > 0) { - runloop_msg_queue_push(msg_hash_to_str(MSG_APPLYING_CHEAT), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_APPLYING_CHEAT), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg_hash_to_str(MSG_APPLYING_CHEAT)); } @@ -574,7 +574,7 @@ void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx) (handle->cheats[handle_idx].desc!=NULL) ? (handle->cheats[handle_idx].desc) : (handle->cheats[handle_idx].code) ); - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); } @@ -782,7 +782,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, bool wraparound) meminfo.id = RETRO_MEMORY_SYSTEM_RAM; if (!core_get_memory(&meminfo)) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -820,7 +820,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, bool wraparound) cheat_manager_state.prev_memory_buf = (uint8_t*) calloc(cheat_manager_state.total_memory_size, sizeof(uint8_t)); if (!cheat_manager_state.prev_memory_buf) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -835,7 +835,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, bool wraparound) { free(cheat_manager_state.prev_memory_buf); cheat_manager_state.prev_memory_buf = NULL; - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -854,7 +854,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, bool wraparound) cheat_manager_state.memory_initialized = true; - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_SUCCESS), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #ifdef HAVE_MENU if (!wraparound) @@ -977,7 +977,7 @@ int cheat_manager_search(enum cheat_search_type search_type) if (cheat_manager_state.num_memory_buffers == 0) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -1084,7 +1084,7 @@ int cheat_manager_search(enum cheat_search_type search_type) snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_CHEAT_SEARCH_FOUND_MATCHES), cheat_manager_state.num_matches); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #ifdef HAVE_MENU menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); @@ -1126,7 +1126,7 @@ int cheat_manager_add_matches(const char *path, if (cheat_manager_state.num_matches + cheat_manager_state.size > 100) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } cheat_manager_setup_search_meta(cheat_manager_state.search_bit_size, &bytes_per_item, &mask, &bits); @@ -1164,7 +1164,7 @@ int cheat_manager_add_matches(const char *path, if (!cheat_manager_add_new_code(cheat_manager_state.search_bit_size, idx, (mask << (byte_part*bits)), cheat_manager_state.big_endian, curr_val)) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } num_added++; @@ -1178,7 +1178,7 @@ int cheat_manager_add_matches(const char *path, if (!cheat_manager_add_new_code(cheat_manager_state.search_bit_size, idx, 0xFF, cheat_manager_state.big_endian, curr_val)) { - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } num_added++; @@ -1191,7 +1191,7 @@ int cheat_manager_add_matches(const char *path, snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS), cheat_manager_state.num_matches); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #ifdef HAVE_MENU menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); @@ -1561,9 +1561,9 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig case CHEAT_MATCH_ACTION_TYPE_COPY : if (!cheat_manager_add_new_code(cheat_manager_state.search_bit_size, idx, (mask << (byte_part*bits)), cheat_manager_state.big_endian, curr_val)) - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); else - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; case CHEAT_MATCH_ACTION_TYPE_DELETE : if (bits < 8) @@ -1573,7 +1573,7 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig memset(cheat_manager_state.matches+idx,0,bytes_per_item); if (cheat_manager_state.num_matches > 0) cheat_manager_state.num_matches--; - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } return; @@ -1601,9 +1601,9 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig case CHEAT_MATCH_ACTION_TYPE_COPY : if (!cheat_manager_add_new_code(cheat_manager_state.search_bit_size, idx, 0xFF, cheat_manager_state.big_endian, curr_val)) - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); else - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; case CHEAT_MATCH_ACTION_TYPE_DELETE : if (bits < 8) @@ -1613,7 +1613,7 @@ void cheat_manager_match_action(enum cheat_match_action_type match_action, unsig memset(cheat_manager_state.matches+idx,0,bytes_per_item); if (cheat_manager_state.num_matches > 0) cheat_manager_state.num_matches--; - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } } diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 69584cef43..ed46de3e66 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1082,7 +1082,7 @@ static bool menu_content_find_first_core(menu_content_ctx_defer_info_t *def_info } #ifdef HAVE_LIBRETRODB -void handle_dbscan_finished(void *task_data, void *user_data, const char *err); +void handle_dbscan_finished(retro_task_t *task, void *task_data, void *user_data, const char *err); #endif static void content_add_to_playlist(const char *path) @@ -1411,7 +1411,7 @@ static int generic_action_ok(const char *path, if(!file_copy(action_path, destination_path, message, sizeof(message))) { runloop_msg_queue_push(msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_ERROR), 1, 100, true); + MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_ERROR), 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("[sideload] %s: %s\n", msg_hash_to_str( MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_ERROR), message); RARCH_LOG(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_ERROR)); @@ -1419,7 +1419,7 @@ static int generic_action_ok(const char *path, else { runloop_msg_queue_push(msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_SUCCESS), 1, 100, true); + MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_SUCCESS), 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("[sideload] %s\n", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_SUCCESS)); } } @@ -1788,7 +1788,8 @@ static int action_ok_playlist_entry_collection(const char *path, { runloop_msg_queue_push( "File could not be loaded from playlist.\n", - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); if (playlist_initialized) playlist_free(tmp_playlist); return menu_cbs_exit(); @@ -1863,7 +1864,8 @@ static int action_ok_playlist_entry(const char *path, { runloop_msg_queue_push( "File could not be loaded from playlist.\n", - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return menu_cbs_exit(); } @@ -1938,7 +1940,7 @@ static int action_ok_playlist_entry_start_content(const char *path, if (!menu_content_playlist_load(playlist, selection_ptr)) { - runloop_msg_queue_push("File could not be loaded from playlist.\n", 1, 100, true); + runloop_msg_queue_push("File could not be loaded from playlist.\n", 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); goto error; } @@ -2240,13 +2242,15 @@ static void menu_input_st_string_cb_disable_kiosk_mode(void *userdata, runloop_msg_queue_push( msg_hash_to_str(MSG_INPUT_KIOSK_MODE_PASSWORD_OK), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { runloop_msg_queue_push( msg_hash_to_str(MSG_INPUT_KIOSK_MODE_PASSWORD_NOK), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -2267,13 +2271,15 @@ static void menu_input_st_string_cb_enable_settings(void *userdata, runloop_msg_queue_push( msg_hash_to_str(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { runloop_msg_queue_push( msg_hash_to_str(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -2303,11 +2309,13 @@ static void menu_input_st_string_cb_save_preset(void *userdata, if(ret) runloop_msg_queue_push( msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); else runloop_msg_queue_push( msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } menu_input_dialog_end(); @@ -2435,11 +2443,13 @@ static int generic_action_ok_shader_preset_save(const char *path, 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); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); else runloop_msg_queue_push( msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -2525,12 +2535,14 @@ static int generic_action_ok_remap_file_operation(const char *path, runloop_msg_queue_push( msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else runloop_msg_queue_push( msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { @@ -2559,12 +2571,14 @@ static int generic_action_ok_remap_file_operation(const char *path, runloop_msg_queue_push( msg_hash_to_str(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else runloop_msg_queue_push( msg_hash_to_str(MSG_ERROR_REMOVING_REMAP_FILE), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return 0; } @@ -2700,7 +2714,7 @@ static int action_ok_set_switch_cpu_profile(const char *path, snprintf(command, sizeof(command), "Current Clock set to %i", profile_clock); #endif - runloop_msg_queue_push(command, 1, 90, true); + runloop_msg_queue_push(command, 1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return menu_cbs_exit(); } @@ -2721,7 +2735,7 @@ static int action_ok_set_switch_gpu_profile(const char *path, snprintf(command, sizeof(command), "Current profile set to %s", profile_name); - runloop_msg_queue_push(command, 1, 90, true); + runloop_msg_queue_push(command, 1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return menu_cbs_exit(); } @@ -2739,7 +2753,7 @@ static int action_ok_set_switch_backlight(const char *path, snprintf(command, sizeof(command), "Brightness set to %d%%", brightness); - runloop_msg_queue_push(command, 1, 90, true); + runloop_msg_queue_push(command, 1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -2919,7 +2933,7 @@ static int action_ok_cheat_add_top(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_TOP_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -2940,7 +2954,7 @@ static int action_ok_cheat_add_bottom(const char *path, msg_hash_to_str(MSG_CHEAT_ADD_BOTTOM_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -2952,7 +2966,7 @@ static int action_ok_cheat_delete_all(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_DELETE_ALL_INSTRUCTIONS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 240, true); + runloop_msg_queue_push(msg, 1, 240, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -2984,7 +2998,7 @@ static int action_ok_cheat_add_new_after(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_AFTER_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -3020,7 +3034,7 @@ static int action_ok_cheat_add_new_before(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_BEFORE_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -3057,7 +3071,7 @@ static int action_ok_cheat_copy_before(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_COPY_BEFORE_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -3094,7 +3108,7 @@ static int action_ok_cheat_copy_after(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_COPY_AFTER_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0 ; } @@ -3133,7 +3147,7 @@ static int action_ok_cheat_delete(const char *path, strlcpy(msg, msg_hash_to_str(MSG_CHEAT_DELETE_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); new_selection_ptr = menu_navigation_get_selection(); menu_entries_pop_stack(&new_selection_ptr, 0, 1); @@ -3245,7 +3259,7 @@ static int action_ok_undo_save_state(const char *path, #ifdef HAVE_NETWORKING #ifdef HAVE_ZLIB -static void cb_decompressed(void *task_data, void *user_data, const char *err) +static void cb_decompressed(retro_task_t *task, void *task_data, void *user_data, const char *err) { decompress_task_data_t *dec = (decompress_task_data_t*)task_data; @@ -3378,7 +3392,7 @@ default_action_ok_list(action_ok_core_updater_list, MENU_ENUM_LABEL_CB_CORE_UPDA default_action_ok_list(action_ok_thumbnails_updater_list, MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_LIST) default_action_ok_list(action_ok_lakka_list, MENU_ENUM_LABEL_CB_LAKKA_LIST) -static void cb_generic_dir_download(void *task_data, +static void cb_generic_dir_download(retro_task_t *task, void *task_data, void *user_data, const char *err) { file_transfer_t *transf = (file_transfer_t*)user_data; @@ -3392,7 +3406,7 @@ static void cb_generic_dir_download(void *task_data, } /* expects http_transfer_t*, file_transfer_t* */ -void cb_generic_download(void *task_data, +void cb_generic_download(retro_task_t *task, void *task_data, void *user_data, const char *err) { char output_path[PATH_MAX_LENGTH]; @@ -3527,10 +3541,14 @@ void cb_generic_download(void *task_data, if (path_is_compressed_file(output_path)) { + void *frontend_userdata = task->frontend_userdata; + task->frontend_userdata = NULL; + if (!task_push_decompress(output_path, dir_path, NULL, NULL, NULL, cb_decompressed, (void*)(uintptr_t) - msg_hash_calculate(msg_hash_to_str(transf->enum_idx)))) + msg_hash_calculate(msg_hash_to_str(transf->enum_idx)), + frontend_userdata)) { err = msg_hash_to_str(MSG_DECOMPRESSION_FAILED); goto finish; @@ -3709,7 +3727,8 @@ static int action_ok_option_create(const char *path, { runloop_msg_queue_push( msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -3726,7 +3745,8 @@ static int action_ok_option_create(const char *path, { runloop_msg_queue_push( msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY), - 1, 100, true); + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); path_set(RARCH_PATH_CORE_OPTIONS, game_path); } config_file_free(conf); @@ -4258,7 +4278,7 @@ void netplay_refresh_rooms_menu(file_list_t *list) #define INET6_ADDRSTRLEN 46 #endif -static void netplay_refresh_rooms_cb(void *task_data, void *user_data, const char *err) +static void netplay_refresh_rooms_cb(retro_task_t *task, void *task_data, void *user_data, const char *err) { char *new_data = NULL; const char *path = NULL; @@ -4385,7 +4405,7 @@ finish: } -static void netplay_lan_scan_callback(void *task_data, +static void netplay_lan_scan_callback(retro_task_t *task, void *task_data, void *user_data, const char *error) { struct netplay_host_list *netplay_hosts = NULL; @@ -4876,7 +4896,7 @@ static int action_ok_video_resolution(const char *path, snprintf(msg, sizeof(msg), "Applying: %dx%d\n START to reset", width, height); - runloop_msg_queue_push(msg, 1, 100, true); + runloop_msg_queue_push(msg, 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } #else generic_action_ok_displaylist_push( @@ -4908,7 +4928,8 @@ static int action_ok_netplay_enable_host(const char *path, { runloop_msg_queue_push( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED), - 1, 480, true); + 1, 480, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } @@ -4938,7 +4959,8 @@ static void action_ok_netplay_enable_client_hostname_cb( (void*)tmp_hostname); runloop_msg_queue_push( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED), - 1, 480, true); + 1, 480, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } else { diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c index 35661aef08..40a258c712 100644 --- a/menu/cbs/menu_cbs_right.c +++ b/menu/cbs/menu_cbs_right.c @@ -284,7 +284,7 @@ static int action_right_cheat_delete_all(unsigned type, const char *label, msg_hash_to_str(MSG_CHEAT_DELETE_ALL_SUCCESS), sizeof(msg)); msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return 0; diff --git a/menu/cbs/menu_cbs_scan.c b/menu/cbs/menu_cbs_scan.c index 6f1490a90e..059778ed96 100644 --- a/menu/cbs/menu_cbs_scan.c +++ b/menu/cbs/menu_cbs_scan.c @@ -37,7 +37,7 @@ #endif #ifdef HAVE_LIBRETRODB -void handle_dbscan_finished(void *task_data, void *user_data, const char *err) +void handle_dbscan_finished(retro_task_t *task, void *task_data, void *user_data, const char *err) { menu_ctx_environment_t menu_environ; menu_environ.type = MENU_ENVIRON_RESET_HORIZONTAL_LIST; diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index 1867101741..eb11a882f8 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -274,7 +274,7 @@ static int action_start_video_resolution(unsigned type, const char *label) video_driver_set_video_mode(width, height, true); strlcpy(msg, "Resetting to: DEFAULT", sizeof(msg)); - runloop_msg_queue_push(msg, 1, 100, true); + runloop_msg_queue_push(msg, 1, 100, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return 0; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 2319275737..534292d607 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -308,7 +308,7 @@ static void materialui_context_reset_textures(materialui_handle_t *mui) APPLICATION_SPECIAL_DIRECTORY_ASSETS_MATERIALUI_ICONS); for (i = 0; i < MUI_TEXTURE_LAST; i++) - menu_display_reset_textures_list(materialui_texture_path(i), iconpath, &mui->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); + menu_display_reset_textures_list(materialui_texture_path(i), iconpath, &mui->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL); free(iconpath); } @@ -641,7 +641,6 @@ static void materialui_compute_entries_box(materialui_handle_t* mui, int width) with acceleration */ static void materialui_render(void *data, bool is_idle) { - menu_animation_ctx_delta_t delta; unsigned bottom, width, height, header_height; size_t i = 0; materialui_handle_t *mui = (materialui_handle_t*)data; @@ -660,11 +659,6 @@ static void materialui_render(void *data, bool is_idle) mui->need_compute = false; } - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - menu_animation_update(delta.ideal); - menu_display_set_width(width); menu_display_set_height(height); header_height = menu_display_get_header_height(); @@ -1525,7 +1519,7 @@ static void materialui_frame(void *data, video_frame_info_t *video_info) ticker.s = title_buf; ticker.len = ticker_limit; - ticker.idx = mui->frame_count / 100; + ticker.idx = menu_animation_get_ticker_time() / 5.0f; ticker.str = title; ticker.selected = true; @@ -1547,7 +1541,7 @@ static void materialui_frame(void *data, video_frame_info_t *video_info) ticker.s = title_buf_msg_tmp; ticker.len = ticker_limit; - ticker.idx = mui->frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.str = title_buf_msg; ticker.selected = true; @@ -1801,7 +1795,7 @@ static void materialui_navigation_set(void *data, bool scroll) if (!mui || !scroll) return; - entry.duration = 10; + entry.duration = 166; entry.target_value = scroll_pos; entry.subject = &mui->scroll_y; entry.easing_enum = EASING_IN_OUT_QUAD; diff --git a/menu/drivers/menu_generic.c b/menu/drivers/menu_generic.c index f263ea16ad..bb9745621d 100644 --- a/menu/drivers/menu_generic.c +++ b/menu/drivers/menu_generic.c @@ -29,6 +29,8 @@ #include "../../content.h" #include "../../retroarch.h" +#include "../../tasks/task_content.h" + static enum action_iterate_type action_iterate_type(const char *label) { if (string_is_equal(label, "info_screen")) @@ -76,6 +78,16 @@ int generic_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_action a if (!menu) return 0; +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (task_load_content_is_pending()) + { + if (task_load_content_should_resume()) + action = MENU_ACTION_OK; + else + return 0; + } +#endif + menu_entries_get_last_stack(NULL, &label, &file_type, &enum_idx, NULL); menu->menu_state_msg[0] = '\0'; diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index a214139139..258220e7c1 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -122,6 +122,9 @@ static void *ozone_init(void **userdata, bool video_is_threaded) settings_t *settings = config_get_ptr(); menu_handle_t *menu = (menu_handle_t*)calloc(1, sizeof(*menu)); + char xmb_path[PATH_MAX_LENGTH]; + char monochrome_path[PATH_MAX_LENGTH]; + if (!menu) return NULL; @@ -232,14 +235,6 @@ static void *ozone_init(void **userdata, bool video_is_threaded) sizeof(ozone->png_path) ); - /* Icons path */ - fill_pathname_join( - ozone->icons_path, - ozone->png_path, - "icons", - sizeof(ozone->icons_path) - ); - /* Sidebar path */ fill_pathname_join( ozone->tab_path, @@ -248,6 +243,29 @@ static void *ozone_init(void **userdata, bool video_is_threaded) sizeof(ozone->tab_path) ); + /* XMB monochrome */ + fill_pathname_join( + xmb_path, + settings->paths.directory_assets, + "xmb", + sizeof(xmb_path) + ); + + fill_pathname_join( + monochrome_path, + xmb_path, + "monochrome", + sizeof(monochrome_path) + ); + + /* Icons path */ + fill_pathname_join( + ozone->icons_path, + monochrome_path, + "png", + sizeof(ozone->icons_path) + ); + last_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme; return menu; @@ -258,7 +276,14 @@ error: ozone_free_list_nodes(ozone->horizontal_list, false); file_list_free(ozone->horizontal_list); } - ozone->horizontal_list = NULL; + + if (ozone->selection_buf_old) + { + ozone_free_list_nodes(ozone->selection_buf_old, false); + file_list_free(ozone->selection_buf_old); + } + ozone->selection_buf_old = NULL; + ozone->horizontal_list = NULL; if (menu) free(menu); @@ -293,6 +318,9 @@ static void ozone_free(void *data) file_list_free(ozone->horizontal_list); } + ozone->horizontal_list = NULL; + ozone->selection_buf_old = NULL; + if (!string_is_empty(ozone->pending_message)) free(ozone->pending_message); } @@ -369,13 +397,13 @@ static void ozone_context_reset(void *data, bool is_threaded) fill_pathname_application_special(buf, sizeof(buf), APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS); - if (!menu_display_reset_textures_list(filename, buf, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + if (!menu_display_reset_textures_list(filename, buf, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename); } else { #endif - if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) { ozone->has_all_assets = false; RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename); @@ -392,7 +420,7 @@ static void ozone_context_reset(void *data, bool is_threaded) strlcpy(filename, OZONE_TAB_TEXTURES_FILES[i], sizeof(filename)); strlcat(filename, ".png", sizeof(filename)); - if (!menu_display_reset_textures_list(filename, ozone->tab_path, &ozone->tab_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + if (!menu_display_reset_textures_list(filename, ozone->tab_path, &ozone->tab_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) { ozone->has_all_assets = false; RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->tab_path, path_default_slash(), filename); @@ -405,11 +433,13 @@ static void ozone_context_reset(void *data, bool is_threaded) /* Icons textures init */ for (i = 0; i < OZONE_ENTRIES_ICONS_TEXTURE_LAST; i++) - if (!menu_display_reset_textures_list(ozone_entries_icon_texture_path(i), ozone->icons_path, &ozone->icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + { + if (!menu_display_reset_textures_list(ozone_entries_icon_texture_path(i), ozone->icons_path, &ozone->icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) { ozone->has_all_assets = false; RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->icons_path, path_default_slash(), ozone_entries_icon_texture_path(i)); } + } menu_display_allocate_white_texture(); @@ -434,8 +464,9 @@ static void ozone_context_reset(void *data, bool is_threaded) if (!ozone->has_all_assets) { RARCH_WARN("[OZONE] Assets missing\n"); - runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false); + runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } + ozone_restart_cursor_animation(ozone); } } @@ -901,7 +932,6 @@ static void ozone_compute_entries_position(ozone_handle_t *ozone) static void ozone_render(void *data, bool is_idle) { size_t i; - menu_animation_ctx_delta_t delta; unsigned end = (unsigned)menu_entries_get_size(); ozone_handle_t *ozone = (ozone_handle_t*)data; if (!data) @@ -915,11 +945,6 @@ static void ozone_render(void *data, bool is_idle) ozone->selection = menu_navigation_get_selection(); - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - menu_animation_update(delta.ideal); - /* TODO Handle pointer & mouse */ menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); @@ -946,7 +971,7 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i /* Title */ ticker.s = title; ticker.len = (video_info->width - 128 - 47 - 130) / ozone->title_font_glyph_width; - ticker.idx = ozone->frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.str = ozone->title; ticker.selected = true; @@ -1423,7 +1448,7 @@ static void ozone_populate_entries(void *data, const char *path, const char *lab ozone->fade_direction = new_depth <= ozone->depth; ozone->depth = new_depth; - ozone->is_playlist = ozone_is_playlist(ozone); + ozone->is_playlist = ozone_is_playlist(ozone, true); if (ozone->categories_selection_ptr == ozone->categories_active_idx_old) { @@ -1441,14 +1466,16 @@ static int ozone_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_act ozone_handle_t *ozone = (ozone_handle_t*) userdata; unsigned horizontal_list_size = 0; + if (!ozone) + { + return generic_menu_iterate(menu, userdata, action); + } + if (ozone->horizontal_list) horizontal_list_size = ozone->horizontal_list->size; ozone->messagebox_state = false || menu_input_dialog_get_display_kb(); - if (!ozone) - return generic_menu_iterate(menu, userdata, action); - selection_buf = menu_entries_get_selection_buf_ptr(0); tag = (uintptr_t)selection_buf; new_action = action; @@ -1518,7 +1545,6 @@ static int ozone_menu_iterate(menu_handle_t *menu, void *userdata, enum menu_act new_action = MENU_ACTION_NOOP; break; } - break; case MENU_ACTION_CANCEL: if (ozone->cursor_in_sidebar) @@ -1822,6 +1848,28 @@ static int ozone_list_bind_init(menu_file_list_cbs_t *cbs, return -1; } +#ifdef HAVE_MENU_WIDGETS +static bool ozone_get_load_content_animation_data(void *userdata, menu_texture_item *icon, char **playlist_name) +{ + ozone_handle_t *ozone = (ozone_handle_t*) userdata; + + if (ozone->categories_selection_ptr > ozone->system_tab_end) + { + ozone_node_t *node = file_list_get_userdata_at_offset(ozone->horizontal_list, ozone->categories_selection_ptr - ozone->system_tab_end-1); + + *icon = node->icon; + *playlist_name = node->console_name; + } + else + { + *icon = ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_QUICKMENU]; + *playlist_name = "RetroArch"; + } + + return true; +} +#endif + menu_ctx_driver_t menu_ctx_ozone = { NULL, /* set_texture */ ozone_messagebox, @@ -1863,5 +1911,10 @@ menu_ctx_driver_t menu_ctx_ozone = { NULL, /* set_thumbnail_content */ menu_display_osk_ptr_at_pos, NULL, /* update_savestate_thumbnail_path */ - NULL /* update_savestate_thumbnail_image */ + NULL, /* update_savestate_thumbnail_image */ + NULL, + NULL, +#ifdef HAVE_MENU_WIDGETS + ozone_get_load_content_animation_data +#endif }; diff --git a/menu/drivers/ozone/ozone.h b/menu/drivers/ozone/ozone.h index cba78cdf90..86e25799f1 100644 --- a/menu/drivers/ozone/ozone.h +++ b/menu/drivers/ozone/ozone.h @@ -33,9 +33,9 @@ typedef struct ozone_handle ozone_handle_t; #define FONT_SIZE_ENTRIES_SUBLABEL 18 #define FONT_SIZE_SIDEBAR 24 -#define ANIMATION_PUSH_ENTRY_DURATION 10 -#define ANIMATION_CURSOR_DURATION 8 -#define ANIMATION_CURSOR_PULSE 30 +#define ANIMATION_PUSH_ENTRY_DURATION 166 +#define ANIMATION_CURSOR_DURATION 133 +#define ANIMATION_CURSOR_PULSE 500 #define ENTRIES_START_Y 127 @@ -205,6 +205,6 @@ size_t ozone_list_get_size(void *data, enum menu_list_type type); void ozone_free_list_nodes(file_list_t *list, bool actiondata); -bool ozone_is_playlist(ozone_handle_t *ozone); +bool ozone_is_playlist(ozone_handle_t *ozone, bool depth); #endif diff --git a/menu/drivers/ozone/ozone_display.c b/menu/drivers/ozone/ozone_display.c index ca6eb2b950..c302cbe369 100644 --- a/menu/drivers/ozone/ozone_display.c +++ b/menu/drivers/ozone/ozone_display.c @@ -107,9 +107,6 @@ void ozone_draw_text( uint32_t color, bool draw_outside) { - if ((color & 0x000000FF) == 0) - return; - menu_display_draw_text(font, str, x, y, width, height, color, text_align, 1.0f, false, diff --git a/menu/drivers/ozone/ozone_entries.c b/menu/drivers/ozone/ozone_entries.c index 08e8b97c40..b1a3c45e0c 100644 --- a/menu/drivers/ozone/ozone_entries.c +++ b/menu/drivers/ozone/ozone_entries.c @@ -227,7 +227,7 @@ border_iterate: /* Prepare text */ entry_rich_label = menu_entry_get_rich_label(&entry); - ticker.idx = ozone->frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.s = rich_label; ticker.str = entry_rich_label; ticker.selected = entry_selected && !ozone->cursor_in_sidebar; @@ -295,7 +295,7 @@ border_iterate: ozone_draw_text(video_info, ozone, sublabel_str, x_offset + 470, y + FONT_SIZE_ENTRIES_SUBLABEL + 80 - 20 - 3 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_sublabel, COLOR_TEXT_ALPHA(ozone->theme->text_sublabel_rgba, alpha_uint32), false); /* Value */ - ticker.idx = ozone->frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.s = entry_value_ticker; ticker.str = entry_value; ticker.selected = entry_selected && !ozone->cursor_in_sidebar; diff --git a/menu/drivers/ozone/ozone_sidebar.c b/menu/drivers/ozone/ozone_sidebar.c index f29ef4afd5..fddaaaa9a8 100644 --- a/menu/drivers/ozone/ozone_sidebar.c +++ b/menu/drivers/ozone/ozone_sidebar.c @@ -206,10 +206,10 @@ void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info) goto console_iterate; /* Icon */ - ozone_draw_icon(video_info, 40, 40, node->icon, ozone->sidebar_offset + 41 + 10, y - 5 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); + ozone_draw_icon(video_info, 46, 46, node->icon, ozone->sidebar_offset + 41 + 10 - 3, y - 5 - 3 + ozone->animations.scroll_y_sidebar, video_info->width, video_info->height, 0, 1, (selected ? ozone->theme->text_selected : ozone->theme->entries_icon)); /* Text */ - ticker.idx = ozone->frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.len = 19; ticker.s = console_title; ticker.selected = selected; @@ -224,7 +224,6 @@ console_iterate: } menu_display_blend_end(video_info); - } font_driver_flush(video_info->width, video_info->height, ozone->fonts.sidebar, video_info); @@ -589,6 +588,9 @@ void ozone_context_reset_horizontal_list(ozone_handle_t *ozone) else chr = title_noext; + if (node->console_name) + free(node->console_name); + node->console_name = strdup(chr); free(sysname); @@ -623,7 +625,7 @@ void ozone_context_destroy_horizontal_list(ozone_handle_t *ozone) } } -bool ozone_is_playlist(ozone_handle_t *ozone) +bool ozone_is_playlist(ozone_handle_t *ozone, bool depth) { bool is_playlist; @@ -651,5 +653,8 @@ bool ozone_is_playlist(ozone_handle_t *ozone) break; } - return is_playlist && ozone->depth == 1; + if (depth) + return is_playlist && ozone->depth == 1; + + return is_playlist; } diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c index d131167d83..fdbef6e46c 100644 --- a/menu/drivers/ozone/ozone_texture.c +++ b/menu/drivers/ozone/ozone_texture.c @@ -760,7 +760,7 @@ bool ozone_reset_theme_textures(ozone_handle_t *ozone) strlcpy(filename, OZONE_THEME_TEXTURES_FILES[i], sizeof(filename)); strlcat(filename, ".png", sizeof(filename)); - if (!menu_display_reset_textures_list(filename, theme_path, &theme->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + if (!menu_display_reset_textures_list(filename, theme_path, &theme->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) result = false; } } diff --git a/menu/drivers/ozone/ozone_theme.h b/menu/drivers/ozone/ozone_theme.h index 686fb892b9..71091d6cd6 100644 --- a/menu/drivers/ozone/ozone_theme.h +++ b/menu/drivers/ozone/ozone_theme.h @@ -20,21 +20,12 @@ #include "ozone.h" #include "ozone_texture.h" +#ifdef HAVE_MENU_WIDGETS +#include "../../widgets/menu_widgets.h" +#endif + #include "../../../retroarch.h" -#define HEX_R(hex) ((hex >> 16) & 0xFF) * (1.0f / 255.0f) -#define HEX_G(hex) ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f) -#define HEX_B(hex) ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f) - -#define COLOR_HEX_TO_FLOAT(hex, alpha) { \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ - HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha \ -} - -#define COLOR_TEXT_ALPHA(color, alpha) (color & 0xFFFFFF00) | alpha - static float ozone_pure_white[16] = { 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 7dbbd44ea5..4b66a48b97 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -1585,7 +1585,7 @@ static void rgui_render(void *data, bool is_idle) /* Format thumbnail title */ ticker.s = thumbnail_title_buf; ticker.len = RGUI_TERM_WIDTH(fb_width) - 10; - ticker.idx = frame_count / RGUI_TERM_START_X(fb_width); + ticker.idx = menu_animation_get_ticker_time(); ticker.str = rgui->thumbnail_content; ticker.selected = true; menu_animation_ticker(&ticker); @@ -1619,7 +1619,7 @@ static void rgui_render(void *data, bool is_idle) ticker.s = title_buf; ticker.len = RGUI_TERM_WIDTH(fb_width) - 10; - ticker.idx = frame_count / RGUI_TERM_START_X(fb_width); + ticker.idx = menu_animation_get_ticker_time(); ticker.str = title; ticker.selected = true; @@ -1709,7 +1709,7 @@ static void rgui_render(void *data, bool is_idle) ticker.s = entry_title_buf; ticker.len = RGUI_TERM_WIDTH(fb_width) - (entry_spacing + 1 + 2); - ticker.idx = frame_count / RGUI_TERM_START_X(fb_width); + ticker.idx = menu_animation_get_ticker_time(); ticker.str = entry_path; ticker.selected = entry_selected; diff --git a/menu/drivers/stripes.c b/menu/drivers/stripes.c index c91918b50f..a72a4db822 100644 --- a/menu/drivers/stripes.c +++ b/menu/drivers/stripes.c @@ -69,7 +69,7 @@ #define STRIPES_RIBBON_VERTICES 2*STRIPES_RIBBON_COLS*STRIPES_RIBBON_ROWS-2*STRIPES_RIBBON_COLS #ifndef STRIPES_DELAY -#define STRIPES_DELAY 10 +#define STRIPES_DELAY 166 #endif #define BATTERY_LEVEL_CHECK_INTERVAL (30 * 1000000) @@ -2450,7 +2450,7 @@ static int stripes_draw_item( ticker.s = tmp; ticker.len = ticker_limit; - ticker.idx = frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.str = ticker_str; ticker.selected = (i == current); @@ -2486,7 +2486,7 @@ static int stripes_draw_item( ticker.s = tmp; ticker.len = 35 * stripes_scale_mod[7]; - ticker.idx = frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.selected = (i == current); if (!string_is_empty(entry->value)) @@ -2654,7 +2654,6 @@ static void stripes_draw_items( static void stripes_render(void *data, bool is_idle) { size_t i; - menu_animation_ctx_delta_t delta; settings_t *settings = config_get_ptr(); stripes_handle_t *stripes = (stripes_handle_t*)data; unsigned end = (unsigned)menu_entries_get_size(); @@ -2664,11 +2663,6 @@ static void stripes_render(void *data, bool is_idle) if (!stripes) return; - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - menu_animation_update(delta.ideal); - if (pointer_enable || mouse_enable) { size_t selection = menu_navigation_get_selection(); @@ -3621,7 +3615,7 @@ static void stripes_context_reset_textures( unsigned i; for (i = 0; i < STRIPES_TEXTURE_LAST; i++) - menu_display_reset_textures_list(stripes_texture_path(i), iconpath, &stripes->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); + menu_display_reset_textures_list(stripes_texture_path(i), iconpath, &stripes->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL); menu_display_allocate_white_texture(); diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 643e66106a..e0e08482e3 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -71,7 +71,7 @@ #define XMB_RIBBON_VERTICES 2*XMB_RIBBON_COLS*XMB_RIBBON_ROWS-2*XMB_RIBBON_COLS #ifndef XMB_DELAY -#define XMB_DELAY 10 +#define XMB_DELAY 166 #endif #define BATTERY_LEVEL_CHECK_INTERVAL (30 * 1000000) @@ -2923,7 +2923,7 @@ static int xmb_draw_item( ticker.s = tmp; ticker.len = ticker_limit; - ticker.idx = frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.str = ticker_str; ticker.selected = (i == current); @@ -2959,7 +2959,7 @@ static int xmb_draw_item( ticker.s = tmp; ticker.len = 35 * scale_mod[7]; - ticker.idx = frame_count / 20; + ticker.idx = menu_animation_get_ticker_time(); ticker.selected = (i == current); if (!string_is_empty(entry->value)) @@ -3140,7 +3140,6 @@ static void xmb_context_reset_internal(xmb_handle_t *xmb, static void xmb_render(void *data, bool is_idle) { size_t i; - menu_animation_ctx_delta_t delta; settings_t *settings = config_get_ptr(); xmb_handle_t *xmb = (xmb_handle_t*)data; unsigned end = (unsigned)menu_entries_get_size(); @@ -3163,11 +3162,6 @@ static void xmb_render(void *data, bool is_idle) xmb->previous_scale_factor = scale_factor; - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - menu_animation_update(delta.ideal); - if (pointer_enable || mouse_enable) { unsigned height; @@ -4906,7 +4900,7 @@ static void xmb_context_reset_textures( for (i = 0; i < XMB_TEXTURE_LAST; i++) { - if (!menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + if (!menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) { RARCH_WARN("[XMB] Asset missing: %s%s\n", iconpath, xmb_texture_path(i)); /* If the icon is missing return the subsetting (because some themes are incomplete) */ @@ -4914,11 +4908,11 @@ static void xmb_context_reset_textures( { /* OSD Warning only if subsetting icon is missing */ if ( - !menu_display_reset_textures_list(xmb_texture_path(XMB_TEXTURE_SUBSETTING), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR) + !menu_display_reset_textures_list(xmb_texture_path(XMB_TEXTURE_SUBSETTING), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL) && !(settings->uints.menu_xmb_theme == XMB_ICON_THEME_CUSTOM) ) { - runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false); + runloop_msg_queue_push(msg_hash_to_str(MSG_MISSING_ASSETS), 1, 256, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Do not draw icons if subsetting is missing */ goto error; } @@ -5771,6 +5765,28 @@ static int xmb_pointer_tap(void *userdata, return 0; } +#ifdef HAVE_MENU_WIDGETS +static bool xmb_get_load_content_animation_data(void *userdata, menu_texture_item *icon, char **playlist_name) +{ + xmb_handle_t *xmb = (xmb_handle_t*) userdata; + + if (xmb->categories_selection_ptr > xmb->system_tab_end) + { + xmb_node_t *node = file_list_get_userdata_at_offset(xmb->horizontal_list, xmb->categories_selection_ptr - xmb->system_tab_end-1); + + *icon = node->icon; + *playlist_name = xmb->title_name; + } + else + { + *icon = xmb->textures.list[XMB_TEXTURE_QUICKMENU]; + *playlist_name = "RetroArch"; + } + + return true; +} +#endif + menu_ctx_driver_t menu_ctx_xmb = { NULL, xmb_messagebox, @@ -5812,5 +5828,10 @@ menu_ctx_driver_t menu_ctx_xmb = { xmb_set_thumbnail_content, menu_display_osk_ptr_at_pos, xmb_update_savestate_thumbnail_path, - xmb_update_savestate_thumbnail_image + xmb_update_savestate_thumbnail_image, + NULL, + NULL, +#ifdef HAVE_MENU_WIDGETS + xmb_get_load_content_animation_data +#endif }; diff --git a/menu/drivers/xui.cpp b/menu/drivers/xui.cpp index f47ee97dcb..3657678be3 100644 --- a/menu/drivers/xui.cpp +++ b/menu/drivers/xui.cpp @@ -571,7 +571,7 @@ static void xui_render(void *data, bool is_idle) ticker.s = title; ticker.len = RXUI_TERM_WIDTH(fb_width) - 3; - ticker.idx = (unsigned int)frame_count / 15; + ticker.idx = menu_animation_get_ticker_time(); ticker.str = title; ticker.selected = true; diff --git a/menu/menu_animation.c b/menu/menu_animation.c index a406faee77..482a80b8d6 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -34,8 +34,6 @@ #include "../configuration.h" #include "../performance_counters.h" -#define IDEAL_DELTA_TIME (1.0 / 60.0 * 1000000.0) - struct tween { float duration; @@ -66,6 +64,7 @@ static menu_animation_t anim; static retro_time_t cur_time = 0; static retro_time_t old_time = 0; static float delta_time = 0.0f; +static float ticker_time = 0.0f; static bool animation_is_active = false; /* from https://github.com/kikito/tween.lua/blob/master/tween.lua */ @@ -496,17 +495,21 @@ bool menu_animation_push(menu_animation_ctx_entry_t *entry) return true; } -bool menu_animation_update(float anim_delta_time) +bool menu_animation_update() { unsigned i; + settings_t *settings = config_get_ptr(); + + menu_animation_update_time(settings->bools.menu_timedate_enable); + anim.in_update = true; anim.pending_deletes = false; for(i = 0; i < da_count(anim.list); i++) { struct tween *tween = da_getptr(anim.list, i); - tween->running_since += anim_delta_time; + tween->running_since += delta_time; *tween->subject = tween->easing( tween->running_since, @@ -591,29 +594,17 @@ bool menu_animation_ticker(const menu_animation_ctx_ticker_t *ticker) return true; } -bool menu_animation_get_ideal_delta_time(menu_animation_ctx_delta_t *delta) -{ - if (!delta) - return false; - delta->ideal = delta->current / IDEAL_DELTA_TIME; - return true; -} - void menu_animation_update_time(bool timedate_enable) { static retro_time_t last_clock_update = 0; - cur_time = cpu_features_get_time_usec(); - delta_time = cur_time - old_time; - - if (delta_time >= IDEAL_DELTA_TIME* 4) - delta_time = IDEAL_DELTA_TIME * 4; - if (delta_time <= IDEAL_DELTA_TIME / 4) - delta_time = IDEAL_DELTA_TIME / 4; + cur_time = cpu_features_get_time_usec() / 1000.0f; + delta_time = old_time == 0 ? 0 : cur_time - old_time; old_time = cur_time; + ticker_time = (cur_time / 1000.0f) * 3.0f; - if (((cur_time - last_clock_update) > 1000000) + if (((cur_time - last_clock_update) > 1000) && timedate_enable) { animation_is_active = true; @@ -752,3 +743,8 @@ void menu_timer_kill(menu_timer_t *timer) menu_animation_ctx_tag tag = (uintptr_t) timer; menu_animation_kill_by_tag(&tag); } + +float menu_animation_get_ticker_time() +{ + return ticker_time; +} \ No newline at end of file diff --git a/menu/menu_animation.h b/menu/menu_animation.h index 64ca8a454e..e39ccc0012 100644 --- a/menu/menu_animation.h +++ b/menu/menu_animation.h @@ -84,12 +84,6 @@ enum menu_animation_easing_type EASING_LAST }; -typedef struct menu_animation_ctx_delta -{ - float current; - float ideal; -} menu_animation_ctx_delta_t; - typedef uintptr_t menu_animation_ctx_tag; typedef struct menu_animation_ctx_subject @@ -141,9 +135,7 @@ void menu_animation_init(void); void menu_animation_free(void); -bool menu_animation_update(float delta_time); - -bool menu_animation_get_ideal_delta_time(menu_animation_ctx_delta_t *delta); +bool menu_animation_update(); bool menu_animation_ticker(const menu_animation_ctx_ticker_t *ticker); @@ -163,6 +155,8 @@ float menu_animation_get_delta_time(void); bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data); +float menu_animation_get_ticker_time(); + RETRO_END_DECLS #endif diff --git a/menu/menu_cbs.h b/menu/menu_cbs.h index 440f30e37e..abe9b3ae84 100644 --- a/menu/menu_cbs.h +++ b/menu/menu_cbs.h @@ -288,7 +288,7 @@ void menu_cbs_init(void *data, int menu_cbs_exit(void); -void cb_generic_download(void *task_data, +void cb_generic_download(retro_task_t *task, void *task_data, void *user_data, const char *err); RETRO_END_DECLS diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 50703545fa..1658826884 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4138,7 +4138,7 @@ static void menu_displaylist_parse_playlist_generic( } #ifdef HAVE_NETWORKING -static void wifi_scan_callback(void *task_data, +static void wifi_scan_callback(retro_task_t *task, void *task_data, void *user_data, const char *error) { unsigned i; @@ -4373,7 +4373,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist FILE *profile = NULL; const size_t profiles_count = sizeof(SWITCH_CPU_PROFILES)/sizeof(SWITCH_CPU_PROFILES[1]); - runloop_msg_queue_push("Warning : extended overclocking can damage the Switch", 1, 90, true); + runloop_msg_queue_push("Warning : extended overclocking can damage the Switch", 1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); @@ -4425,7 +4425,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist FILE *profile = NULL; const size_t profiles_count = sizeof(SWITCH_GPU_PROFILES)/sizeof(SWITCH_GPU_PROFILES[1]); - runloop_msg_queue_push("Warning : extented overclocking can damage the Switch", 1, 90, true); + runloop_msg_queue_push("Warning : extented overclocking can damage the Switch", 1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); profile = popen("gpu-profile get", "r"); fgets(current_profile, PATH_MAX_LENGTH, profile); diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 812dc480df..73ea1c9b29 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -44,6 +44,10 @@ #include "../gfx/video_driver.h" +#ifdef HAVE_MENU_WIDGETS +#include "widgets/menu_widgets.h" +#endif + #include "menu_animation.h" #include "menu_driver.h" #include "menu_cbs.h" @@ -464,6 +468,7 @@ font_data_t *menu_display_font( font_data_t *menu_display_font_file(char* fontpath, float menu_font_size, bool is_threaded) { font_data_t *font_data = NULL; + if (!menu_disp) return NULL; @@ -1252,7 +1257,7 @@ static bool menu_driver_load_image(menu_ctx_load_image_t *load_image_info) return false; } -void menu_display_handle_thumbnail_upload(void *task_data, +void menu_display_handle_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err) { menu_ctx_load_image_t load_image_info; @@ -1268,7 +1273,7 @@ void menu_display_handle_thumbnail_upload(void *task_data, free(user_data); } -void menu_display_handle_left_thumbnail_upload(void *task_data, +void menu_display_handle_left_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err) { menu_ctx_load_image_t load_image_info; @@ -1284,7 +1289,7 @@ void menu_display_handle_left_thumbnail_upload(void *task_data, free(user_data); } -void menu_display_handle_savestate_thumbnail_upload(void *task_data, +void menu_display_handle_savestate_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err) { menu_ctx_load_image_t load_image_info; @@ -1303,7 +1308,7 @@ void menu_display_handle_savestate_thumbnail_upload(void *task_data, /* Function that gets called when we want to load in a * new menu wallpaper. */ -void menu_display_handle_wallpaper_upload(void *task_data, +void menu_display_handle_wallpaper_upload(retro_task_t *task, void *task_data, void *user_data, const char *err) { menu_ctx_load_image_t load_image_info; @@ -1574,6 +1579,10 @@ void menu_display_draw_text( { struct font_params params; + /* Don't draw is alpha is 0 */ + if ((color & 0x000000FF) == 0) + return; + /* Don't draw outside of the screen */ if ( ((x < -64 || x > width + 64) || (y < -64 || y > height + 64)) @@ -1603,7 +1612,8 @@ void menu_display_draw_text( bool menu_display_reset_textures_list( const char *texture_path, const char *iconpath, - uintptr_t *item, enum texture_filter_type filter_type) + uintptr_t *item, enum texture_filter_type filter_type, + unsigned *width, unsigned *height) { struct texture_image ti; char texpath[PATH_MAX_LENGTH] = {0}; @@ -1622,6 +1632,12 @@ bool menu_display_reset_textures_list( if (!image_texture_load(&ti, texpath)) return false; + if (width) + *width = ti.width; + + if (height) + *height = ti.height; + video_driver_texture_load(&ti, filter_type, item); image_texture_free(&ti); @@ -1688,7 +1704,7 @@ const char *config_get_menu_driver_options(void) * when we need to extract the APK contents/zip file. This * file contains assets which then get extracted to the * user's asset directories. */ -static void bundle_decompressed(void *task_data, +static void bundle_decompressed(retro_task_t *task, void *task_data, void *user_data, const char *err) { settings_t *settings = config_get_ptr(); @@ -1759,7 +1775,7 @@ static bool menu_init(menu_handle_t *menu_data) task_push_decompress(settings->arrays.bundle_assets_src, settings->arrays.bundle_assets_dst, NULL, settings->arrays.bundle_assets_dst_subdir, - NULL, bundle_decompressed, NULL); + NULL, bundle_decompressed, NULL, NULL); #endif } @@ -1894,6 +1910,14 @@ void menu_driver_frame(video_frame_info_t *video_info) menu_driver_ctx->frame(menu_userdata, video_info); } +#ifdef HAVE_MENU_WIDGETS +bool menu_driver_get_load_content_animation_data(menu_texture_item *icon, char **playlist_name) +{ + return menu_driver_ctx && menu_driver_ctx->get_load_content_animation_data + && menu_driver_ctx->get_load_content_animation_data(menu_userdata, icon, playlist_name); +} +#endif + bool menu_driver_render(bool is_idle, bool rarch_is_inited, bool rarch_is_dummy_core) { @@ -1924,9 +1948,6 @@ bool menu_driver_render(bool is_idle, bool rarch_is_inited, if (BIT64_GET(menu_driver_data->state, MENU_STATE_BLIT)) { - settings_t *settings = config_get_ptr(); - menu_animation_update_time(settings->bools.menu_timedate_enable); - if (menu_driver_ctx->render) menu_driver_ctx->render(menu_userdata, is_idle); } @@ -2283,6 +2304,9 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) case RARCH_MENU_CTL_OWNS_DRIVER: return menu_driver_data_own; case RARCH_MENU_CTL_DEINIT: +#ifdef HAVE_MENU_WIDGETS + menu_widgets_context_destroy(); +#endif if (menu_driver_ctx && menu_driver_ctx->context_destroy) menu_driver_ctx->context_destroy(menu_userdata); diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 49944b34ba..c47688897a 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "menu_defines.h" #include "menu_input.h" @@ -58,6 +59,19 @@ RETRO_BEGIN_DECLS #define MENU_SETTINGS_CHEEVOS_START 0x40000 #define MENU_SETTINGS_NETPLAY_ROOMS_START 0x80000 +#define COLOR_TEXT_ALPHA(color, alpha) (color & 0xFFFFFF00) | alpha + +#define HEX_R(hex) ((hex >> 16) & 0xFF) * (1.0f / 255.0f) +#define HEX_G(hex) ((hex >> 8 ) & 0xFF) * (1.0f / 255.0f) +#define HEX_B(hex) ((hex >> 0 ) & 0xFF) * (1.0f / 255.0f) + +#define COLOR_HEX_TO_FLOAT(hex, alpha) { \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha, \ + HEX_R(hex), HEX_G(hex), HEX_B(hex), alpha \ +} + extern float osk_dark[16]; enum menu_settings_type @@ -374,6 +388,9 @@ typedef struct menu_ctx_driver int (*pointer_up)(void *data, unsigned x, unsigned y, unsigned ptr, menu_file_list_cbs_t *cbs, menu_entry_t *entry, unsigned action); +#ifdef HAVE_MENU_WIDGETS + bool (*get_load_content_animation_data)(void *userdata, menu_texture_item *icon, char **playlist_name); +#endif } menu_ctx_driver_t; typedef struct menu_ctx_displaylist @@ -479,6 +496,8 @@ void menu_driver_set_binding_state(bool on); void menu_driver_frame(video_frame_info_t *video_info); +bool menu_driver_get_load_content_animation_data(menu_texture_item *icon, char **playlist_name); + /* Is a background texture set for the current menu driver? Should * return true for RGUI, for instance. */ bool menu_driver_is_texture_set(void); @@ -609,16 +628,16 @@ 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_handle_wallpaper_upload(void *task_data, +void menu_display_handle_wallpaper_upload(retro_task_t *task, void *task_data, void *user_data, const char *err); -void menu_display_handle_thumbnail_upload(void *task_data, +void menu_display_handle_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err); -void menu_display_handle_left_thumbnail_upload(void *task_data, +void menu_display_handle_left_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err); -void menu_display_handle_savestate_thumbnail_upload(void *task_data, +void menu_display_handle_savestate_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err); void menu_display_push_quad( @@ -652,10 +671,9 @@ font_data_t *menu_display_font( font_data_t *menu_display_font_file(char* fontpath, float font_size, bool is_threaded); bool menu_display_reset_textures_list( - const char *texture_path, - const char *iconpath, - uintptr_t *item, - enum texture_filter_type filter_type); + const char *texture_path, const char *iconpath, + uintptr_t *item, enum texture_filter_type filter_type, + unsigned *width, unsigned *height); /* Returns the OSK key at a given position */ int menu_display_osk_ptr_at_pos(void *data, int x, int y, diff --git a/menu/menu_input.c b/menu/menu_input.c index 70a8b4e127..2ce35f2ada 100644 --- a/menu/menu_input.c +++ b/menu/menu_input.c @@ -162,7 +162,6 @@ void menu_event_kb_set(bool down, enum retro_key key) */ unsigned menu_event(input_bits_t *p_input, input_bits_t *p_trigger_input) { - menu_animation_ctx_delta_t delta; /* Used for key repeat */ static float delay_timer = 0.0f; static float delay_count = 0.0f; @@ -198,7 +197,7 @@ unsigned menu_event(input_bits_t *p_input, input_bits_t *p_trigger_input) * for old_input_state. */ first_held = true; - delay_timer = initial_held ? 12 : 6; + delay_timer = initial_held ? 200 : 100; delay_count = 0; } @@ -235,10 +234,7 @@ unsigned menu_event(input_bits_t *p_input, input_bits_t *p_trigger_input) menu_driver_ctl(MENU_NAVIGATION_CTL_SET_SCROLL_ACCEL, &new_scroll_accel); - delta.current = menu_animation_get_delta_time(); - - if (menu_animation_get_ideal_delta_time(&delta)) - delay_count += delta.ideal; + delay_count += menu_animation_get_delta_time(); if (menu_input_dialog_get_display_kb()) { diff --git a/menu/menu_networking.c b/menu/menu_networking.c index 4504aac070..9080a663d9 100644 --- a/menu/menu_networking.c +++ b/menu/menu_networking.c @@ -180,7 +180,7 @@ void print_buf_lines(file_list_t *list, char *buf, * with a newline, just ignore the partial last line. */ } -void cb_net_generic_subdir(void *task_data, void *user_data, const char *err) +void cb_net_generic_subdir(retro_task_t *task, void *task_data, void *user_data, const char *err) { #ifdef HAVE_NETWORKING char subdir_path[PATH_MAX_LENGTH]; @@ -222,7 +222,7 @@ finish: #endif } -void cb_net_generic(void *task_data, void *user_data, const char *err) +void cb_net_generic(retro_task_t *task, void *task_data, void *user_data, const char *err) { #ifdef HAVE_NETWORKING bool refresh = false; diff --git a/menu/menu_networking.h b/menu/menu_networking.h index 042af4dd50..bf26b9a16e 100644 --- a/menu/menu_networking.h +++ b/menu/menu_networking.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -33,10 +34,10 @@ void print_buf_lines(file_list_t *list, char *buf, const char *label, int buf_size, enum msg_file_type type, bool append, bool extended); -void cb_net_generic_subdir(void *task_data, void *user_data, +void cb_net_generic_subdir(retro_task_t *task, void *task_data, void *user_data, const char *err); -void cb_net_generic(void *task_data, void *user_data, const char *err); +void cb_net_generic(retro_task_t *task, void *task_data, void *user_data, const char *err); RETRO_END_DECLS diff --git a/menu/menu_setting.c b/menu/menu_setting.c index c8a1c92321..f1fe94621d 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -183,10 +183,12 @@ static int setting_action_ok_bind_all_save_autoconfig(rarch_setting_t *setting, if(!string_is_empty(name) && config_save_autoconf_profile(name, index_offset)) runloop_msg_queue_push( - msg_hash_to_str(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY), 1, 100, true); + msg_hash_to_str(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY), 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); else runloop_msg_queue_push( - msg_hash_to_str(MSG_AUTOCONFIG_FILE_ERROR_SAVING), 1, 100, true); + msg_hash_to_str(MSG_AUTOCONFIG_FILE_ERROR_SAVING), 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return 0; } diff --git a/menu/widgets/menu_widgets.c b/menu/widgets/menu_widgets.c new file mode 100644 index 0000000000..37720f22e8 --- /dev/null +++ b/menu/widgets/menu_widgets.c @@ -0,0 +1,2068 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2018 - natinusala + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "menu_widgets.h" + +#include "../../verbosity.h" +#include "../../retroarch.h" +#include "../../configuration.h" +#include "../../msg_hash.h" + +#include "../../tasks/task_content.h" + +#include "../menu_driver.h" +#include "../menu_animation.h" + +#include "../../gfx/font_driver.h" + +#include +#include +#include +#include +#include +#include + +#define PI 3.14159265359f + +/* TODO: Fix context reset freezing everything in place (probably kills animations when it shouldn't anymore) */ + +static float backdrop[16] = { + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, +}; + +static float msg_queue_background[16] = COLOR_HEX_TO_FLOAT(0x3A3A3A, 1.0f); +static float msg_queue_info[16] = COLOR_HEX_TO_FLOAT(0x12ACF8, 1.0f); + +/* TODO: Colors for warning, error and success */ + +static float msg_queue_task_progress_1[16] = COLOR_HEX_TO_FLOAT(0x55AE99, 1.0f); /* Color of first progress bar in a task message */ +static float msg_queue_task_progress_2[16] = COLOR_HEX_TO_FLOAT(0x388BBD, 1.0f); /* Color of second progress bar in a task message (for multiple tasks with same message) */ + +static float color_task_progress_bar[16] = COLOR_HEX_TO_FLOAT(0x22B14C, 1.0f); + +static unsigned text_color_info = 0xD8EEFFFF; +static unsigned text_color_success = 0x22B14CFF; +static unsigned text_color_error = 0xC23B22FF; +static unsigned text_color_faint = 0x878787FF; + +static float volume_bar_background[16] = COLOR_HEX_TO_FLOAT(0x1A1A1A, 1.0f); +static float volume_bar_normal[16] = COLOR_HEX_TO_FLOAT(0x198AC6, 1.0f); +static float volume_bar_loud[16] = COLOR_HEX_TO_FLOAT(0xF5DD19, 1.0f); +static float volume_bar_loudest[16] = COLOR_HEX_TO_FLOAT(0xC23B22, 1.0f); + +static bool init = false; +static uint64_t menu_widgets_frame_count = 0; +static menu_animation_ctx_tag generic_tag = (uintptr_t) &init; + +/* Font data */ +font_data_t *font_regular; +font_data_t *font_bold; + +video_font_raster_block_t font_raster_regular; +video_font_raster_block_t font_raster_bold; + +static float menu_widgets_pure_white[16] = { + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, + 1.00, 1.00, 1.00, 1.00, +}; + +/* Load content animation */ +#define ANIMATION_LOAD_CONTENT_DURATION 333 + +#define LOAD_CONTENT_ANIMATION_INITIAL_ICON_SIZE 320 +#define LOAD_CONTENT_ANIMATION_TARGET_ICON_SIZE 240 + +static bool load_content_animation_running = false; +static char *load_content_animation_content_name = NULL; +static char *load_content_animation_playlist_name = NULL; +static menu_texture_item load_content_animation_icon = 0; + +static float load_content_animation_icon_color[16]; +static float load_content_animation_icon_size; +static float load_content_animation_icon_alpha; +static float load_content_animation_fade_alpha; +static float load_content_animation_final_fade_alpha; + +static menu_timer_t load_content_animation_end_timer; + +static float menu_widgets_backdrop[16] = { + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, + 0.00, 0.00, 0.00, 0.75, +}; + +/* Messages queue */ + +typedef struct menu_widget_msg +{ + char *msg; + char *msg_new; + float msg_transition_animation; + unsigned msg_len; + unsigned duration; + + unsigned text_height; + + float offset_y; + + float alpha; + + bool dying; /* is it currently doing the fade out animation ? */ + + unsigned width; + bool expired; /* has the timer expired ? if so, should be set to dying */ + + menu_timer_t expiration_timer; + bool expiration_timer_started; + + retro_task_t *task_ptr; + char *task_title_ptr; /* used to detect title change */ + uint8_t task_count; /* how many tasks have used this notification? */ + + int8_t task_progress; + bool task_finished; + bool task_error; + bool task_cancelled; + uint32_t task_ident; + + bool unfolded; /* unfold animation */ + bool unfolding; + float unfold; + + float hourglass_rotation; + menu_timer_t hourglass_timer; +} menu_widget_msg_t; + +static fifo_buffer_t *msg_queue; +static file_list_t *current_msgs; +static unsigned msg_queue_kill; + +static unsigned msg_queue_tasks_count = 0; /* count of messages bound to a taskin current_msgs */ + +/* TODO: Don't display icons if assets are missing */ + +static menu_texture_item msg_queue_icon = 0; +static menu_texture_item msg_queue_icon_outline = 0; +static menu_texture_item msg_queue_icon_rect = 0; +static bool msg_queue_has_icons = false; + +/* there can only be one message animation at a time to avoid confusing users */ +static bool moving = false; + +/* Icons */ +enum menu_widgets_icon +{ + MENU_WIDGETS_ICON_VOLUME_MED = 0, + MENU_WIDGETS_ICON_VOLUME_MAX, + MENU_WIDGETS_ICON_VOLUME_MIN, + MENU_WIDGETS_ICON_VOLUME_MUTE, + + MENU_WIDGETS_ICON_PAUSED, + MENU_WIDGETS_ICON_FAST_FORWARD, + MENU_WIDGETS_ICON_REWIND, + MENU_WIDGETS_ICON_SLOW_MOTION, + + MENU_WIDGETS_ICON_HOURGLASS, + MENU_WIDGETS_ICON_CHECK, + + MENU_WIDGETS_ICON_INFO, + + MENU_WIDGETS_ICON_LAST +}; + +static char *menu_widgets_icons_names[MENU_WIDGETS_ICON_LAST] = { + "menu_volume_med.png", + "menu_volume_max.png", + "menu_volume_min.png", + "menu_volume_mute.png", + + "menu_pause.png", + "menu_frameskip.png", + "menu_rewind.png", + "resume.png", + + "menu_hourglass.png", + "menu_check.png", + + "menu_info.png" +}; + +static menu_texture_item menu_widgets_icons_textures[MENU_WIDGETS_ICON_LAST]; + +/* Volume */ +static float volume_db = 0.0f; +static float volume_percent = 1.0f; +static menu_timer_t volume_timer = 0.0f; + +static float volume_alpha = 0.0f; +static float volume_text_alpha = 0.0f; +static menu_animation_ctx_tag volume_tag = (uintptr_t) &volume_alpha; +static bool volume_mute = false; + +/* FPS */ +static char fps_text[255]; + +/* Status icons */ +static bool paused = false; +static bool fast_forward = false; +static bool rewinding = false; + +/* Screenshot */ +static float screenshot_alpha = 0.0f; +static menu_texture_item screenshot_texture = 0; +static unsigned screenshot_texture_width = 0; +static unsigned screenshot_texture_height = 0; +static char screenshot_shotname[256] = {0}; +static char screenshot_filename[256] = {0}; +static bool screenshot_loaded = false; + +static unsigned screenshot_height; +static unsigned screenshot_width; +static float screenshot_scale_factor; +static unsigned screenshot_thumbnail_width; +static unsigned screenshot_thumbnail_height; +static float screenshot_y; +static menu_timer_t screenshot_timer; + +static unsigned screenshot_shotname_length; + +/* Metrics */ +static unsigned simple_widget_padding; +static unsigned simple_widget_height; +static unsigned glyph_width; + +static unsigned msg_queue_height; +static unsigned msg_queue_icon_size_x; +static unsigned msg_queue_icon_size_y; +static float msg_queue_text_scale_factor; +static unsigned msg_queue_base_width; +static unsigned msg_queue_spacing; +static unsigned msg_queue_glyph_width; +static unsigned msg_queue_rect_start_x; +static unsigned msg_queue_internal_icon_size; +static unsigned msg_queue_internal_icon_offset; +static unsigned msg_queue_icon_offset_y; +static unsigned msg_queue_scissor_start_x; +static unsigned msg_queue_default_rect_width; +static unsigned msg_queue_task_text_start_x; +static unsigned msg_queue_regular_padding_x; +static unsigned msg_queue_regular_text_start; +static unsigned msg_queue_regular_text_base_y; +static unsigned msg_queue_task_rect_start_x; +static unsigned msg_queue_task_hourglass_x; + +bool menu_widgets_set_paused(bool is_paused) +{ + if (!init) + return false; + + paused = is_paused; + return true; +} + +static void msg_widget_msg_transition_animation_done(void *userdata) +{ + menu_widget_msg_t *msg = (menu_widget_msg_t*) userdata; + + free(msg->msg); + + msg->msg = msg->msg_new; + msg->msg_new = NULL; + msg->msg_transition_animation = 0.0f; +} + +static bool menu_widgets_msg_queue_push_internal(retro_task_t *task, const char *msg, + unsigned duration, + char *title, + enum message_queue_icon icon, enum message_queue_category category) +{ + menu_widget_msg_t* msg_widget = NULL; + + if (!init) + return false; + + #ifdef HAVE_THREADS + runloop_msg_queue_lock(); + #endif + + if (fifo_write_avail(msg_queue) > 0) + { + /* Get current msg if it exists */ + if (task != NULL && task->frontend_userdata) + { + msg_widget = (menu_widget_msg_t*) task->frontend_userdata; + msg_widget->task_ptr = task; /* msg_widgets can be passed between tasks */ + } + + /* Spawn a new notification */ + if (msg_widget == NULL) + { + const char *title; + + msg_widget = (menu_widget_msg_t*) calloc(1, sizeof(*msg_widget)); + + title = task != NULL ? task->title : msg; + + msg_widget->duration = duration; + msg_widget->offset_y = 0; + msg_widget->alpha = 1.0f; + + msg_widget->dying = false; + msg_widget->expired = false; + + msg_widget->expiration_timer = 0; + msg_widget->task_ptr = task; + msg_widget->expiration_timer_started = false; + + msg_widget->msg_new = NULL; + msg_widget->msg_transition_animation = 0.0f; + + msg_widget->text_height = 0; + + if (msg_queue_has_icons) + { + msg_widget->unfolded = false; + msg_widget->unfolding = false; + msg_widget->unfold = 0.0f; + } + else + { + msg_widget->unfolded = true; + msg_widget->unfolding = false; + msg_widget->unfold = 1.0f; + } + + if (task) + { + msg_widget->msg = strdup(title); + msg_widget->msg_len = strlen(title); + + msg_widget->task_error = task->error; + msg_widget->task_cancelled = task->cancelled; + msg_widget->task_finished = task->finished; + msg_widget->task_progress = task->progress; + msg_widget->task_ident = task->ident; + msg_widget->task_title_ptr = task->title; + msg_widget->task_count = 1; + + msg_widget->unfolded = true; + + msg_widget->width = font_driver_get_message_width(font_regular, title, msg_widget->msg_len, msg_queue_text_scale_factor) + simple_widget_padding/2; + + task->frontend_userdata = msg_widget; + + msg_widget->hourglass_rotation = 0; + } + else + { + /* Compute rect width, wrap if necessary */ + /* Single line text > two lines text > two lines text with expanded width */ + unsigned title_length = strlen(title); + char *msg = strdup(title); + unsigned width = msg_queue_default_rect_width; + unsigned text_width = font_driver_get_message_width(font_regular, title, title_length, msg_queue_text_scale_factor); + settings_t *settings = config_get_ptr(); + + msg_widget->text_height = msg_queue_text_scale_factor * settings->floats.video_font_size; + + /* Text is too wide, split it into two lines */ + if (text_width > width) + { + if (text_width/2 > width) + { + width = text_width/2; + width += 10 * msg_queue_glyph_width; + } + + word_wrap(msg, msg, title_length/2 + 10, false); + + msg_widget->text_height *= 2.5f; + } + else + { + width = text_width; + msg_widget->text_height *= 1.35f; + } + + msg_widget->msg = msg; + msg_widget->msg_len = strlen(msg); + msg_widget->width = width + simple_widget_padding/2; + } + + fifo_write(msg_queue, &msg_widget, sizeof(msg_widget)); + } + /* Update task info */ + else + { + if (msg_widget->expiration_timer_started) + { + menu_timer_kill(&msg_widget->expiration_timer); + msg_widget->expiration_timer_started = false; + } + + if (task->title != msg_widget->task_title_ptr) + { + menu_animation_ctx_entry_t entry; + unsigned len = strlen(task->title); + unsigned new_width = font_driver_get_message_width(font_regular, task->title, len, msg_queue_text_scale_factor); + + if (msg_widget->msg_new) + free(msg_widget->msg_new); + + msg_widget->msg_new = strdup(task->title); + msg_widget->msg_len = len; + msg_widget->task_title_ptr = task->title; + msg_widget->msg_transition_animation = 0; + + entry.easing_enum = EASING_OUT_QUAD; + entry.tag = (uintptr_t) NULL; + entry.duration = MSG_QUEUE_ANIMATION_DURATION*2; + entry.target_value = msg_queue_height/2.0f; + entry.subject = &msg_widget->msg_transition_animation; + entry.cb = msg_widget_msg_transition_animation_done; + entry.userdata = msg_widget; + + menu_animation_push(&entry); + + msg_widget->task_count++; + + if (new_width > msg_widget->width) + msg_widget->width = new_width; + } + + msg_widget->task_error = task->error; + msg_widget->task_cancelled = task->cancelled; + msg_widget->task_finished = task->finished; + msg_widget->task_progress = task->progress; + } + } + + #ifdef HAVE_THREADS + runloop_msg_queue_unlock(); + #endif + + return true; +} + +bool menu_widgets_msg_queue_push(const char *msg, + unsigned duration, + char *title, + enum message_queue_icon icon, enum message_queue_category category) +{ + return menu_widgets_msg_queue_push_internal(NULL, msg, duration, title, icon, category); +} + +static void menu_widgets_unfold_end(void *userdata) +{ + menu_widget_msg_t *unfold = (menu_widget_msg_t*) userdata; + + unfold->unfolding = false; + moving = false; +} + +static void menu_widgets_move_end(void *userdata) +{ + if (userdata) + { + menu_widget_msg_t *unfold = (menu_widget_msg_t*) userdata; + + menu_animation_ctx_entry_t entry; + + entry.cb = menu_widgets_unfold_end; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &unfold->unfold; + entry.tag = generic_tag; + entry.target_value = 1.0f; + entry.userdata = unfold; + + menu_animation_push(&entry); + + unfold->unfolded = true; + unfold->unfolding = true; + } + else + { + moving = false; + } +} + +static void menu_widgets_msg_queue_expired(void *userdata) +{ + menu_widget_msg_t *msg = (menu_widget_msg_t *) userdata; + + if (msg && !msg->expired) + msg->expired = true; +} + +static void menu_widgets_msg_queue_move() +{ + int i; + float y = 0; + + menu_widget_msg_t *unfold = NULL; /* there should always be one and only one unfolded message */ + + if (current_msgs->size == 0) + return; + + for (i = current_msgs->size-1; i >= 0; i--) + { + menu_widget_msg_t *msg; + + msg = file_list_get_userdata_at_offset(current_msgs, i); + + if (!msg || msg->dying) + continue; + + y += msg_queue_height / (msg->task_ptr ? 2 : 1) + msg_queue_spacing; + + if (!msg->unfolded) + unfold = msg; + + if (msg->offset_y != y) + { + menu_animation_ctx_entry_t entry; + + entry.cb = i == 0 ? menu_widgets_move_end : NULL; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &msg->offset_y; + entry.tag = generic_tag; + entry.target_value = y; + entry.userdata = unfold; + + menu_animation_push(&entry); + + moving = true; + } + } +} + +static void menu_widgets_msg_queue_free(menu_widget_msg_t *msg, bool touch_list) +{ + int i; + menu_animation_ctx_tag tag = (uintptr_t) msg; + + /* Update tasks count */ + if (msg->task_ptr) + msg_queue_tasks_count--; + + /* Kill all animations */ + menu_timer_kill(&msg->hourglass_timer); + menu_animation_kill_by_tag(&tag); + + /* Free it */ + if (msg->msg) + free(msg->msg); + + /* Remove it from the list */ + if (touch_list) + { + file_list_free_userdata(current_msgs, msg_queue_kill); + + for (i = msg_queue_kill; i < current_msgs->size-1; i++) + { + current_msgs->list[i] = current_msgs->list[i+1]; + } + + current_msgs->size--; + } + + moving = false; +} + +static void menu_widgets_msg_queue_kill_end(void *userdata) +{ + menu_widget_msg_t *msg = file_list_get_userdata_at_offset(current_msgs, msg_queue_kill); + + if (!msg) + return; + + menu_widgets_msg_queue_free(msg, true); +} + +static void menu_widgets_msg_queue_kill(unsigned idx) +{ + menu_animation_ctx_entry_t entry; + + menu_widget_msg_t *msg = file_list_get_userdata_at_offset(current_msgs, idx); + + if (!msg) + return; + + moving = true; + msg->dying = true; + + msg_queue_kill = idx; + + /* Drop down */ + entry.cb = NULL; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.tag = generic_tag; + entry.userdata = NULL; + entry.subject = &msg->offset_y; + entry.target_value = msg->offset_y - msg_queue_height/4; + + menu_animation_push(&entry); + + /* Fade out */ + entry.cb = menu_widgets_msg_queue_kill_end; + entry.subject = &msg->alpha; + entry.target_value = 0.0f; + + menu_animation_push(&entry); + + /* Move all messages back to their correct position */ + menu_widgets_msg_queue_move(); +} + +static void color_alpha(float *color, float alpha) +{ + color[3] = color[7] = color[11] = color[15] = alpha; +} + +static void menu_widgets_draw_icon( + video_frame_info_t *video_info, + unsigned icon_width, + unsigned icon_height, + uintptr_t texture, + float x, float y, + unsigned width, unsigned height, + float rotation, float scale_factor, + float *color) +{ + menu_display_ctx_rotate_draw_t rotate_draw; + menu_display_ctx_draw_t draw; + struct video_coords coords; + math_matrix_4x4 mymat; + + if (!texture) + return; + + rotate_draw.matrix = &mymat; + rotate_draw.rotation = rotation; + rotate_draw.scale_x = scale_factor; + rotate_draw.scale_y = scale_factor; + rotate_draw.scale_z = 1; + rotate_draw.scale_enable = true; + + menu_display_rotate_z(&rotate_draw, video_info); + + coords.vertices = 4; + coords.vertex = NULL; + coords.tex_coord = NULL; + coords.lut_tex_coord = NULL; + coords.color = color; + + draw.x = x; + draw.y = height - y - icon_height; + draw.width = icon_width; + draw.height = icon_height; + draw.scale_factor = scale_factor; + draw.rotation = rotation; + draw.coords = &coords; + draw.matrix_data = &mymat; + draw.texture = texture; + draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP; + draw.pipeline.id = 0; + + menu_display_draw(&draw, video_info); +} + +static float menu_widgets_get_thumbnail_scale_factor(const float dst_width, const float dst_height, + const float image_width, const float image_height) +{ + float dst_ratio = dst_width / dst_height; + float image_ratio = image_width / image_height; + + return (dst_ratio > image_ratio) ? dst_height / image_height : dst_width / image_width; +} + +static void menu_widgets_screenshot_dispose(void *userdata) +{ + screenshot_loaded = false; + video_driver_texture_unload(&screenshot_texture); +} + +static void menu_widgets_screenshot_end(void *userdata) +{ + menu_animation_ctx_entry_t entry; + + entry.cb = menu_widgets_screenshot_dispose; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &screenshot_y; + entry.tag = generic_tag; + entry.target_value = -((float)screenshot_height); + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +static void menu_widgets_start_msg_expiration_timer(menu_widget_msg_t *msg_widget, unsigned duration) +{ + if (msg_widget->expiration_timer_started) + return; + + menu_timer_ctx_entry_t timer; + + timer.cb = menu_widgets_msg_queue_expired; + timer.duration = duration; + timer.userdata = msg_widget; + + menu_timer_start(&msg_widget->expiration_timer, &timer); + + msg_widget->expiration_timer_started = true; +} + +static void menu_widgets_hourglass_tick(void *userdata); + +static void menu_widgets_hourglass_end(void *userdata) +{ + menu_widget_msg_t *msg = (menu_widget_msg_t*) userdata; + + msg->hourglass_rotation = 0.0f; + + menu_timer_ctx_entry_t timer; + timer.cb = menu_widgets_hourglass_tick; + timer.duration = HOURGLASS_INTERVAL; + timer.userdata = msg; + + menu_timer_start(&msg->hourglass_timer, &timer); +} + +static void menu_widgets_hourglass_tick(void *userdata) +{ + menu_widget_msg_t *msg = (menu_widget_msg_t*) userdata; + menu_animation_ctx_tag tag = (uintptr_t) msg; + + menu_animation_ctx_entry_t entry; + + entry.easing_enum = EASING_OUT_QUAD; + entry.tag = tag; + entry.duration = HOURGLASS_DURATION; + entry.target_value = -(2 * PI); + entry.subject = &msg->hourglass_rotation; + entry.cb = menu_widgets_hourglass_end; + entry.userdata = msg; + + menu_animation_push(&entry); +} + +void menu_widgets_iterate() +{ + int i; + settings_t *settings = config_get_ptr(); + + if (!init) + return; + + /* Messages queue */ + #ifdef HAVE_THREADS + runloop_msg_queue_lock(); + #endif + + /* Consume one message if available */ + if (fifo_read_avail(msg_queue) > 0 && !moving && current_msgs->size < MSG_QUEUE_ONSCREEN_MAX) + { + menu_widget_msg_t *msg_widget; + + fifo_read(msg_queue, &msg_widget, sizeof(msg_widget)); + + /* Task messages always appear from the bottom of the screen */ + if (msg_queue_tasks_count == 0 || msg_widget->task_ptr) + { + file_list_append(current_msgs, + NULL, + NULL, + 0, + 0, + 0 + ); + + file_list_set_userdata(current_msgs, current_msgs->size-1, msg_widget); + } + /* Regular messages are always above tasks */ + else + { + unsigned idx = current_msgs->size - msg_queue_tasks_count; + file_list_insert(current_msgs, + NULL, + NULL, + 0, + 0, + 0, + idx + ); + + file_list_set_userdata(current_msgs, idx, msg_widget); + } + + /* Start expiration timer if not associated to a task */ + if (msg_widget->task_ptr == NULL) + { + menu_widgets_start_msg_expiration_timer(msg_widget, MSG_QUEUE_ANIMATION_DURATION*2 + msg_widget->duration); + } + /* Else, start hourglass animation timer */ + else + { + msg_queue_tasks_count++; + menu_widgets_hourglass_end(msg_widget); + } + + menu_widgets_msg_queue_move(); + } + + #ifdef HAVE_THREADS + runloop_msg_queue_unlock(); + #endif + + /* Kill first expired message */ + /* Start expiration timer of dead tasks */ + for (i = 0; i < current_msgs->size ; i++) + { + menu_widget_msg_t *msg = file_list_get_userdata_at_offset(current_msgs, i); + + if (!msg) + continue; + + if (msg->task_ptr != NULL && (msg->task_finished || msg->task_cancelled)) + menu_widgets_start_msg_expiration_timer(msg, TASK_FINISHED_DURATION); + + if (msg->expired && !moving) + { + menu_widgets_msg_queue_kill(i); + break; + } + } + + /* Load screenshot and start its animation */ + if (screenshot_filename[0] != '\0') + { + menu_animation_ctx_entry_t entry; + menu_timer_ctx_entry_t timer; + unsigned width; + + video_driver_texture_unload(&screenshot_texture); + menu_display_reset_textures_list(screenshot_filename, "", &screenshot_texture, TEXTURE_FILTER_MIPMAP_LINEAR, &screenshot_texture_width, &screenshot_texture_height); + + video_driver_get_size(&width, NULL); + + screenshot_height = settings->floats.video_font_size * 4; + screenshot_width = width; + + screenshot_scale_factor = menu_widgets_get_thumbnail_scale_factor( + width, screenshot_height, + screenshot_texture_width, screenshot_texture_height + ); + + screenshot_thumbnail_width = screenshot_texture_width * screenshot_scale_factor; + screenshot_thumbnail_height = screenshot_texture_height * screenshot_scale_factor; + + screenshot_shotname_length = (width - screenshot_thumbnail_width - simple_widget_padding*2) / glyph_width; + + screenshot_y = -((float)screenshot_height); + + entry.cb = NULL; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &screenshot_y; + entry.tag = generic_tag; + entry.target_value = 0.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + timer.cb = menu_widgets_screenshot_end; + timer.duration = SCREENSHOT_NOTIFICATION_DURATION; + timer.userdata = NULL; + + menu_timer_start(&screenshot_timer, &timer); + + screenshot_loaded = true; + screenshot_filename[0] = '\0'; + } +} + +static int menu_widgets_draw_indicator(video_frame_info_t *video_info, + menu_texture_item icon, int y, int top_right_x_advance, + enum msg_hash_enums msg) +{ + unsigned width; + settings_t *settings = config_get_ptr(); + + color_alpha(backdrop, DEFAULT_BACKDROP); + + if (icon) + { + unsigned height = simple_widget_height * 2; + width = height; + + menu_display_draw_quad(video_info, + top_right_x_advance - width, y, + width, height, + video_info->width, video_info->height, + backdrop + ); + + color_alpha(menu_widgets_pure_white, 1.0f); + + menu_display_blend_begin(video_info); + menu_widgets_draw_icon(video_info, width, height, + icon, top_right_x_advance - width, y, + video_info->width, video_info->height, + 0, 1, menu_widgets_pure_white + ); + menu_display_blend_end(video_info); + } + else + { + unsigned height = simple_widget_height; + const char *txt = msg_hash_to_str(msg); + width = font_driver_get_message_width(font_regular, txt, strlen(txt), 1) + simple_widget_padding*2; + + menu_display_draw_quad(video_info, + top_right_x_advance - width, y, + width, height, + video_info->width, video_info->height, + backdrop + ); + + menu_display_draw_text(font_regular, + txt, + top_right_x_advance - width + simple_widget_padding, settings->floats.video_font_size + simple_widget_padding/4, + video_info->width, video_info->height, + 0xFFFFFFFF, TEXT_ALIGN_LEFT, + 1.0f, + false, 0, false + ); + } + + return width; +} + +static void menu_widgets_draw_task_msg(menu_widget_msg_t *msg, video_frame_info_t *video_info) +{ + unsigned text_color; + unsigned bar_width; + + unsigned rect_x; + unsigned rect_y; + unsigned rect_width; + unsigned rect_height; + + float *msg_queue_current_background; + float *msg_queue_current_bar; + + unsigned task_percentage_offset = 0; + char task_percentage[256] = {0}; + settings_t *settings = config_get_ptr(); + + task_percentage_offset = glyph_width * (msg->task_error ? 12 : 5) + simple_widget_padding * 1.25f; /*11 = strlen("Task failed")+1 */ + + if (msg->task_finished) + { + if (msg->task_error) + { + snprintf(task_percentage, sizeof(task_percentage), "Task failed"); + } + else + { + snprintf(task_percentage, sizeof(task_percentage), " "); + } + } + else if (msg->task_progress >= 0 && msg->task_progress <= 100) + { + snprintf(task_percentage, sizeof(task_percentage), "%i%%", msg->task_progress); + } + + rect_width = simple_widget_padding + msg->width + task_percentage_offset; + bar_width = rect_width * msg->task_progress/100.0f; + text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha*255.0f)); + + /* Rect */ + if (msg->task_finished) + if (msg->task_count == 1) + msg_queue_current_background = msg_queue_task_progress_1; + else + msg_queue_current_background = msg_queue_task_progress_2; + else + if (msg->task_count == 1) + msg_queue_current_background = msg_queue_background; + else + msg_queue_current_background = msg_queue_task_progress_1; + + rect_x = msg_queue_rect_start_x - msg_queue_icon_size_x; + rect_y = video_info->height - msg->offset_y; + rect_height = msg_queue_height/2; + + color_alpha(msg_queue_current_background, msg->alpha); + menu_display_draw_quad(video_info, + rect_x, rect_y, + rect_width, rect_height, + video_info->width, video_info->height, + msg_queue_current_background + ); + + /* Progress bar */ + if (!msg->task_finished && msg->task_progress >= 0 && msg->task_progress <= 100) + { + if (msg->task_count == 1) + msg_queue_current_bar = msg_queue_task_progress_1; + else + msg_queue_current_bar = msg_queue_task_progress_2; + + color_alpha(msg_queue_current_bar, 1.0f); + menu_display_draw_quad(video_info, + msg_queue_task_rect_start_x, video_info->height - msg->offset_y, + bar_width, rect_height, + video_info->width, video_info->height, + msg_queue_current_bar + ); + } + + /* Icon */ + color_alpha(menu_widgets_pure_white, msg->alpha); + menu_display_blend_begin(video_info); + menu_widgets_draw_icon(video_info, + msg_queue_height/2, + msg_queue_height/2, + menu_widgets_icons_textures[msg->task_finished ? MENU_WIDGETS_ICON_CHECK : MENU_WIDGETS_ICON_HOURGLASS], + msg_queue_task_hourglass_x, + video_info->height - msg->offset_y, + video_info->width, + video_info->height, + msg->task_finished ? 0 : msg->hourglass_rotation, + 1, menu_widgets_pure_white); + menu_display_blend_end(video_info); + + /* Text */ + if (msg->msg_new) + { + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_raster_regular.carr.coords.vertices = 0; + + menu_display_scissor_begin(video_info, rect_x, rect_y, rect_width, rect_height); + menu_display_draw_text(font_regular, + msg->msg_new, + msg_queue_task_text_start_x, + video_info->height - msg->offset_y + msg_queue_text_scale_factor * settings->floats.video_font_size + msg_queue_height/4 - settings->floats.video_font_size/2.25f - msg_queue_height/2 + msg->msg_transition_animation, + video_info->width, video_info->height, + text_color, + TEXT_ALIGN_LEFT, + msg_queue_text_scale_factor, + false, + 0, + true + ); + } + + menu_display_draw_text(font_regular, + msg->msg, + msg_queue_task_text_start_x, + video_info->height - msg->offset_y + msg_queue_text_scale_factor * settings->floats.video_font_size + msg_queue_height/4 - settings->floats.video_font_size/2.25f + msg->msg_transition_animation, + video_info->width, video_info->height, + text_color, + TEXT_ALIGN_LEFT, + msg_queue_text_scale_factor, + false, + 0, + true + ); + + if (msg->msg_new) + { + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_raster_regular.carr.coords.vertices = 0; + + menu_display_scissor_end(video_info); + } + + /* Progress text */ + text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha/2*255.0f)); + menu_display_draw_text(font_regular, + task_percentage, + msg_queue_rect_start_x - msg_queue_icon_size_x + rect_width - msg_queue_glyph_width, + video_info->height - msg->offset_y + msg_queue_text_scale_factor * settings->floats.video_font_size + msg_queue_height/4 - settings->floats.video_font_size/2.25f, + video_info->width, video_info->height, + text_color, + TEXT_ALIGN_RIGHT, + msg_queue_text_scale_factor, + false, + 0, + true + ); +} + +static void menu_widgets_draw_regular_msg(menu_widget_msg_t *msg, video_frame_info_t *video_info) +{ + menu_texture_item icon = 0; + + unsigned bar_width; + unsigned text_color; + + if (!icon) + icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_INFO]; /* TODO: Real icon logic here */ + + /* Icon */ + color_alpha(msg_queue_info, msg->alpha); + color_alpha(menu_widgets_pure_white, msg->alpha); + color_alpha(msg_queue_background, msg->alpha); + + if (!msg->unfolded || msg->unfolding) + { + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_driver_flush(video_info->width, video_info->height, font_bold, video_info); + + font_raster_regular.carr.coords.vertices = 0; + font_raster_bold.carr.coords.vertices = 0; + + menu_display_scissor_begin(video_info, msg_queue_scissor_start_x, 0, + (msg_queue_scissor_start_x + msg->width - simple_widget_padding*2) * msg->unfold, video_info->height); + } + + + if (msg_queue_has_icons) + { + menu_display_blend_begin(video_info); + /* (int) cast is to be consistent with the rect drawing and prevent alignment + * issues, don't remove it */ + menu_widgets_draw_icon(video_info, + msg_queue_icon_size_x, msg_queue_icon_size_y, + msg_queue_icon_rect, msg_queue_spacing, (int)(video_info->height - msg->offset_y - msg_queue_icon_offset_y), + video_info->width, video_info->height, + 0, 1, msg_queue_background); + + menu_display_blend_end(video_info); + } + + /* Background */ + bar_width = simple_widget_padding + msg->width; + + menu_display_draw_quad(video_info, + msg_queue_rect_start_x, video_info->height - msg->offset_y, + bar_width, msg_queue_height, + video_info->width, video_info->height, + msg_queue_background + ); + + /* Text */ + text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha*255.0f)); + + menu_display_draw_text(font_regular, + msg->msg, + msg_queue_regular_text_start - ((1.0f-msg->unfold) * msg->width/2), + video_info->height - msg->offset_y + msg_queue_regular_text_base_y - msg->text_height/2, + video_info->width, video_info->height, + text_color, + TEXT_ALIGN_LEFT, + msg_queue_text_scale_factor, false, 0, true + ); + + if (!msg->unfolded || msg->unfolding) + { + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_driver_flush(video_info->width, video_info->height, font_bold, video_info); + + font_raster_regular.carr.coords.vertices = 0; + font_raster_bold.carr.coords.vertices = 0; + + menu_display_scissor_end(video_info); + } + + if (msg_queue_has_icons) + { + menu_display_blend_begin(video_info); + + menu_widgets_draw_icon(video_info, + msg_queue_icon_size_x, msg_queue_icon_size_y, + msg_queue_icon, msg_queue_spacing, video_info->height - msg->offset_y - msg_queue_icon_offset_y, + video_info->width, video_info->height, + 0, 1, msg_queue_info); + + menu_widgets_draw_icon(video_info, + msg_queue_icon_size_x, msg_queue_icon_size_y, + msg_queue_icon_outline, msg_queue_spacing, video_info->height - msg->offset_y - msg_queue_icon_offset_y, + video_info->width, video_info->height, + 0, 1, menu_widgets_pure_white); + + menu_widgets_draw_icon(video_info, + msg_queue_internal_icon_size, msg_queue_internal_icon_size, + icon, msg_queue_spacing + msg_queue_internal_icon_offset, video_info->height - msg->offset_y - msg_queue_icon_offset_y + msg_queue_internal_icon_offset, + video_info->width, video_info->height, + 0, 1, menu_widgets_pure_white); + + menu_display_blend_end(video_info); + } +} + +static void menu_widgets_draw_backdrop(video_frame_info_t *video_info, float alpha) +{ + color_alpha(menu_widgets_backdrop, alpha); + menu_display_draw_quad(video_info, 0, 0, video_info->width, video_info->height, video_info->width, video_info->height, menu_widgets_backdrop); +} + +static void menu_widgets_draw_load_content_animation(video_frame_info_t *video_info) +{ + /* TODO: scale this right ? (change metrics) */ + + int icon_size = (int) load_content_animation_icon_size; + uint32_t text_alpha = load_content_animation_fade_alpha * 255.0f; + uint32_t text_color = COLOR_TEXT_ALPHA(0xB8B8B800, text_alpha); + unsigned text_offset = -25 * load_content_animation_fade_alpha; + float *icon_color = load_content_animation_icon_color; + + /* Fade out */ + menu_widgets_draw_backdrop(video_info, load_content_animation_fade_alpha); + + /* Icon */ + color_alpha(icon_color, load_content_animation_icon_alpha); + menu_display_blend_begin(video_info); + menu_widgets_draw_icon(video_info, icon_size, + icon_size, load_content_animation_icon, + video_info->width/2 - icon_size/2, + video_info->height/2 - icon_size/2, + video_info->width, + video_info->height, + 0, 1, icon_color + ); + menu_display_blend_end(video_info); + + /* Text */ + menu_display_draw_text(font_bold, + load_content_animation_content_name, + video_info->width/2, + video_info->height/2 + 175 + 25 + text_offset, + video_info->width, + video_info->height, + text_color, + TEXT_ALIGN_CENTER, + 1, + false, + 0, + false + ); + + /* Flush text layer */ + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_driver_flush(video_info->width, video_info->height, font_bold, video_info); + + font_raster_regular.carr.coords.vertices = 0; + font_raster_bold.carr.coords.vertices = 0; + + /* Everything disappears */ + menu_widgets_draw_backdrop(video_info, load_content_animation_final_fade_alpha); +} + + +void menu_widgets_frame(video_frame_info_t *video_info) +{ + int i; + int top_right_x_advance = video_info->width; + + settings_t *settings = config_get_ptr(); + + if (!init) + return; + + menu_widgets_frame_count++; + + menu_display_set_viewport(video_info->width, video_info->height); + + /* Font setup */ + font_driver_bind_block(font_regular, &font_raster_regular); + font_driver_bind_block(font_bold, &font_raster_bold); + + font_raster_regular.carr.coords.vertices = 0; + font_raster_bold.carr.coords.vertices = 0; + + /* Screenshot */ + if (screenshot_loaded) + { + char shotname[256]; + menu_animation_ctx_ticker_t ticker; + + color_alpha(backdrop, DEFAULT_BACKDROP); + + menu_display_draw_quad(video_info, + 0, screenshot_y, + screenshot_width, screenshot_height, + video_info->width, video_info->height, + backdrop + ); + + color_alpha(menu_widgets_pure_white, 1.0f); + menu_widgets_draw_icon(video_info, + screenshot_thumbnail_width, screenshot_thumbnail_height, + screenshot_texture, + 0, screenshot_y, + video_info->width, video_info->height, + 0, 1, menu_widgets_pure_white + ); + + menu_display_draw_text(font_regular, + msg_hash_to_str(MSG_SCREENSHOT_SAVED), + screenshot_thumbnail_width + simple_widget_padding, settings->floats.video_font_size * 1.9f + screenshot_y, + video_info->width, video_info->height, + text_color_faint, + TEXT_ALIGN_LEFT, + 1, false, 0, true + ); + + ticker.idx = menu_animation_get_ticker_time(); + ticker.len = screenshot_shotname_length; + ticker.s = shotname; + ticker.selected = true; + ticker.str = screenshot_shotname; + + menu_animation_ticker(&ticker); + + menu_display_draw_text(font_regular, + shotname, + screenshot_thumbnail_width + simple_widget_padding, settings->floats.video_font_size * 2.9f + screenshot_y, + video_info->width, video_info->height, + text_color_info, + TEXT_ALIGN_LEFT, + 1, false, 0, true + ); + } + + /* Volume */ + if (volume_alpha > 0.0f) + { + char msg[255]; + char percentage_msg[255]; + + menu_texture_item volume_icon = 0; + + unsigned volume_width = video_info->width / 3; + unsigned volume_height = settings->floats.video_font_size * 4; + unsigned icon_size = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MED] ? volume_height : simple_widget_padding; + unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(volume_text_alpha*255.0f)); + unsigned text_color_db = COLOR_TEXT_ALPHA(text_color_faint, (unsigned)(volume_text_alpha*255.0f)); + + unsigned bar_x = icon_size; + unsigned bar_height = settings->floats.video_font_size/2; + unsigned bar_width = volume_width - bar_x - simple_widget_padding; + unsigned bar_y = volume_height / 2 + bar_height/2; + + float *bar_background = NULL; + float *bar_foreground = NULL; + float bar_percentage = 0.0f; + + if (volume_mute) + { + volume_icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MUTE]; + } + else if (volume_percent <= 1.0f) + { + if (volume_percent <= 0.5f) + volume_icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MIN]; + else + volume_icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MED]; + + bar_background = volume_bar_background; + bar_foreground = volume_bar_normal; + bar_percentage = volume_percent; + } + else if (volume_percent > 1.0f && volume_percent <= 2.0f) + { + volume_icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MAX]; + + bar_background = volume_bar_normal; + bar_foreground = volume_bar_loud; + bar_percentage = volume_percent - 1.0f; + } + else + { + volume_icon = menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MAX]; + + bar_background = volume_bar_loud; + bar_foreground = volume_bar_loudest; + bar_percentage = volume_percent - 2.0f; + } + + if (bar_percentage > 1.0f) + bar_percentage = 1.0f; + + /* Backdrop */ + color_alpha(backdrop, volume_alpha); + + menu_display_draw_quad(video_info, + 0, 0, + volume_width, + volume_height, + video_info->width, + video_info->height, + backdrop + ); + + /* Icon */ + if (volume_icon) + { + color_alpha(menu_widgets_pure_white, volume_text_alpha); + + menu_display_blend_begin(video_info); + menu_widgets_draw_icon(video_info, + icon_size, icon_size, + volume_icon, + 0, 0, + video_info->width, video_info->height, + 0, 1, menu_widgets_pure_white + ); + menu_display_blend_end(video_info); + } + + if (volume_mute) + { + if (!menu_widgets_icons_textures[MENU_WIDGETS_ICON_VOLUME_MUTE]) + { + const char *text = msg_hash_to_str(MSG_AUDIO_MUTED); + menu_display_draw_text(font_regular, + text, + volume_width/2, volume_height/2 + settings->floats.video_font_size/3, + video_info->width, video_info->height, + text_color, TEXT_ALIGN_CENTER, + 1, false, 0, false + ); + } + } + else + { + /* Bar */ + color_alpha(bar_background, volume_text_alpha); + color_alpha(bar_foreground, volume_text_alpha); + + menu_display_draw_quad(video_info, + bar_x + bar_percentage * bar_width, bar_y, + bar_width - bar_percentage * bar_width, bar_height, + video_info->width, video_info->height, + bar_background + ); + + menu_display_draw_quad(video_info, + bar_x, bar_y, + bar_percentage * bar_width, bar_height, + video_info->width, video_info->height, + bar_foreground + ); + + /* Text */ + snprintf(msg, sizeof(msg), (volume_db >= 0 ? "+%.1f dB" : "%.1f dB"), + volume_db); + + snprintf(percentage_msg, sizeof(percentage_msg), "%d%%", + (int)(volume_percent * 100.0f)); + + menu_display_draw_text(font_regular, + msg, + volume_width - simple_widget_padding, settings->floats.video_font_size * 2, + video_info->width, video_info->height, + text_color_db, + TEXT_ALIGN_RIGHT, + 1, false, 0, false + ); + + menu_display_draw_text(font_regular, + percentage_msg, + icon_size, settings->floats.video_font_size * 2, + video_info->width, video_info->height, + text_color, + TEXT_ALIGN_LEFT, + 1, false, 0, false + ); + } + } + + /* Draw all messages */ + for (i = 0; i < current_msgs->size; i++) + { + menu_widget_msg_t *msg = file_list_get_userdata_at_offset(current_msgs, i); + + if (!msg) + continue; + + if (msg->task_ptr) + menu_widgets_draw_task_msg(msg, video_info); + else + menu_widgets_draw_regular_msg(msg, video_info); + } + + /* FPS Counter */ + if (video_info->fps_show || video_info->framecount_show) + { + char *text = *fps_text == '\0' ? "n/a" : fps_text; + + int text_width = font_driver_get_message_width(font_regular, text, strlen(text), 1.0f); + int total_width = text_width + simple_widget_padding * 2; + + color_alpha(backdrop, DEFAULT_BACKDROP); + + menu_display_draw_quad(video_info, + top_right_x_advance - total_width, 0, + total_width, simple_widget_height, + video_info->width, video_info->height, + backdrop + ); + + menu_display_draw_text(font_regular, + text, + top_right_x_advance - simple_widget_padding - text_width, settings->floats.video_font_size + simple_widget_padding/4, + video_info->width, video_info->height, + 0xFFFFFFFF, + TEXT_ALIGN_LEFT, + 1, false,0, true + ); + } + + /* Indicators */ + if (paused) + top_right_x_advance -= menu_widgets_draw_indicator(video_info, + menu_widgets_icons_textures[MENU_WIDGETS_ICON_PAUSED], (video_info->fps_show ? simple_widget_height : 0), top_right_x_advance, + MSG_PAUSED); + + if (fast_forward) + top_right_x_advance -= menu_widgets_draw_indicator(video_info, + menu_widgets_icons_textures[MENU_WIDGETS_ICON_FAST_FORWARD], (video_info->fps_show ? simple_widget_height : 0), top_right_x_advance, + MSG_PAUSED); + + if (rewinding) + top_right_x_advance -= menu_widgets_draw_indicator(video_info, + menu_widgets_icons_textures[MENU_WIDGETS_ICON_REWIND], (video_info->fps_show ? simple_widget_height : 0), top_right_x_advance, + MSG_REWINDING); + + if (video_info->runloop_is_slowmotion) + top_right_x_advance -= menu_widgets_draw_indicator(video_info, + menu_widgets_icons_textures[MENU_WIDGETS_ICON_SLOW_MOTION], (video_info->fps_show ? simple_widget_height : 0), top_right_x_advance, + MSG_SLOW_MOTION); + + /* Screenshot */ + if (screenshot_alpha > 0.0f) + { + color_alpha(menu_widgets_pure_white, screenshot_alpha); + menu_display_draw_quad(video_info, + 0, 0, + video_info->width, video_info->height, + video_info->width, video_info->height, + menu_widgets_pure_white + ); + } + + /* Load content animation */ + if (load_content_animation_running) + menu_widgets_draw_load_content_animation(video_info); + else + { + font_driver_flush(video_info->width, video_info->height, font_regular, video_info); + font_driver_flush(video_info->width, video_info->height, font_bold, video_info); + + font_raster_regular.carr.coords.vertices = 0; + font_raster_bold.carr.coords.vertices = 0; + } + + menu_display_unset_viewport(video_info->width, video_info->height); +} + +void menu_widgets_init(bool video_is_threaded) +{ + if (init) + return; + + init = true; + + if (!menu_display_init_first_driver(video_is_threaded)) + goto err; + + menu_widgets_frame_count = 0; + + fps_text[0] = '\0'; + + msg_queue = fifo_new(MSG_QUEUE_PENDING_MAX * sizeof(menu_widget_msg_t*)); + + if (!msg_queue) + goto err; + + current_msgs = (file_list_t*)calloc(1, sizeof(file_list_t)); + + if (!current_msgs) + goto err; + + file_list_reserve(current_msgs, MSG_QUEUE_ONSCREEN_MAX); + + return; +err: + menu_widgets_free(); +} + +void menu_widgets_context_reset(bool is_threaded) +{ + char xmb_path[PATH_MAX_LENGTH]; + char menu_widgets_path[PATH_MAX_LENGTH]; + char theme_path[PATH_MAX_LENGTH]; + int i; + + char monochrome_png_path[PATH_MAX_LENGTH]; + + char ozone_path[PATH_MAX_LENGTH]; + char font_path[PATH_MAX_LENGTH]; + + settings_t *settings = config_get_ptr(); + + unsigned video_info_width; + + video_driver_get_size(&video_info_width, NULL); + + /* Textures paths */ + fill_pathname_join( + menu_widgets_path, + settings->paths.directory_assets, + "menu_widgets", + sizeof(menu_widgets_path) + ); + + fill_pathname_join( + xmb_path, + settings->paths.directory_assets, + "xmb", + sizeof(xmb_path) + ); + + /* Monochrome */ + fill_pathname_join( + theme_path, + xmb_path, + "monochrome", + sizeof(theme_path) + ); + + fill_pathname_join( + monochrome_png_path, + theme_path, + "png", + sizeof(monochrome_png_path) + ); + + /* Load textures */ + /* Icons */ + for (i = 0; i < MENU_WIDGETS_ICON_LAST; i++) + { + menu_display_reset_textures_list(menu_widgets_icons_names[i], monochrome_png_path, &menu_widgets_icons_textures[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL); + } + + /* Message queue */ + menu_display_reset_textures_list("msg_queue_icon.png", menu_widgets_path, &msg_queue_icon, TEXTURE_FILTER_LINEAR, NULL, NULL); + menu_display_reset_textures_list("msg_queue_icon_outline.png", menu_widgets_path, &msg_queue_icon_outline, TEXTURE_FILTER_LINEAR, NULL, NULL); + menu_display_reset_textures_list("msg_queue_icon_rect.png", menu_widgets_path, &msg_queue_icon_rect, TEXTURE_FILTER_NEAREST, NULL, NULL); + + msg_queue_has_icons = msg_queue_icon && msg_queue_icon_outline && msg_queue_icon_rect; + + /* Fonts paths */ + fill_pathname_join( + ozone_path, + settings->paths.directory_assets, + "ozone", + sizeof(ozone_path) + ); + + /* Fonts */ + if (settings->paths.path_font[0] == '\0') + { + fill_pathname_join(font_path, ozone_path, "regular.ttf", sizeof(font_path)); + font_regular = menu_display_font_file(font_path, settings->floats.video_font_size, is_threaded); + + fill_pathname_join(font_path, ozone_path, "bold.ttf", sizeof(font_path)); + font_bold = menu_display_font_file(font_path, settings->floats.video_font_size, is_threaded); + } + else + { + font_regular = menu_display_font_file(settings->paths.path_font, settings->floats.video_font_size, is_threaded); + font_bold = menu_display_font_file(settings->paths.path_font, settings->floats.video_font_size, is_threaded); + } + + /* Metrics */ + simple_widget_padding = settings->floats.video_font_size * 2/3; + simple_widget_height = settings->floats.video_font_size + simple_widget_padding; + glyph_width = font_driver_get_message_width(font_regular, "a", 1, 1); + + msg_queue_height = settings->floats.video_font_size * 2.5f; + + if (msg_queue_has_icons) + { + msg_queue_icon_size_y = msg_queue_height * 1.2347826087f; /* original image is 280x284 */ + msg_queue_icon_size_x = 0.98591549295f * msg_queue_icon_size_y; + } + else + { + msg_queue_icon_size_x = 0; + msg_queue_icon_size_y = 0; + } + + msg_queue_text_scale_factor = 0.69f; + msg_queue_base_width = video_info_width / 4; + msg_queue_spacing = msg_queue_height / 3; + msg_queue_glyph_width = glyph_width * msg_queue_text_scale_factor; + msg_queue_rect_start_x = msg_queue_spacing + msg_queue_icon_size_x; + msg_queue_internal_icon_size = msg_queue_icon_size_y; + msg_queue_internal_icon_offset = (msg_queue_icon_size_y - msg_queue_internal_icon_size)/2; + msg_queue_icon_offset_y = (msg_queue_icon_size_y - msg_queue_height)/2; + msg_queue_scissor_start_x = msg_queue_spacing + msg_queue_icon_size_x - (msg_queue_icon_size_x * 0.28928571428f); + msg_queue_default_rect_width = msg_queue_glyph_width * 40; + + if (msg_queue_has_icons) + msg_queue_regular_padding_x = simple_widget_padding/2; + else + msg_queue_regular_padding_x = simple_widget_padding; + + msg_queue_task_rect_start_x = msg_queue_rect_start_x - msg_queue_icon_size_x; + + msg_queue_task_text_start_x = msg_queue_task_rect_start_x + msg_queue_height/2; + + if (!menu_widgets_icons_textures[MENU_WIDGETS_ICON_HOURGLASS]) + msg_queue_task_text_start_x -= msg_queue_glyph_width*2; + + msg_queue_regular_text_start = msg_queue_rect_start_x + msg_queue_regular_padding_x; + msg_queue_regular_text_base_y = settings->floats.video_font_size * msg_queue_text_scale_factor + msg_queue_height/2; + + msg_queue_task_hourglass_x = msg_queue_rect_start_x - msg_queue_icon_size_x; +} + +void menu_widgets_context_destroy() +{ + int i; + if (!init) + return; + + //TODO: Dismiss onscreen notifications that have been freed + + /* Textures */ + for (i = 0; i < MENU_WIDGETS_ICON_LAST; i++) + { + video_driver_texture_unload(&menu_widgets_icons_textures[i]); + } + + video_driver_texture_unload(&msg_queue_icon); + video_driver_texture_unload(&msg_queue_icon_outline); + video_driver_texture_unload(&msg_queue_icon_rect); + + /* Fonts */ + menu_display_font_free(font_regular); + menu_display_font_free(font_bold); + + font_regular = NULL; + font_bold = NULL; +} + +void menu_widgets_free() +{ + int i; + + init = false; + + /* Kill any pending animation */ + menu_animation_kill_by_tag(&volume_tag); + menu_animation_kill_by_tag(&generic_tag); + + /* Purge everything from the fifo */ + if (msg_queue) + { + while (fifo_read_avail(msg_queue) > 0) + { + menu_widget_msg_t *msg_widget; + + fifo_read(msg_queue, &msg_widget, sizeof(msg_widget)); + + menu_widgets_msg_queue_free(msg_widget, false); + free(msg_widget); + } + + fifo_free(msg_queue); + } + + /* Purge everything from the list */ + if (current_msgs) + { + for (i = 0; i < current_msgs->size; i++) + { + menu_widget_msg_t *msg = file_list_get_userdata_at_offset(current_msgs, i); + + menu_widgets_msg_queue_free(msg, false); + } + file_list_free(current_msgs); + } + + video_driver_texture_unload(&screenshot_texture); + + /* Font */ + video_coord_array_free(&font_raster_regular.carr); + video_coord_array_free(&font_raster_bold.carr); + + font_driver_bind_block(NULL, NULL); +} + +static void menu_widgets_volume_timer_end() +{ + menu_animation_ctx_entry_t entry; + + entry.cb = NULL; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &volume_alpha; + entry.tag = volume_tag; + entry.target_value = 0.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); + + entry.subject = &volume_text_alpha; + + menu_animation_push(&entry); +} + +bool menu_widgets_volume_update_and_show() +{ + settings_t *settings = config_get_ptr(); + bool mute = *(audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE)); + float new_volume = settings->floats.audio_volume; + menu_timer_ctx_entry_t entry; + + if (!init) + return false; + + menu_animation_kill_by_tag(&volume_tag); + + volume_db = new_volume; + volume_percent = pow(10, new_volume/20); + volume_alpha = DEFAULT_BACKDROP; + volume_text_alpha = 1.0f; + volume_mute = mute; + + entry.cb = menu_widgets_volume_timer_end; + entry.duration = VOLUME_DURATION; + entry.userdata = NULL; + + menu_timer_start(&volume_timer, &entry); + + return true; +} + +bool menu_widgets_set_fps_text(char *new_fps_text) +{ + if (!init) + return false; + + strlcpy(fps_text, new_fps_text, sizeof(fps_text)); + + return true; +} + +bool menu_widgets_set_fast_forward(bool is_fast_forward) +{ + if (!init) + return false; + + fast_forward = is_fast_forward; + + return true; +} + +bool menu_widgets_set_rewind(bool is_rewind) +{ + if (!init) + return false; + + rewinding = is_rewind; + + return true; +} + +static void menu_widgets_screenshot_fadeout(void *userdata) +{ + menu_animation_ctx_entry_t entry; + + if (!init) + return; + + entry.cb = menu_widgets_screenshot_fadeout; + entry.duration = SCREENSHOT_DURATION_OUT; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &screenshot_alpha; + entry.tag = generic_tag; + entry.target_value = 0.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +void menu_widgets_screenshot_taken(const char *shotname, const char *filename) +{ + strlcpy(screenshot_filename, filename, sizeof(screenshot_filename)); + strlcpy(screenshot_shotname, shotname, sizeof(screenshot_shotname)); +} + +void menu_widgets_take_screenshot() +{ + menu_animation_ctx_entry_t entry; + + if (!init) + return; + + entry.cb = menu_widgets_screenshot_fadeout; + entry.duration = SCREENSHOT_DURATION_IN; + entry.easing_enum = EASING_IN_QUAD; + entry.subject = &screenshot_alpha; + entry.tag = generic_tag; + entry.target_value = 1.0f; + entry.userdata = NULL; + + menu_animation_push(&entry); +} + +bool menu_widgets_task_msg_queue_push(retro_task_t *task) +{ + if (!init) + return false; + + if (task->title != NULL && !task->mute) + menu_widgets_msg_queue_push_internal(task, NULL, 0, NULL, MESSAGE_QUEUE_CATEGORY_INFO, MESSAGE_QUEUE_ICON_DEFAULT); + + return true; +} + +static void menu_widgets_end_load_content_animation(void *userdata) +{ + task_load_content_resume(); +} + +void menu_widgets_cleanup_load_content_animation() +{ + load_content_animation_running = false; + free(load_content_animation_content_name); +} + +void menu_widgets_start_load_content_animation(const char *content_name, bool remove_extension) +{ + /* TODO: finish the animation based on design, correct all timings */ + /* TODO: scale the icon correctly */ + menu_animation_ctx_entry_t entry; + menu_timer_ctx_entry_t timer_entry; + int i; + + float icon_color[16] = COLOR_HEX_TO_FLOAT(0x0473C9, 1.0f); //TODO: random color + unsigned timing = 0; + + /* Prepare data */ + load_content_animation_icon = 0; + + /* Abort animation if we don't have an icon */ + if (!menu_driver_get_load_content_animation_data(&load_content_animation_icon, + &load_content_animation_playlist_name) || !load_content_animation_icon) + { + menu_widgets_end_load_content_animation(NULL); + return; + } + + load_content_animation_content_name = strdup(content_name); + + if (remove_extension) + path_remove_extension(load_content_animation_content_name); + + /* Reset animation state */ + load_content_animation_icon_size = LOAD_CONTENT_ANIMATION_INITIAL_ICON_SIZE; + load_content_animation_icon_alpha = 0.0f; + load_content_animation_fade_alpha = 0.0f; + load_content_animation_final_fade_alpha = 0.0f; + + memcpy(load_content_animation_icon_color, icon_color, sizeof(load_content_animation_icon_color)); + + /* Setup the animation */ + entry.cb = NULL; + entry.easing_enum = EASING_OUT_QUAD; + entry.tag = (uintptr_t) NULL; + entry.userdata = NULL; + + /* Stage one: icon animation */ + /* Position */ + entry.duration = ANIMATION_LOAD_CONTENT_DURATION; + entry.subject = &load_content_animation_icon_size; + entry.target_value = LOAD_CONTENT_ANIMATION_TARGET_ICON_SIZE; + + menu_animation_push(&entry); + + /* Alpha */ + entry.subject = &load_content_animation_icon_alpha; + entry.target_value = 1.0f; + + menu_animation_push(&entry); + timing += entry.duration; + + /* Stage two: backdrop + text */ + entry.duration = ANIMATION_LOAD_CONTENT_DURATION*1.5; + entry.subject = &load_content_animation_fade_alpha; + entry.target_value = 1.0f; + + menu_animation_push_delayed(timing, &entry); + timing += entry.duration; + + /* Stage three: wait then color transition */ + timing += ANIMATION_LOAD_CONTENT_DURATION*1.5; + + entry.duration = ANIMATION_LOAD_CONTENT_DURATION*3; + + for (i = 0; i < 16; i++) + { + if (i == 3 || i == 7 || i == 11 || i == 15) + continue; + + entry.subject = &load_content_animation_icon_color[i]; + entry.target_value = menu_widgets_pure_white[i]; + + menu_animation_push_delayed(timing, &entry); + } + + timing += entry.duration; + + /* Stage four: wait then make everything disappear */ + timing += ANIMATION_LOAD_CONTENT_DURATION*2; + + entry.duration = ANIMATION_LOAD_CONTENT_DURATION*1.5; + entry.subject = &load_content_animation_final_fade_alpha; + entry.target_value = 1.0f; + + menu_animation_push_delayed(timing, &entry); + timing += entry.duration; + + /* Setup end */ + timer_entry.cb = menu_widgets_end_load_content_animation; + timer_entry.duration = timing; + timer_entry.userdata = NULL; + + menu_timer_start(&load_content_animation_end_timer, &timer_entry); + + /* Draw all the things */ + load_content_animation_running = true; +} + +bool menu_widgets_ready() +{ + return init; +} \ No newline at end of file diff --git a/menu/widgets/menu_widgets.h b/menu/widgets/menu_widgets.h new file mode 100644 index 0000000000..9c31f8dbcf --- /dev/null +++ b/menu/widgets/menu_widgets.h @@ -0,0 +1,74 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 - natinusala + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef _MENU_WIDGETS_H +#define _MENU_WIDGETS_H + +#include "../../gfx/video_driver.h" + +#include +#include + +#define DEFAULT_BACKDROP 0.75f + +#define MSG_QUEUE_PENDING_MAX 32 +#define MSG_QUEUE_ONSCREEN_MAX 4 + +#define MSG_QUEUE_ANIMATION_DURATION 330 +#define VOLUME_DURATION 3000 +#define SCREENSHOT_DURATION_IN 66 +#define SCREENSHOT_DURATION_OUT SCREENSHOT_DURATION_IN*10 +#define SCREENSHOT_NOTIFICATION_DURATION 4000 +#define TASK_FINISHED_DURATION 3000 +#define HOURGLASS_INTERVAL 5000 +#define HOURGLASS_DURATION 1000 + +void menu_widgets_init(bool video_is_threaded); +void menu_widgets_free(); +bool menu_widgets_ready(); + +bool menu_widgets_msg_queue_push(const char *msg, + unsigned duration, + char *title, + enum message_queue_icon icon, enum message_queue_category category); + +bool menu_widgets_volume_update_and_show(); + +bool menu_widgets_set_fps_text(char *fps_text); + +void menu_widgets_iterate(); + +bool menu_widgets_set_paused(bool is_paused); +bool menu_widgets_set_fast_forward(bool is_fast_forward); +bool menu_widgets_set_rewind(bool is_rewind); + +bool menu_widgets_task_msg_queue_push(retro_task_t *task); + +void menu_widgets_take_screenshot(); + +void menu_widgets_screenshot_taken(const char *shotname, const char *filename); + +void menu_widgets_start_load_content_animation(const char *content_name, bool remove_extension); +void menu_widgets_cleanup_load_content_animation(); + +void menu_widgets_context_reset(bool is_threaded); +void menu_widgets_context_destroy(); + +/* All the functions below should be called in + * the video driver - once they are all added, set + * enable_menu_widgets to true for that driver */ +void menu_widgets_frame(video_frame_info_t *video_info); + +#endif \ No newline at end of file diff --git a/movie.c b/movie.c index b6a9a94390..c88895a3eb 100644 --- a/movie.c +++ b/movie.c @@ -293,7 +293,8 @@ bool bsv_movie_init(void) bsv_movie_state.movie_playback = true; runloop_msg_queue_push(msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK), - 2, 180, false); + 2, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s.\n", msg_hash_to_str(MSG_STARTING_MOVIE_PLAYBACK)); set_granularity = true; @@ -312,13 +313,14 @@ bool bsv_movie_init(void) { runloop_msg_queue_push( msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD), - 1, 180, true); + 1, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); return ret; } - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), bsv_movie_state.movie_start_path); @@ -441,7 +443,8 @@ void bsv_movie_deinit(void) static bool bsv_movie_check_movie_playback(void) { runloop_msg_queue_push( - msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED), 2, 180, false); + msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED), 2, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED)); command_event(CMD_EVENT_BSV_MOVIE_DEINIT, NULL); @@ -459,7 +462,8 @@ static bool runloop_check_movie_record(void) return false; runloop_msg_queue_push( - msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED), 2, 180, true); + msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED), 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED)); command_event(CMD_EVENT_BSV_MOVIE_DEINIT, NULL); @@ -497,13 +501,14 @@ static bool runloop_check_movie_init(void) { runloop_msg_queue_push( msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD), - 2, 180, true); + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); return false; } - runloop_msg_queue_push(msg, 2, 180, true); + runloop_msg_queue_push(msg, 2, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); diff --git a/msg_hash.h b/msg_hash.h index 96cbbb8185..fb89883a62 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -345,6 +345,7 @@ enum msg_hash_enums MSG_MOVIE_RECORD_STOPPED, MSG_MOVIE_PLAYBACK_ENDED, MSG_TAKING_SCREENSHOT, + MSG_SCREENSHOT_SAVED, MSG_WIFI_SCAN_COMPLETE, MSG_SCANNING_WIRELESS_NETWORKS, MSG_FAILED_TO_TAKE_SCREENSHOT, diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 7e405b3afd..4dc333e80d 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_DISCORD #include @@ -638,7 +639,7 @@ static int16_t netplay_input_state(netplay_t *netplay, } } -static void netplay_announce_cb(void *task_data, void *user_data, const char *error) +static void netplay_announce_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { RARCH_LOG("[netplay] announcing netplay game... \n"); @@ -963,7 +964,7 @@ bool netplay_command(netplay_t* netplay, struct netplay_connection *connection, if (!netplay_send_raw_cmd(netplay, connection, cmd, data, sz)) return false; - runloop_msg_queue_push(success_msg, 1, 180, false); + runloop_msg_queue_push(success_msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return true; } @@ -1481,7 +1482,8 @@ bool init_netplay(void *direct_host, const char *server, unsigned port) RARCH_LOG("[netplay] %s\n", msg_hash_to_str(MSG_WAITING_FOR_CLIENT)); runloop_msg_queue_push( msg_hash_to_str(MSG_WAITING_FOR_CLIENT), - 0, 180, false); + 0, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); if (settings->bools.netplay_public_announce) netplay_announce(); @@ -1514,7 +1516,8 @@ bool init_netplay(void *direct_host, const char *server, unsigned port) runloop_msg_queue_push( msg_hash_to_str(MSG_NETPLAY_FAILED), - 0, 180, false); + 0, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return false; } diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index 708b9e4a78..dcaf4ed5ea 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -350,7 +350,7 @@ bool netplay_handshake_init(netplay_t *netplay, /* We allow the connection but warn that this could cause issues. */ dmsg = msg_hash_to_str(MSG_NETPLAY_DIFFERENT_VERSIONS); RARCH_WARN("%s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } /* We only care about platform magic if our core is quirky */ @@ -454,7 +454,7 @@ error: if (dmsg) { RARCH_ERR("%s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } return false; } @@ -488,7 +488,7 @@ static void netplay_handshake_ready(netplay_t *netplay, } RARCH_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Unstall if we were waiting for this */ if (netplay->stall == NETPLAY_STALL_NO_CONNECTION) @@ -706,7 +706,7 @@ bool netplay_handshake_pre_nick(netplay_t *netplay, msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST), sizeof(msg)); RARCH_ERR("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return false; } @@ -779,7 +779,7 @@ bool netplay_handshake_pre_password(netplay_t *netplay, msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST), sizeof(msg)); RARCH_ERR("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return false; } @@ -885,7 +885,7 @@ bool netplay_handshake_pre_info(netplay_t *netplay, /* Wrong core! */ dmsg = msg_hash_to_str(MSG_NETPLAY_DIFFERENT_CORES); RARCH_ERR("%s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* FIXME: Should still send INFO, so the other side knows what's what */ return false; } @@ -894,7 +894,7 @@ bool netplay_handshake_pre_info(netplay_t *netplay, { dmsg = msg_hash_to_str(MSG_NETPLAY_DIFFERENT_CORE_VERSIONS); RARCH_WARN("%s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -907,7 +907,7 @@ bool netplay_handshake_pre_info(netplay_t *netplay, { dmsg = msg_hash_to_str(MSG_CONTENT_CRC32S_DIFFER); RARCH_WARN("%s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -954,7 +954,7 @@ bool netplay_handshake_pre_sync(netplay_t *netplay, { const char *msg = msg_hash_to_str(MSG_NETPLAY_INCORRECT_PASSWORD); RARCH_ERR("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return false; } @@ -1069,7 +1069,7 @@ bool netplay_handshake_pre_sync(netplay_t *netplay, snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_NETPLAY_CHANGED_NICK), netplay->nick); RARCH_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } /* Now check the SRAM */ diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index 0c488bccf1..1601ca95c5 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -118,7 +118,7 @@ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection) netplay->is_connected = false; } RARCH_LOG("[netplay] %s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); socket_close(connection->fd); connection->active = false; @@ -636,7 +636,7 @@ static void announce_play_spectate(netplay_t *netplay, if (msg[0]) { RARCH_LOG("[netplay] %s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } @@ -1469,7 +1469,7 @@ static bool netplay_get_cmd(netplay_t *netplay, if (dmsg) { RARCH_LOG("[netplay] %s\n", dmsg); - runloop_msg_queue_push(dmsg, 1, 180, false); + runloop_msg_queue_push(dmsg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } break; } @@ -1775,7 +1775,7 @@ static bool netplay_get_cmd(netplay_t *netplay, snprintf(msg, sizeof(msg)-1, msg_hash_to_str(MSG_NETPLAY_PEER_PAUSED), nick); } RARCH_LOG("[netplay] %s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); break; } @@ -2014,7 +2014,7 @@ void netplay_announce_nat_traversal(netplay_t *netplay) { snprintf(msg, sizeof(msg), "%s\n", msg_hash_to_str(MSG_UPNP_FAILED)); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("[netplay] %s\n", msg); return; } @@ -2022,7 +2022,7 @@ void netplay_announce_nat_traversal(netplay_t *netplay) snprintf(msg, sizeof(msg), "%s: %s:%s\n", msg_hash_to_str(MSG_PUBLIC_ADDRESS), host, port); - runloop_msg_queue_push(msg, 1, 180, false); + runloop_msg_queue_push(msg, 1, 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("[netplay] %s\n", msg); #endif } diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 267b654b03..14560193f8 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -496,6 +496,7 @@ if [ "$HAVE_MENU" != 'no' ]; then HAVE_OZONE=no HAVE_XMB=no HAVE_STRIPES=no + HAVE_MENU_WIDGETS=no fi die : 'Notice: Hardware rendering context not available.' fi diff --git a/qb/config.params.sh b/qb/config.params.sh index 6edcccd117..4eae5f30c1 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -9,6 +9,7 @@ HAVE_SIXEL=no # Libsixel support HAVE_DEBUG=no # Enable a debug build HAVE_LIBRETRODB=yes # Libretrodb support HAVE_MENU=yes # Enable menu drivers +HAVE_MENU_WIDGETS=no # Enable menu widgets HAVE_RGUI=auto # RGUI menu HAVE_MATERIALUI=auto # MaterialUI menu HAVE_XMB=auto # XMB menu diff --git a/record/record_driver.c b/record/record_driver.c index 3d82ac45e0..af40fa5aa6 100644 --- a/record/record_driver.c +++ b/record/record_driver.c @@ -280,7 +280,8 @@ void recording_dump_frame(const void *data, unsigned width, runloop_msg_queue_push( msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE), - 1, 180, true); + 1, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); command_event(CMD_EVENT_RECORD_DEINIT, NULL); return; } diff --git a/retroarch.c b/retroarch.c index 5cb20c2be7..965373d1cc 100644 --- a/retroarch.c +++ b/retroarch.c @@ -60,7 +60,11 @@ #ifdef HAVE_MENU #include "menu/menu_driver.h" +#include "menu/menu_animation.h" #include "menu/menu_input.h" +#ifdef HAVE_MENU_WIDGETS +#include "menu/widgets/menu_widgets.h" +#endif #include "menu/widgets/menu_dialog.h" #include "menu/widgets/menu_input_dialog.h" #endif @@ -1907,7 +1911,7 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) bool threaded_enable = false; #endif task_queue_deinit(); - task_queue_init(threaded_enable, runloop_msg_queue_push); + task_queue_init(threaded_enable, runloop_task_msg_queue_push); } break; case RARCH_CTL_SET_CORE_SHUTDOWN: @@ -2429,12 +2433,30 @@ global_t *global_get_ptr(void) return &g_extern; } -void runloop_msg_queue_push(const char *msg, +void runloop_task_msg_queue_push(retro_task_t *task, const char *msg, unsigned prio, unsigned duration, bool flush) +{ +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_task_msg_queue_push(task)) +#endif + runloop_msg_queue_push(msg, prio, duration, flush, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); +} + +void runloop_msg_queue_push(const char *msg, + unsigned prio, unsigned duration, + bool flush, + char *title, + enum message_queue_icon icon, enum message_queue_category category) { runloop_ctx_msg_info_t msg_info; +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + /* People have 60FPS in mind when they use runloop_msg_queue_push */ + if (video_driver_has_widgets() && menu_widgets_msg_queue_push(msg, duration / 60 * 1000, title, icon, category)) + return; +#endif + #ifdef HAVE_THREADS runloop_msg_queue_lock(); #endif @@ -2450,7 +2472,8 @@ void runloop_msg_queue_push(const char *msg, if (runloop_msg_queue) { msg_queue_push(runloop_msg_queue, msg_info.msg, - msg_info.prio, msg_info.duration); + msg_info.prio, msg_info.duration, + title, icon, category); ui_companion_driver_msg_queue_push(msg_info.msg, msg_info.prio, msg_info.duration, msg_info.flush); @@ -2808,7 +2831,13 @@ static enum runloop_state runloop_check_state( } } -#ifdef HAVE_MENU +#if defined(HAVE_MENU) +#ifdef HAVE_MENU_WIDGETS + menu_widgets_iterate(); +#endif + + menu_animation_update(); + if (menu_is_alive) { enum menu_action action; @@ -3223,8 +3252,17 @@ static enum runloop_state runloop_check_state( /* Display the fast forward state to the user, if needed. */ if (runloop_fastmotion) - runloop_msg_queue_push( - msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false); + { +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets() || !menu_widgets_set_fast_forward(true)) +#endif + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + else + menu_widgets_set_fast_forward(false); +#endif old_button_state = new_button_state; old_hold_button_state = new_hold_button_state; @@ -3266,7 +3304,7 @@ static enum runloop_state runloop_check_state( msg_hash_to_str(MSG_STATE_SLOT), settings->ints.state_slot); - runloop_msg_queue_push(msg, 2, 180, true); + runloop_msg_queue_push(msg, 2, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("%s\n", msg); } @@ -3301,7 +3339,7 @@ static enum runloop_state runloop_check_state( if (cheevos_hardcore_active && cheevos_state_loaded_flag) { cheevos_hardcore_paused = true; - runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED), 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } if (!cheevos_hardcore_active) @@ -3309,12 +3347,23 @@ static enum runloop_state runloop_check_state( { char s[128]; unsigned t = 0; + bool rewinding = state_manager_check_rewind(BIT256_GET(current_input, RARCH_REWIND), + settings->uints.rewind_granularity, runloop_paused, s, sizeof(s), &t); s[0] = '\0'; - if (state_manager_check_rewind(BIT256_GET(current_input, RARCH_REWIND), - settings->uints.rewind_granularity, runloop_is_paused, s, sizeof(s), &t)) - runloop_msg_queue_push(s, 0, t, true); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets()) +#endif + if (state_manager_check_rewind(BIT256_GET(current_input, RARCH_REWIND), + settings->uints.rewind_granularity, runloop_is_paused, s, sizeof(s), &t)) + runloop_msg_queue_push(s, 0, t, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + + +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + menu_widgets_set_rewind(rewinding); +#endif } /* Checks if slowmotion toggle/hold was being pressed and/or held. */ @@ -3352,13 +3401,22 @@ static enum runloop_state runloop_check_state( video_driver_cached_frame(); } - if (state_manager_frame_is_reversed()) - runloop_msg_queue_push( - msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 1, 1, false); - else - runloop_msg_queue_push( - msg_hash_to_str(MSG_SLOW_MOTION), 1, 1, false); +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!video_driver_has_widgets()) + { +#endif + if (state_manager_frame_is_reversed()) + runloop_msg_queue_push( + msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 1, 1, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_SLOW_MOTION), 1, 1, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) } +#endif old_slowmotion_button_state = new_slowmotion_button_state; old_slowmotion_hold_button_state = new_slowmotion_hold_button_state; diff --git a/retroarch.h b/retroarch.h index 1fb5a2232a..feea51625b 100644 --- a/retroarch.h +++ b/retroarch.h @@ -24,6 +24,9 @@ #include #include +#include +#include + #include "core_type.h" #include "core.h" @@ -374,8 +377,15 @@ global_t *global_get_ptr(void); **/ int runloop_iterate(unsigned *sleep_ms); -void runloop_msg_queue_push(const char *msg, unsigned prio, - unsigned duration, bool flush); +void runloop_task_msg_queue_push(retro_task_t *task, const char *msg, + unsigned prio, unsigned duration, + bool flush); + +void runloop_msg_queue_push(const char *msg, + unsigned prio, unsigned duration, + bool flush, + char *title, + enum message_queue_icon icon, enum message_queue_category category); bool runloop_msg_queue_pull(const char **ret); diff --git a/runahead/run_ahead.c b/runahead/run_ahead.c index 2f07d9e5a2..771b32a209 100644 --- a/runahead/run_ahead.c +++ b/runahead/run_ahead.c @@ -218,7 +218,7 @@ void run_ahead(int runahead_count, bool useSecondary) settings_t *settings = config_get_ptr(); if (!settings->bools.run_ahead_hide_warnings) { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES), 0, 2 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } core_run(); runahead_force_input_dirty = true; @@ -258,7 +258,7 @@ void run_ahead(int runahead_count, bool useSecondary) { if (!runahead_save_state()) { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } } @@ -267,7 +267,7 @@ void run_ahead(int runahead_count, bool useSecondary) { if (!runahead_load_state()) { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } } @@ -279,7 +279,7 @@ void run_ahead(int runahead_count, bool useSecondary) if (!secondary_core_ensure_exists()) { runahead_secondary_core_available = false; - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); core_run(); runahead_force_input_dirty = true; return; @@ -296,13 +296,13 @@ void run_ahead(int runahead_count, bool useSecondary) if (!runahead_save_state()) { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_SAVE_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } if (!runahead_load_state_secondary()) { - runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true); + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_FAILED_TO_LOAD_STATE), 0, 3 * 60, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); return; } diff --git a/tasks/task_audio_mixer.c b/tasks/task_audio_mixer.c index e3b7b9ff63..cffe0913a8 100644 --- a/tasks/task_audio_mixer.c +++ b/tasks/task_audio_mixer.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../audio/audio_driver.h" @@ -74,7 +75,7 @@ static void task_audio_mixer_load_free(retro_task_t *task) } if (mixer->cb) - mixer->cb(NULL, NULL, NULL); + mixer->cb(task, NULL, NULL, NULL); } if (!string_is_empty(nbio->path)) @@ -104,7 +105,7 @@ static int cb_nbio_audio_mixer_load(void *data, size_t len) return 0; } -static void task_audio_mixer_handle_upload_ogg(void *task_data, +static void task_audio_mixer_handle_upload_ogg(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -134,7 +135,7 @@ static void task_audio_mixer_handle_upload_ogg(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_ogg_and_play(void *task_data, +static void task_audio_mixer_handle_upload_ogg_and_play(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -165,7 +166,7 @@ static void task_audio_mixer_handle_upload_ogg_and_play(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_flac(void *task_data, +static void task_audio_mixer_handle_upload_flac(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -196,7 +197,7 @@ static void task_audio_mixer_handle_upload_flac(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_flac_and_play(void *task_data, +static void task_audio_mixer_handle_upload_flac_and_play(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -227,7 +228,7 @@ static void task_audio_mixer_handle_upload_flac_and_play(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_mp3(void *task_data, +static void task_audio_mixer_handle_upload_mp3(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -258,7 +259,7 @@ static void task_audio_mixer_handle_upload_mp3(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_mp3_and_play(void *task_data, +static void task_audio_mixer_handle_upload_mp3_and_play(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -289,7 +290,7 @@ static void task_audio_mixer_handle_upload_mp3_and_play(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_mod(void *task_data, +static void task_audio_mixer_handle_upload_mod(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -320,7 +321,7 @@ static void task_audio_mixer_handle_upload_mod(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_mod_and_play(void *task_data, +static void task_audio_mixer_handle_upload_mod_and_play(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -351,7 +352,7 @@ static void task_audio_mixer_handle_upload_mod_and_play(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_wav(void *task_data, +static void task_audio_mixer_handle_upload_wav(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -382,7 +383,7 @@ static void task_audio_mixer_handle_upload_wav(void *task_data, free(user_data); } -static void task_audio_mixer_handle_upload_wav_and_play(void *task_data, +static void task_audio_mixer_handle_upload_wav_and_play(retro_task_t *task, void *task_data, void *user_data, const char *err) { audio_mixer_stream_params_t params; @@ -452,7 +453,7 @@ bool task_push_audio_mixer_load_and_play( { nbio_handle_t *nbio = NULL; struct audio_mixer_handle *mixer = NULL; - retro_task_t *t = (retro_task_t*)calloc(1, sizeof(*t)); + retro_task_t *t = task_init(); struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)calloc(1, sizeof(*user)); if (!t || !user) @@ -560,7 +561,7 @@ bool task_push_audio_mixer_load( { nbio_handle_t *nbio = NULL; struct audio_mixer_handle *mixer = NULL; - retro_task_t *t = (retro_task_t*)calloc(1, sizeof(*t)); + retro_task_t *t = task_init(); struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)calloc(1, sizeof(*user)); if (!t || !user) diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c index f81435aa3f..737a2a1f42 100644 --- a/tasks/task_autodetect.c +++ b/tasks/task_autodetect.c @@ -237,8 +237,12 @@ static void input_autoconfigure_joypad_add(config_file_t *conf, /* This will be the case if input driver is reinitialized. * No reason to spam autoconfigure messages every time. */ bool block_osd_spam = +#if defined(HAVE_LIBNX) && defined(HAVE_MENU_WIDGETS) + true; +#else input_autoconfigured[params->idx] && !string_is_empty(params->name); +#endif msg[0] = display_name[0] = device_type[0] = '\0'; @@ -651,7 +655,7 @@ found: if (hDeviceHandle == INVALID_HANDLE_VALUE) { RARCH_ERR("[Autoconf]: Can't open device for reading and writing: %d.", GetLastError()); - runloop_msg_queue_push("Bliss-Box already in use. Please make sure other programs are not using it.", 2, 300, false); + runloop_msg_queue_push("Bliss-Box already in use. Please make sure other programs are not using it.", 2, 300, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); goto done; } } @@ -910,7 +914,7 @@ static void input_autoconfigure_disconnect_handler(retro_task_t *task) bool input_autoconfigure_disconnect(unsigned i, const char *ident) { char msg[255]; - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); autoconfig_disconnect_t *state = (autoconfig_disconnect_t*)calloc(1, sizeof(*state)); if (!state || !task) @@ -987,7 +991,7 @@ bool input_autoconfigure_connect( unsigned pid) { unsigned i; - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); autoconfig_params_t *state = (autoconfig_params_t*)calloc(1, sizeof(*state)); settings_t *settings = config_get_ptr(); const char *dir_autoconf = settings ? settings->paths.directory_autoconfig : NULL; diff --git a/tasks/task_content.c b/tasks/task_content.c index b094e8b34d..cb111a310c 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -65,6 +65,9 @@ #ifdef HAVE_MENU #include "../menu/menu_driver.h" +#ifdef HAVE_MENU_WIDGETS +#include "../menu/widgets/menu_widgets.h" +#endif #endif #include "../menu/menu_shader.h" @@ -159,6 +162,11 @@ static char pending_subsystem_extensions[PATH_MAX_LENGTH]; #endif static char *pending_subsystem_roms[RARCH_MAX_SUBSYSTEM_ROMS]; +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +static bool pending_load_content_pending = false; +static bool pending_load_content_resume = false; +#endif + static int64_t content_file_read(const char *path, void **buf, int64_t *length) { #ifdef HAVE_COMPRESSION @@ -1141,7 +1149,7 @@ static bool firmware_update_status( { runloop_msg_queue_push( msg_hash_to_str(MSG_FIRMWARE), - 100, 500, true); + 100, 500, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_LOG("Load content blocked. Reason: %s\n", msg_hash_to_str(MSG_FIRMWARE)); @@ -1219,7 +1227,7 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info) { if (error_string) { - runloop_msg_queue_push(error_string, 2, 90, true); + runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", error_string); free(error_string); } @@ -1240,6 +1248,28 @@ bool task_push_start_dummy_core(content_ctx_info_t *content_info) } #ifdef HAVE_MENU +#ifdef HAVE_MENU_WIDGETS +bool task_load_content_is_pending() +{ + return pending_load_content_pending; +} + +bool task_load_content_should_resume() +{ + /* Avoid having one menu frame before running content + once the animation is finished */ + if (pending_load_content_resume) + menu_widgets_cleanup_load_content_animation(); + + return pending_load_content_resume; +} + +void task_load_content_resume() +{ + pending_load_content_resume = true; +} +#endif + bool task_push_load_content_from_playlist_from_menu( const char *core_path, const char *fullpath, @@ -1256,6 +1286,23 @@ bool task_push_load_content_from_playlist_from_menu( settings_t *settings = config_get_ptr(); rarch_system_info_t *sys_info = runloop_get_system_info(); +#ifdef HAVE_MENU_WIDGETS + if (video_driver_has_widgets() && menu_widgets_ready() && !pending_load_content_resume) + { + pending_load_content_pending = true; + + if (label) + menu_widgets_start_load_content_animation(label, false); + else + menu_widgets_start_load_content_animation(path_basename(fullpath), true); + + return true; + } + + pending_load_content_resume = false; + pending_load_content_pending = false; +#endif + content_ctx.check_firmware_before_loading = settings->bools.check_firmware_before_loading; content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL); content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL); @@ -1310,7 +1357,7 @@ bool task_push_load_content_from_playlist_from_menu( { if (error_string) { - runloop_msg_queue_push(error_string, 2, 90, true); + runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", error_string); free(error_string); } @@ -1410,7 +1457,7 @@ bool task_push_start_current_core(content_ctx_info_t *content_info) { if (error_string) { - runloop_msg_queue_push(error_string, 2, 90, true); + runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", error_string); free(error_string); } @@ -1482,6 +1529,18 @@ bool task_push_load_content_with_new_core_from_menu( global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); +#ifdef HAVE_MENU_WIDGETS + if (video_driver_has_widgets() && menu_widgets_ready() && !pending_load_content_resume) + { + pending_load_content_pending = true; + menu_widgets_start_load_content_animation(path_basename(fullpath), true); + return true; + } + + pending_load_content_resume = false; + pending_load_content_pending = false; +#endif + content_ctx.check_firmware_before_loading = settings->bools.check_firmware_before_loading; content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL); content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL); @@ -1540,7 +1599,7 @@ bool task_push_load_content_with_new_core_from_menu( { if (error_string) { - runloop_msg_queue_push(error_string, 2, 90, true); + runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", error_string); free(error_string); } @@ -1669,7 +1728,7 @@ end: { if (error_string) { - runloop_msg_queue_push(error_string, 2, 90, true); + runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); RARCH_ERR("%s\n", error_string); free(error_string); } @@ -1771,6 +1830,18 @@ bool task_push_load_content_with_current_core_from_companion_ui( retro_task_callback_t cb, void *user_data) { +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (video_driver_has_widgets() && menu_widgets_ready() && !pending_load_content_resume) + { + pending_load_content_pending = true; + menu_widgets_start_load_content_animation(path_basename(fullpath), true); + return true; + } + + pending_load_content_resume = false; + pending_load_content_pending = false; +#endif + /* Set content path */ path_set(RARCH_PATH_CONTENT, fullpath); @@ -1820,6 +1891,17 @@ bool task_push_load_subsystem_with_core_from_menu( retro_task_callback_t cb, void *user_data) { +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (video_driver_has_widgets() && menu_widgets_ready() && !pending_load_content_resume) + { + pending_load_content_pending = true; + menu_widgets_start_load_content_animation(path_basename(fullpath), true); + return true; + } + + pending_load_content_resume = false; + pending_load_content_pending = false; +#endif pending_subsystem_init = true; @@ -2112,7 +2194,7 @@ bool content_init(void) { RARCH_ERR("%s\n", error_string); } - runloop_msg_queue_push(error_string, 2, ret ? 1 : 180, true); + runloop_msg_queue_push(error_string, 2, ret ? 1 : 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); free(error_string); } diff --git a/tasks/task_content.h b/tasks/task_content.h index 8e5d552d95..868aff3e2f 100644 --- a/tasks/task_content.h +++ b/tasks/task_content.h @@ -82,6 +82,10 @@ bool task_push_load_content_with_new_core_from_companion_ui( void *user_data); #ifdef HAVE_MENU +bool task_load_content_is_pending(); +bool task_load_content_should_resume(); +void task_load_content_resume(); + bool task_push_load_content_with_new_core_from_menu( const char *core_path, const char *fullpath, diff --git a/tasks/task_database.c b/tasks/task_database.c index cd263a2bdc..a6cb1f0593 100644 --- a/tasks/task_database.c +++ b/tasks/task_database.c @@ -148,7 +148,7 @@ static int task_database_iterate_start(database_info_handle_t *db, if (!string_is_empty(msg)) { #ifdef RARCH_INTERNAL - runloop_msg_queue_push(msg, 1, 180, true); + runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #else fprintf(stderr, "msg: %s\n", msg); #endif @@ -1260,7 +1260,7 @@ static void task_database_handler(retro_task_t *task) else msg = msg_hash_to_str(MSG_SCANNING_OF_FILE_FINISHED); #ifdef RARCH_INTERNAL - runloop_msg_queue_push(msg, 0, 180, true); + runloop_msg_queue_push(msg, 0, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); #else fprintf(stderr, "msg: %s\n", msg); #endif @@ -1313,7 +1313,7 @@ bool task_push_dbscan( bool db_dir_show_hidden_files, retro_task_callback_t cb) { - retro_task_t *t = (retro_task_t*)calloc(1, sizeof(*t)); + retro_task_t *t = task_init(); db_handle_t *db = (db_handle_t*)calloc(1, sizeof(db_handle_t)); if (!t || !db) diff --git a/tasks/task_decompress.c b/tasks/task_decompress.c index e5184d6025..4810cbf822 100644 --- a/tasks/task_decompress.c +++ b/tasks/task_decompress.c @@ -271,7 +271,8 @@ bool task_push_decompress( const char *subdir, const char *valid_ext, retro_task_callback_t cb, - void *user_data) + void *user_data, + void *frontend_userdata) { char tmp[PATH_MAX_LENGTH]; const char *ext = NULL; @@ -334,11 +335,13 @@ bool task_push_decompress( s->archive.type = ARCHIVE_TRANSFER_INIT; s->userdata = (struct archive_extract_userdata*)calloc(1, sizeof(*s->userdata)); - t = (retro_task_t*)calloc(1, sizeof(*t)); + t = task_init(); if (!t) goto error; + t->frontend_userdata = frontend_userdata; + t->state = s; t->handler = task_decompress_handler; diff --git a/tasks/task_http.c b/tasks/task_http.c index 6d9b0cf110..6167b75ece 100644 --- a/tasks/task_http.c +++ b/tasks/task_http.c @@ -265,7 +265,7 @@ static void* task_push_http_transfer_generic( /* Concurrent download of the same file is not allowed */ if (task_queue_find(&find_data)) { - RARCH_LOG("[http] '%s'' is already being downloaded.\n", url); + RARCH_LOG("[http] '%s' is already being downloaded.\n", url); return NULL; } @@ -286,7 +286,7 @@ static void* task_push_http_transfer_generic( strlcpy(http->connection.url, url, sizeof(http->connection.url)); http->status = HTTP_STATUS_CONNECTION_TRANSFER; - t = (retro_task_t*)calloc(1, sizeof(*t)); + t = task_init(); if (!t) goto error; diff --git a/tasks/task_image.c b/tasks/task_image.c index 5673242da9..20168ba55d 100644 --- a/tasks/task_image.c +++ b/tasks/task_image.c @@ -291,7 +291,7 @@ bool task_push_image_load(const char *fullpath, retro_task_callback_t cb, void * { nbio_handle_t *nbio = NULL; struct nbio_image_handle *image = NULL; - retro_task_t *t = (retro_task_t*)calloc(1, sizeof(*t)); + retro_task_t *t = task_init(); if (!t) goto error_msg; diff --git a/tasks/task_netplay_find_content.c b/tasks/task_netplay_find_content.c index 7c336021a4..72ff1550d8 100644 --- a/tasks/task_netplay_find_content.c +++ b/tasks/task_netplay_find_content.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "task_content.h" #include "tasks_internal.h" @@ -53,7 +54,7 @@ typedef struct struct string_list *lpl_list; } netplay_crc_handle_t; -static void netplay_crc_scan_callback(void *task_data, +static void netplay_crc_scan_callback(retro_task_t *task, void *task_data, void *user_data, const char *error) { netplay_crc_handle_t *state = (netplay_crc_handle_t*)task_data; @@ -144,7 +145,8 @@ static void netplay_crc_scan_callback(void *task_data, string_is_empty(state->content_path) ? "content file" : "core"); runloop_msg_queue_push( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY), - 1, 480, true); + 1, 480, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } free(state); @@ -403,8 +405,7 @@ bool task_push_netplay_crc_scan(uint32_t crc, char* name, struct string_list *lpl_list = NULL; core_info_list_t *info = NULL; settings_t *settings = config_get_ptr(); - retro_task_t *task = (retro_task_t *) - calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); netplay_crc_handle_t *state = (netplay_crc_handle_t*) calloc(1, sizeof(*state)); diff --git a/tasks/task_netplay_lan_scan.c b/tasks/task_netplay_lan_scan.c index dba19116e6..4e0a3955a0 100644 --- a/tasks/task_netplay_lan_scan.c +++ b/tasks/task_netplay_lan_scan.c @@ -46,7 +46,7 @@ static void task_netplay_lan_scan_handler(retro_task_t *task) bool task_push_netplay_lan_scan(retro_task_callback_t cb) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); if (!task) return false; @@ -63,7 +63,7 @@ bool task_push_netplay_lan_scan(retro_task_callback_t cb) bool task_push_netplay_lan_scan_rooms(retro_task_callback_t cb) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); if (!task) return false; diff --git a/tasks/task_netplay_nat_traversal.c b/tasks/task_netplay_nat_traversal.c index fbec5c61cc..dc6dfc93e3 100644 --- a/tasks/task_netplay_nat_traversal.c +++ b/tasks/task_netplay_nat_traversal.c @@ -35,7 +35,7 @@ struct nat_traversal_state_data uint16_t port; }; -static void netplay_nat_traversal_callback(void *task_data, +static void netplay_nat_traversal_callback(retro_task_t *task, void *task_data, void *user_data, const char *error) { struct nat_traversal_state_data *ntsd = @@ -65,7 +65,7 @@ bool task_push_netplay_nat_traversal(void *nat_traversal_state, uint16_t port) { #ifdef HAVE_NETWORKING struct nat_traversal_state_data *ntsd; - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); if (!task) return false; diff --git a/tasks/task_overlay.c b/tasks/task_overlay.c index 7f755f6ef9..da6dfd49b0 100644 --- a/tasks/task_overlay.c +++ b/tasks/task_overlay.c @@ -775,7 +775,7 @@ bool task_push_overlay_load_default( loader->state = OVERLAY_STATUS_DEFERRED_LOAD; loader->pos_increment = (loader->size / 4) ? (loader->size / 4) : 4; - t = (retro_task_t*)calloc(1, sizeof(*t)); + t = task_init(); if (!t) goto error; diff --git a/tasks/task_powerstate.c b/tasks/task_powerstate.c index 0e0fbbfa2b..e4e783a045 100644 --- a/tasks/task_powerstate.c +++ b/tasks/task_powerstate.c @@ -18,6 +18,7 @@ #include #include "../../frontend/frontend_driver.h" #include "tasks_internal.h" +#include static int power_percent = 0; static enum frontend_powerstate state = FRONTEND_POWERSTATE_NONE; @@ -38,7 +39,7 @@ enum frontend_powerstate get_last_powerstate(int *percent) return state; } -static void task_powerstate_cb(void *task_data, +static void task_powerstate_cb(retro_task_t* task, void *task_data, void *user_data, const char *error) { powerstate_t *powerstate = (powerstate_t*)task_data; @@ -66,7 +67,7 @@ static void task_powerstate_handler(retro_task_t *task) void task_push_get_powerstate(void) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); powerstate_t *state = NULL; if (!task) diff --git a/tasks/task_save.c b/tasks/task_save.c index 155d31f2ab..957e261eef 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -507,7 +507,7 @@ bool content_undo_load_state(void) return ret; } -static void undo_save_state_cb(void *task_data, +static void undo_save_state_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { /* Wipe the save file buffer as it's intended to be one use only */ @@ -691,7 +691,7 @@ static void task_save_handler(retro_task_t *task) **/ static bool task_push_undo_save_state(const char *path, void *data, size_t size) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state)); settings_t *settings = config_get_ptr(); @@ -892,7 +892,7 @@ error: * Load a state from disk to memory. * **/ -static void content_load_state_cb(void *task_data, +static void content_load_state_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { retro_ctx_serialize_info_t serial_info; @@ -1041,7 +1041,7 @@ error: * * Called after the save state is done. Takes a screenshot if needed. **/ -static void save_state_cb(void *task_data, +static void save_state_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { save_task_state_t *state = (save_task_state_t*)task_data; @@ -1063,7 +1063,7 @@ static void save_state_cb(void *task_data, **/ static void task_push_save_state(const char *path, void *data, size_t size, bool autosave) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state)); settings_t *settings = config_get_ptr(); @@ -1105,7 +1105,7 @@ error: * Load then save a state. * **/ -static void content_load_and_save_state_cb(void *task_data, +static void content_load_and_save_state_cb(retro_task_t *task, void *task_data, void *user_data, const char *error) { load_task_data_t *load_data = (load_task_data_t*)task_data; @@ -1114,7 +1114,7 @@ static void content_load_and_save_state_cb(void *task_data, size_t size = load_data->undo_size; bool autosave = load_data->autosave; - content_load_state_cb(task_data, user_data, error); + content_load_state_cb(NULL, task_data, user_data, error); task_push_save_state(path, data, size, autosave); @@ -1134,7 +1134,7 @@ static void content_load_and_save_state_cb(void *task_data, static void task_push_load_and_save_state(const char *path, void *data, size_t size, bool load_to_backup_buffer, bool autosave) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state)); settings_t *settings = config_get_ptr(); @@ -1279,7 +1279,7 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave) bool content_load_state(const char *path, bool load_to_backup_buffer, bool autoload) { - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state)); settings_t *settings = config_get_ptr(); diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 88f732cc2c..b24c53fd0d 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -43,6 +43,10 @@ #define IMG_EXT "bmp" #endif +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) +#include "../../menu/widgets/menu_widgets.h" +#endif + #include "../defaults.h" #include "../command.h" #include "../configuration.h" @@ -70,6 +74,7 @@ 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; }; @@ -124,6 +129,11 @@ static bool screenshot_dump_direct(screenshot_task_state_t *state) bmp_type); #endif +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!state->silence) + menu_widgets_screenshot_taken(state->shotname, state->filename); +#endif + return ret; } @@ -169,7 +179,7 @@ static void task_screenshot_handler(retro_task_t *task) if (!ret) { char *msg = strdup(msg_hash_to_str(MSG_FAILED_TO_TAKE_SCREENSHOT)); - runloop_msg_queue_push(msg, 1, state->is_paused ? 1 : 180, true); + runloop_msg_queue_push(msg, 1, state->is_paused ? 1 : 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); free(msg); } } @@ -190,14 +200,13 @@ static bool screenshot_dump( char screenshot_path[PATH_MAX_LENGTH]; uint8_t *buf = NULL; settings_t *settings = config_get_ptr(); - retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); screenshot_task_state_t *state = (screenshot_task_state_t*) calloc(1, sizeof(*state)); const char *screenshot_dir = settings->paths.directory_screenshot; - char shotname[256]; struct retro_system_info system_info; - shotname[0] = '\0'; + state->shotname[0] = '\0'; screenshot_path[0] = '\0'; if (!core_get_system_info(&system_info)) @@ -249,15 +258,15 @@ static bool screenshot_dump( else screenshot_name = path_basename(name_base); - fill_str_dated_filename(shotname, screenshot_name, - IMG_EXT, sizeof(shotname)); + fill_str_dated_filename(state->shotname, screenshot_name, + IMG_EXT, sizeof(state->shotname)); } else - snprintf(shotname, sizeof(shotname), + snprintf(state->shotname, sizeof(state->shotname), "%s.png", path_basename(name_base)); fill_pathname_join(state->filename, screenshot_dir, - shotname, sizeof(state->filename)); + state->shotname, sizeof(state->filename)); } } @@ -279,6 +288,11 @@ static bool screenshot_dump( if (use_thread) { +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (video_driver_has_widgets()) + task_free_title(task); + else +#endif if (!savestate) task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); @@ -415,6 +429,11 @@ bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebu bool is_perfcnt_enable = false; bool ret = false; +#if defined(HAVE_MENU) && defined(HAVE_MENU_WIDGETS) + if (!silence) + menu_widgets_take_screenshot(); +#endif + runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); ret = take_screenshot_choice(name_base, silence, is_paused, is_idle, diff --git a/tasks/task_wifi.c b/tasks/task_wifi.c index bf945b3c36..228d665853 100644 --- a/tasks/task_wifi.c +++ b/tasks/task_wifi.c @@ -38,7 +38,7 @@ static void task_wifi_scan_handler(retro_task_t *task) bool task_push_wifi_scan(retro_task_callback_t cb) { - retro_task_t *task = (retro_task_t *)calloc(1, sizeof(*task)); + retro_task_t *task = task_init(); if (!task) return false; diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index ae3e6e639c..9ffa6e6920 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -84,7 +84,8 @@ bool task_push_decompress( const char *subdir, const char *valid_ext, retro_task_callback_t cb, - void *user_data); + void *user_data, + void *frontend_userdata); void task_file_load_handler(retro_task_t *task); diff --git a/ui/drivers/qt/ui_qt_window.cpp b/ui/drivers/qt/ui_qt_window.cpp index 8b3ca88e13..ea1150fd79 100644 --- a/ui/drivers/qt/ui_qt_window.cpp +++ b/ui/drivers/qt/ui_qt_window.cpp @@ -3131,7 +3131,7 @@ int MainWindow::onExtractArchive(QString path, QString extractionDir, QString te if (!task_push_decompress(file, dir, NULL, NULL, NULL, - cb, this)) + cb, this, NULL)) { m_updateProgressDialog->cancel(); return -1; diff --git a/wifi/drivers/connmanctl.c b/wifi/drivers/connmanctl.c index 2909ec3fb2..8fffda7e89 100644 --- a/wifi/drivers/connmanctl.c +++ b/wifi/drivers/connmanctl.c @@ -62,7 +62,7 @@ static void connmanctl_scan(void) pclose(popen("connmanctl scan wifi", "r")); - runloop_msg_queue_push("Wi-Fi scan complete.", 1, 180, true); + runloop_msg_queue_push("Wi-Fi scan complete.", 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); serv_file = popen("connmanctl services", "r"); while (fgets (line, 512, serv_file) != NULL) @@ -214,7 +214,7 @@ static bool connmanctl_connect_ssid(unsigned i, const char* passphrase) while (fgets (ln, 512, command_file) != NULL) { - runloop_msg_queue_push(ln, 1, 180, true); + runloop_msg_queue_push(ln, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } pclose(command_file);