From a588c24f59d2d0cd230b8fa7534ba002430c716b Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 5 Nov 2022 18:50:40 +0100 Subject: [PATCH] jfileselect: add a programmable filter --- include/justui/jfileselect.h | 14 +++++++++++ src/jfileselect.c | 45 +++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/include/justui/jfileselect.h b/include/justui/jfileselect.h index 9b743cb..e4401c8 100644 --- a/include/justui/jfileselect.h +++ b/include/justui/jfileselect.h @@ -39,6 +39,8 @@ typedef struct { bool saveas; /* Whether we are currently using the input field */ bool input_mode; + /* File filter; NULL accepts everything */ + bool (*filter_function)(struct dirent const *entry); /* Current cursor position (0 .. folder_entries-1) */ int16_t cursor; @@ -96,6 +98,18 @@ char const *jfileselect_selected_file(jfileselect *fs); /* jfileselect_current_folder(): Get the path to the current folder */ char const *jfileselect_current_folder(jfileselect *fs); +/* jfileselect_set_filter(): Set a filter function + + The function is called on each directory entry read when scanning a folder. + It should return true to show the entry, false to ignore it. By default, + jfileselect_default_filter is used. Note filters in general should really + accept folders. */ +void jfileselect_set_filter(jfileselect *fs, + bool (*filter)(struct dirent const *entry)); + +/* Default filter. Rejects "@MainMem", "SAVE-F", "." and "..". */ +bool jfileselect_default_filter(struct dirent const *entry); + /* Trivial properties */ void jfileselect_set_font(jfileselect *fs, font_t const *font); void jfileselect_set_line_spacing(jfileselect *fs, int line_spacing); diff --git a/src/jfileselect.c b/src/jfileselect.c index 58ccc72..dbc8364 100644 --- a/src/jfileselect.c +++ b/src/jfileselect.c @@ -56,6 +56,8 @@ jfileselect *jfileselect_create(void *parent) fs->selected_file = NULL; fs->saveas_input = input; fs->saveas = false; + fs->input_mode = false; + fs->filter_function = jfileselect_default_filter; fs->cursor = -1; fs->scroll = 0; @@ -166,28 +168,14 @@ static char *path_up(char const *path) return parent; } -static bool accept_entry(struct dirent *ent) -{ - /* TODO: jfileselect: Programmable filter */ - if(!strcmp(ent->d_name, "@MainMem")) - return false; - if(!strcmp(ent->d_name, "SAVE-F")) - return false; - if(!strcmp(ent->d_name, ".")) - return false; - if(!strcmp(ent->d_name, "..")) - return false; - return true; -} - -static int count_accepted_entries(DIR *dp) +static int count_accepted_entries(jfileselect *fs, DIR *dp) { int n = 0; struct dirent *ent; rewinddir(dp); while((ent = readdir(dp))) - n += accept_entry(ent); + n += (fs->filter_function ? fs->filter_function(ent) : 1); return n; } @@ -222,7 +210,7 @@ static bool load_folder_switch(jfileselect *fs, char *path) return false; /* Count entries */ - int n = count_accepted_entries(dp) + fs->saveas; + int n = count_accepted_entries(fs, dp) + fs->saveas; /* Allocate memory for the fileinfo structures */ struct fileinfo *finfo = malloc(n * sizeof *finfo); @@ -234,7 +222,7 @@ static bool load_folder_switch(jfileselect *fs, char *path) /* Read the fileinfo structures */ rewinddir(dp); for(int i = 0; i < n && (ent = readdir(dp));) { - if(!accept_entry(ent)) + if(fs->filter_function && !fs->filter_function(ent)) continue; finfo[i].name = strdup(ent->d_name); @@ -254,7 +242,7 @@ static bool load_folder_switch(jfileselect *fs, char *path) if(ent->d_type == DT_DIR) { DIR *sub = opendir(full_path); if(sub) { - finfo[i].size = count_accepted_entries(sub); + finfo[i].size = count_accepted_entries(fs, sub); closedir(sub); } } @@ -320,6 +308,25 @@ char const *jfileselect_current_folder(jfileselect *fs) return fs->path; } +void jfileselect_set_filter(jfileselect *fs, + bool (*filter)(struct dirent const *entry)) +{ + fs->filter_function = filter; +} + +bool jfileselect_default_filter(struct dirent const *ent) +{ + if(!strcmp(ent->d_name, "@MainMem")) + return false; + if(!strcmp(ent->d_name, "SAVE-F")) + return false; + if(!strcmp(ent->d_name, ".")) + return false; + if(!strcmp(ent->d_name, "..")) + return false; + return true; +} + //--- // Polymorphic widget operations //---