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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_file/file_ops.c')
-rw-r--r--source/blender/editors/space_file/file_ops.c949
1 files changed, 779 insertions, 170 deletions
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 27d6fabba4e..8347ad87258 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -31,9 +31,11 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
+#include "BLI_linklist.h"
#include "BLO_readfile.h"
+#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
@@ -97,9 +99,9 @@ static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
{
FileSelection sel;
sel.first = 0;
- sel.last = filelist_numfiles(sfile->files) - 1;
+ sel.last = filelist_files_ensure(sfile->files) - 1;
- filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
}
typedef enum FileSelect {
@@ -137,7 +139,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- int numfiles = filelist_numfiles(sfile->files);
+ int numfiles = filelist_files_ensure(sfile->files);
FileSelection sel;
sel = find_file_mouse_rect(sfile, ar, rect);
@@ -150,7 +152,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
int f = sel.last;
while (f >= 0) {
- if (filelist_is_selected(sfile->files, f, CHECK_ALL) )
+ if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) )
break;
f--;
}
@@ -166,50 +168,118 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
FileSelect retval = FILE_SELECT_NOTHING;
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
- int numfiles = filelist_numfiles(sfile->files);
- struct direntry *file;
+ int numfiles = filelist_files_ensure(sfile->files);
+ const FileDirEntry *file;
/* make the selected file active */
if ((selected_idx >= 0) &&
(selected_idx < numfiles) &&
(file = filelist_file(sfile->files, selected_idx)))
{
+ params->highlight_file = selected_idx;
params->active_file = selected_idx;
- if (S_ISDIR(file->type)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ 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! */
- else if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
+ else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
// XXX error("Path too long, cannot enter this directory");
}
else {
- if (strcmp(file->relname, "..") == 0) {
+ if (is_parent_dir) {
/* avoids /../../ */
BLI_parent_dir(params->dir);
+
+ if (params->recursion_level > 1) {
+ /* Disable 'dirtree' recursion when going up in tree. */
+ params->recursion_level = 0;
+ filelist_setrecursion(sfile->files, params->recursion_level);
+ }
}
else {
BLI_cleanup_dir(G.main->name, params->dir);
- strcat(params->dir, file->relname);
+ strcat(params->dir, file->relpath);
BLI_add_slash(params->dir);
}
- file_change_dir(C, 0);
+ ED_file_change_dir(C, false);
retval = FILE_SELECT_DIR;
}
}
else {
- if (file->relname) {
- BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
- }
retval = FILE_SELECT_FILE;
}
+ fileselect_file_set(sfile, selected_idx);
}
return retval;
}
+/**
+ * \warning: loops over all files so better use cautiously
+ */
+static bool file_is_any_selected(struct FileList *files)
+{
+ const int numfiles = filelist_files_ensure(files);
+ int i;
+
+ /* Is any file selected ? */
+ for (i = 0; i < numfiles; ++i) {
+ if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * If \a file is outside viewbounds, this adjusts view to make sure it's inside
+ */
+static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const int file)
+{
+ FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+ rctf *cur = &ar->v2d.cur;
+ rcti rect;
+ bool changed = true;
+
+ file_tile_boundbox(ar, layout, file, &rect);
+
+ /* down - also use if tile is higher than viewbounds so view is aligned to file name */
+ if (cur->ymin > rect.ymin || layout->tile_h > ar->winy) {
+ cur->ymin = rect.ymin - (2 * layout->tile_border_y);
+ cur->ymax = cur->ymin + ar->winy;
+ }
+ /* up */
+ else if (cur->ymax < rect.ymax) {
+ cur->ymax = rect.ymax + layout->tile_border_y;
+ cur->ymin = cur->ymax - ar->winy;
+ }
+ /* left - also use if tile is wider than viewbounds so view is aligned to file name */
+ else if (cur->xmin > rect.xmin || layout->tile_w > ar->winx) {
+ cur->xmin = rect.xmin - layout->tile_border_x;
+ cur->xmax = cur->xmin + ar->winx;
+ }
+ /* right */
+ else if (cur->xmax < rect.xmax) {
+ cur->xmax = rect.xmax + (2 * layout->tile_border_x);
+ cur->xmin = cur->xmax - ar->winx;
+ }
+ else {
+ BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax &&
+ cur->ymin <= rect.ymin && cur->ymax >= rect.ymax);
+ changed = false;
+ }
+
+ if (changed) {
+ UI_view2d_curRect_validate(&ar->v2d);
+ }
+}
+
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
{
@@ -219,25 +289,76 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
/* flag the files as selected in the filelist */
- filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type);
+ filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
/* Don't act on multiple selected files */
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)) {
+ if (filelist_entry_select_index_get(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;
+ }
+ else {
+ ARegion *ar = CTX_wm_region(C);
+ const FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
+
+ /* Adjust view to display selection. Doing iterations for first and last
+ * selected item makes view showing as much of the selection possible.
+ * Not really useful if tiles are (almost) bigger than viewbounds though. */
+ if (((layout->flag & FILE_LAYOUT_HOR) && ar->winx > (1.2f * layout->tile_w)) ||
+ ((layout->flag & FILE_LAYOUT_VER) && ar->winy > (2.0f * layout->tile_h)))
+ {
+ file_ensure_inside_viewbounds(ar, sfile, sel.last);
+ file_ensure_inside_viewbounds(ar, sfile, sel.first);
+ }
+ }
+
/* update operator for name change event */
- file_draw_check_cb(C, NULL, NULL);
+ 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;
+ float mouseco_view[2];
+
+ UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
+
+ 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 = (int)mouseco_view[1];
+ 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 = (int)mouseco_view[0];
+ 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);
@@ -251,24 +372,40 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
result = WM_border_select_modal(C, op, event);
if (result == OPERATOR_RUNNING_MODAL) {
-
WM_operator_properties_border_to_rcti(op, &rect);
BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
sel = file_selection_get(C, &rect, 0);
- if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
- file_deselect_all(sfile, HILITED_FILE);
- filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL);
+ if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
+ int idx;
+
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
+ filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
+ for (idx = sel.last; idx >= 0; idx--) {
+ const FileDirEntry *file = filelist_file(sfile->files, idx);
+
+ /* dont highlight readonly file (".." or ".") on border select */
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ filelist_entry_select_set(sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
+ }
+
+ /* make sure highlight_file is no readonly file */
+ if (sel.last == 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->mval);
}
else {
- params->active_file = -1;
+ params->highlight_file = -1;
params->sel_first = params->sel_last = -1;
- file_deselect_all(sfile, HILITED_FILE);
+ fileselect_file_set(sfile, params->active_file);
+ file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
@@ -278,6 +415,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
static int file_border_select_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
rcti rect;
FileSelect ret;
const bool select = (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
@@ -286,14 +424,16 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rcti(op, &rect);
if (!extend) {
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- file_deselect_all(sfile, SELECTED_FILE);
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
}
BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect);
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
+
+ /* unselect '..' parent entry - it's not supposed to be selected if more than one file is selected */
+ filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+
if (FILE_SELECT_DIR == ret) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -340,10 +480,25 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin))
return OPERATOR_CANCELLED;
- /* single select, deselect all selected first */
- if (!extend) file_deselect_all(sfile, SELECTED_FILE);
+ if (sfile && sfile->params) {
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+
+ if ((idx >= 0) && (idx < numfiles)) {
+ /* single select, deselect all selected first */
+ if (!extend) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
+ }
+ }
ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
+
+ 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);
+ }
+
if (FILE_SELECT_DIR == ret)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
else if (FILE_SELECT_FILE == ret)
@@ -377,34 +532,267 @@ 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_entry_select_index_get(files, active_old, CHECK_ALL) &&
+ filelist_entry_select_index_get(files, active_new, CHECK_ALL))
+ {
+ /* 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_entry_select_index_get(files, other_site, CHECK_ALL));
+
+ /* don't change highlight_file 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 = extend ? 1 : 0;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (active < 0) {
+ return false;
+ }
+
+ if (extend) {
+ /* highlight the active walker file for extended selection for better visual feedback */
+ params->highlight_file = params->active_file;
+
+ /* 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);
+ }
+ 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) };
+
+ /* 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);
+ /* entire sel is cleared here, so select active again */
+ if (deselect) {
+ filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+ }
+ else {
+ filelist_entry_select_index_set(
+ files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+ }
+
+ BLI_assert(IN_RANGE(active, -1, numfiles));
+ fileselect_file_set(sfile, params->active_file);
+
+ /* ensure newly selected file is inside viewbounds */
+ file_ensure_inside_viewbounds(CTX_wm_region(C), sfile, params->active_file);
+
+ /* 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_files_ensure(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;
+ }
+ /* if we don't extend, selecting '..' (index == 0) is allowed so
+ * using key selection to go to parent directory is possible */
+ else if (active_new != 0) {
+ /* 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_files_ensure(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) {
- filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL);
+ if (has_selection) {
+ filelist_entries_select_index_range_set(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;
- filelist_select(sfile->files, &sel, FILE_SEL_ADD, SELECTED_FILE, check_type);
+ int i;
+
+ filelist_entries_select_index_range_set(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_entry_select_index_get(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;
}
@@ -424,18 +812,20 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot)
/* ---------- BOOKMARKS ----------- */
+/* Note we could get rid of this one, but it's used by some addon so... Does not hurt keeping it around for now. */
static int bookmark_select_exec(bContext *C, wmOperator *op)
{
SpaceFile *sfile = CTX_wm_space_file(C);
+ PropertyRNA *prop;
- if (RNA_struct_find_property(op->ptr, "dir")) {
+ if ((prop = RNA_struct_find_property(op->ptr, "dir"))) {
char entry[256];
FileSelectParams *params = sfile->params;
- RNA_string_get(op->ptr, "dir", entry);
+ RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
BLI_cleanup_dir(G.main->name, params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -465,17 +855,18 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct FSMenu *fsmenu = fsmenu_get();
+ struct FSMenu *fsmenu = ED_fsmenu_get();
struct FileSelectParams *params = ED_fileselect_get_params(sfile);
if (params->dir[0] != '\0') {
char name[FILE_MAX];
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, FS_INSERT_SAVE);
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, FS_INSERT_SAVE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
}
+ ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
return OPERATOR_FINISHED;
}
@@ -495,17 +886,27 @@ void FILE_OT_bookmark_add(wmOperatorType *ot)
static int bookmark_delete_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
- struct FSMenu *fsmenu = fsmenu_get();
- int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
-
- if (RNA_struct_find_property(op->ptr, "index")) {
- int index = RNA_int_get(op->ptr, "index");
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
+
+ if (prop) {
+ int index;
+ if (RNA_property_is_set(op->ptr, prop)) {
+ index = RNA_property_int_get(op->ptr, prop);
+ }
+ else { /* if index unset, use active bookmark... */
+ index = sfile->bookmarknr;
+ }
if ((index > -1) && (index < nentries)) {
char name[FILE_MAX];
fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
+ ED_area_tag_refresh(sa);
ED_area_tag_redraw(sa);
}
}
@@ -531,19 +932,150 @@ void FILE_OT_bookmark_delete(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ScrArea *sa = CTX_wm_area(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
+ int index;
+ bool changed = false;
+
+ for (index = 0; fsme; fsme = fsme_next) {
+ fsme_next = fsme->next;
+
+ if (!BLI_is_dir(fsme->path)) {
+ fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
+ changed = true;
+ }
+ else {
+ index++;
+ }
+ }
+
+ if (changed) {
+ char name[FILE_MAX];
+
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(fsmenu, name);
+ fsmenu_refresh_bookmarks_status(fsmenu);
+ ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(sa);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cleanup Bookmarks";
+ ot->description = "Delete all invalid bookmarks";
+ ot->idname = "FILE_OT_bookmark_cleanup";
+
+ /* api callbacks */
+ ot->exec = bookmark_cleanup_exec;
+ ot->poll = ED_operator_file_active;
+
+ /* properties */
+}
+
+enum {
+ FILE_BOOKMARK_MOVE_TOP = -2,
+ FILE_BOOKMARK_MOVE_UP = -1,
+ FILE_BOOKMARK_MOVE_DOWN = 1,
+ FILE_BOOKMARK_MOVE_BOTTOM = 2,
+};
+
+static int bookmark_move_exec(bContext *C, wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
+ struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
+ const struct FSMenuEntry *fsmentry_org = fsmentry;
+
+ char fname[FILE_MAX];
+
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
+ const int act_index = sfile->bookmarknr;
+ int new_index;
+
+ if (totitems < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (direction) {
+ case FILE_BOOKMARK_MOVE_TOP:
+ new_index = 0;
+ break;
+ case FILE_BOOKMARK_MOVE_BOTTOM:
+ new_index = totitems - 1;
+ break;
+ case FILE_BOOKMARK_MOVE_UP:
+ case FILE_BOOKMARK_MOVE_DOWN:
+ default:
+ new_index = (totitems + act_index + direction) % totitems;
+ break;
+ }
+
+ if (new_index == act_index) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
+ if (fsmentry != fsmentry_org) {
+ ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry);
+ }
+
+ /* Need to update active bookmark number. */
+ sfile->bookmarknr = new_index;
+
+ BLI_make_file_string("/", fname, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(fsmenu, fname);
+
+ ED_area_tag_redraw(sa);
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_bookmark_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
+ {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Move Bookmark";
+ ot->idname = "FILE_OT_bookmark_move";
+ ot->description = "Move the active bookmark up/down in the list";
+
+ /* api callbacks */
+ ot->poll = ED_operator_file_active;
+ ot->exec = bookmark_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER; /* No undo! */
+
+ RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *sa = CTX_wm_area(C);
char name[FILE_MAX];
- struct FSMenu *fsmenu = fsmenu_get();
+ struct FSMenu *fsmenu = ED_fsmenu_get();
- while (fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
+ while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0);
}
- BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+ BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
ED_area_tag_redraw(sa);
-
+
return OPERATOR_FINISHED;
}
@@ -568,31 +1100,31 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
if (sfile == NULL || sfile->files == NULL) return 0;
- numfiles = filelist_numfiles(sfile->files);
+ numfiles = filelist_files_ensure(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)
@@ -658,65 +1190,67 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
{
+ PropertyRNA *prop;
+
BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
- if (RNA_struct_find_property(op->ptr, "relative_path")) {
- if (RNA_boolean_get(op->ptr, "relative_path")) {
+
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
BLI_path_rel(filepath, G.main->name);
}
}
- if (RNA_struct_find_property(op->ptr, "filename")) {
- RNA_string_set(op->ptr, "filename", sfile->params->file);
+ if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
+ RNA_property_string_set(op->ptr, prop, sfile->params->file);
}
- if (RNA_struct_find_property(op->ptr, "directory")) {
- RNA_string_set(op->ptr, "directory", sfile->params->dir);
+ if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
+ RNA_property_string_set(op->ptr, prop, sfile->params->dir);
}
- if (RNA_struct_find_property(op->ptr, "filepath")) {
- RNA_string_set(op->ptr, "filepath", filepath);
+ if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
+ RNA_property_string_set(op->ptr, prop, filepath);
}
/* some ops have multiple files to select */
/* this is called on operators check() so clear collections first since
* they may be already set. */
{
- PointerRNA itemptr;
- PropertyRNA *prop_files = RNA_struct_find_property(op->ptr, "files");
- PropertyRNA *prop_dirs = RNA_struct_find_property(op->ptr, "dirs");
- int i, numfiles = filelist_numfiles(sfile->files);
+ int i, numfiles = filelist_files_ensure(sfile->files);
- if (prop_files) {
+ if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
+ PointerRNA itemptr;
int num_files = 0;
- RNA_property_collection_clear(op->ptr, prop_files);
+ RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
- struct direntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop_files, &itemptr);
- RNA_string_set(&itemptr, "name", file->relname);
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
+ FileDirEntry *file = filelist_file(sfile->files, i);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
num_files++;
}
}
/* make sure the file specified in the filename button is added even if no files selected */
if (0 == num_files) {
- RNA_property_collection_add(op->ptr, prop_files, &itemptr);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", sfile->params->file);
}
}
- if (prop_dirs) {
+ if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
+ PointerRNA itemptr;
int num_dirs = 0;
- RNA_property_collection_clear(op->ptr, prop_dirs);
+ RNA_property_collection_clear(op->ptr, prop);
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
- struct direntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
- RNA_string_set(&itemptr, "name", file->relname);
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) {
+ FileDirEntry *file = filelist_file(sfile->files, i);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
num_dirs++;
}
}
/* make sure the directory specified in the button is added even if no directory selected */
if (0 == num_dirs) {
- RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
RNA_string_set(&itemptr, "name", sfile->params->dir);
}
}
@@ -751,7 +1285,7 @@ void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
-void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
+void file_draw_check(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
@@ -771,11 +1305,18 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
}
}
+/* for use with; UI_block_func_set */
+void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
+{
+ file_draw_check(C);
+}
+
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- if (RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
- if (RNA_boolean_get(sfile->op->ptr, "check_existing")) {
+ 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)) {
@@ -788,23 +1329,42 @@ bool file_draw_check_exists(SpaceFile *sfile)
return false;
}
-/* sends events now, so things get handled on windowqueue level */
int file_exec(bContext *C, wmOperator *exec_op)
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
-
- if (sfile->op) {
+
+ /* directory change */
+ if (file && (file->typeflag & FILE_TYPE_DIR)) {
+ if (!file->relpath) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (FILENAME_IS_PARENT(file->relpath)) {
+ BLI_parent_dir(sfile->params->dir);
+ }
+ else {
+ BLI_cleanup_dir(G.main->name, sfile->params->dir);
+ strcat(sfile->params->dir, file->relpath);
+ BLI_add_slash(sfile->params->dir);
+ }
+
+ ED_file_change_dir(C, false);
+ }
+ /* opening file - sends events now, so things get handled on windowqueue level */
+ else if (sfile->op) {
wmOperator *op = sfile->op;
/* when used as a macro, for doubleclick,
* to prevent closing when doubleclicking on .. item */
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
+ const int numfiles = filelist_files_ensure(sfile->files);
int i, active = 0;
- for (i = 0; i < filelist_numfiles(sfile->files); i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
+ for (i = 0; i < numfiles; i++) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
active = 1;
break;
}
@@ -818,15 +1378,17 @@ int file_exec(bContext *C, wmOperator *exec_op)
file_sfile_to_operator(op, sfile, filepath);
if (BLI_exists(sfile->params->dir)) {
- fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, FS_INSERT_SAVE | FS_INSERT_FIRST);
+ fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
+ FS_INSERT_SAVE | FS_INSERT_FIRST);
}
- BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
- fsmenu_write_file(fsmenu_get(), filepath);
+ BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLENDER_BOOKMARK_FILE);
+ fsmenu_write_file(ED_fsmenu_get(), filepath);
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
}
-
+
return OPERATOR_FINISHED;
}
@@ -859,16 +1421,21 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
BLI_cleanup_dir(G.main->name, sfile->params->dir);
/* if not browsing in .blend file, we still want to check whether the path is a directory */
if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX], tgroup[FILE_MAX];
- if (BLO_is_a_library(sfile->params->dir, tdir, tgroup)) {
- file_change_dir(C, 0);
+ char tdir[FILE_MAX];
+ if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
+ ED_file_change_dir(C, false);
}
else {
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
}
else {
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
+ }
+ if (sfile->params->recursion_level > 1) {
+ /* Disable 'dirtree' recursion when going up in tree. */
+ sfile->params->recursion_level = 0;
+ filelist_setrecursion(sfile->files, sfile->params->recursion_level);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -896,9 +1463,10 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct FSMenu *fsmenu = fsmenu_get();
+ ScrArea *sa = CTX_wm_area(C);
+ struct FSMenu *fsmenu = ED_fsmenu_get();
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@@ -933,7 +1501,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -965,7 +1533,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
// update folders_prev so we can check for it in folderlist_clear_next()
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -988,11 +1556,11 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
return OPERATOR_PASS_THROUGH;
- numfiles = filelist_numfiles(sfile->files);
+ numfiles = filelist_files_ensure(sfile->files);
/* check if we are editing a name */
for (i = 0; i < numfiles; ++i) {
- if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) ) {
edit_idx = i;
break;
}
@@ -1110,10 +1678,12 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
{
char name[FILE_MAXFILE];
char path[FILE_MAX];
- int generate_name = 1;
+ bool generate_name = true;
+ PropertyRNA *prop;
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ ScrArea *sa = CTX_wm_area(C);
if (!sfile->params) {
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
@@ -1122,9 +1692,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
path[0] = '\0';
- if (RNA_struct_find_property(op->ptr, "directory")) {
- RNA_string_get(op->ptr, "directory", path);
- if (path[0] != '\0') generate_name = 0;
+ if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
+ RNA_property_string_get(op->ptr, prop, path);
+ if (path[0] != '\0') {
+ generate_name = false;
+ }
}
if (generate_name) {
@@ -1134,10 +1706,23 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
}
+ else { /* We assume we are able to generate a valid name! */
+ char org_path[FILE_MAX];
+
+ BLI_strncpy(org_path, path, sizeof(org_path));
+ if (BLI_path_make_safe(path)) {
+ BKE_reportf(op->reports, RPT_WARNING, "'%s' given path is OS-invalid, creating '%s' path instead",
+ org_path, path);
+ }
+ }
/* create the file */
- BLI_dir_create_recursive(path);
+ if (!BLI_dir_create_recursive(path)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
+ return OPERATOR_CANCELLED;
+ }
+ /* Should no more be needed, now that BLI_dir_create_recursive returns a success state - but kept just in case. */
if (!BLI_exists(path)) {
BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
return OPERATOR_CANCELLED;
@@ -1151,11 +1736,11 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
if (RNA_boolean_get(op->ptr, "open")) {
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
}
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1185,6 +1770,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
}
+/* TODO This should go to BLI_path_utils. */
static void file_expand_directory(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -1197,7 +1783,7 @@ static void file_expand_directory(bContext *C)
else if (sfile->params->dir[0] == '~') {
char tmpstr[sizeof(sfile->params->dir) - 1];
BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr));
- BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr);
+ BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr);
}
else if (sfile->params->dir[0] == '\0')
@@ -1225,6 +1811,7 @@ static void file_expand_directory(bContext *C)
}
}
+/* TODO check we still need this, it's annoying to have OS-specific code here... :/ */
#if defined(WIN32)
static bool can_create_dir(const char *dir)
{
@@ -1260,7 +1847,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
if (BLI_exists(sfile->params->dir)) {
/* if directory exists, enter it immediately */
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -1311,6 +1898,9 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, sfile->params->file, matched_file);
+ /* *After* file_select_match! */
+ BLI_filename_make_safe(sfile->params->file);
+
if (matches) {
/* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
sfile->params->file[0] = '\0';
@@ -1329,23 +1919,26 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- file_change_dir(C, 1);
+ ED_file_change_dir(C, true);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
else if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX], tgroup[FILE_MAX];
+ char tdir[FILE_MAX];
BLI_add_slash(filepath);
- if (BLO_is_a_library(filepath, tdir, tgroup)) {
+ if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
- file_change_dir(C, 0);
+ ED_file_change_dir(C, false);
UI_textbutton_activate_but(C, but);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
}
}
+ else if (matches > 1) {
+ file_draw_check(C);
+ }
}
}
@@ -1365,10 +1958,11 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
+ ScrArea *sa = CTX_wm_area(C);
if (sfile->params) {
sfile->params->flag ^= FILE_HIDE_DOT;
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -1388,37 +1982,37 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_buttons_region(ScrArea *sa)
+ARegion *file_tools_region(ScrArea *sa)
{
ARegion *ar, *arnew;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_CHANNELS)
- return ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL)
+ return ar;
/* add subdiv level; after header */
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_HEADER)
- break;
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
/* is error! */
- if (ar == NULL) return NULL;
-
- arnew = MEM_callocN(sizeof(ARegion), "buttons for file panels");
+ if (ar == NULL)
+ return NULL;
+ arnew = MEM_callocN(sizeof(ARegion), "tools for file");
BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_CHANNELS;
+ arnew->regiontype = RGN_TYPE_TOOLS;
arnew->alignment = RGN_ALIGN_LEFT;
-
- arnew->flag = RGN_FLAG_HIDDEN;
-
+
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, arnew, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
+
return arnew;
}
static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
{
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_buttons_region(sa);
+ ARegion *ar = file_tools_region(sa);
if (ar)
ED_region_toggle_hidden(C, ar);
@@ -1448,7 +2042,7 @@ static int file_filenum_exec(bContext *C, wmOperator *op)
if (sfile->params && (inc != 0)) {
BLI_newname(sfile->params->file, inc);
ED_area_tag_redraw(sa);
- file_draw_check_cb(C, NULL, NULL);
+ file_draw_check(C);
// WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1477,12 +2071,12 @@ 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 numfiles = filelist_numfiles(sfile->files);
- if ( (0 <= idx) && (idx < numfiles) ) {
- struct direntry *file = filelist_file(sfile->files, idx);
- filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL);
- BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+ if ((0 <= idx) && (idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, idx);
+ filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
+ BLI_strncpy(sfile->params->renameedit, file->relpath, FILE_MAXFILE);
sfile->params->renamefile[0] = '\0';
}
ED_area_tag_redraw(sa);
@@ -1494,20 +2088,34 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
static int file_rename_poll(bContext *C)
{
- int poll = ED_operator_file_active(C);
+ bool poll = ED_operator_file_active(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- if (sfile->params->active_file < 0) {
- poll = 0;
+ int idx = sfile->params->highlight_file;
+ int numfiles = filelist_files_ensure(sfile->files);
+
+ if ((0 <= idx) && (idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, idx);
+ if (FILENAME_IS_CURRPAR(file->relpath)) {
+ poll = false;
+ }
+ }
+
+ if (sfile->params->highlight_file < 0) {
+ poll = false;
}
else {
- char dir[FILE_MAX], group[FILE_MAX];
- if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
+ char dir[FILE_MAX];
+ if (filelist_islibrary(sfile->files, dir, NULL)) {
+ poll = false;
+ }
}
}
- else
- poll = 0;
+ else {
+ poll = false;
+ }
+
return poll;
}
@@ -1530,14 +2138,14 @@ static int file_delete_poll(bContext *C)
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile && sfile->params) {
- char dir[FILE_MAX], group[FILE_MAX];
- int numfiles = filelist_numfiles(sfile->files);
+ char dir[FILE_MAX];
+ int numfiles = filelist_files_ensure(sfile->files);
int i;
int num_selected = 0;
- if (filelist_islibrary(sfile->files, dir, group)) poll = 0;
+ if (filelist_islibrary(sfile->files, dir, NULL)) poll = 0;
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
num_selected++;
}
}
@@ -1556,19 +2164,20 @@ int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
char str[FILE_MAX];
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- struct direntry *file;
- int numfiles = filelist_numfiles(sfile->files);
+ ScrArea *sa = CTX_wm_area(C);
+ FileDirEntry *file;
+ int numfiles = filelist_files_ensure(sfile->files);
int i;
for (i = 0; i < numfiles; i++) {
- if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
+ if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
- BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
+ BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath);
BLI_delete(str, false, false);
}
}
- ED_fileselect_clear(wm, sfile);
+ ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;