From 9821dd72bac89053ce0213e68116855910c681e9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 31 Aug 2019 17:28:48 +1000 Subject: Cleanup: rename natural string comparison --- source/blender/editors/space_file/filelist.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index f7dda1defe8..ee86a583974 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -434,7 +434,7 @@ 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 BLI_strcasecmp_natural(name1, name2); } static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) @@ -461,7 +461,7 @@ static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) name1 = entry1->name; name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_strcasecmp_natural(name1, name2); } static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) @@ -488,7 +488,7 @@ static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) name1 = entry1->name; name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_strcasecmp_natural(name1, name2); } static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2) @@ -546,7 +546,7 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void name1 = entry1->name; name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_strcasecmp_natural(name1, name2); } void filelist_sort(struct FileList *filelist) -- cgit v1.2.3 From ee8f69c96cba62b083fb089432cddd0bce5d08e1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 3 Sep 2019 15:43:38 +0200 Subject: UI: File Browser Design Overhaul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a general redesign of the File Browser GUI and interaction methods. For screenshots, check patch D5601. Main changes in short: * File Browser as floating window * New layout of regions * Popovers for view and filter options * Vertical list view with interactive column header * New and updated icons * Keymap consistency fixes * Many tweaks and fixes to the drawing of views ---- General: * The file browser now opens as temporary floating window. It closes on Esc. The header is hidden then. * When the file browser is opened as regular editor, the header remains visible. * All file browser regions are now defined in Python (the button layout). * Adjusted related operator UI names. Keymap: Keymap is now consistent with other list-based views in Blender, such as the Outliner. * Left click to select, double-click to open * Right-click context menus * Shift-click to fill selection * Ctrl-click to extend selection Operator options: These previously overlapped with the source list, which caused numerous issues with resizing and presenting many settings in a small panel area. It was also generally inconsistent with Blender. * Moved to new sidebar, which can easily be shown or hidden using a prominent Options toggle. * IO operators have new layouts to match this new sidebar, using sub-panels. This will have to be committed separately (Add-on repository). * If operators want to show the options by default, they have the option to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise they are hidden by default. General Layout: The layout has been changed to be simpler, more standard, and fits better in with Blender 2.8. * More conventional layout (file path at top, file name at the bottom, execute/cancel buttons in bottom right). * Use of popovers to group controls, and allow for more descriptive naming. * Search box is always live now, just like Outliner. Views: * Date Modified column combines both date and time, also uses user friendly strings for recent dates (i.e. "Yesterday", "Today"). * Details columns (file size, modification date/time) are now toggleable for all display types, they are not hardcoded per display type. * File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They are now also calculated using base 10 of course. * Option to sort in inverse order. Vertical List View: * This view now used a much simpler single vertical list with columns for information. * Users can click on the headers of these columns to order by that category, and click again to reverse the ordering. Icons: * Updated icons by Jendrzych, with better centering. * Files and folders have new icons in Icon view. * Both files and folders have reworked superimposed icons that show users the file/folder type. * 3D file documents correctly use the 3d file icon, which was unused previously. * Workspaces now show their icon on Link/Append - also when listed in the Outliner. Minor Python-API breakage: * `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and `LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`. Removes the feature where directories would automatically be created if they are entered into the file path text button, but don't exist. We were not sure if users use it enough to keep it. We can definitely bring it back. ---- //Combined effort by @billreynish, @harley, @jendrzych, my university colleague Brian Meisenheimer and myself.// Differential Revision: https://developer.blender.org/D5601 Reviewers: Brecht, Bastien --- source/blender/editors/space_file/file_draw.c | 637 +++++++++++------------- source/blender/editors/space_file/file_intern.h | 16 +- source/blender/editors/space_file/file_ops.c | 112 ++++- source/blender/editors/space_file/file_panels.c | 1 + source/blender/editors/space_file/filelist.c | 153 +++--- source/blender/editors/space_file/filelist.h | 2 +- source/blender/editors/space_file/filesel.c | 274 +++++++--- source/blender/editors/space_file/space_file.c | 118 +++-- 8 files changed, 767 insertions(+), 546 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 3a6d59c1dbf..0083fc244d8 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -26,6 +26,7 @@ #include #include "BLI_blenlib.h" +#include "BLI_fileops_types.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -77,234 +78,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 +122,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 +135,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 +177,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 use_dropshadow = !is_icon && + (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -442,13 +215,27 @@ static void file_draw_preview(uiBlock *block, /* shadow */ if (use_dropshadow) { - UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + UI_draw_box_shadow(128, (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) { + /* File and Folder icons draw with lowered opacity until we add themes */ + col[3] = 0.6f; + /* Use dark images if background is light */ + float bg[3]; + UI_GetThemeColor3fv(TH_BACK, bg); + if (rgb_to_grayscale(bg) > 0.5f) { + col[0] = 0; + col[1] = 0; + col[2] = 0; + } + } + else if (typeflags & FILE_TYPE_FTFONT) { UI_GetThemeColor4fv(TH_TEXT, col); } @@ -477,30 +264,61 @@ 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 = MIN2(icon_aspect, 0.7); + uchar icon_color[4] = {255, 255, 255, 255}; + float bg[3]; + /* base this off theme color of file or folder later */ + UI_GetThemeColor3fv(TH_BACK, bg); + if (rgb_to_grayscale(bg) > 0.5f) { + icon_color[0] = 0; + icon_color[1] = 0; + icon_color[2] = 0; + } + 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.65f)); + 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) { GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint pos_attr = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint col_attr = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GPU_PRIM_LINE_LOOP, 4); + immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.15f); + immVertex2f(pos_attr, (float)xco + 1, (float)(yco + ey)); + immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.2f); + immVertex2f(pos_attr, (float)(xco + ex), (float)(yco + ey)); + immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.2f); + immVertex2f(pos_attr, (float)(xco + ex), (float)yco + 1); + immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.3f); + immVertex2f(pos_attr, (float)xco + 1, (float)yco + 1); + immEnd(); 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 +375,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 +384,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 +453,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 +643,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 +666,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 +707,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 +730,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 +770,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 +807,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 +828,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..61f13098783 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -30,9 +30,11 @@ struct ARegion; struct ARegionType; struct FileSelectParams; struct SpaceFile; +struct View2D; /* file_ops.c */ struct ARegion *file_tools_region(struct ScrArea *sa); +struct ARegion *file_tool_props_region(struct ScrArea *sa); /* file_draw.c */ #define TILE_BORDER_X (UI_UNIT_X / 4) @@ -42,9 +44,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 +67,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 +116,16 @@ 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_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); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index eb5f02b6e13..bd018581d32 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! */ @@ -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,7 +444,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 +497,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; } @@ -691,7 +695,7 @@ static bool file_walk_select_do(bContext *C, 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)) { @@ -1185,7 +1189,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 +1238,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); @@ -1713,7 +1764,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) { @@ -1998,7 +2049,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot) ot->idname = "FILE_OT_directory_new"; /* api callbacks */ - ot->invoke = WM_operator_confirm; ot->exec = file_directory_new_exec; ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ @@ -2260,10 +2310,29 @@ ARegion *file_tools_region(ScrArea *sa) 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; +} + +ARegion *file_tool_props_region(ScrArea *sa) +{ + ARegion *ar, *arnew; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) { + return ar; + } + + /* add subdiv level; after execute region */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE); + + /* is error! */ + if (ar == NULL) { + return NULL; + } + + arnew = MEM_callocN(sizeof(ARegion), "tool props for file"); + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_TOOL_PROPS; + arnew->alignment = RGN_ALIGN_RIGHT; return arnew; } @@ -2292,6 +2361,17 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } +static bool file_filenum_poll(bContext *C) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + + if (!ED_operator_file_active(C)) { + return false; + } + + return sfile->params && (sfile->params->action_type == FILE_SAVE); +} + /** * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. */ @@ -2349,7 +2429,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..b41358f575f 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -103,6 +103,7 @@ 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; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index ee86a583974..fdc101f3d82 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -329,25 +329,20 @@ 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 6 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_FOLDER = 1, + SPECIAL_IMG_PARENT = 2, + SPECIAL_IMG_DRIVE_FIXED = 3, + SPECIAL_IMG_DRIVE_ATTACHED = 4, + SPECIAL_IMG_DRIVE_REMOTE = 5, SPECIAL_IMG_MAX, }; @@ -369,6 +364,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 +428,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 +443,14 @@ static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2) name1 = entry1->name; name2 = entry2->name; - return BLI_strcasecmp_natural(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 +462,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_strcasecmp_natural(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 +490,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_strcasecmp_natural(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 +528,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 +551,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_strcasecmp_natural(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 +657,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 +679,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 +699,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 +727,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; @@ -904,42 +928,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,10 +995,13 @@ 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; @@ -1243,7 +1240,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 +2126,9 @@ 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_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,9 +2178,9 @@ 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; default: 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..3223fe0c6ce 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -49,6 +49,8 @@ #include "BLI_utildefines.h" #include "BLI_fnmatch.h" +#include "BLT_translation.h" + #include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_main.h" @@ -69,6 +71,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 +103,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; @@ -161,6 +167,10 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->flag &= ~FILE_DIRSEL_ONLY; } + 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; @@ -261,6 +271,10 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->sort = FILE_SORT_ALPHA; } + if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) { + params->action_type = RNA_property_enum_get(op->ptr, prop); + } + if (params->display == FILE_DEFAULTDISPLAY) { if (params->display_previous == FILE_DEFAULTDISPLAY) { if (U.uiflag & USER_SHOW_THUMBNAILS) { @@ -268,11 +282,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 +307,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; @@ -344,7 +358,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 +386,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 +409,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 +429,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 +440,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 +457,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,25 +470,121 @@ 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) @@ -512,20 +622,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 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 (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 +675,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,57 +701,66 @@ 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; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 1fd878e4662..1befdd52d7d 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -72,23 +72,40 @@ 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); ar->regiontype = RGN_TYPE_TOOLS; ar->alignment = RGN_ALIGN_LEFT; + /* Tools region (lower split region) */ + ar = MEM_callocN(sizeof(ARegion), "lower tools region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + + /* Execute region */ + ar = MEM_callocN(sizeof(ARegion), "execute region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_EXECUTE; + ar->alignment = RGN_ALIGN_BOTTOM; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + /* Tool props region is added as needed. */ +#if 0 /* 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->alignment = RGN_ALIGN_RIGHT; +#endif /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for file"); @@ -204,6 +221,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) 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 +235,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 +273,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; } } @@ -269,10 +288,20 @@ 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. */ + /* Create TOOLS region. */ file_tools_region(sa); - ED_area_initialize(wm, CTX_wm_window(C), sa); + ED_area_initialize(wm, win, sa); + } + if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) { + /* Create TOOL_PROPS region. */ + ARegion *region_props = file_tool_props_region(sa); + + if (params->flag & FILE_HIDE_TOOL_PROPS) { + region_props->flag |= RGN_FLAG_HIDDEN; + } + + ED_area_initialize(wm, win, sa); } ED_area_tag_redraw(sa); @@ -406,6 +435,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 +473,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 +488,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 +575,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 +588,18 @@ 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); - - /* scrolling here is just annoying, disable it */ - ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur); - ar->v2d.cur.ymin = 0; - - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(&ar->v2d); + ED_region_panels(C, ar); +} - file_draw_buttons(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; +} - 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 +690,21 @@ 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); + /* regions: channels (directories) */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); art->regionid = RGN_TYPE_TOOLS; @@ -677,8 +719,8 @@ 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; -- cgit v1.2.3 From 9e3cd98529dc2f8dbb00357126d5286ee74fae1f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 3 Sep 2019 19:50:04 +0200 Subject: Fix T69451: Walk-select in empty directory asserts Code assumed the '..' was there, which isn't the case any more. Just early exiting for empty directories is fine. --- source/blender/editors/space_file/file_ops.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index bd018581d32..d738a20bf53 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -584,6 +584,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)) { @@ -692,6 +697,11 @@ 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); -- cgit v1.2.3 From 197653e08749b8fd3a5cbec212438df391b8b41c Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 3 Sep 2019 23:05:32 +0200 Subject: Fix selecting multiple files ignoring first file E.g. box selecting wouldn't allow selecting the first file. Work selection and shift/ctrl selection had similar issues. Code assumed that the first item was the '..' parent item and manually removed it from the selection. I could just remove this special handling, but instead I made the behavior more dynamic. So the file list checks if the '..' item is there and only then applies special treatment. That way we can easily bring the '..' item back or make it optional if wanted. --- source/blender/editors/space_file/file_ops.c | 22 +++++++++++----------- source/blender/editors/space_file/filelist.c | 13 +++++++++++++ source/blender/editors/space_file/filelist.h | 4 ++++ 3 files changed, 28 insertions(+), 11 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d738a20bf53..5168300d21e 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -450,7 +450,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op) /* 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); @@ -518,8 +518,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (extend) { /* unselect '..' parent entry - it's not supposed to be selected if more * than one file is selected */ - filelist_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) { @@ -618,7 +617,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); @@ -635,7 +634,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 */ @@ -650,11 +649,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); @@ -662,6 +656,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( @@ -732,7 +732,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; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index fdc101f3d82..46302e0d087 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2299,6 +2299,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 9af0b7d623f..9b1107294ff 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -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); -- cgit v1.2.3 From 45d4c925799e94c6d442a9a9066af2d3305724e1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 4 Sep 2019 16:21:42 +0200 Subject: Move file execute region back to C, fixing bugs We moved this to Python too quickly, causing the following regressions: * No auto completion for file names * Additional handling not applied on changes, like automatic extension appending (see file_filename_enter_handle) * Red highlight missing when the file name already exists Note that earlier (before the file browser redesign), this didn't use the panel and layout code at all. So even if it's still not in Python, at least it's integrated into regular panel management now. OS-specific ordering of the open and cancel button is kept. Fixes T69457. --- source/blender/editors/space_file/file_intern.h | 3 +- source/blender/editors/space_file/file_panels.c | 110 +++++++++++++++++++++++- source/blender/editors/space_file/space_file.c | 3 +- 3 files changed, 113 insertions(+), 3 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 61f13098783..4b86f38f8e4 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -136,7 +136,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_panels.c b/source/blender/editors/space_file/file_panels.c index b41358f575f..290b5385bf7 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; @@ -109,3 +109,111 @@ void file_panels_register(ARegionType *art) pt->draw = file_panel_operator; BLI_addtail(&art->paneltypes, pt); } + +static void file_panel_execution_cancel_button(uiBlock *block) +{ + uiDefButO(block, + UI_BTYPE_BUT, + "FILE_OT_cancel", + WM_OP_EXEC_REGION_WIN, + IFACE_("Cancel"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + ""); +} + +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; + + 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, ¶ms_rna_ptr); + + row = uiLayoutRow(pa->layout, false); + uiLayoutSetScaleX(row, 1.3f); + 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, + ¶ms_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); + + /* 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); + + { + if (windows_layout == false) { + file_panel_execution_cancel_button(block); + } + but = uiDefButO(block, + UI_BTYPE_BUT, + "FILE_OT_execute", + WM_OP_EXEC_REGION_WIN, + params->title, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + ""); + /* Just a display hint. */ + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); + if (windows_layout) { + file_panel_execution_cancel_button(block); + } + } +} + +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/space_file.c b/source/blender/editors/space_file/space_file.c index 1befdd52d7d..7525ac5b705 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -704,6 +704,7 @@ void ED_spacetype_file(void) 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"); @@ -726,7 +727,7 @@ void ED_spacetype_file(void) 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); } -- cgit v1.2.3 From d813cc706d79daf84100f9090db5f11c917e50c0 Mon Sep 17 00:00:00 2001 From: William Reynish Date: Thu, 5 Sep 2019 07:54:41 +0200 Subject: File Browser: Add Zip files as native recognised file type Differential Revision: https://developer.blender.org/D5683 Reviewers: Brecht --- source/blender/editors/space_file/filelist.c | 8 ++++++++ source/blender/editors/space_file/filesel.c | 3 +++ 2 files changed, 11 insertions(+) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 46302e0d087..df783358625 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1006,6 +1006,9 @@ static int filelist_geticon_ex(const int typeflag, 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) { @@ -2126,6 +2129,9 @@ 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; } @@ -2183,6 +2189,8 @@ int ED_file_extension_icon(const char *path) 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; } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 3223fe0c6ce..d683c9d5c98 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -199,6 +199,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; } -- cgit v1.2.3 From 9972d6c3062010bea514c9e382b0a99275d63a89 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 6 Sep 2019 01:22:35 +0200 Subject: UI: Bring back features for file path button Adds back auto-completion and auto-creation (inserting a non-existing file-path would create it) for the file path button. The second feature was left out knowingly, but seems there are reasonable use cases for it. We can't add these features to the button in the Python script, we have to call into C. So using a template to do that. Note that this is based on the old file browser code, I've copied over the TODO comment. --- source/blender/editors/space_file/file_draw.c | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 0083fc244d8..722cb885614 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -71,6 +71,52 @@ #include "file_intern.h" // own include +void ED_file_path_button(bScreen *screen, + const SpaceFile *sfile, + FileSelectParams *params, + uiBlock *block) +{ + PointerRNA params_rna_ptr; + uiBut *but; + + RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, ¶ms_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, + ¶ms_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); + } + + /* clear func */ + UI_block_func_set(block, NULL, NULL, NULL); +} + /* Dummy helper - we need dynamic tooltips here. */ static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) { -- cgit v1.2.3 From e10f8c27a256eb8881bb17eb1ba7426573ff208a Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 6 Sep 2019 11:06:32 +0200 Subject: UI: Confirmation prompt for file path auto-create This confirmation prompt was there earlier, we removed the prompts for creating new directories all together, but in this case it's reasonable. Without it, it's simply too easy to create new directories by accident. --- source/blender/editors/space_file/file_ops.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 5168300d21e..cb3b11fb8e6 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2059,6 +2059,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot) ot->idname = "FILE_OT_directory_new"; /* api callbacks */ + 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 */ @@ -2067,6 +2068,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. */ @@ -2198,6 +2200,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)); -- cgit v1.2.3 From 5fd46d27f57f0abacf202cc6d147191998133557 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 6 Sep 2019 11:21:47 +0200 Subject: Fix failing assert on directory auto-creation The failing assert was there before the recent file browser design overhaul. Might have been in there for quite a while in fact. Auto-creation in this case means that the file path would be created if a non-existent path was entered in the file browser path button. --- source/blender/editors/space_file/file_ops.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index cb3b11fb8e6..9939351ee45 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1976,6 +1976,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"); @@ -2024,9 +2025,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 */ @@ -2039,7 +2042,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); } -- cgit v1.2.3 From 24d05b5ff9d6d85a7ff8f58b47bef31b5dbcec81 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 6 Sep 2019 07:44:50 -0700 Subject: UI: File Browser Large Icon Update Replaces the large icons used in the File Browser with updated versions by Andrzej Ambroz (jendrzych). Differential Revision: https://developer.blender.org/D5698 Reviewed by Brecht Van Lommel --- source/blender/editors/space_file/file_draw.c | 20 ++++++++++---------- source/blender/editors/space_file/filelist.c | 13 +++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 722cb885614..3e16a8473ad 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -316,18 +316,18 @@ static void file_draw_preview(uiBlock *block, if (is_icon) { const float icon_size = 16.0f / icon_aspect * U.dpi_fac; - float icon_opacity = MIN2(icon_aspect, 0.7); - uchar icon_color[4] = {255, 255, 255, 255}; - float bg[3]; - /* base this off theme color of file or folder later */ - UI_GetThemeColor3fv(TH_BACK, bg); - if (rgb_to_grayscale(bg) > 0.5f) { - icon_color[0] = 0; - icon_color[1] = 0; - icon_color[2] = 0; + float icon_opacity = 0.3f; + uchar icon_color[4] = {0, 0, 0, 255}; + float bgcolor[4]; + UI_GetThemeColor4fv(TH_TEXT, 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.65f)); + 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); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index df783358625..1a7608ba291 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -334,15 +334,16 @@ enum { #define SPECIAL_IMG_SIZE 256 #define SPECIAL_IMG_ROWS 1 -#define SPECIAL_IMG_COLS 6 +#define SPECIAL_IMG_COLS 7 enum { SPECIAL_IMG_DOCUMENT = 0, - SPECIAL_IMG_FOLDER = 1, - SPECIAL_IMG_PARENT = 2, - SPECIAL_IMG_DRIVE_FIXED = 3, - SPECIAL_IMG_DRIVE_ATTACHED = 4, - SPECIAL_IMG_DRIVE_REMOTE = 5, + 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, }; -- cgit v1.2.3 From 5289b16d775d3bddd2815f24d56a5eccc53f0c75 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 6 Sep 2019 10:02:18 -0700 Subject: UI: File Browser Preview Outlines File Browser image thumbnails get just a contrasting outline and no shadow. Differential Revision: https://developer.blender.org/D5708 Reviewed by Brecht Van Lommel --- source/blender/editors/space_file/file_draw.c | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 3e16a8473ad..e11ca06494d 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -223,7 +223,7 @@ static void file_draw_preview(uiBlock *block, float scaledx, scaledy; float scale; int ex, ey; - bool use_dropshadow = !is_icon && + bool show_outline = !is_icon && (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -259,11 +259,6 @@ 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(128, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); - } - GPU_blend(true); /* the large image */ @@ -344,23 +339,21 @@ static void file_draw_preview(uiBlock *block, } } - /* border */ - if (use_dropshadow) { + /* Contrasting outline around some preview types. */ + if (show_outline) { GPUVertFormat *format = immVertexFormat(); - uint pos_attr = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint col_attr = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - immBegin(GPU_PRIM_LINE_LOOP, 4); - immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.15f); - immVertex2f(pos_attr, (float)xco + 1, (float)(yco + ey)); - immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.2f); - immVertex2f(pos_attr, (float)(xco + ex), (float)(yco + ey)); - immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.2f); - immVertex2f(pos_attr, (float)(xco + ex), (float)yco + 1); - immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.3f); - immVertex2f(pos_attr, (float)xco + 1, (float)yco + 1); - immEnd(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + 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(); } -- cgit v1.2.3 From 0b2d1badecc48b5cbff5ec088b29c6e9acc5e1d0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 8 Sep 2019 00:12:26 +1000 Subject: Cleanup: use post increment/decrement When the result isn't used, prefer post increment/decrement (already used nearly everywhere in Blender). --- source/blender/editors/space_file/file_ops.c | 4 ++-- source/blender/editors/space_file/filelist.c | 2 +- source/blender/editors/space_file/filesel.c | 4 ++-- source/blender/editors/space_file/fsmenu.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 9939351ee45..c6061cb6f58 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -239,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; } @@ -1744,7 +1744,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; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 1a7608ba291..27cccf6bab1 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -895,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; } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index d683c9d5c98..be8ebc18c2c 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -631,7 +631,7 @@ static void file_attribute_columns_widths(const FileSelectParams *params, FileLa const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); const int pad = small_size ? 0 : ATTRIBUTE_COLUMN_PADDING * 2; - for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; ++i) { + for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) { layout->attribute_columns[i].width = 0; } @@ -895,7 +895,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); } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index b50c37baae6..c7a139a8b24 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)) { -- cgit v1.2.3 From 1601413b63c1355fbb467c45b740c4f021b43f5f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sun, 8 Sep 2019 20:31:12 +0200 Subject: UI: Allow file number shortcuts ouside main region Makes the numpad + and - type of shortcuts to increase/decrease the file number suffix work in the upper and lower bar of the file browser. Had to add keymap handlers to the execute region for this to work. --- source/blender/editors/space_file/space_file.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 7525ac5b705..d6a4eafc658 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -593,8 +593,14 @@ static void file_ui_region_draw(const bContext *C, ARegion *ar) static void file_execution_region_init(wmWindowManager *wm, ARegion *ar) { + wmKeyMap *keymap; + 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); + WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); } static void file_execution_region_draw(const bContext *C, ARegion *ar) -- cgit v1.2.3 From 8127bbbe39cb10aae65883db94684791fbbd5aa9 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 9 Sep 2019 15:23:00 +0200 Subject: Cleanup: clang-format --- source/blender/editors/space_file/file_draw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index e11ca06494d..ca26a56a26e 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -224,7 +224,7 @@ static void file_draw_preview(uiBlock *block, float scale; int ex, ey; bool show_outline = !is_icon && - (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); + (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -315,8 +315,7 @@ static void file_draw_preview(uiBlock *block, uchar icon_color[4] = {0, 0, 0, 255}; float bgcolor[4]; UI_GetThemeColor4fv(TH_TEXT, bgcolor); - if (rgb_to_grayscale(bgcolor) < 0.5f) - { + if (rgb_to_grayscale(bgcolor) < 0.5f) { icon_color[0] = 255; icon_color[1] = 255; icon_color[2] = 255; -- cgit v1.2.3 From 2aa3e9c67cc554dd285f37147e83d5e6f82625c3 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 9 Sep 2019 16:36:10 +0200 Subject: UI: Add superimposed + and - icons for file number Brings back + and - icons to the file name button, but now as superimposed icons. --- source/blender/editors/space_file/file_panels.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 290b5385bf7..b0fed1fafd4 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -132,7 +132,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) uiBlock *block = uiLayoutGetBlock(pa->layout); uiBut *but; uiLayout *row; - PointerRNA params_rna_ptr; + PointerRNA params_rna_ptr, *but_extra_rna_ptr; const bool overwrite_alert = file_draw_check_exists(sfile); const bool windows_layout = @@ -176,6 +176,15 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) * immediate ui_apply_but_func but only after button deactivates */ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); + if (params->action_type == FILE_SAVE) { + 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); -- cgit v1.2.3 From 6d4b311888d01f32381d8838a440981134613d40 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Mon, 9 Sep 2019 08:29:21 -0700 Subject: UI: File Browser Sizes in Binary for Windows This adds per-platform change so Windows users will see file sizes calculated with a base of 1024. Differential Revision: https://developer.blender.org/D5714 Reviewed by Brecht Van Lommel --- source/blender/editors/space_file/filesel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index be8ebc18c2c..e54f13e9356 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -639,7 +639,7 @@ static void file_attribute_columns_widths(const FileSelectParams *params, FileLa 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 MB") + 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; } -- cgit v1.2.3 From 8f55794c0e803ec5454febe2e45651c721f62c8f Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 10 Sep 2019 08:07:39 -0700 Subject: UI: File Browser Custom Folder Color Allows file browser folders to be shown in a theme-selectable color, default of manila. Differential Revision: https://developer.blender.org/D5713 Reviewed by Brecht Van Lommel --- source/blender/editors/space_file/file_draw.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index ca26a56a26e..0aec6d5e6a0 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -138,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)); @@ -265,15 +262,11 @@ static void file_draw_preview(uiBlock *block, float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; if (is_icon) { - /* File and Folder icons draw with lowered opacity until we add themes */ - col[3] = 0.6f; - /* Use dark images if background is light */ - float bg[3]; - UI_GetThemeColor3fv(TH_BACK, bg); - if (rgb_to_grayscale(bg) > 0.5f) { - col[0] = 0; - col[1] = 0; - col[2] = 0; + if (typeflags & FILE_TYPE_DIR) { + UI_GetThemeColor4fv(TH_ICON_FOLDER, col); + } + else { + UI_GetThemeColor4fv(TH_TEXT, col); } } else if (typeflags & FILE_TYPE_FTFONT) { @@ -314,7 +307,7 @@ static void file_draw_preview(uiBlock *block, float icon_opacity = 0.3f; uchar icon_color[4] = {0, 0, 0, 255}; float bgcolor[4]; - UI_GetThemeColor4fv(TH_TEXT, bgcolor); + UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); if (rgb_to_grayscale(bgcolor) < 0.5f) { icon_color[0] = 255; icon_color[1] = 255; -- cgit v1.2.3 From 42c062c98a2e8e48a63d909ec39ed7d6677a7504 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 10 Sep 2019 18:36:05 +0200 Subject: UI: File browser deselect on click on empty space For the default and industry compatible keymap, clicking on empty space in the file browser will deselect all files. Also makes selection use same operator description we use for other select operators. --- source/blender/editors/space_file/file_ops.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index c6061cb6f58..127196cca74 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -489,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; @@ -521,10 +522,15 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) 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); } @@ -540,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; @@ -559,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); } /** -- cgit v1.2.3 From 4ce3fbd52ae8bd054cfbac06ef3a1aea7568386b Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 10 Sep 2019 15:12:42 -0700 Subject: UI: File Browser Friendly Volume Descriptions File Browser Volumes list gets nicer friendly drive names with volume label or device description. Differential Revision: https://developer.blender.org/D5747 Reviewed by Brecht Van Lommel --- source/blender/editors/space_file/fsmenu.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index c7a139a8b24..7faa2b883f2 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -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); } -- cgit v1.2.3 From 8d6b0eda5db45b63de8fccea1e3af41bf0bf09e0 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 16 Sep 2019 18:14:23 +0200 Subject: UI: Show in-/decrement buttons for exporters As per Brecht's suggestion, use the check_existing property to control visibility of the '+' and '-' icons. It is typically set for save operations. Adds another FileSelectParams flag (to avoid duplicated propertie lookups) and removes the recently introduced FileSelectParams.action_type again. Fixes T69881. --- source/blender/editors/space_file/file_ops.c | 15 ++++++--------- source/blender/editors/space_file/file_panels.c | 2 +- source/blender/editors/space_file/filesel.c | 7 +++---- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 127196cca74..b741a255383 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1506,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; } } } @@ -2398,7 +2395,7 @@ static bool file_filenum_poll(bContext *C) return false; } - return sfile->params && (sfile->params->action_type == FILE_SAVE); + return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING); } /** diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index b0fed1fafd4..8b83b5e1b05 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -176,7 +176,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) * immediate ui_apply_but_func but only after button deactivates */ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); - if (params->action_type == FILE_SAVE) { + 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); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e54f13e9356..6e576006332 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -167,6 +167,9 @@ 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; } @@ -274,10 +277,6 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->sort = FILE_SORT_ALPHA; } - if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) { - params->action_type = RNA_property_enum_get(op->ptr, prop); - } - if (params->display == FILE_DEFAULTDISPLAY) { if (params->display_previous == FILE_DEFAULTDISPLAY) { if (U.uiflag & USER_SHOW_THUMBNAILS) { -- cgit v1.2.3 From 5e2f0adb1b9c8df45e00be579e20144b3972b53b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 19 Sep 2019 16:14:47 +0200 Subject: UI: layout support for fixed size buttons, and use for file browser open/cancel Not exposed to Python API yet, this should get more detailed testing with different layouts before that happens. Ref T69652 --- source/blender/editors/space_file/file_panels.c | 52 ++++++++++++------------- 1 file changed, 24 insertions(+), 28 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 8b83b5e1b05..9ba098fcf45 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -110,18 +110,22 @@ void file_tool_props_region_panels_register(ARegionType *art) BLI_addtail(&art->paneltypes, pt); } -static void file_panel_execution_cancel_button(uiBlock *block) +static void file_panel_execution_cancel_button(uiLayout *layout) { - uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_cancel", - WM_OP_EXEC_REGION_WIN, - IFACE_("Cancel"), - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - ""); + 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) @@ -145,7 +149,6 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, ¶ms_rna_ptr); row = uiLayoutRow(pa->layout, false); - uiLayoutSetScaleX(row, 1.3f); uiLayoutSetScaleY(row, 1.3f); /* callbacks for operator check functions */ @@ -192,23 +195,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) UI_block_func_set(block, NULL, NULL, NULL); { - if (windows_layout == false) { - file_panel_execution_cancel_button(block); - } - but = uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_execute", - WM_OP_EXEC_REGION_WIN, - params->title, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - ""); - /* Just a display hint. */ - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); + uiLayout *sub = uiLayoutRow(row, false); + uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN); + if (windows_layout) { - file_panel_execution_cancel_button(block); + 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); } } } -- cgit v1.2.3 From 09b728ff3e3702ab7718f8604a8712ce34783803 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 12:03:32 +0200 Subject: Fix empty file options region in regular editor This would happen when opening a file browser as regular editor, opening a temporary file browser from there (e.g. Ctrl+O) and cancelling the operation. In some cases this would cause most of the editor to be filled with an empty operator options region: * Go to Shading workspace * File -> Append * Cancel --- source/blender/editors/space_file/space_file.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index d6a4eafc658..34429570671 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -225,6 +225,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); struct FSMenu *fsmenu = ED_fsmenu_get(); + ARegion *region_tool_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS); if (!sfile->folders_prev) { sfile->folders_prev = folderlist_new(); @@ -293,8 +294,9 @@ static void file_refresh(const bContext *C, ScrArea *sa) ED_area_initialize(wm, win, sa); } - if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) { - /* Create TOOL_PROPS region. */ + + /* If there's an file-operation, ensure we have the option region */ + if (sa && sfile->op && (region_tool_props == NULL)) { ARegion *region_props = file_tool_props_region(sa); if (params->flag & FILE_HIDE_TOOL_PROPS) { @@ -303,6 +305,14 @@ static void file_refresh(const bContext *C, ScrArea *sa) ED_area_initialize(wm, win, sa); } + /* If there's _no_ file-operation, ensure we _don't_ have the option region */ + else if (sa && (sfile->op == NULL) && (region_tool_props != NULL)) { + /* Remove TOOL_PROPS region. */ + ED_region_exit((bContext *)C, region_tool_props); + BKE_area_region_free(sa->type, region_tool_props); + BLI_remlink(&sa->regionbase, region_tool_props); + MEM_freeN(region_tool_props); + } ED_area_tag_redraw(sa); } -- cgit v1.2.3 From f5dc979a7eb0833b7abcf9db9ab9a01905786091 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 12:26:06 +0200 Subject: Cleanup: Add/use utility to remove regions --- source/blender/editors/space_file/space_file.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 34429570671..a70b307e657 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -307,11 +307,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) } /* If there's _no_ file-operation, ensure we _don't_ have the option region */ else if (sa && (sfile->op == NULL) && (region_tool_props != NULL)) { - /* Remove TOOL_PROPS region. */ - ED_region_exit((bContext *)C, region_tool_props); - BKE_area_region_free(sa->type, region_tool_props); - BLI_remlink(&sa->regionbase, region_tool_props); - MEM_freeN(region_tool_props); + ED_region_remove(C, sa, region_tool_props); } ED_area_tag_redraw(sa); -- cgit v1.2.3 From f431c199541e400653e1f8f590934a22b9672dc6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Sep 2019 21:04:56 +1000 Subject: Cleanup: discarded-qualifier warning --- source/blender/editors/space_file/space_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index a70b307e657..2daa52a841e 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -307,7 +307,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) } /* If there's _no_ file-operation, ensure we _don't_ have the option region */ else if (sa && (sfile->op == NULL) && (region_tool_props != NULL)) { - ED_region_remove(C, sa, region_tool_props); + ED_region_remove((bContext *)C, sa, region_tool_props); } ED_area_tag_redraw(sa); -- cgit v1.2.3 From d1cc340e56691cb82e444289415ede24ba4d2bc0 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 15:09:47 +0200 Subject: Rewrite file region handling for non-editor mode This makes it so that regions only needed when the file browser is invoked as an operation (e.g. Ctrl+O rather than a regular editor) are lazy created then, and removed if the file browser is changed into a regular editor then (e.g. Ctrl+O over regular file browser editor -> Cancel). That should remove some troublesome assumptions and makes versioning redundant. It also fixes the issue of an empty execute region at the bottom after cancelling a file operation invoked from a regular file browser editor. --- source/blender/editors/space_file/file_intern.h | 7 +- source/blender/editors/space_file/file_ops.c | 50 +------ source/blender/editors/space_file/space_file.c | 177 ++++++++++++++++++------ 3 files changed, 135 insertions(+), 99 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 4b86f38f8e4..701c28abfa2 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -32,10 +32,6 @@ struct FileSelectParams; struct SpaceFile; struct View2D; -/* file_ops.c */ -struct ARegion *file_tools_region(struct ScrArea *sa); -struct ARegion *file_tool_props_region(struct ScrArea *sa); - /* file_draw.c */ #define TILE_BORDER_X (UI_UNIT_X / 4) #define TILE_BORDER_Y (UI_UNIT_Y / 4) @@ -112,6 +108,9 @@ 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); + +struct ARegion *file_tools_region_ensure(struct ScrArea *sa, struct ARegion *ar_prev); + void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index b741a255383..fb8c8c5295d 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2315,58 +2315,10 @@ 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) -{ - 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; - - return arnew; -} - -ARegion *file_tool_props_region(ScrArea *sa) -{ - ARegion *ar, *arnew; - - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) { - return ar; - } - - /* add subdiv level; after execute region */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE); - - /* is error! */ - if (ar == NULL) { - return NULL; - } - - arnew = MEM_callocN(sizeof(ARegion), "tool props for file"); - BLI_insertlinkafter(&sa->regionbase, ar, arnew); - arnew->regiontype = RGN_TYPE_TOOL_PROPS; - arnew->alignment = RGN_ALIGN_RIGHT; - - 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); + ARegion *ar = file_tools_region_ensure(sa, BKE_area_find_region_type(sa, RGN_TYPE_UI)); if (ar) { ED_region_toggle_hidden(C, ar); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 2daa52a841e..ef7586e9432 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -55,6 +55,80 @@ #include "filelist.h" #include "GPU_framebuffer.h" +static ARegion *file_tools_region_create(ListBase *regionbase, ARegion *ar_prev) +{ + ARegion *ar = MEM_callocN(sizeof(ARegion), "tools region for file"); + BLI_insertlinkafter(regionbase, ar_prev, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_LEFT; + + return ar; +} + +ARegion *file_tools_region_ensure(ScrArea *sa, ARegion *ar_prev) +{ + ARegion *ar; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) { + return ar; + } + + return file_tools_region_create(&sa->regionbase, ar_prev); +} + +static ARegion *file_tools_options_toggle_region_ensure(ScrArea *sa, ARegion *ar_prev) +{ + ARegion *ar; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL && (ar->next != NULL) && + (ar->next->regiontype == RGN_TYPE_TOOLS)) { + BLI_assert(ar->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV)); + return ar; + } + + ar = MEM_callocN(sizeof(ARegion), "options toggle region for file"); + BLI_insertlinkafter(&sa->regionbase, ar_prev, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + + return ar; +} + +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)) @@ -80,32 +154,9 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen ar->flag |= RGN_FLAG_DYNAMIC_SIZE; /* Tools region */ - ar = MEM_callocN(sizeof(ARegion), "tools region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_LEFT; - /* Tools region (lower split region) */ - ar = MEM_callocN(sizeof(ARegion), "lower tools region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + file_tools_region_create(&sfile->regionbase, ar); - /* Execute region */ - ar = MEM_callocN(sizeof(ARegion), "execute region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_EXECUTE; - ar->alignment = RGN_ALIGN_BOTTOM; - ar->flag |= RGN_FLAG_DYNAMIC_SIZE; - - /* Tool props region is added as needed. */ -#if 0 - /* 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_RIGHT; -#endif + /* Options toggle, tool props and execute region are added as needed, see file_refresh(). */ /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for file"); @@ -218,6 +269,59 @@ 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_tools_upper = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + 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); + ARegion *ar_tools_lower; + bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */ + + if (ar_tools_upper == NULL) { + ar_tools_upper = file_tools_region_ensure(sa, ar_ui); + needs_init = true; + } + + /* If there's an file-operation, ensure we have the option and execute region */ + if (sfile->op && (ar_props == NULL)) { + ar_tools_lower = file_tools_options_toggle_region_ensure(sa, ar_tools_upper); + ar_execute = file_execute_region_ensure(sa, ar_tools_lower); + 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)) { + ar_tools_lower = ar_tools_upper->next; + + BLI_assert(ar_execute != NULL); + BLI_assert(ar_tools_lower != NULL); + BLI_assert(ar_tools_lower->regiontype == RGN_TYPE_TOOLS); + + ED_region_remove(C, sa, ar_props); + ED_region_remove(C, sa, ar_execute); + ED_region_remove(C, sa, ar_tools_lower); + 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); @@ -225,7 +329,6 @@ static void file_refresh(const bContext *C, ScrArea *sa) SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); struct FSMenu *fsmenu = ED_fsmenu_get(); - ARegion *region_tool_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS); if (!sfile->folders_prev) { sfile->folders_prev = folderlist_new(); @@ -288,26 +391,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 region. */ - file_tools_region(sa); - - ED_area_initialize(wm, win, sa); - } - - /* If there's an file-operation, ensure we have the option region */ - if (sa && sfile->op && (region_tool_props == NULL)) { - ARegion *region_props = file_tool_props_region(sa); - - if (params->flag & FILE_HIDE_TOOL_PROPS) { - region_props->flag |= RGN_FLAG_HIDDEN; - } - - ED_area_initialize(wm, win, sa); - } - /* If there's _no_ file-operation, ensure we _don't_ have the option region */ - else if (sa && (sfile->op == NULL) && (region_tool_props != NULL)) { - ED_region_remove((bContext *)C, sa, region_tool_props); + if (sa) { + file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params); } ED_area_tag_redraw(sa); -- cgit v1.2.3 From b20182e334180d751acff4565d2cf061dcb90add Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 15:35:28 +0200 Subject: Refactor: Ensure there's always a valid file editor tool region So far the file browser code had some lazy creation for the tool region, even though it should always be there. The only reason I can see for this is compatiblity. So I simply added versioning code to add the region in case it's not there. Now we should be able to savely assume the tool region to be there, whithout any unusual lazy-creation. --- source/blender/editors/space_file/file_intern.h | 2 -- source/blender/editors/space_file/file_ops.c | 2 +- source/blender/editors/space_file/space_file.c | 32 ++++--------------------- 3 files changed, 5 insertions(+), 31 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 701c28abfa2..96a9828236a 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -109,8 +109,6 @@ void file_sfile_to_operator_ex(bContext *C, char *filepath); void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile); -struct ARegion *file_tools_region_ensure(struct ScrArea *sa, struct ARegion *ar_prev); - void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index fb8c8c5295d..0224192d559 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2318,7 +2318,7 @@ void FILE_OT_hidedot(struct wmOperatorType *ot) static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused)) { ScrArea *sa = CTX_wm_area(C); - ARegion *ar = file_tools_region_ensure(sa, BKE_area_find_region_type(sa, RGN_TYPE_UI)); + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); if (ar) { ED_region_toggle_hidden(C, ar); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index ef7586e9432..d59a75e5e05 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -55,27 +55,6 @@ #include "filelist.h" #include "GPU_framebuffer.h" -static ARegion *file_tools_region_create(ListBase *regionbase, ARegion *ar_prev) -{ - ARegion *ar = MEM_callocN(sizeof(ARegion), "tools region for file"); - BLI_insertlinkafter(regionbase, ar_prev, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_LEFT; - - return ar; -} - -ARegion *file_tools_region_ensure(ScrArea *sa, ARegion *ar_prev) -{ - ARegion *ar; - - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) { - return ar; - } - - return file_tools_region_create(&sa->regionbase, ar_prev); -} - static ARegion *file_tools_options_toggle_region_ensure(ScrArea *sa, ARegion *ar_prev) { ARegion *ar; @@ -154,7 +133,10 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen ar->flag |= RGN_FLAG_DYNAMIC_SIZE; /* Tools region */ - file_tools_region_create(&sfile->regionbase, ar); + ar = MEM_callocN(sizeof(ARegion), "tools region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_LEFT; /* Options toggle, tool props and execute region are added as needed, see file_refresh(). */ @@ -276,18 +258,12 @@ static void file_ensure_valid_region_state(bContext *C, SpaceFile *sfile, FileSelectParams *params) { - ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI); ARegion *ar_tools_upper = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); 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); ARegion *ar_tools_lower; bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */ - if (ar_tools_upper == NULL) { - ar_tools_upper = file_tools_region_ensure(sa, ar_ui); - needs_init = true; - } - /* If there's an file-operation, ensure we have the option and execute region */ if (sfile->op && (ar_props == NULL)) { ar_tools_lower = file_tools_options_toggle_region_ensure(sa, ar_tools_upper); -- cgit v1.2.3 From 2f1e8f4b97e72a078d8a6725a29cb371f6d12880 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 15:54:59 +0200 Subject: Remove redundant file bookmarks region toggle operator For the default keymap we were only using the regular toolshelf operator, doing this for the industry compatible keymap too now (we could even remove it there, we don't use it in other editors). Since we "now" have proper operators for toggling regions, this specific one is totally redundant. --- source/blender/editors/space_file/file_intern.h | 1 - source/blender/editors/space_file/file_ops.c | 24 ------------------------ source/blender/editors/space_file/space_file.c | 1 - 3 files changed, 26 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 96a9828236a..b0ff67844d8 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -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); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 0224192d559..48cded9073f 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2315,30 +2315,6 @@ void FILE_OT_hidedot(struct wmOperatorType *ot) ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } -static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused)) -{ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); - - if (ar) { - ED_region_toggle_hidden(C, ar); - } - - 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 */ -} - static bool file_filenum_poll(bContext *C) { SpaceFile *sfile = CTX_wm_space_file(C); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index d59a75e5e05..141036f856a 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -562,7 +562,6 @@ static void file_operatortypes(void) 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); -- cgit v1.2.3 From adfe68e2025b6d85312361a3d1b4d1397c1ce2a9 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 17:36:38 +0200 Subject: UI: Replace big options button in file browser The big options button in the lower left is now gone, it's replaced by a smaller icon toggle button in the upper right. That means I could also remove code for the region we had just for this button. I also added versioning code for the removal, to make sure the region is removed cleanly when reading old files. --- source/blender/editors/space_file/space_file.c | 32 +++----------------------- 1 file changed, 3 insertions(+), 29 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 141036f856a..2f0e796d500 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -55,25 +55,6 @@ #include "filelist.h" #include "GPU_framebuffer.h" -static ARegion *file_tools_options_toggle_region_ensure(ScrArea *sa, ARegion *ar_prev) -{ - ARegion *ar; - - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL && (ar->next != NULL) && - (ar->next->regiontype == RGN_TYPE_TOOLS)) { - BLI_assert(ar->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV)); - return ar; - } - - ar = MEM_callocN(sizeof(ARegion), "options toggle region for file"); - BLI_insertlinkafter(&sa->regionbase, ar_prev, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - ar->flag |= RGN_FLAG_DYNAMIC_SIZE; - - return ar; -} - static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev) { ARegion *ar; @@ -138,7 +119,7 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen ar->regiontype = RGN_TYPE_TOOLS; ar->alignment = RGN_ALIGN_LEFT; - /* Options toggle, tool props and execute region are added as needed, see file_refresh(). */ + /* Tool props and execute region are added as needed, see file_refresh(). */ /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for file"); @@ -258,16 +239,14 @@ static void file_ensure_valid_region_state(bContext *C, SpaceFile *sfile, FileSelectParams *params) { - ARegion *ar_tools_upper = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); 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); - ARegion *ar_tools_lower; 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_tools_lower = file_tools_options_toggle_region_ensure(sa, ar_tools_upper); - ar_execute = file_execute_region_ensure(sa, ar_tools_lower); + ar_execute = file_execute_region_ensure(sa, ar_tools); ar_props = file_tool_props_region_ensure(sa, ar_execute); if (params->flag & FILE_HIDE_TOOL_PROPS) { @@ -281,15 +260,10 @@ static void file_ensure_valid_region_state(bContext *C, } /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */ else if ((sfile->op == NULL) && (ar_props != NULL)) { - ar_tools_lower = ar_tools_upper->next; - BLI_assert(ar_execute != NULL); - BLI_assert(ar_tools_lower != NULL); - BLI_assert(ar_tools_lower->regiontype == RGN_TYPE_TOOLS); ED_region_remove(C, sa, ar_props); ED_region_remove(C, sa, ar_execute); - ED_region_remove(C, sa, ar_tools_lower); needs_init = true; } -- cgit v1.2.3 From ac15bf16462b79265eac70091f40d0ca0cde77b0 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 20 Sep 2019 20:41:00 +0200 Subject: UI: Avoid file browser directory change if path didn't change E.g. entering the file path field and then pressing enter without any change would call an unneccesary directory change, causing flickering. So the main point of this is to avoid flickering. Without this the text field could also be used to refresh the file list, but for that we have a proper button. --- source/blender/editors/space_file/file_ops.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 48cded9073f..b4b51de302d 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2149,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 */ @@ -2182,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 */ -- cgit v1.2.3 From 57519f237a914aa2645c44bf86917c05f6e45e30 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sun, 29 Sep 2019 20:16:19 +0200 Subject: UI: Let file browser tool/bookmarks region push upper bar in Main reason for doing this is that the navigation buttons are very close to the file list now, making them much faster to reach. Initially we let the upper bar (the one with the file path, navigation and display buttons) use full area width, because designs back then had more horizontal space problems. The designs have changed meanwhile, and horizontal space is less of an issue. However, when the file browser is shrunk horizontally, or if it's open in a small area (e.g. see "Shading" workspace), having the tool region open brings back the space issues. But even the file list layout becomes problematic then, and the same issue was present before the new file browser design, so we've decided this is an acceptable tradeoff. --- source/blender/editors/space_file/space_file.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 2f0e796d500..d63fcf402de 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -106,6 +106,12 @@ 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; + /* Tools region */ + ar = MEM_callocN(sizeof(ARegion), "tools region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_LEFT; + /* ui list region */ ar = MEM_callocN(sizeof(ARegion), "ui region for file"); BLI_addtail(&sfile->regionbase, ar); @@ -113,12 +119,6 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen 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); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_LEFT; - /* Tool props and execute region are added as needed, see file_refresh(). */ /* main region */ @@ -239,14 +239,14 @@ static void file_ensure_valid_region_state(bContext *C, SpaceFile *sfile, FileSelectParams *params) { - ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + 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_tools); + 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) { -- cgit v1.2.3 From ddb157999eed6907e3fd8753d61e65491f2f3a6d Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 30 Sep 2019 18:54:11 +0200 Subject: UI: Remember File Browser Display Options in Preferences This makes it so that some display related properties of the file browser state are remembered in the Preferences. Otherwise, users often end up doing the same set up work over and over again, so this is a nice way to save users some work. It's typical for other file browsers to remember their state too, so another benefit is having a more conventional behavior, meeting user expectations better. Some points: * We currently store: Window size, display type, thumbnail size, enabled details-columns, sort options, "Show Hidden" option. More can be added easily. * No changes are stored to the Preferences if "Auto-save Preferences" is disabled. This is how Quick Favorites behave too and it's a reasonable way to make this behavior optional. * The Preferences are only saved to permanent memory upon closing Blender, following existing convention of Preferences and Quick Favorites. * If settings weren't actually changed, Preference saving is skipped. * Only temporary file browsers save their state (invoked through actions like open or save), not regular file browser editors. These are usually used for different purposes and workflows. * Removes "Show Thumbnails" Preferences option. It would need some special handling, possibly introducing bugs. For users, this simplifies behavior and should make things more predictable. Left in DNA data in case we decide to bring it back. Reviewers: brecht, #user_interface, billreynish, campbellbarton Reviewed By: #user_interface, William Reynish, Campbell Barton, Brecht van Lommel (quick first pass review in person) Maniphest Tasks: T69460 Differential Revision: https://developer.blender.org/D5893 --- source/blender/editors/space_file/filesel.c | 97 ++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 22 deletions(-) (limited to 'source/blender/editors/space_file') diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6e576006332..e2c9bb8d6e5 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -49,6 +49,8 @@ #include "BLI_utildefines.h" #include "BLI_fnmatch.h" +#include "BLO_readfile.h" + #include "BLT_translation.h" #include "BKE_appdir.h" @@ -102,9 +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 = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; + sfile->params->details_flags = U_default.file_space_data.details_flags; } params = sfile->params; @@ -274,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_VERTICALDISPLAY; - } - } - else { - params->display = FILE_VERTICALDISPLAY; - } - } - else { - params->display = params->display_previous; - } + params->display = U_default.file_space_data.display_type; } if (is_relative_path) { @@ -307,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_VERTICALDISPLAY; - params->display_previous = FILE_DEFAULTDISPLAY; params->sort = FILE_SORT_ALPHA; params->filter = 0; params->filter_glob[0] = '\0'; @@ -346,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; @@ -766,7 +809,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) layout->tile_border_x * 2; layout->flag = FILE_LAYOUT_HOR; } - params->display_previous = params->display; layout->dirty = false; } @@ -923,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; } -- cgit v1.2.3