-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
History develop #168
base: develop
Are you sure you want to change the base?
History develop #168
Changes from all commits
16bbd0c
0d6fe84
724f40f
42b9bd7
7b4bf24
092b009
c2be0c2
1fecd26
05b17e8
3ad6247
77ea002
0d00291
808bc60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 *ini = mini_try_load(history_path); | ||
bookkeeping_ini_load_list(history->history_items, HISTORY_COUNT, ini, "history"); | ||
bookkeeping_ini_load_list(history->favorite_items, HISTORY_COUNT, ini, "favorite"); | ||
|
||
|
||
mini_free(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 *ini = mini_create(history_path); | ||
|
||
bookkeeping_ini_save_list(history->history_items, HISTORY_COUNT, ini, "history"); | ||
bookkeeping_ini_save_list(history->favorite_items, FAVORITES_COUNT, ini, "favorite"); | ||
|
||
mini_save(ini, MINI_FLAGS_SKIP_EMPTY_GROUPS); | ||
mini_free(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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* @file rom_history.h | ||
* @brief Menu History | ||
* @ingroup menu | ||
*/ | ||
|
||
#ifndef HISTORY_H__ | ||
#define HISTORY_H__ | ||
|
||
#include "path.h" | ||
|
||
|
||
#define FAVORITES_COUNT 5 | ||
#define HISTORY_COUNT 5 | ||
|
||
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 history Structure */ | ||
typedef struct { | ||
bookkeeping_item_t history_items[HISTORY_COUNT]; | ||
|
||
bookkeeping_item_t favorite_items[HISTORY_COUNT]; | ||
} bookkeeping_t; | ||
|
||
|
||
/** @brief Init history path */ | ||
void bookkeeping_init (char *path); | ||
|
||
/** @brief The history to load */ | ||
void bookkeeping_load (bookkeeping_t *history); | ||
|
||
/** @brief The history to save */ | ||
void bookkeeping_save (bookkeeping_t *history); | ||
|
||
void bookkeeping_history_add(bookkeeping_t *bookkeeping, path_t* primary_path, path_t* secondary_path, bookkeeping_item_types_t type ); | ||
|
||
void bookkeeping_favorite_add(bookkeeping_t *bookkeeping, path_t* primary_path, path_t* secondary_path, bookkeeping_item_types_t type ); | ||
void bookkeeping_favorite_remove(bookkeeping_t *bookkeeping, int selection); | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. given this is menu related, and particular reason why you should not just use the current There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At first I felt it was better to have them in their own file out of the way of the config.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); | ||
bookkeeping_init(path_get(path)); | ||
bookkeeping_load(&menu->bookkeeping); | ||
menu->load.load_history = -1; | ||
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 }, | ||
{ MENU_MODE_HISTORY, view_history_init, view_history_display } | ||
}; | ||
|
||
static view_t *menu_get_view (menu_mode_t id) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use the dpad / joystick e.g.
as already defined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left, Right on the D-Pad feels more accident prone, I'd personally want something more specific for the user to press like the C buttons.
I still think that left and right on the dpad should be the fast movement.