diff --git a/Makefile b/Makefile index f31233df..8c6bed6d 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ SRCS = \ menu/components/background.c \ menu/components/boxart.c \ menu/components/common.c \ + menu/components/context_menu.c \ menu/components/file_list.c \ menu/fonts.c \ menu/menu.c \ diff --git a/src/menu/actions.c b/src/menu/actions.c index d1ab0496..98f4bd3b 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -15,7 +15,7 @@ static void actions_clear (menu_t *menu) { menu->actions.fast = false; menu->actions.enter = false; menu->actions.back = false; - menu->actions.file_info = false; + menu->actions.options = false; menu->actions.system_info = false; menu->actions.settings = false; } @@ -103,7 +103,7 @@ void actions_update (menu_t *menu) { } else if (down.c[0].B) { menu->actions.back = true; } else if (down.c[0].R) { - menu->actions.file_info = true; + menu->actions.options = true; } else if (down.c[0].L) { menu->actions.system_info = true; } else if (down.c[0].start) { diff --git a/src/menu/cart_load.c b/src/menu/cart_load.c index a8de2087..07a60a15 100644 --- a/src/menu/cart_load.c +++ b/src/menu/cart_load.c @@ -47,15 +47,10 @@ char *cart_load_convert_error_message (cart_load_err_t err) { } cart_load_err_t cart_load_n64_rom_and_save (menu_t *menu, rom_header_t *header, flashcart_progress_callback_t progress) { - if (menu->settings.use_saves_folder) { - if (create_saves_subdirectory(menu)) { - return CART_LOAD_ERR_SAVES_SUBDIR; - } - } - path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); - bool byte_swap = (header->config_flags == ROM_MID_BIG_ENDIAN); + flashcart_save_type_t save_type = convert_save_type(header); + menu->flashcart_error = flashcart_load_rom(path_get(path), byte_swap, progress); if (menu->flashcart_error != FLASHCART_OK) { path_free(path); @@ -65,9 +60,13 @@ cart_load_err_t cart_load_n64_rom_and_save (menu_t *menu, rom_header_t *header, path_ext_replace(path, "sav"); if (menu->settings.use_saves_folder) { path_push_subdir(path, SAVES_SUBDIRECTORY); + if ((save_type != FLASHCART_SAVE_TYPE_NONE) && create_saves_subdirectory(menu)) { + path_free(path); + return CART_LOAD_ERR_SAVES_SUBDIR; + } } - menu->flashcart_error = flashcart_load_save(path_get(path), convert_save_type(header)); + menu->flashcart_error = flashcart_load_save(path_get(path), save_type); if (menu->flashcart_error != FLASHCART_OK) { path_free(path); return CART_LOAD_ERR_SAVE; @@ -79,12 +78,6 @@ cart_load_err_t cart_load_n64_rom_and_save (menu_t *menu, rom_header_t *header, } cart_load_err_t cart_load_emulator (menu_t *menu, cart_load_emu_type_t emu_type, flashcart_progress_callback_t progress) { - if (menu->settings.use_saves_folder) { - if (create_saves_subdirectory(menu)) { - return CART_LOAD_ERR_SAVES_SUBDIR; - } - } - path_t *path = path_init("sd:/", EMU_LOCATION); flashcart_save_type_t save_type = FLASHCART_SAVE_TYPE_NONE; uint32_t emulated_rom_offset = 0x200000; @@ -128,6 +121,10 @@ cart_load_err_t cart_load_emulator (menu_t *menu, cart_load_emu_type_t emu_type, path_ext_replace(path, "sav"); if (menu->settings.use_saves_folder) { path_push_subdir(path, SAVES_SUBDIRECTORY); + if ((save_type != FLASHCART_SAVE_TYPE_NONE) && create_saves_subdirectory(menu)) { + path_free(path); + return CART_LOAD_ERR_SAVES_SUBDIR; + } } menu->flashcart_error = flashcart_load_save(path_get(path), save_type); diff --git a/src/menu/components.h b/src/menu/components.h index ce19af07..6ebf2463 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -37,6 +37,22 @@ void component_background_draw (void); void component_file_list_draw (entry_t *list, int entries, int selected); +typedef struct { + int count; + int selected; + struct { + const char *text; + void (*action) (menu_t *menu); + } list[]; +} component_context_menu_t; + +#define COMPONENT_CONTEXT_MENU_LIST_END { .text = NULL } + +void component_context_menu_init (component_context_menu_t *cm); +void component_context_menu_show (component_context_menu_t *cm); +bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm); +void component_context_menu_draw (component_context_menu_t *cm); + typedef struct { bool loading; surface_t *image; diff --git a/src/menu/components/constants.h b/src/menu/components/constants.h index a9012068..2faa11a7 100644 --- a/src/menu/components/constants.h +++ b/src/menu/components/constants.h @@ -79,5 +79,7 @@ #define FILE_LIST_HIGHLIGHT_COLOR RGBA32(0x3F, 0x3F, 0x3F, 0xFF) +#define CONTEXT_MENU_HIGHLIGHT_COLOR RGBA32(0x3F, 0x3F, 0x3F, 0xFF) + #endif diff --git a/src/menu/components/context_menu.c b/src/menu/components/context_menu.c new file mode 100644 index 00000000..00229f85 --- /dev/null +++ b/src/menu/components/context_menu.c @@ -0,0 +1,92 @@ +#include "../components.h" +#include "../fonts.h" +#include "constants.h" + + +void component_context_menu_init (component_context_menu_t *cm) { + cm->selected = -1; + cm->count = 0; + for (int i = 0; (cm->list[i].text) != NULL; i++) { + cm->count += 1; + } +} + +void component_context_menu_show (component_context_menu_t *cm) { + cm->selected = 0; +} + +bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm) { + if (!cm || (cm->selected < 0)) { + return false; + } + + if (menu->actions.back) { + cm->selected = -1; + } else if (menu->actions.enter) { + if (cm->list[cm->selected].action) { + cm->list[cm->selected].action(menu); + cm->selected = -1; + } + } else if (menu->actions.go_up) { + cm->selected -= 1; + if (cm->selected < 0) { + cm->selected = 0; + } + } else if (menu->actions.go_down) { + cm->selected += 1; + if (cm->selected >= cm->count) { + cm->selected = (cm->count - 1); + } + } + + return true; +} + +void component_context_menu_draw (component_context_menu_t *cm) { + if (!cm || (cm->selected < 0)) { + return; + } + + rdpq_paragraph_builder_begin( + &(rdpq_textparms_t) { + .width = VISIBLE_AREA_WIDTH, + .height = VISIBLE_AREA_HEIGHT, + .align = ALIGN_CENTER, + .valign = VALIGN_CENTER, + }, + FNT_DEFAULT, + NULL + ); + + for (int i = 0; i < cm->count; i++) { + const char *text = cm->list[i].text; + rdpq_paragraph_builder_span(text, strlen(text)); + if (cm->list[i + 1].text != NULL) { + rdpq_paragraph_builder_newline(); + } + } + + rdpq_paragraph_t *layout = rdpq_paragraph_builder_end(); + + int width = layout->bbox[2] - layout->bbox[0] + MESSAGEBOX_MARGIN; + int height = layout->bbox[3] - layout->bbox[1] + MESSAGEBOX_MARGIN; + + component_dialog_draw(width, height); + + int highlight_x0 = DISPLAY_CENTER_X - (width / 2); + int highlight_x1 = DISPLAY_CENTER_X + (width / 2); + int highlight_height = (layout->bbox[3] - layout->bbox[1]) / layout->nlines; + int highlight_y = VISIBLE_AREA_Y0 + layout->bbox[1] + ((cm->selected) * highlight_height); + + component_box_draw( + highlight_x0, + highlight_y, + highlight_x1, + highlight_y + highlight_height, + CONTEXT_MENU_HIGHLIGHT_COLOR + ); + + rdpq_paragraph_render(layout, VISIBLE_AREA_X0, VISIBLE_AREA_Y0); + + rdpq_paragraph_free(layout); +} diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index 5e0d07b7..503d5dec 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -78,7 +78,7 @@ typedef struct { bool enter; bool back; - bool file_info; + bool options; bool system_info; bool settings; } actions; diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index 95e43c9a..37375400 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -168,8 +168,57 @@ static bool pop_directory (menu_t *menu) { return false; } +void show_properties (menu_t *menu) { + menu->next_mode = MENU_MODE_FILE_INFO; +} + +void delete_entry (menu_t *menu) { + int selected = menu->browser.selected; + + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); + + if (menu->browser.entry->type == ENTRY_TYPE_DIR) { + if (directory_delete(path_get(path))) { + menu_show_error(menu, "Couldn't delete directory\nDirectory might not be empty"); + path_free(path); + return; + } + } else { + if (file_delete(path_get(path))) { + menu_show_error(menu, "Couldn't delete file"); + path_free(path); + return; + } + } + + path_free(path); + + if (load_directory(menu)) { + menu->browser.valid = false; + menu_show_error(menu, "Couldn't refresh directory contents after delete operation"); + return; + } + + menu->browser.selected = selected; + if (menu->browser.selected >= menu->browser.entries) { + menu->browser.selected = menu->browser.entries - 1; + } + menu->browser.entry = menu->browser.selected >= 0 ? &menu->browser.list[menu->browser.selected] : NULL; +} + +static component_context_menu_t entry_context_menu = { + .list = { + { .text = "Properties", .action = show_properties }, + { .text = "Delete", .action = delete_entry }, + COMPONENT_CONTEXT_MENU_LIST_END, + } +}; static void process (menu_t *menu) { + if (component_context_menu_process(menu, &entry_context_menu)) { + return; + } + int scroll_speed = menu->actions.fast ? 10 : 1; if (menu->browser.entries > 1) { @@ -216,8 +265,8 @@ static void process (menu_t *menu) { menu->browser.valid = false; menu_show_error(menu, "Couldn't open last directory"); } - } else if (menu->actions.file_info && menu->browser.entry) { - menu->next_mode = MENU_MODE_FILE_INFO; + } else if (menu->actions.options && menu->browser.entry) { + component_context_menu_show(&entry_context_menu); } else if (menu->actions.system_info) { menu->next_mode = MENU_MODE_SYSTEM_INFO; } else if (menu->actions.settings) { @@ -259,7 +308,7 @@ static void draw (menu_t *menu, surface_t *d) { ALIGN_RIGHT, VALIGN_TOP, "%s\n" "L: Settings", - menu->browser.entries == 0 ? "" : "R: Info" + menu->browser.entries == 0 ? "" : "R: Options" ); if (menu->current_time >= 0) { @@ -271,12 +320,15 @@ static void draw (menu_t *menu, surface_t *d) { ); } + component_context_menu_draw(&entry_context_menu); + rdpq_detach_show(); } void view_browser_init (menu_t *menu) { if (!menu->browser.valid) { + component_context_menu_init(&entry_context_menu); if (load_directory(menu)) { path_free(menu->browser.directory); menu->browser.directory = path_init("sd:/", ""); diff --git a/src/utils/fs.c b/src/utils/fs.c index e37ef5a4..549803a0 100644 --- a/src/utils/fs.c +++ b/src/utils/fs.c @@ -165,8 +165,9 @@ bool directory_create (char *path) { *separator++ = '\0'; } - if ((strlen(directory) > 0) && (!directory_exists(directory))) { - if (f_mkdir(directory) != FR_OK) { + if (directory[0] != '\0') { + FRESULT res = f_mkdir(directory); + if ((res != FR_OK) && (res != FR_EXIST)) { error = true; break; }