[Bf-blender-cvs] [939948c] master: File Browser Arrow Keys Navigation

Julian Eisel noreply at git.blender.org
Thu Jun 11 17:21:21 CEST 2015


Commit: 939948c23384119dbcc7d94614cabf76dde22391
Author: Julian Eisel
Date:   Thu Jun 11 17:20:29 2015 +0200
Branches: master
https://developer.blender.org/rB939948c23384119dbcc7d94614cabf76dde22391

File Browser Arrow Keys Navigation

Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.

When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting

Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between

>From which file do we start navigating?
>From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)

(Also tweaks color for highlighted file for better feedback)

D1297, Review done by @campbellbarton, thx a lot :)

===================================================================

M	source/blender/blenlib/BLI_rect.h
M	source/blender/blenlib/intern/rct.c
M	source/blender/editors/space_file/CMakeLists.txt
M	source/blender/editors/space_file/file_draw.c
M	source/blender/editors/space_file/file_intern.h
M	source/blender/editors/space_file/file_ops.c
A	source/blender/editors/space_file/file_utils.c
M	source/blender/editors/space_file/filesel.c
M	source/blender/editors/space_file/space_file.c
M	source/blender/makesdna/DNA_space_types.h

===================================================================

diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index e0a0b34..242ba9f 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -78,6 +78,10 @@ bool BLI_rctf_isect_x(const rctf *rect, const float x);
 bool BLI_rctf_isect_y(const rctf *rect, const float y);
 bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
 bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
+int BLI_rcti_length_x(const rcti *rect, const int x);
+int BLI_rcti_length_y(const rcti *rect, const int y);
+float BLI_rctf_length_x(const rctf *rect, const float x);
+float BLI_rctf_length_y(const rctf *rect, const float y);
 bool BLI_rcti_isect_segment(const struct rcti *rect, const int s1[2], const int s2[2]);
 bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2]);
 bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 1edc900..8de5d2e 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -123,6 +123,38 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
 }
 
 /**
+ * \returns shortest distance from \a rect to x/y (0 if inside)
+*/
+
+int BLI_rcti_length_x(const rcti *rect, const int x)
+{
+	if (x < rect->xmin) return rect->xmin - x;
+	if (x > rect->xmax) return x - rect->xmax;
+	return 0;
+}
+
+int BLI_rcti_length_y(const rcti *rect, const int y)
+{
+	if (y < rect->ymin) return rect->ymin - y;
+	if (y > rect->ymax) return y - rect->ymax;
+	return 0;
+}
+
+float BLI_rctf_length_x(const rctf *rect, const float x)
+{
+	if (x < rect->xmin) return rect->xmin - x;
+	if (x > rect->xmax) return x - rect->xmax;
+	return 0.0f;
+}
+
+float BLI_rctf_length_y(const rctf *rect, const float y)
+{
+	if (y < rect->ymin) return rect->ymin - y;
+	if (y > rect->ymax) return y - rect->ymax;
+	return 0.0f;
+}
+
+/**
  * is \a rct_b inside \a rct_a
  */
 bool BLI_rctf_inside_rctf(rctf *rct_a, const rctf *rct_b)
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index fc007a6..4c33499 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 0e4d885..6347ce7 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -543,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)) {
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index dbb5e8a..d7af6c9 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -59,8 +59,17 @@ bool file_draw_check_exists(SpaceFile *sfile);
 /* file_ops.h */
 struct wmOperatorType;
 struct wmOperator;
+
+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);
@@ -111,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 f8d13bb..680a28f 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);
@@ -242,6 +243,53 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
 	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 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 +324,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 +409,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 +457,240 @@ 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;
+
+	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 (!params || active < 0) return false;
+
+	/* highlight t

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list