Final 'FileBrowser First Stage' merge.

It basically rewrites most of filelist.c, with some more limited changes in other areas of filebrowser.

From user perspective, it:
* Removes some info in 'long' drawing mode (owner, permissions) - OS-specific data that do not really matter in Blender!
* Makes short/long display 'fixed' size (among four choices, like thumbnails mode).
* Allows to list several layers of dirtree at once, in a flat way (inside .blend files and/or real directories).
* Consequently, adds datablocks types filtering.
* Uses way less RAM when listing big directories, especially in thumbnail mode (we are talking of several hundred of MiB spared).
* Generates thumbnails way faster.

From code perspective, it:
* Is ready for asset engine needs (on data structure level in filebrowser's listing).
* Simplifies and makes 'generic' file listing much lighter.
* Separates file listing in three different aspects:
** 'generic' filelisting (in BLI), which becomes a shallow wrapper around stat struct.
** 'filebrowser drawing' filelisting, which only contains current visible subset of the whole list (sliding window), with extra drawing data (strings for size, date/time, preview, etc.).
** 'asset-ready' filelisting, which is used for operations common to 'basic' filehandling and future asset-related one.
* Uses uuid's to handle file selection/state in the browser, instead of using flags in filelisting items.
* Uses much lighter BLI_task handling for previews, instead of heavy 'job' system (using the new 'notifier' timer to handle UI refresh, in similar way to jobs).
* Moves .blend datablocks preview handling to IMB_thumbnail (necessary to avoid storing all datablock previews at once, and gives better consistency and performances too).

Revision: https://developer.blender.org/D1316

Thanks to Campbell & Sergey for the reviews. :)
This commit is contained in:
Bastien Montagne 2015-08-19 22:41:39 +02:00
parent 5c659574e6
commit f69e9681fa
Notes: blender-bot 2023-03-01 15:38:46 +01:00
Referenced by issue #104305, Crash when adding nodegroup asset in node editor (when large Asset Libraries are present)
21 changed files with 2776 additions and 1100 deletions

View File

@ -40,22 +40,23 @@ class FILEBROWSER_HT_header(Header):
row.operator("file.parent", text="", icon='FILE_PARENT')
row.operator("file.refresh", text="", icon='FILE_REFRESH')
row = layout.row()
row.separator()
row = layout.row(align=True)
layout.separator()
layout.operator_context = 'EXEC_DEFAULT'
row.operator("file.directory_new", icon='NEWFOLDER')
layout.operator("file.directory_new", icon='NEWFOLDER', text="")
layout.separator()
layout.operator_context = 'INVOKE_DEFAULT'
params = st.params
# can be None when save/reload with a file selector open
if params:
is_lib_browser = params.use_library_browsing
layout.prop(params, "recursion_level", text="")
layout.prop(params, "display_type", expand=True, text="")
if params.display_type == 'FILE_IMGDISPLAY':
layout.prop(params, "thumbnail_size", text="")
layout.prop(params, "thumbnail_size", text="")
layout.prop(params, "sort_method", expand=True, text="")
@ -81,9 +82,17 @@ class FILEBROWSER_HT_header(Header):
row.prop(params, "use_filter_sound", text="")
row.prop(params, "use_filter_text", text="")
if is_lib_browser:
row.prop(params, "use_filter_blendid", text="")
if params.use_filter_blendid:
row.separator()
row.prop(params, "filter_id_category", text="")
row.separator()
row.prop(params, "filter_search", text="", icon='VIEWZOOM')
layout.template_running_jobs()
class FILEBROWSER_UL_dir(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
@ -214,5 +223,24 @@ class FILEBROWSER_PT_recent_folders(Panel):
col.operator("file.reset_recent", icon='X', text="")
class FILEBROWSER_PT_advanced_filter(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOLS'
bl_category = "Filter"
bl_label = "Advanced Filter"
def draw(self, context):
layout = self.layout
space = context.space_data
params = space.params
if params and params.use_library_browsing:
layout.prop(params, "use_filter_blendid")
if params.use_filter_blendid:
layout.separator()
col = layout.column()
col.prop(params, "filter_id")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@ -91,11 +91,19 @@ char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_NONNULL();
/* Filelist */
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **filelist);
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist);
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src);
void BLI_filelist_duplicate(
struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
void *(*dup_poin)(void *));
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *));
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries);
void BLI_filelist_entry_free(struct direntry *entry);
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries);
void BLI_filelist_entry_size_to_string(const struct stat *st, const uint64_t sz, const bool compact, char r_size[]);
void BLI_filelist_entry_mode_to_string(
const struct stat *st, const bool compact, char r_mode1[], char r_mode2[], char r_mode3[]);
void BLI_filelist_entry_owner_to_string(const struct stat *st, const bool compact, char r_owner[]);
void BLI_filelist_entry_datetime_to_string(
const struct stat *st, const int64_t ts, const bool compact, char r_time[], char r_date[]);
/* Files */

View File

@ -39,7 +39,11 @@
typedef unsigned int mode_t;
#endif
struct ImBuf;
#define FILELIST_DIRENTRY_SIZE_LEN 16
#define FILELIST_DIRENTRY_MODE_LEN 4
#define FILELIST_DIRENTRY_OWNER_LEN 16
#define FILELIST_DIRENTRY_TIME_LEN 8
#define FILELIST_DIRENTRY_DATE_LEN 16
struct direntry {
mode_t type;
@ -56,19 +60,6 @@ struct direntry {
#else
struct stat s;
#endif
unsigned int flags;
char size[16];
char mode1[4];
char mode2[4];
char mode3[4];
char owner[16];
char time[8];
char date[16];
char extra[16];
void *poin;
int nr;
struct ImBuf *image;
unsigned int selflag; /* selection flag */
};
struct dirlink {

View File

@ -182,7 +182,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
/* Hack around for UNC paths on windows - does not support stat on '\\SERVER\foo\..', sigh... */
file->type |= S_IFDIR;
}
file->flags = 0;
dir_ctx->nrfiles++;
file++;
dlink = dlink->next;
@ -209,112 +208,13 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
}
}
/**
* Fills in the "mode[123]", "size" and "string" fields in the elements of the files
* array with descriptive details about each item. "string" will have a format similar to "ls -l".
*/
static void bli_adddirstrings(struct BuildDirCtx *dir_ctx)
{
const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
/* symbolic display, indexed by mode field value */
int num;
double size;
struct direntry *file;
struct tm *tm;
time_t zero = 0;
#ifndef WIN32
int mode;
#endif
for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) {
/* Mode */
#ifdef WIN32
BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
#else
mode = file->s.st_mode;
BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l';
if (mode & (S_ISUID | S_ISGID)) {
if (file->mode1[2] == 'x') file->mode1[2] = 's';
else file->mode1[2] = 'S';
if (file->mode2[2] == 'x') file->mode2[2] = 's';
}
if (mode & S_ISVTX) {
if (file->mode3[2] == 'x') file->mode3[2] = 't';
else file->mode3[2] = 'T';
}
#endif
/* User */
#ifdef WIN32
strcpy(file->owner, "user");
#else
{
struct passwd *pwuser;
pwuser = getpwuid(file->s.st_uid);
if (pwuser) {
BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
}
else {
BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid);
}
}
#endif
/* Time */
tm = localtime(&file->s.st_mtime);
// prevent impossible dates in windows
if (tm == NULL) tm = localtime(&zero);
strftime(file->time, sizeof(file->time), "%H:%M", tm);
strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
/* Size */
/*
* Seems st_size is signed 32-bit value in *nix and Windows. This
* will buy us some time until files get bigger than 4GB or until
* everyone starts using __USE_FILE_OFFSET64 or equivalent.
*/
size = (double)file->s.st_size;
if (size > 1024.0 * 1024.0 * 1024.0 * 1024.0) {
BLI_snprintf(file->size, sizeof(file->size), "%.1f TiB", size / (1024.0 * 1024.0 * 1024.0 * 1024.0));
}
else if (size > 1024.0 * 1024.0 * 1024.0) {
BLI_snprintf(file->size, sizeof(file->size), "%.1f GiB", size / (1024.0 * 1024.0 * 1024.0));
}
else if (size > 1024.0 * 1024.0) {
BLI_snprintf(file->size, sizeof(file->size), "%.1f MiB", size / (1024.0 * 1024.0));
}
else if (size > 1024.0) {
BLI_snprintf(file->size, sizeof(file->size), "%.1f KiB", size / 1024.0);
}
else {
BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)size);
}
}
}
/**
* Scans the contents of the directory named *dirname, and allocates and fills in an
* array of entries describing them in *filelist.
*
* \return The length of filelist array.
*/
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist)
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
{
struct BuildDirCtx dir_ctx;
@ -322,68 +222,188 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **f
dir_ctx.files = NULL;
bli_builddir(&dir_ctx, dirname);
bli_adddirstrings(&dir_ctx);
if (dir_ctx.files) {
*filelist = dir_ctx.files;
*r_filelist = dir_ctx.files;
}
else {
// keep blender happy. Blender stores this in a variable
// where 0 has special meaning.....
*filelist = MEM_mallocN(sizeof(**filelist), __func__);
*r_filelist = MEM_mallocN(sizeof(**r_filelist), __func__);
}
return dir_ctx.nrfiles;
}
/**
* Convert given entry's size into human-readable strings.
*
*/
void BLI_filelist_entry_size_to_string(
const struct stat *st, const uint64_t sz, const bool compact, char r_size[FILELIST_DIRENTRY_SIZE_LEN])
{
double size;
const char *fmt;
const char *units[] = {"KiB", "MiB", "GiB", "TiB", NULL};
const char *units_compact[] = {"K", "M", "G", "T", NULL};
const char *unit = "B";
/*
* Seems st_size is signed 32-bit value in *nix and Windows. This
* will buy us some time until files get bigger than 4GB or until
* everyone starts using __USE_FILE_OFFSET64 or equivalent.
*/
size = (double)(st ? st->st_size : sz);
if (size > 1024.0) {
const char **u;
for (u = compact ? units_compact : units, size /= 1024.0; size > 1024.0 && *(u + 1); u++, size /= 1024.0);
fmt = size > 100.0 ? "%.0f %s" : (size > 10.0 ? "%.1f %s" : "%.2f %s");
unit = *u;
}
else {
fmt = "%.0f %s";
}
BLI_snprintf(r_size, sizeof(*r_size) * FILELIST_DIRENTRY_SIZE_LEN, fmt, size, unit);
}
/**
* Convert given entry's modes into human-readable strings.
*
*/
void BLI_filelist_entry_mode_to_string(
const struct stat *st, const bool UNUSED(compact), char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN], char r_mode3[FILELIST_DIRENTRY_MODE_LEN])
{
const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
#ifdef WIN32
BLI_strncpy(r_mode1, types[0], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN);
BLI_strncpy(r_mode2, types[0], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN);
BLI_strncpy(r_mode3, types[0], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN);
#else
const int mode = st->st_mode;
BLI_strncpy(r_mode1, types[(mode & 0700) >> 6], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN);
BLI_strncpy(r_mode2, types[(mode & 0070) >> 3], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN);
BLI_strncpy(r_mode3, types[(mode & 0007)], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN);
if (((mode & S_ISGID) == S_ISGID) && (r_mode2[2] == '-')) r_mode2[2] = 'l';
if (mode & (S_ISUID | S_ISGID)) {
if (r_mode1[2] == 'x') r_mode1[2] = 's';
else r_mode1[2] = 'S';
if (r_mode2[2] == 'x') r_mode2[2] = 's';
}
if (mode & S_ISVTX) {
if (r_mode3[2] == 'x') r_mode3[2] = 't';
else r_mode3[2] = 'T';
}
#endif
}
/**
* Convert given entry's owner into human-readable strings.
*
*/
void BLI_filelist_entry_owner_to_string(
const struct stat *st, const bool UNUSED(compact), char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
{
#ifdef WIN32
strcpy(r_owner, "unknown");
#else
struct passwd *pwuser = getpwuid(st->st_uid);
if (pwuser) {
BLI_strncpy(r_owner, pwuser->pw_name, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN);
}
else {
BLI_snprintf(r_owner, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN, "%u", st->st_uid);
}
#endif
}
/**
* Convert given entry's time into human-readable strings.
*/
void BLI_filelist_entry_datetime_to_string(
const struct stat *st, const int64_t ts, const bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN])
{
const struct tm *tm = localtime(st ? &st->st_mtime : &ts);
const time_t zero = 0;
/* Prevent impossible dates in windows. */
if (tm == NULL) {
tm = localtime(&zero);
}
if (r_time) {
strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm);
}
if (r_date) {
strftime(r_date, sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN, compact ? "%d/%m/%y" : "%d-%b-%y", tm);
}
}
/**
* Deep-duplicate of a single direntry.
*
* \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
*dst = *src;
if (dst->relname) {
dst->relname = MEM_dupallocN(src->relname);
}
if (dst->path) {
dst->path = MEM_dupallocN(src->path);
}
}
/**
* Deep-duplicate of an array of direntries, including the array itself.
*
* \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
*/
void BLI_filelist_duplicate(
struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
void *(*dup_poin)(void *))
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries)
{
unsigned int i;
*dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
for (i = 0; i < nrentries; ++i) {
struct direntry * const src = &src_filelist[i];
struct direntry *dest = &(*dest_filelist)[i];
*dest = *src;
if (dest->image) {
dest->image = IMB_dupImBuf(src->image);
}
if (dest->relname) {
dest->relname = MEM_dupallocN(src->relname);
}
if (dest->path) {
dest->path = MEM_dupallocN(src->path);
}
if (dest->poin && dup_poin) {
dest->poin = dup_poin(src->poin);
}
struct direntry *dst = &(*dest_filelist)[i];
BLI_filelist_entry_duplicate(dst, src);
}
}
/**
* frees storage for a single direntry, not the direntry itself.
*/
void BLI_filelist_entry_free(struct direntry *entry)
{
if (entry->relname) {
MEM_freeN((void *)entry->relname);
}
if (entry->path) {
MEM_freeN((void *)entry->path);
}
}
/**
* frees storage for an array of direntries, including the array itself.
*/
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *))
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
for (i = 0; i < nrentries; ++i) {
struct direntry *entry = filelist + i;
if (entry->image) {
IMB_freeImBuf(entry->image);
}
if (entry->relname)
MEM_freeN((void *)entry->relname);
if (entry->path)
MEM_freeN((void *)entry->path);
if (entry->poin && free_poin)
free_poin(entry->poin);
BLI_filelist_entry_free(&filelist[i]);
}
if (filelist != NULL) {

View File

@ -33,6 +33,7 @@
struct ARegion;
struct FileSelectParams;
struct ScrArea;
struct SpaceFile;
struct bContext;
struct wmWindowManager;
@ -40,17 +41,13 @@ struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
#define MAX_FILE_COLUMN 8
#define MAX_FILE_COLUMN 4
typedef enum FileListColumns {
COLUMN_NAME = 0,
COLUMN_DATE,
COLUMN_TIME,
COLUMN_SIZE,
COLUMN_MODE1,
COLUMN_MODE2,
COLUMN_MODE3,
COLUMN_OWNER
} FileListColumns;
typedef struct FileLayout {
@ -71,6 +68,9 @@ typedef struct FileLayout {
int dirty;
int textheight;
float column_widths[MAX_FILE_COLUMN];
/* When we change display size, we may have to update static strings like size of files... */
short curr_size;
} FileLayout;
typedef struct FileSelection {
@ -100,9 +100,9 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile);
void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile);
int ED_file_extension_icon(const char *relname);

View File

@ -757,7 +757,7 @@ static void init_iconfile_list(struct ListBase *list)
}
}
BLI_filelist_free(dir, totfile, NULL);
BLI_filelist_free(dir, totfile);
dir = NULL;
}

View File

@ -3343,7 +3343,8 @@ void uiTemplateOperatorSearch(uiLayout *layout)
#define B_STOPCOMPO 4
#define B_STOPSEQ 5
#define B_STOPCLIP 6
#define B_STOPOTHER 7
#define B_STOPFILE 7
#define B_STOPOTHER 8
static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
{
@ -3366,6 +3367,9 @@ static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
case B_STOPCLIP:
WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
break;
case B_STOPFILE:
WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
break;
case B_STOPOTHER:
G.is_break = true;
break;
@ -3396,6 +3400,12 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
owner = sa;
handle_event = B_STOPCLIP;
}
else if (sa->spacetype == SPACE_FILE) {
if (WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR)) {
owner = sa;
}
handle_event = B_STOPFILE;
}
else {
Scene *scene;
/* another scene can be rendering too, for example via compositor */

View File

@ -31,6 +31,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
../../../../intern/atomic
../../../../intern/guardedalloc
../../../../intern/glew-mx
)

View File

@ -29,6 +29,7 @@ Import ('env')
sources = env.Glob('*.c')
incs = [
'#/intern/atomic',
'#/intern/guardedalloc',
env['BF_GLEW_INC'],
'#/intern/glew-mx',

View File

@ -35,6 +35,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
#include "BLI_math.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@ -47,6 +48,8 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BLO_readfile.h"
#include "BLT_translation.h"
#include "IMB_imbuf_types.h"
@ -64,12 +67,20 @@
#include "UI_resources.h"
#include "UI_view2d.h"
#include "WM_api.h"
#include "WM_types.h"
#include "filelist.h"
#include "file_intern.h" // own include
/* Dummy helper - we need dynamic tooltips here. */
static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
{
char *dyn_tooltip = argN;
return BLI_strdup(dyn_tooltip);
}
/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d.
* The controls are laid out as follows:
*
@ -157,9 +168,9 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
/* Text input fields for directory and file. */
if (available_w > 0) {
const struct direntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL;
const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL;
int overwrite_alert = file_draw_check_exists(sfile);
const bool is_active_dir = file && file->path && BLI_is_dir(file->path);
const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER);
/* callbacks for operator check functions */
UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
@ -220,8 +231,8 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
/* Execute / cancel buttons. */
if (loadbutton) {
const struct direntry *file = filelist_file(sfile->files, params->active_file);
const char *str_exec = (file && file->path && BLI_is_dir(file->path)) ?
const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL;
const char *str_exec = (file && (file->typeflag & FILE_TYPE_FOLDER)) ?
/* params->title is already translated! */
IFACE_("Open Directory") : params->title;
@ -244,44 +255,6 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh
}
static int get_file_icon(struct direntry *file)
{
if (file->type & S_IFDIR) {
if (FILENAME_IS_PARENT(file->relname)) {
return ICON_FILE_PARENT;
}
if (file->flags & FILE_TYPE_APPLICATIONBUNDLE) {
return ICON_UGLYPACKAGE;
}
if (file->flags & FILE_TYPE_BLENDER) {
return ICON_FILE_BLEND;
}
return ICON_FILE_FOLDER;
}
else if (file->flags & FILE_TYPE_BLENDER)
return ICON_FILE_BLEND;
else if (file->flags & FILE_TYPE_BLENDER_BACKUP)
return ICON_FILE_BACKUP;
else if (file->flags & FILE_TYPE_IMAGE)
return ICON_FILE_IMAGE;
else if (file->flags & FILE_TYPE_MOVIE)
return ICON_FILE_MOVIE;
else if (file->flags & FILE_TYPE_PYSCRIPT)
return ICON_FILE_SCRIPT;
else if (file->flags & FILE_TYPE_SOUND)
return ICON_FILE_SOUND;
else if (file->flags & FILE_TYPE_FTFONT)
return ICON_FILE_FONT;
else if (file->flags & FILE_TYPE_BTX)
return ICON_FILE_BLANK;
else if (file->flags & FILE_TYPE_COLLADA)
return ICON_FILE_BLANK;
else if (file->flags & FILE_TYPE_TEXT)
return ICON_FILE_TEXT;
else
return ICON_FILE_BLANK;
}
static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag)
{
uiBut *but;
@ -293,10 +266,12 @@ static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int
/*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/
but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, "");
but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
if (drag) {
UI_but_drag_set_path(but, path, false);
/* path is no more static, cannot give it directly to but... */
UI_but_drag_set_path(but, BLI_strdup(path), true);
}
}
@ -338,7 +313,9 @@ void file_calc_previews(const bContext *C, ARegion *ar)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool is_icon, bool drag)
static void file_draw_preview(
uiBlock *block, const char *path, int sx, int sy, const float icon_aspect,
ImBuf *imb, const int icon, FileLayout *layout, const bool is_icon, const int typeflags, const bool drag)
{
uiBut *but;
float fx, fy;
@ -348,7 +325,7 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
float scaledx, scaledy;
float scale;
int ex, ey;
bool use_dropshadow = !is_icon && (file->flags & FILE_TYPE_IMAGE);
bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
BLI_assert(imb != NULL);
@ -394,7 +371,7 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
glEnable(GL_BLEND);
/* the image */
if (!is_icon && file->flags & FILE_TYPE_FTFONT) {
if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
UI_ThemeColor(TH_TEXT);
}
else {
@ -402,16 +379,23 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
}
glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
if (icon) {
UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f);
}
/* border */
if (use_dropshadow) {
glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
}
but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
/* dragregion */
if (drag) {
but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, "");
UI_but_drag_set_image(but, file->path, get_file_icon(file), imb, scale, false);
/* path is no more static, cannot give it directly to but... */
UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true);
}
glDisable(GL_BLEND);
@ -424,6 +408,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
char filename[FILE_MAX + 12];
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
BLI_make_file_string(G.main->name, orgname, sfile->params->dir, oldname);
@ -435,7 +420,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
if (!BLI_exists(newname)) {
BLI_rename(orgname, newname);
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
}
ED_region_tag_redraw(ar);
@ -500,7 +485,8 @@ void file_draw_list(const bContext *C, ARegion *ar)
FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
View2D *v2d = &ar->v2d;
struct FileList *files = sfile->files;
struct direntry *file;
struct FileDirEntry *file;
const char *root = filelist_dir(files);
ImBuf *imb;
uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
int numfiles;
@ -513,8 +499,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
short align;
bool do_drag;
int column_space = 0.6f * UI_UNIT_X;
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
numfiles = filelist_numfiles(files);
numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
@ -536,27 +525,61 @@ void file_draw_list(const bContext *C, ARegion *ar)
numfiles_layout += layout->columns;
}
filelist_file_cache_slidingwindow_set(files, numfiles_layout);
textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : (int)layout->column_widths[COLUMN_NAME];
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
if (numfiles > 0) {
const bool success = filelist_file_cache_block(files, min_ii(offset + (numfiles_layout / 2), numfiles - 1));
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
filelist_cache_previews_update(files);
/* Handle preview timer here, since it's filelist_file_cache_block() and filelist_cache_previews_update()
* which controlls previews task. */
{
const bool previews_running = filelist_cache_previews_running(files);
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C),
NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01);
}
if (!previews_running && sfile->previews_timer) {
/* Preview is not running, no need to keep generating update events! */
// printf("%s: Inactive preview task, sleeping!\n", __func__);
WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
}
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
unsigned int file_selflag;
char path[FILE_MAX_LIBEXTRA];
ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X);
sy = (int)(v2d->tot.ymax - sy);
file = filelist_file(files, i);
file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL);
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
UI_ThemeColor4(TH_TEXT);
if (!(file->selflag & FILE_SEL_EDITING)) {
if ((params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) {
int colorid = (file->selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0;
if (!(file_selflag & FILE_SEL_EDITING)) {
if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ||
(file_selflag & FILE_SEL_SELECTED))
{
int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0;
BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relname));
BLI_assert(i > 0 || FILENAME_IS_CURRPAR(file->relpath));
draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
@ -564,26 +587,29 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_draw_roundbox_corner_set(UI_CNR_NONE);
/* don't drag parent or refresh items */
do_drag = !(FILENAME_IS_CURRPAR(file->relname));
do_drag = !(FILENAME_IS_CURRPAR(file->relpath));
if (FILE_IMGDISPLAY == params->display) {
const int icon = filelist_geticon(files, i, false);
is_icon = 0;
imb = filelist_getimage(files, i);
if (!imb) {
imb = filelist_geticon(files, i);
imb = filelist_geticon_image(files, i);
is_icon = 1;
}
file_draw_preview(block, file, sx, sy, imb, layout, is_icon, do_drag);
file_draw_preview(block, path, sx, sy, thumb_icon_aspect,
imb, icon, layout, is_icon, file->typeflag, do_drag);
}
else {
file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
file_draw_icon(block, path, sx, sy - (UI_UNIT_Y / 6), filelist_geticon(files, i, true),
ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
UI_ThemeColor4(TH_TEXT);
if (file->selflag & FILE_SEL_EDITING) {
if (file_selflag & FILE_SEL_EDITING) {
uiBut *but;
short width;
@ -591,9 +617,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X);
}
else if (params->display == FILE_LONGDISPLAY) {
width = layout->column_widths[COLUMN_NAME] + layout->column_widths[COLUMN_MODE1] +
layout->column_widths[COLUMN_MODE2] + layout->column_widths[COLUMN_MODE3] +
(column_space * 3.5f);
width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f);
}
else {
BLI_assert(params->display == FILE_IMGDISPLAY);
@ -601,53 +625,51 @@ void file_draw_list(const bContext *C, ARegion *ar)
}
but = uiDefBut(block, UI_BTYPE_TEXT, 1, "", sx, sy - layout->tile_h - 0.15f * UI_UNIT_X,
width, textheight, sfile->params->renameedit, 1.0f, (float)sizeof(sfile->params->renameedit), 0, 0, "");
width, textheight, sfile->params->renameedit, 1.0f,
(float)sizeof(sfile->params->renameedit), 0, 0, "");
UI_but_func_rename_set(but, renamebutton_cb, file);
UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */
UI_but_flag_disable(but, UI_BUT_UNDO);
if (false == UI_but_active_only(C, ar, block, but)) {
file->selflag &= ~FILE_SEL_EDITING;
file_selflag = filelist_entry_select_set(
sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
}
}
if (!(file->selflag & FILE_SEL_EDITING)) {
if (!(file_selflag& FILE_SEL_EDITING)) {
int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy;
file_draw_string(sx + 1, tpos, file->relname, (float)textwidth, textheight, align);
file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align);
}
if (params->display == FILE_SHORTDISPLAY) {
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
if (!(file->type & S_IFDIR)) {
file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
if (!(file->typeflag & FILE_TYPE_DIR)) {
if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
}
file_draw_string(
sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
}
else if (params->display == FILE_LONGDISPLAY) {
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
#ifndef WIN32
/* rwx rwx rwx */
file_draw_string(sx, sy, file->mode1, layout->column_widths[COLUMN_MODE1], layout->tile_h, align);
sx += layout->column_widths[COLUMN_MODE1] + column_space;
file_draw_string(sx, sy, file->mode2, layout->column_widths[COLUMN_MODE2], layout->tile_h, align);
sx += layout->column_widths[COLUMN_MODE2] + column_space;
file_draw_string(sx, sy, file->mode3, layout->column_widths[COLUMN_MODE3], layout->tile_h, align);
sx += layout->column_widths[COLUMN_MODE3] + column_space;
file_draw_string(sx, sy, file->owner, layout->column_widths[COLUMN_OWNER], layout->tile_h, align);
sx += layout->column_widths[COLUMN_OWNER] + column_space;
#endif
file_draw_string(sx, sy, file->date, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
if ((file->entry->date_str[0] == '\0') || update_stat_strings) {
BLI_filelist_entry_datetime_to_string(
NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str);
}
file_draw_string(sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
file_draw_string(sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
if (!(file->type & S_IFDIR)) {
file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
if (!(file->typeflag & FILE_TYPE_DIR)) {
if ((file->entry->size_str[0] == '\0') || update_stat_strings) {
BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
}
file_draw_string(
sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
}
@ -656,4 +678,5 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
layout->curr_size = params->thumbnail_size;
}

View File

@ -48,6 +48,8 @@ struct ARegion *file_tools_region(struct ScrArea *sa);
#define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2)
#define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6)
#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
void file_draw_buttons(const bContext *C, ARegion *ar);
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);

View File

@ -99,9 +99,9 @@ static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
{
FileSelection sel;
sel.first = 0;
sel.last = filelist_numfiles(sfile->files) - 1;
sel.last = filelist_files_ensure(sfile->files) - 1;
filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
}
typedef enum FileSelect {
@ -139,7 +139,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
int numfiles = filelist_numfiles(sfile->files);
int numfiles = filelist_files_ensure(sfile->files);
FileSelection sel;
sel = find_file_mouse_rect(sfile, ar, rect);
@ -152,7 +152,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
int f = sel.last;
while (f >= 0) {
if (filelist_is_selected(sfile->files, f, CHECK_ALL) )
if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) )
break;
f--;
}
@ -168,8 +168,8 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
FileSelect retval = FILE_SELECT_NOTHING;
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
int numfiles = filelist_numfiles(sfile->files);
struct direntry *file;
int numfiles = filelist_files_ensure(sfile->files);
const FileDirEntry *file;
/* make the selected file active */
if ((selected_idx >= 0) &&
@ -177,27 +177,33 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
(file = filelist_file(sfile->files, selected_idx)))
{
params->highlight_file = selected_idx;
sfile->params->active_file = selected_idx;
params->active_file = selected_idx;
if (S_ISDIR(file->type)) {
const bool is_parent_dir = FILENAME_IS_PARENT(file->relname);
if (file->typeflag & FILE_TYPE_DIR) {
const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
if (do_diropen == false) {
params->file[0] = '\0';
retval = FILE_SELECT_DIR;
}
/* the path is too long and we are not going up! */
else if (!is_parent_dir && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
// XXX error("Path too long, cannot enter this directory");
}
else {
if (is_parent_dir) {
/* avoids /../../ */
BLI_parent_dir(params->dir);
if (params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
params->recursion_level = 0;
filelist_setrecursion(sfile->files, params->recursion_level);
}
}
else {
BLI_cleanup_dir(G.main->name, params->dir);
strcat(params->dir, file->relname);
strcat(params->dir, file->relpath);
BLI_add_slash(params->dir);
}
@ -218,11 +224,12 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
*/
static bool file_is_any_selected(struct FileList *files)
{
const int numfiles = filelist_numfiles(files);
const int numfiles = filelist_files_ensure(files);
int i;
/* Is any file selected ? */
for (i = 0; i < numfiles; ++i) {
if (filelist_is_selected(files, i, CHECK_ALL)) {
if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
return true;
}
}
@ -239,7 +246,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
/* flag the files as selected in the filelist */
filelist_select(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
/* Don't act on multiple selected files */
if (sel.first != sel.last) select = 0;
@ -247,7 +254,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
/* Do we have a valid selection and are we actually selecting */
if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
/* Check last selection, if selected, act on the file or dir */
if (filelist_is_selected(sfile->files, sel.last, check_type)) {
if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
retval = file_select_do(C, sel.last, do_diropen);
}
}
@ -305,25 +312,24 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
result = WM_border_select_modal(C, op, event);
if (result == OPERATOR_RUNNING_MODAL) {
WM_operator_properties_border_to_rcti(op, &rect);
BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
sel = file_selection_get(C, &rect, 0);
if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
int idx;
file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
for (idx = sel.last; idx >= 0; idx--) {
struct direntry *file = filelist_file(sfile->files, idx);
const FileDirEntry *file = filelist_file(sfile->files, idx);
/* dont highlight readonly file (".." or ".") on border select */
if (FILENAME_IS_CURRPAR(file->relname)) {
file->selflag &= ~FILE_SEL_HIGHLIGHTED;
if (FILENAME_IS_CURRPAR(file->relpath)) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
}
/* make sure highlight_file is no readonly file */
@ -366,7 +372,7 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
/* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
filelist_select_file(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
if (FILE_SELECT_DIR == ret) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@ -416,8 +422,9 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (sfile && sfile->params) {
int idx = sfile->params->highlight_file;
int numfiles = filelist_files_ensure(sfile->files);
if (idx >= 0) {
if ((idx >= 0) && (idx < numfiles)) {
/* single select, deselect all selected first */
if (!extend) {
file_deselect_all(sfile, FILE_SEL_SELECTED);
@ -429,7 +436,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (extend) {
/* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
filelist_select_file(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
if (FILE_SELECT_DIR == ret)
@ -484,12 +491,13 @@ static bool file_walk_select_selection_set(
if (has_selection) {
if (extend &&
filelist_is_selected(files, active_old, FILE_SEL_SELECTED) &&
filelist_is_selected(files, active_new, FILE_SEL_SELECTED))
filelist_entry_select_index_get(files, active_old, FILE_SEL_SELECTED) &&
filelist_entry_select_index_get(files, active_new, FILE_SEL_SELECTED))
{
/* conditions for deselecting: initial file is selected, new file is
* selected and either other_side isn't selected/found or we use fill */
deselect = (fill || other_site == -1 || !filelist_is_selected(files, other_site, FILE_SEL_SELECTED));
deselect = (fill || other_site == -1 ||
!filelist_entry_select_index_get(files, other_site, FILE_SEL_SELECTED));
/* don't change highlight_file here since we either want to deselect active or we want to
* walk through a block of selected files without selecting/deselecting anything */
@ -527,7 +535,7 @@ static bool file_walk_select_selection_set(
params->highlight_file = params->active_file;
/* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
filelist_select_file(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
else {
/* deselect all first */
@ -548,15 +556,15 @@ static bool file_walk_select_selection_set(
}
/* fill selection between last and first selected file */
filelist_select(
filelist_entries_select_index_range_set(
files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
/* entire sel is cleared here, so select active again */
if (deselect) {
filelist_select_file(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
}
}
else {
filelist_select_file(
filelist_entry_select_index_set(
files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
}
@ -576,7 +584,7 @@ static bool file_walk_select_do(
const bool extend, const bool fill)
{
struct FileList *files = sfile->files;
const int numfiles = filelist_numfiles(files);
const int numfiles = filelist_files_ensure(files);
const bool has_selection = file_is_any_selected(files);
const int active_old = params->active_file;
int active_new = -1;
@ -692,7 +700,7 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelection sel;
const int numfiles = filelist_numfiles(sfile->files);
const int numfiles = filelist_files_ensure(sfile->files);
const bool has_selection = file_is_any_selected(sfile->files);
sel.first = 0;
@ -700,18 +708,18 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
/* select all only if previously no file was selected */
if (has_selection) {
filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
sfile->params->active_file = -1;
}
else {
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
int i;
filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type);
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type);
/* set active_file to first selected */
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, check_type)) {
if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
sfile->params->active_file = i;
break;
}
@ -1029,7 +1037,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
if (sfile == NULL || sfile->files == NULL) return 0;
numfiles = filelist_numfiles(sfile->files);
numfiles = filelist_files_ensure(sfile->files);
params = ED_fileselect_get_params(sfile);
origfile = params->highlight_file;
@ -1143,17 +1151,17 @@ void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
/* this is called on operators check() so clear collections first since
* they may be already set. */
{
int i, numfiles = filelist_numfiles(sfile->files);
int i, numfiles = filelist_files_ensure(sfile->files);
if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
PointerRNA itemptr;
int num_files = 0;
RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
struct direntry *file = filelist_file(sfile->files, i);
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
FileDirEntry *file = filelist_file(sfile->files, i);
RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", file->relname);
RNA_string_set(&itemptr, "name", file->relpath);
num_files++;
}
}
@ -1169,10 +1177,10 @@ void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
int num_dirs = 0;
RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
struct direntry *file = filelist_file(sfile->files, i);
if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) {
FileDirEntry *file = filelist_file(sfile->files, i);
RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", file->relname);
RNA_string_set(&itemptr, "name", file->relpath);
num_dirs++;
}
}
@ -1262,19 +1270,17 @@ int file_exec(bContext *C, wmOperator *exec_op)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
const struct direntry *file = filelist_file(sfile->files, sfile->params->active_file);
const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
/* directory change */
if (file && S_ISDIR(file->type)) {
BLI_assert(file->path == NULL || STRPREFIX(file->path, sfile->params->dir));
if (FILENAME_IS_PARENT(file->relname)) {
if (file && (file->typeflag & FILE_TYPE_DIR)) {
if (FILENAME_IS_PARENT(file->relpath)) {
BLI_parent_dir(sfile->params->dir);
}
else if (file->relname) {
else if (file->relpath) {
BLI_cleanup_dir(G.main->name, sfile->params->dir);
strcat(sfile->params->dir, file->relname);
strcat(sfile->params->dir, file->relpath);
BLI_add_slash(sfile->params->dir);
}
@ -1287,10 +1293,11 @@ int file_exec(bContext *C, wmOperator *exec_op)
/* when used as a macro, for doubleclick,
* to prevent closing when doubleclicking on .. item */
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
const int numfiles = filelist_files_ensure(sfile->files);
int i, active = 0;
for (i = 0; i < filelist_numfiles(sfile->files); i++) {
if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
active = 1;
break;
}
@ -1358,6 +1365,11 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
else {
ED_file_change_dir(C, true);
}
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
sfile->params->recursion_level = 0;
filelist_setrecursion(sfile->files, sfile->params->recursion_level);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
}
@ -1384,9 +1396,10 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@ -1476,11 +1489,11 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
return OPERATOR_PASS_THROUGH;
numfiles = filelist_numfiles(sfile->files);
numfiles = filelist_files_ensure(sfile->files);
/* check if we are editing a name */
for (i = 0; i < numfiles; ++i) {
if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) ) {
edit_idx = i;
break;
}
@ -1603,6 +1616,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@ -1655,7 +1669,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
@ -1876,10 +1890,11 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
if (sfile->params) {
sfile->params->flag ^= FILE_HIDE_DOT;
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@ -1989,11 +2004,11 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
if (sfile->params) {
int idx = sfile->params->highlight_file;
int numfiles = filelist_numfiles(sfile->files);
int numfiles = filelist_files_ensure(sfile->files);
if ((0 <= idx) && (idx < numfiles)) {
struct direntry *file = filelist_file(sfile->files, idx);
filelist_select_file(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
FileDirEntry *file = filelist_file(sfile->files, idx);
filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
BLI_strncpy(sfile->params->renameedit, file->relpath, FILE_MAXFILE);
sfile->params->renamefile[0] = '\0';
}
ED_area_tag_redraw(sa);
@ -2005,29 +2020,34 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
static int file_rename_poll(bContext *C)
{
int poll = ED_operator_file_active(C);
bool poll = ED_operator_file_active(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
int idx = sfile->params->highlight_file;
int numfiles = filelist_files_ensure(sfile->files);
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
if (FILENAME_IS_CURRPAR(file->relname)) {
poll = 0;
if ((0 <= idx) && (idx < numfiles)) {
FileDirEntry *file = filelist_file(sfile->files, idx);
if (FILENAME_IS_CURRPAR(file->relpath)) {
poll = false;
}
}
if (sfile->params->highlight_file < 0) {
poll = 0;
poll = false;
}
else {
char dir[FILE_MAX];
if (filelist_islibrary(sfile->files, dir, NULL)) poll = 0;
if (filelist_islibrary(sfile->files, dir, NULL)) {
poll = false;
}
}
}
else
poll = 0;
else {
poll = false;
}
return poll;
}
@ -2051,13 +2071,13 @@ static int file_delete_poll(bContext *C)
if (sfile && sfile->params) {
char dir[FILE_MAX];
int numfiles = filelist_numfiles(sfile->files);
int numfiles = filelist_files_ensure(sfile->files);
int i;
int num_selected = 0;
if (filelist_islibrary(sfile->files, dir, NULL)) poll = 0;
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
num_selected++;
}
}
@ -2076,19 +2096,20 @@ int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
char str[FILE_MAX];
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct direntry *file;
int numfiles = filelist_numfiles(sfile->files);
ScrArea *sa = CTX_wm_area(C);
FileDirEntry *file;
int numfiles = filelist_files_ensure(sfile->files);
int i;
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath);
BLI_delete(str, false, false);
}
}
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;

File diff suppressed because it is too large Load Diff

View File

@ -40,9 +40,10 @@ extern "C" {
struct BlendHandle;
struct FileList;
struct FileSelection;
struct direntry;
struct wmWindowManager;
struct FileDirEntry;
typedef enum FileSelType {
FILE_SEL_REMOVE = 0,
FILE_SEL_ADD = 1,
@ -65,11 +66,10 @@ int folderlist_clear_next(struct SpaceFile *sfile);
void filelist_setsorting(struct FileList *filelist, const short sort);
bool filelist_need_sorting(struct FileList *filelist);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
const unsigned int filter,
const unsigned int filter, const unsigned int filter_id,
const char *filter_glob, const char *filter_search);
void filelist_filter(struct FileList *filelist);
@ -77,34 +77,48 @@ void filelist_init_icons(void);
void filelist_free_icons(void);
void filelist_imgsize(struct FileList *filelist, short w, short h);
struct ImBuf * filelist_getimage(struct FileList *filelist, const int index);
struct ImBuf * filelist_geticon(struct FileList *filelist, const int index);
struct ImBuf * filelist_geticon_image(struct FileList *filelist, const int index);
int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
struct FileList * filelist_new(short type);
void filelist_clear(struct FileList *filelist);
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection);
void filelist_free(struct FileList *filelist);
const char * filelist_dir(struct FileList *filelist);
void filelist_readdir(struct FileList *filelist);
void filelist_setdir(struct FileList *filelist, const char *dir);
void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
int filelist_empty(struct FileList *filelist);
int filelist_numfiles(struct FileList *filelist);
struct direntry * filelist_file(struct FileList *filelist, int index);
int filelist_find(struct FileList *filelist, const char *file);
FileDirEntry * filelist_file(struct FileList *filelist, int index);
int filelist_file_findpath(struct FileList *filelist, const char *file);
FileDirEntry * filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
bool filelist_file_cache_block(struct FileList *filelist, const int index);
short filelist_changed(struct FileList *filelist);
bool filelist_force_reset(struct FileList *filelist);
bool filelist_pending(struct FileList *filelist);
bool filelist_is_ready(struct FileList *filelist);
void filelist_select(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check);
bool filelist_is_selected(struct FileList *filelist, int index, FileCheckType check);
unsigned int filelist_entry_select_set(const struct FileList *filelist, const struct FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check);
void filelist_entry_select_index_set(struct FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check);
void filelist_entries_select_index_range_set(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check);
unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check);
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
struct BlendHandle *filelist_lib(struct FileList *filelist);
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group);
void filelist_freelib(struct FileList *filelist);
bool filelist_need_thumbnails(struct FileList *filelist);
void thumbnails_start(struct FileList *filelist, const struct bContext *C);
void thumbnails_stop(struct wmWindowManager *wm, struct FileList *filelist);
int thumbnails_running(struct wmWindowManager *wm, struct FileList *filelist);
void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa);
int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa);
bool filelist_cache_previews_update(struct FileList *filelist);
void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);
bool filelist_cache_previews_running(struct FileList *filelist);
#ifdef __cplusplus
}

View File

@ -163,6 +163,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->filter = 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_blender")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_blenlib")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDERLIB : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_backup")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER_BACKUP : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_image")))
@ -200,6 +202,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
}
/* For now, always init filterid to 'all true' */
params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD |
FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE |
FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO;
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
}
@ -292,9 +301,9 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
*/
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct direntry *file = filelist_file(sfile->files, index);
if (file && file->relname[0] && file->path && !BLI_is_dir(file->path)) {
BLI_strncpy(sfile->params->file, file->relname, FILE_MAXFILE);
const struct FileDirEntry *file = filelist_file(sfile->files, index);
if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) {
BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE);
}
}
@ -446,37 +455,20 @@ float file_font_pointsize(void)
#endif
}
static void column_widths(struct FileList *files, struct FileLayout *layout)
static void column_widths(FileSelectParams *params, struct FileLayout *layout)
{
int i;
int numfiles = filelist_numfiles(files);
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
for (i = 0; i < MAX_FILE_COLUMN; ++i) {
layout->column_widths[i] = 0;
}
for (i = 0; (i < numfiles); ++i) {
struct direntry *file = filelist_file(files, i);
if (file) {
float len;
len = file_string_width(file->relname);
if (len > layout->column_widths[COLUMN_NAME]) layout->column_widths[COLUMN_NAME] = len;
len = file_string_width(file->date);
if (len > layout->column_widths[COLUMN_DATE]) layout->column_widths[COLUMN_DATE] = len;
len = file_string_width(file->time);
if (len > layout->column_widths[COLUMN_TIME]) layout->column_widths[COLUMN_TIME] = len;
len = file_string_width(file->size);
if (len > layout->column_widths[COLUMN_SIZE]) layout->column_widths[COLUMN_SIZE] = len;
len = file_string_width(file->mode1);
if (len > layout->column_widths[COLUMN_MODE1]) layout->column_widths[COLUMN_MODE1] = len;
len = file_string_width(file->mode2);
if (len > layout->column_widths[COLUMN_MODE2]) layout->column_widths[COLUMN_MODE2] = len;
len = file_string_width(file->mode3);
if (len > layout->column_widths[COLUMN_MODE3]) layout->column_widths[COLUMN_MODE3] = len;
len = file_string_width(file->owner);
if (len > layout->column_widths[COLUMN_OWNER]) layout->column_widths[COLUMN_OWNER] = len;
}
}
layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;;
/* Biggest possible reasonable values... */
layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89");
layout->column_widths[COLUMN_TIME] = file_string_width("23:59");
layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB");
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@ -496,7 +488,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
return;
}
numfiles = filelist_numfiles(sfile->files);
numfiles = filelist_files_ensure(sfile->files);
textheight = (int)file_font_pointsize();
layout = sfile->layout;
layout->textheight = textheight;
@ -535,7 +527,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
layout->rows = layout->height / (layout->tile_h + 2 * layout->tile_border_y);
column_widths(sfile->files, layout);
column_widths(params, layout);
if (params->display == FILE_SHORTDISPLAY) {
maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
@ -545,12 +537,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
else {
maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
(int)layout->column_widths[COLUMN_NAME] + column_space +
#ifndef WIN32
(int)layout->column_widths[COLUMN_MODE1] + column_space +
(int)layout->column_widths[COLUMN_MODE2] + column_space +
(int)layout->column_widths[COLUMN_MODE3] + column_space +
(int)layout->column_widths[COLUMN_OWNER] + column_space +
#endif
(int)layout->column_widths[COLUMN_DATE] + column_space +
(int)layout->column_widths[COLUMN_TIME] + column_space +
(int)layout->column_widths[COLUMN_SIZE] + column_space;
@ -581,9 +567,10 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
if (sfile->params) {
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
/* Clear search string, it is very rare to want to keep that filter while changing dir,
* and usually very annoying to keep it actually! */
@ -610,8 +597,8 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
int match = 0;
int i;
struct direntry *file;
int n = filelist_numfiles(sfile->files);
FileDirEntry *file;
int n = filelist_files_ensure(sfile->files);
/* select any file that matches the pattern, this includes exact match
* if the user selects a single file by entering the filename
@ -619,10 +606,10 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
/* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
if (fnmatch(pattern, file->relname, 0) == 0) {
file->selflag |= FILE_SEL_SELECTED;
if (fnmatch(pattern, file->relpath, 0) == 0) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
if (!match) {
BLI_strncpy(matched_file, file->relname, FILE_MAX);
BLI_strncpy(matched_file, file->relpath, FILE_MAX);
}
match++;
}
@ -687,14 +674,12 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
/* search if str matches the beginning of name */
if (str[0] && sfile->files) {
AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
int nentries = filelist_numfiles(sfile->files);
int nentries = filelist_files_ensure(sfile->files);
int i;
for (i = 0; i < nentries; ++i) {
struct direntry *file = filelist_file(sfile->files, i);
if (file && (S_ISREG(file->type) || S_ISDIR(file->type))) {
UI_autocomplete_update_name(autocpl, file->relname);
}
FileDirEntry *file = filelist_file(sfile->files, i);
UI_autocomplete_update_name(autocpl, file->relpath);
}
match = UI_autocomplete_end(autocpl, str);
}
@ -702,20 +687,20 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
return match;
}
void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile)
void ED_fileselect_clear(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
{
/* only NULL in rare cases - [#29734] */
if (sfile->files) {
thumbnails_stop(wm, sfile->files);
filelist_readjob_stop(wm, sa);
filelist_freelib(sfile->files);
filelist_free(sfile->files);
filelist_clear(sfile->files);
}
sfile->params->highlight_file = -1;
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile)
void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
{
if (!sfile) return;
if (sfile->op) {
@ -727,7 +712,8 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile)
folderlist_free(sfile->folders_next);
if (sfile->files) {
ED_fileselect_clear(wm, sfile);
ED_fileselect_clear(wm, sa, sfile);
filelist_free(sfile->files);
MEM_freeN(sfile->files);
sfile->files = NULL;
}

View File

@ -117,6 +117,8 @@ static void file_free(SpaceLink *sl)
{
SpaceFile *sfile = (SpaceFile *) sl;
BLI_assert(sfile->previews_timer == NULL);
if (sfile->files) {
// XXXXX would need to do thumbnails_stop here, but no context available
filelist_freelib(sfile->files);
@ -170,7 +172,12 @@ static void file_exit(wmWindowManager *wm, ScrArea *sa)
{
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
ED_fileselect_exit(wm, sfile);
if (sfile->previews_timer) {
WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer);
sfile->previews_timer = NULL;
}
ED_fileselect_exit(wm, sa, sfile);
}
static SpaceLink *file_duplicate(SpaceLink *sl)
@ -211,13 +218,15 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
if (!sfile->files) {
sfile->files = filelist_new(params->type);
filelist_setdir(sfile->files, params->dir);
params->highlight_file = -1; /* added this so it opens nicer (ton) */
}
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
filelist_setsorting(sfile->files, params->sort);
filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT,
filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0,
false, /* TODO hide_parent, should be controllable? */
params->flag & FILE_FILTER ? params->filter : 0,
params->filter_id,
params->filter_glob,
params->filter_search);
@ -227,39 +236,45 @@ static void file_refresh(const bContext *C, ScrArea *sa)
sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir);
sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
if (filelist_empty(sfile->files)) {
thumbnails_stop(wm, sfile->files);
filelist_readdir(sfile->files);
filelist_sort(sfile->files);
BLI_strncpy(params->dir, filelist_dir(sfile->files), FILE_MAX);
}
else if (filelist_need_sorting(sfile->files)) {
thumbnails_stop(wm, sfile->files);
filelist_sort(sfile->files);
if (filelist_force_reset(sfile->files)) {
filelist_readjob_stop(wm, sa);
filelist_clear(sfile->files);
}
if ((params->display == FILE_IMGDISPLAY) && filelist_need_thumbnails(sfile->files)) {
if (!thumbnails_running(wm, sfile->files)) {
thumbnails_start(sfile->files, C);
if (filelist_empty(sfile->files)) {
if (!filelist_pending(sfile->files)) {
filelist_readjob_start(sfile->files, C);
}
}
else {
/* stop any running thumbnail jobs if we're not displaying them - speedup for NFS */
thumbnails_stop(wm, sfile->files);
}
filelist_sort(sfile->files);
filelist_filter(sfile->files);
if (params->display == FILE_IMGDISPLAY) {
filelist_cache_previews_set(sfile->files, true);
}
else {
filelist_cache_previews_set(sfile->files, false);
if (sfile->previews_timer) {
WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
if (params->renamefile[0] != '\0') {
int idx = filelist_find(sfile->files, params->renamefile);
int idx = filelist_file_findpath(sfile->files, params->renamefile);
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
FileDirEntry *file = filelist_file(sfile->files, idx);
if (file) {
file->selflag |= FILE_SEL_EDITING;
filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
}
}
BLI_strncpy(sfile->params->renameedit, sfile->params->renamefile, sizeof(sfile->params->renameedit));
params->renamefile[0] = '\0';
/* File listing is now async, do not clear renamefile if matching entry not found
* and dirlist is not finished! */
if (idx >= 0 || filelist_is_ready(sfile->files)) {
params->renamefile[0] = '\0';
}
}
if (sfile->layout) {
@ -278,7 +293,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
{
/* SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; */
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
/* context changes */
switch (wmn->category) {
@ -292,6 +307,12 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
break;
case ND_SPACE_FILE_PREVIEW:
if (filelist_cache_previews_update(sfile->files)) {
ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
break;
}
break;
}

View File

@ -590,6 +590,7 @@ typedef struct FileSelectParams {
char filter_glob[64]; /* list of filetypes to filter */
char filter_search[64]; /* text items' name must match to be shown. */
int filter_id; /* same as filter, but for ID types (aka library groups). */
int active_file; /* active file used for keyboard navigation */
int highlight_file; /* file under cursor */
@ -603,7 +604,9 @@ typedef struct FileSelectParams {
short flag; /* settings for filter, hiding dots files,... */
short sort; /* sort order */
short display; /* display mode flag */
short filter; /* filter when (flags & FILE_FILTER) is true */
int filter; /* filter when (flags & FILE_FILTER) is true */
short recursion_level; /* max number of levels in dirtree to show at once, 0 to disable recursion. */
/* XXX --- still unused -- */
short f_fp; /* show font preview */
@ -635,6 +638,7 @@ typedef struct SpaceFile {
struct wmOperator *op;
struct wmTimer *smoothscroll_timer;
struct wmTimer *previews_timer;
struct FileLayout *layout;
@ -709,7 +713,10 @@ typedef enum eFileSel_Params_Flag {
} eFileSel_Params_Flag;
/* files in filesel list: file types */
/* files in filesel list: file types
* Note we could use mere values (instead of bitflags) for file types themselves,
* but since we do not lack of bytes currently...
*/
typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDER = (1 << 2),
FILE_TYPE_BLENDER_BACKUP = (1 << 3),
@ -725,6 +732,9 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_COLLADA = (1 << 13),
FILE_TYPE_OPERATOR = (1 << 14), /* from filter_glob operator property */
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_BLENDERLIB = (1 << 31),
} eFileSel_File_Types;
/* Selection Flags in filesel: struct direntry, unsigned char selflag */
@ -735,6 +745,117 @@ typedef enum eDirEntry_SelectFlag {
FILE_SEL_EDITING = (1 << 4),
} eDirEntry_SelectFlag;
#define FILE_LIST_MAX_RECURSION 4
/* ***** Related to file browser, but never saved in DNA, only here to help with RNA. ***** */
/* About Unique identifier.
* Stored in a CustomProps once imported.
* Each engine is free to use it as it likes - it will be the only thing passed to it by blender to identify
* asset/variant/version (concatenating the three into a single 48 bytes one).
* Assumed to be 128bits, handled as four integers due to lack of real bytes proptype in RNA :|.
*/
#define ASSET_UUID_LENGTH 16
/* Used to communicate with asset engines outside of 'import' context. */
typedef struct AssetUUID {
int uuid_asset[4];
int uuid_variant[4];
int uuid_revision[4];
} AssetUUID;
typedef struct AssetUUIDList {
AssetUUID *uuids;
int nbr_uuids, pad;
} AssetUUIDList;
/* Container for a revision, only relevant in asset context. */
typedef struct FileDirEntryRevision {
struct FileDirEntryRevision *next, *prev;
int uuid[4];
char *comment;
uint64_t size;
int64_t time;
/* Temp caching of UI-generated strings... */
char size_str[16];
char time_str[8];
char date_str[16];
} FileDirEntryRevision;
/* Container for a variant, only relevant in asset context.
* In case there are no variants, a single one shall exist, with NULL name/description. */
typedef struct FileDirEntryVariant {
struct FileDirEntryVariant *next, *prev;
int uuid[4];
char *name;
char *description;
ListBase revisions;
int nbr_revisions;
int act_revision;
} FileDirEntryVariant;
/* Container for mere direntry, with additional asset-related data. */
typedef struct FileDirEntry {
struct FileDirEntry *next, *prev;
int uuid[4];
char *name;
char *description;
/* Either point to active variant/revision if available, or own entry (in mere filebrowser case). */
FileDirEntryRevision *entry;
int typeflag; /* eFileSel_File_Types */
int blentype; /* ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */
char *relpath;
void *poin; /* TODO: make this a real ID pointer? */
struct ImBuf *image;
/* Tags are for info only, most of filtering is done in asset engine. */
char **tags;
int nbr_tags;
short status;
short flags;
ListBase variants;
int nbr_variants;
int act_variant;
} FileDirEntry;
/* Array of direntries. */
/* This struct is used in various, different contexts.
* In Filebrowser UI, it stores the total number of available entries, the number of visible (filtered) entries,
* and a subset of those in 'entries' ListBase, from idx_start (included) to idx_end (excluded).
* In AssetEngine context (i.e. outside of 'browsing' context), entries contain all needed data, there is no filtering,
* so nbr_entries_filtered, entry_idx_start and entry_idx_end should all be set to -1.
*/
typedef struct FileDirEntryArr {
ListBase entries;
int nbr_entries;
int nbr_entries_filtered;
int entry_idx_start, entry_idx_end;
char root[1024]; /* FILE_MAX */
} FileDirEntryArr;
/* FileDirEntry.status */
enum {
ASSET_STATUS_LOCAL = 1 << 0, /* If active uuid is available localy/immediately. */
ASSET_STATUS_LATEST = 1 << 1, /* If active uuid is latest available version. */
};
/* FileDirEntry.flags */
enum {
FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */
};
/* Image/UV Editor ======================================== */
/* Image/UV Editor */

View File

@ -219,6 +219,16 @@ static EnumPropertyItem buttons_texture_context_items[] = {
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem fileselectparams_recursion_level_items[] = {
{0, "NONE", 0, "None", "Only list current directory's content, with no recursion"},
{1, "BLEND", 0, "Blend File", "List .blend files' content"},
{2, "ALL_1", 0, "One Level", "List all sub-directories' content, one level of recursion"},
{3, "ALL_2", 0, "Two Levels", "List all sub-directories' content, two levels of recursion"},
{4, "ALL_3", 0, "Three Levels", "List all sub-directories' content, three levels of recursion"},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@ -1522,6 +1532,37 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain), Scene *UNU
/* File browser. */
static int rna_FileSelectParams_use_lib_get(PointerRNA *ptr)
{
FileSelectParams *params = ptr->data;
return params && (params->type == FILE_LOADLIB);
}
static EnumPropertyItem *rna_FileSelectParams_recursion_level_itemf(
bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
FileSelectParams *params = ptr->data;
if (params && params->type != FILE_LOADLIB) {
EnumPropertyItem *item = NULL;
int totitem = 0;
RNA_enum_items_add_value(&item, &totitem, fileselectparams_recursion_level_items, 0);
RNA_enum_items_add_value(&item, &totitem, fileselectparams_recursion_level_items, 2);
RNA_enum_items_add_value(&item, &totitem, fileselectparams_recursion_level_items, 3);
RNA_enum_items_add_value(&item, &totitem, fileselectparams_recursion_level_items, 4);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
*r_free = false;
return fileselectparams_recursion_level_items;
}
static void rna_FileBrowser_FSMenuEntry_path_get(PointerRNA *ptr, char *value)
{
char *path = ED_fsmenu_entry_get_path(ptr->data);
@ -3710,6 +3751,58 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem file_filter_idtypes_items[] = {
{FILTER_ID_AC, "ACTION", ICON_ANIM_DATA, "Actions", "Show/hide Action datablocks"},
{FILTER_ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armatures", "Show/hide Armature datablocks"},
{FILTER_ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brushes", "Show/hide Brushes datablocks"},
{FILTER_ID_CA, "CAMERA", ICON_CAMERA_DATA, "Cameras", "Show/hide Camera datablocks"},
{FILTER_ID_CU, "CURVE", ICON_CURVE_DATA, "Curves", "Show/hide Curve datablocks"},
{FILTER_ID_GD, "GREASE_PENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Show/hide Grease pencil datablocks"},
{FILTER_ID_GR, "GROUP", ICON_GROUP, "Groups", "Show/hide Group datablocks"},
{FILTER_ID_IM, "IMAGE", ICON_IMAGE_DATA, "Images", "Show/hide Image datablocks"},
{FILTER_ID_LA, "LAMP", ICON_LAMP_DATA, "Lamps", "Show/hide Lamp datablocks"},
{FILTER_ID_LS, "LINESTYLE", ICON_LINE_DATA, "Freestyle Linestyles", "Show/hide Freestyle's Line Style datablocks"},
{FILTER_ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattices", "Show/hide Lattice datablocks"},
{FILTER_ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Materials", "Show/hide Material datablocks"},
{FILTER_ID_MB, "METABALL", ICON_META_DATA, "Metaballs", "Show/hide Mateball datablocks"},
{FILTER_ID_MC, "MOVIE_CLIP", ICON_CLIP, "Movie Clips", "Show/hide Movie Clip datablocks"},
{FILTER_ID_ME, "MESH", ICON_MESH_DATA, "Meshes", "Show/hide Mesh datablocks"},
{FILTER_ID_MSK, "MASK", ICON_MOD_MASK, "Masks", "Show/hide Mask datablocks"},
{FILTER_ID_NT, "NODE_TREE", ICON_NODETREE, "Node Trees", "Show/hide Node Tree datablocks"},
{FILTER_ID_OB, "OBJECT", ICON_OBJECT_DATA, "Objects", "Show/hide Object datablocks"},
{FILTER_ID_PAL, "PALETTE", ICON_COLOR, "Palettes", "Show/hide Palette datablocks"},
{FILTER_ID_PC, "PAINT_CURVE", ICON_CURVE_BEZCURVE, "Paint Curves", "Show/hide Paint Curve datablocks"},
{FILTER_ID_SCE, "SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide Scene datablocks"},
{FILTER_ID_SPK, "SPEAKER", ICON_SPEAKER, "Speakers", "Show/hide Speaker datablocks"},
{FILTER_ID_SO, "SOUND", ICON_SOUND, "Sounds", "Show/hide Sound datablocks"},
{FILTER_ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Textures", "Show/hide Texture datablocks"},
{FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text datablocks"},
{FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font datablocks"},
{FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World datablocks"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem file_filter_idcategories_items[] = {
{FILTER_ID_SCE,
"SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide scenes"},
{FILTER_ID_AC,
"ANIMATION", ICON_ANIM_DATA, "Animations", "Show/hide animation data"},
{FILTER_ID_OB | FILTER_ID_GR,
"OBJECT", ICON_GROUP, "Objects & Groups", "Show/hide objects and groups"},
{FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME,
"GEOMETRY", ICON_MESH_DATA, "Geometry", "Show/hide meshes, curves, lattice, armatures and metaballs data"},
{FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
"SHADING", ICON_MATERIAL_DATA, "Shading",
"Show/hide materials, nodetrees, textures and Freestyle's linestyles"},
{FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
"IMAGE", ICON_IMAGE_DATA, "Images & Sounds", "Show/hide images, movie clips, sounds and masks"},
{FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO,
"ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lamps, cameras and speakers"},
{FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | FILTER_ID_VF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "FileSelectParams", NULL);
RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters");
@ -3728,12 +3821,23 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "File Name", "Active file in the file browser");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "use_library_browsing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Library Browser", "Whether we may browse blender files' content or not");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_FileSelectParams_use_lib_get", NULL);
prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "display");
RNA_def_property_enum_items(prop, file_display_items);
RNA_def_property_ui_text(prop, "Display Mode", "Display mode for the file list");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "recursion_level", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, fileselectparams_recursion_level_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FileSelectParams_recursion_level_itemf");
RNA_def_property_ui_text(prop, "Recursion", "Numbers of dirtree levels to show simultaneously");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_FILTER);
RNA_def_property_ui_text(prop, "Filter Files", "Enable filtering of files");
@ -3803,7 +3907,27 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Filter Folder", "Show folders");
RNA_def_property_ui_icon(prop, ICON_FILE_FOLDER, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "use_filter_blendid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDERLIB);
RNA_def_property_ui_text(prop, "Filter Blender IDs", "Show .blend files items (objects, materials, etc.)");
RNA_def_property_ui_icon(prop, ICON_BLENDER, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_id", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "filter_id");
RNA_def_property_enum_items(prop, file_filter_idtypes_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Filter ID types", "Which ID types to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_id_category", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "filter_id");
RNA_def_property_enum_items(prop, file_filter_idcategories_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Filter ID categories", "Which ID categories to show/hide, when browsing a library");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
prop = RNA_def_property(srna, "filter_glob", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "filter_glob");
RNA_def_property_ui_text(prop, "Extension Filter", "");

View File

@ -417,7 +417,7 @@ enum {
WM_JOB_TYPE_OBJECT_SIM_FLUID,
WM_JOB_TYPE_OBJECT_BAKE_TEXTURE,
WM_JOB_TYPE_OBJECT_BAKE,
WM_JOB_TYPE_FILESEL_THUMBNAIL,
WM_JOB_TYPE_FILESEL_READDIR,
WM_JOB_TYPE_CLIP_BUILD_PROXY,
WM_JOB_TYPE_CLIP_TRACK_MARKERS,
WM_JOB_TYPE_CLIP_SOLVE_CAMERA,

View File

@ -361,6 +361,7 @@ typedef struct wmNotifier {
#define ND_SPACE_NODE_VIEW (17<<16)
#define ND_SPACE_CHANGED (18<<16) /*sent to a new editor type after it's replaced an old one*/
#define ND_SPACE_CLIP (19<<16)
#define ND_SPACE_FILE_PREVIEW (20<<16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00

View File

@ -1262,6 +1262,8 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL,
"File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
@ -2594,86 +2596,34 @@ static short wm_link_append_flag(wmOperator *op)
return flag;
}
static int wm_link_append_exec(bContext *C, wmOperator *op)
/* Helper.
* if `name` is non-NULL, we assume a single-item link/append.
* else if `*todo_libraries` is NULL we assume first-run.
*/
static void wm_link_append_do_libgroup(
bContext *C, wmOperator *op, const char *root, const char *libname, char *group, char *name,
const short flag, GSet **todo_libraries)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Main *mainl = NULL;
Main *mainl;
BlendHandle *bh;
Library *lib;
PropertyRNA *prop;
char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX];
char *group;
int idcode, totfiles = 0;
short flag;
RNA_string_get(op->ptr, "filename", name);
RNA_string_get(op->ptr, "directory", dir);
char path[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
int idcode;
const bool is_first_run = (*todo_libraries == NULL);
/* test if we have a valid data */
if (BLO_library_path_explode(dir, libname, &group, NULL) == 0) {
BKE_report(op->reports, RPT_ERROR, "Not a library");
return OPERATOR_CANCELLED;
}
else if ((group == NULL) || (group[0] == '\0')) {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
else if (BLI_path_cmp(bmain->name, libname) == 0) {
BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
return OPERATOR_CANCELLED;
}
/* check if something is indicated for append/link */
prop = RNA_struct_find_property(op->ptr, "files");
if (prop) {
totfiles = RNA_property_collection_length(op->ptr, prop);
if (totfiles == 0) {
if (name[0] == '\0') {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
}
}
else if (name[0] == '\0') {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
BLI_assert(group);
idcode = BKE_idcode_from_name(group);
bh = BLO_blendhandle_from_file(libname, op->reports);
if (bh == NULL) {
/* unlikely since we just browsed it, but possible
* error reports will have been made by BLO_blendhandle_from_file() */
return OPERATOR_CANCELLED;
return;
}
/* from here down, no error returns */
idcode = BKE_idcode_from_name(group);
/* now we have or selected, or an indicated file */
if (RNA_boolean_get(op->ptr, "autoselect"))
BKE_scene_base_deselect_all(scene);
flag = wm_link_append_flag(op);
/* sanity checks for flag */
if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
/* TODO, user never gets this message */
BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2);
flag &= ~FILE_GROUP_INSTANCE;
}
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
*
* take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */
BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1);
/* here appending/linking starts */
mainl = BLO_library_append_begin(bmain, &bh, libname);
lib = mainl->curlib;
@ -2686,19 +2636,47 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
mainl->versionfile, mainl->subversionfile);
}
if (totfiles == 0) {
if (name) {
BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
}
else {
if (is_first_run) {
*todo_libraries = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
}
RNA_BEGIN (op->ptr, itemptr, "files")
{
RNA_string_get(&itemptr, "name", name);
BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
char curr_libname[FILE_MAX];
int curr_idcode;
RNA_string_get(&itemptr, "name", relname);
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, curr_libname, &group, &name)) {
if (!group || !name) {
continue;
}
curr_idcode = BKE_idcode_from_name(group);
if ((idcode == curr_idcode) && (BLI_path_cmp(curr_libname, libname) == 0)) {
BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
}
else if (is_first_run) {
BLI_join_dirfile(path, sizeof(path), curr_libname, group);
if (!BLI_gset_haskey(*todo_libraries, path)) {
BLI_gset_insert(*todo_libraries, BLI_strdup(path));
}
}
}
}
RNA_END;
}
BLO_library_append_end(C, mainl, &bh, idcode, flag);
BLO_blendhandle_close(bh);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
IMB_colormanagement_check_file_config(bmain);
@ -2708,6 +2686,95 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_assert(BLI_findindex(&bmain->library, lib) != -1);
BKE_library_make_local(bmain, lib, true);
}
}
static int wm_link_append_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
short flag;
GSet *todo_libraries = NULL;
RNA_string_get(op->ptr, "filename", relname);
RNA_string_get(op->ptr, "directory", root);
BLI_join_dirfile(path, sizeof(path), root, relname);
/* test if we have a valid data */
if (!BLO_library_path_explode(path, libname, &group, &name)) {
BKE_report(op->reports, RPT_ERROR, "Not a library");
return OPERATOR_CANCELLED;
}
else if (!group) {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
else if (BLI_path_cmp(bmain->name, libname) == 0) {
BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
return OPERATOR_CANCELLED;
}
/* check if something is indicated for append/link */
prop = RNA_struct_find_property(op->ptr, "files");
if (prop) {
totfiles = RNA_property_collection_length(op->ptr, prop);
if (totfiles == 0) {
if (!name) {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
}
}
else if (!name) {
BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
return OPERATOR_CANCELLED;
}
flag = wm_link_append_flag(op);
/* sanity checks for flag */
if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
/* TODO, user never gets this message */
BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2);
flag &= ~FILE_GROUP_INSTANCE;
}
/* from here down, no error returns */
/* now we have or selected, or an indicated file */
if (RNA_boolean_get(op->ptr, "autoselect"))
BKE_scene_base_deselect_all(scene);
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
*
* take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */
BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1);
if (totfiles != 0) {
name = NULL;
}
wm_link_append_do_libgroup(C, op, root, libname, group, name, flag, &todo_libraries);
if (todo_libraries) {
GSetIterator libs_it;
GSET_ITER(libs_it, todo_libraries) {
char *libpath = (char *)BLI_gsetIterator_getKey(&libs_it);
BLO_library_path_explode(libpath, libname, &group, NULL);
wm_link_append_do_libgroup(C, op, root, libname, group, NULL, flag, &todo_libraries);
}
BLI_gset_free(todo_libraries, MEM_freeN);
}
/* important we unset, otherwise these object wont
* link into other scenes from this blend file */
@ -2718,10 +2785,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
GPU_materials_free();
BLO_blendhandle_close(bh);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, dir, FILE_MAX);
BLI_strncpy(G.lib, root, FILE_MAX);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@ -2761,7 +2827,7 @@ static void WM_OT_link(wmOperatorType *ot)
ot->flag |= OPTYPE_UNDO;
WM_operator_properties_filesel(
ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE,
ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY);
@ -2781,7 +2847,7 @@ static void WM_OT_append(wmOperatorType *ot)
ot->flag |= OPTYPE_UNDO;
WM_operator_properties_filesel(
ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE,
ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY);