From 16bbd0c3b8620211ef720f243f8deaabefac15e6 Mon Sep 17 00:00:00 2001 From: Ross Gouldthorpe Date: Sat, 30 Nov 2024 21:24:05 +0000 Subject: [PATCH] Basic Last Game and Favorties Moved the Load last game and favorites with menu into the branch --- Makefile | 2 + src/menu/actions.c | 6 + src/menu/menu.c | 10 ++ src/menu/menu_state.h | 7 + src/menu/path.c | 11 +- src/menu/path.h | 4 +- src/menu/rom_history.c | 233 ++++++++++++++++++++++++++++++++ src/menu/rom_history.h | 35 +++++ src/menu/ui_components.h | 2 + src/menu/ui_components/common.c | 30 ++++ src/menu/views/browser.c | 19 ++- src/menu/views/favorite.c | 149 ++++++++++++++++++++ src/menu/views/load_disk.c | 10 ++ src/menu/views/load_rom.c | 18 ++- src/menu/views/views.h | 3 + 15 files changed, 532 insertions(+), 7 deletions(-) create mode 100644 src/menu/rom_history.c create mode 100644 src/menu/rom_history.h create mode 100644 src/menu/views/favorite.c diff --git a/Makefile b/Makefile index 052b3c44..f38d1d5b 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ SRCS = \ menu/path.c \ menu/png_decoder.c \ menu/rom_info.c \ + menu/rom_history.c \ menu/settings.c \ menu/sound.c \ menu/ui_components/background.c \ @@ -62,6 +63,7 @@ SRCS = \ menu/views/error.c \ menu/views/fault.c \ menu/views/file_info.c \ + menu/views/favorite.c \ menu/views/image_viewer.c \ menu/views/text_viewer.c \ menu/views/load_disk.c \ diff --git a/src/menu/actions.c b/src/menu/actions.c index 4cafbce7..156f278b 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -22,6 +22,8 @@ static void actions_clear (menu_t *menu) { menu->actions.options = false; menu->actions.settings = false; menu->actions.lz_context = false; + menu->actions.favorite = false; + menu->actions.load_last = false; } static void actions_update_direction (menu_t *menu) { @@ -109,6 +111,10 @@ static void actions_update_buttons (menu_t *menu) { menu->actions.settings = true; } else if (pressed.l || pressed.z) { menu->actions.lz_context = true; + } else if (pressed.c_left) { + menu->actions.load_last = true; + } else if (pressed.c_right) { + menu->actions.favorite = true; } } diff --git a/src/menu/menu.c b/src/menu/menu.c index 91a51a09..3603931d 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -23,6 +23,7 @@ #define MENU_DIRECTORY "/menu" #define MENU_SETTINGS_FILE "config.ini" #define MENU_CUSTOM_FONT_FILE "custom.font64" +#define MENU_HISTORY_FILE "history.ini" #define MENU_CACHE_DIRECTORY "cache" #define BACKGROUND_CACHE_FILE "background.data" @@ -70,6 +71,13 @@ static void menu_init (boot_params_t *boot_params) { settings_load(&menu->settings); path_pop(path); + path_push(path, MENU_HISTORY_FILE); + history_init(path_get(path)); + history_load(&menu->history); + menu->load.load_last = false; + menu->load.load_favorite = -1; + path_pop(path); + resolution_t resolution = { .width = 640, .height = 480, @@ -150,6 +158,8 @@ static view_t menu_views[] = { { MENU_MODE_LOAD_EMULATOR, view_load_emulator_init, view_load_emulator_display }, { MENU_MODE_ERROR, view_error_init, view_error_display }, { MENU_MODE_FAULT, view_fault_init, view_fault_display }, + { MENU_MODE_FAVORITE, view_favorite_init, view_favorite_display }, + {} }; static view_t *menu_get_view (menu_mode_t id) { diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index eaeb83ec..8d3a7b5c 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -16,6 +16,7 @@ #include "path.h" #include "rom_info.h" #include "settings.h" +#include "rom_history.h" /** @brief Menu mode enumeration */ @@ -38,6 +39,7 @@ typedef enum { MENU_MODE_ERROR, MENU_MODE_FAULT, MENU_MODE_BOOT, + MENU_MODE_FAVORITE } menu_mode_t; /** @brief File entry type enumeration */ @@ -67,6 +69,7 @@ typedef struct { const char *storage_prefix; settings_t settings; + history_t history; boot_params_t *boot_params; char *error_message; @@ -86,6 +89,8 @@ typedef struct { bool options; bool settings; bool lz_context; + bool favorite; + bool load_last; } actions; struct { @@ -103,6 +108,8 @@ typedef struct { rom_info_t rom_info; path_t *disk_path; disk_info_t disk_info; + bool load_last; + int load_favorite; } load; struct { diff --git a/src/menu/path.c b/src/menu/path.c index 59f622f2..bab60912 100644 --- a/src/menu/path.c +++ b/src/menu/path.c @@ -19,7 +19,7 @@ static void path_resize (path_t *path, size_t min_length) { assert(path->buffer != NULL); } -static path_t *path_create (const char *string) { +path_t *path_create (const char *string) { if (string == NULL) { string = ""; } @@ -141,3 +141,12 @@ void path_ext_replace (path_t *path, char *ext) { path_append(path, "."); path_append(path, ext); } + +bool path_has_value(path_t *path) { + if(path != NULL) { + if(strlen(path->buffer) > 0) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/menu/path.h b/src/menu/path.h index df2672d2..bc66e9c7 100644 --- a/src/menu/path.h +++ b/src/menu/path.h @@ -19,7 +19,7 @@ typedef struct { size_t capacity; } path_t; - +path_t *path_create (const char *string); path_t *path_init (const char *prefix, char *string); void path_free (path_t *path); path_t *path_clone (path_t *string); @@ -33,6 +33,6 @@ void path_push_subdir (path_t *path, char *string); char *path_ext_get (path_t *path); void path_ext_remove (path_t *path); void path_ext_replace (path_t *path, char *ext); - +bool path_has_value(path_t *path); #endif diff --git a/src/menu/rom_history.c b/src/menu/rom_history.c new file mode 100644 index 00000000..7f2aee58 --- /dev/null +++ b/src/menu/rom_history.c @@ -0,0 +1,233 @@ +#include +#include + +#include "rom_history.h" +#include "utils/fs.h" +#include "path.h" + +#define EMULATOR_TEST true + +static char *history_path = NULL; + +static path_t* empty_path = NULL; +static history_t init; + +/** @brief Init history path */ +void history_init (char *path) { + if (history_path) { + free(history_path); + } + history_path = strdup(path); + empty_path = path_create(""); +} + +/** @brief The history to load */ +void history_load (history_t *history) { + if (!file_exists(history_path)) { + history_save(&init); + } + + mini_t *ini = mini_try_load(history_path); + history->last_rom = path_create(mini_get_string(ini, "history", "last_rom", "")); + history->last_disk = path_create(mini_get_string(ini, "history", "last_disk", "")); + + char buffer[1024]; + + for(int i=0;ifavorites_rom[i] = path_create(buffer); +#else + sprintf(buffer,"%dfavorite_rom", i); + history->favorites_rom[i] = path_create(mini_get_string(ini, "favorite", buffer, "")); +#endif + } + + for(int i=0;ifavorites_disk[i] = path_create(buffer); +#else + sprintf(buffer,"%dfavorite_disk", i); + history->favorites_disk[i] = path_create(mini_get_string(ini, "favorite", buffer, "")); +#endif + } + + mini_free(ini); +} + +/** @brief The history to save */ +void history_save (history_t *history) +{ + mini_t *ini = mini_create(history_path); + + mini_set_string(ini, "history", "last_rom", history->last_rom != NULL ? path_get(history->last_rom) : ""); + mini_set_string(ini, "history", "last_disk", history->last_disk != NULL ? path_get(history->last_disk) : ""); + + char buf[20]; + for(int i=0;ifavorites_rom[i]; + mini_set_string(ini, "favorite", buf, path != NULL ? path_get(path) : ""); + } + + for(int i=0;ifavorites_disk[i]; + mini_set_string(ini, "favorite", buf, path != NULL ? path_get(path) : ""); + } + + mini_save(ini, MINI_FLAGS_SKIP_EMPTY_GROUPS); + mini_free(ini); +} + + + +static void history_last_rom_update(history_t *history, path_t* path) { + if(history->last_rom != NULL) { + path_free(history->last_rom); + } + + if(path != NULL) { + history->last_rom = path_clone(path); + } else { + history->last_rom = path_create(""); + } +} + + +static void history_last_disk_update(history_t *history, path_t* path) { + if(history->last_disk != NULL) { + path_free(history->last_disk); + } + + if(path != NULL) { + history->last_disk = path_clone(path); + } else { + history->last_disk = path_create(""); + } +} + +void history_last_rom_set(history_t *history, path_t* disk_path, path_t* rom_path) +{ + history_last_rom_update(history, rom_path); + history_last_disk_update(history, disk_path); + + history_save(history); +} + +static void history_favorite_insert(history_t *history, int location, path_t* rom, path_t* disk) { + if(history->favorites_rom[location]) { + path_free(history->favorites_rom[location]); + } + if(history->favorites_disk[location]) { + path_free(history->favorites_disk[location]); + } + + history->favorites_rom[location] = rom != NULL ? path_clone(rom) : path_create(""); + history->favorites_disk[location] = rom != NULL ? path_clone(disk) : path_create(""); +} + + +static void history_favorite_replace(history_t *history, int toReplace, path_t* rom, path_t* disk) { + if(history->favorites_rom[toReplace]) { + path_free(history->favorites_rom[toReplace]); + history->favorites_rom[toReplace] = NULL; + } + if(rom != NULL) { + history->favorites_rom[toReplace] = path_clone(rom); + } + + if(history->favorites_disk[toReplace]) { + path_free(history->favorites_disk[toReplace]); + history->favorites_disk[toReplace] = NULL; + } + if(disk != NULL) { + history->favorites_disk[toReplace] = path_clone(disk); + } +} + +static void history_favorite_rotate(history_t *history) +{ + for(int i=1;ifavorites_rom[i], history->favorites_disk[i]); + } + + history_favorite_replace(history, FAVORITES_COUNT -1, NULL, NULL); +} + +static bool history_favorite_check_match(path_t* left, path_t* right) { + bool matches = false; + if(left == NULL && right == NULL) { + matches = true; + } else { + if(left != NULL && right != NULL) { + matches = (strcmp(path_get(left), path_get(right)) == 0); + } + } + + return matches; +} + +static bool history_favorite_exists(history_t *history, path_t* rom, path_t* disk) { + for(int i=0;ifavorites_rom[i], rom); + bool diskMatch = history_favorite_check_match(history->favorites_disk[i], disk); + + if(romMatch && diskMatch) { + return true; + } + } + + return false; +} + +void history_favorite_add(history_t *history, path_t* rom, path_t* disk) { + // if the game is already in the favorite list then don't add again + + if(rom == NULL) { + rom = empty_path; + } + if(disk == NULL) { + disk = empty_path; + } + + if(history_favorite_exists(history, rom, disk)) { + return; + } + + // look for a free space in the list + int place = -1; + for(int i=0;i < FAVORITES_COUNT;i++) { + if(!(path_has_value(history->favorites_rom[i]) || path_has_value(history->favorites_disk[i]))) { + place = i; + break; + } + } + + // if no free space then rotate the favorite list (first in first out) + // and set the place to add at the end of the list + if(place == -1) { + history_favorite_rotate(history); + place = FAVORITES_COUNT - 1; + } + + history_favorite_insert(history, place, rom, disk); + history_save(history); +} + +void history_favorite_remove(history_t *history, int location) +{ + if(location >= 0 && location < FAVORITES_COUNT) { + if(path_has_value(history->favorites_rom[location])) { + path_free(history->favorites_rom[location]); + history->favorites_rom[location] = path_create(""); + } + + if(path_has_value(history->favorites_disk[location])) { + path_free(history->favorites_disk[location]); + history->favorites_disk[location] = path_create(""); + } + } +} \ No newline at end of file diff --git a/src/menu/rom_history.h b/src/menu/rom_history.h new file mode 100644 index 00000000..ecbf7d8f --- /dev/null +++ b/src/menu/rom_history.h @@ -0,0 +1,35 @@ +/** + * @file rom_history.h + * @brief Menu History + * @ingroup menu + */ + +#ifndef HISTORY_H__ +#define HISTORY_H__ + +#include "path.h" + +#define FAVORITES_COUNT 5 + +/** @brief Settings Structure */ +typedef struct { + path_t* last_rom; + path_t* last_disk; + + path_t* favorites_rom[FAVORITES_COUNT]; + path_t* favorites_disk[FAVORITES_COUNT]; +} history_t; + +/** @brief Init history path */ +void history_init (char *path); +/** @brief The history to load */ +void history_load (history_t *history); +/** @brief The history to save */ +void history_save (history_t *history); + +void history_last_rom_set(history_t *history, path_t* disk_path, path_t* rom_path); + +void history_favorite_add(history_t *history, path_t* rom, path_t* disk); +void history_favorite_remove(history_t *history, int location); + +#endif \ No newline at end of file diff --git a/src/menu/ui_components.h b/src/menu/ui_components.h index f0dc6060..b80cd081 100644 --- a/src/menu/ui_components.h +++ b/src/menu/ui_components.h @@ -252,4 +252,6 @@ void ui_components_boxart_free(component_boxart_t *b); */ void ui_components_boxart_draw(component_boxart_t *b); + +void ui_components_main_text_draw_location (float x, float y, char *fmt, ...); #endif /* UI_COMPONENTS_H__ */ diff --git a/src/menu/ui_components/common.c b/src/menu/ui_components/common.c index dec31885..47d5efb1 100644 --- a/src/menu/ui_components/common.c +++ b/src/menu/ui_components/common.c @@ -195,3 +195,33 @@ void ui_components_actions_bar_text_draw (rdpq_align_t align, rdpq_valign_t vali free(formatted); } } + +void ui_components_main_text_draw_location (float x, float y, char *fmt, ...) { + char buffer[1024]; + size_t nbytes = sizeof(buffer); + + va_list va; + va_start(va, fmt); + char *formatted = vasnprintf(buffer, &nbytes, fmt, va); + va_end(va); + + rdpq_text_printn( + &(rdpq_textparms_t) { + .width = VISIBLE_AREA_WIDTH - (TEXT_MARGIN_HORIZONTAL * 2), + .height = LAYOUT_ACTIONS_SEPARATOR_Y - OVERSCAN_HEIGHT - (TEXT_MARGIN_VERTICAL * 2), + .align = ALIGN_LEFT, + .valign = VALIGN_TOP, + .wrap = WRAP_ELLIPSES, + .line_spacing = TEXT_LINE_SPACING_ADJUST, + }, + FNT_DEFAULT, + VISIBLE_AREA_X0 + TEXT_MARGIN_HORIZONTAL + x, + VISIBLE_AREA_Y0 + TEXT_MARGIN_VERTICAL + TEXT_OFFSET_VERTICAL + y, + formatted, + nbytes + ); + + if (formatted != buffer) { + free(formatted); + } +} diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index abe86b59..5065f4ea 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -358,6 +358,19 @@ static void process (menu_t *menu) { } else if (menu->actions.settings) { ui_components_context_menu_show(&settings_context_menu); sound_play_effect(SFX_SETTING); + } else if (menu->actions.favorite) { + menu->next_mode = MENU_MODE_FAVORITE; + sound_play_effect(SFX_ENTER); + } else if (menu->actions.load_last) { + if(path_has_value(menu->history.last_disk)) { + menu->load.load_last = true; + menu->next_mode = MENU_MODE_LOAD_DISK; + sound_play_effect(SFX_ENTER); + } else if (path_has_value(menu->history.last_rom)) { + menu->load.load_last = true; + menu->next_mode = MENU_MODE_LOAD_ROM; + sound_play_effect(SFX_ENTER); + } } } @@ -403,12 +416,16 @@ static void draw (menu_t *menu, surface_t *d) { if (menu->current_time >= 0) { ui_components_actions_bar_text_draw( ALIGN_CENTER, VALIGN_TOP, - "\n" "%s", ctime(&menu->current_time) ); } + ui_components_actions_bar_text_draw( + ALIGN_CENTER, VALIGN_BOTTOM, + " Favorite" + ); + ui_components_context_menu_draw(&entry_context_menu); ui_components_context_menu_draw(&settings_context_menu); diff --git a/src/menu/views/favorite.c b/src/menu/views/favorite.c new file mode 100644 index 00000000..9c036847 --- /dev/null +++ b/src/menu/views/favorite.c @@ -0,0 +1,149 @@ +#include +#include "views.h" +#include "../rom_history.h" +#include "../fonts.h" +#include "../ui_components/constants.h" +#include "../sound.h" + +static int selected_favorite = -1; + +static void favorite_reset_selected(menu_t* menu) { + selected_favorite = -1; + + for(int i=0;ihistory.favorites_rom[i]) || path_has_value(menu->history.favorites_disk[i])) { + selected_favorite = i; + break; + } + } +} + +static void process(menu_t* menu) { + if (menu->actions.back) { + menu->next_mode = MENU_MODE_BROWSER; + } else if(menu->actions.go_down) { + int last_favorite = selected_favorite; + + do + { + selected_favorite++; + + if(selected_favorite >= FAVORITES_COUNT) { + selected_favorite = last_favorite; + break; + } else if(path_has_value(menu->history.favorites_rom[selected_favorite]) || path_has_value(menu->history.favorites_disk[selected_favorite])) { + sound_play_effect(SFX_CURSOR); + break; + } + } while (true); + } else if(menu->actions.go_up) { + int last_favorite = selected_favorite; + + do + { + selected_favorite--; + + if(selected_favorite < 0) { + selected_favorite = last_favorite; + break; + } else if(path_has_value(menu->history.favorites_rom[selected_favorite]) || path_has_value(menu->history.favorites_disk[selected_favorite])) { + sound_play_effect(SFX_CURSOR); + break; + } + } while (true); + } else if(menu->actions.enter && selected_favorite != -1) { + menu->load.load_favorite = selected_favorite; + + if(path_has_value(menu->history.favorites_disk[selected_favorite])) { + menu->next_mode = MENU_MODE_LOAD_DISK; + sound_play_effect(SFX_ENTER); + } else if(path_has_value(menu->history.favorites_rom[selected_favorite])) { + menu->next_mode = MENU_MODE_LOAD_ROM; + sound_play_effect(SFX_ENTER); + } + } else if(menu->actions.options && selected_favorite != -1) { + history_favorite_remove(&menu->history, selected_favorite); + favorite_reset_selected(menu); + sound_play_effect(SFX_SETTING); + } +} + +static void draw_favorites(menu_t *menu, surface_t *display) { + + float y = 24; + float x = 10; + + if(selected_favorite != -1) { + float highlight_y = 32 + y + (selected_favorite * 16 * 2); + + ui_components_box_draw( + VISIBLE_AREA_X0, + highlight_y, + VISIBLE_AREA_X0 + FILE_LIST_HIGHLIGHT_WIDTH, + highlight_y + 32, + FILE_LIST_HIGHLIGHT_COLOR + ); + } + + for(int i=0;i < FAVORITES_COUNT; i++) + { + ui_components_main_text_draw_location(x, y, "%d :", (i+1)); + if(path_has_value(menu->history.favorites_rom[i])) { + ui_components_main_text_draw_location(x + 64, y, "%s", path_last_get(menu->history.favorites_rom[i])); + } + y += 16; + + if(path_has_value(menu->history.favorites_disk[i])) { + ui_components_main_text_draw_location(x + 64, y,"%s", path_last_get(menu->history.favorites_disk[i])); + } + y += 16; + } +} + +static void draw(menu_t *menu, surface_t *display) { + rdpq_attach(display, NULL); + + ui_components_background_draw(); + + ui_components_layout_draw(); + + ui_components_main_text_draw( + ALIGN_CENTER, VALIGN_TOP, + "Favorites"); + + draw_favorites(menu, display); + + if(selected_favorite != -1) { + ui_components_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "A: Load Favorite\n" + "B: Exit" + ); + + ui_components_actions_bar_text_draw( + ALIGN_RIGHT, VALIGN_TOP, + "R: Remove Favorite" + ); + } else { + ui_components_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "B: Exit" + ); + } + + + rdpq_detach_show(); +} + + + + +void view_favorite_init (menu_t *menu) { + favorite_reset_selected(menu); +} + +void view_favorite_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} \ No newline at end of file diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index c1e24a79..c527814e 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -3,6 +3,7 @@ #include "boot/boot.h" #include "../sound.h" #include "views.h" +#include "../rom_history.h" static bool load_disk_with_rom; @@ -39,6 +40,8 @@ static void process (menu_t *menu) { } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; + } else if (menu->actions.favorite) { + history_favorite_add(&menu->history, menu->load.rom_path, NULL); } } @@ -86,6 +89,12 @@ static void draw (menu_t *menu, surface_t *d) { "B: Exit" ); + ui_components_actions_bar_text_draw( + ALIGN_CENTER, VALIGN_TOP, + "\n" + "C>: Favorite" + ); + if (menu->load.rom_path) { ui_components_actions_bar_text_draw( ALIGN_RIGHT, VALIGN_TOP, @@ -132,6 +141,7 @@ static void load (menu_t *menu) { return; } + history_last_rom_set(&menu->history, menu->load.rom_path, menu->load.disk_path); menu->next_mode = MENU_MODE_BOOT; if (load_disk_with_rom) { diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index fb95003f..3f73c9f7 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -5,9 +5,11 @@ #include "views.h" #include #include "utils/fs.h" +#include "../rom_history.h" static bool show_extra_info_message = false; static component_boxart_t *boxart; +static char* name = NULL; static char *convert_error_message (rom_err_t err) { switch (err) { @@ -240,7 +242,7 @@ static void draw (menu_t *menu, surface_t *d) { "N64 ROM information\n" "\n" "%s", - menu->browser.entry->name + name ); ui_components_main_text_draw( @@ -334,6 +336,8 @@ static void load (menu_t *menu) { return; } + history_last_rom_set(&menu->history, menu->load.rom_path, NULL); + menu->next_mode = MENU_MODE_BOOT; menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM; @@ -359,8 +363,16 @@ void view_load_rom_init (menu_t *menu) { path_free(menu->load.rom_path); } - menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); - } + if(menu->load.load_last) { + menu->load.rom_path = path_clone(menu->history.last_rom); + } else if(menu->load.load_favorite != -1) { + menu->load.rom_path = path_clone(menu->history.favorites_rom[menu->load.load_favorite]); + } else { + menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); + } + + name = path_last_get(menu->load.rom_path); + } rom_err_t err = rom_info_load(menu->load.rom_path, &menu->load.rom_info); if (err != ROM_OK) { diff --git a/src/menu/views/views.h b/src/menu/views/views.h index 8c475280..522b63b1 100644 --- a/src/menu/views/views.h +++ b/src/menu/views/views.h @@ -65,7 +65,10 @@ void view_error_display (menu_t *menu, surface_t *display); void view_fault_init (menu_t *menu); void view_fault_display (menu_t *menu, surface_t *display); +void view_favorite_init (menu_t *menu); + void menu_show_error (menu_t *menu, char *error_message); +void view_favorite_display (menu_t *menu, surface_t *display); /** @} */ /* view */