-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[develop] Add ROM favorites and history tabs to file browser (#168)
## Description Contains the code required for showing history and favourites. There are now 3 tabs at the top of the browser display: Files, History, Favorites. When you launch a game, either rom or disk, the file path for those will be written out to an ini file called `history.ini`, which can then be reloaded quickly from the History tab Roms and Disks can be added as favorites. Select the rom or Disk as normal, then bring up the options menu (R). an option to "add to favorites" will be on the new list. Those can then be selected from the favorites tab. Currently there are limits to the number of history and favorites and that is set to 8. ## Motivation and Context Issue request for last game history and favorites from the menu GUI. ## How Has This Been Tested? Tested locally on Supercart 64 & SummerCart64, Tested last loading just a rom, just a disk and a disk and rom Tested History, loading rom, disk and rom and disk. Tested favorites using F-Zero X and expansion. ## Screenshots <!-- (if appropriate): --> ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [x] My code follows the code style of this project. - [x] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. <!--- It would be nice if you could sign off your contribution by replacing the name with your GitHub user name and GitHub email contact. --> Signed-off-by: GITHUB_USER <GITHUB_USER_EMAIL> --------- Co-authored-by: Robin Jones <[email protected]>
- Loading branch information
1 parent
0affd82
commit 0375789
Showing
18 changed files
with
839 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
#include <libdragon.h> | ||
#include <mini.c/src/mini.h> | ||
|
||
#include "bookkeeping.h" | ||
#include "utils/fs.h" | ||
#include "path.h" | ||
|
||
static char *history_path = NULL; | ||
|
||
static path_t *empty_path = NULL; | ||
static bookkeeping_t init; | ||
|
||
/** @brief Init history path */ | ||
void bookkeeping_init (char *path) { | ||
if (history_path) { | ||
free(history_path); | ||
} | ||
history_path = strdup(path); | ||
empty_path = path_create(""); | ||
} | ||
|
||
|
||
void bookkeeping_ini_load_list(bookkeeping_item_t *list, int count, mini_t *ini, const char *group) | ||
{ | ||
char buf[64]; | ||
for(int i=0; i<count; i++) { | ||
sprintf(buf,"%d_primary_path", i); | ||
list[i].primary_path = path_create(mini_get_string(ini, group, buf, "")); | ||
|
||
sprintf(buf,"%d_secondary_path", i); | ||
list[i].secondary_path = path_create(mini_get_string(ini, group, buf, "")); | ||
|
||
sprintf(buf,"%d_type", i); | ||
list[i].bookkeeping_type = mini_get_int(ini, group, buf, BOOKKEEPING_TYPE_EMPTY); | ||
} | ||
} | ||
|
||
/** @brief The history to load */ | ||
void bookkeeping_load (bookkeeping_t *history) { | ||
if (!file_exists(history_path)) { | ||
bookkeeping_save(&init); | ||
} | ||
|
||
mini_t *bookkeeping_ini = mini_try_load(history_path); | ||
bookkeeping_ini_load_list(history->history_items, HISTORY_COUNT, bookkeeping_ini, "history"); | ||
bookkeeping_ini_load_list(history->favorite_items, HISTORY_COUNT, bookkeeping_ini, "favorite"); | ||
|
||
|
||
mini_free(bookkeeping_ini); | ||
} | ||
|
||
static void bookkeeping_ini_save_list(bookkeeping_item_t *list, int count, mini_t *ini, const char *group) | ||
{ | ||
char buf[64]; | ||
for(int i=0; i<count; i++) { | ||
sprintf(buf, "%d_primary_path", i); | ||
path_t* path = list[i].primary_path; | ||
mini_set_string(ini, group, buf, path != NULL ? path_get(path) : ""); | ||
|
||
sprintf(buf, "%d_secondary_path", i); | ||
path = list[i].secondary_path; | ||
mini_set_string(ini, group, buf, path != NULL ? path_get(path) : ""); | ||
|
||
sprintf(buf,"%d_type", i); | ||
mini_set_int(ini, group, buf, list[i].bookkeeping_type); | ||
} | ||
} | ||
|
||
/** @brief The history to save */ | ||
void bookkeeping_save (bookkeeping_t *history) | ||
{ | ||
mini_t *bookkeeping_ini = mini_create(history_path); | ||
|
||
bookkeeping_ini_save_list(history->history_items, HISTORY_COUNT, bookkeeping_ini, "history"); | ||
bookkeeping_ini_save_list(history->favorite_items, FAVORITES_COUNT, bookkeeping_ini, "favorite"); | ||
|
||
mini_save(bookkeeping_ini, MINI_FLAGS_SKIP_EMPTY_GROUPS); | ||
mini_free(bookkeeping_ini); | ||
} | ||
|
||
static bool bookkeeping_item_match(bookkeeping_item_t *left, bookkeeping_item_t *right) { | ||
if(left != NULL && right != NULL) { | ||
return path_are_match(left->primary_path, right->primary_path) && path_are_match(left->secondary_path, right->secondary_path) && left->bookkeeping_type == right->bookkeeping_type; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
static void bookkeeping_clear_item(bookkeeping_item_t *item, bool leave_null) { | ||
if(item->primary_path != NULL){ | ||
path_free(item->primary_path); | ||
|
||
if(leave_null) { | ||
item->primary_path = NULL; | ||
} else { | ||
item->primary_path = path_create(""); | ||
} | ||
} | ||
if(item->secondary_path != NULL){ | ||
path_free(item->secondary_path); | ||
|
||
if(leave_null) { | ||
item->secondary_path = NULL; | ||
} else { | ||
item->secondary_path = path_create(""); | ||
} | ||
} | ||
item->bookkeeping_type = BOOKKEEPING_TYPE_EMPTY; | ||
} | ||
|
||
static void bookkeeping_copy_item(bookkeeping_item_t *source, bookkeeping_item_t *destination) { | ||
bookkeeping_clear_item(destination, true); | ||
|
||
destination->primary_path = path_clone(source->primary_path); | ||
destination->secondary_path = source->secondary_path != NULL ? path_clone(source->secondary_path) : path_create(""); | ||
destination->bookkeeping_type = source->bookkeeping_type; | ||
} | ||
|
||
static void bookkeeping_move_items_down(bookkeeping_item_t *list, int start, int end) { | ||
int current = end; | ||
|
||
do { | ||
if(current <= start || current < 0) { | ||
break; | ||
} | ||
|
||
bookkeeping_copy_item(&list[current - 1], &list[current]); | ||
current--; | ||
} while(true); | ||
} | ||
|
||
|
||
static void bookkeeping_move_items_up(bookkeeping_item_t *list, int start, int end) { | ||
int current = start; | ||
|
||
do { | ||
if(current > end) { | ||
break; | ||
} | ||
|
||
bookkeeping_copy_item(&list[current + 1], &list[current]); | ||
current++; | ||
} while(true); | ||
} | ||
|
||
|
||
static void bookkeeping_insert_top(bookkeeping_item_t *list, int count, bookkeeping_item_t *new_item) { | ||
// if it matches the top of the list already then nothing to do | ||
if(bookkeeping_item_match(&list[0], new_item)) { | ||
return; | ||
} | ||
|
||
// if the top isn't empty then we need to move things around | ||
if(list[0].bookkeeping_type != BOOKKEEPING_TYPE_EMPTY) { | ||
int found_at = -1; | ||
for(int i=1; i < count; i++) { | ||
if(bookkeeping_item_match(&list[i], new_item)){ | ||
found_at = i; | ||
break; | ||
} | ||
} | ||
|
||
if(found_at == -1) { | ||
bookkeeping_move_items_down(list, 0, count - 1); | ||
} else { | ||
bookkeeping_move_items_down(list, 0, found_at); | ||
} | ||
} | ||
|
||
bookkeeping_copy_item(new_item, &list[0]); | ||
} | ||
|
||
void bookkeeping_history_add(bookkeeping_t *bookkeeping, path_t *primary_path, path_t *secondary_path, bookkeeping_item_types_t type ) { | ||
bookkeeping_item_t new_item = { | ||
.primary_path = primary_path, | ||
.secondary_path = secondary_path, | ||
.bookkeeping_type = type | ||
}; | ||
|
||
bookkeeping_insert_top(bookkeeping->history_items, HISTORY_COUNT, &new_item); | ||
bookkeeping_save(bookkeeping); | ||
} | ||
|
||
|
||
void bookkeeping_favorite_add(bookkeeping_t *bookkeeping, path_t *primary_path, path_t *secondary_path, bookkeeping_item_types_t type ) { | ||
bookkeeping_item_t new_item = { | ||
.primary_path = primary_path, | ||
.secondary_path = secondary_path, | ||
.bookkeeping_type = type | ||
}; | ||
|
||
bookkeeping_insert_top(bookkeeping->favorite_items, FAVORITES_COUNT, &new_item); | ||
bookkeeping_save(bookkeeping); | ||
} | ||
|
||
void bookkeeping_favorite_remove(bookkeeping_t *bookkeeping, int selection) { | ||
if(bookkeeping->favorite_items[selection].bookkeeping_type != BOOKKEEPING_TYPE_EMPTY) { | ||
|
||
bookkeeping_move_items_up(bookkeeping->favorite_items, selection, FAVORITES_COUNT -1); | ||
bookkeeping_clear_item(&bookkeeping->favorite_items[FAVORITES_COUNT -1], false); | ||
|
||
bookkeeping_save(bookkeeping); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/** | ||
* @file bookkeeping.h | ||
* @brief Bookkeeping of loadded ROM's. | ||
* @ingroup menu | ||
*/ | ||
|
||
#ifndef BOOKKEEPING_H__ | ||
#define BOOKKEEPING_H__ | ||
|
||
#include "path.h" | ||
|
||
|
||
#define FAVORITES_COUNT 8 | ||
#define HISTORY_COUNT 8 | ||
|
||
typedef enum { | ||
BOOKKEEPING_TYPE_EMPTY, | ||
BOOKKEEPING_TYPE_ROM, | ||
BOOKKEEPING_TYPE_DISK, | ||
} bookkeeping_item_types_t; | ||
|
||
typedef struct { | ||
path_t *primary_path; | ||
path_t *secondary_path; | ||
|
||
bookkeeping_item_types_t bookkeeping_type; | ||
|
||
} bookkeeping_item_t; | ||
|
||
/** @brief ROM bookkeeping Structure */ | ||
typedef struct { | ||
bookkeeping_item_t history_items[HISTORY_COUNT]; | ||
|
||
bookkeeping_item_t favorite_items[HISTORY_COUNT]; | ||
} bookkeeping_t; | ||
|
||
|
||
/** @brief Init ROM bookkeeping path */ | ||
void bookkeeping_init (char *path); | ||
|
||
/** @brief The ROM bookkeeping to load */ | ||
void bookkeeping_load (bookkeeping_t *history); | ||
|
||
/** @brief The ROM bookkeeping to save */ | ||
void bookkeeping_save (bookkeeping_t *history); | ||
|
||
/** | ||
* @brief Add a ROM to the history. | ||
* | ||
* @param bookkeeping The bookkeeping structure. | ||
* @param primary_path The primary path of the ROM. | ||
* @param secondary_path The secondary path of the ROM. | ||
* @param type The type of the bookkeeping item. | ||
*/ | ||
void bookkeeping_history_add(bookkeeping_t *bookkeeping, path_t *primary_path, path_t *secondary_path, bookkeeping_item_types_t type ); | ||
|
||
/** | ||
* @brief Add a ROM to the favorites. | ||
* | ||
* @param bookkeeping The bookkeeping structure. | ||
* @param primary_path The primary path of the ROM. | ||
* @param secondary_path The secondary path of the ROM. | ||
* @param type The type of the bookkeeping item. | ||
*/ | ||
void bookkeeping_favorite_add(bookkeeping_t *bookkeeping, path_t *primary_path, path_t *secondary_path, bookkeeping_item_types_t type ); | ||
|
||
/** | ||
* @brief Remove a ROM from the favorites. | ||
* | ||
* @param bookkeeping The bookkeeping structure. | ||
* @param selection The index of the favorite item to remove. | ||
*/ | ||
void bookkeeping_favorite_remove(bookkeeping_t *bookkeeping, int selection); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.