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