diff options
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r-- | source/blender/editors/space_file/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 54 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_intern.h | 14 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_ops.c | 327 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_utils.c | 46 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 35 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.h | 5 | ||||
-rw-r--r-- | source/blender/editors/space_file/filesel.c | 87 | ||||
-rw-r--r-- | source/blender/editors/space_file/fsmenu.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_file/space_file.c | 48 |
10 files changed, 479 insertions, 140 deletions
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index fc007a659b4..4c33499da41 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC file_draw.c file_ops.c file_panels.c + file_utils.c filelist.c filesel.c fsmenu.c diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 98c7ddeff77..6347ce7c4e8 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -295,22 +295,29 @@ static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon, static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align) { - uiStyle *style = UI_style_get(); - uiFontStyle fs = style->widgetlabel; + uiStyle *style; + uiFontStyle fs; rcti rect; char fname[FILE_MAXFILE]; + if (string[0] == '\0') { + return; + } + + style = UI_style_get(); + fs = style->widgetlabel; + fs.align = align; BLI_strncpy(fname, string, FILE_MAXFILE); - file_shorten_string(fname, width + 1.0f, 0); + UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0'); /* 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 + 4.0f)); + rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC)); rect.ymin = sy - height; rect.ymax = sy; - + UI_fontstyle_draw(&fs, &rect, fname); } @@ -323,35 +330,40 @@ void file_calc_previews(const bContext *C, ARegion *ar) UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height); } -static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool dropshadow, bool drag) +static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool is_icon, bool drag) { uiBut *but; float fx, fy; float dx, dy; int xco, yco; + float ui_imbx, ui_imby; float scaledx, scaledy; float scale; int ex, ey; + bool use_dropshadow = !is_icon && (file->flags & FILE_TYPE_IMAGE); BLI_assert(imb != NULL); - if ((imb->x * UI_DPI_FAC > layout->prv_w) || - (imb->y * UI_DPI_FAC > layout->prv_h)) + ui_imbx = imb->x * UI_DPI_FAC; + ui_imby = imb->y * UI_DPI_FAC; + /* Unlike thumbnails, icons are not scaled up. */ + if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) || + (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h)))) { if (imb->x > imb->y) { scaledx = (float)layout->prv_w; - scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w; + scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w; scale = scaledx / imb->x; } else { scaledy = (float)layout->prv_h; - scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h; + scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h; scale = scaledy / imb->y; } } else { - scaledx = (float)imb->x * UI_DPI_FAC; - scaledy = (float)imb->y * UI_DPI_FAC; + scaledx = ui_imbx; + scaledy = ui_imby; scale = UI_DPI_FAC; } @@ -367,17 +379,23 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* shadow */ - if (dropshadow) + if (use_dropshadow) { UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + } glEnable(GL_BLEND); /* the image */ - glColor4f(1.0, 1.0, 1.0, 1.0); + if (!is_icon && file->flags & FILE_TYPE_FTFONT) { + UI_ThemeColor(TH_TEXT); + } + else { + glColor4f(1.0, 1.0, 1.0, 1.0); + } glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale); /* border */ - if (dropshadow) { + if (use_dropshadow) { glColor4f(0.0f, 0.0f, 0.0f, 0.4f); fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); } @@ -525,9 +543,9 @@ void file_draw_list(const bContext *C, ARegion *ar) if (!(file->selflag & FILE_SEL_EDITING)) { - if ((params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) { + if ((params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) || (file->selflag & FILE_SEL_SELECTED)) { int colorid = (file->selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; - int shade = (params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0; + int shade = (params->highlight_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0; /* readonly files (".." and ".") must not be drawn as selected - set color back to normal */ if (FILENAME_IS_CURRPAR(file->relname)) { @@ -549,7 +567,7 @@ void file_draw_list(const bContext *C, ARegion *ar) is_icon = 1; } - file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), do_drag); + file_draw_preview(block, file, sx, sy, imb, layout, is_icon, do_drag); } else { file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index e7a6cd62a33..d7af6c9b812 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -59,9 +59,17 @@ bool file_draw_check_exists(SpaceFile *sfile); /* file_ops.h */ struct wmOperatorType; struct wmOperator; -struct wmEvent; + +typedef enum WalkSelectDirection { + FILE_SELECT_WALK_UP, + FILE_SELECT_WALK_DOWN, + FILE_SELECT_WALK_LEFT, + FILE_SELECT_WALK_RIGHT, +} WalkSelectDirections; + void FILE_OT_highlight(struct wmOperatorType *ot); void FILE_OT_select(struct wmOperatorType *ot); +void FILE_OT_select_walk(struct wmOperatorType *ot); void FILE_OT_select_all_toggle(struct wmOperatorType *ot); void FILE_OT_select_border(struct wmOperatorType *ot); void FILE_OT_select_bookmark(struct wmOperatorType *ot); @@ -102,7 +110,6 @@ void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ -float file_shorten_string(char *string, float w, int front); float file_string_width(const char *str); float file_font_pointsize(void); @@ -113,5 +120,8 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v); /* file_panels.c */ void file_panels_register(struct ARegionType *art); +/* file_utils.c */ +void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); + #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index f8d13bb6adb..8c9233e3ce5 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -176,7 +176,8 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) (selected_idx < numfiles) && (file = filelist_file(sfile->files, selected_idx))) { - params->active_file = selected_idx; + params->highlight_file = selected_idx; + sfile->params->active_file = selected_idx; if (S_ISDIR(file->type)) { const bool is_parent_dir = FILENAME_IS_PARENT(file->relname); @@ -214,6 +215,23 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) return retval; } +/** + * \warning: loops over all files so better use cautiously + */ +static bool file_is_any_selected(struct FileList *files) +{ + const int numfiles = filelist_numfiles(files); + int i; + + for (i = 0; i < numfiles; ++i) { + if (filelist_is_selected(files, i, CHECK_ALL)) { + return true; + } + } + + return false; +} + static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { @@ -229,19 +247,53 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, if (sel.first != sel.last) select = 0; /* Do we have a valid selection and are we actually selecting */ - if ((sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE))) { + if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) { /* Check last selection, if selected, act on the file or dir */ if (filelist_is_selected(sfile->files, sel.last, check_type)) { retval = file_select_do(C, sel.last, do_diropen); } } + if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { + sfile->params->active_file = -1; + } + /* update operator for name change event */ file_draw_check(C); return retval; } +static int file_border_select_find_last_selected( + SpaceFile *sfile, ARegion *ar, const FileSelection *sel, + const int mouse_xy[2]) +{ + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + rcti bounds_first, bounds_last; + int dist_first, dist_last; + + file_tile_boundbox(ar, layout, sel->first, &bounds_first); + file_tile_boundbox(ar, layout, sel->last, &bounds_last); + + /* are first and last in the same column (horizontal layout)/row (vertical layout)? */ + if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) || + (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) + { + /* use vertical distance */ + const int my_loc = mouse_xy[1] - ar->winrct.ymin; + dist_first = BLI_rcti_length_y(&bounds_first, my_loc); + dist_last = BLI_rcti_length_y(&bounds_last, my_loc); + } + else { + /* use horizontal distance */ + const int mx_loc = mouse_xy[0] - ar->winrct.xmin; + dist_first = BLI_rcti_length_x(&bounds_first, mx_loc); + dist_last = BLI_rcti_length_x(&bounds_last, mx_loc); + } + + return dist_first < dist_last ? sel->first : sel->last; +} + static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -276,17 +328,17 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent * file->selflag &= ~FILE_SEL_HIGHLIGHTED; } - /* active_file gets highlighted as well - make sure it is no readonly file */ + /* make sure highlight_file is no readonly file */ if (sel.last == idx) { - params->active_file = idx; + params->highlight_file = idx; } } } params->sel_first = sel.first; params->sel_last = sel.last; - + params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, &event->x); } else { - params->active_file = -1; + params->highlight_file = -1; params->sel_first = params->sel_last = -1; file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -361,7 +413,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; if (sfile && sfile->params) { - int idx = sfile->params->active_file; + int idx = sfile->params->highlight_file; if (idx >= 0) { struct direntry *file = filelist_file(sfile->files, idx); @@ -409,35 +461,252 @@ void FILE_OT_select(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** + * \returns true if selection has changed + */ +static bool file_walk_select_selection_set( + bContext *C, SpaceFile *sfile, + const int direction, const int numfiles, + const int active_old, const int active_new, const int other_site, + const bool has_selection, const bool extend, const bool fill) +{ + FileSelectParams *params = sfile->params; + struct FileList *files = sfile->files; + const int last_sel = params->active_file; /* store old value */ + int active = active_old; /* could use active_old instead, just for readability */ + bool deselect = false; + + BLI_assert(params); + + if (has_selection) { + if (extend && + filelist_is_selected(files, active_old, FILE_SEL_SELECTED) && + filelist_is_selected(files, active_new, FILE_SEL_SELECTED)) + { + /* conditions for deselecting: initial file is selected, new file is + * selected and either other_side isn't selected/found or we use fill */ + deselect = (fill || other_site == -1 || !filelist_is_selected(files, other_site, FILE_SEL_SELECTED)); + + /* don't change active here since we either want to deselect active or we want to + * walk through a block of selected files without selecting/deselecting anything */ + params->active_file = active_new; + /* but we want to change active if we use fill (needed to get correct selection bounds) */ + if (deselect && fill) { + active = active_new; + } + } + else { + /* regular selection change */ + params->active_file = active = active_new; + } + } + else { + /* select last file */ + if (ELEM(direction, FILE_SELECT_WALK_UP, FILE_SELECT_WALK_LEFT)) { + params->active_file = active = numfiles - 1; + } + /* select first file */ + else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) { + params->active_file = active = 1; + } + else { + BLI_assert(0); + } + } + + if (active < 0) { + return false; + } + + /* highlight the active walker file for extended selection for better visual feedback */ + if (extend) { + params->highlight_file = params->active_file; + } + else { + /* deselect all first */ + file_deselect_all(sfile, FILE_SEL_SELECTED); + + /* highlight file under mouse pos */ + params->highlight_file = -1; + WM_event_add_mousemove(C); + } + + /* do the actual selection */ + if (fill) { + FileSelection sel = { MIN2(active, last_sel), MAX2(active, last_sel) }; + + /* fill selection between last and first selected file */ + filelist_select( + files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + /* entire sel is cleared here, so select active again */ + if (deselect) { + filelist_select_file(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + } + } + else { + filelist_select_file( + files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + } + + BLI_assert(IN_RANGE(active, 0, numfiles)); + + /* selection changed */ + return true; +} + +/** + * \returns true if selection has changed + */ +static bool file_walk_select_do( + bContext *C, SpaceFile *sfile, + FileSelectParams *params, const int direction, + const bool extend, const bool fill) +{ + struct FileList *files = sfile->files; + const int numfiles = filelist_numfiles(files); + const bool has_selection = file_is_any_selected(files); + const int active_old = params->active_file; + int active_new = -1; + int other_site = -1; /* file on the other site of active_old */ + + + /* *** get all needed files for handling selection *** */ + + 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; + + if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) + { + active_new = active_old - 1; + other_site = active_old + 1; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_DOWN) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_RIGHT)) + { + active_new = active_old + 1; + other_site = active_old - 1; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_LEFT) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_UP)) + { + active_new = active_old - idx_shift; + other_site = active_old + idx_shift; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_RIGHT) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_DOWN)) + { + + active_new = active_old + idx_shift; + other_site = active_old - idx_shift; + } + else { + BLI_assert(0); + } + + if (!IN_RANGE(active_new, 0, numfiles)) { + if (extend) { + /* extend to invalid file -> abort */ + return false; + } + else { + /* select initial file */ + active_new = active_old; + } + } + if (!IN_RANGE(other_site, 0, numfiles)) { + other_site = -1; + } + } + + return file_walk_select_selection_set( + C, sfile, direction, numfiles, active_old, active_new, other_site, has_selection, extend, fill); +} + +static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = sfile->params; + const int direction = RNA_enum_get(op->ptr, "direction"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool fill = RNA_boolean_get(op->ptr, "fill"); + + if (file_walk_select_do(C, sfile, params, direction, extend, fill)) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void FILE_OT_select_walk(wmOperatorType *ot) +{ + static EnumPropertyItem direction_items[] = { + {FILE_SELECT_WALK_UP, "UP", 0, "Prev", ""}, + {FILE_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""}, + {FILE_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""}, + {FILE_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Walk Select/Deselect File"; + ot->description = "Select/Deselect files by walking through them"; + ot->idname = "FILE_OT_select_walk"; + + /* api callbacks */ + ot->invoke = file_walk_select_invoke; + ot->poll = ED_operator_file_active; + + /* properties */ + prop = RNA_def_enum(ot->srna, "direction", direction_items, 0, "Walk Direction", + "Select/Deselect file in this direction"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", + "Extend selection instead of deselecting everything first"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op)) { ScrArea *sa = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); FileSelection sel; - int numfiles = filelist_numfiles(sfile->files); - int i; - bool is_selected = false; + const int numfiles = filelist_numfiles(sfile->files); + const bool has_selection = file_is_any_selected(sfile->files); sel.first = 0; sel.last = numfiles - 1; - /* Is any file selected ? */ - for (i = 0; i < numfiles; ++i) { - if (filelist_is_selected(sfile->files, i, CHECK_ALL)) { - is_selected = true; - break; - } - } /* select all only if previously no file was selected */ - if (is_selected) { + if (has_selection) { filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + sfile->params->active_file = -1; } else { const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; + int i; + filelist_select(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type); + + /* set active_file to first selected */ + for (i = 0; i < numfiles; i++) { + if (filelist_is_selected(sfile->files, i, check_type)) { + sfile->params->active_file = i; + break; + } + } } + file_draw_check(C); + WM_event_add_mousemove(C); ED_area_tag_redraw(sa); + return OPERATOR_FINISHED; } @@ -748,28 +1017,28 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) numfiles = filelist_numfiles(sfile->files); params = ED_fileselect_get_params(sfile); - origfile = params->active_file; + origfile = params->highlight_file; mx -= ar->winrct.xmin; my -= ar->winrct.ymin; if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) { float fx, fy; - int active_file; + int highlight_file; UI_view2d_region_to_view(v2d, mx, my, &fx, &fy); - active_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy)); + highlight_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy)); - if ((active_file >= 0) && (active_file < numfiles)) - params->active_file = active_file; + if ((highlight_file >= 0) && (highlight_file < numfiles)) + params->highlight_file = highlight_file; else - params->active_file = -1; + params->highlight_file = -1; } else - params->active_file = -1; + params->highlight_file = -1; - return (params->active_file != origfile); + return (params->highlight_file != origfile); } static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -1669,7 +1938,7 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); if (sfile->params) { - int idx = sfile->params->active_file; + int idx = sfile->params->highlight_file; int numfiles = filelist_numfiles(sfile->files); if ( (0 <= idx) && (idx < numfiles) ) { struct direntry *file = filelist_file(sfile->files, idx); @@ -1690,7 +1959,7 @@ static int file_rename_poll(bContext *C) SpaceFile *sfile = CTX_wm_space_file(C); if (sfile && sfile->params) { - int idx = sfile->params->active_file; + int idx = sfile->params->highlight_file; if (idx >= 0) { struct direntry *file = filelist_file(sfile->files, idx); @@ -1699,7 +1968,7 @@ static int file_rename_poll(bContext *C) } } - if (sfile->params->active_file < 0) { + if (sfile->params->highlight_file < 0) { poll = 0; } else { diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c new file mode 100644 index 00000000000..8a80e4a69ee --- /dev/null +++ b/source/blender/editors/space_file/file_utils.c @@ -0,0 +1,46 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_file/file_utils.c + * \ingroup spfile + */ + +#include "BLI_rect.h" + +#include "BKE_context.h" + +#include "ED_screen.h" +#include "ED_fileselect.h" + +#include "WM_types.h" + +#include "file_intern.h" + + +void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds) +{ + int xmin, ymax; + + ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax); + BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, + ar->winy - ymax - layout->tile_h - layout->tile_border_y, ar->winy - ymax); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 66acd7d05e3..4048c9fc1a1 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -654,7 +654,7 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index) if (file->flags & FILE_TYPE_BLENDER) { ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; } - else if ((file->flags & FILE_TYPE_MOVIE) || (file->flags & FILE_TYPE_MOVIE_ICON)) { + else if (file->flags & FILE_TYPE_MOVIE) { ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; } else if (file->flags & FILE_TYPE_SOUND) { @@ -900,7 +900,6 @@ static void filelist_setfiletypes(struct FileList *filelist) file = filelist->filelist; for (num = 0; num < filelist->numfiles; num++, file++) { - file->type = file->s.st_mode; /* restore the mess below */ #ifndef __APPLE__ /* Don't check extensions for directories, allow in OSX cause bundles have extensions*/ if (file->type & S_IFDIR) { @@ -1105,7 +1104,7 @@ static void filelist_from_library(struct FileList *filelist) previews = NULL; nprevs = 0; names = BLO_blendhandle_get_linkable_groups(filelist->libfiledata); - nnames = BLI_linklist_length(names); + nnames = BLI_linklist_count(names); } filelist->numfiles = nnames + 1; @@ -1235,7 +1234,7 @@ static void filelist_from_main(struct FileList *filelist) files = filelist->filelist; - if (!filelist->filter_data.hide_parent) { + if (files && !filelist->filter_data.hide_parent) { memset(&(filelist->filelist[0]), 0, sizeof(struct direntry)); filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[0].type |= S_IFDIR; @@ -1247,7 +1246,7 @@ static void filelist_from_main(struct FileList *filelist) for (id = lb->first; id; id = id->next) { ok = 1; if (ok) { - if (!filelist->filter_data.hide_dot || id->name[2] != '.') { + if (files && (!filelist->filter_data.hide_dot || id->name[2] != '.')) { memset(files, 0, sizeof(struct direntry)); if (id->lib == NULL) { files->relname = BLI_strdup(id->name + 2); @@ -1334,20 +1333,23 @@ static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float tj->do_update = do_update; while ((*stop == 0) && (limg)) { + ThumbSource source = 0; + + BLI_assert(limg->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | + FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)); if (limg->flags & FILE_TYPE_IMAGE) { - limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE); + source = THB_SOURCE_IMAGE; } else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND); + source = THB_SOURCE_BLEND; } else if (limg->flags & FILE_TYPE_MOVIE) { - limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE); - if (!limg->img) { - /* remember that file can't be loaded via IMB_open_anim */ - limg->flags &= ~FILE_TYPE_MOVIE; - limg->flags |= FILE_TYPE_MOVIE_ICON; - } + source = THB_SOURCE_MOVIE; } + else if (limg->flags & FILE_TYPE_FTFONT) { + source = THB_SOURCE_FONT; + } + limg->img = IMB_thumb_manage(limg->path, THB_LARGE, source); *do_update = true; PIL_sleep_ms(10); limg = limg->next; @@ -1363,11 +1365,6 @@ static void thumbnails_update(void *tjv) while (limg) { if (!limg->done && limg->img) { tj->filelist->filelist[limg->index].image = IMB_dupImBuf(limg->img); - /* update flag for movie files where thumbnail can't be created */ - if (limg->flags & FILE_TYPE_MOVIE_ICON) { - tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE; - tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON; - } limg->done = true; IMB_freeImBuf(limg->img); limg->img = NULL; @@ -1408,7 +1405,7 @@ void thumbnails_start(FileList *filelist, const bContext *C) continue; } if (!filelist->filelist[idx].image) { - if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | + if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { FileImage *limg = MEM_callocN(sizeof(*limg), __func__); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 797d54a89b1..44e0a5169fa 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -40,12 +40,7 @@ extern "C" { struct BlendHandle; struct FileList; struct FileSelection; -struct FolderList; -struct Main; -struct ReportList; -struct Scene; struct direntry; -struct rcti; struct wmWindowManager; typedef enum FileSelType { diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 14b72eb8f6d..66eb79abae2 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -102,6 +102,8 @@ short ED_fileselect_set_params(SpaceFile *sfile) /* set path to most recently opened .blend */ BLI_split_dirfile(G.main->name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); sfile->params->filter_glob[0] = '\0'; + /* set the default thumbnails size */ + sfile->params->thumbnail_size = 128; } params = sfile->params; @@ -248,6 +250,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) /* operator has no setting for this */ params->sort = FILE_SORT_ALPHA; + params->active_file = -1; /* initialize the list with previous folders */ @@ -281,6 +284,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile) sfile->params->type = FILE_UNIX; sfile->params->flag = 0; sfile->params->title[0] = '\0'; + sfile->params->active_file = -1; } int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar) @@ -396,63 +400,23 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y) } } -/* Shorten a string to a given width w. - * If front is set, shorten from the front, - * otherwise shorten from the end. */ -float file_shorten_string(char *string, float w, int front) -{ - char temp[FILE_MAX]; - short shortened = 0; - float sw = 0; - float pad = 0; - - if (w <= 0) { - *string = '\0'; - return 0.0; - } +float file_string_width(const char *str) +{ + uiStyle *style = UI_style_get(); + float width; - sw = file_string_width(string); - if (front == 1) { - const char *s = string; - BLI_strncpy(temp, "...", 4); - pad = file_string_width(temp); - while ((*s) && (sw + pad > w)) { - s++; - sw = file_string_width(s); - shortened = 1; - } - if (shortened) { - int slen = strlen(s); - BLI_strncpy(temp + 3, s, slen + 1); - temp[slen + 4] = '\0'; - BLI_strncpy(string, temp, slen + 4); - } + UI_fontstyle_set(&style->widget); + if (style->widget.kerning == 1) { /* for BLF_width */ + BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT); } - else { - const char *s = string; - while (sw > w) { - int slen = strlen(string); - string[slen - 1] = '\0'; - sw = file_string_width(s); - shortened = 1; - } - if (shortened) { - int slen = strlen(string); - if (slen > 3) { - BLI_strncpy(string + slen - 3, "...", 4); - } - } + width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + + if (style->widget.kerning == 1) { + BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT); } - - return sw; -} -float file_string_width(const char *str) -{ - uiStyle *style = UI_style_get(); - UI_fontstyle_set(&style->widget); - return BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + return width; } float file_font_pointsize(void) @@ -527,8 +491,8 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) layout->textheight = textheight; if (params->display == FILE_IMGDISPLAY) { - layout->prv_w = 4.8f * UI_UNIT_X; - layout->prv_h = 4.8f * UI_UNIT_Y; + 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.3f * UI_UNIT_X; layout->tile_border_y = 0.3f * UI_UNIT_X; layout->prv_border_x = 0.3f * UI_UNIT_X; @@ -642,8 +606,8 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche */ for (i = 0; i < n; i++) { file = filelist_file(sfile->files, i); - /* use same rule as 'FileCheckType.CHECK_FILES' */ - if (S_ISREG(file->type) && (fnmatch(pattern, file->relname, 0) == 0)) { + /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */ + if (fnmatch(pattern, file->relname, 0) == 0) { file->selflag |= FILE_SEL_SELECTED; if (!match) { BLI_strncpy(matched_file, file->relname, FILE_MAX); @@ -694,13 +658,8 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) closedir(dir); match = UI_autocomplete_end(autocpl, str); - if (match) { - if (match == AUTOCOMPLETE_FULL_MATCH) { - BLI_add_slash(str); - } - else { - BLI_strncpy(sfile->params->dir, str, sizeof(sfile->params->dir)); - } + if (match == AUTOCOMPLETE_FULL_MATCH) { + BLI_add_slash(str); } } } @@ -740,7 +699,7 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile) filelist_free(sfile->files); } - sfile->params->active_file = -1; + sfile->params->highlight_file = -1; WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index c6ee6875403..fdf7b458865 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -565,7 +565,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); - if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII)) + if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8)) continue; /* Exclude "all my files" as it makes no sense in blender fileselector */ diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 782b318b8a2..c7e0e4ad4e9 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -212,7 +212,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) if (!sfile->files) { sfile->files = filelist_new(params->type); filelist_setdir(sfile->files, params->dir); - params->active_file = -1; /* added this so it opens nicer (ton) */ + params->highlight_file = -1; /* added this so it opens nicer (ton) */ } filelist_setsorting(sfile->files, params->sort); filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT, @@ -377,7 +377,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_view_ortho(v2d); /* on first read, find active file */ - if (params->active_file == -1) { + if (params->highlight_file == -1) { wmEvent *event = CTX_wm_window(C)->eventstate; file_highlight_set(sfile, ar, event->x, event->y); } @@ -397,6 +397,7 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) static void file_operatortypes(void) { WM_operatortype_append(FILE_OT_select); + WM_operatortype_append(FILE_OT_select_walk); WM_operatortype_append(FILE_OT_select_all_toggle); WM_operatortype_append(FILE_OT_select_border); WM_operatortype_append(FILE_OT_select_bookmark); @@ -462,6 +463,49 @@ static void file_keymap(struct wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "fill", true); RNA_boolean_set(kmi->ptr, "open", false); + + /* arrow keys navigation (walk selecting) */ + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP); + RNA_boolean_set(kmi->ptr, "extend", true); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP); + RNA_boolean_set(kmi->ptr, "extend", true); + RNA_boolean_set(kmi->ptr, "fill", true); + + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN); + RNA_boolean_set(kmi->ptr, "extend", true); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN); + RNA_boolean_set(kmi->ptr, "extend", true); + RNA_boolean_set(kmi->ptr, "fill", true); + + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT); + RNA_boolean_set(kmi->ptr, "extend", true); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT); + RNA_boolean_set(kmi->ptr, "extend", true); + RNA_boolean_set(kmi->ptr, "fill", true); + + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT); + RNA_boolean_set(kmi->ptr, "extend", true); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT); + RNA_boolean_set(kmi->ptr, "extend", true); + RNA_boolean_set(kmi->ptr, "fill", true); + + /* front and back mouse folder navigation */ WM_keymap_add_item(keymap, "FILE_OT_previous", BUTTON4MOUSE, KM_CLICK, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0); |