diff --git a/config_spec.yml b/config_spec.yml index 3e36d1e5c67..c3780f2db0a 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -19,6 +19,11 @@ general: f7: string f8: string filter_current_game: bool + recent: + discs: + type: array + items: + type: string input: bindings: diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index e76e6144292..4f6e5c0b05a 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -24,6 +24,8 @@ #include "../xemu-notifications.h" #include "snapshot-manager.hh" +static const unsigned int MAX_RECENT_DISCS = 10; + void ActionEjectDisc(void) { Error *err = NULL; @@ -57,6 +59,49 @@ void ActionLoadDiscFile(const char *file_path) if (err) { xemu_queue_error_message(error_get_pretty(err)); error_free(err); + } else { + if (!g_config.general.recent.discs) { + g_config.general.recent.discs = g_new0(const char *, 1); + g_config.general.recent.discs_count = 0; + } + + // If current disc entry is already in history, + // collapse other entries down, + // then move the current entry to the slot at the top. + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + if (g_strcmp0(g_config.general.recent.discs[i], file_path) == 0) { + const char *current_path = g_config.general.recent.discs[i]; + for (unsigned int j = i; j > 0; j--) { + g_config.general.recent.discs[j] = + g_config.general.recent.discs[j - 1]; + } + g_config.general.recent.discs[0] = current_path; + return; + } + } + // Free a slot for our entry. + if (g_config.general.recent.discs_count >= MAX_RECENT_DISCS) { + for (unsigned i = MAX_RECENT_DISCS; + i < g_config.general.recent.discs_count; i++) { + g_free((void *)g_config.general.recent.discs[i]); + } + + g_free((void *)g_config.general.recent.discs[MAX_RECENT_DISCS - 1]); + g_config.general.recent.discs_count = MAX_RECENT_DISCS; + } else { + // Allocate new space. + const char **new_discs = + g_renew(const char *, g_config.general.recent.discs, + g_config.general.recent.discs_count + 1); + g_config.general.recent.discs = new_discs; + g_config.general.recent.discs_count++; + } + + for (unsigned i = g_config.general.recent.discs_count - 1; i > 0; i--) { + g_config.general.recent.discs[i] = + g_config.general.recent.discs[i - 1]; + } + g_config.general.recent.discs[0] = g_strdup(file_path); } } @@ -81,7 +126,7 @@ void ActionShutdown(void) void ActionScreenshot(void) { - g_screenshot_pending = true; + g_screenshot_pending = true; } void ActionActivateBoundSnapshot(int slot, bool save) @@ -112,3 +157,13 @@ void ActionLoadSnapshotChecked(const char *name) { g_snapshot_mgr.LoadSnapshotChecked(name); } + +void ActionClearDiscRecent(void) +{ + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + g_free((void *)g_config.general.recent.discs[i]); + } + g_free(g_config.general.recent.discs); + g_config.general.recent.discs = NULL; + g_config.general.recent.discs_count = 0; +} diff --git a/ui/xui/actions.hh b/ui/xui/actions.hh index d0aff3fd230..d4619b476e5 100644 --- a/ui/xui/actions.hh +++ b/ui/xui/actions.hh @@ -27,3 +27,4 @@ void ActionShutdown(); void ActionScreenshot(); void ActionActivateBoundSnapshot(int slot, bool save); void ActionLoadSnapshotChecked(const char *name); +void ActionClearDiscRecent(void); diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index 799f0da1c74..7091fd99bf9 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -142,6 +142,30 @@ void ShowMainMenu() if (ImGui::MenuItem("Eject Disc", SHORTCUT_MENU_TEXT(E))) ActionEjectDisc(); if (ImGui::MenuItem("Load Disc...", SHORTCUT_MENU_TEXT(O))) ActionLoadDisc(); + bool has_any_entries = (g_config.general.recent.discs_count > 0); + if (ImGui::BeginMenu("Recent Discs", has_any_entries)) { + + for (unsigned i = 0; i < g_config.general.recent.discs_count; i++) { + const char *disc_path = g_config.general.recent.discs[i]; + const char *filename = g_path_get_basename(disc_path); + + if (ImGui::MenuItem(filename)) + { + ActionLoadDiscFile(disc_path); + } + + g_free((void *)filename); + } + + ImGui::Separator(); + if (ImGui::MenuItem("Clear Recent Discs")) + { + ActionClearDiscRecent(); + } + + ImGui::EndMenu(); + } + ImGui::Separator(); if (ImGui::MenuItem("Settings...")) g_main_menu.ShowSettings();