Blender  V3.3
file_ops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
8 #include "BLI_utildefines.h"
9 
10 #include "BLI_blenlib.h"
11 #include "BLI_linklist.h"
12 #include "BLI_math.h"
13 
14 #include "BLO_readfile.h"
15 
16 #include "BKE_appdir.h"
17 #include "BKE_context.h"
18 #include "BKE_global.h"
19 #include "BKE_main.h"
20 #include "BKE_report.h"
21 #include "BKE_screen.h"
22 
23 #ifdef WIN32
24 # include "BLI_winstuff.h"
25 #endif
26 
27 #include "ED_asset.h"
28 #include "ED_fileselect.h"
29 #include "ED_screen.h"
30 #include "ED_select_utils.h"
31 
32 #include "UI_interface.h"
33 #include "UI_interface_icons.h"
34 #include "UI_resources.h"
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40 
41 #include "UI_view2d.h"
42 
43 #include "WM_api.h"
44 #include "WM_types.h"
45 
46 #include "file_intern.h"
47 #include "filelist.h"
48 #include "fsmenu.h"
49 
50 #include <ctype.h>
51 #include <errno.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 
56 /* -------------------------------------------------------------------- */
61  ARegion *region,
62  const rcti *rect_region)
63 {
64  FileSelection sel;
65 
66  View2D *v2d = &region->v2d;
67  rcti rect_view;
68  rctf rect_view_fl;
69  rctf rect_region_fl;
70 
71  BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
72 
73  /* Okay, manipulating v2d rects here is hacky... */
74  v2d->mask.ymax -= sfile->layout->offset_top;
75  v2d->cur.ymax -= sfile->layout->offset_top;
76  UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
77  v2d->mask.ymax += sfile->layout->offset_top;
78  v2d->cur.ymax += sfile->layout->offset_top;
79 
80  BLI_rcti_init(&rect_view,
81  (int)(v2d->tot.xmin + rect_view_fl.xmin),
82  (int)(v2d->tot.xmin + rect_view_fl.xmax),
83  (int)(v2d->tot.ymax - rect_view_fl.ymin),
84  (int)(v2d->tot.ymax - rect_view_fl.ymax));
85 
86  sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
87 
88  return sel;
89 }
90 
91 typedef enum FileSelect {
96 
97 static void clamp_to_filelist(int numfiles, FileSelection *sel)
98 {
99  /* box select before the first file */
100  if ((sel->first < 0) && (sel->last >= 0)) {
101  sel->first = 0;
102  }
103  /* don't select if everything is outside filelist */
104  if ((sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles))) {
105  sel->first = -1;
106  sel->last = -1;
107  }
108 
109  /* fix if last file invalid */
110  if ((sel->first > 0) && (sel->last < 0)) {
111  sel->last = numfiles - 1;
112  }
113 
114  /* clamp */
115  if ((sel->first >= numfiles)) {
116  sel->first = numfiles - 1;
117  }
118  if ((sel->last >= numfiles)) {
119  sel->last = numfiles - 1;
120  }
121 }
122 
123 static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
124 {
125  ARegion *region = CTX_wm_region(C);
126  SpaceFile *sfile = CTX_wm_space_file(C);
127  int numfiles = filelist_files_ensure(sfile->files);
128  FileSelection sel;
129 
130  sel = find_file_mouse_rect(sfile, region, rect);
131  if (!((sel.first == -1) && (sel.last == -1))) {
132  clamp_to_filelist(numfiles, &sel);
133  }
134 
135  /* if desired, fill the selection up from the last selected file to the current one */
136  if (fill && (sel.last >= 0) && (sel.last < numfiles)) {
137  int f;
138  /* Try to find a smaller-index selected item. */
139  for (f = sel.last; f >= 0; f--) {
141  break;
142  }
143  }
144  if (f >= 0) {
145  sel.first = f + 1;
146  }
147  /* If none found, try to find a higher-index selected item. */
148  else {
149  for (f = sel.first; f < numfiles; f++) {
151  break;
152  }
153  }
154  if (f < numfiles) {
155  sel.last = f - 1;
156  }
157  }
158  }
159  return sel;
160 }
161 
162 static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
163 {
164  Main *bmain = CTX_data_main(C);
166  SpaceFile *sfile = CTX_wm_space_file(C);
168  int numfiles = filelist_files_ensure(sfile->files);
169  const FileDirEntry *file;
170 
171  /* make the selected file active */
172  if ((selected_idx >= 0) && (selected_idx < numfiles) &&
173  (file = filelist_file(sfile->files, selected_idx))) {
174  params->highlight_file = selected_idx;
175  params->active_file = selected_idx;
176 
177  if (file->typeflag & FILE_TYPE_DIR) {
178  const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
179 
180  if (do_diropen == false) {
181  retval = FILE_SELECT_DIR;
182  }
183  /* the path is too long and we are not going up! */
184  else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
185  // XXX error("Path too long, cannot enter this directory");
186  }
187  else {
188  if (is_parent_dir) {
189  /* avoids /../../ */
191 
192  if (params->recursion_level > 1) {
193  /* Disable 'dirtree' recursion when going up in tree. */
194  params->recursion_level = 0;
195  filelist_setrecursion(sfile->files, params->recursion_level);
196  }
197  }
198  else if (file->redirection_path) {
199  BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir));
202  }
203  else {
205  strcat(params->dir, file->relpath);
207  }
208 
210  retval = FILE_SELECT_DIR;
211  }
212  }
213  else {
214  retval = FILE_SELECT_FILE;
215  }
216  fileselect_file_set(sfile, selected_idx);
217  }
218  return retval;
219 }
220 
224 static bool file_is_any_selected(struct FileList *files)
225 {
226  const int numfiles = filelist_files_ensure(files);
227  int i;
228 
229  /* Is any file selected ? */
230  for (i = 0; i < numfiles; i++) {
232  return true;
233  }
234  }
235 
236  return false;
237 }
238 
240 {
241  const int numfiles = filelist_files_ensure(files);
242  FileSelection selection = {-1, -1};
243 
244  /* Iterate over the files once but in two loops, one to find the first selected file, and the
245  * other to find the last. */
246 
247  int file_index;
248  for (file_index = 0; file_index < numfiles; file_index++) {
249  if (filelist_entry_is_selected(files, file_index)) {
250  /* First selected entry found. */
251  selection.first = file_index;
252  break;
253  }
254  }
255 
256  for (; file_index < numfiles; file_index++) {
257  if (filelist_entry_is_selected(files, file_index)) {
258  selection.last = file_index;
259  /* Keep looping, we may find more selected files. */
260  }
261  }
262 
263  return selection;
264 }
265 
269 static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
270 {
271  FileLayout *layout = ED_fileselect_get_layout(sfile, region);
272  rctf *cur = &region->v2d.cur;
273  rcti rect;
274  bool changed = true;
275 
276  file_tile_boundbox(region, layout, file, &rect);
277 
278  /* down - also use if tile is higher than viewbounds so view is aligned to file name */
279  if (cur->ymin > rect.ymin || layout->tile_h > region->winy) {
280  cur->ymin = rect.ymin - (2 * layout->tile_border_y);
281  cur->ymax = cur->ymin + region->winy;
282  }
283  /* up */
284  else if ((cur->ymax - layout->offset_top) < rect.ymax) {
285  cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
286  cur->ymin = cur->ymax - region->winy;
287  }
288  /* left - also use if tile is wider than viewbounds so view is aligned to file name */
289  else if (cur->xmin > rect.xmin || layout->tile_w > region->winx) {
290  cur->xmin = rect.xmin - layout->tile_border_x;
291  cur->xmax = cur->xmin + region->winx;
292  }
293  /* right */
294  else if (cur->xmax < rect.xmax) {
295  cur->xmax = rect.xmax + (2 * layout->tile_border_x);
296  cur->xmin = cur->xmax - region->winx;
297  }
298  else {
299  BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
300  (cur->ymax - layout->offset_top) >= rect.ymax);
301  changed = false;
302  }
303 
304  if (changed) {
306  }
307 }
308 
310  SpaceFile *sfile,
311  FileSelection *sel)
312 {
313  const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
314 
315  if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) &&
316  ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h))) {
317  return;
318  }
319 
320  /* Adjust view to display selection. Doing iterations for first and last
321  * selected item makes view showing as much of the selection possible.
322  * Not really useful if tiles are (almost) bigger than viewbounds though. */
323  file_ensure_inside_viewbounds(region, sfile, sel->last);
324  file_ensure_inside_viewbounds(region, sfile, sel->first);
325 }
326 
328  bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
329 {
330  SpaceFile *sfile = CTX_wm_space_file(C);
333  FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
334  const FileCheckType check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
335 
336  /* flag the files as selected in the filelist */
338  sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
339 
340  /* Don't act on multiple selected files */
341  if (sel.first != sel.last) {
342  select = 0;
343  }
344 
345  /* Do we have a valid selection and are we actually selecting */
346  if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
347  /* Check last selection, if selected, act on the file or dir */
348  if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
349  retval = file_select_do(C, sel.last, do_diropen);
350  }
351  }
352 
353  if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
354  params->active_file = -1;
355  }
356  else if (sel.last >= 0) {
357  ARegion *region = CTX_wm_region(C);
358  file_ensure_selection_inside_viewbounds(region, sfile, &sel);
359  }
360 
361  /* update operator for name change event */
363 
364  return retval;
365 }
366 
369 /* -------------------------------------------------------------------- */
374  ARegion *region,
375  const FileSelection *sel,
376  const int mouse_xy[2])
377 {
378  FileLayout *layout = ED_fileselect_get_layout(sfile, region);
379  rcti bounds_first, bounds_last;
380  int dist_first, dist_last;
381  float mouseco_view[2];
382 
383  UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
384 
385  file_tile_boundbox(region, layout, sel->first, &bounds_first);
386  file_tile_boundbox(region, layout, sel->last, &bounds_last);
387 
388  /* are first and last in the same column (horizontal layout)/row (vertical layout)? */
389  if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
390  (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) {
391  /* use vertical distance */
392  const int my_loc = (int)mouseco_view[1];
393  dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
394  dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
395  }
396  else {
397  /* use horizontal distance */
398  const int mx_loc = (int)mouseco_view[0];
399  dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
400  dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
401  }
402 
403  return (dist_first < dist_last) ? sel->first : sel->last;
404 }
405 
406 static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
407 {
408  ARegion *region = CTX_wm_region(C);
409  SpaceFile *sfile = CTX_wm_space_file(C);
411  FileSelection sel;
412  rcti rect;
413 
414  int result;
415 
416  result = WM_gesture_box_modal(C, op, event);
417 
420 
421  ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
422 
423  sel = file_selection_get(C, &rect, 0);
424  if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
425  int idx;
426 
431 
432  for (idx = sel.last; idx >= 0; idx--) {
433  const FileDirEntry *file = filelist_file(sfile->files, idx);
434 
435  /* Don't highlight read-only file (".." or ".") on box select. */
436  if (FILENAME_IS_CURRPAR(file->relpath)) {
439  }
440 
441  /* make sure highlight_file is no readonly file */
442  if (sel.last == idx) {
443  params->highlight_file = idx;
444  }
445  }
446  }
447  params->sel_first = sel.first;
448  params->sel_last = sel.last;
449  params->active_file = file_box_select_find_last_selected(sfile, region, &sel, event->mval);
450  }
451  else {
452  params->highlight_file = -1;
453  params->sel_first = params->sel_last = -1;
454  fileselect_file_set(sfile, params->active_file);
457  }
458 
459  return result;
460 }
461 
463 {
464  ARegion *region = CTX_wm_region(C);
465  SpaceFile *sfile = CTX_wm_space_file(C);
466  rcti rect;
467  FileSelect ret;
468 
470 
471  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
472  const bool select = (sel_op != SEL_OP_SUB);
473  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
475  }
476 
477  ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
478 
479  ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
480 
481  /* unselect '..' parent entry - it's not supposed to be selected if more than
482  * one file is selected */
484 
485  if (FILE_SELECT_DIR == ret) {
487  }
488  else if (FILE_SELECT_FILE == ret) {
490  }
491  return OPERATOR_FINISHED;
492 }
493 
495 {
496  /* identifiers */
497  ot->name = "Box Select";
498  ot->description = "Activate/select the file(s) contained in the border";
499  ot->idname = "FILE_OT_select_box";
500 
501  /* api callbacks */
505  /* Operator works for file or asset browsing */
508 
509  /* properties */
512 }
513 
516 /* -------------------------------------------------------------------- */
520 static rcti file_select_mval_to_select_rect(const int mval[2])
521 {
522  rcti rect;
523  rect.xmin = rect.xmax = mval[0];
524  rect.ymin = rect.ymax = mval[1];
525  return rect;
526 }
527 
529 {
530  ARegion *region = CTX_wm_region(C);
531  SpaceFile *sfile = CTX_wm_space_file(C);
532  FileSelect ret;
533  rcti rect;
534  const bool extend = RNA_boolean_get(op->ptr, "extend");
535  const bool fill = RNA_boolean_get(op->ptr, "fill");
536  const bool do_diropen = RNA_boolean_get(op->ptr, "open");
537  const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
538  const bool only_activate_if_selected = RNA_boolean_get(op->ptr, "only_activate_if_selected");
539  /* Used so right mouse clicks can do both, activate and spawn the context menu. */
540  const bool pass_through = RNA_boolean_get(op->ptr, "pass_through");
541  bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
542 
543  if (region->regiontype != RGN_TYPE_WINDOW) {
544  return OPERATOR_CANCELLED;
545  }
546 
547  int mval[2];
548  mval[0] = RNA_int_get(op->ptr, "mouse_x");
549  mval[1] = RNA_int_get(op->ptr, "mouse_y");
550  rect = file_select_mval_to_select_rect(mval);
551 
552  if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &region->v2d, rect.xmin, rect.ymin)) {
554  }
555 
556  if (extend || fill) {
557  wait_to_deselect_others = false;
558  }
559 
560  int ret_val = OPERATOR_FINISHED;
561 
563  if (sfile && params) {
564  int idx = params->highlight_file;
565  int numfiles = filelist_files_ensure(sfile->files);
566 
567  if ((idx >= 0) && (idx < numfiles)) {
568  const bool is_selected = filelist_entry_select_index_get(sfile->files, idx, CHECK_ALL) &
570  if (only_activate_if_selected && is_selected) {
571  /* Don't deselect other items. */
572  }
573  else if (wait_to_deselect_others && is_selected) {
574  ret_val = OPERATOR_RUNNING_MODAL;
575  }
576  /* single select, deselect all selected first */
577  else if (!extend) {
579  }
580  }
581  }
582 
583  ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
584 
585  if (extend) {
586  /* unselect '..' parent entry - it's not supposed to be selected if more
587  * than one file is selected */
589  }
590 
591  if (ret == FILE_SELECT_NOTHING) {
592  if (deselect_all) {
594  }
595  }
596  else if (ret == FILE_SELECT_DIR) {
598  }
599  else if (ret == FILE_SELECT_FILE) {
601  }
602 
603  WM_event_add_mousemove(CTX_wm_window(C)); /* for directory changes */
605 
606  if ((ret_val == OPERATOR_FINISHED) && pass_through) {
607  ret_val |= OPERATOR_PASS_THROUGH;
608  }
609  return ret_val;
610 }
611 
613 {
614  PropertyRNA *prop;
615 
616  /* identifiers */
617  ot->name = "Select";
618  ot->idname = "FILE_OT_select";
619  ot->description = "Handle mouse clicks to select and activate items";
620 
621  /* api callbacks */
625  /* Operator works for file or asset browsing */
627 
628  /* properties */
630  prop = RNA_def_boolean(ot->srna,
631  "extend",
632  false,
633  "Extend",
634  "Extend selection instead of deselecting everything first");
636  prop = RNA_def_boolean(
637  ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
639  prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
641  prop = RNA_def_boolean(ot->srna,
642  "deselect_all",
643  false,
644  "Deselect On Nothing",
645  "Deselect all when nothing under the cursor");
647  prop = RNA_def_boolean(ot->srna,
648  "only_activate_if_selected",
649  false,
650  "Only Activate if Selected",
651  "Do not change selection if the item under the cursor is already "
652  "selected, only activate it");
654  prop = RNA_def_boolean(ot->srna,
655  "pass_through",
656  false,
657  "Pass Through",
658  "Even on successful execution, pass the event on so other operators can "
659  "execute on it as well");
661 }
662 
665 /* -------------------------------------------------------------------- */
673  ARegion *region,
674  SpaceFile *sfile,
675  const int direction,
676  const int numfiles,
677  const int active_old,
678  const int active_new,
679  const int other_site,
680  const bool has_selection,
681  const bool extend,
682  const bool fill)
683 {
685  struct FileList *files = sfile->files;
686  const int last_sel = params->active_file; /* store old value */
687  int active = active_old; /* could use active_old instead, just for readability */
688  bool deselect = false;
689 
691 
692  if (numfiles == 0) {
693  /* No files visible, nothing to do. */
694  return false;
695  }
696 
697  if (has_selection) {
698  if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
699  filelist_entry_select_index_get(files, active_new, CHECK_ALL)) {
700  /* conditions for deselecting: initial file is selected, new file is
701  * selected and either other_side isn't selected/found or we use fill */
702  deselect = (fill || other_site == -1 ||
703  !filelist_entry_select_index_get(files, other_site, CHECK_ALL));
704 
705  /* don't change highlight_file here since we either want to deselect active or we want
706  * to walk through a block of selected files without selecting/deselecting anything */
707  params->active_file = active_new;
708  /* but we want to change active if we use fill
709  * (needed to get correct selection bounds) */
710  if (deselect && fill) {
711  active = active_new;
712  }
713  }
714  else {
715  /* regular selection change */
716  params->active_file = active = active_new;
717  }
718  }
719  else {
720  /* select last file */
721  if (ELEM(direction, UI_SELECT_WALK_UP, UI_SELECT_WALK_LEFT)) {
722  params->active_file = active = numfiles - 1;
723  }
724  /* select first file */
725  else if (ELEM(direction, UI_SELECT_WALK_DOWN, UI_SELECT_WALK_RIGHT)) {
726  params->active_file = active = 0;
727  }
728  else {
729  BLI_assert(0);
730  }
731  }
732 
733  if (active < 0) {
734  return false;
735  }
736 
737  if (extend) {
738  /* highlight the active walker file for extended selection for better visual feedback */
739  params->highlight_file = params->active_file;
740 
741  /* unselect '..' parent entry - it's not supposed to be selected if more
742  * than one file is selected */
744  }
745  else {
746  /* deselect all first */
748 
749  /* highlight file under mouse pos */
750  params->highlight_file = -1;
752  }
753 
754  /* do the actual selection */
755  if (fill) {
756  FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)};
757 
758  /* fill selection between last and first selected file */
760  files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
761  /* entire sel is cleared here, so select active again */
762  if (deselect) {
764  }
765 
766  /* unselect '..' parent entry - it's not supposed to be selected if more
767  * than one file is selected */
768  if ((sel.last - sel.first) > 1) {
770  }
771  }
772  else {
775  }
776 
777  BLI_assert(IN_RANGE(active, -1, numfiles));
778  fileselect_file_set(sfile, params->active_file);
779 
780  /* ensure newly selected file is inside viewbounds */
781  file_ensure_inside_viewbounds(region, sfile, params->active_file);
782 
783  /* selection changed */
784  return true;
785 }
786 
791  SpaceFile *sfile,
793  const int direction,
794  const bool extend,
795  const bool fill)
796 {
797  wmWindow *win = CTX_wm_window(C);
798  ARegion *region = CTX_wm_region(C);
799  struct FileList *files = sfile->files;
800  const int numfiles = filelist_files_ensure(files);
801  const bool has_selection = file_is_any_selected(files);
802  const int active_old = params->active_file;
803  int active_new = -1;
804  int other_site = -1; /* file on the other site of active_old */
805 
806  /* *** get all needed files for handling selection *** */
807 
808  if (numfiles == 0) {
809  /* No files visible, nothing to do. */
810  return false;
811  }
812 
813  if (has_selection) {
814  FileLayout *layout = ED_fileselect_get_layout(sfile, region);
815  const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
816 
817  if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_UP) ||
818  (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_LEFT)) {
819  active_new = active_old - 1;
820  other_site = active_old + 1;
821  }
822  else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_DOWN) ||
823  (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_RIGHT)) {
824  active_new = active_old + 1;
825  other_site = active_old - 1;
826  }
827  else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_LEFT) ||
828  (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_UP)) {
829  active_new = active_old - idx_shift;
830  other_site = active_old + idx_shift;
831  }
832  else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_RIGHT) ||
833  (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_DOWN)) {
834 
835  active_new = active_old + idx_shift;
836  other_site = active_old - idx_shift;
837  }
838  else {
839  BLI_assert(0);
840  }
841 
842  if (!IN_RANGE(active_new, -1, numfiles)) {
843  if (extend) {
844  /* extend to invalid file -> abort */
845  return false;
846  }
847  /* if we don't extend, selecting '..' (index == 0) is allowed so
848  * using key selection to go to parent directory is possible */
849  if (active_new != 0) {
850  /* select initial file */
851  active_new = active_old;
852  }
853  }
854  if (!IN_RANGE(other_site, 0, numfiles)) {
855  other_site = -1;
856  }
857  }
858 
860  region,
861  sfile,
862  direction,
863  numfiles,
864  active_old,
865  active_new,
866  other_site,
867  has_selection,
868  extend,
869  fill);
870 }
871 
872 static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
873 {
874  SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
876  const int direction = RNA_enum_get(op->ptr, "direction");
877  const bool extend = RNA_boolean_get(op->ptr, "extend");
878  const bool fill = RNA_boolean_get(op->ptr, "fill");
879 
880  if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
882  return OPERATOR_FINISHED;
883  }
884 
885  return OPERATOR_CANCELLED;
886 }
887 
889 {
890  PropertyRNA *prop;
891 
892  /* identifiers */
893  ot->name = "Walk Select/Deselect File";
894  ot->description = "Select/Deselect files by walking through them";
895  ot->idname = "FILE_OT_select_walk";
896 
897  /* api callbacks */
899  /* Operator works for file or asset browsing */
901 
902  /* properties */
904  prop = RNA_def_boolean(ot->srna,
905  "extend",
906  false,
907  "Extend",
908  "Extend selection instead of deselecting everything first");
910  prop = RNA_def_boolean(
911  ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
913 }
914 
917 /* -------------------------------------------------------------------- */
922 {
924  SpaceFile *sfile = CTX_wm_space_file(C);
926  FileSelection sel;
927  const int numfiles = filelist_files_ensure(sfile->files);
928  int action = RNA_enum_get(op->ptr, "action");
929 
930  if (action == SEL_TOGGLE) {
931  action = file_is_any_selected(sfile->files) ? SEL_DESELECT : SEL_SELECT;
932  }
933 
934  sel.first = 0;
935  sel.last = numfiles - 1;
936 
937  FileCheckType check_type;
938  FileSelType filesel_type;
939 
940  switch (action) {
941  case SEL_SELECT:
942  case SEL_INVERT: {
943  check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
944  filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD;
945  break;
946  }
947  case SEL_DESELECT: {
948  check_type = CHECK_ALL;
949  filesel_type = FILE_SEL_REMOVE;
950  break;
951  }
952  default: {
953  BLI_assert(0);
954  return OPERATOR_CANCELLED;
955  }
956  }
957 
959  sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type);
960 
961  params->active_file = -1;
962  if (action != SEL_DESELECT) {
963  for (int i = 0; i < numfiles; i++) {
964  if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
965  params->active_file = i;
966  break;
967  }
968  }
969  }
970 
974 
975  return OPERATOR_FINISHED;
976 }
977 
979 {
980  /* identifiers */
981  ot->name = "(De)select All Files";
982  ot->description = "Select or deselect all files";
983  ot->idname = "FILE_OT_select_all";
984 
985  /* api callbacks */
987  /* Operator works for file or asset browsing */
989 
990  /* properties */
992 }
993 
996 /* -------------------------------------------------------------------- */
1001 {
1002  SpaceFile *sfile = CTX_wm_space_file(C);
1005 
1006  if (sel.first == -1 && sel.last == -1 && params->active_file == -1) {
1007  /* Nothing was selected. */
1008  return OPERATOR_CANCELLED;
1009  }
1010 
1011  /* Extend the selection area with the active file, as it may not be selected but still is
1012  * important to have in view. */
1013  if (sel.first == -1 || params->active_file < sel.first) {
1014  sel.first = params->active_file;
1015  }
1016  if (sel.last == -1 || params->active_file > sel.last) {
1017  sel.last = params->active_file;
1018  }
1019 
1020  ScrArea *area = CTX_wm_area(C);
1021  ARegion *region = CTX_wm_region(C);
1022  file_ensure_selection_inside_viewbounds(region, sfile, &sel);
1023 
1024  file_draw_check(C);
1027 
1028  return OPERATOR_FINISHED;
1029 }
1030 
1032 {
1033  /* identifiers */
1034  ot->name = "Frame Selected";
1035  ot->description = "Scroll the selected files into view";
1036  ot->idname = "FILE_OT_view_selected";
1037 
1038  /* api callbacks */
1040  /* Operator works for file or asset browsing */
1042 }
1043 
1046 /* -------------------------------------------------------------------- */
1050 /* Note we could get rid of this one, but it's used by some addon so...
1051  * Does not hurt keeping it around for now. */
1053 {
1054  Main *bmain = CTX_data_main(C);
1055  SpaceFile *sfile = CTX_wm_space_file(C);
1056  PropertyRNA *prop;
1057 
1058  if ((prop = RNA_struct_find_property(op->ptr, "dir"))) {
1060  char entry[256];
1061 
1062  RNA_property_string_get(op->ptr, prop, entry);
1063  BLI_strncpy(params->dir, entry, sizeof(params->dir));
1066 
1068  }
1069 
1070  return OPERATOR_FINISHED;
1071 }
1072 
1074 {
1075  PropertyRNA *prop;
1076 
1077  /* identifiers */
1078  ot->name = "Select Directory";
1079  ot->description = "Select a bookmarked directory";
1080  ot->idname = "FILE_OT_select_bookmark";
1081 
1082  /* api callbacks */
1084  /* Bookmarks are for file browsing only (not asset browsing). */
1086 
1087  /* properties */
1088  prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Directory", "");
1090 }
1091 
1094 /* -------------------------------------------------------------------- */
1099 {
1100  ScrArea *area = CTX_wm_area(C);
1101  SpaceFile *sfile = CTX_wm_space_file(C);
1102  struct FSMenu *fsmenu = ED_fsmenu_get();
1104 
1105  if (params->dir[0] != '\0') {
1106  char name[FILE_MAX];
1107 
1109  fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, ICON_FILE_FOLDER, FS_INSERT_SAVE);
1110  BLI_join_dirfile(name,
1111  sizeof(name),
1114  fsmenu_write_file(fsmenu, name);
1115  }
1116 
1119  return OPERATOR_FINISHED;
1120 }
1121 
1123 {
1124  /* identifiers */
1125  ot->name = "Add Bookmark";
1126  ot->description = "Add a bookmark for the selected/active directory";
1127  ot->idname = "FILE_OT_bookmark_add";
1128 
1129  /* api callbacks */
1131  /* Bookmarks are for file browsing only (not asset browsing). */
1133 }
1134 
1137 /* -------------------------------------------------------------------- */
1142 {
1143  ScrArea *area = CTX_wm_area(C);
1144  SpaceFile *sfile = CTX_wm_space_file(C);
1145  struct FSMenu *fsmenu = ED_fsmenu_get();
1146  int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1147 
1148  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
1149 
1150  if (prop) {
1151  int index;
1152  if (RNA_property_is_set(op->ptr, prop)) {
1153  index = RNA_property_int_get(op->ptr, prop);
1154  }
1155  else { /* if index unset, use active bookmark... */
1156  index = sfile->bookmarknr;
1157  }
1158  if ((index > -1) && (index < nentries)) {
1159  char name[FILE_MAX];
1160 
1162  BLI_join_dirfile(name,
1163  sizeof(name),
1166  fsmenu_write_file(fsmenu, name);
1169  }
1170  }
1171 
1172  return OPERATOR_FINISHED;
1173 }
1174 
1176 {
1177  PropertyRNA *prop;
1178 
1179  /* identifiers */
1180  ot->name = "Delete Bookmark";
1181  ot->description = "Delete selected bookmark";
1182  ot->idname = "FILE_OT_bookmark_delete";
1183 
1184  /* api callbacks */
1186  /* Bookmarks are for file browsing only (not asset browsing). */
1188 
1189  /* properties */
1190  prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
1192 }
1193 
1196 /* -------------------------------------------------------------------- */
1201 {
1202  ScrArea *area = CTX_wm_area(C);
1203  struct FSMenu *fsmenu = ED_fsmenu_get();
1204  struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
1205  int index;
1206  bool changed = false;
1207 
1208  for (index = 0; fsme; fsme = fsme_next) {
1209  fsme_next = fsme->next;
1210 
1211  if (!BLI_is_dir(fsme->path)) {
1213  changed = true;
1214  }
1215  else {
1216  index++;
1217  }
1218  }
1219 
1220  if (changed) {
1221  char name[FILE_MAX];
1222 
1224  sizeof(name),
1227  fsmenu_write_file(fsmenu, name);
1231  }
1232 
1233  return OPERATOR_FINISHED;
1234 }
1235 
1237 {
1238  /* identifiers */
1239  ot->name = "Cleanup Bookmarks";
1240  ot->description = "Delete all invalid bookmarks";
1241  ot->idname = "FILE_OT_bookmark_cleanup";
1242 
1243  /* api callbacks */
1245  /* Bookmarks are for file browsing only (not asset browsing). */
1247 
1248  /* properties */
1249 }
1250 
1253 /* -------------------------------------------------------------------- */
1257 enum {
1262 };
1263 
1265 {
1266  ScrArea *area = CTX_wm_area(C);
1267  SpaceFile *sfile = CTX_wm_space_file(C);
1268  struct FSMenu *fsmenu = ED_fsmenu_get();
1269  struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
1270  const struct FSMenuEntry *fsmentry_org = fsmentry;
1271 
1272  char fname[FILE_MAX];
1273 
1274  const int direction = RNA_enum_get(op->ptr, "direction");
1275  const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1276  const int act_index = sfile->bookmarknr;
1277  int new_index;
1278 
1279  if (totitems < 2) {
1280  return OPERATOR_CANCELLED;
1281  }
1282 
1283  switch (direction) {
1285  new_index = 0;
1286  break;
1288  new_index = totitems - 1;
1289  break;
1290  case FILE_BOOKMARK_MOVE_UP:
1292  default:
1293  new_index = (totitems + act_index + direction) % totitems;
1294  break;
1295  }
1296 
1297  if (new_index == act_index) {
1298  return OPERATOR_CANCELLED;
1299  }
1300 
1301  BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
1302  if (fsmentry != fsmentry_org) {
1303  ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry);
1304  }
1305 
1306  /* Need to update active bookmark number. */
1307  sfile->bookmarknr = new_index;
1308 
1309  BLI_join_dirfile(fname,
1310  sizeof(fname),
1313  fsmenu_write_file(fsmenu, fname);
1314 
1316  return OPERATOR_FINISHED;
1317 }
1318 
1320 {
1321  SpaceFile *sfile = CTX_wm_space_file(C);
1322 
1323  /* Bookmarks are for file browsing only (not asset browsing). */
1325  return false;
1326  }
1327 
1328  return sfile->bookmarknr != -1;
1329 }
1330 
1332 {
1333  static const EnumPropertyItem slot_move[] = {
1334  {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
1335  {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
1336  {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
1337  {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
1338  {0, NULL, 0, NULL, NULL}};
1339 
1340  /* identifiers */
1341  ot->name = "Move Bookmark";
1342  ot->idname = "FILE_OT_bookmark_move";
1343  ot->description = "Move the active bookmark up/down in the list";
1344 
1345  /* api callbacks */
1348 
1349  /* flags */
1350  ot->flag = OPTYPE_REGISTER; /* No undo! */
1351 
1352  RNA_def_enum(ot->srna,
1353  "direction",
1354  slot_move,
1355  0,
1356  "Direction",
1357  "Direction to move the active bookmark towards");
1358 }
1359 
1362 /* -------------------------------------------------------------------- */
1367 {
1368  ScrArea *area = CTX_wm_area(C);
1369  char name[FILE_MAX];
1370  struct FSMenu *fsmenu = ED_fsmenu_get();
1371 
1372  while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
1374  }
1375  BLI_join_dirfile(name,
1376  sizeof(name),
1379  fsmenu_write_file(fsmenu, name);
1381 
1382  return OPERATOR_FINISHED;
1383 }
1384 
1386 {
1387  /* identifiers */
1388  ot->name = "Reset Recent";
1389  ot->description = "Reset recent files";
1390  ot->idname = "FILE_OT_reset_recent";
1391 
1392  /* api callbacks */
1394  /* File browsing only operator (not asset browsing). */
1396 }
1397 
1400 /* -------------------------------------------------------------------- */
1404 int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
1405 {
1406  View2D *v2d = &region->v2d;
1408  int numfiles, origfile;
1409 
1410  /* In case blender starts where the mouse is over a File browser,
1411  * this operator can be invoked when the `sfile` or `sfile->layout` isn't initialized yet. */
1412  if (sfile == NULL || sfile->files == NULL || sfile->layout == NULL) {
1413  return 0;
1414  }
1415 
1417  /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
1418  * what creates the params for the current browse mode. See T93508. */
1419  if (!params) {
1420  return false;
1421  }
1422  numfiles = filelist_files_ensure(sfile->files);
1423 
1424  origfile = params->highlight_file;
1425 
1426  mx -= region->winrct.xmin;
1427  my -= region->winrct.ymin;
1428 
1429  if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
1430  float fx, fy;
1431  int highlight_file;
1432 
1433  UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
1434 
1435  highlight_file = ED_fileselect_layout_offset(
1436  sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
1437 
1438  if ((highlight_file >= 0) && (highlight_file < numfiles)) {
1439  params->highlight_file = highlight_file;
1440  }
1441  else {
1442  params->highlight_file = -1;
1443  }
1444  }
1445  else {
1446  params->highlight_file = -1;
1447  }
1448 
1449  return (params->highlight_file != origfile);
1450 }
1451 
1452 static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1453 {
1454  ARegion *region = CTX_wm_region(C);
1455  SpaceFile *sfile = CTX_wm_space_file(C);
1456 
1457  if (!file_highlight_set(sfile, region, event->xy[0], event->xy[1])) {
1458  return OPERATOR_PASS_THROUGH;
1459  }
1460 
1462 
1463  return OPERATOR_PASS_THROUGH;
1464 }
1465 
1467 {
1468  /* identifiers */
1469  ot->name = "Highlight File";
1470  ot->description = "Highlight selected file(s)";
1471  ot->idname = "FILE_OT_highlight";
1472 
1473  /* api callbacks */
1475  /* Operator works for file or asset browsing */
1477 }
1478 
1481 /* -------------------------------------------------------------------- */
1486  wmOperator *UNUSED(op),
1487  const wmEvent *event)
1488 {
1489  const ARegion *region = CTX_wm_region(C);
1490  SpaceFile *sfile = CTX_wm_space_file(C);
1491 
1493  &region->v2d, sfile->layout, event->mval[0], event->mval[1])) {
1496  &region->v2d, params, sfile->layout, event->mval[0]);
1497 
1498  if (column_type != COLUMN_NONE) {
1499  const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
1500 
1502  if (params->sort == column->sort_type) {
1503  /* Already sorting by selected column -> toggle sort invert (three state logic). */
1504  params->flag ^= FILE_SORT_INVERT;
1505  }
1506  else {
1507  params->sort = column->sort_type;
1508  params->flag &= ~FILE_SORT_INVERT;
1509  }
1510 
1512  }
1513  }
1514 
1515  return OPERATOR_PASS_THROUGH;
1516 }
1517 
1519 {
1520  /* identifiers */
1521  ot->name = "Sort from Column";
1522  ot->description = "Change sorting to use column under cursor";
1523  ot->idname = "FILE_OT_sort_column_ui_context";
1524 
1525  /* api callbacks */
1527  /* Operator works for file or asset browsing */
1529 
1530  ot->flag = OPTYPE_INTERNAL;
1531 }
1532 
1535 /* -------------------------------------------------------------------- */
1540 {
1541  bool poll = ED_operator_file_browsing_active(C);
1542  SpaceFile *sfile = CTX_wm_space_file(C);
1543 
1544  if (!sfile || !sfile->op) {
1545  poll = 0;
1546  }
1547 
1548  return poll;
1549 }
1550 
1552 {
1554  SpaceFile *sfile = CTX_wm_space_file(C);
1555  wmOperator *op = sfile->op;
1556 
1557  sfile->op = NULL;
1558 
1560 
1561  return OPERATOR_FINISHED;
1562 }
1563 
1565 {
1566  /* identifiers */
1567  ot->name = "Cancel File Load";
1568  ot->description = "Cancel loading of selected file";
1569  ot->idname = "FILE_OT_cancel";
1570 
1571  /* api callbacks */
1574 }
1575 
1578 /* -------------------------------------------------------------------- */
1582 void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
1583 {
1585  PropertyRNA *prop;
1586 
1587  /* XXX, not real length */
1588  BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file);
1589 
1590  if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
1591  if (RNA_property_boolean_get(op->ptr, prop)) {
1592  BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
1593  }
1594  }
1595 
1596  if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1597  RNA_property_string_set(op->ptr, prop, params->file);
1598  }
1599  if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1600  RNA_property_string_set(op->ptr, prop, params->dir);
1601  }
1602  if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1603  RNA_property_string_set(op->ptr, prop, filepath);
1604  }
1605 
1606  /* some ops have multiple files to select */
1607  /* this is called on operators check() so clear collections first since
1608  * they may be already set. */
1609  {
1610  int i, numfiles = filelist_files_ensure(sfile->files);
1611 
1612  if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
1613  PointerRNA itemptr;
1614  int num_files = 0;
1616  for (i = 0; i < numfiles; i++) {
1618  FileDirEntry *file = filelist_file(sfile->files, i);
1619  /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
1620  if (!file->redirection_path) {
1621  RNA_property_collection_add(op->ptr, prop, &itemptr);
1622  RNA_string_set(&itemptr, "name", file->relpath);
1623  num_files++;
1624  }
1625  }
1626  }
1627  /* make sure the file specified in the filename button is added even if no
1628  * files selected */
1629  if (0 == num_files) {
1630  RNA_property_collection_add(op->ptr, prop, &itemptr);
1631  RNA_string_set(&itemptr, "name", params->file);
1632  }
1633  }
1634 
1635  if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
1636  PointerRNA itemptr;
1637  int num_dirs = 0;
1639  for (i = 0; i < numfiles; i++) {
1641  FileDirEntry *file = filelist_file(sfile->files, i);
1642  RNA_property_collection_add(op->ptr, prop, &itemptr);
1643  RNA_string_set(&itemptr, "name", file->relpath);
1644  num_dirs++;
1645  }
1646  }
1647 
1648  /* make sure the directory specified in the button is added even if no
1649  * directory selected */
1650  if (0 == num_dirs) {
1651  RNA_property_collection_add(op->ptr, prop, &itemptr);
1652  RNA_string_set(&itemptr, "name", params->dir);
1653  }
1654  }
1655  }
1656 }
1658 {
1659  char filepath_dummy[FILE_MAX];
1660 
1661  file_sfile_to_operator_ex(bmain, op, sfile, filepath_dummy);
1662 }
1663 
1665 {
1667  PropertyRNA *prop;
1668 
1669  /* If neither of the above are set, split the filepath back */
1670  if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1671  char filepath[FILE_MAX];
1672  RNA_property_string_get(op->ptr, prop, filepath);
1674  filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file));
1675  }
1676  else {
1677  if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1678  RNA_property_string_get(op->ptr, prop, params->file);
1679  }
1680  if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1681  RNA_property_string_get(op->ptr, prop, params->dir);
1682  }
1683  }
1684 
1685  /* we could check for relative_path property which is used when converting
1686  * in the other direction but doesn't hurt to do this every time */
1688 
1689  /* XXX, files and dirs updates missing, not really so important though */
1690 }
1691 
1692 void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
1693 {
1695  BLI_assert(BLI_exists(filepath));
1696 
1697  if (BLI_is_dir(filepath)) {
1698  BLI_strncpy(params->dir, filepath, sizeof(params->dir));
1699  }
1700  else {
1701  if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
1703  filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file));
1704  }
1705  else {
1706  BLI_split_dir_part(filepath, params->dir, sizeof(params->dir));
1707  }
1708  }
1709 }
1710 
1712 {
1713  /* May happen when manipulating non-active spaces. */
1714  if (UNLIKELY(area->spacetype != SPACE_FILE)) {
1715  return;
1716  }
1717  SpaceFile *sfile = area->spacedata.first;
1718  wmOperator *op = sfile->op;
1719  if (op) { /* fail on reload */
1720  if (op->type->check) {
1721  Main *bmain = CTX_data_main(C);
1722  file_sfile_to_operator(bmain, op, sfile);
1723 
1724  /* redraw */
1725  if (op->type->check(C, op)) {
1726  file_operator_to_sfile(bmain, sfile, op);
1727 
1728  /* redraw, else the changed settings won't get updated */
1730  }
1731  }
1732  }
1733 }
1734 
1736 {
1737  ScrArea *area = CTX_wm_area(C);
1739 }
1740 
1741 void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1742 {
1743  file_draw_check(C);
1744 }
1745 
1747 {
1748  if (sfile->op) { /* fails on reload */
1750  if (params && (params->flag & FILE_CHECK_EXISTING)) {
1751  char filepath[FILE_MAX];
1752  BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file);
1753  if (BLI_is_file(filepath)) {
1754  return true;
1755  }
1756  }
1757  }
1758 
1759  return false;
1760 }
1761 
1764 /* -------------------------------------------------------------------- */
1771 static bool file_execute(bContext *C, SpaceFile *sfile)
1772 {
1773  Main *bmain = CTX_data_main(C);
1775  FileDirEntry *file = filelist_file(sfile->files, params->active_file);
1776 
1777  if (file && file->redirection_path) {
1778  /* redirection_path is an absolute path that takes precedence
1779  * over using params->dir + params->file. */
1780  BLI_split_dirfile(file->redirection_path,
1781  params->dir,
1782  params->file,
1783  sizeof(params->dir),
1784  sizeof(params->file));
1785  /* Update relpath with redirected filename as well so that the alternative
1786  * combination of params->dir + relpath remains valid as well. */
1787  MEM_freeN(file->relpath);
1788  file->relpath = BLI_strdup(params->file);
1789  }
1790 
1791  /* directory change */
1792  if (file && (file->typeflag & FILE_TYPE_DIR)) {
1793  if (!file->relpath) {
1794  return false;
1795  }
1796 
1797  if (FILENAME_IS_PARENT(file->relpath)) {
1799  }
1800  else {
1802  BLI_path_append(params->dir, sizeof(params->dir) - 1, file->relpath);
1804  }
1806  }
1807  /* Opening file, sends events now, so things get handled on window-queue level. */
1808  else if (sfile->op) {
1809  wmOperator *op = sfile->op;
1810  char filepath[FILE_MAX];
1811 
1812  sfile->op = NULL;
1813 
1814  file_sfile_to_operator_ex(bmain, op, sfile, filepath);
1815 
1816  if (BLI_exists(params->dir)) {
1819  params->dir,
1820  NULL,
1821  ICON_FILE_FOLDER,
1823  }
1824 
1825  BLI_join_dirfile(filepath,
1826  sizeof(filepath),
1829  fsmenu_write_file(ED_fsmenu_get(), filepath);
1831  }
1832 
1833  return true;
1834 }
1835 
1837 {
1838  SpaceFile *sfile = CTX_wm_space_file(C);
1839 
1840  if (!file_execute(C, sfile)) {
1841  return OPERATOR_CANCELLED;
1842  }
1843 
1844  return OPERATOR_FINISHED;
1845 }
1846 
1848 {
1849  /* identifiers */
1850  ot->name = "Execute File Window";
1851  ot->description = "Execute selected file";
1852  ot->idname = "FILE_OT_execute";
1853 
1854  /* api callbacks */
1855  ot->exec = file_exec;
1856  /* Important since handler is on window level.
1857  *
1858  * Avoid using #file_operator_poll since this is also used for entering directories
1859  * which is used even when the file manager doesn't have an operator. */
1861 }
1862 
1867 {
1868  rcti rect = file_select_mval_to_select_rect(event->mval);
1869  if (file_select(C, &rect, FILE_SEL_ADD, false, false) == FILE_SELECT_NOTHING) {
1870  return false;
1871  }
1872 
1873  return true;
1874 }
1875 
1877 {
1878  ARegion *region = CTX_wm_region(C);
1879  SpaceFile *sfile = CTX_wm_space_file(C);
1880 
1882  sfile->layout, &region->v2d, event->mval[0], event->mval[1])) {
1884  }
1885 
1886  /* Note that this isn't needed practically, because the keymap already activates the hovered item
1887  * on mouse-press. This execute operator is called afterwards on the double-click event then.
1888  * However relying on this would be fragile and could break with keymap changes, so better to
1889  * have this mouse-execute operator that makes sure once more that the hovered file is active. */
1890  if (!file_ensure_hovered_is_active(C, event)) {
1891  return OPERATOR_CANCELLED;
1892  }
1893 
1894  if (!file_execute(C, sfile)) {
1895  return OPERATOR_CANCELLED;
1896  }
1897 
1898  return OPERATOR_FINISHED;
1899 }
1900 
1902 {
1903  /* identifiers */
1904  ot->name = "Execute File";
1905  ot->description =
1906  "Perform the current execute action for the file under the cursor (e.g. open the file)";
1907  ot->idname = "FILE_OT_mouse_execute";
1908 
1909  /* api callbacks */
1912 
1913  ot->flag = OPTYPE_INTERNAL;
1914 }
1915 
1918 /* -------------------------------------------------------------------- */
1923 {
1925  SpaceFile *sfile = CTX_wm_space_file(C);
1926  struct FSMenu *fsmenu = ED_fsmenu_get();
1927 
1928  ED_fileselect_clear(wm, sfile);
1929 
1930  /* refresh system directory menu */
1932 
1933  /* Update bookmarks 'valid' state. */
1934  fsmenu_refresh_bookmarks_status(wm, fsmenu);
1935 
1937 
1938  return OPERATOR_FINISHED;
1939 }
1940 
1942 {
1943  /* identifiers */
1944  ot->name = "Refresh File List";
1945  ot->description = "Refresh the file list";
1946  ot->idname = "FILE_OT_refresh";
1947 
1948  /* api callbacks */
1950  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
1951 }
1952 
1955 /* -------------------------------------------------------------------- */
1960 {
1961  Main *bmain = CTX_data_main(C);
1962  SpaceFile *sfile = CTX_wm_space_file(C);
1964 
1965  if (params) {
1966  if (BLI_path_parent_dir(params->dir)) {
1969  if (params->recursion_level > 1) {
1970  /* Disable 'dirtree' recursion when going up in tree. */
1971  params->recursion_level = 0;
1972  filelist_setrecursion(sfile->files, params->recursion_level);
1973  }
1975  }
1976  }
1977 
1978  return OPERATOR_FINISHED;
1979 }
1980 
1982 {
1983  /* identifiers */
1984  ot->name = "Parent File";
1985  ot->description = "Move to parent directory";
1986  ot->idname = "FILE_OT_parent";
1987 
1988  /* api callbacks */
1990  /* File browsing only operator (not asset browsing). */
1991  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
1992 }
1993 
1996 /* -------------------------------------------------------------------- */
2001 {
2002  SpaceFile *sfile = CTX_wm_space_file(C);
2004 
2005  if (params) {
2006  folderlist_pushdir(sfile->folders_next, params->dir);
2007  folderlist_popdir(sfile->folders_prev, params->dir);
2008  folderlist_pushdir(sfile->folders_next, params->dir);
2009 
2011  }
2013 
2014  return OPERATOR_FINISHED;
2015 }
2016 
2018 {
2019  /* identifiers */
2020  ot->name = "Previous Folder";
2021  ot->description = "Move to previous folder";
2022  ot->idname = "FILE_OT_previous";
2023 
2024  /* api callbacks */
2026  /* File browsing only operator (not asset browsing). */
2027  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2028 }
2029 
2032 /* -------------------------------------------------------------------- */
2037 {
2038  SpaceFile *sfile = CTX_wm_space_file(C);
2040  if (params) {
2041  folderlist_pushdir(sfile->folders_prev, params->dir);
2042  folderlist_popdir(sfile->folders_next, params->dir);
2043 
2044  /* update folders_prev so we can check for it in #folderlist_clear_next() */
2045  folderlist_pushdir(sfile->folders_prev, params->dir);
2046 
2048  }
2050 
2051  return OPERATOR_FINISHED;
2052 }
2053 
2055 {
2056  /* identifiers */
2057  ot->name = "Next Folder";
2058  ot->description = "Move to next folder";
2059  ot->idname = "FILE_OT_next";
2060 
2061  /* api callbacks */
2062  ot->exec = file_next_exec;
2063  /* File browsing only operator (not asset browsing). */
2064  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2065 }
2066 
2069 /* -------------------------------------------------------------------- */
2073 /* only meant for timer usage */
2075 {
2076  ScrArea *area = CTX_wm_area(C);
2077  SpaceFile *sfile = CTX_wm_space_file(C);
2078  ARegion *region, *region_ctx = CTX_wm_region(C);
2079  const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
2080  int i;
2081 
2082  /* escape if not our timer */
2083  if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata) {
2084  return OPERATOR_PASS_THROUGH;
2085  }
2086 
2087  const int numfiles = filelist_files_ensure(sfile->files);
2088 
2089  /* Due to async nature of file listing, we may execute this code before `file_refresh()`
2090  * editing entry is available in our listing,
2091  * so we also have to handle switching to rename mode here. */
2093  if ((params->rename_flag &
2096  }
2097 
2098  /* check if we are editing a name */
2099  int edit_idx = -1;
2100  for (i = 0; i < numfiles; i++) {
2103  edit_idx = i;
2104  break;
2105  }
2106  }
2107 
2109  wmWindow *win = CTX_wm_window(C);
2110 
2111  /* if we are not editing, we are done */
2112  if (edit_idx == -1) {
2113  /* Do not invalidate timer if filerename is still pending,
2114  * we might still be building the filelist and yet have to find edited entry. */
2115  if (params->rename_flag == 0) {
2116  file_params_smoothscroll_timer_clear(wm, win, sfile);
2117  }
2118  return OPERATOR_PASS_THROUGH;
2119  }
2120 
2121  /* we need the correct area for scrolling */
2123  if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2124  file_params_smoothscroll_timer_clear(wm, win, sfile);
2125  return OPERATOR_PASS_THROUGH;
2126  }
2127 
2128  /* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
2129  * in vertical layout).
2130  */
2131  const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
2132 
2133  /* Scroll offset is the first file in the row/column we are editing in. */
2134  if (sfile->scroll_offset == 0) {
2135  sfile->scroll_offset = (edit_idx / items_block_size) * items_block_size;
2136  }
2137 
2138  const int numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, region);
2139  const int first_visible_item = ED_fileselect_layout_offset(
2140  sfile->layout, (int)region->v2d.cur.xmin, (int)-region->v2d.cur.ymax);
2141  const int last_visible_item = first_visible_item + numfiles_layout + 1;
2142 
2143  /* NOTE: the special case for vertical layout is because filename is at the bottom of items then,
2144  * so we artificially move current row back one step, to ensure we show bottom of
2145  * active item rather than its top (important in case visible height is low). */
2146  const int middle_offset = max_ii(
2147  0, (first_visible_item + last_visible_item) / 2 - (is_horizontal ? 0 : items_block_size));
2148 
2149  const int min_middle_offset = numfiles_layout / 2;
2150  const int max_middle_offset = ((numfiles / items_block_size) * items_block_size +
2151  ((numfiles % items_block_size) != 0 ? items_block_size : 0)) -
2152  (numfiles_layout / 2);
2153  /* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the
2154  * beginning/end of the view. */
2155  /* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf...
2156  * that is why we still need to keep the min/max_middle_offset checks too. :( */
2157  const float min_tot_scroll = is_horizontal ? region->v2d.tot.xmin : -region->v2d.tot.ymax;
2158  const float max_tot_scroll = is_horizontal ? region->v2d.tot.xmax : -region->v2d.tot.ymin;
2159  const float min_curr_scroll = is_horizontal ? region->v2d.cur.xmin : -region->v2d.cur.ymax;
2160  const float max_curr_scroll = is_horizontal ? region->v2d.cur.xmax : -region->v2d.cur.ymin;
2161 
2162  /* Check if we have reached our final scroll position. */
2163  /* Filelist has to be ready, otherwise it makes no sense to stop scrolling yet. */
2164  const bool is_ready = filelist_is_ready(sfile->files);
2165  /* Edited item must be in the 'middle' of shown area (kind of approximated).
2166  * Note that we have to do the check in 'block space', not in 'item space' here. */
2167  const bool is_centered = (abs(middle_offset / items_block_size -
2168  sfile->scroll_offset / items_block_size) == 0);
2169  /* OR edited item must be towards the beginning, and we are scrolled fully to the start. */
2170  const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) &&
2171  (min_curr_scroll - min_tot_scroll < 1.0f) &&
2172  (middle_offset - min_middle_offset < items_block_size));
2173  /* OR edited item must be towards the end, and we are scrolled fully to the end.
2174  * This one is crucial (unlike the one for the beginning), because without it we won't scroll
2175  * fully to the end, and last column or row will end up only partially drawn. */
2176  const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) &&
2177  (max_tot_scroll - max_curr_scroll < 1.0f) &&
2178  (max_middle_offset - middle_offset < items_block_size));
2179 
2180  if (is_ready && (is_centered || is_full_start || is_full_end)) {
2181  file_params_smoothscroll_timer_clear(wm, win, sfile);
2182  /* Post-scroll (after rename has been validated by user) is done,
2183  * rename process is totally finished, cleanup. */
2184  if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) {
2186  }
2187  return OPERATOR_FINISHED;
2188  }
2189 
2190  /* Temporarily set context to the main window region,
2191  * so that the pan operator works. */
2192  CTX_wm_region_set(C, region);
2193 
2194  /* scroll one step in the desired direction */
2195  PointerRNA op_ptr;
2196  int deltax = 0;
2197  int deltay = 0;
2198 
2199  /* We adjust speed of scrolling to avoid tens of seconds of it in e.g. directories with tens of
2200  * thousands of folders... See T65782. */
2201  /* This will slow down scrolling when approaching final goal, also avoids going too far and
2202  * having to bounce back... */
2203 
2204  /* Number of blocks (columns in horizontal layout, rows otherwise) between current middle of
2205  * screen, and final goal position. */
2206  const int diff_offset = sfile->scroll_offset / items_block_size -
2207  middle_offset / items_block_size;
2208  /* convert diff_offset into pixels. */
2209  const int diff_offset_delta = abs(diff_offset) *
2210  (is_horizontal ?
2211  sfile->layout->tile_w + 2 * sfile->layout->tile_border_x :
2212  sfile->layout->tile_h + 2 * sfile->layout->tile_border_y);
2213  const int scroll_delta = max_ii(2, diff_offset_delta / 15);
2214 
2215  if (diff_offset < 0) {
2216  if (is_horizontal) {
2217  deltax = -scroll_delta;
2218  }
2219  else {
2220  deltay = scroll_delta;
2221  }
2222  }
2223  else {
2224  if (is_horizontal) {
2225  deltax = scroll_delta;
2226  }
2227  else {
2228  deltay = -scroll_delta;
2229  }
2230  }
2231  WM_operator_properties_create(&op_ptr, "VIEW2D_OT_pan");
2232  RNA_int_set(&op_ptr, "deltax", deltax);
2233  RNA_int_set(&op_ptr, "deltay", deltay);
2234 
2235  WM_operator_name_call(C, "VIEW2D_OT_pan", WM_OP_EXEC_DEFAULT, &op_ptr, event);
2236  WM_operator_properties_free(&op_ptr);
2237 
2238  ED_region_tag_redraw(region);
2239 
2240  /* and restore context */
2241  CTX_wm_region_set(C, region_ctx);
2242 
2243  return OPERATOR_FINISHED;
2244 }
2245 
2247 {
2248  /* identifiers */
2249  ot->name = "Smooth Scroll";
2250  ot->idname = "FILE_OT_smoothscroll";
2251  ot->description = "Smooth scroll to make editable file visible";
2252 
2253  /* api callbacks */
2255  /* Operator works for file or asset browsing */
2257 }
2258 
2261 /* -------------------------------------------------------------------- */
2266 {
2267  Main *bmain = CTX_data_main(C);
2268  SpaceFile *sfile = CTX_wm_space_file(C);
2269 
2270  if (sfile) {
2271  char filepath[FILE_MAX];
2272 
2273  RNA_string_get(op->ptr, "filepath", filepath);
2274  if (!BLI_exists(filepath)) {
2275  BKE_report(op->reports, RPT_ERROR, "File does not exist");
2276  return OPERATOR_CANCELLED;
2277  }
2278 
2279  file_sfile_filepath_set(sfile, filepath);
2280 
2281  if (sfile->op) {
2282  file_sfile_to_operator(bmain, sfile->op, sfile);
2283  file_draw_check(C);
2284  }
2285 
2287  return OPERATOR_FINISHED;
2288  }
2289 
2290  return OPERATOR_CANCELLED;
2291 }
2292 
2294 {
2295  ot->name = "File Selector Drop";
2296  ot->idname = "FILE_OT_filepath_drop";
2297 
2299  /* File browsing only operator (not asset browsing). */
2301 
2302  RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", "");
2303 }
2304 
2307 /* -------------------------------------------------------------------- */
2317 static bool new_folder_path(const char *parent, char folder[FILE_MAX], char name[FILE_MAXFILE])
2318 {
2319  int i = 1;
2320  int len = 0;
2321 
2322  BLI_strncpy(name, "New Folder", FILE_MAXFILE);
2323  BLI_join_dirfile(folder, FILE_MAX, parent, name);
2324  /* check whether folder with the name already exists, in this case
2325  * add number to the name. Check length of generated name to avoid
2326  * crazy case of huge number of folders each named 'New Folder (x)' */
2327  while (BLI_exists(folder) && (len < FILE_MAXFILE)) {
2328  len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
2329  BLI_join_dirfile(folder, FILE_MAX, parent, name);
2330  i++;
2331  }
2332 
2333  return (len < FILE_MAXFILE);
2334 }
2335 
2337 {
2338  char name[FILE_MAXFILE];
2339  char path[FILE_MAX];
2340  bool generate_name = true;
2341  PropertyRNA *prop;
2342 
2344  SpaceFile *sfile = CTX_wm_space_file(C);
2346  const bool do_diropen = RNA_boolean_get(op->ptr, "open");
2347 
2348  if (!params) {
2349  BKE_report(op->reports, RPT_WARNING, "No parent directory given");
2350  return OPERATOR_CANCELLED;
2351  }
2352 
2353  path[0] = '\0';
2354 
2355  if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
2356  RNA_property_string_get(op->ptr, prop, path);
2357  if (path[0] != '\0') {
2358  generate_name = false;
2359  }
2360  }
2361 
2362  if (generate_name) {
2363  /* create a new, non-existing folder name */
2364  if (!new_folder_path(params->dir, path, name)) {
2365  BKE_report(op->reports, RPT_ERROR, "Could not create new folder name");
2366  return OPERATOR_CANCELLED;
2367  }
2368  }
2369  else { /* We assume we are able to generate a valid name! */
2370  char org_path[FILE_MAX];
2371 
2372  BLI_strncpy(org_path, path, sizeof(org_path));
2373  if (BLI_path_make_safe(path)) {
2374  BKE_reportf(op->reports,
2375  RPT_WARNING,
2376  "'%s' given path is OS-invalid, creating '%s' path instead",
2377  org_path,
2378  path);
2379  }
2380  }
2381 
2382  /* create the file */
2383  errno = 0;
2384  if (!BLI_dir_create_recursive(path) ||
2385  /* Should no more be needed,
2386  * now that BLI_dir_create_recursive returns a success state - but kept just in case. */
2387  !BLI_exists(path)) {
2388  BKE_reportf(op->reports,
2389  RPT_ERROR,
2390  "Could not create new folder: %s",
2391  errno ? strerror(errno) : "unknown error");
2392  return OPERATOR_CANCELLED;
2393  }
2394 
2395  eFileSel_Params_RenameFlag rename_flag = params->rename_flag;
2396 
2397  /* If we don't enter the directory directly, remember file to jump into editing. */
2398  if (do_diropen == false) {
2399  BLI_assert_msg(params->rename_id == NULL,
2400  "File rename handling should immediately clear rename_id when done, "
2401  "because otherwise it will keep taking precedence over renamefile.");
2402  BLI_strncpy(params->renamefile, name, FILE_MAXFILE);
2403  rename_flag = FILE_PARAMS_RENAME_PENDING;
2404  }
2405 
2407  params->rename_flag = rename_flag;
2408 
2409  /* reload dir to make sure we're seeing what's in the directory */
2410  ED_fileselect_clear(wm, sfile);
2411 
2412  if (do_diropen) {
2413  BLI_strncpy(params->dir, path, sizeof(params->dir));
2415  }
2416 
2418 
2419  return OPERATOR_FINISHED;
2420 }
2421 
2423 {
2424  PropertyRNA *prop;
2425 
2426  /* identifiers */
2427  ot->name = "Create New Directory";
2428  ot->description = "Create a new directory";
2429  ot->idname = "FILE_OT_directory_new";
2430 
2431  /* api callbacks */
2434  /* File browsing only operator (not asset browsing). */
2435  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2436 
2437  prop = RNA_def_string_dir_path(
2438  ot->srna, "directory", NULL, FILE_MAX, "Directory", "Name of new directory");
2440  prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
2443 }
2444 
2447 /* -------------------------------------------------------------------- */
2451 /* TODO: This should go to BLI_path_utils. */
2453 {
2454  Main *bmain = CTX_data_main(C);
2455  SpaceFile *sfile = CTX_wm_space_file(C);
2457 
2458  if (params) {
2459  if (BLI_path_is_rel(params->dir)) {
2460  /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
2461  const char *blendfile_path = BKE_main_blendfile_path(bmain);
2462  BLI_path_abs(params->dir,
2463  (blendfile_path[0] != '\0') ? blendfile_path :
2465  }
2466  else if (params->dir[0] == '~') {
2467  char tmpstr[sizeof(params->dir) - 1];
2468  BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr));
2469  BLI_path_join(
2470  params->dir, sizeof(params->dir), BKE_appdir_folder_default_or_root(), tmpstr, NULL);
2471  }
2472 
2473  else if (params->dir[0] == '\0')
2474 #ifndef WIN32
2475  {
2476  params->dir[0] = '/';
2477  params->dir[1] = '\0';
2478  }
2479 #else
2480  {
2482  }
2483  /* change "C:" --> "C:\", T28102. */
2484  else if ((isalpha(params->dir[0]) && (params->dir[1] == ':')) && (params->dir[2] == '\0')) {
2485  params->dir[2] = '\\';
2486  params->dir[3] = '\0';
2487  }
2488  else if (BLI_path_is_unc(params->dir)) {
2489  BLI_path_normalize_unc(params->dir, FILE_MAX_LIBEXTRA);
2490  }
2491 #endif
2492  }
2493 }
2494 
2495 /* TODO: check we still need this, it's annoying to have OS-specific code here... :/. */
2496 #if defined(WIN32)
2497 static bool can_create_dir(const char *dir)
2498 {
2499  /* for UNC paths we need to check whether the parent of the new
2500  * directory is a proper directory itself and not a share or the
2501  * UNC root (server name) itself. Calling BLI_is_dir does this
2502  */
2503  if (BLI_path_is_unc(dir)) {
2504  char parent[PATH_MAX];
2505  BLI_strncpy(parent, dir, PATH_MAX);
2506  BLI_path_parent_dir(parent);
2507  return BLI_is_dir(parent);
2508  }
2509  return true;
2510 }
2511 #endif
2512 
2513 void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but))
2514 {
2515  Main *bmain = CTX_data_main(C);
2516  SpaceFile *sfile = CTX_wm_space_file(C);
2518 
2519  if (params) {
2520  char old_dir[sizeof(params->dir)];
2521 
2522  BLI_strncpy(old_dir, params->dir, sizeof(old_dir));
2523 
2525 
2526  /* special case, user may have pasted a filepath into the directory */
2527  if (!filelist_is_dir(sfile->files, params->dir)) {
2528  char tdir[FILE_MAX_LIBEXTRA];
2529  char *group, *name;
2530 
2531  if (BLI_is_file(params->dir)) {
2532  char path[sizeof(params->dir)];
2533  BLI_strncpy(path, params->dir, sizeof(path));
2535  path, params->dir, params->file, sizeof(params->dir), sizeof(params->file));
2536  }
2537  else if (BLO_library_path_explode(params->dir, tdir, &group, &name)) {
2538  if (group) {
2539  BLI_path_append(tdir, sizeof(tdir), group);
2540  }
2541  BLI_strncpy(params->dir, tdir, sizeof(params->dir));
2542  if (name) {
2543  BLI_strncpy(params->file, name, sizeof(params->file));
2544  }
2545  else {
2546  params->file[0] = '\0';
2547  }
2548  }
2549  }
2550 
2552 
2553  if (filelist_is_dir(sfile->files, params->dir)) {
2554  if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
2555  /* if directory exists, enter it immediately */
2557  }
2558 
2559  /* don't do for now because it selects entire text instead of
2560  * placing cursor at the end */
2561  // UI_textbutton_activate_but(C, but);
2562  }
2563 #if defined(WIN32)
2564  else if (!can_create_dir(params->dir)) {
2565  const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2566  if (lastdir) {
2567  BLI_strncpy(params->dir, lastdir, sizeof(params->dir));
2568  }
2569  }
2570 #endif
2571  else {
2572  const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2573  char tdir[FILE_MAX_LIBEXTRA];
2574 
2575  /* If we are 'inside' a blend library, we cannot do anything... */
2576  if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
2577  BLI_strncpy(params->dir, lastdir, sizeof(params->dir));
2578  }
2579  else {
2580  /* if not, ask to create it and enter if confirmed */
2581  wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
2582  PointerRNA ptr;
2584  RNA_string_set(&ptr, "directory", params->dir);
2585  RNA_boolean_set(&ptr, "open", true);
2586  /* Enable confirmation prompt, else it's too easy
2587  * to accidentally create new directories. */
2588  RNA_boolean_set(&ptr, "confirm", true);
2589 
2590  if (lastdir) {
2591  BLI_strncpy(params->dir, lastdir, sizeof(params->dir));
2592  }
2593 
2596  }
2597  }
2598 
2600  }
2601 }
2602 
2603 void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but)
2604 {
2605  Main *bmain = CTX_data_main(C);
2606  SpaceFile *sfile = CTX_wm_space_file(C);
2608  uiBut *but = arg_but;
2609  char matched_file[FILE_MAX];
2610 
2611  if (params) {
2612  char filepath[sizeof(params->dir)];
2613  int matches;
2614  matched_file[0] = '\0';
2615  filepath[0] = '\0';
2616 
2618 
2619  matches = file_select_match(sfile, params->file, matched_file);
2620 
2621  /* *After* file_select_match! */
2622  const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
2623  BLI_filename_make_safe_ex(params->file, allow_tokens);
2624 
2625  if (matches) {
2626  /* replace the pattern (or filename that the user typed in,
2627  * with the first selected file of the match */
2628  BLI_strncpy(params->file, matched_file, sizeof(params->file));
2629 
2631  }
2632 
2633  if (matches == 1) {
2634  BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file);
2635 
2636  /* if directory, open it and empty filename field */
2637  if (filelist_is_dir(sfile->files, filepath)) {
2639  BLI_strncpy(params->dir, filepath, sizeof(params->dir));
2640  params->file[0] = '\0';
2644  }
2645  }
2646  else if (matches > 1) {
2647  file_draw_check(C);
2648  }
2649  }
2650 }
2651 
2654 /* -------------------------------------------------------------------- */
2659 {
2661  SpaceFile *sfile = CTX_wm_space_file(C);
2663 
2664  if (params) {
2665  params->flag ^= FILE_HIDE_DOT;
2666  ED_fileselect_clear(wm, sfile);
2668  }
2669 
2670  return OPERATOR_FINISHED;
2671 }
2672 
2674 {
2675  /* identifiers */
2676  ot->name = "Toggle Hide Dot Files";
2677  ot->description = "Toggle hide hidden dot files";
2678  ot->idname = "FILE_OT_hidedot";
2679 
2680  /* api callbacks */
2682  /* File browsing only operator (not asset browsing). */
2683  ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2684 }
2685 
2688 /* -------------------------------------------------------------------- */
2693 {
2694  SpaceFile *sfile = CTX_wm_space_file(C);
2695 
2696  /* File browsing only operator (not asset browsing). */
2698  return false;
2699  }
2700 
2702  return params && (params->flag & FILE_CHECK_EXISTING);
2703 }
2704 
2708 static void filenum_newname(char *name, size_t name_size, int add)
2709 {
2710  char head[FILE_MAXFILE], tail[FILE_MAXFILE];
2711  char name_temp[FILE_MAXFILE];
2712  int pic;
2713  ushort digits;
2714 
2715  pic = BLI_path_sequence_decode(name, head, tail, &digits);
2716 
2717  /* are we going from 100 -> 99 or from 10 -> 9 */
2718  if (add < 0 && digits > 0) {
2719  int i, exp;
2720  exp = 1;
2721  for (i = digits; i > 1; i--) {
2722  exp *= 10;
2723  }
2724  if (pic >= exp && (pic + add) < exp) {
2725  digits--;
2726  }
2727  }
2728 
2729  pic += add;
2730  if (pic < 0) {
2731  pic = 0;
2732  }
2733  BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
2734  BLI_strncpy(name, name_temp, name_size);
2735 }
2736 
2738 {
2739  SpaceFile *sfile = CTX_wm_space_file(C);
2741  ScrArea *area = CTX_wm_area(C);
2742 
2743  int inc = RNA_int_get(op->ptr, "increment");
2744  if (params && (inc != 0)) {
2745  filenum_newname(params->file, sizeof(params->file), inc);
2747  file_draw_check(C);
2748  // WM_event_add_notifier(C, NC_WINDOW, NULL);
2749  }
2750 
2751  return OPERATOR_FINISHED;
2752 }
2753 
2755 {
2756  /* identifiers */
2757  ot->name = "Increment Number in Filename";
2758  ot->description = "Increment number in filename";
2759  ot->idname = "FILE_OT_filenum";
2760 
2761  /* api callbacks */
2764 
2765  /* props */
2766  RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
2767 }
2768 
2771 /* -------------------------------------------------------------------- */
2775 static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
2776 {
2777  const int numfiles = filelist_files_ensure(sfile->files);
2778 
2779  if ((file_idx >= 0) && (file_idx < numfiles)) {
2780  FileDirEntry *file = filelist_file(sfile->files, file_idx);
2781 
2782  if ((require_selected == false) ||
2785 
2787  sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
2788  BLI_strncpy(params->renamefile, file->relpath, FILE_MAXFILE);
2789  /* We can skip the pending state,
2790  * as we can directly set FILE_SEL_EDITING on the expected entry here. */
2791  params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
2792  }
2793  }
2794 }
2795 
2797 {
2798  ScrArea *area = CTX_wm_area(C);
2799  SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
2801 
2802  if (params) {
2803  file_rename_state_activate(sfile, params->active_file, false);
2805  }
2806 
2807  return OPERATOR_FINISHED;
2808 }
2809 
2811 {
2812  /* identifiers */
2813  ot->name = "Rename File or Directory";
2814  ot->description = "Rename file or file directory";
2815  ot->idname = "FILE_OT_rename";
2816 
2817  /* api callbacks */
2819  /* File browsing only operator (not asset browsing). */
2821 }
2822 
2825 /* -------------------------------------------------------------------- */
2830 {
2832  return false;
2833  }
2834 
2835  SpaceFile *sfile = CTX_wm_space_file(C);
2837  if (!sfile || !params) {
2838  return false;
2839  }
2840 
2841  char dir[FILE_MAX_LIBEXTRA];
2842  if (filelist_islibrary(sfile->files, dir, NULL)) {
2843  return false;
2844  }
2845 
2846  int numfiles = filelist_files_ensure(sfile->files);
2847  for (int i = 0; i < numfiles; i++) {
2849  /* Has a selected file -> the operator can run. */
2850  return true;
2851  }
2852  }
2853 
2854  return false;
2855 }
2856 
2858  FileDirEntry *file,
2859  const char **r_error_message)
2860 {
2861  char str[FILE_MAX];
2862  BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath);
2863  if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) {
2864  return false;
2865  }
2866 
2867  return true;
2868 }
2869 
2871 {
2873  SpaceFile *sfile = CTX_wm_space_file(C);
2875  int numfiles = filelist_files_ensure(sfile->files);
2876 
2877  const char *error_message = NULL;
2878  bool report_error = false;
2879  errno = 0;
2880  for (int i = 0; i < numfiles; i++) {
2882  FileDirEntry *file = filelist_file(sfile->files, i);
2883  if (!file_delete_single(params, file, &error_message)) {
2884  report_error = true;
2885  }
2886  }
2887  }
2888 
2889  if (report_error) {
2890  if (error_message != NULL) {
2891  BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message);
2892  }
2893  else {
2894  BKE_reportf(op->reports,
2895  RPT_ERROR,
2896  "Could not delete file or directory: %s",
2897  errno ? strerror(errno) : "unknown error");
2898  }
2899  }
2900 
2901  ED_fileselect_clear(wm, sfile);
2903 
2904  return OPERATOR_FINISHED;
2905 }
2906 
2908 {
2909  /* identifiers */
2910  ot->name = "Delete Selected Files";
2911  ot->description = "Move selected files to the trash or recycle bin";
2912  ot->idname = "FILE_OT_delete";
2913 
2914  /* api callbacks */
2917  ot->poll = file_delete_poll; /* <- important, handler is on window level */
2918 }
2919 
2922 /* -------------------------------------------------------------------- */
2927 {
2928  const ScrArea *area = CTX_wm_area(C);
2929  const SpaceFile *sfile = CTX_wm_space_file(C);
2931 
2932  ARegion *region_ctx = CTX_wm_region(C);
2933 
2934  if (area) {
2935  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2936  CTX_wm_region_set(C, region);
2937  if (UI_textbutton_activate_rna(C, region, params, "filter_search")) {
2938  break;
2939  }
2940  }
2941  }
2942 
2943  CTX_wm_region_set(C, region_ctx);
2944 
2945  return OPERATOR_FINISHED;
2946 }
2947 
2949 {
2950  /* identifiers */
2951  ot->name = "Filter";
2952  ot->description = "Start entering filter text";
2953  ot->idname = "FILE_OT_start_filter";
2954 
2955  /* api callbacks */
2957  /* Operator works for file or asset browsing */
2959 }
2960 
2963 /* -------------------------------------------------------------------- */
2968 {
2969  const ScrArea *area = CTX_wm_area(C);
2970  const SpaceFile *sfile = CTX_wm_space_file(C);
2972 
2973  ARegion *region_ctx = CTX_wm_region(C);
2974 
2975  if (area) {
2976  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2977  CTX_wm_region_set(C, region);
2978  if (UI_textbutton_activate_rna(C, region, params, "directory")) {
2979  break;
2980  }
2981  }
2982  }
2983 
2984  CTX_wm_region_set(C, region_ctx);
2985 
2986  return OPERATOR_FINISHED;
2987 }
2988 
2990 {
2991  /* identifiers */
2992  ot->name = "Edit Directory Path";
2993  ot->description = "Start editing directory field";
2994  ot->idname = "FILE_OT_edit_directory_path";
2995 
2996  /* api callbacks */
2999 }
3000 
3003 /* -------------------------------------------------------------------- */
3008 {
3009  // wmOperatorType *ot;
3010  // wmOperatorTypeMacro *otmacro;
3011 
3012  /* future macros */
3013 }
3014 
const char * BKE_appdir_folder_default_or_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition: appdir.c:153
const char * BKE_appdir_folder_id_create(int folder_id, const char *subfolder)
Definition: appdir.c:727
#define BLENDER_BOOKMARK_FILE
Definition: BKE_appdir.h:178
@ BLENDER_USER_CONFIG
Definition: BKE_appdir.h:157
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:743
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct SpaceFile * CTX_wm_space_file(const bContext *C)
Definition: context.c:842
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:314
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:402
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:397
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL()
Definition: fileops.c:1219
int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL()
Definition: fileops.c:947
#define PATH_MAX
Definition: BLI_fileops.h:29
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE int max_ii(int a, int b)
void BLI_split_dir_part(const char *string, char *dir, size_t dirlen)
Definition: path_util.c:1490
int BLI_path_sequence_decode(const char *string, char *head, char *tail, unsigned short *r_digits_len)
Definition: path_util.c:56
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1)
Definition: path_util.c:314
bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1)
Definition: path_util.c:232
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:347
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2)
Definition: path_util.c:221
#define FILE_MAXFILE
void BLI_split_dirfile(const char *string, char *dir, char *file, size_t dirlen, size_t filelen)
Definition: path_util.c:1465
#define FILE_MAX
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2)
Definition: path_util.c:131
#define FILENAME_IS_CURRPAR(_n)
void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1514
void BLI_path_sequence_encode(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
Definition: path_util.c:123
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
int BLI_path_slash_ensure(char *string) ATTR_NONNULL()
Definition: path_util.c:1780
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:450
bool BLI_path_parent_dir(char *path) ATTR_NONNULL()
Definition: path_util.c:623
#define FILE_MAXDIR
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:352
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:897
#define FILENAME_IS_PARENT(_n)
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1531
int BLI_rcti_length_x(const rcti *rect, int x)
Definition: rct.c:148
int BLI_rcti_length_y(const rcti *rect, int y)
Definition: rct.c:159
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned short ushort
Definition: BLI_sys_types.h:68
#define UNPACK2(a)
#define IN_RANGE(a, b, c)
#define UNUSED(x)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
Compatibility-like things for windows.
void BLI_windows_get_default_root_dir(char root_dir[4])
external readfile function prototypes.
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition: readfile.c:1503
@ RGN_TYPE_WINDOW
@ FILE_SORT_DEFAULT
@ FILE_TYPE_DIR
@ SPACE_FILE
eFileSel_Params_RenameFlag
@ FILE_PARAMS_RENAME_POSTSCROLL_PENDING
@ FILE_PARAMS_RENAME_ACTIVE
@ FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE
@ FILE_PARAMS_RENAME_PENDING
@ FILE_SEL_EDITING
@ FILE_SEL_HIGHLIGHTED
@ FILE_SEL_SELECTED
@ FILE_CHECK_EXISTING
@ FILE_SORT_INVERT
@ FILE_DIRSEL_ONLY
@ FILE_HIDE_DOT
@ FILE_PATH_TOKENS_ALLOW
#define FILE_MAX_LIBEXTRA
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_file_change_dir(struct bContext *C)
Definition: filesel.c:1105
#define FILE_LAYOUT_HOR
Definition: ED_fileselect.h:30
#define FILE_LAYOUT_VER
Definition: ED_fileselect.h:31
@ FS_CATEGORY_RECENT
@ FS_CATEGORY_BOOKMARKS
struct FSMenu * ED_fsmenu_get(void)
Definition: fsmenu.c:63
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect)
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
Definition: filesel.c:760
bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const struct View2D *v2d, int x, int y)
void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile)
Definition: filesel.c:1213
struct FSMenuEntry * ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:71
bool ED_fileselect_layout_isect_rect(const FileLayout *layout, const struct View2D *v2d, const struct rcti *rect, struct rcti *r_dst)
@ FS_INSERT_SAVE
@ FS_INSERT_FIRST
int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:219
int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *region)
Definition: filesel.c:677
struct FileSelectParams * ED_fileselect_get_active_params(const struct SpaceFile *sfile)
FileAttributeColumnType
Definition: ED_fileselect.h:33
@ COLUMN_NONE
Definition: ED_fileselect.h:34
void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, struct FSMenuEntry *fsm_head)
Definition: fsmenu.c:198
struct FSMenuEntry * ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition: fsmenu.c:231
FileLayout * ED_fileselect_get_layout(struct SpaceFile *sfile, struct ARegion *region)
Definition: filesel.c:1064
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:729
bool ED_operator_file_active(struct bContext *C)
Definition: screen_ops.c:271
bool ED_operator_file_browsing_active(struct bContext *C)
Definition: screen_ops.c:276
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_area_tag_refresh(ScrArea *area)
Definition: area.c:758
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ UI_SELECT_WALK_RIGHT
@ UI_SELECT_WALK_UP
@ UI_SELECT_WALK_LEFT
@ UI_SELECT_WALK_DOWN
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
eSelectOp
@ SEL_OP_SUB
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but)
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
void UI_view2d_region_to_view_rctf(const struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL()
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
void UI_view2d_curRect_validate(struct View2D *v2d)
Definition: view2d.cc:828
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
@ OPTYPE_REGISTER
Definition: WM_types.h:146
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
#define ND_SPACE_FILE_PARAMS
Definition: WM_types.h:466
#define NC_SPACE
Definition: WM_types.h:342
#define ND_SPACE_FILE_LIST
Definition: WM_types.h:467
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
FILE * file
int len
Definition: draw_manager.c:108
#define str(s)
void file_params_renamefile_clear(struct FileSelectParams *params)
Definition: filesel.c:1297
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file)
Definition: filesel.c:1120
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm, struct wmWindow *win, SpaceFile *sfile)
Definition: filesel.c:1267
void fileselect_file_set(SpaceFile *sfile, int index)
Definition: filesel.c:668
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params)
Definition: filesel.c:1311
bool file_attribute_column_header_is_inside(const struct View2D *v2d, const FileLayout *layout, int x, int y)
void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds)
Definition: file_utils.c:22
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, const FileSelectParams *params, FileLayout *layout, int x)
Definition: filesel.c:853
void file_params_smoothscroll_timer_clear(struct wmWindowManager *wm, struct wmWindow *win, SpaceFile *sfile)
Definition: filesel.c:1261
void file_select_deselect_all(SpaceFile *sfile, uint flag)
Definition: filesel.c:1111
void FILE_OT_filenum(struct wmOperatorType *ot)
Definition: file_ops.c:2754
void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but)
Definition: file_ops.c:2603
void FILE_OT_select_box(wmOperatorType *ot)
Definition: file_ops.c:494
static int file_edit_directory_path_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:2967
void ED_operatormacros_file(void)
Definition: file_ops.c:3007
static int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
Definition: file_ops.c:2036
void file_draw_check(bContext *C)
Definition: file_ops.c:1735
static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: file_ops.c:872
void FILE_OT_bookmark_add(wmOperatorType *ot)
Definition: file_ops.c:1122
void FILE_OT_rename(struct wmOperatorType *ot)
Definition: file_ops.c:2810
void FILE_OT_select_bookmark(wmOperatorType *ot)
Definition: file_ops.c:1073
static int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
Definition: file_ops.c:1551
static bool file_walk_select_do(bContext *C, SpaceFile *sfile, FileSelectParams *params, const int direction, const bool extend, const bool fill)
Definition: file_ops.c:790
static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *region, const rcti *rect_region)
Definition: file_ops.c:60
void FILE_OT_mouse_execute(wmOperatorType *ot)
Definition: file_ops.c:1901
static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: file_ops.c:406
void FILE_OT_edit_directory_path(struct wmOperatorType *ot)
Definition: file_ops.c:2989
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:2926
static bool file_bookmark_move_poll(bContext *C)
Definition: file_ops.c:1319
static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:1098
static int file_box_select_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:462
void FILE_OT_cancel(struct wmOperatorType *ot)
Definition: file_ops.c:1564
static bool file_ensure_hovered_is_active(bContext *C, const wmEvent *event)
Definition: file_ops.c:1866
static int file_directory_new_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:2336
static int file_execute_mouse_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: file_ops.c:1876
static bool file_is_any_selected(struct FileList *files)
Definition: file_ops.c:224
static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:2796
void FILE_OT_highlight(struct wmOperatorType *ot)
Definition: file_ops.c:1466
void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but))
Definition: file_ops.c:2513
void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
Definition: file_ops.c:1518
static int file_box_select_find_last_selected(SpaceFile *sfile, ARegion *region, const FileSelection *sel, const int mouse_xy[2])
Definition: file_ops.c:373
static rcti file_select_mval_to_select_rect(const int mval[2])
Definition: file_ops.c:520
static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
Definition: file_ops.c:162
void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
Definition: file_ops.c:1664
static int file_previous_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:2000
void FILE_OT_directory_new(struct wmOperatorType *ot)
Definition: file_ops.c:2422
void FILE_OT_filepath_drop(wmOperatorType *ot)
Definition: file_ops.c:2293
static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
Definition: file_ops.c:2775
void FILE_OT_parent(struct wmOperatorType *ot)
Definition: file_ops.c:1981
void FILE_OT_bookmark_delete(wmOperatorType *ot)
Definition: file_ops.c:1175
void FILE_OT_select_walk(wmOperatorType *ot)
Definition: file_ops.c:888
static int file_column_sort_ui_context_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: file_ops.c:1485
static int filepath_drop_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:2265
static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
Definition: file_ops.c:123
static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:1000
static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
Definition: file_ops.c:1959
static void clamp_to_filelist(int numfiles, FileSelection *sel)
Definition: file_ops.c:97
@ FILE_BOOKMARK_MOVE_UP
Definition: file_ops.c:1259
@ FILE_BOOKMARK_MOVE_DOWN
Definition: file_ops.c:1260
@ FILE_BOOKMARK_MOVE_BOTTOM
Definition: file_ops.c:1261
@ FILE_BOOKMARK_MOVE_TOP
Definition: file_ops.c:1258
void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
Definition: file_ops.c:1236
static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
Definition: file_ops.c:1922
void file_draw_check_ex(bContext *C, ScrArea *area)
Definition: file_ops.c:1711
void FILE_OT_hidedot(struct wmOperatorType *ot)
Definition: file_ops.c:2673
void FILE_OT_smoothscroll(wmOperatorType *ot)
Definition: file_ops.c:2246
void FILE_OT_refresh(struct wmOperatorType *ot)
Definition: file_ops.c:1941
void FILE_OT_bookmark_move(wmOperatorType *ot)
Definition: file_ops.c:1331
static FileSelection file_current_selection_range_get(struct FileList *files)
Definition: file_ops.c:239
static void filenum_newname(char *name, size_t name_size, int add)
Definition: file_ops.c:2708
static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:1200
void FILE_OT_select_all(wmOperatorType *ot)
Definition: file_ops.c:978
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
Definition: file_ops.c:327
static int file_delete_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:2870
static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
Definition: file_ops.c:2658
static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
Definition: file_ops.c:269
static bool file_operator_poll(bContext *C)
Definition: file_ops.c:1539
void FILE_OT_reset_recent(wmOperatorType *ot)
Definition: file_ops.c:1385
static bool file_filenum_poll(bContext *C)
Definition: file_ops.c:2692
int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
Definition: file_ops.c:1404
void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
Definition: file_ops.c:1741
void FILE_OT_select(wmOperatorType *ot)
Definition: file_ops.c:612
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
Definition: file_ops.c:1692
void FILE_OT_delete(struct wmOperatorType *ot)
Definition: file_ops.c:2907
void FILE_OT_execute(struct wmOperatorType *ot)
Definition: file_ops.c:1847
static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: file_ops.c:1452
static bool file_delete_single(const FileSelectParams *params, FileDirEntry *file, const char **r_error_message)
Definition: file_ops.c:2857
static void file_ensure_selection_inside_viewbounds(ARegion *region, SpaceFile *sfile, FileSelection *sel)
Definition: file_ops.c:309
static bool new_folder_path(const char *parent, char folder[FILE_MAX], char name[FILE_MAXFILE])
Definition: file_ops.c:2317
static int file_select_all_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:921
static int file_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:1836
void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
Definition: file_ops.c:1582
void FILE_OT_start_filter(struct wmOperatorType *ot)
Definition: file_ops.c:2948
static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
Definition: file_ops.c:2074
static void file_expand_directory(bContext *C)
Definition: file_ops.c:2452
void file_sfile_to_operator(Main *bmain, wmOperator *op, SpaceFile *sfile)
Definition: file_ops.c:1657
bool file_draw_check_exists(SpaceFile *sfile)
Definition: file_ops.c:1746
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
Definition: file_ops.c:1366
static bool file_execute(bContext *C, SpaceFile *sfile)
Definition: file_ops.c:1771
void FILE_OT_next(struct wmOperatorType *ot)
Definition: file_ops.c:2054
void FILE_OT_view_selected(wmOperatorType *ot)
Definition: file_ops.c:1031
static int bookmark_delete_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:1141
FileSelect
Definition: file_ops.c:91
@ FILE_SELECT_NOTHING
Definition: file_ops.c:92
@ FILE_SELECT_DIR
Definition: file_ops.c:93
@ FILE_SELECT_FILE
Definition: file_ops.c:94
static int file_select_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:528
void FILE_OT_previous(struct wmOperatorType *ot)
Definition: file_ops.c:2017
static int bookmark_select_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:1052
static int bookmark_move_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:1264
static bool file_delete_poll(bContext *C)
Definition: file_ops.c:2829
static bool file_walk_select_selection_set(wmWindow *win, ARegion *region, 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)
Definition: file_ops.c:672
static int file_filenum_exec(bContext *C, wmOperator *op)
Definition: file_ops.c:2737
bool filelist_is_ready(struct FileList *filelist)
Definition: filelist.c:2158
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2926
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
Definition: filelist.c:2998
const char * folderlist_peeklastdir(ListBase *folderlist)
Definition: filelist.c:133
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2988
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2936
void folderlist_popdir(struct ListBase *folderlist, char *dir)
Definition: filelist.c:89
uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition: filelist.c:2964
void folderlist_pushdir(ListBase *folderlist, const char *dir)
Definition: filelist.c:109
void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
Definition: filelist.c:2132
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2879
FileDirEntry * filelist_file(struct FileList *filelist, int index)
Definition: filelist.c:2280
int filelist_files_ensure(FileList *filelist)
Definition: filelist.c:2173
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition: filelist.c:2975
bool filelist_is_dir(struct FileList *filelist, const char *path)
Definition: filelist.c:2111
uint filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition: filelist.c:2949
FileSelType
Definition: filelist.h:26
@ FILE_SEL_REMOVE
Definition: filelist.h:27
@ FILE_SEL_ADD
Definition: filelist.h:28
@ FILE_SEL_TOGGLE
Definition: filelist.h:29
FileCheckType
Definition: filelist.h:32
@ CHECK_FILES
Definition: filelist.h:34
@ CHECK_DIRS
Definition: filelist.h:33
@ CHECK_ALL
Definition: filelist.h:35
void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition: fsmenu.c:489
void fsmenu_refresh_system_category(struct FSMenu *fsmenu)
Definition: fsmenu.c:1056
void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, int icon, FSMenuInsert flag)
Definition: fsmenu.c:366
void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu)
Definition: fsmenu.c:1229
void fsmenu_write_file(struct FSMenu *fsmenu, const char *filepath)
Definition: fsmenu.c:522
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
ccl_device_inline float3 exp(float3 v)
Definition: math_float3.h:392
bool add(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer)
static void area(int d1, int d2, int e1, int e2, float weights[2])
bool active
all scheduled work for the GPU.
T abs(const T &a)
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2429
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value)
Definition: rna_access.c:3149
void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
Definition: rna_access.c:3835
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:4026
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
Definition: rna_access.c:3239
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_string_file_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3711
PropertyRNA * RNA_def_string_dir_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3735
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3687
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
short regiontype
struct FSMenuEntry * next
char name[256]
Definition: fsmenu.c:53
FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX]
Definition: ED_fileselect.h:78
int tile_border_y
Definition: ED_fileselect.h:64
int flow_columns
Definition: ED_fileselect.h:70
int tile_border_x
Definition: ED_fileselect.h:63
Definition: BKE_main.h:121
struct wmTimer * smoothscroll_timer
short bookmarknr
struct FileLayout * layout
struct wmOperator * op
ListBase * folders_prev
struct FileList * files
ListBase * folders_next
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
int xy[2]
Definition: WM_types.h:682
int mval[2]
Definition: WM_types.h:684
void * customdata
Definition: WM_types.h:715
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval)
void WM_event_add_mousemove(wmWindow *win)
@ EVT_FILESELECT_CANCEL
@ EVT_FILESELECT_EXEC
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_generic_select(wmOperatorType *ot)
void WM_operator_properties_select_walk_direction(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: wm_operators.c:962
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: wm_operators.c:903
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
Definition: wm_operators.c:667
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783