194 lines
4.4 KiB
C
194 lines
4.4 KiB
C
#include "filedialog.h"
|
|
#include "input.h"
|
|
#include <dirent.h>
|
|
#include <gint/display.h>
|
|
#include <gint/gint.h>
|
|
#include <gint/keyboard.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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
|
|
: "<Create a new file>";
|
|
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);
|
|
}
|