Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_screen.h8
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c27
-rw-r--r--source/blender/blenloader/intern/versioning_280.c28
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/editors/include/ED_fileselect.h36
-rw-r--r--source/blender/editors/interface/interface_panel.c7
-rw-r--r--source/blender/editors/screen/area.c7
-rw-r--r--source/blender/editors/space_file/file_draw.c533
-rw-r--r--source/blender/editors/space_file/file_intern.h18
-rw-r--r--source/blender/editors/space_file/file_ops.c65
-rw-r--r--source/blender/editors/space_file/filelist.c23
-rw-r--r--source/blender/editors/space_file/filelist.h2
-rw-r--r--source/blender/editors/space_file/filesel.c219
-rw-r--r--source/blender/editors/space_file/space_file.c70
-rw-r--r--source/blender/makesdna/DNA_screen_types.h1
-rw-r--r--source/blender/makesdna/DNA_space_types.h18
-rw-r--r--source/blender/makesrna/intern/rna_space.c54
-rw-r--r--source/blender/makesrna/intern/rna_ui.c25
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c82
-rw-r--r--source/blender/windowmanager/intern/wm_files.c6
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c12
-rw-r--r--source/blender/windowmanager/intern/wm_window.c14
24 files changed, 754 insertions, 508 deletions
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 5d3e7ad5ec2..7d992320033 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -179,6 +179,8 @@ typedef struct ARegionType {
/* header type definitions */
ListBase headertypes;
+ int flag;
+
/* hardcoded constraints, smaller than these values region is not visible */
int minsizex, minsizey;
/* when new region opens (region prefsizex/y are zero then */
@@ -192,6 +194,12 @@ typedef struct ARegionType {
short event_cursor;
} ARegionType;
+/* ARegionType.flag */
+enum {
+ /** Never show category tabs in this region type. */
+ RGN_TYPE_FLAG_NO_CATEGORIES = (1 << 8),
+};
+
/* panel types */
typedef struct PanelType {
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 91f16ca9b7b..c2b51d6bb29 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -261,36 +261,17 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
*/
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
- const bool compact,
+ /* Used to change MB -> M, etc. - is that really useful? */
+ const bool UNUSED(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) {
- /* pass */
- }
- 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);
+ double size = (double)(st ? st->st_size : sz);
+ BLI_str_format_byte_unit(r_size, size, true);
}
/**
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 15b4f513050..0ef566d9e89 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3569,4 +3569,32 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ {
+ /* Versioning code until next subversion bump goes here. */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI);
+ ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+
+ if (ar_ui && ar_header) {
+ /* Reinsert UI region so that it spawns entire area width */
+ BLI_remlink(regionbase, ar_ui);
+ BLI_insertlinkafter(regionbase, ar_header, ar_ui);
+
+ ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ }
+
+ if (sfile->params) {
+ sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index e987a623d0b..cdde8f03fbc 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -145,6 +145,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* Include next version bump.
*/
{
+ copy_v4_v4_char(btheme->space_file.execution_buts, btheme->space_file.button);
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 7273f857a41..57e35a26121 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -34,17 +34,31 @@ struct wmWindowManager;
#define FILE_LAYOUT_HOR 1
#define FILE_LAYOUT_VER 2
-#define MAX_FILE_COLUMN 4
-
typedef enum FileListColumns {
+ COLUMN_NONE = -1,
COLUMN_NAME = 0,
- COLUMN_DATE,
- COLUMN_TIME,
+ COLUMN_DATETIME,
COLUMN_SIZE,
+
+ COLUMN_MAX
} FileListColumns;
+typedef struct FileDetailsColumn {
+ /** UI name for this column */
+ const char *name;
+
+ float width;
+ /* The sort type to use when sorting by this column. */
+ int sort_type; /* eFileSortType */
+
+ /* Alignment of column texts, header text is always left aligned */
+ int text_align; /* eFontStyle_Align */
+} FileDetailsColumn;
+
typedef struct FileLayout {
/* view settings - XXX - move into own struct */
+ int offset_top;
+ int columnheader_h;
int prv_w;
int prv_h;
int tile_w;
@@ -60,7 +74,7 @@ typedef struct FileLayout {
int flag;
int dirty;
int textheight;
- float column_widths[MAX_FILE_COLUMN];
+ FileDetailsColumn details_columns[COLUMN_MAX];
/* When we change display size, we may have to update static strings like size of files... */
short curr_size;
@@ -72,6 +86,7 @@ typedef struct FileSelection {
} FileSelection;
struct rcti;
+struct View2D;
struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
@@ -87,6 +102,17 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *ar);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+void ED_fileselect_layout_maskrect(const FileLayout *layout,
+ const struct View2D *v2d,
+ struct rcti *r_rect);
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout,
+ const struct View2D *v2d,
+ int x,
+ int y);
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const struct View2D *v2d,
+ const struct rcti *rect,
+ struct rcti *r_dst);
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 8adb82a22c8..1115a791692 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -245,6 +245,10 @@ static void panels_collapse_all(ScrArea *sa, ARegion *ar, const Panel *from_pa)
for (pa = ar->panels.first; pa; pa = pa->next) {
PanelType *pt = pa->type;
+ if (pt->flag & PNL_HIDDEN) {
+ continue;
+ }
+
/* close panels with headers in the same context */
if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) {
if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) {
@@ -1977,6 +1981,9 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
interp_v3_v3v3_uchar(
theme_col_tab_highlight_inactive, theme_col_tab_inactive, theme_col_text_hi, 0.12f);
+ /* Should be handled on registration (don't register category if not supported in region). */
+ BLI_assert((ar->type->flag & RGN_TYPE_FLAG_NO_CATEGORIES) == 0);
+
is_alpha = (ar->overlap && (theme_col_back[3] != 255));
if (fstyle->kerning == 1) {
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 5099c370a85..e30a21d3c6c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1275,9 +1275,6 @@ static void region_rect_recursive(
else if (ED_area_is_global(sa)) {
prefsizey = ED_region_global_size_y();
}
- else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) {
- prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2);
- }
else {
prefsizey = UI_DPI_FAC * (ar->sizey > 1 ? ar->sizey + 0.5f : ar->type->prefsizey);
}
@@ -2426,6 +2423,10 @@ void ED_region_panels_layout_ex(const bContext *C,
PanelType *pt = pt_link->link;
Panel *panel = UI_panel_find_by_type(&ar->panels, pt);
+ if (pt->flag & PNL_HIDDEN) {
+ continue;
+ }
+
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
continue;
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3a6d59c1dbf..1daffc3cdc8 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -77,234 +77,6 @@ static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char
return BLI_strdup(dyn_tooltip);
}
-/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d.
- * The controls are laid out as follows:
- *
- * -------------------------------------------
- * | Directory input | execute |
- * -------------------------------------------
- * | Filename input | + | - | cancel |
- * -------------------------------------------
- *
- * The input widgets will stretch to fill any excess space.
- * When there isn't enough space for all controls to be shown, they are
- * hidden in this order: x/-, execute/cancel, input widgets.
- */
-void file_draw_buttons(const bContext *C, ARegion *ar)
-{
- /* Button layout. */
- const int max_x = ar->winx - 10;
- const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN);
- const int input_minw = 20;
- const int btn_h = UI_UNIT_Y;
- const int btn_fn_w = UI_UNIT_X;
- const int btn_minw = 80;
- const int btn_margin = 20;
- const int separator = 4;
-
- /* Additional locals. */
- char uiblockstr[32];
- int loadbutton;
- int fnumbuttons;
- int min_x = 10;
- int chan_offs = 0;
- int available_w = max_x - min_x;
- int line1_w = available_w;
- int line2_w = available_w;
-
- uiBut *but;
- uiBlock *block;
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_params(sfile);
- ARegion *artmp;
- const bool is_browse_only = (sfile->op == NULL);
-
- /* Initialize UI block. */
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar);
- block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
-
- /* exception to make space for collapsed region icon */
- for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) {
- if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) {
- chan_offs = 16;
- min_x += chan_offs;
- available_w -= chan_offs;
- }
- }
-
- /* Is there enough space for the execute / cancel buttons? */
-
- if (is_browse_only) {
- loadbutton = 0;
- }
- else {
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin;
- CLAMP_MIN(loadbutton, btn_minw);
- if (available_w <= loadbutton + separator + input_minw) {
- loadbutton = 0;
- }
- }
-
- if (loadbutton) {
- line1_w -= (loadbutton + separator);
- line2_w = line1_w;
- }
-
- /* Is there enough space for file number increment/decrement buttons? */
- fnumbuttons = 2 * btn_fn_w;
- if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) {
- fnumbuttons = 0;
- }
- else {
- line2_w -= (fnumbuttons + separator);
- }
-
- /* Text input fields for directory and file. */
- if (available_w > 0) {
- 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->typeflag & FILE_TYPE_FOLDER);
-
- /* callbacks for operator check functions */
- UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
-
- but = uiDefBut(block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line1_y,
- line1_w - chan_offs,
- btn_h,
- params->dir,
- 0.0,
- (float)FILE_MAX,
- 0,
- 0,
- TIP_("File path"));
- UI_but_func_complete_set(but, autocomplete_directory, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- UI_but_funcN_set(but, file_directory_enter_handle, NULL, but);
-
- /* TODO, directory editing is non-functional while a library is loaded
- * until this is properly supported just disable it. */
- if (sfile->files && filelist_lib(sfile->files)) {
- UI_but_flag_enable(but, UI_BUT_DISABLED);
- }
-
- if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
- but = uiDefBut(
- block,
- UI_BTYPE_TEXT,
- -1,
- "",
- min_x,
- line2_y,
- line2_w - chan_offs,
- btn_h,
- is_active_dir ? (char *)"" : params->file,
- 0.0,
- (float)FILE_MAXFILE,
- 0,
- 0,
- TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
- UI_but_func_complete_set(but, autocomplete_file, NULL);
- UI_but_flag_enable(but, UI_BUT_NO_UTF8);
- UI_but_flag_disable(but, UI_BUT_UNDO);
- /* silly workaround calling NFunc to ensure this does not get called
- * immediate ui_apply_but_func but only after button deactivates */
- UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
-
- /* check if this overrides a file and if the operator option is used */
- if (overwrite_alert) {
- UI_but_flag_enable(but, UI_BUT_REDALERT);
- }
- }
-
- /* clear func */
- UI_block_func_set(block, NULL, NULL, NULL);
- }
-
- /* Filename number increment / decrement buttons. */
- if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) {
- UI_block_align_begin(block);
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_REMOVE,
- min_x + line2_w + separator - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Decrement the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1);
-
- but = uiDefIconButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_filenum",
- 0,
- ICON_ADD,
- min_x + line2_w + separator + btn_fn_w - chan_offs,
- line2_y,
- btn_fn_w,
- btn_h,
- TIP_("Increment the filename number"));
- RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1);
- UI_block_align_end(block);
- }
-
- /* Execute / cancel buttons. */
- if (loadbutton) {
- const struct FileDirEntry *file = sfile->files ?
- filelist_file(sfile->files, params->active_file) :
- NULL;
- char const *str_exec;
-
- if (file && FILENAME_IS_PARENT(file->relpath)) {
- str_exec = IFACE_("Parent Directory");
- }
- else if (file && file->typeflag & FILE_TYPE_DIR) {
- str_exec = IFACE_("Open Directory");
- }
- else {
- str_exec = params->title; /* params->title is already translated! */
- }
-
- but = uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_execute",
- WM_OP_EXEC_REGION_WIN,
- str_exec,
- max_x - loadbutton,
- line1_y,
- loadbutton,
- btn_h,
- "");
- /* Just a display hint. */
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
-
- uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_cancel",
- WM_OP_EXEC_REGION_WIN,
- IFACE_("Cancel"),
- max_x - loadbutton,
- line2_y,
- loadbutton,
- btn_h,
- "");
- }
-
- UI_block_end(C, block);
- UI_block_draw(C, block);
-}
-
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
{
float color[4];
@@ -349,7 +121,7 @@ static void file_draw_string(int sx,
rcti rect;
char fname[FILE_MAXFILE];
- if (string[0] == '\0') {
+ if (string[0] == '\0' || width < 1) {
return;
}
@@ -362,7 +134,7 @@ static void file_draw_string(int sx,
/* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict
* (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
+ rect.xmax = sx + round_fl_to_int(width);
rect.ymin = sy - height;
rect.ymax = sy;
@@ -557,6 +329,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
static void draw_background(FileLayout *layout, View2D *v2d)
{
+ const int item_height = layout->tile_h + (2 * layout->tile_border_y);
int i;
int sy;
@@ -565,9 +338,11 @@ static void draw_background(FileLayout *layout, View2D *v2d)
immUniformThemeColorShade(TH_BACK, -7);
/* alternating flat shade background */
- for (i = 0; (i <= layout->rows); i += 2) {
- sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) -
- layout->tile_border_y;
+ for (i = 2; (i <= layout->rows + 1); i += 2) {
+ sy = (int)v2d->cur.ymax - layout->offset_top - i * item_height - layout->tile_border_y;
+
+ /* Offsett pattern slightly to add scroll effect. */
+ sy += round_fl_to_int(item_height * (v2d->tot.ymax - v2d->cur.ymax) / item_height);
immRectf(pos,
v2d->cur.xmin,
@@ -632,6 +407,159 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
}
}
+static void draw_columnheader_background(const FileLayout *layout, const View2D *v2d)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, 7);
+
+ immRectf(
+ pos, v2d->cur.xmin, v2d->cur.ymax - layout->columnheader_h, v2d->cur.xmax, v2d->cur.ymax);
+
+ immUnbindProgram();
+}
+
+static void draw_columnheader_columns(const FileSelectParams *params,
+ FileLayout *layout,
+ const View2D *v2d,
+ const uchar text_col[4])
+{
+ const float divider_pad = 0.2 * layout->columnheader_h;
+ int sx = v2d->cur.xmin, sy = v2d->cur.ymax;
+
+ for (FileListColumns column_type = 0; column_type < COLUMN_MAX; column_type++) {
+ if (!file_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ const FileDetailsColumn *column = &layout->details_columns[column_type];
+
+ /* Active sort type triangle */
+ if (params->sort == column->sort_type) {
+ float tri_color[4];
+
+ rgba_uchar_to_float(tri_color, text_col);
+ UI_draw_icon_tri(sx + column->width - (0.3f * U.widget_unit) - DETAILS_COLUMN_PADDING / 2.0f,
+ sy + (0.1f * U.widget_unit) - (layout->columnheader_h / 2),
+ (params->flag & FILE_SORT_INVERT) ? 't' : 'v',
+ tri_color);
+ }
+
+ file_draw_string(sx + DETAILS_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ column->name,
+ column->width - 2 * DETAILS_COLUMN_PADDING,
+ layout->columnheader_h - layout->tile_border_y,
+ UI_STYLE_TEXT_LEFT,
+ text_col);
+
+ /* Separator line */
+ if (column_type != COLUMN_NAME) {
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, sx - 1, sy - divider_pad);
+ immVertex2f(pos, sx - 1, sy - layout->columnheader_h + divider_pad);
+ immEnd();
+ immUnbindProgram();
+ }
+
+ sx += column->width;
+ }
+
+ /* Vertical separator lines line */
+ {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -10);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, v2d->cur.xmin, sy);
+ immVertex2f(pos, v2d->cur.xmax, sy);
+ immVertex2f(pos, v2d->cur.xmin, sy - layout->columnheader_h);
+ immVertex2f(pos, v2d->cur.xmax, sy - layout->columnheader_h);
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/**
+ * Updates the stat string stored in file->entry if necessary.
+ */
+static const char *filelist_get_details_column_string(FileListColumns column,
+ const FileDirEntry *file,
+ const bool small_size,
+ const bool update_stat_strings)
+{
+ switch (column) {
+ case COLUMN_DATETIME:
+ if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if ((file->entry->datetime_str[0] == '\0') || update_stat_strings) {
+ char date[16], time[8];
+ BLI_filelist_entry_datetime_to_string(NULL, file->entry->time, small_size, time, date);
+ BLI_snprintf(
+ file->entry->datetime_str, sizeof(file->entry->datetime_str), "%s %s", date, time);
+ }
+
+ return file->entry->datetime_str;
+ }
+ break;
+ case COLUMN_SIZE:
+ if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
+ !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
+ 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);
+ }
+
+ return file->entry->size_str;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static void draw_details_columns(const FileSelectParams *params,
+ const FileLayout *layout,
+ const FileDirEntry *file,
+ const int pos_x,
+ const int pos_y,
+ const uchar text_col[4])
+{
+ const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
+ int sx = pos_x - layout->tile_border_x - (UI_UNIT_X * 0.1f), sy = pos_y;
+
+ for (FileListColumns column_type = 0; column_type < COLUMN_MAX; column_type++) {
+ const FileDetailsColumn *column = &layout->details_columns[column_type];
+
+ /* Name column is not a detail column (should already be drawn), always skip here. */
+ if ((column_type == COLUMN_NAME) || !file_column_type_enabled(params, column_type)) {
+ sx += column->width;
+ continue;
+ }
+ const char *str = filelist_get_details_column_string(
+ column_type, file, small_size, update_stat_strings);
+
+ if (str) {
+ file_draw_string(sx + DETAILS_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ str,
+ column->width - 2 * DETAILS_COLUMN_PADDING,
+ layout->tile_h,
+ column->text_align,
+ text_col);
+ }
+
+ sx += column->width;
+ }
+}
+
void file_draw_list(const bContext *C, ARegion *ar)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -652,18 +580,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
bool is_icon;
eFontStyle_Align align;
bool do_drag;
- int column_space = 0.6f * UI_UNIT_X;
unsigned char text_col[4];
- const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
- const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
+ const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
-
draw_background(layout, v2d);
-
draw_dividers(layout, v2d);
}
@@ -684,8 +608,9 @@ void file_draw_list(const bContext *C, ARegion *ar)
filelist_file_cache_slidingwindow_set(files, numfiles_layout);
- textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w :
- (int)layout->column_widths[COLUMN_NAME];
+ textwidth = (FILE_IMGDISPLAY == params->display) ?
+ layout->tile_w :
+ round_fl_to_int(layout->details_columns[COLUMN_NAME].width);
textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5);
align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT;
@@ -719,11 +644,16 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLF_batch_draw_begin();
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
+
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
unsigned int file_selflag;
char path[FILE_MAX_LIBEXTRA];
+ int padx = 0.1f * UI_UNIT_X;
+ int icon_ofs = 0;
+
ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
- sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X);
+ sx += (int)(v2d->tot.xmin + padx);
sy = (int)(v2d->tot.ymax - sy);
file = filelist_file(files, i);
@@ -737,15 +667,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK;
int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 :
0;
+ const short width = ELEM(params->display, FILE_VERTICALDISPLAY, FILE_HORIZONTALDISPLAY) ?
+ layout->tile_w - (2 * padx) :
+ layout->tile_w;
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);
+ draw_tile(
+ sx, sy - 1, width, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
}
}
UI_draw_roundbox_corner_set(UI_CNR_NONE);
@@ -778,38 +707,27 @@ void file_draw_list(const bContext *C, ARegion *ar)
file_draw_icon(block,
path,
sx,
- sy - (UI_UNIT_Y / 6),
+ sy - layout->tile_border_y,
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;
+ icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
- UI_GetThemeColor4ubv(TH_TEXT, text_col);
-
if (file_selflag & FILE_SEL_EDITING) {
uiBut *but;
- short width;
-
- if (params->display == FILE_SHORTDISPLAY) {
- 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] + (column_space * 3.5f);
- }
- else {
- BLI_assert(params->display == FILE_IMGDISPLAY);
- width = textwidth;
- }
+ const short width = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ layout->details_columns[COLUMN_NAME].width - DETAILS_COLUMN_PADDING;
but = uiDefBut(block,
UI_BTYPE_TEXT,
1,
"",
- sx,
+ sx + icon_ofs,
sy - layout->tile_h - 0.15f * UI_UNIT_X,
- width,
+ width - icon_ofs,
textheight,
sfile->params->renamefile,
1.0f,
@@ -825,74 +743,21 @@ void file_draw_list(const bContext *C, ARegion *ar)
sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
}
}
-
- 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->name, (float)textwidth, textheight, align, text_col);
- }
-
- sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
- if (params->display == FILE_SHORTDISPLAY) {
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- 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,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ else {
+ const int tpos = (FILE_IMGDISPLAY == params->display) ?
+ sy - layout->tile_h + layout->textheight :
+ sy - layout->tile_border_y;
+ file_draw_string(sx + 1 + icon_ofs,
+ tpos,
+ file->name,
+ (float)textwidth - 1 - icon_ofs - padx - layout->tile_border_x,
+ textheight,
+ align,
+ text_col);
}
- else if (params->display == FILE_LONGDISPLAY) {
- if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) {
- 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,
- text_col);
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- file_draw_string(sx,
- sy,
- file->entry->time_str,
- layout->column_widths[COLUMN_TIME],
- layout->tile_h,
- align,
- text_col);
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- else {
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- }
- if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) ||
- !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) {
- 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,
- text_col);
- }
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if (params->display != FILE_IMGDISPLAY) {
+ draw_details_columns(params, layout, file, sx, sy, text_col);
}
}
@@ -901,5 +766,11 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
+ /* Draw last, on top of file list. */
+ if (draw_columnheader) {
+ draw_columnheader_background(layout, v2d);
+ draw_columnheader_columns(params, layout, v2d, text_col);
+ }
+
layout->curr_size = params->thumbnail_size;
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index bad25511dd5..4d5b7bc79d4 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -30,6 +30,7 @@ struct ARegion;
struct ARegionType;
struct FileSelectParams;
struct SpaceFile;
+struct View2D;
/* file_ops.c */
struct ARegion *file_tools_region(struct ScrArea *sa);
@@ -42,9 +43,14 @@ 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 DETAILS_COLUMN_PADDING (0.5f * UI_UNIT_X)
+
#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
-void file_draw_buttons(const bContext *C, ARegion *ar);
+#if 0
+void file_draw_filepath_buttons(const bContext *C, ARegion *ar);
+void file_draw_execute_buttons(const bContext *C, ARegion *ar);
+#endif
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);
@@ -64,6 +70,7 @@ typedef enum WalkSelectDirection {
} WalkSelectDirections;
void FILE_OT_highlight(struct wmOperatorType *ot);
+void FILE_OT_sort_column_ui_context(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
void FILE_OT_select_walk(struct wmOperatorType *ot);
void FILE_OT_select_all(struct wmOperatorType *ot);
@@ -112,6 +119,15 @@ void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOpera
/* filesel.c */
void fileselect_file_set(SpaceFile *sfile, const int index);
+bool file_column_type_enabled(const FileSelectParams *params, FileListColumns column);
+bool file_column_header_is_inside(const struct View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y);
+FileListColumns file_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x);
float file_string_width(const char *str);
float file_font_pointsize(void);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index eb5f02b6e13..d1006cd8e35 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -78,7 +78,12 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const r
BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
+ /* Okay, manipulating v2d rects here is hacky... */
+ v2d->mask.ymax -= sfile->layout->offset_top;
+ v2d->cur.ymax -= sfile->layout->offset_top;
UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
+ v2d->mask.ymax += sfile->layout->offset_top;
+ v2d->cur.ymax += sfile->layout->offset_top;
BLI_rcti_init(&rect_view,
(int)(v2d->tot.xmin + rect_view_fl.xmin),
@@ -262,8 +267,8 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
cur->ymax = cur->ymin + ar->winy;
}
/* up */
- else if (cur->ymax < rect.ymax) {
- cur->ymax = rect.ymax + layout->tile_border_y;
+ else if ((cur->ymax - layout->offset_top) < rect.ymax) {
+ cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
cur->ymin = cur->ymax - ar->winy;
}
/* left - also use if tile is wider than viewbounds so view is aligned to file name */
@@ -278,7 +283,7 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i
}
else {
BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
- cur->ymax >= rect.ymax);
+ (cur->ymax - layout->offset_top) >= rect.ymax);
changed = false;
}
@@ -384,7 +389,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve
if (result == OPERATOR_RUNNING_MODAL) {
WM_operator_properties_border_to_rcti(op, &rect);
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
sel = file_selection_get(C, &rect, 0);
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
@@ -440,7 +445,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op)
file_deselect_all(sfile, FILE_SEL_SELECTED);
}
- BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
+ ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect);
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
@@ -493,7 +498,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.xmin = rect.xmax = event->mval[0];
rect.ymin = rect.ymax = event->mval[1];
- if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) {
+ if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &ar->v2d, rect.xmin, rect.ymin)) {
return OPERATOR_CANCELLED;
}
@@ -1185,7 +1190,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
mx -= ar->winrct.xmin;
my -= ar->winrct.ymin;
- if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) {
+ if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
float fx, fy;
int highlight_file;
@@ -1234,6 +1239,52 @@ void FILE_OT_highlight(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active;
}
+static int file_column_sort_ui_context_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ const ARegion *ar = CTX_wm_region(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ if (file_column_header_is_inside(&ar->v2d, sfile->layout, event->mval[0], event->mval[1])) {
+ const FileListColumns column_type = file_column_type_find_isect(
+ &ar->v2d, sfile->params, sfile->layout, event->mval[0]);
+
+ if (column_type != COLUMN_NONE) {
+ const FileDetailsColumn *column = &sfile->layout->details_columns[column_type];
+
+ if (column->sort_type != FILE_SORT_NONE) {
+ if (sfile->params->sort == column->sort_type) {
+ /* Already sorting by selected column -> toggle sort invert (three state logic). */
+ sfile->params->flag ^= FILE_SORT_INVERT;
+ }
+ else {
+ sfile->params->sort = column->sort_type;
+ sfile->params->flag &= ~FILE_SORT_INVERT;
+ }
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ }
+ }
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sort from Column";
+ ot->description = "Change sorting to use column under cursor";
+ ot->idname = "FILE_OT_sort_column_ui_context";
+
+ /* api callbacks */
+ ot->invoke = file_column_sort_ui_context_invoke;
+ ot->poll = ED_operator_file_active;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index f7dda1defe8..0445614e486 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -329,6 +329,7 @@ enum {
FL_IS_PENDING = 1 << 2,
FL_NEED_SORTING = 1 << 3,
FL_NEED_FILTERING = 1 << 4,
+ FL_SORT_INVERT = 1 << 5,
};
#define SPECIAL_IMG_SIZE 48
@@ -571,16 +572,34 @@ void filelist_sort(struct FileList *filelist)
break;
}
+ /* We could avoid this extra reversal by letting callbacks check for inverted sorting. Would
+ * make return values a bit cryptic though, and it's not like reversal is that expensive. */
+ if (filelist->flags & FL_SORT_INVERT) {
+ FileListInternEntry *current_entry = BLI_pophead(&filelist->filelist_intern.entries);
+ FileListInternEntry *parent_entry = BLI_pophead(&filelist->filelist_intern.entries);
+
+ BLI_listbase_reverse(&filelist->filelist_intern.entries);
+ /* Reinsert '..' item at the top */
+ BLI_assert(FILENAME_IS_CURRENT(current_entry->relpath));
+ BLI_assert(FILENAME_IS_PARENT(parent_entry->relpath));
+ BLI_addhead(&filelist->filelist_intern.entries, parent_entry);
+ BLI_addhead(&filelist->filelist_intern.entries, current_entry);
+ }
+
filelist_filter_clear(filelist);
filelist->flags &= ~FL_NEED_SORTING;
}
}
-void filelist_setsorting(struct FileList *filelist, const short sort)
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
{
- if (filelist->sort != sort) {
+ const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
+
+ if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
filelist->sort = sort;
filelist->flags |= FL_NEED_SORTING;
+ filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
+ (filelist->flags & ~FL_SORT_INVERT);
}
}
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index caf77246797..9af0b7d623f 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -55,7 +55,7 @@ void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
const char *folderlist_peeklastdir(struct ListBase *folderdist);
int folderlist_clear_next(struct SpaceFile *sfile);
-void filelist_setsorting(struct FileList *filelist, const short sort);
+void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index db42d007b8e..13bc8bb3dfb 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -69,6 +69,8 @@
#include "file_intern.h"
#include "filelist.h"
+#define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X)
+
FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile)
{
if (!sfile->params) {
@@ -99,6 +101,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sfile->params->filter_glob[0] = '\0';
/* set the default thumbnails size */
sfile->params->thumbnail_size = 128;
+ /* Show size column by default. */
+ sfile->params->details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
}
params = sfile->params;
@@ -268,11 +272,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->display = FILE_IMGDISPLAY;
}
else {
- params->display = FILE_SHORTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
}
}
else {
- params->display = FILE_SHORTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
}
}
else {
@@ -293,7 +297,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->type = FILE_UNIX;
params->flag |= FILE_HIDE_DOT;
params->flag &= ~FILE_DIRSEL_ONLY;
- params->display = FILE_SHORTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
params->display_previous = FILE_DEFAULTDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
@@ -372,7 +376,7 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
}
else {
const int y_item = layout->tile_h + (2 * layout->tile_border_y);
- const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur));
+ const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)) - layout->offset_top;
const int y_over = y_item - (y_view % y_item);
numfiles = (int)((float)(y_view + y_over) / (float)(y_item));
return numfiles * layout->columns;
@@ -395,9 +399,9 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
}
colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmin = (rect->ymin - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x);
- rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y);
+ rowmax = (rect->ymax - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
if (is_inside(colmin, rowmin, layout->columns, layout->rows) ||
is_inside(colmax, rowmax, layout->columns, layout->rows)) {
@@ -443,7 +447,7 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
}
offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x);
- offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y);
+ offsety = (y - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y);
if (offsetx > layout->columns - 1) {
return -1;
@@ -461,22 +465,114 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
return active_file;
}
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
+void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
+{
+ *r_rect = v2d->mask;
+ r_rect->ymax -= layout->offset_top;
+}
+
+bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect_pt(&maskrect, x, y);
+}
+
+bool ED_fileselect_layout_isect_rect(const FileLayout *layout,
+ const View2D *v2d,
+ const rcti *rect,
+ rcti *r_dst)
+{
+ rcti maskrect;
+ ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
+ return BLI_rcti_isect(&maskrect, rect, r_dst);
+}
+
void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
{
if (layout->flag == FILE_LAYOUT_HOR) {
*x = layout->tile_border_x +
(tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
+ *y = layout->offset_top + layout->tile_border_y +
(tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y);
}
else {
*x = layout->tile_border_x +
((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x);
- *y = layout->tile_border_y +
+ *y = layout->offset_top + layout->tile_border_y +
((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y);
}
}
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
+bool file_column_header_is_inside(const View2D *v2d, const FileLayout *layout, int x, int y)
+{
+ rcti header_rect = v2d->mask;
+ header_rect.ymin = header_rect.ymax - layout->columnheader_h;
+ return BLI_rcti_isect_pt(&header_rect, x, y);
+}
+
+bool file_column_type_enabled(const FileSelectParams *params, FileListColumns column)
+{
+ switch (column) {
+ case COLUMN_NAME:
+ /* Always enabled */
+ return true;
+ case COLUMN_DATETIME:
+ return (params->details_flags & FILE_DETAILS_DATETIME) != 0;
+ case COLUMN_SIZE:
+ return (params->details_flags & FILE_DETAILS_SIZE) != 0;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
+FileListColumns file_column_type_find_isect(const View2D *v2d,
+ const FileSelectParams *params,
+ FileLayout *layout,
+ int x)
+{
+ float mx, my;
+ int offset_tile;
+
+ UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my);
+ offset_tile = ED_fileselect_layout_offset(
+ layout, (int)(v2d->tot.xmin + mx), (int)(v2d->tot.ymax - my));
+ if (offset_tile > -1) {
+ int tile_x, tile_y;
+ int pos_x = 0;
+ int rel_x; /* x relative to the hovered tile */
+
+ ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y);
+ /* Column header drawing doesn't use left tile border, so subtract it. */
+ rel_x = mx - (tile_x - layout->tile_border_x);
+
+ for (FileListColumns column = 0; column < COLUMN_MAX; column++) {
+ if (!file_column_type_enabled(params, column)) {
+ continue;
+ }
+ const int width = layout->details_columns[column].width;
+
+ if (IN_RANGE(rel_x, pos_x, pos_x + width)) {
+ return column;
+ }
+
+ pos_x += width;
+ }
+ }
+
+ return COLUMN_NONE;
+}
+
float file_string_width(const char *str)
{
uiStyle *style = UI_style_get();
@@ -512,20 +608,49 @@ float file_font_pointsize(void)
#endif
}
-static void column_widths(FileSelectParams *params, struct FileLayout *layout)
+static void details_columns_widths(const FileSelectParams *params, FileLayout *layout)
{
- int i;
+ FileDetailsColumn *columns = layout->details_columns;
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const int pad = small_size ? 0 : DETAILS_COLUMN_PADDING * 2;
- for (i = 0; i < MAX_FILE_COLUMN; ++i) {
- layout->column_widths[i] = 0;
+ for (int i = 0; i < COLUMN_MAX; ++i) {
+ layout->details_columns[i].width = 0;
}
- 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");
+ columns[COLUMN_DATETIME].width = file_string_width(small_size ? "23/08/89" : "23-Dec-89 23:59") +
+ pad;
+ columns[COLUMN_SIZE].width = file_string_width(small_size ? "98.7 M" : "98.7 MB") + pad;
+ if (params->display == FILE_IMGDISPLAY) {
+ columns[COLUMN_NAME].width = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X;
+ }
+ /* Name column uses remaining width */
+ else {
+ int remwidth = layout->tile_w;
+ for (FileListColumns column_type = COLUMN_MAX - 1; column_type >= 0; column_type--) {
+ if ((column_type == COLUMN_NAME) || !file_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ remwidth -= columns[column_type].width;
+ }
+ columns[COLUMN_NAME].width = remwidth;
+ }
+}
+
+static void details_columns_init(const FileSelectParams *params, FileLayout *layout)
+{
+ details_columns_widths(params, layout);
+
+ layout->details_columns[COLUMN_NAME].name = "Name";
+ layout->details_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA;
+ layout->details_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->details_columns[COLUMN_DATETIME].name = "Date Modified";
+ layout->details_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME;
+ layout->details_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_CENTER;
+ layout->details_columns[COLUMN_SIZE].name = "Size";
+ layout->details_columns[COLUMN_SIZE].sort_type = FILE_SORT_SIZE;
+ layout->details_columns[COLUMN_SIZE].text_align = UI_STYLE_TEXT_RIGHT;
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@@ -533,7 +658,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
FileSelectParams *params = ED_fileselect_get_params(sfile);
FileLayout *layout = NULL;
View2D *v2d = &ar->v2d;
- int maxlen = 0;
int numfiles;
int textheight;
@@ -561,6 +685,8 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight;
layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
+ layout->columnheader_h = 0;
+ layout->offset_top = 0;
if (layout->columns > 0) {
layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero
}
@@ -569,40 +695,51 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->rows = numfiles + 1; // XXX dirty, modulo is zero
}
layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
- layout->tile_border_y * 2;
+ layout->tile_border_y * 2 - layout->offset_top;
layout->flag = FILE_LAYOUT_VER;
}
- else {
- int column_space = 0.6f * UI_UNIT_X;
- int column_icon_space = 0.2f * UI_UNIT_X;
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ int rowcount;
- layout->prv_w = 0;
- layout->prv_h = 0;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.4f * UI_UNIT_X;
layout->tile_border_y = 0.1f * UI_UNIT_Y;
- layout->prv_border_x = 0;
- layout->prv_border_y = 0;
layout->tile_h = textheight * 3 / 2;
+ layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
+ layout->tile_w = layout->width;
+ layout->columns = 1;
+ layout->columnheader_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
+ layout->offset_top = layout->columnheader_h;
+ rowcount = (int)(BLI_rctf_size_y(&v2d->cur) - layout->offset_top - 2 * layout->tile_border_y) /
+ (layout->tile_h + 2 * layout->tile_border_y);
+ details_columns_init(params, layout);
+
+ if (numfiles && (int)rowcount / numfiles >= 1) {
+ layout->rows = rowcount;
+ }
+ else {
+ layout->rows = rowcount + (numfiles - rowcount);
+ }
+ layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
+ layout->tile_border_y * 2 + layout->offset_top;
+ layout->flag = FILE_LAYOUT_VER;
+ }
+ else if (params->display == FILE_HORIZONTALDISPLAY) {
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
+ layout->tile_border_x = 0.4f * UI_UNIT_X;
+ layout->tile_border_y = 0.1f * UI_UNIT_Y;
+ layout->tile_h = textheight * 3 / 2;
+ layout->columnheader_h = 0;
+ layout->offset_top = layout->columnheader_h;
layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
/* Padding by full scrollbar H is too much, can overlap tile border Y. */
layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) /
(layout->tile_h + 2 * layout->tile_border_y);
+ layout->tile_w = VERTLIST_MAJORCOLUMN_WIDTH;
+ details_columns_init(params, layout);
- column_widths(params, layout);
-
- if (params->display == FILE_SHORTDISPLAY) {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- else {
- maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space +
- (int)layout->column_widths[COLUMN_NAME] + column_space +
- (int)layout->column_widths[COLUMN_DATE] + column_space +
- (int)layout->column_widths[COLUMN_TIME] + column_space +
- (int)layout->column_widths[COLUMN_SIZE] + column_space;
- }
- layout->tile_w = maxlen;
if (layout->rows > 0) {
layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 1fd878e4662..992ffd3f461 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -72,6 +72,13 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
/* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */
ar->alignment = RGN_ALIGN_TOP;
+ /* ui list region */
+ ar = MEM_callocN(sizeof(ARegion), "ui region for file");
+ BLI_addtail(&sfile->regionbase, ar);
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_TOP;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
/* Tools region */
ar = MEM_callocN(sizeof(ARegion), "tools region for file");
BLI_addtail(&sfile->regionbase, ar);
@@ -84,11 +91,12 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
ar->regiontype = RGN_TYPE_TOOL_PROPS;
ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- /* ui list region */
- ar = MEM_callocN(sizeof(ARegion), "ui region for file");
+ /* Execute region */
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_UI;
- ar->alignment = RGN_ALIGN_TOP;
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -217,7 +225,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
- filelist_setsorting(sfile->files, params->sort);
+ filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT);
filelist_setfilter_options(sfile->files,
(params->flag & FILE_FILTER) != 0,
(params->flag & FILE_HIDE_DOT) != 0,
@@ -406,6 +414,11 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
v2d->keepofs &= ~V2D_LOCKOFS_Y;
v2d->keepofs |= V2D_LOCKOFS_X;
}
+ else if (params->display == FILE_VERTICALDISPLAY) {
+ v2d->scroll = V2D_SCROLL_RIGHT;
+ v2d->keepofs &= ~V2D_LOCKOFS_Y;
+ v2d->keepofs |= V2D_LOCKOFS_X;
+ }
else {
v2d->scroll = V2D_SCROLL_BOTTOM;
v2d->keepofs &= ~V2D_LOCKOFS_X;
@@ -439,7 +452,9 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(v2d, NULL);
+ rcti view_rect;
+ ED_fileselect_layout_maskrect(sfile->layout, v2d, &view_rect);
+ scrollers = UI_view2d_scrollers_calc(v2d, &view_rect);
UI_view2d_scrollers_draw(v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -452,6 +467,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_select_box);
WM_operatortype_append(FILE_OT_select_bookmark);
WM_operatortype_append(FILE_OT_highlight);
+ WM_operatortype_append(FILE_OT_sort_column_ui_context);
WM_operatortype_append(FILE_OT_execute);
WM_operatortype_append(FILE_OT_cancel);
WM_operatortype_append(FILE_OT_parent);
@@ -538,7 +554,8 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
/* own keymap */
keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
@@ -548,7 +565,8 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
}
-static void file_ui_region_draw(const bContext *C, ARegion *ar)
+#if 0
+static void file_ui_region_draw_ex(const bContext *C, ARegion *ar, bool is_execution_buts)
{
float col[3];
/* clear */
@@ -563,10 +581,33 @@ static void file_ui_region_draw(const bContext *C, ARegion *ar)
/* set view2d view matrix for scrolling (without scrollers) */
UI_view2d_view_ortho(&ar->v2d);
- file_draw_buttons(C, ar);
+
+ if (is_execution_buts) {
+ file_draw_execute_buttons(C, ar);
+ }
+ else {
+ file_draw_filepath_buttons(C, ar);
+ }
UI_view2d_view_restore(C);
}
+#endif
+
+static void file_ui_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
+}
+
+static void file_execution_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
+}
+
+static void file_execution_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
+}
static void file_ui_region_listener(wmWindow *UNUSED(win),
ScrArea *UNUSED(sa),
@@ -656,13 +697,22 @@ void ED_spacetype_file(void)
/* regions: ui */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_UI;
- art->prefsizey = 60;
+ art->flag = RGN_TYPE_FLAG_NO_CATEGORIES;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_ui_region_listener;
art->init = file_ui_region_init;
art->draw = file_ui_region_draw;
BLI_addhead(&st->regiontypes, art);
+ /* regions: execution */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
+ art->regionid = RGN_TYPE_EXECUTE;
+ art->keymapflag = ED_KEYMAP_UI;
+ art->listener = file_ui_region_listener;
+ art->init = file_execution_region_init;
+ art->draw = file_execution_region_draw;
+ BLI_addhead(&st->regiontypes, art);
+
/* regions: channels (directories) */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_TOOLS;
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 0319993631c..e37d72ff8af 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -523,6 +523,7 @@ enum {
#define PNL_DEFAULT_CLOSED 1
#define PNL_NO_HEADER 2
#define PNL_LAYOUT_VERT_BAR 4
+#define PNL_HIDDEN 8
/* Fallback panel category (only for old scripts which need updating) */
#define PNL_CATEGORY_FALLBACK "Misc"
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 505042432ed..1b1b8fe2cce 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -670,8 +670,10 @@ typedef struct FileSelectParams {
/** Display mode flag. */
short display;
short display_previous;
+ /** Details toggles (file size, creation date, etc.) */
+ char details_flags;
/** Filter when (flags & FILE_FILTER) is true. */
- char _pad2[2];
+ char _pad2;
int filter;
/** Max number of levels in dirtree to show at once, 0 to disable recursion. */
@@ -729,8 +731,8 @@ typedef struct SpaceFile {
/* FileSelectParams.display */
enum eFileDisplayType {
FILE_DEFAULTDISPLAY = 0,
- FILE_SHORTDISPLAY = 1,
- FILE_LONGDISPLAY = 2,
+ FILE_VERTICALDISPLAY = 1,
+ FILE_HORIZONTALDISPLAY = 2,
FILE_IMGDISPLAY = 3,
};
@@ -743,6 +745,12 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
+/* FileSelectParams.details_flags */
+enum eFileDetails {
+ FILE_DETAILS_SIZE = (1 << 0),
+ FILE_DETAILS_DATETIME = (1 << 1),
+};
+
/* these values need to be hardcoded in structs, dna does not recognize defines */
/* also defined in BKE */
#define FILE_MAXDIR 768
@@ -780,6 +788,7 @@ typedef enum eFileSel_Params_Flag {
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */
FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_SORT_INVERT = (1 << 11)
} eFileSel_Params_Flag;
/* sfile->params->rename_flag */
@@ -875,8 +884,7 @@ typedef struct FileDirEntryRevision {
int64_t time;
/* Temp caching of UI-generated strings... */
char size_str[16];
- char time_str[8];
- char date_str[16];
+ char datetime_str[16 + 8];
} FileDirEntryRevision;
/* Container for a variant, only relevant in asset context.
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 6dc0cf045cd..8cb988ff859 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -418,19 +418,15 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
{FILE_SORT_ALPHA,
"FILE_SORT_ALPHA",
ICON_SORTALPHA,
- "Sort alphabetically",
+ "Alphabet",
"Sort the file list alphabetically"},
{FILE_SORT_EXTENSION,
"FILE_SORT_EXTENSION",
ICON_SORTBYEXT,
- "Sort by extension",
+ "Kind",
"Sort the file list by extension/type"},
- {FILE_SORT_TIME,
- "FILE_SORT_TIME",
- ICON_SORTTIME,
- "Sort by time",
- "Sort files by modification time"},
- {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Sort by size", "Sort files by size"},
+ {FILE_SORT_TIME, "FILE_SORT_TIME", ICON_SORTTIME, "Date", "Sort files by modification time"},
+ {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Size", "Sort files by size"},
{0, NULL, 0, NULL, NULL},
};
@@ -5142,16 +5138,16 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem file_display_items[] = {
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
- "Short List",
- "Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
ICON_LONGDISPLAY,
- "Long List",
- "Display files as a detailed list"},
+ "Vertical List",
+ "Display files as a vertical list"},
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_SHORTDISPLAY,
+ "Horizontal List",
+ "Display files as a horizontal list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL},
};
@@ -5276,7 +5272,10 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Title", "Title for the file browser");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
+ /* Use BYTESTRING rather than DIRPATH as subtype so UI code doesn't add OT_directory_browse
+ * button when displaying this prop in the file browser (it would just open a file browser). That
+ * should be the only effective difference between the two. */
+ prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_BYTESTRING);
RNA_def_property_string_sdna(prop, NULL, "dir");
RNA_def_property_ui_text(prop, "Directory", "Directory displayed in the file browser");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -5304,6 +5303,19 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
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, "show_details_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_SIZE);
+ RNA_def_property_ui_text(prop, "File Size", "Draw a column listing the size of each file");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "show_details_datetime", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_DATETIME);
+ RNA_def_property_ui_text(
+ prop,
+ "File Modification Date",
+ "Draw a column listing the date and time of modification for each file");
+ 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");
@@ -5320,6 +5332,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sort", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "use_sort_invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_SORT_INVERT);
+ RNA_def_property_ui_text(
+ prop, "Reverse Sorting", "Sort items descending, from highest value to lowest");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "use_filter_image", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_IMAGE);
RNA_def_property_ui_text(prop, "Filter Images", "Show image files");
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 097e62a1fea..51d39bb3ca5 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -269,7 +269,20 @@ static StructRNA *rna_Panel_register(Main *bmain,
return NULL;
}
- if ((1 << dummypt.region_type) & RGN_TYPE_HAS_CATEGORY_MASK) {
+ if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type))) {
+ return NULL;
+ }
+
+ if (art->flag & RGN_TYPE_FLAG_NO_CATEGORIES) {
+ /* Skip category registration if region doesn't allow categories. */
+# ifndef NDEBUG
+ if (dummypt.category[0] != '\0') {
+ printf("Category '%s' can't be registered, category tabs are disabled for this region.",
+ dummypt.category);
+ }
+# endif
+ }
+ else if ((1 << dummypt.region_type) & RGN_TYPE_HAS_CATEGORY_MASK) {
if (dummypt.category[0] == '\0') {
/* Use a fallback, otherwise an empty value will draw the panel in every category. */
strcpy(dummypt.category, PNL_CATEGORY_FALLBACK);
@@ -292,10 +305,6 @@ static StructRNA *rna_Panel_register(Main *bmain,
}
}
- if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type))) {
- return NULL;
- }
-
/* check if we have registered this panel type before, and remove it */
for (pt = art->paneltypes.first; pt; pt = pt->next) {
if (STREQ(pt->idname, dummypt.idname)) {
@@ -1281,6 +1290,12 @@ static void rna_def_panel(BlenderRNA *brna)
"Hide Header",
"If set to False, the panel shows a header, which contains a clickable "
"arrow to collapse the panel and the label (see bl_label)"},
+ {PNL_HIDDEN,
+ "HIDDEN",
+ 0,
+ "Hidden",
+ "Do not show this panel, only register it for display at a non-default position (e.g. in a "
+ "popup)."},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 5d6e405dd5d..a479ab62b88 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -162,7 +162,7 @@ enum {
WM_WINDOW_RENDER = 1,
WM_WINDOW_USERPREFS,
WM_WINDOW_DRIVERS,
- // WM_WINDOW_FILESEL // UNUSED
+ WM_WINDOW_FILESEL,
};
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 88a4c13c4ca..4e9604545ca 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2337,45 +2337,32 @@ static int wm_handler_fileselect_do(bContext *C,
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
- ScrArea *sa;
+ wmWindow *win = CTX_wm_window(C);
+ const int sizex = 1020 * UI_DPI_FAC;
+ const int sizey = 600 * UI_DPI_FAC;
- /* sa can be null when window A is active, but mouse is over window B
- * in this case, open file select in original window A. Also don't
- * use global areas. */
- if (handler->context.area == NULL || ED_area_is_global(handler->context.area)) {
- bScreen *screen = CTX_wm_screen(C);
- sa = (ScrArea *)screen->areabase.first;
- }
- else {
- sa = handler->context.area;
- }
+ if (WM_window_open_temp(
+ C, win->eventstate->x, win->eventstate->y, sizex, sizey, WM_WINDOW_FILESEL) !=
+ NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
- if (sa->full) {
- /* ensure the first area becomes the file browser, because the second one is the small
- * top (info-)area which might be too small (in fullscreens we have max two areas) */
- if (sa->prev) {
- sa = sa->prev;
- }
- ED_area_newspace(C, sa, SPACE_FILE, true); /* 'sa' is modified in-place */
- /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
- }
- else if (sa->spacetype == SPACE_FILE) {
- sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
- }
- else {
- sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
- }
+ BLI_assert(area->spacetype == SPACE_FILE);
- /* note, getting the 'sa' back from the context causes a nasty bug where the newly created
- * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */
- /* sa = CTX_wm_area(C); */
+ region_header->flag |= RGN_FLAG_HIDDEN;
+ /* Header on bottom, AZone triangle to toggle header looks misplaced at the top */
+ region_header->alignment = RGN_ALIGN_BOTTOM;
- /* settings for filebrowser, sfile is not operator owner but sends events */
- sfile = (SpaceFile *)sa->spacedata.first;
- sfile->op = handler->op;
+ /* settings for filebrowser, sfile is not operator owner but sends events */
+ sfile = (SpaceFile *)area->spacedata.first;
+ sfile->op = handler->op;
- ED_fileselect_set_params(sfile);
+ ED_fileselect_set_params(sfile);
+ }
+ else {
+ BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
action = WM_HANDLER_BREAK;
break;
@@ -2388,14 +2375,27 @@ static int wm_handler_fileselect_do(bContext *C,
BLI_remlink(handlers, handler);
if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
- ScrArea *sa = CTX_wm_area(C);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_is_temp_screen(win)) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *file_sa = screen->areabase.first;
- if (sa->full) {
- ED_screen_full_prevspace(C, sa);
- }
- /* user may have left fullscreen */
- else {
- ED_area_prevspace(C, sa);
+ BLI_assert(file_sa->spacetype == SPACE_FILE);
+
+ if (BLI_listbase_is_single(&file_sa->spacedata)) {
+ wmWindow *ctx_win = CTX_wm_window(C);
+ wm_window_close(C, wm, win);
+ CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs.
+ }
+ else if (file_sa->full) {
+ ED_screen_full_prevspace(C, file_sa);
+ }
+ else {
+ ED_area_prevspace(C, file_sa);
+ }
+
+ break;
+ }
}
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 6a5800f4288..eeec78729ea 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2304,7 +2304,7 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
void WM_OT_open_mainfile(wmOperatorType *ot)
{
- ot->name = "Open Blender File";
+ ot->name = "Open";
ot->idname = "WM_OT_open_mainfile";
ot->description = "Open a Blender file";
@@ -2486,7 +2486,7 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH,
- FILE_LONGDISPLAY,
+ FILE_HORIZONTALDISPLAY,
FILE_SORT_TIME);
}
@@ -2620,7 +2620,7 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot)
{
PropertyRNA *prop;
- ot->name = "Save As Blender File";
+ ot->name = "Save As";
ot->idname = "WM_OT_save_as_mainfile";
ot->description = "Save the current file in the desired location";
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5a6606984ba..2cd2cf0636a 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -561,7 +561,7 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
void WM_OT_link(wmOperatorType *ot)
{
- ot->name = "Link from Library";
+ ot->name = "Link";
ot->idname = "WM_OT_link";
ot->description = "Link from a Library .blend file";
@@ -585,7 +585,7 @@ void WM_OT_link(wmOperatorType *ot)
void WM_OT_append(wmOperatorType *ot)
{
- ot->name = "Append from Library";
+ ot->name = "Append";
ot->idname = "WM_OT_append";
ot->description = "Append from a Library .blend file";
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index f22b5d07686..f2db68ec6b8 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -65,14 +65,14 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
0,
"Default",
"Automatically determine display type for files"},
- {FILE_SHORTDISPLAY,
- "LIST_SHORT",
- ICON_SHORTDISPLAY,
+ {FILE_VERTICALDISPLAY,
+ "LIST_VERTICAL",
+ ICON_SHORTDISPLAY, // * Name of deprecated Short List*
"Short List",
"Display files as short list"},
- {FILE_LONGDISPLAY,
- "LIST_LONG",
- ICON_LONGDISPLAY,
+ {FILE_HORIZONTALDISPLAY,
+ "LIST_HORIZONTAL",
+ ICON_LONGDISPLAY, // * Name of deprecated Long List*
"Long List",
"Display files as a detailed list"},
{FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index d17b8817691..4c095e0dca0 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -807,6 +807,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+ eSpace_Type space_type = SPACE_EMPTY;
const char *title;
/* convert to native OS window coordinates */
@@ -888,14 +889,21 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
CTX_wm_area_set(C, sa);
if (type == WM_WINDOW_RENDER) {
- ED_area_newspace(C, sa, SPACE_IMAGE, false);
+ space_type = SPACE_IMAGE;
}
else if (type == WM_WINDOW_DRIVERS) {
- ED_area_newspace(C, sa, SPACE_GRAPH, false);
+ space_type = SPACE_GRAPH;
+ }
+ else if (type == WM_WINDOW_USERPREFS) {
+ space_type = SPACE_USERPREF;
+ }
+ else if (type == WM_WINDOW_FILESEL) {
+ space_type = SPACE_FILE;
}
else {
- ED_area_newspace(C, sa, SPACE_USERPREF, false);
+ BLI_assert(false);
}
+ ED_area_newspace(C, sa, space_type, false);
ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */