#include "filedialog.h" #include "input.h" #include #include #include #include #include #include static void path_append(char **path, char const *folder) { char *newpath = malloc(strlen(*path) + strlen(folder) + 2); strcpy(newpath, *path); if (strcmp(*path, "/") != 0) strcat(newpath, "/"); strcat(newpath, folder); free(*path); *path = newpath; } static void path_remove(char **path) { if (!strcmp(*path, "/")) return; *strrchr(*path, '/') = 0; } static int accept_entry(struct dirent *ent) { if (!strcmp(ent->d_name, "@MainMem")) return 0; if (!strcmp(ent->d_name, "SAVE-F")) return 0; if (!strcmp(ent->d_name, ".")) return 0; if (!strcmp(ent->d_name, "..")) return 0; /* here we could filter based on suffix */ return 1; } static void load_folder(char const *path, DIR **dp, int *total, int allow_new_file) { struct dirent *ent; if (*dp) closedir(*dp); *dp = (DIR *)gint_world_switch(GINT_CALL(opendir, path)); *total = allow_new_file; while ((ent = readdir(*dp))) *total += accept_entry(ent); } static int letter_for_key(int key, int alpha) { if (alpha) { int row = 6 - (key >> 4); int col = (key & 0x0f) - 1; int i = 6 * row + col; return "abcdefghijklmno\0\0\0pqrst\0uvwxy\0z \"\0\0\0"[i]; } int digit = keycode_digit(key); if (digit >= 0) return digit + '0'; if (key == KEY_DOT) return '.'; return 0; } static int do_dialog(char *buf, int n, int allow_new_file) { extern volatile int has_ticked; char *path = strdup("/"), *entry_name, *selected_name; DIR *dp = NULL; struct dirent *ent, *selected_ent; int total = 0, cursor = 0, scroll = 0, edit = -1, isfolder = 0, rc = 0; /* both sizes below can be changed */ const int visible = 13; char new_name[32]; load_folder(path, &dp, &total, allow_new_file); for (;;) { rewinddir(dp); dclear(C_BLACK); dprint(1, 1, C_WHITE, "Browsing: %s", path); selected_name = NULL; selected_ent = NULL; for (int i = -scroll; i < visible;) { int selected = (cursor == scroll + i); /* when editing is enabled offer an entry "new file" */ if (i == -scroll && allow_new_file) { entry_name = edit >= 0 ? new_name : ""; isfolder = 0; } else { ent = readdir(dp); if (!ent) break; if (!accept_entry(ent)) continue; entry_name = ent->d_name; isfolder = (ent->d_type == DT_DIR); if (selected) selected_ent = ent; } if (i < 0) { i++; continue; } int y = 20 + 15 * i; if (selected) { selected_name = entry_name; drect(0, y - 1, DWIDTH - 1, y + 13, C_WHITE); } dprint(1, y, selected ? C_BLACK : C_WHITE, "%s%s", entry_name, isfolder ? "/" : entry_name == new_name ? "|" : ""); i++; } dupdate(); key_event_t ev = getkey(); int key = ev.key; if (key == KEY_UP && cursor > 0) cursor--; if (key == KEY_DOWN && cursor < total - 1) cursor++; if (scroll > 0 && cursor <= scroll) scroll = cursor - 1; if (scroll + visible < total && cursor >= scroll + visible - 2) scroll = cursor - visible + 2; int changed_path = 0; if (key == KEY_EXIT && edit >= 0) { edit = -1; } else if (key == KEY_EXIT) { if (!strcmp(path, "/")) goto end; path_remove(&path); changed_path = 1; } else if (key == KEY_EXE && edit > 0) { break; } else if (key == KEY_EXE && !selected_ent) { memset(new_name, 0, sizeof new_name); edit = 0; } else if (key == KEY_EXE && selected_ent->d_type == DT_DIR) { path_append(&path, selected_ent->d_name); changed_path = 1; } else if (key == KEY_EXE && selected_ent->d_type != DT_DIR) { break; } if (edit > 0 && key == KEY_DEL) { new_name[--edit] = 0; } else if (edit >= 0 && new_name[sizeof new_name - 2] == 0) { int letter = letter_for_key(key, ev.alpha); if (letter) new_name[edit++] = letter; } if (changed_path) { load_folder(path, &dp, &total, allow_new_file); cursor = scroll = 0; } } if ((size_t)n >= strlen(path) + strlen(selected_name) + 2) { strcpy(buf, path); if (strcmp(path, "/") != 0) strcat(buf, "/"); strcat(buf, selected_name); } else rc = 1; end: free(path); closedir(dp); has_ticked = 0; input_set_down(K_EXIT); return rc; } int filedialog_open(char *buf, int n) { return do_dialog(buf, n, 0); } int filedialog_save(char *buf, int n) { return do_dialog(buf, n, 1); }