From 732165153bf0a45b882a2395ad6c53a8fd103921 Mon Sep 17 00:00:00 2001 From: windows-server-2003 Date: Sat, 8 Sep 2018 17:31:54 +0900 Subject: [PATCH] Implemented new file selector --- arm9/source/common/colors.h | 1 + arm9/source/common/ui.c | 90 ++++++++++++++++++++++++++++++++ arm9/source/common/ui.h | 2 + arm9/source/filesys/fsutil.c | 31 ++++++----- arm9/source/filesys/fsutil.h | 2 +- arm9/source/filesys/support.c | 2 +- arm9/source/godmode.c | 1 - arm9/source/utils/scripting.c | 9 ++-- resources/sample/HelloScript.gm9 | 2 + 9 files changed, 119 insertions(+), 21 deletions(-) diff --git a/arm9/source/common/colors.h b/arm9/source/common/colors.h index d0e0e67..cb888eb 100644 --- a/arm9/source/common/colors.h +++ b/arm9/source/common/colors.h @@ -44,6 +44,7 @@ #define COLOR_FILE COLOR_TINTEDGREEN #define COLOR_DIR COLOR_TINTEDBLUE #define COLOR_ROOT COLOR_GREY +#define COLOR_ENTRY(e) (((e)->marked) ? COLOR_MARKED : ((e)->type == T_DIR) ? COLOR_DIR : ((e)->type == T_FILE) ? COLOR_FILE : ((e)->type == T_ROOT) ? COLOR_ROOT : COLOR_GREY) // hex viewer colors #define COLOR_HVOFFS RGB(0x40, 0x60, 0x50) diff --git a/arm9/source/common/ui.c b/arm9/source/common/ui.c index f1f2dec..30ecb33 100644 --- a/arm9/source/common/ui.c +++ b/arm9/source/common/ui.c @@ -598,6 +598,96 @@ u32 ShowSelectPrompt(u32 n, const char** options, const char *format, ...) { return (sel >= n) ? 0 : sel + 1; } +u32 ShowFileScrollPrompt(u32 n, const DirEntry** options, bool hide_ext, const char *format, ...) { + u32 str_height, fname_len; + u32 x, y, yopt; + const u32 item_width = SCREEN_WIDTH(MAIN_SCREEN) - 40; + int sel = 0, scroll = 0; + u32 n_show = min(n, 10); + + char str[STRBUF_SIZE] = { 0 }; + va_list va; + va_start(va, format); + vsnprintf(str, STRBUF_SIZE, format, va); + va_end(va); + + if (n == 0) return 0; // check for low number of options + // else if (n == 1) return ShowPrompt(true, "%s\n%s?", str, options[0]) ? 1 : 0; + + str_height = GetDrawStringHeight(str) + (n_show * (line_height + 2)) + (4 * line_height); + x = (SCREEN_WIDTH_MAIN - item_width) / 2; + y = (str_height >= SCREEN_HEIGHT) ? 0 : (SCREEN_HEIGHT - str_height) / 2; + yopt = y + GetDrawStringHeight(str) + 8; + fname_len = min(64, item_width / FONT_WIDTH_EXT - 14); + + ClearScreenF(true, false, COLOR_STD_BG); + DrawStringF(MAIN_SCREEN, x, y, COLOR_STD_FONT, COLOR_STD_BG, "%s", str); + DrawStringF(MAIN_SCREEN, x, yopt + (n_show*(line_height+2)) + line_height, COLOR_STD_FONT, COLOR_STD_BG, "( select, cancel)"); + while (true) { + for (u32 i = scroll; i < scroll+n_show; i++) { + char bytestr[16]; + FormatBytes(bytestr, options[i]->size); + + char content_str[64 + 1]; + char temp_str[256]; + strncpy(temp_str, options[i]->name, 255); + + char* dot = strrchr(temp_str, '.'); + if (hide_ext && dot) *dot = '\0'; + + ResizeString(content_str, temp_str, fname_len, 8, false); + + DrawStringF(MAIN_SCREEN, x, yopt + ((line_height+2)*(i-scroll)), + (sel == (int)i) ? COLOR_STD_FONT : COLOR_ENTRY(options[i]), COLOR_STD_BG, "%2.2s %s", + (sel == (int)i) ? "->" : "", content_str); + + DrawStringF(MAIN_SCREEN, x + item_width - font_width * 11, yopt + ((line_height+2)*(i-scroll)), + (sel == (int)i) ? COLOR_STD_FONT : COLOR_ENTRY(options[i]), COLOR_STD_BG, "%10.10s", + (options[i]->type == T_DIR) ? "(dir)" : (options[i]->type == T_DOTDOT) ? "(..)" : bytestr); + } + // show [n more] + if (n - n_show - scroll) { + char more_str[64 + 1]; + snprintf(more_str, 64, " [%d more]", (int)(n - (n_show-1) - scroll)); + DrawStringF(MAIN_SCREEN, x, yopt + (line_height+2)*(n_show-1), COLOR_LIGHTGREY, COLOR_STD_BG, "%-*s", item_width / font_width, more_str); + } + // show scroll bar + u32 bar_x = x + item_width + 2; + const u32 flist_height = (n_show * (line_height + 2)); + const u32 bar_width = 2; + if (n > n_show) { // draw position bar at the right + const u32 bar_height_min = 32; + u32 bar_height = (n_show * flist_height) / n; + if (bar_height < bar_height_min) bar_height = bar_height_min; + const u32 bar_y = ((u64) scroll * (flist_height - bar_height)) / (n - n_show) + yopt; + + DrawRectangle(MAIN_SCREEN, bar_x, yopt, bar_width, (bar_y - yopt), COLOR_STD_BG); + DrawRectangle(MAIN_SCREEN, bar_x, bar_y + bar_height, bar_width, SCREEN_HEIGHT - (bar_y + bar_height), COLOR_STD_BG); + DrawRectangle(MAIN_SCREEN, bar_x, bar_y, bar_width, bar_height, COLOR_SIDE_BAR); + } else DrawRectangle(MAIN_SCREEN, bar_x, yopt, bar_width, flist_height, COLOR_STD_BG); + + u32 pad_state = InputWait(0); + if (pad_state & BUTTON_DOWN) sel++; + else if (pad_state & BUTTON_UP) sel--; + else if (pad_state & BUTTON_RIGHT) sel += n_show; + else if (pad_state & BUTTON_LEFT) sel -= n_show; + else if (pad_state & BUTTON_A) break; + else if (pad_state & BUTTON_B) { + sel = n; + break; + } + if (sel < 0) sel = 0; + else if (sel >= (int)n) sel = n-1; + if (sel < scroll) scroll = sel; + else if (sel == (int) n-1 && sel >= (int)(scroll + n_show - 1)) scroll = sel - n_show + 1; + else if (sel >= (int)(scroll + (n_show-1) - 1)) scroll = sel - (n_show-1) + 1; + } + + ClearScreenF(true, false, COLOR_STD_BG); + + return (sel >= (int)n) ? 0 : sel + 1; +} + u32 ShowHotkeyPrompt(u32 n, const char** options, const u32* keys, const char *format, ...) { char str[STRBUF_SIZE] = { 0 }; char* ptr = str; diff --git a/arm9/source/common/ui.h b/arm9/source/common/ui.h index 5ac7748..6cc36e8 100644 --- a/arm9/source/common/ui.h +++ b/arm9/source/common/ui.h @@ -7,6 +7,7 @@ #include #include "common.h" #include "colors.h" +#include "fsdir.h" // only required for ShowFileScrollPrompt #define BYTES_PER_PIXEL 3 @@ -73,6 +74,7 @@ void ShowString(const char *format, ...); void ShowIconString(u8* icon, int w, int h, const char *format, ...); bool ShowPrompt(bool ask, const char *format, ...); u32 ShowSelectPrompt(u32 n, const char** options, const char *format, ...); +u32 ShowFileScrollPrompt(u32 n, const DirEntry** entries, bool hide_ext, const char *format, ...); u32 ShowHotkeyPrompt(u32 n, const char** options, const u32* keys, const char *format, ...); bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...); u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...); diff --git a/arm9/source/filesys/fsutil.c b/arm9/source/filesys/fsutil.c index 14a1b14..8ca183d 100644 --- a/arm9/source/filesys/fsutil.c +++ b/arm9/source/filesys/fsutil.c @@ -794,7 +794,7 @@ bool PathAttr(const char* path, u8 attr, u8 mask) { return (f_chmod(path, attr, mask) == FR_OK); } -bool FileSelectorWorker(char* result, const char* text, const char* path, const char* pattern, u32 flags, void* buffer) { +bool FileSelectorWorker(char* result, const char* text, const char* path, const char* pattern, u32 flags, void* buffer, bool new_style) { DirStruct* contents = (DirStruct*) buffer; char path_local[256]; strncpy(path_local, path, 256); @@ -813,7 +813,7 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const while (pos < contents->n_entries) { char opt_names[_MAX_FS_OPT+1][32+1]; - DirEntry* res_entry[_MAX_FS_OPT+1] = { NULL }; + DirEntry* res_entry[MAX_DIR_ENTRIES+1] = { NULL }; u32 n_opt = 0; for (; pos < contents->n_entries; pos++) { DirEntry* entry = &(contents->entry[pos]); @@ -821,35 +821,38 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const ((entry->type == T_FILE) && (no_files || (fvx_match_name(entry->name, pattern) != FR_OK))) || (entry->type == T_DOTDOT) || (strncmp(entry->name, "._", 2) == 0)) continue; - if (n_opt == _MAX_FS_OPT) { + if (!new_style && n_opt == _MAX_FS_OPT) { snprintf(opt_names[n_opt++], 32, "[more...]"); break; } - char temp_str[256]; - snprintf(temp_str, 256, "%s", entry->name); - if (hide_ext && (entry->type == T_FILE)) { - char* dot = strrchr(temp_str, '.'); - if (dot) *dot = '\0'; + if (!new_style) { + char temp_str[256]; + snprintf(temp_str, 256, "%s", entry->name); + if (hide_ext && (entry->type == T_FILE)) { + char* dot = strrchr(temp_str, '.'); + if (dot) *dot = '\0'; + } + TruncateString(opt_names[n_opt], temp_str, 32, 8); } - TruncateString(opt_names[n_opt], temp_str, 32, 8); res_entry[n_opt++] = entry; n_found++; } - if ((pos >= contents->n_entries) && (n_opt < n_found)) + if ((pos >= contents->n_entries) && (n_opt < n_found) && !new_style) snprintf(opt_names[n_opt++], 32, "[more...]"); if (!n_opt) break; const char* optionstr[_MAX_FS_OPT+1] = { NULL }; for (u32 i = 0; i <= _MAX_FS_OPT; i++) optionstr[i] = opt_names[i]; - u32 user_select = ShowSelectPrompt(n_opt, optionstr, "%s", text); + u32 user_select = new_style ? ShowFileScrollPrompt(n_opt, (const DirEntry**)res_entry, hide_ext, "%s", text) + : ShowSelectPrompt(n_opt, optionstr, "%s", text); if (!user_select) return false; DirEntry* res_local = res_entry[user_select-1]; if (res_local && (res_local->type == T_DIR)) { // selected dir if (select_dirs) { strncpy(result, res_local->path, 256); return true; - } else if (FileSelectorWorker(result, text, res_local->path, pattern, flags, buffer)) { + } else if (FileSelectorWorker(result, text, res_local->path, pattern, flags, buffer, new_style)) { return true; } break; @@ -867,11 +870,11 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const } } -bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags) { +bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags, bool new_style) { void* buffer = (void*) malloc(sizeof(DirStruct)); if (!buffer) return false; - bool ret = FileSelectorWorker(result, text, path, pattern, flags, buffer); + bool ret = FileSelectorWorker(result, text, path, pattern, flags, buffer, new_style); free(buffer); return ret; } diff --git a/arm9/source/filesys/fsutil.h b/arm9/source/filesys/fsutil.h index 0760086..1c56429 100644 --- a/arm9/source/filesys/fsutil.h +++ b/arm9/source/filesys/fsutil.h @@ -85,4 +85,4 @@ bool PathRename(const char* path, const char* newname); bool PathAttr(const char* path, u8 attr, u8 mask); /** Select a file **/ -bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags); +bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags, bool new_style); diff --git a/arm9/source/filesys/support.c b/arm9/source/filesys/support.c index f0ecade..16a0404 100644 --- a/arm9/source/filesys/support.c +++ b/arm9/source/filesys/support.c @@ -116,5 +116,5 @@ bool FileSelectorSupport(char* result, const char* text, const char* dname, cons { char path[256]; if (!GetSupportDir(path, dname)) return false; - return FileSelector(result, text, path, pattern, HIDE_EXT); + return FileSelector(result, text, path, pattern, HIDE_EXT, false); } diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 0c912cb..ee152e4 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -26,7 +26,6 @@ #define COLOR_TOP_BAR (PERM_RED ? COLOR_RED : PERM_ORANGE ? COLOR_ORANGE : PERM_BLUE ? COLOR_BRIGHTBLUE : \ PERM_YELLOW ? COLOR_BRIGHTYELLOW : PERM_GREEN ? COLOR_GREEN : COLOR_WHITE) -#define COLOR_ENTRY(e) (((e)->marked) ? COLOR_MARKED : ((e)->type == T_DIR) ? COLOR_DIR : ((e)->type == T_FILE) ? COLOR_FILE : ((e)->type == T_ROOT) ? COLOR_ROOT : COLOR_GREY) #define BOOTPAUSE_KEY (BUTTON_R1|BUTTON_UP) #define BOOTMENU_KEY (BUTTON_R1|BUTTON_LEFT) diff --git a/arm9/source/utils/scripting.c b/arm9/source/utils/scripting.c index 385c6a5..f8f0b9e 100644 --- a/arm9/source/utils/scripting.c +++ b/arm9/source/utils/scripting.c @@ -153,8 +153,8 @@ Gm9ScriptCmd cmd_list[] = { { CMD_ID_QR , "qr" , 2, 0 }, { CMD_ID_ASK , "ask" , 1, 0 }, { CMD_ID_INPUT , "input" , 2, 0 }, - { CMD_ID_FILESEL , "filesel" , 3, _FLG('d') }, - { CMD_ID_DIRSEL , "dirsel" , 3, 0 }, + { CMD_ID_FILESEL , "filesel" , 3, _FLG('d') | _FLG('x') }, + { CMD_ID_DIRSEL , "dirsel" , 3, _FLG('x') }, { CMD_ID_SET , "set" , 2, 0 }, { CMD_ID_STRSPLIT, "strsplit", 3, _FLG('b') | _FLG('f')}, { CMD_ID_STRREP , "strrep" , 3, 0 }, @@ -562,6 +562,7 @@ u32 get_flag(char* str, u32 len, char* err_str) { else if (strncmp(str, "--silent", len) == 0) flag_char = 's'; else if (strncmp(str, "--unequal", len) == 0) flag_char = 'u'; else if (strncmp(str, "--overwrite", len) == 0) flag_char = 'w'; + else if (strncmp(str, "--explorer", len) == 0) flag_char = 'x'; if ((flag_char < 'a') && (flag_char > 'z')) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "illegal flag"); @@ -1039,11 +1040,11 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { } else { u32 flags_ext = (flags & _FLG('d')) ? 0 : NO_DIRS; *(npattern++) = '\0'; - ret = FileSelector(choice, argv[0], path, npattern, flags_ext); + ret = FileSelector(choice, argv[0], path, npattern, flags_ext, (flags & _FLG('x'))); if (err_str) snprintf(err_str, _ERR_STR_LEN, "fileselect abort"); } } else { - ret = FileSelector(choice, argv[0], path, NULL, NO_FILES | SELECT_DIRS); + ret = FileSelector(choice, argv[0], path, NULL, NO_FILES | SELECT_DIRS, (flags & _FLG('x'))); if (err_str) snprintf(err_str, _ERR_STR_LEN, "dirselect abort"); } diff --git a/resources/sample/HelloScript.gm9 b/resources/sample/HelloScript.gm9 index d57441c..a78af55 100644 --- a/resources/sample/HelloScript.gm9 +++ b/resources/sample/HelloScript.gm9 @@ -107,11 +107,13 @@ echo $[TESTREP] # The 'filesel' command allows the user to choose a file inside a directory # The path is stored inside a variable, and the selection can be limited via wildcards # -d / --include_dirs allows to browse folders and select files inside +# -x / --explorer uses new style file selector like main file explorer filesel "Please select a file" 0:/*.* SELFILE # 'dirsel' COMMAND # The 'dirsel' command works identically to the 'filesel' command, but allows selecting a dir # Note that a final slash ('/') is not expected here and there can be no wildcard pattern. +# -x / --explorer uses new style file selector like main file explorer dirsel "Now, select a dir" 0: SELDIR echo "You selected $[SELFILE]\nand $[SELDIR]\nWe'll do nothing with either :)."