diff options
Diffstat (limited to 'source/blender/editors/space_file/filelist.c')
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 4156 |
1 files changed, 2131 insertions, 2025 deletions
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 623442b753a..31a59f06079 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -21,7 +21,6 @@ * \ingroup spfile */ - /* global includes */ #include <stdlib.h> @@ -83,249 +82,246 @@ #include "filelist.h" - /* ----------------- FOLDERLIST (previous/next) -------------- */ typedef struct FolderList { - struct FolderList *next, *prev; - char *foldername; + struct FolderList *next, *prev; + char *foldername; } FolderList; ListBase *folderlist_new(void) { - ListBase *p = MEM_callocN(sizeof(*p), __func__); - return p; + ListBase *p = MEM_callocN(sizeof(*p), __func__); + return p; } void folderlist_popdir(struct ListBase *folderlist, char *dir) { - const char *prev_dir; - struct FolderList *folder; - folder = folderlist->last; + const char *prev_dir; + struct FolderList *folder; + folder = folderlist->last; - if (folder) { - /* remove the current directory */ - MEM_freeN(folder->foldername); - BLI_freelinkN(folderlist, folder); + if (folder) { + /* remove the current directory */ + MEM_freeN(folder->foldername); + BLI_freelinkN(folderlist, folder); - folder = folderlist->last; - if (folder) { - prev_dir = folder->foldername; - BLI_strncpy(dir, prev_dir, FILE_MAXDIR); - } - } - /* delete the folder next or use setdir directly before PREVIOUS OP */ + folder = folderlist->last; + if (folder) { + prev_dir = folder->foldername; + BLI_strncpy(dir, prev_dir, FILE_MAXDIR); + } + } + /* delete the folder next or use setdir directly before PREVIOUS OP */ } void folderlist_pushdir(ListBase *folderlist, const char *dir) { - struct FolderList *folder, *previous_folder; - previous_folder = folderlist->last; + struct FolderList *folder, *previous_folder; + previous_folder = folderlist->last; - /* check if already exists */ - if (previous_folder && previous_folder->foldername) { - if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { - return; - } - } + /* check if already exists */ + if (previous_folder && previous_folder->foldername) { + if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { + return; + } + } - /* create next folder element */ - folder = MEM_mallocN(sizeof(*folder), __func__); - folder->foldername = BLI_strdup(dir); + /* create next folder element */ + folder = MEM_mallocN(sizeof(*folder), __func__); + folder->foldername = BLI_strdup(dir); - /* add it to the end of the list */ - BLI_addtail(folderlist, folder); + /* add it to the end of the list */ + BLI_addtail(folderlist, folder); } const char *folderlist_peeklastdir(ListBase *folderlist) { - struct FolderList *folder; + struct FolderList *folder; - if (!folderlist->last) - return NULL; + if (!folderlist->last) + return NULL; - folder = folderlist->last; - return folder->foldername; + folder = folderlist->last; + return folder->foldername; } int folderlist_clear_next(struct SpaceFile *sfile) { - struct FolderList *folder; + struct FolderList *folder; - /* if there is no folder_next there is nothing we can clear */ - if (!sfile->folders_next) - return 0; + /* if there is no folder_next there is nothing we can clear */ + if (!sfile->folders_next) + return 0; - /* if previous_folder, next_folder or refresh_folder operators are executed - * it doesn't clear folder_next */ - folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) - return 0; + /* if previous_folder, next_folder or refresh_folder operators are executed + * it doesn't clear folder_next */ + folder = sfile->folders_prev->last; + if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) + return 0; - /* eventually clear flist->folders_next */ - return 1; + /* eventually clear flist->folders_next */ + return 1; } /* not listbase itself */ void folderlist_free(ListBase *folderlist) { - if (folderlist) { - FolderList *folder; - for (folder = folderlist->first; folder; folder = folder->next) - MEM_freeN(folder->foldername); - BLI_freelistN(folderlist); - } + if (folderlist) { + FolderList *folder; + for (folder = folderlist->first; folder; folder = folder->next) + MEM_freeN(folder->foldername); + BLI_freelistN(folderlist); + } } ListBase *folderlist_duplicate(ListBase *folderlist) { - if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); - FolderList *folder; + if (folderlist) { + ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); + FolderList *folder; - BLI_duplicatelist(folderlistn, folderlist); + BLI_duplicatelist(folderlistn, folderlist); - for (folder = folderlistn->first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); - } - return folderlistn; - } - return NULL; + for (folder = folderlistn->first; folder; folder = folder->next) { + folder->foldername = MEM_dupallocN(folder->foldername); + } + return folderlistn; + } + return NULL; } - /* ------------------FILELIST------------------------ */ typedef struct FileListInternEntry { - struct FileListInternEntry *next, *prev; + struct FileListInternEntry *next, *prev; - /** ASSET_UUID_LENGTH */ - char uuid[16]; + /** ASSET_UUID_LENGTH */ + char uuid[16]; - /** eFileSel_File_Types */ - int typeflag; - /** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */ - int blentype; + /** eFileSel_File_Types */ + int typeflag; + /** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */ + int blentype; - char *relpath; - /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ - char *name; + char *relpath; + /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ + char *name; - BLI_stat_t st; + BLI_stat_t st; } FileListInternEntry; typedef struct FileListIntern { - /** FileListInternEntry items. */ - ListBase entries; - FileListInternEntry **filtered; + /** FileListInternEntry items. */ + ListBase entries; + FileListInternEntry **filtered; - char curr_uuid[16]; /* Used to generate uuid during internal listing. */ + char curr_uuid[16]; /* Used to generate uuid during internal listing. */ } FileListIntern; -#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */ +#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */ typedef struct FileListEntryCache { - size_t size; /* The size of the cache... */ + size_t size; /* The size of the cache... */ - int flags; + int flags; - /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */ - ListBase cached_entries; + /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */ + ListBase cached_entries; - /* Block cache: all entries between start and end index. - * used for part of the list on display. */ - FileDirEntry **block_entries; - int block_start_index, block_end_index, block_center_index, block_cursor; + /* Block cache: all entries between start and end index. + * used for part of the list on display. */ + FileDirEntry **block_entries; + int block_start_index, block_end_index, block_center_index, block_cursor; - /* Misc cache: random indices, FIFO behavior. - * Note: Not 100% sure we actually need that, time will say. */ - int misc_cursor; - int *misc_entries_indices; - GHash *misc_entries; + /* Misc cache: random indices, FIFO behavior. + * Note: Not 100% sure we actually need that, time will say. */ + int misc_cursor; + int *misc_entries_indices; + GHash *misc_entries; - /* Allows to quickly get a cached entry from its UUID. */ - GHash *uuids; + /* Allows to quickly get a cached entry from its UUID. */ + GHash *uuids; - /* Previews handling. */ - TaskPool *previews_pool; - ThreadQueue *previews_done; + /* Previews handling. */ + TaskPool *previews_pool; + ThreadQueue *previews_done; } FileListEntryCache; /* FileListCache.flags */ enum { - FLC_IS_INIT = 1 << 0, - FLC_PREVIEWS_ACTIVE = 1 << 1, + FLC_IS_INIT = 1 << 0, + FLC_PREVIEWS_ACTIVE = 1 << 1, }; typedef struct FileListEntryPreview { - char path[FILE_MAX]; - unsigned int flags; - int index; - ImBuf *img; + char path[FILE_MAX]; + unsigned int flags; + int index; + ImBuf *img; } FileListEntryPreview; - typedef struct FileListFilter { - unsigned int filter; - unsigned int filter_id; - char filter_glob[FILE_MAXFILE]; - char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */ - short flags; + unsigned int filter; + unsigned int filter_id; + char filter_glob[FILE_MAXFILE]; + char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */ + short flags; } FileListFilter; /* FileListFilter.flags */ enum { - FLF_DO_FILTER = 1 << 0, - FLF_HIDE_DOT = 1 << 1, - FLF_HIDE_PARENT = 1 << 2, - FLF_HIDE_LIB_DIR = 1 << 3, + FLF_DO_FILTER = 1 << 0, + FLF_HIDE_DOT = 1 << 1, + FLF_HIDE_PARENT = 1 << 2, + FLF_HIDE_LIB_DIR = 1 << 3, }; typedef struct FileList { - FileDirEntryArr filelist; + FileDirEntryArr filelist; - short prv_w; - short prv_h; + short prv_w; + short prv_h; - short flags; + short flags; - short sort; + short sort; - FileListFilter filter_data; + FileListFilter filter_data; - struct FileListIntern filelist_intern; + struct FileListIntern filelist_intern; - struct FileListEntryCache filelist_cache; + struct FileListEntryCache filelist_cache; - /* We need to keep those info outside of actual filelist items, because those are no more persistent - * (only generated on demand, and freed as soon as possible). - * Persistent part (mere list of paths + stat info) is kept as small as possible, and filebrowser-agnostic. - */ - GHash *selection_state; + /* We need to keep those info outside of actual filelist items, because those are no more persistent + * (only generated on demand, and freed as soon as possible). + * Persistent part (mere list of paths + stat info) is kept as small as possible, and filebrowser-agnostic. + */ + GHash *selection_state; - short max_recursion; - short recursion_level; + short max_recursion; + short recursion_level; - struct BlendHandle *libfiledata; + struct BlendHandle *libfiledata; - /* Set given path as root directory, if last bool is true may change given string in place to a valid value. - * Returns True if valid dir. */ - bool (*checkdirf)(struct FileList *, char *, const bool); + /* Set given path as root directory, if last bool is true may change given string in place to a valid value. + * Returns True if valid dir. */ + bool (*checkdirf)(struct FileList *, char *, const bool); - /* Fill filelist (to be called by read job). */ - void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); + /* Fill filelist (to be called by read job). */ + void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); - /* Filter an entry of current filelist. */ - bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + /* Filter an entry of current filelist. */ + bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); } FileList; /* FileList.flags */ enum { - FL_FORCE_RESET = 1 << 0, - FL_IS_READY = 1 << 1, - FL_IS_PENDING = 1 << 2, - FL_NEED_SORTING = 1 << 3, - FL_NEED_FILTERING = 1 << 4, + FL_FORCE_RESET = 1 << 0, + FL_IS_READY = 1 << 1, + FL_IS_PENDING = 1 << 2, + FL_NEED_SORTING = 1 << 3, + FL_NEED_FILTERING = 1 << 4, }; #define SPECIAL_IMG_SIZE 48 @@ -333,27 +329,29 @@ enum { #define SPECIAL_IMG_COLS 4 enum { - SPECIAL_IMG_FOLDER = 0, - SPECIAL_IMG_PARENT = 1, - SPECIAL_IMG_REFRESH = 2, - SPECIAL_IMG_BLENDFILE = 3, - SPECIAL_IMG_SOUNDFILE = 4, - SPECIAL_IMG_MOVIEFILE = 5, - SPECIAL_IMG_PYTHONFILE = 6, - SPECIAL_IMG_TEXTFILE = 7, - SPECIAL_IMG_FONTFILE = 8, - SPECIAL_IMG_UNKNOWNFILE = 9, - SPECIAL_IMG_LOADING = 10, - SPECIAL_IMG_BACKUP = 11, - SPECIAL_IMG_MAX, + SPECIAL_IMG_FOLDER = 0, + SPECIAL_IMG_PARENT = 1, + SPECIAL_IMG_REFRESH = 2, + SPECIAL_IMG_BLENDFILE = 3, + SPECIAL_IMG_SOUNDFILE = 4, + SPECIAL_IMG_MOVIEFILE = 5, + SPECIAL_IMG_PYTHONFILE = 6, + SPECIAL_IMG_TEXTFILE = 7, + SPECIAL_IMG_FONTFILE = 8, + SPECIAL_IMG_UNKNOWNFILE = 9, + SPECIAL_IMG_LOADING = 10, + SPECIAL_IMG_BACKUP = 11, + SPECIAL_IMG_MAX, }; static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; - -static void filelist_readjob_main(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); -static void filelist_readjob_lib(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); -static void filelist_readjob_dir(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_main( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_lib( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_dir( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* helper, could probably go in BKE actually? */ static int groupname_to_code(const char *group); @@ -364,1053 +362,1114 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size); /* ********** Sort helpers ********** */ -static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2) -{ - /* type is equal to stat.st_mode */ - - if (entry1->typeflag & FILE_TYPE_DIR) { - if (entry2->typeflag & FILE_TYPE_DIR) { - /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs, - * then libs (.blend files), then categories in libs. */ - if (entry1->typeflag & FILE_TYPE_BLENDERLIB) { - if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) { - return 1; - } - } - else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) { - return -1; - } - else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - return 1; - } - } - else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - return -1; - } - } - else { - return -1; - } - } - else if (entry2->typeflag & FILE_TYPE_DIR) { - return 1; - } - - /* make sure "." and ".." are always first */ - if (FILENAME_IS_CURRENT(entry1->relpath)) return -1; - if (FILENAME_IS_CURRENT(entry2->relpath)) return 1; - if (FILENAME_IS_PARENT(entry1->relpath)) return -1; - if (FILENAME_IS_PARENT(entry2->relpath)) return 1; - - return 0; +static int compare_direntry_generic(const FileListInternEntry *entry1, + const FileListInternEntry *entry2) +{ + /* type is equal to stat.st_mode */ + + if (entry1->typeflag & FILE_TYPE_DIR) { + if (entry2->typeflag & FILE_TYPE_DIR) { + /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs, + * then libs (.blend files), then categories in libs. */ + if (entry1->typeflag & FILE_TYPE_BLENDERLIB) { + if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) { + return 1; + } + } + else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) { + return -1; + } + else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + return 1; + } + } + else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + return -1; + } + } + else { + return -1; + } + } + else if (entry2->typeflag & FILE_TYPE_DIR) { + return 1; + } + + /* make sure "." and ".." are always first */ + if (FILENAME_IS_CURRENT(entry1->relpath)) + return -1; + if (FILENAME_IS_CURRENT(entry2->relpath)) + return 1; + if (FILENAME_IS_PARENT(entry1->relpath)) + return -1; + if (FILENAME_IS_PARENT(entry2->relpath)) + return 1; + + return 0; } static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int64_t time1, time2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int64_t time1, time2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - time1 = (int64_t)entry1->st.st_mtime; - time2 = (int64_t)entry2->st.st_mtime; - if (time1 < time2) return 1; - if (time1 > time2) return -1; + time1 = (int64_t)entry1->st.st_mtime; + time2 = (int64_t)entry2->st.st_mtime; + if (time1 < time2) + return 1; + if (time1 > time2) + return -1; - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - uint64_t size1, size2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + uint64_t size1, size2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - size1 = entry1->st.st_size; - size2 = entry2->st.st_size; - if (size1 < size2) return 1; - if (size1 > size2) return -1; + size1 = entry1->st.st_size; + size2 = entry2->st.st_size; + if (size1 < size2) + return 1; + if (size1 > size2) + return -1; - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int ret; - - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } - - if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) return -1; - if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) return 1; - if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) { - if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) return 1; - if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) return -1; - if (entry1->blentype < entry2->blentype) return -1; - if (entry1->blentype > entry2->blentype) return 1; - } - else { - const char *sufix1, *sufix2; - - if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) - sufix1 = strrchr(entry1->relpath, '.'); - if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) - sufix2 = strrchr(entry2->relpath, '.'); - if (!sufix1) sufix1 = ""; - if (!sufix2) sufix2 = ""; - - if ((ret = BLI_strcasecmp(sufix1, sufix2))) { - return ret; - } - } - - name1 = entry1->name; - name2 = entry2->name; - - return BLI_natstrcmp(name1, name2); + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int ret; + + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } + + if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) + return -1; + if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) + return 1; + if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) { + if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) + return 1; + if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) + return -1; + if (entry1->blentype < entry2->blentype) + return -1; + if (entry1->blentype > entry2->blentype) + return 1; + } + else { + const char *sufix1, *sufix2; + + if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) + sufix1 = strrchr(entry1->relpath, '.'); + if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) + sufix2 = strrchr(entry2->relpath, '.'); + if (!sufix1) + sufix1 = ""; + if (!sufix2) + sufix2 = ""; + + if ((ret = BLI_strcasecmp(sufix1, sufix2))) { + return ret; + } + } + + name1 = entry1->name; + name2 = entry2->name; + + return BLI_natstrcmp(name1, name2); } void filelist_sort(struct FileList *filelist) { - if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) { - switch (filelist->sort) { - case FILE_SORT_ALPHA: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL); - break; - case FILE_SORT_TIME: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL); - break; - case FILE_SORT_SIZE: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL); - break; - case FILE_SORT_EXTENSION: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL); - break; - case FILE_SORT_NONE: /* Should never reach this point! */ - default: - BLI_assert(0); - break; - } - - filelist_filter_clear(filelist); - filelist->flags &= ~FL_NEED_SORTING; - } + if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) { + switch (filelist->sort) { + case FILE_SORT_ALPHA: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL); + break; + case FILE_SORT_TIME: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL); + break; + case FILE_SORT_SIZE: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL); + break; + case FILE_SORT_EXTENSION: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL); + break; + case FILE_SORT_NONE: /* Should never reach this point! */ + default: + BLI_assert(0); + break; + } + + filelist_filter_clear(filelist); + filelist->flags &= ~FL_NEED_SORTING; + } } void filelist_setsorting(struct FileList *filelist, const short sort) { - if (filelist->sort != sort) { - filelist->sort = sort; - filelist->flags |= FL_NEED_SORTING; - } + if (filelist->sort != sort) { + filelist->sort = sort; + filelist->flags |= FL_NEED_SORTING; + } } /* ********** Filter helpers ********** */ static bool is_hidden_file(const char *filename, FileListFilter *filter) { - char *sep = (char *)BLI_last_slash(filename); - bool is_hidden = false; - - if (filter->flags & FLF_HIDE_DOT) { - if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { - is_hidden = true; /* ignore .file */ - } - else { - int len = strlen(filename); - if ((len > 0) && (filename[len - 1] == '~')) { - is_hidden = true; /* ignore file~ */ - } - } - } - if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { - if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { - is_hidden = true; /* ignore .. */ - } - } - if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { - is_hidden = true; /* ignore . */ - } - /* filename might actually be a piece of path, in which case we have to check all its parts. */ - if (!is_hidden && sep) { - char tmp_filename[FILE_MAX_LIBEXTRA]; - - BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); - sep = tmp_filename + (sep - filename); - while (sep) { - BLI_assert(sep[1] != '\0'); - if (is_hidden_file(sep + 1, filter)) { - is_hidden = true; - break; - } - *sep = '\0'; - sep = (char *)BLI_last_slash(tmp_filename); - } - } - return is_hidden; -} - -static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter) -{ - bool is_filtered = !is_hidden_file(file->relpath, filter); - - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if (filter->filter) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } - } - } - else { - if (!(file->typeflag & filter->filter)) { - is_filtered = false; - } - } - } - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; - } - } - } - - return is_filtered; + char *sep = (char *)BLI_last_slash(filename); + bool is_hidden = false; + + if (filter->flags & FLF_HIDE_DOT) { + if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { + is_hidden = true; /* ignore .file */ + } + else { + int len = strlen(filename); + if ((len > 0) && (filename[len - 1] == '~')) { + is_hidden = true; /* ignore file~ */ + } + } + } + if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { + if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { + is_hidden = true; /* ignore .. */ + } + } + if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { + is_hidden = true; /* ignore . */ + } + /* filename might actually be a piece of path, in which case we have to check all its parts. */ + if (!is_hidden && sep) { + char tmp_filename[FILE_MAX_LIBEXTRA]; + + BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); + sep = tmp_filename + (sep - filename); + while (sep) { + BLI_assert(sep[1] != '\0'); + if (is_hidden_file(sep + 1, filter)) { + is_hidden = true; + break; + } + *sep = '\0'; + sep = (char *)BLI_last_slash(tmp_filename); + } + } + return is_hidden; +} + +static bool is_filtered_file(FileListInternEntry *file, + const char *UNUSED(root), + FileListFilter *filter) +{ + bool is_filtered = !is_hidden_file(file->relpath, filter); + + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } + } + } + else { + if (!(file->typeflag & filter->filter)) { + is_filtered = false; + } + } + } + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; + } + } + } + + return is_filtered; } static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { - bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; - - BLI_join_dirfile(path, sizeof(path), root, file->relpath); - - if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if (filter->filter || filter->filter_id) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } - } - } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { - is_filtered = false; - } - else { - unsigned int filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { - is_filtered = false; - } - } - } - } - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; - } - } - } - } - else { - is_filtered = is_filtered_file(file, root, filter); - } - - return is_filtered; -} - -static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter) -{ - return !is_hidden_file(file->relpath, filter); + bool is_filtered; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; + + BLI_join_dirfile(path, sizeof(path), root, file->relpath); + + if (BLO_library_path_explode(path, dir, &group, &name)) { + is_filtered = !is_hidden_file(file->relpath, filter); + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter || filter->filter_id) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } + } + } + if (is_filtered && group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { + is_filtered = false; + } + else { + unsigned int filter_id = groupname_to_filter_id(group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } + } + } + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; + } + } + } + } + else { + is_filtered = is_filtered_file(file, root, filter); + } + + return is_filtered; +} + +static bool is_filtered_main(FileListInternEntry *file, + const char *UNUSED(dir), + FileListFilter *filter) +{ + return !is_hidden_file(file->relpath, filter); } static void filelist_filter_clear(FileList *filelist) { - filelist->flags |= FL_NEED_FILTERING; + filelist->flags |= FL_NEED_FILTERING; } void filelist_filter(FileList *filelist) { - int num_filtered = 0; - const int num_files = filelist->filelist.nbr_entries; - FileListInternEntry **filtered_tmp, *file; - - if (filelist->filelist.nbr_entries == 0) { - return; - } - - if (!(filelist->flags & FL_NEED_FILTERING)) { - /* Assume it has already been filtered, nothing else to do! */ - return; - } - - filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR; - if (filelist->max_recursion) { - /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless - * root path is a blend file. */ - char dir[FILE_MAX_LIBEXTRA]; - if (!filelist_islibrary(filelist, dir, NULL)) { - filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; - } - } - - filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__); - - /* Filter remap & count how many files are left after filter in a single loop. */ - for (file = filelist->filelist_intern.entries.first; file; file = file->next) { - if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { - filtered_tmp[num_filtered++] = file; - } - } - - if (filelist->filelist_intern.filtered) { - MEM_freeN(filelist->filelist_intern.filtered); - } - filelist->filelist_intern.filtered = MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, - __func__); - memcpy(filelist->filelist_intern.filtered, filtered_tmp, - sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered); - filelist->filelist.nbr_entries_filtered = num_filtered; -// printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries); - - filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); - filelist->flags &= ~FL_NEED_FILTERING; - - MEM_freeN(filtered_tmp); -} - -void filelist_setfilter_options(FileList *filelist, const bool do_filter, - const bool hide_dot, const bool hide_parent, - const unsigned int filter, const unsigned int filter_id, - const char *filter_glob, const char *filter_search) -{ - bool update = false; - - if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { - filelist->filter_data.flags ^= FLF_DO_FILTER; - update = true; - } - if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { - filelist->filter_data.flags ^= FLF_HIDE_DOT; - update = true; - } - if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) { - filelist->filter_data.flags ^= FLF_HIDE_PARENT; - update = true; - } - if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { - filelist->filter_data.filter = filter; - filelist->filter_data.filter_id = filter_id; - update = true; - } - if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { - BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob)); - update = true; - } - if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) { - BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, filter_search, '*', - sizeof(filelist->filter_data.filter_search)); - update = true; - } - - if (update) { - /* And now, free filtered data so that we know we have to filter again. */ - filelist_filter_clear(filelist); - } + int num_filtered = 0; + const int num_files = filelist->filelist.nbr_entries; + FileListInternEntry **filtered_tmp, *file; + + if (filelist->filelist.nbr_entries == 0) { + return; + } + + if (!(filelist->flags & FL_NEED_FILTERING)) { + /* Assume it has already been filtered, nothing else to do! */ + return; + } + + filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR; + if (filelist->max_recursion) { + /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless + * root path is a blend file. */ + char dir[FILE_MAX_LIBEXTRA]; + if (!filelist_islibrary(filelist, dir, NULL)) { + filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; + } + } + + filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__); + + /* Filter remap & count how many files are left after filter in a single loop. */ + for (file = filelist->filelist_intern.entries.first; file; file = file->next) { + if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { + filtered_tmp[num_filtered++] = file; + } + } + + if (filelist->filelist_intern.filtered) { + MEM_freeN(filelist->filelist_intern.filtered); + } + filelist->filelist_intern.filtered = MEM_mallocN( + sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__); + memcpy(filelist->filelist_intern.filtered, + filtered_tmp, + sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered); + filelist->filelist.nbr_entries_filtered = num_filtered; + // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries); + + filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); + filelist->flags &= ~FL_NEED_FILTERING; + + MEM_freeN(filtered_tmp); +} + +void filelist_setfilter_options(FileList *filelist, + const bool do_filter, + const bool hide_dot, + const bool hide_parent, + const unsigned int filter, + const unsigned int filter_id, + const char *filter_glob, + const char *filter_search) +{ + bool update = false; + + if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { + filelist->filter_data.flags ^= FLF_DO_FILTER; + update = true; + } + if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { + filelist->filter_data.flags ^= FLF_HIDE_DOT; + update = true; + } + if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) { + filelist->filter_data.flags ^= FLF_HIDE_PARENT; + update = true; + } + if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { + filelist->filter_data.filter = filter; + filelist->filter_data.filter_id = filter_id; + update = true; + } + if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { + BLI_strncpy( + filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob)); + update = true; + } + if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) { + BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, + filter_search, + '*', + sizeof(filelist->filter_data.filter_search)); + update = true; + } + + if (update) { + /* And now, free filtered data so that we know we have to filter again. */ + filelist_filter_clear(filelist); + } } /* ********** Icon/image helpers ********** */ void filelist_init_icons(void) { - short x, y, k; - ImBuf *bbuf; - ImBuf *ibuf; + short x, y, k; + ImBuf *bbuf; + ImBuf *ibuf; - BLI_assert(G.background == false); + BLI_assert(G.background == false); #ifdef WITH_HEADLESS - bbuf = NULL; + bbuf = NULL; #else - bbuf = IMB_ibImageFromMemory((const uchar *)datatoc_prvicons_png, datatoc_prvicons_png_size, IB_rect, NULL, "<splash>"); + bbuf = IMB_ibImageFromMemory( + (const uchar *)datatoc_prvicons_png, datatoc_prvicons_png_size, IB_rect, NULL, "<splash>"); #endif - if (bbuf) { - for (y = 0; y < SPECIAL_IMG_ROWS; y++) { - for (x = 0; x < SPECIAL_IMG_COLS; x++) { - int tile = SPECIAL_IMG_COLS * y + x; - if (tile < SPECIAL_IMG_MAX) { - ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect); - for (k = 0; k < SPECIAL_IMG_SIZE; k++) { - memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE], &bbuf->rect[(k + y * SPECIAL_IMG_SIZE) * SPECIAL_IMG_SIZE * SPECIAL_IMG_COLS + x * SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE * sizeof(int)); - } - gSpecialFileImages[tile] = ibuf; - } - } - } - IMB_freeImBuf(bbuf); - } + if (bbuf) { + for (y = 0; y < SPECIAL_IMG_ROWS; y++) { + for (x = 0; x < SPECIAL_IMG_COLS; x++) { + int tile = SPECIAL_IMG_COLS * y + x; + if (tile < SPECIAL_IMG_MAX) { + ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect); + for (k = 0; k < SPECIAL_IMG_SIZE; k++) { + memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE], + &bbuf->rect[(k + y * SPECIAL_IMG_SIZE) * SPECIAL_IMG_SIZE * SPECIAL_IMG_COLS + + x * SPECIAL_IMG_SIZE], + SPECIAL_IMG_SIZE * sizeof(int)); + } + gSpecialFileImages[tile] = ibuf; + } + } + } + IMB_freeImBuf(bbuf); + } } void filelist_free_icons(void) { - int i; + int i; - BLI_assert(G.background == false); + BLI_assert(G.background == false); - for (i = 0; i < SPECIAL_IMG_MAX; ++i) { - IMB_freeImBuf(gSpecialFileImages[i]); - gSpecialFileImages[i] = NULL; - } + for (i = 0; i < SPECIAL_IMG_MAX; ++i) { + IMB_freeImBuf(gSpecialFileImages[i]); + gSpecialFileImages[i] = NULL; + } } void filelist_imgsize(struct FileList *filelist, short w, short h) { - filelist->prv_w = w; - filelist->prv_h = h; + filelist->prv_w = w; + filelist->prv_h = h; } static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index) { - BLI_assert(G.background == false); + BLI_assert(G.background == false); - return filelist_file(filelist, index); + return filelist_file(filelist, index); } ImBuf *filelist_getimage(struct FileList *filelist, const int index) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); + FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return file->image; + return file->image; } static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char *relpath) { - ImBuf *ibuf = NULL; - - if (typeflag & FILE_TYPE_DIR) { - if (FILENAME_IS_PARENT(relpath)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; - } - else if (FILENAME_IS_CURRENT(relpath)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; - } - } - else if (typeflag & FILE_TYPE_BLENDER) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; - } - else if (typeflag & FILE_TYPE_BLENDERLIB) { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - else if (typeflag & (FILE_TYPE_MOVIE)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; - } - else if (typeflag & FILE_TYPE_SOUND) { - ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; - } - else if (typeflag & FILE_TYPE_PYSCRIPT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; - } - else if (typeflag & FILE_TYPE_FTFONT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; - } - else if (typeflag & FILE_TYPE_TEXT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; - } - else if (typeflag & FILE_TYPE_IMAGE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; - } - else if (typeflag & FILE_TYPE_BLENDER_BACKUP) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - - return ibuf; + ImBuf *ibuf = NULL; + + if (typeflag & FILE_TYPE_DIR) { + if (FILENAME_IS_PARENT(relpath)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; + } + else if (FILENAME_IS_CURRENT(relpath)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; + } + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; + } + } + else if (typeflag & FILE_TYPE_BLENDER) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; + } + else if (typeflag & FILE_TYPE_BLENDERLIB) { + ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + } + else if (typeflag & (FILE_TYPE_MOVIE)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; + } + else if (typeflag & FILE_TYPE_SOUND) { + ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; + } + else if (typeflag & FILE_TYPE_PYSCRIPT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; + } + else if (typeflag & FILE_TYPE_FTFONT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; + } + else if (typeflag & FILE_TYPE_TEXT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; + } + else if (typeflag & FILE_TYPE_IMAGE) { + ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; + } + else if (typeflag & FILE_TYPE_BLENDER_BACKUP) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; + } + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + } + + return ibuf; } ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); - - return filelist_geticon_image_ex(file->typeflag, file->relpath); -} - -static int filelist_geticon_ex( - const int typeflag, const int blentype, const char *relpath, const bool is_main, const bool ignore_libdir) -{ - if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { - if (FILENAME_IS_PARENT(relpath)) { - return is_main ? ICON_FILE_PARENT : ICON_NONE; - } - else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) { - return ICON_UGLYPACKAGE; - } - else if (typeflag & FILE_TYPE_BLENDER) { - return ICON_FILE_BLEND; - } - else if (is_main) { - /* Do not return icon for folders if icons are not 'main' draw type - * (e.g. when used over previews). */ - return ICON_FILE_FOLDER; - } - } - - if (typeflag & FILE_TYPE_BLENDER) - return ICON_FILE_BLEND; - else if (typeflag & FILE_TYPE_BLENDER_BACKUP) - return ICON_FILE_BACKUP; - else if (typeflag & FILE_TYPE_IMAGE) - return ICON_FILE_IMAGE; - else if (typeflag & FILE_TYPE_MOVIE) - return ICON_FILE_MOVIE; - else if (typeflag & FILE_TYPE_PYSCRIPT) - return ICON_FILE_SCRIPT; - else if (typeflag & FILE_TYPE_SOUND) - return ICON_FILE_SOUND; - else if (typeflag & FILE_TYPE_FTFONT) - return ICON_FILE_FONT; - else if (typeflag & FILE_TYPE_BTX) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_COLLADA) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_ALEMBIC) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_TEXT) - return ICON_FILE_TEXT; - else if (typeflag & FILE_TYPE_BLENDERLIB) { - const int ret = UI_idcode_icon_get(blentype); - if (ret != ICON_NONE) { - return ret; - } - } - return is_main ? ICON_FILE_BLANK : ICON_NONE; + FileDirEntry *file = filelist_geticon_get_file(filelist, index); + + return filelist_geticon_image_ex(file->typeflag, file->relpath); +} + +static int filelist_geticon_ex(const int typeflag, + const int blentype, + const char *relpath, + const bool is_main, + const bool ignore_libdir) +{ + if ((typeflag & FILE_TYPE_DIR) && + !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { + if (FILENAME_IS_PARENT(relpath)) { + return is_main ? ICON_FILE_PARENT : ICON_NONE; + } + else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) { + return ICON_UGLYPACKAGE; + } + else if (typeflag & FILE_TYPE_BLENDER) { + return ICON_FILE_BLEND; + } + else if (is_main) { + /* Do not return icon for folders if icons are not 'main' draw type + * (e.g. when used over previews). */ + return ICON_FILE_FOLDER; + } + } + + if (typeflag & FILE_TYPE_BLENDER) + return ICON_FILE_BLEND; + else if (typeflag & FILE_TYPE_BLENDER_BACKUP) + return ICON_FILE_BACKUP; + else if (typeflag & FILE_TYPE_IMAGE) + return ICON_FILE_IMAGE; + else if (typeflag & FILE_TYPE_MOVIE) + return ICON_FILE_MOVIE; + else if (typeflag & FILE_TYPE_PYSCRIPT) + return ICON_FILE_SCRIPT; + else if (typeflag & FILE_TYPE_SOUND) + return ICON_FILE_SOUND; + else if (typeflag & FILE_TYPE_FTFONT) + return ICON_FILE_FONT; + else if (typeflag & FILE_TYPE_BTX) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_COLLADA) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_ALEMBIC) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_TEXT) + return ICON_FILE_TEXT; + else if (typeflag & FILE_TYPE_BLENDERLIB) { + const int ret = UI_idcode_icon_get(blentype); + if (ret != ICON_NONE) { + return ret; + } + } + return is_main ? ICON_FILE_BLANK : ICON_NONE; } int filelist_geticon(struct FileList *filelist, const int index, const bool is_main) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); + FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false); + return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false); } /* ********** Main ********** */ -static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) +static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), + char *r_dir, + const bool do_change) { - if (do_change) { - BLI_make_exist(r_dir); - return true; - } - else { - return BLI_is_dir(r_dir); - } + if (do_change) { + BLI_make_exist(r_dir); + return true; + } + else { + return BLI_is_dir(r_dir); + } } -static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) +static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), + char *r_dir, + const bool do_change) { - char tdir[FILE_MAX_LIBEXTRA]; - char *name; + char tdir[FILE_MAX_LIBEXTRA]; + char *name; - const bool is_valid = (BLI_is_dir(r_dir) || - (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name)); + const bool is_valid = (BLI_is_dir(r_dir) || + (BLO_library_path_explode(r_dir, tdir, NULL, &name) && + BLI_is_file(tdir) && !name)); - if (do_change && !is_valid) { - /* if not a valid library, we need it to be a valid directory! */ - BLI_make_exist(r_dir); - return true; - } - return is_valid; + if (do_change && !is_valid) { + /* if not a valid library, we need it to be a valid directory! */ + BLI_make_exist(r_dir); + return true; + } + return is_valid; } static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change) { - /* TODO */ - return filelist_checkdir_lib(filelist, r_dir, do_change); + /* TODO */ + return filelist_checkdir_lib(filelist, r_dir, do_change); } static void filelist_entry_clear(FileDirEntry *entry) { - if (entry->name) { - MEM_freeN(entry->name); - } - if (entry->description) { - MEM_freeN(entry->description); - } - if (entry->relpath) { - MEM_freeN(entry->relpath); - } - if (entry->image) { - IMB_freeImBuf(entry->image); - } - /* For now, consider FileDirEntryRevision::poin as not owned here, - * so no need to do anything about it */ - - if (!BLI_listbase_is_empty(&entry->variants)) { - FileDirEntryVariant *var; - - for (var = entry->variants.first; var; var = var->next) { - if (var->name) { - MEM_freeN(var->name); - } - if (var->description) { - MEM_freeN(var->description); - } - - if (!BLI_listbase_is_empty(&var->revisions)) { - FileDirEntryRevision *rev; - - for (rev = var->revisions.first; rev; rev = rev->next) { - if (rev->comment) { - MEM_freeN(rev->comment); - } - } - - BLI_freelistN(&var->revisions); - } - } - - /* TODO: tags! */ - - BLI_freelistN(&entry->variants); - } - else if (entry->entry) { - MEM_freeN(entry->entry); - } + if (entry->name) { + MEM_freeN(entry->name); + } + if (entry->description) { + MEM_freeN(entry->description); + } + if (entry->relpath) { + MEM_freeN(entry->relpath); + } + if (entry->image) { + IMB_freeImBuf(entry->image); + } + /* For now, consider FileDirEntryRevision::poin as not owned here, + * so no need to do anything about it */ + + if (!BLI_listbase_is_empty(&entry->variants)) { + FileDirEntryVariant *var; + + for (var = entry->variants.first; var; var = var->next) { + if (var->name) { + MEM_freeN(var->name); + } + if (var->description) { + MEM_freeN(var->description); + } + + if (!BLI_listbase_is_empty(&var->revisions)) { + FileDirEntryRevision *rev; + + for (rev = var->revisions.first; rev; rev = rev->next) { + if (rev->comment) { + MEM_freeN(rev->comment); + } + } + + BLI_freelistN(&var->revisions); + } + } + + /* TODO: tags! */ + + BLI_freelistN(&entry->variants); + } + else if (entry->entry) { + MEM_freeN(entry->entry); + } } static void filelist_entry_free(FileDirEntry *entry) { - filelist_entry_clear(entry); - MEM_freeN(entry); + filelist_entry_clear(entry); + MEM_freeN(entry); } static void filelist_direntryarr_free(FileDirEntryArr *array) { #if 0 - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - for (entry = array->entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&array->entries); + for (entry = array->entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&array->entries); #else - BLI_assert(BLI_listbase_is_empty(&array->entries)); + BLI_assert(BLI_listbase_is_empty(&array->entries)); #endif - array->nbr_entries = 0; - array->nbr_entries_filtered = -1; - array->entry_idx_start = -1; - array->entry_idx_end = -1; + array->nbr_entries = 0; + array->nbr_entries_filtered = -1; + array->entry_idx_start = -1; + array->entry_idx_end = -1; } static void filelist_intern_entry_free(FileListInternEntry *entry) { - if (entry->relpath) { - MEM_freeN(entry->relpath); - } - if (entry->name) { - MEM_freeN(entry->name); - } - MEM_freeN(entry); + if (entry->relpath) { + MEM_freeN(entry->relpath); + } + if (entry->name) { + MEM_freeN(entry->name); + } + MEM_freeN(entry); } static void filelist_intern_free(FileListIntern *filelist_intern) { - FileListInternEntry *entry, *entry_next; + FileListInternEntry *entry, *entry_next; - for (entry = filelist_intern->entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_intern_entry_free(entry); - } - BLI_listbase_clear(&filelist_intern->entries); + for (entry = filelist_intern->entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_intern_entry_free(entry); + } + BLI_listbase_clear(&filelist_intern->entries); - MEM_SAFE_FREE(filelist_intern->filtered); + MEM_SAFE_FREE(filelist_intern->filtered); } -static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void filelist_cache_preview_runf(TaskPool *__restrict pool, + void *taskdata, + int UNUSED(threadid)) { - FileListEntryCache *cache = BLI_task_pool_userdata(pool); - FileListEntryPreview *preview = taskdata; + FileListEntryCache *cache = BLI_task_pool_userdata(pool); + FileListEntryPreview *preview = taskdata; - ThumbSource source = 0; + ThumbSource source = 0; -// printf("%s: Start (%d)...\n", __func__, threadid); + // printf("%s: Start (%d)...\n", __func__, threadid); -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - BLI_assert(preview->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | - FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + BLI_assert(preview->flags & + (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | + FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - if (preview->flags & FILE_TYPE_IMAGE) { - source = THB_SOURCE_IMAGE; - } - else if (preview->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { - source = THB_SOURCE_BLEND; - } - else if (preview->flags & FILE_TYPE_MOVIE) { - source = THB_SOURCE_MOVIE; - } - else if (preview->flags & FILE_TYPE_FTFONT) { - source = THB_SOURCE_FONT; - } + if (preview->flags & FILE_TYPE_IMAGE) { + source = THB_SOURCE_IMAGE; + } + else if (preview->flags & + (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { + source = THB_SOURCE_BLEND; + } + else if (preview->flags & FILE_TYPE_MOVIE) { + source = THB_SOURCE_MOVIE; + } + else if (preview->flags & FILE_TYPE_FTFONT) { + source = THB_SOURCE_FONT; + } - IMB_thumb_path_lock(preview->path); - preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); - IMB_thumb_path_unlock(preview->path); + IMB_thumb_path_lock(preview->path); + preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); + IMB_thumb_path_unlock(preview->path); - /* Used to tell free func to not free anything. - * Note that we do not care about cas result here, - * we only want value attribution itself to be atomic (and memory barier).*/ - atomic_cas_uint32(&preview->flags, preview->flags, 0); - BLI_thread_queue_push(cache->previews_done, preview); + /* Used to tell free func to not free anything. + * Note that we do not care about cas result here, + * we only want value attribution itself to be atomic (and memory barier).*/ + atomic_cas_uint32(&preview->flags, preview->flags, 0); + BLI_thread_queue_push(cache->previews_done, preview); -// printf("%s: End (%d)...\n", __func__, threadid); + // printf("%s: End (%d)...\n", __func__, threadid); } -static void filelist_cache_preview_freef(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), + void *taskdata, + int UNUSED(threadid)) { - FileListEntryPreview *preview = taskdata; + FileListEntryPreview *preview = taskdata; - /* If preview->flag is empty, it means that preview has already been generated and added to done queue, - * we do not own it anymore. */ - if (preview->flags) { - if (preview->img) { - IMB_freeImBuf(preview->img); - } - MEM_freeN(preview); - } + /* If preview->flag is empty, it means that preview has already been generated and added to done queue, + * we do not own it anymore. */ + if (preview->flags) { + if (preview->img) { + IMB_freeImBuf(preview->img); + } + MEM_freeN(preview); + } } static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) { - if (!cache->previews_pool) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); + if (!cache->previews_pool) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); - cache->previews_pool = BLI_task_pool_create_background(scheduler, cache); - cache->previews_done = BLI_thread_queue_init(); + cache->previews_pool = BLI_task_pool_create_background(scheduler, cache); + cache->previews_done = BLI_thread_queue_init(); - IMB_thumb_locks_acquire(); - } + IMB_thumb_locks_acquire(); + } } static void filelist_cache_previews_clear(FileListEntryCache *cache) { - FileListEntryPreview *preview; + FileListEntryPreview *preview; - if (cache->previews_pool) { - BLI_task_pool_cancel(cache->previews_pool); + if (cache->previews_pool) { + BLI_task_pool_cancel(cache->previews_pool); - while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { -// printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->img) { - IMB_freeImBuf(preview->img); - } - MEM_freeN(preview); - } - } + while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { + // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + if (preview->img) { + IMB_freeImBuf(preview->img); + } + MEM_freeN(preview); + } + } } static void filelist_cache_previews_free(FileListEntryCache *cache) { - if (cache->previews_pool) { - BLI_thread_queue_nowait(cache->previews_done); + if (cache->previews_pool) { + BLI_thread_queue_nowait(cache->previews_done); - filelist_cache_previews_clear(cache); + filelist_cache_previews_clear(cache); - BLI_thread_queue_free(cache->previews_done); - BLI_task_pool_free(cache->previews_pool); - cache->previews_pool = NULL; - cache->previews_done = NULL; + BLI_thread_queue_free(cache->previews_done); + BLI_task_pool_free(cache->previews_pool); + cache->previews_pool = NULL; + cache->previews_done = NULL; - IMB_thumb_locks_release(); - } + IMB_thumb_locks_release(); + } - cache->flags &= ~FLC_PREVIEWS_ACTIVE; + cache->flags &= ~FLC_PREVIEWS_ACTIVE; } static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); + BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); - if (!entry->image && - !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && - (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | - FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) - { - FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - BLI_join_dirfile(preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); - preview->index = index; - preview->flags = entry->typeflag; - preview->img = NULL; -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + if (!entry->image && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && + (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | + FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { + FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + preview->index = index; + preview->flags = entry->typeflag; + preview->img = NULL; + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - filelist_cache_preview_ensure_running(cache); - BLI_task_pool_push_ex(cache->previews_pool, filelist_cache_preview_runf, preview, - true, filelist_cache_preview_freef, TASK_PRIORITY_LOW); - } + filelist_cache_preview_ensure_running(cache); + BLI_task_pool_push_ex(cache->previews_pool, + filelist_cache_preview_runf, + preview, + true, + filelist_cache_preview_freef, + TASK_PRIORITY_LOW); + } } static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) { - BLI_listbase_clear(&cache->cached_entries); + BLI_listbase_clear(&cache->cached_entries); - cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; - cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); + cache->block_cursor = cache->block_start_index = cache->block_center_index = + cache->block_end_index = 0; + cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); - cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size); - cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, __func__); - copy_vn_i(cache->misc_entries_indices, cache_size, -1); - cache->misc_cursor = 0; + cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size); + cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, + __func__); + copy_vn_i(cache->misc_entries_indices, cache_size, -1); + cache->misc_cursor = 0; - /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */ - cache->uuids = BLI_ghash_new_ex( - BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2); + /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */ + cache->uuids = BLI_ghash_new_ex( + BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2); - cache->size = cache_size; - cache->flags = FLC_IS_INIT; + cache->size = cache_size; + cache->flags = FLC_IS_INIT; } static void filelist_cache_free(FileListEntryCache *cache) { - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { - return; - } + if (!(cache->flags & FLC_IS_INIT)) { + return; + } - filelist_cache_previews_free(cache); + filelist_cache_previews_free(cache); - MEM_freeN(cache->block_entries); + MEM_freeN(cache->block_entries); - BLI_ghash_free(cache->misc_entries, NULL, NULL); - MEM_freeN(cache->misc_entries_indices); + BLI_ghash_free(cache->misc_entries, NULL, NULL); + MEM_freeN(cache->misc_entries_indices); - BLI_ghash_free(cache->uuids, NULL, NULL); + BLI_ghash_free(cache->uuids, NULL, NULL); - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&cache->cached_entries); + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) { - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { - return; - } + if (!(cache->flags & FLC_IS_INIT)) { + return; + } - filelist_cache_previews_clear(cache); + filelist_cache_previews_clear(cache); - cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; - if (new_size != cache->size) { - cache->block_entries = MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size); - } + cache->block_cursor = cache->block_start_index = cache->block_center_index = + cache->block_end_index = 0; + if (new_size != cache->size) { + cache->block_entries = MEM_reallocN(cache->block_entries, + sizeof(*cache->block_entries) * new_size); + } - BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size); - if (new_size != cache->size) { - cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices, - sizeof(*cache->misc_entries_indices) * new_size); - } - copy_vn_i(cache->misc_entries_indices, new_size, -1); + BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size); + if (new_size != cache->size) { + cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices, + sizeof(*cache->misc_entries_indices) * new_size); + } + copy_vn_i(cache->misc_entries_indices, new_size, -1); - BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2); + BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2); - cache->size = new_size; + cache->size = new_size; - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&cache->cached_entries); + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } FileList *filelist_new(short type) { - FileList *p = MEM_callocN(sizeof(*p), __func__); - - filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); - - p->selection_state = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); - - switch (type) { - case FILE_MAIN: - p->checkdirf = filelist_checkdir_main; - p->read_jobf = filelist_readjob_main; - p->filterf = is_filtered_main; - break; - case FILE_LOADLIB: - p->checkdirf = filelist_checkdir_lib; - p->read_jobf = filelist_readjob_lib; - p->filterf = is_filtered_lib; - break; - default: - p->checkdirf = filelist_checkdir_dir; - p->read_jobf = filelist_readjob_dir; - p->filterf = is_filtered_file; - break; - } - return p; + FileList *p = MEM_callocN(sizeof(*p), __func__); + + filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); + + p->selection_state = BLI_ghash_new( + BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); + + switch (type) { + case FILE_MAIN: + p->checkdirf = filelist_checkdir_main; + p->read_jobf = filelist_readjob_main; + p->filterf = is_filtered_main; + break; + case FILE_LOADLIB: + p->checkdirf = filelist_checkdir_lib; + p->read_jobf = filelist_readjob_lib; + p->filterf = is_filtered_lib; + break; + default: + p->checkdirf = filelist_checkdir_dir; + p->read_jobf = filelist_readjob_dir; + p->filterf = is_filtered_file; + break; + } + return p; } void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection) { - if (!filelist) { - return; - } + if (!filelist) { + return; + } - filelist_filter_clear(filelist); + filelist_filter_clear(filelist); - if (do_cache) { - filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); - } + if (do_cache) { + filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); + } - filelist_intern_free(&filelist->filelist_intern); + filelist_intern_free(&filelist->filelist_intern); - filelist_direntryarr_free(&filelist->filelist); + filelist_direntryarr_free(&filelist->filelist); - if (do_selection && filelist->selection_state) { - BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL); - } + if (do_selection && filelist->selection_state) { + BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL); + } } void filelist_clear(struct FileList *filelist) { - filelist_clear_ex(filelist, true, true); + filelist_clear_ex(filelist, true, true); } void filelist_free(struct FileList *filelist) { - if (!filelist) { - printf("Attempting to delete empty filelist.\n"); - return; - } + if (!filelist) { + printf("Attempting to delete empty filelist.\n"); + return; + } - /* No need to clear cache & selection_state, we free them anyway. */ - filelist_clear_ex(filelist, false, false); - filelist_cache_free(&filelist->filelist_cache); + /* No need to clear cache & selection_state, we free them anyway. */ + filelist_clear_ex(filelist, false, false); + filelist_cache_free(&filelist->filelist_cache); - if (filelist->selection_state) { - BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL); - filelist->selection_state = NULL; - } + if (filelist->selection_state) { + BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL); + filelist->selection_state = NULL; + } - memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); + memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); - filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); - filelist->sort = FILE_SORT_NONE; + filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); + filelist->sort = FILE_SORT_NONE; } void filelist_freelib(struct FileList *filelist) { - if (filelist->libfiledata) - BLO_blendhandle_close(filelist->libfiledata); - filelist->libfiledata = NULL; + if (filelist->libfiledata) + BLO_blendhandle_close(filelist->libfiledata); + filelist->libfiledata = NULL; } BlendHandle *filelist_lib(struct FileList *filelist) { - return filelist->libfiledata; + return filelist->libfiledata; } -static const char *fileentry_uiname(const char *root, const char *relpath, const int typeflag, char *buff) +static const char *fileentry_uiname(const char *root, + const char *relpath, + const int typeflag, + char *buff) { - char *name = NULL; + char *name = NULL; - if (typeflag & FILE_TYPE_BLENDERLIB) { - char abspath[FILE_MAX_LIBEXTRA]; - char *group; + if (typeflag & FILE_TYPE_BLENDERLIB) { + char abspath[FILE_MAX_LIBEXTRA]; + char *group; - BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); - BLO_library_path_explode(abspath, buff, &group, &name); - if (!name) { - name = group; - } - } - /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */ - if (!name) { - if (typeflag & FILE_TYPE_DIR) { - name = (char *)relpath; - } - else { - name = (char *)BLI_path_basename(relpath); - } - } - BLI_assert(name); + BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); + BLO_library_path_explode(abspath, buff, &group, &name); + if (!name) { + name = group; + } + } + /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */ + if (!name) { + if (typeflag & FILE_TYPE_DIR) { + name = (char *)relpath; + } + else { + name = (char *)BLI_path_basename(relpath); + } + } + BLI_assert(name); - return name; + return name; } const char *filelist_dir(struct FileList *filelist) { - return filelist->filelist.root; + return filelist->filelist.root; } bool filelist_is_dir(struct FileList *filelist, const char *path) { - return filelist->checkdirf(filelist, (char *)path, false); + return filelist->checkdirf(filelist, (char *)path, false); } /** @@ -1418,40 +1477,40 @@ bool filelist_is_dir(struct FileList *filelist, const char *path) */ void filelist_setdir(struct FileList *filelist, char *r_dir) { - BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); + BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); - BLI_assert(is_valid_path); - UNUSED_VARS_NDEBUG(is_valid_path); + BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); + const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); + BLI_assert(is_valid_path); + UNUSED_VARS_NDEBUG(is_valid_path); - if (!STREQ(filelist->filelist.root, r_dir)) { - BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root)); - filelist->flags |= FL_FORCE_RESET; - } + if (!STREQ(filelist->filelist.root, r_dir)) { + BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root)); + filelist->flags |= FL_FORCE_RESET; + } } void filelist_setrecursion(struct FileList *filelist, const int recursion_level) { - if (filelist->max_recursion != recursion_level) { - filelist->max_recursion = recursion_level; - filelist->flags |= FL_FORCE_RESET; - } + if (filelist->max_recursion != recursion_level) { + filelist->max_recursion = recursion_level; + filelist->flags |= FL_FORCE_RESET; + } } bool filelist_force_reset(struct FileList *filelist) { - return (filelist->flags & FL_FORCE_RESET) != 0; + return (filelist->flags & FL_FORCE_RESET) != 0; } bool filelist_is_ready(struct FileList *filelist) { - return (filelist->flags & FL_IS_READY) != 0; + return (filelist->flags & FL_IS_READY) != 0; } bool filelist_pending(struct FileList *filelist) { - return (filelist->flags & FL_IS_PENDING) != 0; + return (filelist->flags & FL_IS_PENDING) != 0; } /** @@ -1460,740 +1519,759 @@ bool filelist_pending(struct FileList *filelist) */ int filelist_files_ensure(FileList *filelist) { - if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { - filelist_sort(filelist); - filelist_filter(filelist); - } + if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { + filelist_sort(filelist); + filelist_filter(filelist); + } - return filelist->filelist.nbr_entries_filtered; + return filelist->filelist.nbr_entries_filtered; } static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[index]; - FileListEntryCache *cache = &filelist->filelist_cache; - FileDirEntry *ret; - FileDirEntryRevision *rev; + FileListInternEntry *entry = filelist->filelist_intern.filtered[index]; + FileListEntryCache *cache = &filelist->filelist_cache; + FileDirEntry *ret; + FileDirEntryRevision *rev; - ret = MEM_callocN(sizeof(*ret), __func__); - rev = MEM_callocN(sizeof(*rev), __func__); + ret = MEM_callocN(sizeof(*ret), __func__); + rev = MEM_callocN(sizeof(*rev), __func__); - rev->size = (uint64_t)entry->st.st_size; + rev->size = (uint64_t)entry->st.st_size; - rev->time = (int64_t)entry->st.st_mtime; + rev->time = (int64_t)entry->st.st_mtime; - ret->entry = rev; - ret->relpath = BLI_strdup(entry->relpath); - ret->name = BLI_strdup(entry->name); - ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath); - memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); - ret->blentype = entry->blentype; - ret->typeflag = entry->typeflag; + ret->entry = rev; + ret->relpath = BLI_strdup(entry->relpath); + ret->name = BLI_strdup(entry->name); + ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath); + memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); + ret->blentype = entry->blentype; + ret->typeflag = entry->typeflag; - BLI_addtail(&cache->cached_entries, ret); - return ret; + BLI_addtail(&cache->cached_entries, ret); + return ret; } static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) { - BLI_remlink(&filelist->filelist_cache.cached_entries, entry); - filelist_entry_free(entry); + BLI_remlink(&filelist->filelist_cache.cached_entries, entry); + filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) +static FileDirEntry *filelist_file_ex(struct FileList *filelist, + const int index, + const bool use_request) { - FileDirEntry *ret = NULL, *old; - FileListEntryCache *cache = &filelist->filelist_cache; - const size_t cache_size = cache->size; - int old_index; + FileDirEntry *ret = NULL, *old; + FileListEntryCache *cache = &filelist->filelist_cache; + const size_t cache_size = cache->size; + int old_index; - if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) { - return ret; - } + if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) { + return ret; + } - if (index >= cache->block_start_index && index < cache->block_end_index) { - const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size; - return cache->block_entries[idx]; - } + if (index >= cache->block_start_index && index < cache->block_end_index) { + const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size; + return cache->block_entries[idx]; + } - if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) { - return ret; - } + if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) { + return ret; + } - if (!use_request) { - return NULL; - } + if (!use_request) { + return NULL; + } -// printf("requesting file %d (not yet cached)\n", index); + // printf("requesting file %d (not yet cached)\n", index); - /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */ - ret = filelist_file_create_entry(filelist, index); - old_index = cache->misc_entries_indices[cache->misc_cursor]; - if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) { - BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL); - filelist_file_release_entry(filelist, old); - } - BLI_ghash_insert(cache->misc_entries, POINTER_FROM_INT(index), ret); - BLI_ghash_insert(cache->uuids, ret->uuid, ret); + /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */ + ret = filelist_file_create_entry(filelist, index); + old_index = cache->misc_entries_indices[cache->misc_cursor]; + if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) { + BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL); + filelist_file_release_entry(filelist, old); + } + BLI_ghash_insert(cache->misc_entries, POINTER_FROM_INT(index), ret); + BLI_ghash_insert(cache->uuids, ret->uuid, ret); - cache->misc_entries_indices[cache->misc_cursor] = index; - cache->misc_cursor = (cache->misc_cursor + 1) % cache_size; + cache->misc_entries_indices[cache->misc_cursor] = index; + cache->misc_cursor = (cache->misc_cursor + 1) % cache_size; -#if 0 /* Actually no, only block cached entries should have preview imho. */ - if (cache->previews_pool) { - filelist_cache_previews_push(filelist, ret, index); - } +#if 0 /* Actually no, only block cached entries should have preview imho. */ + if (cache->previews_pool) { + filelist_cache_previews_push(filelist, ret, index); + } #endif - return ret; + return ret; } FileDirEntry *filelist_file(struct FileList *filelist, int index) { - return filelist_file_ex(filelist, index, true); + return filelist_file_ex(filelist, index, true); } int filelist_file_findpath(struct FileList *filelist, const char *filename) { - int fidx = -1; + int fidx = -1; - if (filelist->filelist.nbr_entries_filtered < 0) { - return fidx; - } + if (filelist->filelist.nbr_entries_filtered < 0) { + return fidx; + } - /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though. - * This is only used to find again renamed entry, - * annoying but looks hairy to get rid of it currently. */ + /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though. + * This is only used to find again renamed entry, + * annoying but looks hairy to get rid of it currently. */ - for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; - if (STREQ(entry->relpath, filename)) { - return fidx; - } - } + for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; + if (STREQ(entry->relpath, filename)) { + return fidx; + } + } - return -1; + return -1; } FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]) { - if (filelist->filelist.nbr_entries_filtered < 0) { - return NULL; - } + if (filelist->filelist.nbr_entries_filtered < 0) { + return NULL; + } - if (filelist->filelist_cache.uuids) { - FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid); - if (entry) { - return entry; - } - } + if (filelist->filelist_cache.uuids) { + FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid); + if (entry) { + return entry; + } + } - { - int fidx; + { + int fidx; - for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; - if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) { - return filelist_file(filelist, fidx); - } - } - } + for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; + if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) { + return filelist_file(filelist, fidx); + } + } + } - return NULL; + return NULL; } void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size) { - /* Always keep it power of 2, in [256, 8192] range for now, - * cache being app. twice bigger than requested window. */ - size_t size = 256; - window_size *= 2; + /* Always keep it power of 2, in [256, 8192] range for now, + * cache being app. twice bigger than requested window. */ + size_t size = 256; + window_size *= 2; - while (size < window_size && size < 8192) { - size *= 2; - } + while (size < window_size && size < 8192) { + size *= 2; + } - if (size != filelist->filelist_cache.size) { - filelist_cache_clear(&filelist->filelist_cache, size); - } + if (size != filelist->filelist_cache.size) { + filelist_cache_clear(&filelist->filelist_cache, size); + } } /* Helpers, low-level, they assume cursor + size <= cache_size */ -static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor) +static bool filelist_file_cache_block_create(FileList *filelist, + const int start_index, + const int size, + int cursor) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - { - int i, idx; + { + int i, idx; - for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) { - FileDirEntry *entry; + for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) { + FileDirEntry *entry; - /* That entry might have already been requested and stored in misc cache... */ - if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) { - entry = filelist_file_create_entry(filelist, idx); - BLI_ghash_insert(cache->uuids, entry->uuid, entry); - } - cache->block_entries[cursor] = entry; - } - return true; - } + /* That entry might have already been requested and stored in misc cache... */ + if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) { + entry = filelist_file_create_entry(filelist, idx); + BLI_ghash_insert(cache->uuids, entry->uuid, entry); + } + cache->block_entries[cursor] = entry; + } + return true; + } - return false; + return false; } -static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor) +static void filelist_file_cache_block_release(struct FileList *filelist, + const int size, + int cursor) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - { - int i; + { + int i; - for (i = 0; i < size; i++, cursor++) { - FileDirEntry *entry = cache->block_entries[cursor]; -// printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/); - BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL); - filelist_file_release_entry(filelist, entry); + for (i = 0; i < size; i++, cursor++) { + FileDirEntry *entry = cache->block_entries[cursor]; + // printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/); + BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL); + filelist_file_release_entry(filelist, entry); #ifndef NDEBUG - cache->block_entries[cursor] = NULL; + cache->block_entries[cursor] = NULL; #endif - } - } + } + } } /* Load in cache all entries "around" given index (as much as block cache may hold). */ bool filelist_file_cache_block(struct FileList *filelist, const int index) { - FileListEntryCache *cache = &filelist->filelist_cache; - const size_t cache_size = cache->size; - - const int nbr_entries = filelist->filelist.nbr_entries_filtered; - int start_index = max_ii(0, index - (cache_size / 2)); - int end_index = min_ii(nbr_entries, index + (cache_size / 2)); - int i; - const bool full_refresh = (filelist->flags & FL_IS_READY) == 0; - - if ((index < 0) || (index >= nbr_entries)) { -// printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries); - return false; - } - - /* Maximize cached range! */ - if ((end_index - start_index) < cache_size) { - if (start_index == 0) { - end_index = min_ii(nbr_entries, start_index + cache_size); - } - else if (end_index == nbr_entries) { - start_index = max_ii(0, end_index - cache_size); - } - } - - BLI_assert((end_index - start_index) <= cache_size) ; - -// printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__, -// start_index, end_index, index, cache->block_start_index, cache->block_end_index); - - /* If we have something to (re)cache... */ - if (full_refresh || (start_index != cache->block_start_index) || (end_index != cache->block_end_index)) { - if (full_refresh || (start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) { - int size1 = cache->block_end_index - cache->block_start_index; - int size2 = 0; - int idx1 = cache->block_cursor, idx2 = 0; - -// printf("Full Recaching!\n"); - - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - filelist_cache_previews_clear(cache); - } - - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_start_index = cache->block_end_index = cache->block_cursor = 0; - - /* New cached block does not overlap existing one, simple. */ - if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) { - return false; - } - - cache->block_start_index = start_index; - cache->block_end_index = end_index; - } - else { -// printf("Partial Recaching!\n"); - - /* At this point, we know we keep part of currently cached entries, so update previews - * if needed, and remove everything from working queue - we'll add all newly needed - * entries at the end. */ - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - filelist_cache_previews_update(filelist); - filelist_cache_previews_clear(cache); - } - -// printf("\tpreview cleaned up...\n"); - - if (start_index > cache->block_start_index) { - int size1 = start_index - cache->block_start_index; - int size2 = 0; - int idx1 = cache->block_cursor, idx2 = 0; - -// printf("\tcache releasing: [%d:%d] (%d, %d)\n", -// cache->block_start_index, cache->block_start_index + size1, -// cache->block_cursor, size1); - - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_cursor = (idx1 + size1 + size2) % cache_size; - cache->block_start_index = start_index; - } - if (end_index < cache->block_end_index) { - int size1 = cache->block_end_index - end_index; - int size2 = 0; - int idx1, idx2 = 0; - -// printf("\tcache releasing: [%d:%d] (%d)\n", -// cache->block_end_index - size1, cache->block_end_index, cache->block_cursor); - - idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size; - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_end_index = end_index; - } - -// printf("\tcache cleaned up...\n"); - - if (start_index < cache->block_start_index) { - /* Add (request) needed entries before already cached ones. */ - /* Note: We need some index black magic to wrap around (cycle) - * inside our cache_size array... */ - int size1 = cache->block_start_index - start_index; - int size2 = 0; - int idx1, idx2; - - if (size1 > cache->block_cursor) { - size2 = size1; - size1 -= cache->block_cursor; - size2 -= size1; - idx2 = 0; - idx1 = cache_size - size1; - } - else { - idx1 = cache->block_cursor - size1; - } - - if (size2) { - if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) { - return false; - } - } - if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) { - return false; - } - - cache->block_cursor = idx1; - cache->block_start_index = start_index; - } -// printf("\tstart-extended...\n"); - if (end_index > cache->block_end_index) { - /* Add (request) needed entries after already cached ones. */ - /* Note: We need some index black magic to wrap around (cycle) - * inside our cache_size array... */ - int size1 = end_index - cache->block_end_index; - int size2 = 0; - int idx1, idx2; - - idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size; - if ((idx1 + size1) > cache_size) { - size2 = size1; - size1 = cache_size - idx1; - size2 -= size1; - idx2 = 0; - } - - if (size2) { - if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) { - return false; - } - } - if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) { - return false; - } - - cache->block_end_index = end_index; - } - -// printf("\tend-extended...\n"); - } - } - else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) { - /* We try to always preview visible entries first, so 'restart' preview background task. */ - filelist_cache_previews_update(filelist); - filelist_cache_previews_clear(cache); - } - -// printf("Re-queueing previews...\n"); - - /* Note we try to preview first images around given index - i.e. assumed visible ones. */ - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) { - if ((index - i) >= start_index) { - const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i); - } - if ((index + i) < end_index) { - const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i); - } - } - } - - cache->block_center_index = index; - -// printf("%s Finished!\n", __func__); - - return true; + FileListEntryCache *cache = &filelist->filelist_cache; + const size_t cache_size = cache->size; + + const int nbr_entries = filelist->filelist.nbr_entries_filtered; + int start_index = max_ii(0, index - (cache_size / 2)); + int end_index = min_ii(nbr_entries, index + (cache_size / 2)); + int i; + const bool full_refresh = (filelist->flags & FL_IS_READY) == 0; + + if ((index < 0) || (index >= nbr_entries)) { + // printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries); + return false; + } + + /* Maximize cached range! */ + if ((end_index - start_index) < cache_size) { + if (start_index == 0) { + end_index = min_ii(nbr_entries, start_index + cache_size); + } + else if (end_index == nbr_entries) { + start_index = max_ii(0, end_index - cache_size); + } + } + + BLI_assert((end_index - start_index) <= cache_size); + + // printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__, + // start_index, end_index, index, cache->block_start_index, cache->block_end_index); + + /* If we have something to (re)cache... */ + if (full_refresh || (start_index != cache->block_start_index) || + (end_index != cache->block_end_index)) { + if (full_refresh || (start_index >= cache->block_end_index) || + (end_index <= cache->block_start_index)) { + int size1 = cache->block_end_index - cache->block_start_index; + int size2 = 0; + int idx1 = cache->block_cursor, idx2 = 0; + + // printf("Full Recaching!\n"); + + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + filelist_cache_previews_clear(cache); + } + + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_start_index = cache->block_end_index = cache->block_cursor = 0; + + /* New cached block does not overlap existing one, simple. */ + if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) { + return false; + } + + cache->block_start_index = start_index; + cache->block_end_index = end_index; + } + else { + // printf("Partial Recaching!\n"); + + /* At this point, we know we keep part of currently cached entries, so update previews + * if needed, and remove everything from working queue - we'll add all newly needed + * entries at the end. */ + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + filelist_cache_previews_update(filelist); + filelist_cache_previews_clear(cache); + } + + // printf("\tpreview cleaned up...\n"); + + if (start_index > cache->block_start_index) { + int size1 = start_index - cache->block_start_index; + int size2 = 0; + int idx1 = cache->block_cursor, idx2 = 0; + + // printf("\tcache releasing: [%d:%d] (%d, %d)\n", + // cache->block_start_index, cache->block_start_index + size1, + // cache->block_cursor, size1); + + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_cursor = (idx1 + size1 + size2) % cache_size; + cache->block_start_index = start_index; + } + if (end_index < cache->block_end_index) { + int size1 = cache->block_end_index - end_index; + int size2 = 0; + int idx1, idx2 = 0; + + // printf("\tcache releasing: [%d:%d] (%d)\n", + // cache->block_end_index - size1, cache->block_end_index, cache->block_cursor); + + idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size; + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_end_index = end_index; + } + + // printf("\tcache cleaned up...\n"); + + if (start_index < cache->block_start_index) { + /* Add (request) needed entries before already cached ones. */ + /* Note: We need some index black magic to wrap around (cycle) + * inside our cache_size array... */ + int size1 = cache->block_start_index - start_index; + int size2 = 0; + int idx1, idx2; + + if (size1 > cache->block_cursor) { + size2 = size1; + size1 -= cache->block_cursor; + size2 -= size1; + idx2 = 0; + idx1 = cache_size - size1; + } + else { + idx1 = cache->block_cursor - size1; + } + + if (size2) { + if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) { + return false; + } + } + if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) { + return false; + } + + cache->block_cursor = idx1; + cache->block_start_index = start_index; + } + // printf("\tstart-extended...\n"); + if (end_index > cache->block_end_index) { + /* Add (request) needed entries after already cached ones. */ + /* Note: We need some index black magic to wrap around (cycle) + * inside our cache_size array... */ + int size1 = end_index - cache->block_end_index; + int size2 = 0; + int idx1, idx2; + + idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size; + if ((idx1 + size1) > cache_size) { + size2 = size1; + size1 = cache_size - idx1; + size2 -= size1; + idx2 = 0; + } + + if (size2) { + if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) { + return false; + } + } + if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) { + return false; + } + + cache->block_end_index = end_index; + } + + // printf("\tend-extended...\n"); + } + } + else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) { + /* We try to always preview visible entries first, so 'restart' preview background task. */ + filelist_cache_previews_update(filelist); + filelist_cache_previews_clear(cache); + } + + // printf("Re-queueing previews...\n"); + + /* Note we try to preview first images around given index - i.e. assumed visible ones. */ + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) { + if ((index - i) >= start_index) { + const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size; + filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i); + } + if ((index + i) < end_index) { + const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size; + filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i); + } + } + } + + cache->block_center_index = index; + + // printf("%s Finished!\n", __func__); + + return true; } void filelist_cache_previews_set(FileList *filelist, const bool use_previews) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) { - return; - } - /* Do not start preview work while listing, gives nasty flickering! */ - else if (use_previews && (filelist->flags & FL_IS_READY)) { - cache->flags |= FLC_PREVIEWS_ACTIVE; + if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) { + return; + } + /* Do not start preview work while listing, gives nasty flickering! */ + else if (use_previews && (filelist->flags & FL_IS_READY)) { + cache->flags |= FLC_PREVIEWS_ACTIVE; - BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL)); + BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL)); -// printf("%s: Init Previews...\n", __func__); + // printf("%s: Init Previews...\n", __func__); - /* No need to populate preview queue here, filelist_file_cache_block() handles this. */ - } - else { -// printf("%s: Clear Previews...\n", __func__); + /* No need to populate preview queue here, filelist_file_cache_block() handles this. */ + } + else { + // printf("%s: Clear Previews...\n", __func__); - filelist_cache_previews_free(cache); - } + filelist_cache_previews_free(cache); + } } bool filelist_cache_previews_update(FileList *filelist) { - FileListEntryCache *cache = &filelist->filelist_cache; - TaskPool *pool = cache->previews_pool; - bool changed = false; - - if (!pool) { - return changed; - } - -// printf("%s: Update Previews...\n", __func__); - - while (!BLI_thread_queue_is_empty(cache->previews_done)) { - FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done); - FileDirEntry *entry; - - /* Paranoid (should never happen currently - * since we consume this queue from a single thread), but... */ - if (!preview) { - continue; - } - /* entry might have been removed from cache in the mean time, - * we do not want to cache it again here. */ - entry = filelist_file_ex(filelist, preview->index, false); - -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - - if (preview->img) { - /* Due to asynchronous process, a preview for a given image may be generated several times, i.e. - * entry->image may already be set at this point. */ - if (entry && !entry->image) { - entry->image = preview->img; - changed = true; - } - else { - IMB_freeImBuf(preview->img); - } - } - else if (entry) { - /* We want to avoid re-processing this entry continuously! - * Note that, since entries only live in cache, - * preview will be retried quite often anyway. */ - entry->flags |= FILE_ENTRY_INVALID_PREVIEW; - } - - MEM_freeN(preview); - } - - return changed; + FileListEntryCache *cache = &filelist->filelist_cache; + TaskPool *pool = cache->previews_pool; + bool changed = false; + + if (!pool) { + return changed; + } + + // printf("%s: Update Previews...\n", __func__); + + while (!BLI_thread_queue_is_empty(cache->previews_done)) { + FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done); + FileDirEntry *entry; + + /* Paranoid (should never happen currently + * since we consume this queue from a single thread), but... */ + if (!preview) { + continue; + } + /* entry might have been removed from cache in the mean time, + * we do not want to cache it again here. */ + entry = filelist_file_ex(filelist, preview->index, false); + + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + + if (preview->img) { + /* Due to asynchronous process, a preview for a given image may be generated several times, i.e. + * entry->image may already be set at this point. */ + if (entry && !entry->image) { + entry->image = preview->img; + changed = true; + } + else { + IMB_freeImBuf(preview->img); + } + } + else if (entry) { + /* We want to avoid re-processing this entry continuously! + * Note that, since entries only live in cache, + * preview will be retried quite often anyway. */ + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + } + + MEM_freeN(preview); + } + + return changed; } bool filelist_cache_previews_running(FileList *filelist) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - return (cache->previews_pool != NULL); + return (cache->previews_pool != NULL); } /* would recognize .blend as well */ static bool file_is_blend_backup(const char *str) { - const size_t a = strlen(str); - size_t b = 7; - bool retval = 0; + const size_t a = strlen(str); + size_t b = 7; + bool retval = 0; - if (a == 0 || b >= a) { - /* pass */ - } - else { - const char *loc; + if (a == 0 || b >= a) { + /* pass */ + } + else { + const char *loc; - if (a > b + 1) - b++; + if (a > b + 1) + b++; - /* allow .blend1 .blend2 .blend32 */ - loc = BLI_strcasestr(str + a - b, ".blend"); + /* allow .blend1 .blend2 .blend32 */ + loc = BLI_strcasestr(str + a - b, ".blend"); - if (loc) - retval = 1; - } + if (loc) + retval = 1; + } - return (retval); + return (retval); } /* TODO: Maybe we should move this to BLI? * On the other hand, it's using defines from spacefile area, so not sure... */ int ED_path_extension_type(const char *path) { - if (BLO_has_bfile_extension(path)) { - return FILE_TYPE_BLENDER; - } - else if (file_is_blend_backup(path)) { - return FILE_TYPE_BLENDER_BACKUP; - } - else if (BLI_path_extension_check(path, ".app")) { - return FILE_TYPE_APPLICATIONBUNDLE; - } - else if (BLI_path_extension_check(path, ".py")) { - return FILE_TYPE_PYSCRIPT; - } - else if (BLI_path_extension_check_n(path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) { - return FILE_TYPE_TEXT; - } - else if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { - return FILE_TYPE_FTFONT; - } - else if (BLI_path_extension_check(path, ".btx")) { - return FILE_TYPE_BTX; - } - else if (BLI_path_extension_check(path, ".dae")) { - return FILE_TYPE_COLLADA; - } - else if (BLI_path_extension_check(path, ".abc")) { - return FILE_TYPE_ALEMBIC; - } - else if (BLI_path_extension_check_array(path, imb_ext_image)) { - return FILE_TYPE_IMAGE; - } - else if (BLI_path_extension_check(path, ".ogg")) { - if (IMB_isanim(path)) { - return FILE_TYPE_MOVIE; - } - else { - return FILE_TYPE_SOUND; - } - } - else if (BLI_path_extension_check_array(path, imb_ext_movie)) { - return FILE_TYPE_MOVIE; - } - else if (BLI_path_extension_check_array(path, imb_ext_audio)) { - return FILE_TYPE_SOUND; - } - return 0; + if (BLO_has_bfile_extension(path)) { + return FILE_TYPE_BLENDER; + } + else if (file_is_blend_backup(path)) { + return FILE_TYPE_BLENDER_BACKUP; + } + else if (BLI_path_extension_check(path, ".app")) { + return FILE_TYPE_APPLICATIONBUNDLE; + } + else if (BLI_path_extension_check(path, ".py")) { + return FILE_TYPE_PYSCRIPT; + } + else if (BLI_path_extension_check_n( + path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) { + return FILE_TYPE_TEXT; + } + else if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { + return FILE_TYPE_FTFONT; + } + else if (BLI_path_extension_check(path, ".btx")) { + return FILE_TYPE_BTX; + } + else if (BLI_path_extension_check(path, ".dae")) { + return FILE_TYPE_COLLADA; + } + else if (BLI_path_extension_check(path, ".abc")) { + return FILE_TYPE_ALEMBIC; + } + else if (BLI_path_extension_check_array(path, imb_ext_image)) { + return FILE_TYPE_IMAGE; + } + else if (BLI_path_extension_check(path, ".ogg")) { + if (IMB_isanim(path)) { + return FILE_TYPE_MOVIE; + } + else { + return FILE_TYPE_SOUND; + } + } + else if (BLI_path_extension_check_array(path, imb_ext_movie)) { + return FILE_TYPE_MOVIE; + } + else if (BLI_path_extension_check_array(path, imb_ext_audio)) { + return FILE_TYPE_SOUND; + } + return 0; } static int file_extension_type(const char *dir, const char *relpath) { - char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), dir, relpath); - return ED_path_extension_type(path); + char path[FILE_MAX]; + BLI_join_dirfile(path, sizeof(path), dir, relpath); + return ED_path_extension_type(path); } int ED_file_extension_icon(const char *path) { - const int type = ED_path_extension_type(path); - - switch (type) { - case FILE_TYPE_BLENDER: - return ICON_FILE_BLEND; - case FILE_TYPE_BLENDER_BACKUP: - return ICON_FILE_BACKUP; - case FILE_TYPE_IMAGE: - return ICON_FILE_IMAGE; - case FILE_TYPE_MOVIE: - return ICON_FILE_MOVIE; - case FILE_TYPE_PYSCRIPT: - return ICON_FILE_SCRIPT; - case FILE_TYPE_SOUND: - return ICON_FILE_SOUND; - case FILE_TYPE_FTFONT: - return ICON_FILE_FONT; - case FILE_TYPE_BTX: - return ICON_FILE_BLANK; - case FILE_TYPE_COLLADA: - return ICON_FILE_BLANK; - case FILE_TYPE_ALEMBIC: - return ICON_FILE_BLANK; - case FILE_TYPE_TEXT: - return ICON_FILE_TEXT; - default: - return ICON_FILE_BLANK; - } + const int type = ED_path_extension_type(path); + + switch (type) { + case FILE_TYPE_BLENDER: + return ICON_FILE_BLEND; + case FILE_TYPE_BLENDER_BACKUP: + return ICON_FILE_BACKUP; + case FILE_TYPE_IMAGE: + return ICON_FILE_IMAGE; + case FILE_TYPE_MOVIE: + return ICON_FILE_MOVIE; + case FILE_TYPE_PYSCRIPT: + return ICON_FILE_SCRIPT; + case FILE_TYPE_SOUND: + return ICON_FILE_SOUND; + case FILE_TYPE_FTFONT: + return ICON_FILE_FONT; + case FILE_TYPE_BTX: + return ICON_FILE_BLANK; + case FILE_TYPE_COLLADA: + return ICON_FILE_BLANK; + case FILE_TYPE_ALEMBIC: + return ICON_FILE_BLANK; + case FILE_TYPE_TEXT: + return ICON_FILE_TEXT; + default: + return ICON_FILE_BLANK; + } } int filelist_empty(struct FileList *filelist) { - return (filelist->filelist.nbr_entries == 0); -} - -unsigned int filelist_entry_select_set( - const FileList *filelist, const FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check) + return (filelist->filelist.nbr_entries == 0); +} + +unsigned int filelist_entry_select_set(const FileList *filelist, + const FileDirEntry *entry, + FileSelType select, + unsigned int flag, + FileCheckType check) { - /* Default NULL pointer if not found is fine here! */ - void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid); - unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0; - const unsigned int org_entry_flag = entry_flag; + /* Default NULL pointer if not found is fine here! */ + void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid); + unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0; + const unsigned int org_entry_flag = entry_flag; - BLI_assert(entry); - BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); + BLI_assert(entry); + BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); - if (((check == CHECK_ALL)) || - ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || - ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) - { - switch (select) { - case FILE_SEL_REMOVE: - entry_flag &= ~flag; - break; - case FILE_SEL_ADD: - entry_flag |= flag; - break; - case FILE_SEL_TOGGLE: - entry_flag ^= flag; - break; - } - } + if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || + ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) { + switch (select) { + case FILE_SEL_REMOVE: + entry_flag &= ~flag; + break; + case FILE_SEL_ADD: + entry_flag |= flag; + break; + case FILE_SEL_TOGGLE: + entry_flag ^= flag; + break; + } + } - if (entry_flag != org_entry_flag) { - if (es_p) { - if (entry_flag) { - *es_p = POINTER_FROM_UINT(entry_flag); - } - else { - BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL); - } - } - else if (entry_flag) { - void *key = MEM_mallocN(sizeof(entry->uuid), __func__); - memcpy(key, entry->uuid, sizeof(entry->uuid)); - BLI_ghash_insert(filelist->selection_state, key, POINTER_FROM_UINT(entry_flag)); - } - } + if (entry_flag != org_entry_flag) { + if (es_p) { + if (entry_flag) { + *es_p = POINTER_FROM_UINT(entry_flag); + } + else { + BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL); + } + } + else if (entry_flag) { + void *key = MEM_mallocN(sizeof(entry->uuid), __func__); + memcpy(key, entry->uuid, sizeof(entry->uuid)); + BLI_ghash_insert(filelist->selection_state, key, POINTER_FROM_UINT(entry_flag)); + } + } - return entry_flag; + return entry_flag; } -void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check) +void filelist_entry_select_index_set(FileList *filelist, + const int index, + FileSelType select, + unsigned int flag, + FileCheckType check) { - FileDirEntry *entry = filelist_file(filelist, index); + FileDirEntry *entry = filelist_file(filelist, index); - if (entry) { - filelist_entry_select_set(filelist, entry, select, flag, check); - } + if (entry) { + filelist_entry_select_set(filelist, entry, select, flag, check); + } } -void filelist_entries_select_index_range_set( - FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check) +void filelist_entries_select_index_range_set(FileList *filelist, + FileSelection *sel, + FileSelType select, + unsigned int flag, + FileCheckType check) { - /* select all valid files between first and last indicated */ - if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) && - (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) - { - int current_file; - for (current_file = sel->first; current_file <= sel->last; current_file++) { - filelist_entry_select_index_set(filelist, current_file, select, flag, check); - } - } + /* select all valid files between first and last indicated */ + if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) && + (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) { + int current_file; + for (current_file = sel->first; current_file <= sel->last; current_file++) { + filelist_entry_select_index_set(filelist, current_file, select, flag, check); + } + } } -unsigned int filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check) +unsigned int filelist_entry_select_get(FileList *filelist, + FileDirEntry *entry, + FileCheckType check) { - BLI_assert(entry); - BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); + BLI_assert(entry); + BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); - if (((check == CHECK_ALL)) || - ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || - ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) - { - /* Default NULL pointer if not found is fine here! */ - return POINTER_AS_UINT(BLI_ghash_lookup(filelist->selection_state, entry->uuid)); - } + if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || + ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) { + /* Default NULL pointer if not found is fine here! */ + return POINTER_AS_UINT(BLI_ghash_lookup(filelist->selection_state, entry->uuid)); + } - return 0; + return 0; } -unsigned int filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check) +unsigned int filelist_entry_select_index_get(FileList *filelist, + const int index, + FileCheckType check) { - FileDirEntry *entry = filelist_file(filelist, index); - - if (entry) { - return filelist_entry_select_get(filelist, entry, check); - } - - return 0; + FileDirEntry *entry = filelist_file(filelist, index); + + if (entry) { + return filelist_entry_select_get(filelist, entry, check); + } + + return 0; } /* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { - return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); + return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); } static int groupname_to_code(const char *group) { - char buf[BLO_GROUP_MAX]; - char *lslash; + char buf[BLO_GROUP_MAX]; + char *lslash; - BLI_assert(group); + BLI_assert(group); - BLI_strncpy(buf, group, sizeof(buf)); - lslash = (char *)BLI_last_slash(buf); - if (lslash) - lslash[0] = '\0'; + BLI_strncpy(buf, group, sizeof(buf)); + lslash = (char *)BLI_last_slash(buf); + if (lslash) + lslash[0] = '\0'; - return buf[0] ? BKE_idcode_from_name(buf) : 0; + return buf[0] ? BKE_idcode_from_name(buf) : 0; } static unsigned int groupname_to_filter_id(const char *group) { - int id_code = groupname_to_code(group); + int id_code = groupname_to_code(group); - return BKE_idcode_to_idfilter(id_code); + return BKE_idcode_to_idfilter(id_code); } /** @@ -2201,127 +2279,130 @@ static unsigned int groupname_to_filter_id(const char *group) * and main one (used by UI among other things). */ typedef struct TodoDir { - int level; - char *dir; + int level; + char *dir; } TodoDir; -static int filelist_readjob_list_dir( - const char *root, ListBase *entries, const char *filter_glob, - const bool do_lib, const char *main_name, const bool skip_currpar) -{ - struct direntry *files; - int nbr_files, nbr_entries = 0; - - nbr_files = BLI_filelist_dir_contents(root, &files); - if (files) { - int i = nbr_files; - while (i--) { - FileListInternEntry *entry; - - if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) { - continue; - } - - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = MEM_dupallocN(files[i].relname); - entry->st = files[i].s; - - /* Set file type. */ - if (S_ISDIR(files[i].s.st_mode)) { - entry->typeflag = FILE_TYPE_DIR; - } - else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { - /* If we are considering .blend files as libs, promote them to directory status. */ - char name[FILE_MAX]; - - entry->typeflag = FILE_TYPE_BLENDER; - - BLI_join_dirfile(name, sizeof(name), root, entry->relpath); - - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, name) != 0) { - entry->typeflag |= FILE_TYPE_DIR; - } - } - /* Otherwise, do not check extensions for directories! */ - else if (!(entry->typeflag & FILE_TYPE_DIR)) { - entry->typeflag = file_extension_type(root, entry->relpath); - if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { - entry->typeflag |= FILE_TYPE_OPERATOR; - } - } - - BLI_addtail(entries, entry); - nbr_entries++; - } - BLI_filelist_free(files, nbr_files); - } - return nbr_entries; +static int filelist_readjob_list_dir(const char *root, + ListBase *entries, + const char *filter_glob, + const bool do_lib, + const char *main_name, + const bool skip_currpar) +{ + struct direntry *files; + int nbr_files, nbr_entries = 0; + + nbr_files = BLI_filelist_dir_contents(root, &files); + if (files) { + int i = nbr_files; + while (i--) { + FileListInternEntry *entry; + + if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) { + continue; + } + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = MEM_dupallocN(files[i].relname); + entry->st = files[i].s; + + /* Set file type. */ + if (S_ISDIR(files[i].s.st_mode)) { + entry->typeflag = FILE_TYPE_DIR; + } + else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { + /* If we are considering .blend files as libs, promote them to directory status. */ + char name[FILE_MAX]; + + entry->typeflag = FILE_TYPE_BLENDER; + + BLI_join_dirfile(name, sizeof(name), root, entry->relpath); + + /* prevent current file being used as acceptable dir */ + if (BLI_path_cmp(main_name, name) != 0) { + entry->typeflag |= FILE_TYPE_DIR; + } + } + /* Otherwise, do not check extensions for directories! */ + else if (!(entry->typeflag & FILE_TYPE_DIR)) { + entry->typeflag = file_extension_type(root, entry->relpath); + if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { + entry->typeflag |= FILE_TYPE_OPERATOR; + } + } + + BLI_addtail(entries, entry); + nbr_entries++; + } + BLI_filelist_free(files, nbr_files); + } + return nbr_entries; } static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar) { - FileListInternEntry *entry; - LinkNode *ln, *names; - int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX_LIBEXTRA], *group; - bool ok; - - struct BlendHandle *libfiledata = NULL; - - /* name test */ - ok = BLO_library_path_explode(root, dir, &group, NULL); - if (!ok) { - return nbr_entries; - } - - /* there we go */ - libfiledata = BLO_blendhandle_from_file(dir, NULL); - if (libfiledata == NULL) { - return nbr_entries; - } - - /* memory for strings is passed into filelist[i].entry->relpath - * and freed in filelist_entry_free. */ - if (group) { - idcode = groupname_to_code(group); - names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); - } - else { - names = BLO_blendhandle_get_linkable_groups(libfiledata); - nnames = BLI_linklist_count(names); - } - - BLO_blendhandle_close(libfiledata); - - if (!skip_currpar) { - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = BLI_strdup(FILENAME_PARENT); - entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); - BLI_addtail(entries, entry); - nbr_entries++; - } - - for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { - const char *blockname = ln->link; - - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = BLI_strdup(blockname); - entry->typeflag |= FILE_TYPE_BLENDERLIB; - if (!(group && idcode)) { - entry->typeflag |= FILE_TYPE_DIR; - entry->blentype = groupname_to_code(blockname); - } - else { - entry->blentype = idcode; - } - BLI_addtail(entries, entry); - nbr_entries++; - } - - BLI_linklist_free(names, free); - - return nbr_entries; + FileListInternEntry *entry; + LinkNode *ln, *names; + int i, nnames, idcode = 0, nbr_entries = 0; + char dir[FILE_MAX_LIBEXTRA], *group; + bool ok; + + struct BlendHandle *libfiledata = NULL; + + /* name test */ + ok = BLO_library_path_explode(root, dir, &group, NULL); + if (!ok) { + return nbr_entries; + } + + /* there we go */ + libfiledata = BLO_blendhandle_from_file(dir, NULL); + if (libfiledata == NULL) { + return nbr_entries; + } + + /* memory for strings is passed into filelist[i].entry->relpath + * and freed in filelist_entry_free. */ + if (group) { + idcode = groupname_to_code(group); + names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); + } + else { + names = BLO_blendhandle_get_linkable_groups(libfiledata); + nnames = BLI_linklist_count(names); + } + + BLO_blendhandle_close(libfiledata); + + if (!skip_currpar) { + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(FILENAME_PARENT); + entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); + BLI_addtail(entries, entry); + nbr_entries++; + } + + for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { + const char *blockname = ln->link; + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(blockname); + entry->typeflag |= FILE_TYPE_BLENDERLIB; + if (!(group && idcode)) { + entry->typeflag |= FILE_TYPE_DIR; + entry->blentype = groupname_to_code(blockname); + } + else { + entry->blentype = idcode; + } + BLI_addtail(entries, entry); + nbr_entries++; + } + + BLI_linklist_free(names, free); + + return nbr_entries; } #if 0 @@ -2330,428 +2411,453 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const /* Code ***NOT*** updated for job stuff! */ static void filelist_readjob_main_rec(Main *bmain, FileList *filelist) { - ID *id; - FileDirEntry *files, *firstlib = NULL; - ListBase *lb; - int a, fake, idcode, ok, totlib, totbl; - - // filelist->type = FILE_MAIN; // XXX TODO: add modes to filebrowser - - BLI_assert(filelist->filelist.entries == NULL); - - if (filelist->filelist.root[0] == '/') filelist->filelist.root[0] = '\0'; - - if (filelist->filelist.root[0]) { - idcode = groupname_to_code(filelist->filelist.root); - if (idcode == 0) filelist->filelist.root[0] = '\0'; - } - - if (filelist->dir[0] == 0) { - /* make directories */ -#ifdef WITH_FREESTYLE - filelist->filelist.nbr_entries = 24; -#else - filelist->filelist.nbr_entries = 23; -#endif - filelist_resize(filelist, filelist->filelist.nbr_entries); - - for (a = 0; a < filelist->filelist.nbr_entries; a++) { - filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR; - } - - filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT); - filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene"); - filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object"); - filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh"); - filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve"); - filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball"); - filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material"); - filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture"); - filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image"); - filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika"); - filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave"); - filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice"); - filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light"); - filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera"); - filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo"); - filelist->filelist.entries[15].entry->relpath = BLI_strdup("World"); - filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen"); - filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont"); - filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text"); - filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature"); - filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action"); - filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree"); - filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker"); -#ifdef WITH_FREESTYLE - filelist->filelist.entries[23].entry->relpath = BLI_strdup("FreestyleLineStyle"); -#endif - } - else { - /* make files */ - idcode = groupname_to_code(filelist->filelist.root); - - lb = which_libbase(bmain, idcode); - if (lb == NULL) return; - - filelist->filelist.nbr_entries = 0; - for (id = lb->first; id; id = id->next) { - if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { - filelist->filelist.nbr_entries++; - } - } - - /* XXX TODO: if databrowse F4 or append/link - * filelist->flags & FLF_HIDE_PARENT has to be set */ - if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) - filelist->filelist.nbr_entries++; - - if (filelist->filelist.nbr_entries > 0) { - filelist_resize(filelist, filelist->filelist.nbr_entries); - } - - files = filelist->filelist.entries; - - if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) { - files->entry->relpath = BLI_strdup(FILENAME_PARENT); - files->typeflag |= FILE_TYPE_DIR; - - files++; - } - - totlib = totbl = 0; - for (id = lb->first; id; id = id->next) { - ok = 1; - if (ok) { - if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { - if (id->lib == NULL) { - files->entry->relpath = BLI_strdup(id->name + 2); - } - else { - char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3]; - BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2); - files->entry->relpath = BLI_strdup(relname); - } -// files->type |= S_IFREG; -#if 0 /* XXX TODO show the selection status of the objects */ - if (!filelist->has_func) { /* F4 DATA BROWSE */ - if (idcode == ID_OB) { - if ( ((Object *)id)->flag & SELECT) files->entry->selflag |= FILE_SEL_SELECTED; - } - else if (idcode == ID_SCE) { - if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->entry->selflag |= FILE_SEL_SELECTED; - } - } -#endif -// files->entry->nr = totbl + 1; - files->entry->poin = id; - fake = id->flag & LIB_FAKEUSER; - if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { - files->typeflag |= FILE_TYPE_IMAGE; - } -// if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us); -// else if (id->lib) BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us); -// else if (fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us); -// else BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us); - - if (id->lib) { - if (totlib == 0) firstlib = files; - totlib++; - } - - files++; - } - totbl++; - } - } - - /* only qsort of library blocks */ - if (totlib > 1) { - qsort(firstlib, totlib, sizeof(*files), compare_name); - } - } + ID *id; + FileDirEntry *files, *firstlib = NULL; + ListBase *lb; + int a, fake, idcode, ok, totlib, totbl; + + // filelist->type = FILE_MAIN; // XXX TODO: add modes to filebrowser + + BLI_assert(filelist->filelist.entries == NULL); + + if (filelist->filelist.root[0] == '/') filelist->filelist.root[0] = '\0'; + + if (filelist->filelist.root[0]) { + idcode = groupname_to_code(filelist->filelist.root); + if (idcode == 0) filelist->filelist.root[0] = '\0'; + } + + if (filelist->dir[0] == 0) { + /* make directories */ +# ifdef WITH_FREESTYLE + filelist->filelist.nbr_entries = 24; +# else + filelist->filelist.nbr_entries = 23; +# endif + filelist_resize(filelist, filelist->filelist.nbr_entries); + + for (a = 0; a < filelist->filelist.nbr_entries; a++) { + filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR; + } + + filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT); + filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene"); + filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object"); + filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh"); + filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve"); + filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball"); + filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material"); + filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture"); + filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image"); + filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika"); + filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave"); + filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice"); + filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light"); + filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera"); + filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo"); + filelist->filelist.entries[15].entry->relpath = BLI_strdup("World"); + filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen"); + filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont"); + filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text"); + filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature"); + filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action"); + filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree"); + filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker"); +# ifdef WITH_FREESTYLE + filelist->filelist.entries[23].entry->relpath = BLI_strdup("FreestyleLineStyle"); +# endif + } + else { + /* make files */ + idcode = groupname_to_code(filelist->filelist.root); + + lb = which_libbase(bmain, idcode); + if (lb == NULL) return; + + filelist->filelist.nbr_entries = 0; + for (id = lb->first; id; id = id->next) { + if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { + filelist->filelist.nbr_entries++; + } + } + + /* XXX TODO: if databrowse F4 or append/link + * filelist->flags & FLF_HIDE_PARENT has to be set */ + if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) + filelist->filelist.nbr_entries++; + + if (filelist->filelist.nbr_entries > 0) { + filelist_resize(filelist, filelist->filelist.nbr_entries); + } + + files = filelist->filelist.entries; + + if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) { + files->entry->relpath = BLI_strdup(FILENAME_PARENT); + files->typeflag |= FILE_TYPE_DIR; + + files++; + } + + totlib = totbl = 0; + for (id = lb->first; id; id = id->next) { + ok = 1; + if (ok) { + if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { + if (id->lib == NULL) { + files->entry->relpath = BLI_strdup(id->name + 2); + } + else { + char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3]; + BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2); + files->entry->relpath = BLI_strdup(relname); + } +// files->type |= S_IFREG; +# if 0 /* XXX TODO show the selection status of the objects */ + if (!filelist->has_func) { /* F4 DATA BROWSE */ + if (idcode == ID_OB) { + if ( ((Object *)id)->flag & SELECT) files->entry->selflag |= FILE_SEL_SELECTED; + } + else if (idcode == ID_SCE) { + if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->entry->selflag |= FILE_SEL_SELECTED; + } + } +# endif +// files->entry->nr = totbl + 1; + files->entry->poin = id; + fake = id->flag & LIB_FAKEUSER; + if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { + files->typeflag |= FILE_TYPE_IMAGE; + } +// if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us); +// else if (id->lib) BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us); +// else if (fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us); +// else BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us); + + if (id->lib) { + if (totlib == 0) firstlib = files; + totlib++; + } + + files++; + } + totbl++; + } + } + + /* only qsort of library blocks */ + if (totlib > 1) { + qsort(firstlib, totlib, sizeof(*files), compare_name); + } + } } #endif -static void filelist_readjob_do( - const bool do_lib, - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - ListBase entries = {0}; - BLI_Stack *todo_dirs; - TodoDir *td_dir; - char dir[FILE_MAX_LIBEXTRA]; - char filter_glob[FILE_MAXFILE]; - const char *root = filelist->filelist.root; - const int max_recursion = filelist->max_recursion; - int nbr_done_dirs = 0, nbr_todo_dirs = 1; - -// BLI_assert(filelist->filtered == NULL); - BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && (filelist->filelist.nbr_entries == 0)); - - todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); - td_dir = BLI_stack_push_r(todo_dirs); - td_dir->level = 1; - - BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); - BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); - - BLI_cleanup_dir(main_name, dir); - td_dir->dir = BLI_strdup(dir); - - while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { - FileListInternEntry *entry; - int nbr_entries = 0; - bool is_lib = do_lib; - - char *subdir; - char rel_subdir[FILE_MAX_LIBEXTRA]; - int recursion_level; - bool skip_currpar; - - td_dir = BLI_stack_peek(todo_dirs); - subdir = td_dir->dir; - recursion_level = td_dir->level; - skip_currpar = (recursion_level > 1); - - BLI_stack_discard(todo_dirs); - - /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over - * entry->relpath itself (nor any path containing it), since it may actually be a datablock - * name inside .blend file, which can have slashes and backslashes! See T46827. - * Note that in the end, this means we 'cache' valid relative subdir once here, - * this is actually better. */ - BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); - BLI_cleanup_dir(root, rel_subdir); - BLI_path_rel(rel_subdir, root); - - if (do_lib) { - nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar); - } - if (!nbr_entries) { - is_lib = false; - nbr_entries = filelist_readjob_list_dir(subdir, &entries, filter_glob, do_lib, main_name, skip_currpar); - } - - for (entry = entries.first; entry; entry = entry->next) { - BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); - - /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here, - * things would crash way before we overflow that counter! - * Using an atomic operation to avoid having to lock thread... - * Note that we do not really need this here currently, - * since there is a single listing thread, but better - * remain consistent about threading! */ - *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); - - /* Only thing we change in direntry here, so we need to free it first. */ - MEM_freeN(entry->relpath); - entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' - * added by BLI_path_rel to rel_subdir */ - entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir)); - - /* Here we decide whether current filedirentry is to be listed too, or not. */ - if (max_recursion && (is_lib || (recursion_level <= max_recursion))) { - if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) { - /* Skip... */ - } - else if (!is_lib && (recursion_level >= max_recursion) && - ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) - { - /* Do not recurse in real directories in this case, only in .blend libs. */ - } - else { - /* We have a directory we want to list, add it to todo list! */ - BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); - BLI_cleanup_dir(main_name, dir); - td_dir = BLI_stack_push_r(todo_dirs); - td_dir->level = recursion_level + 1; - td_dir->dir = BLI_strdup(dir); - nbr_todo_dirs++; - } - } - } - - if (nbr_entries) { - BLI_mutex_lock(lock); - - *do_update = true; - - BLI_movelisttolist(&filelist->filelist.entries, &entries); - filelist->filelist.nbr_entries += nbr_entries; - - BLI_mutex_unlock(lock); - } - - nbr_done_dirs++; - *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; - MEM_freeN(subdir); - } - - /* If we were interrupted by stop, stack may not be empty and we need to free - * pending dir paths. */ - while (!BLI_stack_is_empty(todo_dirs)) { - td_dir = BLI_stack_peek(todo_dirs); - MEM_freeN(td_dir->dir); - BLI_stack_discard(todo_dirs); - } - BLI_stack_free(todo_dirs); +static void filelist_readjob_do(const bool do_lib, + FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + ListBase entries = {0}; + BLI_Stack *todo_dirs; + TodoDir *td_dir; + char dir[FILE_MAX_LIBEXTRA]; + char filter_glob[FILE_MAXFILE]; + const char *root = filelist->filelist.root; + const int max_recursion = filelist->max_recursion; + int nbr_done_dirs = 0, nbr_todo_dirs = 1; + + // BLI_assert(filelist->filtered == NULL); + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == 0)); + + todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); + td_dir = BLI_stack_push_r(todo_dirs); + td_dir->level = 1; + + BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); + BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); + + BLI_cleanup_dir(main_name, dir); + td_dir->dir = BLI_strdup(dir); + + while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { + FileListInternEntry *entry; + int nbr_entries = 0; + bool is_lib = do_lib; + + char *subdir; + char rel_subdir[FILE_MAX_LIBEXTRA]; + int recursion_level; + bool skip_currpar; + + td_dir = BLI_stack_peek(todo_dirs); + subdir = td_dir->dir; + recursion_level = td_dir->level; + skip_currpar = (recursion_level > 1); + + BLI_stack_discard(todo_dirs); + + /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over + * entry->relpath itself (nor any path containing it), since it may actually be a datablock + * name inside .blend file, which can have slashes and backslashes! See T46827. + * Note that in the end, this means we 'cache' valid relative subdir once here, + * this is actually better. */ + BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); + BLI_cleanup_dir(root, rel_subdir); + BLI_path_rel(rel_subdir, root); + + if (do_lib) { + nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar); + } + if (!nbr_entries) { + is_lib = false; + nbr_entries = filelist_readjob_list_dir( + subdir, &entries, filter_glob, do_lib, main_name, skip_currpar); + } + + for (entry = entries.first; entry; entry = entry->next) { + BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); + + /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here, + * things would crash way before we overflow that counter! + * Using an atomic operation to avoid having to lock thread... + * Note that we do not really need this here currently, + * since there is a single listing thread, but better + * remain consistent about threading! */ + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32( + (uint32_t *)filelist->filelist_intern.curr_uuid, 1); + + /* Only thing we change in direntry here, so we need to free it first. */ + MEM_freeN(entry->relpath); + entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' + * added by BLI_path_rel to rel_subdir */ + entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir)); + + /* Here we decide whether current filedirentry is to be listed too, or not. */ + if (max_recursion && (is_lib || (recursion_level <= max_recursion))) { + if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) { + /* Skip... */ + } + else if (!is_lib && (recursion_level >= max_recursion) && + ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) { + /* Do not recurse in real directories in this case, only in .blend libs. */ + } + else { + /* We have a directory we want to list, add it to todo list! */ + BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); + BLI_cleanup_dir(main_name, dir); + td_dir = BLI_stack_push_r(todo_dirs); + td_dir->level = recursion_level + 1; + td_dir->dir = BLI_strdup(dir); + nbr_todo_dirs++; + } + } + } + + if (nbr_entries) { + BLI_mutex_lock(lock); + + *do_update = true; + + BLI_movelisttolist(&filelist->filelist.entries, &entries); + filelist->filelist.nbr_entries += nbr_entries; + + BLI_mutex_unlock(lock); + } + + nbr_done_dirs++; + *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; + MEM_freeN(subdir); + } + + /* If we were interrupted by stop, stack may not be empty and we need to free + * pending dir paths. */ + while (!BLI_stack_is_empty(todo_dirs)) { + td_dir = BLI_stack_peek(todo_dirs); + MEM_freeN(td_dir->dir); + BLI_stack_discard(todo_dirs); + } + BLI_stack_free(todo_dirs); +} + +static void filelist_readjob_dir(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); +} + +static void filelist_readjob_lib(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); +} + +static void filelist_readjob_main(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + /* TODO! */ + filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_dir( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); -} - -static void filelist_readjob_lib( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); -} - -static void filelist_readjob_main( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - /* TODO! */ - filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); -} - - typedef struct FileListReadJob { - ThreadMutex lock; - char main_name[FILE_MAX]; - struct FileList *filelist; - /** XXX We may use a simpler struct here... just a linked list and root path? */ - struct FileList *tmp_filelist; + ThreadMutex lock; + char main_name[FILE_MAX]; + struct FileList *filelist; + /** XXX We may use a simpler struct here... just a linked list and root path? */ + struct FileList *tmp_filelist; } FileListReadJob; static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; -// printf("START filelist reading (%d files, main thread: %d)\n", -// flrj->filelist->filelist.nbr_entries, BLI_thread_is_main()); + // printf("START filelist reading (%d files, main thread: %d)\n", + // flrj->filelist->filelist.nbr_entries, BLI_thread_is_main()); - BLI_mutex_lock(&flrj->lock); + BLI_mutex_lock(&flrj->lock); - BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); + BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); - flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); + flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); - BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; + BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); + flrj->tmp_filelist->filelist.nbr_entries = 0; - flrj->tmp_filelist->filelist_intern.filtered = NULL; - BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); - memset(flrj->tmp_filelist->filelist_intern.curr_uuid, 0, sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid)); + flrj->tmp_filelist->filelist_intern.filtered = NULL; + BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); + memset(flrj->tmp_filelist->filelist_intern.curr_uuid, + 0, + sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid)); - flrj->tmp_filelist->libfiledata = NULL; - memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); - flrj->tmp_filelist->selection_state = NULL; + flrj->tmp_filelist->libfiledata = NULL; + memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); + flrj->tmp_filelist->selection_state = NULL; - BLI_mutex_unlock(&flrj->lock); + BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf(flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); + flrj->tmp_filelist->read_jobf( + flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); } static void filelist_readjob_update(void *flrjv) { - FileListReadJob *flrj = flrjv; - FileListIntern *fl_intern = &flrj->filelist->filelist_intern; - ListBase new_entries = {NULL}; - int nbr_entries, new_nbr_entries = 0; + FileListReadJob *flrj = flrjv; + FileListIntern *fl_intern = &flrj->filelist->filelist_intern; + ListBase new_entries = {NULL}; + int nbr_entries, new_nbr_entries = 0; - BLI_movelisttolist(&new_entries, &fl_intern->entries); - nbr_entries = flrj->filelist->filelist.nbr_entries; + BLI_movelisttolist(&new_entries, &fl_intern->entries); + nbr_entries = flrj->filelist->filelist.nbr_entries; - BLI_mutex_lock(&flrj->lock); + BLI_mutex_lock(&flrj->lock); - if (flrj->tmp_filelist->filelist.nbr_entries) { - /* We just move everything out of 'thread context' into final list. */ - new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; - BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; - } + if (flrj->tmp_filelist->filelist.nbr_entries) { + /* We just move everything out of 'thread context' into final list. */ + new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; + BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); + flrj->tmp_filelist->filelist.nbr_entries = 0; + } - BLI_mutex_unlock(&flrj->lock); + BLI_mutex_unlock(&flrj->lock); - if (new_nbr_entries) { - /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */ - filelist_clear_ex(flrj->filelist, true, false); + if (new_nbr_entries) { + /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */ + filelist_clear_ex(flrj->filelist, true, false); - flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING); - } + flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING); + } - /* if no new_nbr_entries, this is NOP */ - BLI_movelisttolist(&fl_intern->entries, &new_entries); - flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; + /* if no new_nbr_entries, this is NOP */ + BLI_movelisttolist(&fl_intern->entries, &new_entries); + flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; } static void filelist_readjob_endjob(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; - /* In case there would be some dangling update... */ - filelist_readjob_update(flrjv); + /* In case there would be some dangling update... */ + filelist_readjob_update(flrjv); - flrj->filelist->flags &= ~FL_IS_PENDING; - flrj->filelist->flags |= FL_IS_READY; + flrj->filelist->flags &= ~FL_IS_PENDING; + flrj->filelist->flags |= FL_IS_READY; } static void filelist_readjob_free(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; -// printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries); + // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries); - if (flrj->tmp_filelist) { - /* tmp_filelist shall never ever be filtered! */ - BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0); - BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries)); + if (flrj->tmp_filelist) { + /* tmp_filelist shall never ever be filtered! */ + BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0); + BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries)); - filelist_freelib(flrj->tmp_filelist); - filelist_free(flrj->tmp_filelist); - MEM_freeN(flrj->tmp_filelist); - } + filelist_freelib(flrj->tmp_filelist); + filelist_free(flrj->tmp_filelist); + MEM_freeN(flrj->tmp_filelist); + } - BLI_mutex_end(&flrj->lock); + BLI_mutex_end(&flrj->lock); - MEM_freeN(flrj); + MEM_freeN(flrj); } void filelist_readjob_start(FileList *filelist, const bContext *C) { - Main *bmain = CTX_data_main(C); - wmJob *wm_job; - FileListReadJob *flrj; + Main *bmain = CTX_data_main(C); + wmJob *wm_job; + FileListReadJob *flrj; - /* prepare job data */ - flrj = MEM_callocN(sizeof(*flrj), __func__); - flrj->filelist = filelist; - BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); + /* prepare job data */ + flrj = MEM_callocN(sizeof(*flrj), __func__); + flrj->filelist = filelist; + BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); - filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); - filelist->flags |= FL_IS_PENDING; + filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); + filelist->flags |= FL_IS_PENDING; - BLI_mutex_init(&flrj->lock); + BLI_mutex_init(&flrj->lock); - /* setup job */ - wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Listing Dirs...", - WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR); - WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); - WM_jobs_callbacks(wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + CTX_wm_area(C), + "Listing Dirs...", + WM_JOB_PROGRESS, + WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); + WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_callbacks( + wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); - /* start the job */ - WM_jobs_start(CTX_wm_manager(C), wm_job); + /* start the job */ + WM_jobs_start(CTX_wm_manager(C), wm_job); } void filelist_readjob_stop(wmWindowManager *wm, ScrArea *sa) { - WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); } int filelist_readjob_running(wmWindowManager *wm, ScrArea *sa) { - return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); } |