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:
authorAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
committerAntonio Vazquez <blendergit@gmail.com>2019-10-02 14:15:37 +0300
commit386ba094988fc793f8e060d15438566e5e2d2cae (patch)
tree4cbde50b5d1d7a45c89ee99c29dd1b86d1d97b59 /source/blender/editors/space_file
parent6129e20cec4639aebf335ff13b2ba0c59670662d (diff)
parentf97a64aa9b7b384f8221a1ef4f2eef9cde1238db (diff)
Merge branch 'master' into temp-gpencil-drw-engine
Conflicts: source/blender/draw/engines/gpencil/gpencil_engine.c
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r--source/blender/editors/space_file/file_draw.c680
-rw-r--r--source/blender/editors/space_file/file_intern.h23
-rw-r--r--source/blender/editors/space_file/file_ops.c218
-rw-r--r--source/blender/editors/space_file/file_panels.c116
-rw-r--r--source/blender/editors/space_file/filelist.c177
-rw-r--r--source/blender/editors/space_file/filelist.h6
-rw-r--r--source/blender/editors/space_file/filesel.c369
-rw-r--r--source/blender/editors/space_file/fsmenu.c19
-rw-r--r--source/blender/editors/space_file/space_file.c169
9 files changed, 1112 insertions, 665 deletions
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3a6d59c1dbf..0aec6d5e6a0 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include "BLI_blenlib.h"
+#include "BLI_fileops_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -70,239 +71,57 @@
#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))
+void ED_file_path_button(bScreen *screen,
+ const SpaceFile *sfile,
+ FileSelectParams *params,
+ uiBlock *block)
{
- 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:
- *
- * -------------------------------------------
- * | 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;
-
+ PointerRNA params_rna_ptr;
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;
- }
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "directory",
+ 0,
+ 0.0f,
+ (float)FILE_MAX,
+ 0.0f,
+ 0.0f,
+ TIP_("File path"));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_directory, NULL);
+ 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 && sfile->files && filelist_lib(sfile->files)) {
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
- 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,
- "");
- }
+ /* clear func */
+ UI_block_func_set(block, NULL, NULL, NULL);
+}
- UI_block_end(C, block);
- UI_block_draw(C, block);
+/* 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);
}
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
@@ -319,13 +138,10 @@ static void file_draw_icon(
{
uiBut *but;
int x, y;
- // float alpha = 1.0f;
x = sx;
y = sy - height;
- /*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, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path));
@@ -349,7 +165,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 +178,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;
@@ -404,8 +220,8 @@ static void file_draw_preview(uiBlock *block,
float scaledx, scaledy;
float scale;
int ex, ey;
- bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ bool show_outline = !is_icon &&
+ (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER));
BLI_assert(imb != NULL);
@@ -440,15 +256,20 @@ static void file_draw_preview(uiBlock *block,
xco = sx + (int)dx;
yco = sy - layout->prv_h + (int)dy;
- /* shadow */
- if (use_dropshadow) {
- UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
- }
-
GPU_blend(true);
- /* the image */
- if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
+ /* the large image */
+
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ if (is_icon) {
+ if (typeflags & FILE_TYPE_DIR) {
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, col);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_TEXT, col);
+ }
+ }
+ else if (typeflags & FILE_TYPE_FTFONT) {
UI_GetThemeColor4fv(TH_TEXT, col);
}
@@ -477,30 +298,58 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon) {
- UI_icon_draw_ex((float)xco + (7 * UI_DPI_FAC),
- (float)yco + (7 * UI_DPI_FAC),
- icon,
- icon_aspect,
- 1.0f,
- 0.0f,
- NULL,
- false);
+ if (icon && (icon != ICON_FILE_FONT)) {
+ /* size of center icon is scaled to fit container and UI scale */
+ float icon_x, icon_y;
+
+ if (is_icon) {
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
+ }
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+ else {
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+
+ /* Smaller, fainter icon for preview image thumbnail. */
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ }
}
- /* border */
- if (use_dropshadow) {
+ /* Contrasting outline around some preview types. */
+ if (show_outline) {
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ float border_color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_BACK, bgcolor);
+ if (rgb_to_grayscale(bgcolor) > 0.5f) {
+ border_color[0] = 0.0f;
+ border_color[1] = 0.0f;
+ border_color[2] = 0.0f;
+ }
+ immUniformColor4fv(border_color);
imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
immUnbindProgram();
}
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) {
@@ -557,6 +406,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 +415,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 +484,176 @@ 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, 11);
+
+ immRectf(pos,
+ v2d->cur.xmin,
+ v2d->cur.ymax - layout->attribute_column_header_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->attribute_column_header_h;
+ int sx = v2d->cur.xmin, sy = v2d->cur.ymax;
+
+ for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ const FileAttributeColumn *column = &layout->attribute_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) -
+ ATTRIBUTE_COLUMN_PADDING / 2.0f,
+ sy + (0.1f * U.widget_unit) - (layout->attribute_column_header_h / 2),
+ (params->flag & FILE_SORT_INVERT) ? 't' : 'v',
+ tri_color);
+ }
+
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(column->name),
+ column->width - 2 * ATTRIBUTE_COLUMN_PADDING,
+ layout->attribute_column_header_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->attribute_column_header_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->attribute_column_header_h);
+ immVertex2f(pos, v2d->cur.xmax, sy - layout->attribute_column_header_h);
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/**
+ * Updates the stat string stored in file->entry if necessary.
+ */
+static const char *filelist_get_details_column_string(FileAttributeColumnType 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[FILELIST_DIRENTRY_DATE_LEN], time[FILELIST_DIRENTRY_TIME_LEN];
+ bool is_today, is_yesterday;
+
+ BLI_filelist_entry_datetime_to_string(
+ NULL, file->entry->time, small_size, time, date, &is_today, &is_yesterday);
+
+ if (is_today || is_yesterday) {
+ BLI_strncpy(date, is_today ? N_("Today") : N_("Yesterday"), sizeof(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 (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX;
+ column_type++) {
+ const FileAttributeColumn *column = &layout->attribute_columns[column_type];
+
+ /* Name column is not a detail column (should already be drawn), always skip here. */
+ if (column_type == COLUMN_NAME) {
+ sx += column->width;
+ continue;
+ }
+ if (!file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+
+ const char *str = filelist_get_details_column_string(
+ column_type, file, small_size, update_stat_strings);
+
+ if (str) {
+ file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING,
+ sy - layout->tile_border_y,
+ IFACE_(str),
+ column->width - 2 * ATTRIBUTE_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 +674,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 float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
+ const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
+ const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f);
numfiles = filelist_files_ensure(files);
if (params->display != FILE_IMGDISPLAY) {
-
draw_background(layout, v2d);
-
draw_dividers(layout, v2d);
}
@@ -679,13 +697,14 @@ void file_draw_list(const bContext *C, ARegion *ar)
numfiles_layout += layout->rows;
}
else {
- numfiles_layout += layout->columns;
+ numfiles_layout += layout->flow_columns;
}
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->attribute_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 +738,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 +761,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 +801,28 @@ 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->attribute_columns[COLUMN_NAME].width -
+ ATTRIBUTE_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 +838,19 @@ 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 txpos = (params->display == FILE_IMGDISPLAY) ? sx : sx + 1 + icon_ofs;
+ const int typos = (params->display == FILE_IMGDISPLAY) ?
+ sy - layout->tile_h + layout->textheight :
+ sy - layout->tile_border_y;
+ const int twidth = (params->display == FILE_IMGDISPLAY) ?
+ textwidth :
+ textwidth - 1 - icon_ofs - padx - layout->tile_border_x;
+ file_draw_string(txpos, typos, file->name, (float)twidth, 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 +859,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..b0ff67844d8 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -30,9 +30,7 @@ struct ARegion;
struct ARegionType;
struct FileSelectParams;
struct SpaceFile;
-
-/* file_ops.c */
-struct ARegion *file_tools_region(struct ScrArea *sa);
+struct View2D;
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
@@ -42,9 +40,10 @@ 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 ATTRIBUTE_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);
void file_calc_previews(const bContext *C, ARegion *ar);
void file_draw_list(const bContext *C, ARegion *ar);
@@ -64,6 +63,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);
@@ -82,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -108,10 +107,21 @@ void file_sfile_to_operator_ex(bContext *C,
struct SpaceFile *sfile,
char *filepath);
void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+
void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
void fileselect_file_set(SpaceFile *sfile, const int index);
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType column);
+bool file_attribute_column_header_is_inside(const struct View2D *v2d,
+ const FileLayout *layout,
+ int x,
+ int y);
+FileAttributeColumnType file_attribute_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);
@@ -122,7 +132,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
/* file_panels.c */
-void file_panels_register(struct ARegionType *art);
+void file_tool_props_region_panels_register(struct ARegionType *art);
+void file_execute_region_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index eb5f02b6e13..b4b51de302d 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),
@@ -190,7 +195,6 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
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! */
@@ -235,7 +239,7 @@ static bool file_is_any_selected(struct FileList *files)
int i;
/* Is any file selected ? */
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
return true;
}
@@ -262,8 +266,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 +282,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 +388,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,13 +444,13 @@ 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);
/* unselect '..' parent entry - it's not supposed to be selected if more than
* one file is selected */
- filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, 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);
@@ -485,6 +489,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool fill = RNA_boolean_get(op->ptr, "fill");
const bool do_diropen = RNA_boolean_get(op->ptr, "open");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
if (ar->regiontype != RGN_TYPE_WINDOW) {
return OPERATOR_CANCELLED;
@@ -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;
}
@@ -514,14 +519,18 @@ 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_entry_select_index_set(
- sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
- if (FILE_SELECT_DIR == ret) {
+ if (ret == FILE_SELECT_NOTHING) {
+ if (deselect_all) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
+ }
+ else if (ret == FILE_SELECT_DIR) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
- else if (FILE_SELECT_FILE == ret) {
+ else if (ret == FILE_SELECT_FILE) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -537,8 +546,8 @@ void FILE_OT_select(wmOperatorType *ot)
/* identifiers */
ot->name = "Select";
- ot->description = "Activate/select file";
ot->idname = "FILE_OT_select";
+ ot->description = "Handle mouse clicks to select and activate items";
/* api callbacks */
ot->invoke = file_select_invoke;
@@ -556,6 +565,12 @@ void FILE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/**
@@ -580,6 +595,11 @@ static bool file_walk_select_selection_set(bContext *C,
BLI_assert(params);
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
filelist_entry_select_index_get(files, active_new, CHECK_ALL)) {
@@ -609,7 +629,7 @@ static bool file_walk_select_selection_set(bContext *C,
}
/* select first file */
else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) {
- params->active_file = active = extend ? 1 : 0;
+ params->active_file = active = 0;
}
else {
BLI_assert(0);
@@ -626,7 +646,7 @@ static bool file_walk_select_selection_set(bContext *C,
/* unselect '..' parent entry - it's not supposed to be selected if more
* than one file is selected */
- filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
}
else {
/* deselect all first */
@@ -641,11 +661,6 @@ static bool file_walk_select_selection_set(bContext *C,
if (fill) {
FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)};
- /* clamping selection to not include '..' parent entry */
- if (sel.first == 0) {
- sel.first = 1;
- }
-
/* fill selection between last and first selected file */
filelist_entries_select_index_range_set(
files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
@@ -653,6 +668,12 @@ static bool file_walk_select_selection_set(bContext *C,
if (deselect) {
filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
}
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more
+ * than one file is selected */
+ if ((sel.last - sel.first) > 1) {
+ filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ }
}
else {
filelist_entry_select_index_set(
@@ -688,10 +709,15 @@ static bool file_walk_select_do(bContext *C,
/* *** get all needed files for handling selection *** */
+ if (numfiles == 0) {
+ /* No files visible, nothing to do. */
+ return false;
+ }
+
if (has_selection) {
ARegion *ar = CTX_wm_region(C);
FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
- const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns;
+ const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) ||
(layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) {
@@ -718,7 +744,7 @@ static bool file_walk_select_do(bContext *C,
BLI_assert(0);
}
- if (!IN_RANGE(active_new, 0, numfiles)) {
+ if (!IN_RANGE(active_new, -1, numfiles)) {
if (extend) {
/* extend to invalid file -> abort */
return false;
@@ -1185,7 +1211,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 +1260,53 @@ 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_attribute_column_header_is_inside(
+ &ar->v2d, sfile->layout, event->mval[0], event->mval[1])) {
+ const FileAttributeColumnType column_type = file_attribute_column_type_find_isect(
+ &ar->v2d, sfile->params, sfile->layout, event->mval[0]);
+
+ if (column_type != COLUMN_NONE) {
+ const FileAttributeColumn *column = &sfile->layout->attribute_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);
@@ -1433,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- PropertyRNA *prop;
- if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
- if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
- char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
- if (BLI_is_file(filepath)) {
- return true;
- }
+ if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
+ char filepath[FILE_MAX];
+ BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
+ if (BLI_is_file(filepath)) {
+ return true;
}
}
}
@@ -1683,7 +1753,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* check if we are editing a name */
int edit_idx = -1;
- for (i = 0; i < numfiles; ++i) {
+ for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) &
(FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) {
edit_idx = i;
@@ -1713,7 +1783,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
* in vertical layout).
*/
- const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->columns;
+ const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
/* Scroll offset is the first file in the row/column we are editing in. */
if (sfile->scroll_offset == 0) {
@@ -1915,6 +1985,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);
+ const bool do_diropen = RNA_boolean_get(op->ptr, "open");
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@@ -1963,9 +2034,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* now remember file to jump into editing */
- BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
- sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ /* If we don't enter the directory directly, remember file to jump into editing. */
+ if (do_diropen == false) {
+ BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
+ sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
+ }
/* set timer to smoothly view newly generated file */
/* max 30 frs/sec */
@@ -1978,7 +2051,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, sa, sfile);
- if (RNA_boolean_get(op->ptr, "open")) {
+ if (do_diropen) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
ED_file_change_dir(C);
}
@@ -1998,7 +2071,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
ot->idname = "FILE_OT_directory_new";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = file_directory_new_exec;
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
@@ -2007,6 +2080,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operator_properties_confirm_or_exec(ot);
}
/* TODO This should go to BLI_path_utils. */
@@ -2075,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
+ char old_dir[sizeof(sfile->params->dir)];
+
+ BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
+
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
@@ -2108,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
- /* if directory exists, enter it immediately */
- ED_file_change_dir(C);
+ if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
+ /* if directory exists, enter it immediately */
+ ED_file_change_dir(C);
+ }
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -2138,6 +2218,8 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "directory", sfile->params->dir);
RNA_boolean_set(&ptr, "open", true);
+ /* Enable confirmation prompt, else it's too easy to accidentaly create new directories. */
+ RNA_boolean_set(&ptr, "confirm", true);
if (lastdir) {
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
@@ -2239,57 +2321,15 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_tools_region(ScrArea *sa)
+static bool file_filenum_poll(bContext *C)
{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tools for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOLS;
- arnew->alignment = RGN_ALIGN_LEFT;
-
- ar = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, arnew, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
- return arnew;
-}
-
-static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_tools_region(sa);
+ SpaceFile *sfile = CTX_wm_space_file(C);
- if (ar) {
- ED_region_toggle_hidden(C, ar);
+ if (!ED_operator_file_active(C)) {
+ return false;
}
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Bookmarks";
- ot->description = "Toggle bookmarks display";
- ot->idname = "FILE_OT_bookmark_toggle";
-
- /* api callbacks */
- ot->exec = file_bookmark_toggle_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
}
/**
@@ -2349,7 +2389,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = file_filenum_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
+ ot->poll = file_filenum_poll;
/* props */
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index d9a6e70121f..9ba098fcf45 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -95,7 +95,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
}
-void file_panels_register(ARegionType *art)
+void file_tool_props_region_panels_register(ARegionType *art)
{
PanelType *pt;
@@ -103,8 +103,122 @@ void file_panels_register(ARegionType *art)
strcpy(pt->idname, "FILE_PT_operator");
strcpy(pt->label, N_("Operator"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
pt->poll = file_panel_operator_poll;
pt->draw_header = file_panel_operator_header;
pt->draw = file_panel_operator;
BLI_addtail(&art->paneltypes, pt);
}
+
+static void file_panel_execution_cancel_button(uiLayout *layout)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel");
+}
+
+static void file_panel_execution_execute_button(uiLayout *layout, const char *title)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ /* Just a display hint. */
+ uiLayoutSetActiveDefault(row, true);
+ uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
+}
+
+static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelectParams *params = ED_fileselect_get_params(sfile);
+ uiBlock *block = uiLayoutGetBlock(pa->layout);
+ uiBut *but;
+ uiLayout *row;
+ PointerRNA params_rna_ptr, *but_extra_rna_ptr;
+
+ const bool overwrite_alert = file_draw_check_exists(sfile);
+ const bool windows_layout =
+#ifdef _WIN32
+ true;
+#else
+ false;
+#endif
+
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
+
+ row = uiLayoutRow(pa->layout, false);
+ uiLayoutSetScaleY(row, 1.3f);
+
+ /* callbacks for operator check functions */
+ UI_block_func_set(block, file_draw_check_cb, NULL, NULL);
+
+ but = uiDefButR(block,
+ UI_BTYPE_TEXT,
+ -1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 5,
+ UI_UNIT_Y,
+ &params_rna_ptr,
+ "filename",
+ 0,
+ 0.0f,
+ (float)FILE_MAXFILE,
+ 0,
+ 0,
+ TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name")));
+
+ BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO));
+ BLI_assert(!UI_but_is_utf8(but));
+
+ UI_but_func_complete_set(but, autocomplete_file, NULL);
+ /* 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);
+
+ if (params->flag & FILE_CHECK_EXISTING) {
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
+ RNA_int_set(but_extra_rna_ptr, "increment", 1);
+ but_extra_rna_ptr = UI_but_extra_operator_icon_add(
+ but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE);
+ RNA_int_set(but_extra_rna_ptr, "increment", -1);
+ }
+
+ /* check if this overrides a file and if the operator option is used */
+ if (overwrite_alert) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
+ UI_block_func_set(block, NULL, NULL, NULL);
+
+ {
+ uiLayout *sub = uiLayoutRow(row, false);
+ uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN);
+
+ if (windows_layout) {
+ file_panel_execution_execute_button(sub, params->title);
+ file_panel_execution_cancel_button(sub);
+ }
+ else {
+ file_panel_execution_cancel_button(sub);
+ file_panel_execution_execute_button(sub, params->title);
+ }
+ }
+}
+
+void file_execute_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype file execution buttons");
+ strcpy(pt->idname, "FILE_PT_execution_buttons");
+ strcpy(pt->label, N_("Execute Buttons"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PNL_NO_HEADER;
+ pt->poll = file_panel_operator_poll;
+ pt->draw = file_panel_execution_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index f7dda1defe8..27cccf6bab1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -329,25 +329,21 @@ 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
-#define SPECIAL_IMG_ROWS 4
-#define SPECIAL_IMG_COLS 4
+#define SPECIAL_IMG_SIZE 256
+#define SPECIAL_IMG_ROWS 1
+#define SPECIAL_IMG_COLS 7
enum {
- SPECIAL_IMG_FOLDER = 0,
- SPECIAL_IMG_PARENT = 1,
- SPECIAL_IMG_REFRESH = 2,
- SPECIAL_IMG_BLENDFILE = 3,
- SPECIAL_IMG_SOUNDFILE = 4,
- SPECIAL_IMG_MOVIEFILE = 5,
- SPECIAL_IMG_PYTHONFILE = 6,
- SPECIAL_IMG_TEXTFILE = 7,
- SPECIAL_IMG_FONTFILE = 8,
- SPECIAL_IMG_UNKNOWNFILE = 9,
- SPECIAL_IMG_LOADING = 10,
- SPECIAL_IMG_BACKUP = 11,
+ SPECIAL_IMG_DOCUMENT = 0,
+ SPECIAL_IMG_UNSUPORTED = 1,
+ SPECIAL_IMG_FOLDER = 2,
+ SPECIAL_IMG_PARENT = 3,
+ SPECIAL_IMG_DRIVE_FIXED = 4,
+ SPECIAL_IMG_DRIVE_ATTACHED = 5,
+ SPECIAL_IMG_DRIVE_REMOTE = 6,
SPECIAL_IMG_MAX,
};
@@ -369,6 +365,19 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
/* ********** Sort helpers ********** */
+struct FileSortData {
+ bool inverted;
+};
+
+static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
+{
+ return sort_data->inverted ? -val : val;
+}
+
+/**
+ * Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
+ * it should be used as-is and not inverted.
+ */
static int compare_direntry_generic(const FileListInternEntry *entry1,
const FileListInternEntry *entry2)
{
@@ -420,10 +429,11 @@ static int compare_direntry_generic(const FileListInternEntry *entry1,
return 0;
}
-static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_name(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -434,13 +444,14 @@ static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2)
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_date(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int64_t time1, time2;
int ret;
@@ -452,22 +463,23 @@ static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2)
time1 = (int64_t)entry1->st.st_mtime;
time2 = (int64_t)entry2->st.st_mtime;
if (time1 < time2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (time1 > time2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_size(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -479,22 +491,23 @@ static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2)
size1 = entry1->st.st_size;
size2 = entry2->st.st_size;
if (size1 < size2) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
if (size1 > size2) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
-static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2)
+static int compare_extension(void *user_data, const void *a1, const void *a2)
{
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
+ const struct FileSortData *sort_data = user_data;
char *name1, *name2;
int ret;
@@ -516,10 +529,10 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
return -1;
}
if (entry1->blentype < entry2->blentype) {
- return -1;
+ return compare_apply_inverted(-1, sort_data);
}
if (entry1->blentype > entry2->blentype) {
- return 1;
+ return compare_apply_inverted(1, sort_data);
}
}
else {
@@ -539,48 +552,58 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
}
if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
- return ret;
+ return compare_apply_inverted(ret, sort_data);
}
}
name1 = entry1->name;
name2 = entry2->name;
- return BLI_natstrcmp(name1, name2);
+ return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
}
void filelist_sort(struct FileList *filelist)
{
if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) {
+ void *sort_cb = NULL;
+
switch (filelist->sort) {
case FILE_SORT_ALPHA:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
+ sort_cb = compare_name;
break;
case FILE_SORT_TIME:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
+ sort_cb = compare_date;
break;
case FILE_SORT_SIZE:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
+ sort_cb = compare_size;
break;
case FILE_SORT_EXTENSION:
- BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
+ sort_cb = compare_extension;
break;
case FILE_SORT_NONE: /* Should never reach this point! */
default:
BLI_assert(0);
break;
}
+ BLI_listbase_sort_r(
+ &filelist->filelist_intern.entries,
+ sort_cb,
+ &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
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);
}
}
@@ -635,9 +658,9 @@ static bool is_filtered_file(FileListInternEntry *file,
{
bool is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter) {
+ if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -657,6 +680,7 @@ static bool is_filtered_file(FileListInternEntry *file,
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -676,9 +700,9 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
if (BLO_library_path_explode(path, dir, &group, &name)) {
is_filtered = !is_hidden_file(file->relpath, filter);
- if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) {
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
/* We only check for types if some type are enabled in filtering. */
- if (filter->filter || filter->filter_id) {
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (file->typeflag &
(FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
@@ -704,6 +728,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
}
}
}
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -870,7 +895,7 @@ void filelist_free_icons(void)
BLI_assert(G.background == false);
- for (i = 0; i < SPECIAL_IMG_MAX; ++i) {
+ for (i = 0; i < SPECIAL_IMG_MAX; i++) {
IMB_freeImBuf(gSpecialFileImages[i]);
gSpecialFileImages[i] = NULL;
}
@@ -904,42 +929,12 @@ static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char
if (FILENAME_IS_PARENT(relpath)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
}
- else if (FILENAME_IS_CURRENT(relpath)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
- }
else {
ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
}
}
- else if (typeflag & FILE_TYPE_BLENDER) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
- }
- else if (typeflag & FILE_TYPE_BLENDERLIB) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
- }
- else if (typeflag & (FILE_TYPE_MOVIE)) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
- }
- else if (typeflag & FILE_TYPE_SOUND) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
- }
- else if (typeflag & FILE_TYPE_PYSCRIPT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
- }
- else if (typeflag & FILE_TYPE_FTFONT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
- }
- else if (typeflag & FILE_TYPE_TEXT) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
- }
- else if (typeflag & FILE_TYPE_IMAGE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
- }
- else if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
- }
else {
- ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ ibuf = gSpecialFileImages[SPECIAL_IMG_DOCUMENT];
}
return ibuf;
@@ -1001,14 +996,20 @@ static int filelist_geticon_ex(const int typeflag,
return ICON_FILE_BLANK;
}
else if (typeflag & FILE_TYPE_COLLADA) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_ALEMBIC) {
- return ICON_FILE_BLANK;
+ return ICON_FILE_3D;
+ }
+ else if (typeflag & FILE_TYPE_OBJECT_IO) {
+ return ICON_FILE_3D;
}
else if (typeflag & FILE_TYPE_TEXT) {
return ICON_FILE_TEXT;
}
+ else if (typeflag & FILE_TYPE_ARCHIVE) {
+ return ICON_FILE_ARCHIVE;
+ }
else if (typeflag & FILE_TYPE_BLENDERLIB) {
const int ret = UI_idcode_icon_get(blentype);
if (ret != ICON_NONE) {
@@ -1243,7 +1244,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
BLI_task_pool_cancel(cache->previews_pool);
while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
- // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
+ // preview->img);
if (preview->img) {
IMB_freeImBuf(preview->img);
}
@@ -2128,6 +2130,12 @@ int ED_path_extension_type(const char *path)
else if (BLI_path_extension_check(path, ".abc")) {
return FILE_TYPE_ALEMBIC;
}
+ else if (BLI_path_extension_check(path, ".zip")) {
+ return FILE_TYPE_ARCHIVE;
+ }
+ else if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", NULL)) {
+ return FILE_TYPE_OBJECT_IO;
+ }
else if (BLI_path_extension_check_array(path, imb_ext_image)) {
return FILE_TYPE_IMAGE;
}
@@ -2177,11 +2185,13 @@ int ED_file_extension_icon(const char *path)
case FILE_TYPE_BTX:
return ICON_FILE_BLANK;
case FILE_TYPE_COLLADA:
- return ICON_FILE_BLANK;
case FILE_TYPE_ALEMBIC:
- return ICON_FILE_BLANK;
+ case FILE_TYPE_OBJECT_IO:
+ return ICON_FILE_3D;
case FILE_TYPE_TEXT:
return ICON_FILE_TEXT;
+ case FILE_TYPE_ARCHIVE:
+ return ICON_FILE_ARCHIVE;
default:
return ICON_FILE_BLANK;
}
@@ -2298,6 +2308,19 @@ unsigned int filelist_entry_select_index_get(FileList *filelist,
return 0;
}
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
+void filelist_entry_parent_select_set(FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check)
+{
+ if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
+ filelist_entry_select_index_set(filelist, 0, select, flag, check);
+ }
+}
+
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
{
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index caf77246797..9b1107294ff 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,
@@ -117,6 +117,10 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
+void filelist_entry_parent_select_set(struct FileList *filelist,
+ FileSelType select,
+ unsigned int flag,
+ FileCheckType check);
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index db42d007b8e..e2c9bb8d6e5 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -49,6 +49,10 @@
#include "BLI_utildefines.h"
#include "BLI_fnmatch.h"
+#include "BLO_readfile.h"
+
+#include "BLT_translation.h"
+
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -69,6 +73,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) {
@@ -98,7 +104,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
/* set the default thumbnails size */
- sfile->params->thumbnail_size = 128;
+ sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
+ /* Show size column by default. */
+ sfile->params->details_flags = U_default.file_space_data.details_flags;
}
params = sfile->params;
@@ -161,6 +169,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag &= ~FILE_DIRSEL_ONLY;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
+ }
+ if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0;
+ }
+
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;
@@ -189,6 +204,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_archive"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ARCHIVE : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0;
}
@@ -258,26 +276,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->sort = RNA_property_enum_get(op->ptr, prop);
}
else {
- params->sort = FILE_SORT_ALPHA;
+ params->sort = U_default.file_space_data.sort_type;
}
if (params->display == FILE_DEFAULTDISPLAY) {
- if (params->display_previous == FILE_DEFAULTDISPLAY) {
- if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) {
- params->display = FILE_IMGDISPLAY;
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = FILE_SHORTDISPLAY;
- }
- }
- else {
- params->display = params->display_previous;
- }
+ params->display = U_default.file_space_data.display_type;
}
if (is_relative_path) {
@@ -291,10 +294,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
else {
/* default values, if no operator */
params->type = FILE_UNIX;
- params->flag |= FILE_HIDE_DOT;
+ params->flag |= U_default.file_space_data.flag;
params->flag &= ~FILE_DIRSEL_ONLY;
- params->display = FILE_SHORTDISPLAY;
- params->display_previous = FILE_DEFAULTDISPLAY;
+ params->display = FILE_VERTICALDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
@@ -330,6 +332,63 @@ short ED_fileselect_set_params(SpaceFile *sfile)
return 1;
}
+/* The subset of FileSelectParams.flag items we store into preferences. */
+#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT)
+
+void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
+{
+ wmOperator *op = sfile->op;
+ UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+
+ ED_fileselect_set_params(sfile);
+
+ if (!op) {
+ return;
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "display_type")) {
+ sfile->params->display = sfile_udata->display_type;
+ }
+ if (!RNA_struct_property_is_set(op->ptr, "sort_method")) {
+ sfile->params->sort = sfile_udata->sort_type;
+ }
+ sfile->params->thumbnail_size = sfile_udata->thumbnail_size;
+ sfile->params->details_flags = sfile_udata->details_flags;
+
+ /* Combine flags we take from params with the flags we take from userdef. */
+ sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) |
+ (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
+}
+
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but it's neglectable.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window, pass its size here so we
+ * can store that in the preferences. Otherwise NULL.
+ */
+void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2])
+{
+ UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
+ UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
+
+ sfile_udata_new->display_type = sfile->params->display;
+ sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size;
+ sfile_udata_new->sort_type = sfile->params->sort;
+ sfile_udata_new->details_flags = sfile->params->details_flags;
+ sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED;
+
+ if (temp_win_size) {
+ sfile_udata_new->temp_win_sizex = temp_win_size[0];
+ sfile_udata_new->temp_win_sizey = temp_win_size[1];
+ }
+
+ /* Tag prefs as dirty if something has changed. */
+ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
+ U.runtime.is_dirty = true;
+ }
+}
+
void ED_fileselect_reset_params(SpaceFile *sfile)
{
sfile->params->type = FILE_UNIX;
@@ -344,7 +403,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile)
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
- if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) {
+ if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) {
BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE);
}
}
@@ -372,10 +431,10 @@ 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;
+ return numfiles * layout->flow_columns;
}
}
@@ -395,19 +454,19 @@ 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)) {
- CLAMP(colmin, 0, layout->columns - 1);
+ if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) ||
+ is_inside(colmax, rowmax, layout->flow_columns, layout->rows)) {
+ CLAMP(colmin, 0, layout->flow_columns - 1);
CLAMP(rowmin, 0, layout->rows - 1);
- CLAMP(colmax, 0, layout->columns - 1);
+ CLAMP(colmax, 0, layout->flow_columns - 1);
CLAMP(rowmax, 0, layout->rows - 1);
}
- if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) {
+ if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) {
sel.first = -1;
}
else {
@@ -415,10 +474,10 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.first = layout->rows * colmin + rowmin;
}
else {
- sel.first = colmin + layout->columns * rowmin;
+ sel.first = colmin + layout->flow_columns * rowmin;
}
}
- if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) {
+ if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) {
sel.last = -1;
}
else {
@@ -426,7 +485,7 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r
sel.last = layout->rows * colmax + rowmax;
}
else {
- sel.last = colmax + layout->columns * rowmax;
+ sel.last = colmax + layout->flow_columns * rowmax;
}
}
@@ -443,9 +502,9 @@ 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) {
+ if (offsetx > layout->flow_columns - 1) {
return -1;
}
if (offsety > layout->rows - 1) {
@@ -456,27 +515,123 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
active_file = layout->rows * offsetx + offsety;
}
else {
- active_file = offsetx + layout->columns * offsety;
+ active_file = offsetx + layout->flow_columns * offsety;
}
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 +
- ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y);
+ ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x);
+ *y = layout->offset_top + layout->tile_border_y +
+ ((tile) / layout->flow_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_attribute_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->attribute_column_header_h;
+ return BLI_rcti_isect_pt(&header_rect, x, y);
+}
+
+bool file_attribute_column_type_enabled(const FileSelectParams *params,
+ FileAttributeColumnType 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).
+ */
+FileAttributeColumnType file_attribute_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 (FileAttributeColumnType column = 0; column < ATTRIBUTE_COLUMN_MAX; column++) {
+ if (!file_attribute_column_type_enabled(params, column)) {
+ continue;
+ }
+ const int width = layout->attribute_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 +667,52 @@ float file_font_pointsize(void)
#endif
}
-static void column_widths(FileSelectParams *params, struct FileLayout *layout)
+static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout)
{
- int i;
+ FileAttributeColumn *columns = layout->attribute_columns;
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
+ const int pad = small_size ? 0 : ATTRIBUTE_COLUMN_PADDING * 2;
- for (i = 0; i < MAX_FILE_COLUMN; ++i) {
- layout->column_widths[i] = 0;
+ for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) {
+ layout->attribute_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 6789, 23:59") +
+ pad;
+ columns[COLUMN_SIZE].width = file_string_width(small_size ? "98.7 M" : "098.7 MiB") + 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 (FileAttributeColumnType column_type = ATTRIBUTE_COLUMN_MAX - 1; column_type >= 0;
+ column_type--) {
+ if ((column_type == COLUMN_NAME) ||
+ !file_attribute_column_type_enabled(params, column_type)) {
+ continue;
+ }
+ remwidth -= columns[column_type].width;
+ }
+ columns[COLUMN_NAME].width = remwidth;
+ }
+}
+
+static void file_attribute_columns_init(const FileSelectParams *params, FileLayout *layout)
+{
+ file_attribute_columns_widths(params, layout);
+
+ layout->attribute_columns[COLUMN_NAME].name = N_("Name");
+ layout->attribute_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA;
+ layout->attribute_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_DATETIME].name = N_("Date Modified");
+ layout->attribute_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME;
+ layout->attribute_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_LEFT;
+ layout->attribute_columns[COLUMN_SIZE].name = N_("Size");
+ layout->attribute_columns[COLUMN_SIZE].sort_type = FILE_SORT_SIZE;
+ layout->attribute_columns[COLUMN_SIZE].text_align = UI_STYLE_TEXT_RIGHT;
}
void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
@@ -533,7 +720,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;
@@ -560,61 +746,69 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
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);
- if (layout->columns > 0) {
- layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = 0;
+ if (layout->flow_columns > 0) {
+ layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero
}
else {
- layout->columns = 1;
+ layout->flow_columns = 1;
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->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->flow_columns = 1;
+ layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
+ layout->offset_top = layout->attribute_column_header_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);
+ file_attribute_columns_init(params, layout);
+
+ layout->rows = MAX2(rowcount, numfiles);
+ BLI_assert(layout->rows != 0);
+ 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->prv_border_x = 0;
- layout->prv_border_y = 0;
layout->tile_h = textheight * 3 / 2;
+ layout->attribute_column_header_h = 0;
+ layout->offset_top = layout->attribute_column_header_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;
+ file_attribute_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
+ layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
}
else {
layout->rows = 1;
- layout->columns = numfiles + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero
}
- layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) +
+ layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) +
layout->tile_border_x * 2;
layout->flag = FILE_LAYOUT_HOR;
}
- params->display_previous = params->display;
layout->dirty = false;
}
@@ -742,7 +936,7 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
int nentries = filelist_files_ensure(sfile->files);
int i;
- for (i = 0; i < nentries; ++i) {
+ for (i = 0; i < nentries; i++) {
FileDirEntry *file = filelist_file(sfile->files, i);
UI_autocomplete_update_name(autocpl, file->relpath);
}
@@ -771,6 +965,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
return;
}
if (sfile->op) {
+ wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
+ int win_size[2];
+
+ if (temp_win) {
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+ }
+ ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL);
+
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index b50c37baae6..7faa2b883f2 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -404,7 +404,7 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
fprintf(fp, "[Recent]\n");
for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT);
fsm_iter && (nwritten < FSMENU_RECENT_MAX);
- fsm_iter = fsm_iter->next, ++nwritten) {
+ fsm_iter = fsm_iter->next, nwritten++) {
if (fsm_iter->path && fsm_iter->save) {
fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
@@ -492,20 +492,17 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Flee from horrible win querying hover floppy drives! */
if (i > 1) {
- /* Try to get volume label as well... */
+ /* Try to get a friendly drive description. */
+ SHFILEINFOW shFile = {0};
BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
- if (GetVolumeInformationW(
- wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) {
- size_t label_len;
-
- BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4);
-
- label_len = MIN2(strlen(line), FILE_MAXDIR - 6);
- BLI_snprintf(line + label_len, 6, " (%.2s)", tmps);
-
+ if (SHGetFileInfoW(wline, 0, &shFile, sizeof(SHFILEINFOW), SHGFI_DISPLAYNAME)) {
+ BLI_strncpy_wchar_as_utf8(line, shFile.szDisplayName, FILE_MAXDIR);
name = line;
}
}
+ if (name == NULL) {
+ name = tmps;
+ }
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 1fd878e4662..d63fcf402de 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,6 +55,40 @@
#include "filelist.h"
#include "GPU_framebuffer.h"
+static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ return ar;
+ }
+
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag = RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ return ar;
+ }
+
+ /* add subdiv level; after execute region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_RIGHT;
+
+ return ar;
+}
+
/* ******************** default callbacks for file space ***************** */
static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -78,17 +112,14 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
- BLI_addtail(&sfile->regionbase, ar);
- 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");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_TOP;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ /* Tool props and execute region are added as needed, see file_refresh(). */
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -201,9 +232,50 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
+static void file_ensure_valid_region_state(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ ScrArea *sa,
+ SpaceFile *sfile,
+ FileSelectParams *params)
+{
+ ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
+ ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
+
+ /* If there's an file-operation, ensure we have the option and execute region */
+ if (sfile->op && (ar_props == NULL)) {
+ ar_execute = file_execute_region_ensure(sa, ar_ui);
+ ar_props = file_tool_props_region_ensure(sa, ar_execute);
+
+ if (params->flag & FILE_HIDE_TOOL_PROPS) {
+ ar_props->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ }
+
+ needs_init = true;
+ }
+ /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
+ else if ((sfile->op == NULL) && (ar_props != NULL)) {
+ BLI_assert(ar_execute != NULL);
+
+ ED_region_remove(C, sa, ar_props);
+ ED_region_remove(C, sa, ar_execute);
+ needs_init = true;
+ }
+
+ if (needs_init) {
+ ED_area_initialize(wm, win, sa);
+ }
+}
+
static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
struct FSMenu *fsmenu = ED_fsmenu_get();
@@ -217,15 +289,16 @@ 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_setfilter_options(sfile->files,
- (params->flag & FILE_FILTER) != 0,
- (params->flag & FILE_HIDE_DOT) != 0,
- false, /* TODO hide_parent, should be controllable? */
- params->filter,
- params->filter_id,
- params->filter_glob,
- params->filter_search);
+ 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,
+ true, /* Just always hide parent, prefer to not add an extra user option for this. */
+ params->filter,
+ params->filter_id,
+ params->filter_glob,
+ params->filter_search);
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -254,7 +327,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
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);
+ WM_event_remove_timer_notifier(wm, win, sfile->previews_timer);
sfile->previews_timer = NULL;
}
}
@@ -268,11 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
/* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
- /* Create TOOLS/TOOL_PROPS regions. */
- file_tools_region(sa);
-
- ED_area_initialize(wm, CTX_wm_window(C), sa);
+ if (sa) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
}
ED_area_tag_redraw(sa);
@@ -406,6 +476,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 +514,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,13 +529,13 @@ 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);
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
@@ -538,7 +615,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);
@@ -550,22 +628,24 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
static void file_ui_region_draw(const bContext *C, ARegion *ar)
{
- float col[3];
- /* clear */
- UI_GetThemeColor3fv(TH_BACK, col);
- GPU_clear_color(col[0], col[1], col[2], 0.0);
- GPU_clear(GPU_COLOR_BIT);
+ ED_region_panels(C, ar);
+}
- /* scrolling here is just annoying, disable it */
- ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur);
- ar->v2d.cur.ymin = 0;
+static void file_execution_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap;
- /* set view2d view matrix for scrolling (without scrollers) */
- UI_view2d_view_ortho(&ar->v2d);
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
- file_draw_buttons(C, ar);
+ /* own keymap */
+ keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0);
+ WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap);
+}
- UI_view2d_view_restore(C);
+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),
@@ -656,13 +736,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->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);
+ file_execute_region_panels_register(art);
+
/* regions: channels (directories) */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_TOOLS;
@@ -677,14 +766,14 @@ void ED_spacetype_file(void)
/* regions: tool properties */
art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
art->regionid = RGN_TYPE_TOOL_PROPS;
- art->prefsizex = 0;
- art->prefsizey = 360;
+ art->prefsizex = 240;
+ art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
art->listener = file_tools_region_listener;
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
- file_panels_register(art);
+ file_tool_props_region_panels_register(art);
BKE_spacetype_register(st);
}