Blender V4.5
file_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_fileops.h"
10#include "BLI_linklist.h"
11#include "BLI_listbase.h"
12#include "BLI_path_utils.hh"
13#include "BLI_string.h"
14#include "BLI_utildefines.h"
15
16#include "BKE_appdir.hh"
17#include "BKE_blendfile.hh"
18#include "BKE_context.hh"
19#include "BKE_main.hh"
20#include "BKE_report.hh"
21#include "BKE_screen.hh"
22
23#include "BLT_translation.hh"
24
25#ifdef WIN32
26# include "BLI_winstuff.h"
27#endif
28
29#include "ED_fileselect.hh"
30#include "ED_screen.hh"
31#include "ED_select_utils.hh"
32
33#include "UI_interface.hh"
34#include "UI_interface_icons.hh"
35#include "UI_resources.hh"
36
37#include "MEM_guardedalloc.h"
38
39#include "RNA_access.hh"
40#include "RNA_define.hh"
41
42#include "UI_view2d.hh"
43
44#include "WM_api.hh"
45#include "WM_types.hh"
46
47#include "file_intern.hh"
48#include "filelist.hh"
49#include "fsmenu.h"
50
51#include <algorithm>
52#include <cctype>
53#include <cerrno>
54#include <cstdio>
55#include <cstdlib>
56#include <cstring>
57
58/* -------------------------------------------------------------------- */
61
63 ARegion *region,
64 const rcti *rect_region)
65{
66 FileSelection sel;
67
68 View2D *v2d = &region->v2d;
69 rcti rect_view;
70 rctf rect_view_fl;
71 rctf rect_region_fl;
72
73 BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
74
75 /* Okay, manipulating v2d rects here is hacky... */
76 v2d->mask.ymax -= sfile->layout->offset_top;
77 v2d->cur.ymax -= sfile->layout->offset_top;
78 UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
79 v2d->mask.ymax += sfile->layout->offset_top;
80 v2d->cur.ymax += sfile->layout->offset_top;
81
82 BLI_rcti_init(&rect_view,
83 int(v2d->tot.xmin + rect_view_fl.xmin),
84 int(v2d->tot.xmin + rect_view_fl.xmax),
85 int(v2d->tot.ymax - rect_view_fl.ymin),
86 int(v2d->tot.ymax - rect_view_fl.ymax));
87
88 sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
89
90 return sel;
91}
92
98
99static void clamp_to_filelist(int numfiles, FileSelection *sel)
100{
101 /* box select before the first file */
102 if ((sel->first < 0) && (sel->last >= 0)) {
103 sel->first = 0;
104 }
105 /* don't select if everything is outside filelist */
106 if ((sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles))) {
107 sel->first = -1;
108 sel->last = -1;
109 }
110
111 /* fix if last file invalid */
112 if ((sel->first > 0) && (sel->last < 0)) {
113 sel->last = numfiles - 1;
114 }
115
116 /* clamp */
117 if (sel->first >= numfiles) {
118 sel->first = numfiles - 1;
119 }
120 if (sel->last >= numfiles) {
121 sel->last = numfiles - 1;
122 }
123}
124
125static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
126{
127 ARegion *region = CTX_wm_region(C);
128 SpaceFile *sfile = CTX_wm_space_file(C);
129 int numfiles = filelist_files_ensure(sfile->files);
130 FileSelection sel;
131
132 sel = find_file_mouse_rect(sfile, region, rect);
133 if (!((sel.first == -1) && (sel.last == -1))) {
134 clamp_to_filelist(numfiles, &sel);
135 }
136
137 /* if desired, fill the selection up from the last selected file to the current one */
138 if (fill && (sel.last >= 0) && (sel.last < numfiles)) {
139 int f;
140 /* Try to find a smaller-index selected item. */
141 for (f = sel.last; f >= 0; f--) {
143 break;
144 }
145 }
146 if (f >= 0) {
147 sel.first = f + 1;
148 }
149 /* If none found, try to find a higher-index selected item. */
150 else {
151 for (f = sel.first; f < numfiles; f++) {
153 break;
154 }
155 }
156 if (f < numfiles) {
157 sel.last = f - 1;
158 }
159 }
160 }
161 return sel;
162}
163
164static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
165{
166 Main *bmain = CTX_data_main(C);
168 SpaceFile *sfile = CTX_wm_space_file(C);
170 int numfiles = filelist_files_ensure(sfile->files);
171 const FileDirEntry *file;
172
173 /* make the selected file active */
174 if ((selected_idx >= 0) && (selected_idx < numfiles) &&
175 (file = filelist_file(sfile->files, selected_idx)))
176 {
177 params->highlight_file = selected_idx;
178 params->active_file = selected_idx;
179
180 if (file->typeflag & FILE_TYPE_DIR) {
181 const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
182
183 if (do_diropen == false) {
184 retval = FILE_SELECT_DIR;
185 }
186 /* the path is too long and we are not going up! */
187 else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
188 // XXX error("Path too long, cannot enter this directory");
189 }
190 else {
191 if (is_parent_dir) {
192 /* Avoids `/../../`. */
194
195 if (params->recursion_level > 1) {
196 /* Disable `dirtree` recursion when going up in tree. */
197 params->recursion_level = 0;
198 filelist_setrecursion(sfile->files, params->recursion_level);
199 }
200 }
201 else if (file->redirection_path) {
202 STRNCPY(params->dir, file->redirection_path);
204 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
205 }
206 else {
208 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
209 BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath);
210 }
211
213 retval = FILE_SELECT_DIR;
214 }
215 }
216 else {
217 retval = FILE_SELECT_FILE;
218 }
219 fileselect_file_set(C, sfile, selected_idx);
220 }
221 return retval;
222}
223
228{
229 const int numfiles = filelist_files_ensure(files);
230 int i;
231
232 /* Is any file selected ? */
233 for (i = 0; i < numfiles; i++) {
235 return true;
236 }
237 }
238
239 return false;
240}
241
243{
244 const int numfiles = filelist_files_ensure(files);
245 FileSelection selection = {-1, -1};
246
247 /* Iterate over the files once but in two loops, one to find the first selected file, and the
248 * other to find the last. */
249
250 int file_index;
251 for (file_index = 0; file_index < numfiles; file_index++) {
252 if (filelist_entry_is_selected(files, file_index)) {
253 /* First selected entry found. */
254 selection.first = file_index;
255 break;
256 }
257 }
258
259 for (; file_index < numfiles; file_index++) {
260 if (filelist_entry_is_selected(files, file_index)) {
261 selection.last = file_index;
262 /* Keep looping, we may find more selected files. */
263 }
264 }
265
266 return selection;
267}
268
272static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
273{
274 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
275 rctf *cur = &region->v2d.cur;
276 rcti rect;
277 bool changed = true;
278
279 file_tile_boundbox(region, layout, file, &rect);
280
281 /* down - also use if tile is higher than viewbounds so view is aligned to file name */
282 if (cur->ymin > rect.ymin || layout->tile_h > region->winy) {
283 cur->ymin = rect.ymin - (2 * layout->tile_border_y);
284 cur->ymax = cur->ymin + region->winy;
285 }
286 /* up */
287 else if ((cur->ymax - layout->offset_top) < rect.ymax) {
288 cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
289 cur->ymin = cur->ymax - region->winy;
290 }
291 /* left - also use if tile is wider than viewbounds so view is aligned to file name */
292 else if (cur->xmin > rect.xmin || layout->tile_w > region->winx) {
293 cur->xmin = rect.xmin - layout->tile_border_x;
294 cur->xmax = cur->xmin + region->winx;
295 }
296 /* right */
297 else if (cur->xmax < rect.xmax) {
298 cur->xmax = rect.xmax + (2 * layout->tile_border_x);
299 cur->xmin = cur->xmax - region->winx;
300 }
301 else {
302 BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
303 (cur->ymax - layout->offset_top) >= rect.ymax);
304 changed = false;
305 }
306
307 if (changed) {
309 }
310}
311
313 SpaceFile *sfile,
314 FileSelection *sel)
315{
316 const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
317
318 if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) &&
319 ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h)))
320 {
321 return;
322 }
323
324 /* Adjust view to display selection. Doing iterations for first and last
325 * selected item makes view showing as much of the selection possible.
326 * Not really useful if tiles are (almost) bigger than viewbounds though. */
327 file_ensure_inside_viewbounds(region, sfile, sel->last);
328 file_ensure_inside_viewbounds(region, sfile, sel->first);
329}
330
332 bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
333{
334 SpaceFile *sfile = CTX_wm_space_file(C);
337 FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
338 const FileCheckType check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
339
340 /* flag the files as selected in the filelist */
342 sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
343
344 /* Don't act on multiple selected files */
345 if (sel.first != sel.last) {
346 select = FileSelType(0);
347 }
348
349 /* Do we have a valid selection and are we actually selecting */
350 if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
351 /* Check last selection, if selected, act on the file or dir */
352 if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
353 retval = file_select_do(C, sel.last, do_diropen);
354 }
355 }
356
357 if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
358 params->active_file = -1;
359 }
360 else if (sel.last >= 0) {
361 ARegion *region = CTX_wm_region(C);
362 file_ensure_selection_inside_viewbounds(region, sfile, &sel);
363 }
364
365 /* update operator for name change event */
367
368 return retval;
369}
370
372
373/* -------------------------------------------------------------------- */
376
381 ScrArea *area,
383{
384 /* NOTE: use warning instead of error here, because the bookmark operation may be part of
385 * other actions which should not cause the operator to fail entirely. */
386 const std::optional<std::string> cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG,
387 nullptr);
388 if (!cfgdir.has_value()) {
389 BKE_report(reports, RPT_ERROR, "Unable to create configuration directory to write bookmarks");
390 return false;
391 }
392
393 char filepath[FILE_MAX];
394 BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_BOOKMARK_FILE);
395 if (!fsmenu_write_file(fsmenu, filepath)) {
396 BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath);
397 return false;
398 }
399
401 ED_area_tag_redraw(area);
402 return true;
403}
404
406
407/* -------------------------------------------------------------------- */
410
412 ARegion *region,
413 const FileSelection *sel,
414 const int mouse_xy[2])
415{
416 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
417 rcti bounds_first, bounds_last;
418 int dist_first, dist_last;
419 float mouseco_view[2];
420
421 UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
422
423 file_tile_boundbox(region, layout, sel->first, &bounds_first);
424 file_tile_boundbox(region, layout, sel->last, &bounds_last);
425
426 /* are first and last in the same column (horizontal layout)/row (vertical layout)? */
427 if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
428 (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin))
429 {
430 /* use vertical distance */
431 const int my_loc = int(mouseco_view[1]);
432 dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
433 dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
434 }
435 else {
436 /* use horizontal distance */
437 const int mx_loc = int(mouseco_view[0]);
438 dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
439 dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
440 }
441
442 return (dist_first < dist_last) ? sel->first : sel->last;
443}
444
446{
447 ARegion *region = CTX_wm_region(C);
448 SpaceFile *sfile = CTX_wm_space_file(C);
450 FileSelection sel;
451 rcti rect;
452
454
455 result = WM_gesture_box_modal(C, op, event);
456
459
460 ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
461
462 sel = file_selection_get(C, &rect, false);
463 if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
464 int idx;
465
470
471 for (idx = sel.last; idx >= 0; idx--) {
472 const FileDirEntry *file = filelist_file(sfile->files, idx);
473
474 /* Don't highlight read-only file (".." or ".") on box select. */
475 if (FILENAME_IS_CURRPAR(file->relpath)) {
478 }
479
480 /* make sure highlight_file is no readonly file */
481 if (sel.last == idx) {
482 params->highlight_file = idx;
483 }
484 }
485 }
486 params->sel_first = sel.first;
487 params->sel_last = sel.last;
488 params->active_file = file_box_select_find_last_selected(sfile, region, &sel, event->mval);
489 }
490 else {
491 params->highlight_file = -1;
492 params->sel_first = params->sel_last = -1;
493 fileselect_file_set(C, sfile, params->active_file);
496 }
497
498 return result;
499}
500
502{
503 ARegion *region = CTX_wm_region(C);
504 SpaceFile *sfile = CTX_wm_space_file(C);
505 rcti rect;
507
509
510 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
511 const bool select = (sel_op != SEL_OP_SUB);
512 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
514 }
515
516 ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
517
518 ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
519
520 /* unselect '..' parent entry - it's not supposed to be selected if more than
521 * one file is selected */
523
524 if (FILE_SELECT_DIR == ret) {
526 }
527 else if (FILE_SELECT_FILE == ret) {
529 }
530 return OPERATOR_FINISHED;
531}
532
534{
535 /* identifiers */
536 ot->name = "Box Select";
537 ot->description = "Activate/select the file(s) contained in the border";
538 ot->idname = "FILE_OT_select_box";
539
540 /* API callbacks. */
541 ot->invoke = WM_gesture_box_invoke;
542 ot->exec = file_box_select_exec;
543 ot->modal = file_box_select_modal;
544 /* Operator works for file or asset browsing */
546 ot->cancel = WM_gesture_box_cancel;
547
548 /* properties */
551}
552
554
555/* -------------------------------------------------------------------- */
558
559static rcti file_select_mval_to_select_rect(const int mval[2])
560{
561 rcti rect;
562 rect.xmin = rect.xmax = mval[0];
563 rect.ymin = rect.ymax = mval[1];
564 return rect;
565}
566
568{
569 ARegion *region = CTX_wm_region(C);
570 SpaceFile *sfile = CTX_wm_space_file(C);
572 rcti rect;
573 const bool extend = RNA_boolean_get(op->ptr, "extend");
574 const bool fill = RNA_boolean_get(op->ptr, "fill");
575 const bool do_diropen = RNA_boolean_get(op->ptr, "open");
576 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
577 const bool only_activate_if_selected = RNA_boolean_get(op->ptr, "only_activate_if_selected");
578 /* Used so right mouse clicks can do both, activate and spawn the context menu. */
579 const bool pass_through = RNA_boolean_get(op->ptr, "pass_through");
580 bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
581
582 if (region->regiontype != RGN_TYPE_WINDOW) {
583 return OPERATOR_CANCELLED;
584 }
585
586 int mval[2];
587 mval[0] = RNA_int_get(op->ptr, "mouse_x");
588 mval[1] = RNA_int_get(op->ptr, "mouse_y");
590
591 if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &region->v2d, rect.xmin, rect.ymin)) {
593 }
594
595 if (extend || fill) {
596 wait_to_deselect_others = false;
597 }
598
600
602 if (params) {
603 int idx = params->highlight_file;
604 int numfiles = filelist_files_ensure(sfile->files);
605
606 if ((idx >= 0) && (idx < numfiles)) {
607 const bool is_selected = filelist_entry_select_index_get(sfile->files, idx, CHECK_ALL) &
609 if (only_activate_if_selected && is_selected) {
610 /* Don't deselect other items. */
611 }
612 else if (wait_to_deselect_others && is_selected) {
613 ret_val = OPERATOR_RUNNING_MODAL;
614 }
615 /* single select, deselect all selected first */
616 else if (!extend) {
618 }
619 }
620 }
621
622 ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
623
624 if (extend) {
625 /* unselect '..' parent entry - it's not supposed to be selected if more
626 * than one file is selected */
628 }
629
630 if (ret == FILE_SELECT_NOTHING) {
631 if (deselect_all) {
633 }
634 }
635 else if (ret == FILE_SELECT_DIR) {
637 }
638 else if (ret == FILE_SELECT_FILE) {
640 }
641
642 WM_event_add_mousemove(CTX_wm_window(C)); /* for directory changes */
644
645 if ((ret_val == OPERATOR_FINISHED) && pass_through) {
646 ret_val |= OPERATOR_PASS_THROUGH;
647 }
648 return ret_val;
649}
650
652{
653 PropertyRNA *prop;
654
655 /* identifiers */
656 ot->name = "Select";
657 ot->idname = "FILE_OT_select";
658 ot->description = "Handle mouse clicks to select and activate items";
659
660 /* API callbacks. */
662 ot->exec = file_select_exec;
664 /* Operator works for file or asset browsing */
666
667 /* properties */
669 prop = RNA_def_boolean(ot->srna,
670 "extend",
671 false,
672 "Extend",
673 "Extend selection instead of deselecting everything first");
675 prop = RNA_def_boolean(
676 ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
679 prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
681 prop = RNA_def_boolean(ot->srna,
682 "deselect_all",
683 false,
684 "Deselect On Nothing",
685 "Deselect all when nothing under the cursor");
687 prop = RNA_def_boolean(ot->srna,
688 "only_activate_if_selected",
689 false,
690 "Only Activate if Selected",
691 "Do not change selection if the item under the cursor is already "
692 "selected, only activate it");
694 prop = RNA_def_boolean(ot->srna,
695 "pass_through",
696 false,
697 "Pass Through",
698 "Even on successful execution, pass the event on so other operators can "
699 "execute on it as well");
701}
702
704
705/* -------------------------------------------------------------------- */
708
713 wmWindow *win,
714 ARegion *region,
715 SpaceFile *sfile,
716 const int direction,
717 const int numfiles,
718 const int active_old,
719 const int active_new,
720 const int other_site,
721 const bool has_selection,
722 const bool extend,
723 const bool fill)
724{
726 FileList *files = sfile->files;
727 const int last_sel = params->active_file; /* store old value */
728 int active = active_old; /* could use active_old instead, just for readability */
729 bool deselect = false;
730
732
733 if (numfiles == 0) {
734 /* No files visible, nothing to do. */
735 return false;
736 }
737
738 if (has_selection) {
739 if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
740 filelist_entry_select_index_get(files, active_new, CHECK_ALL))
741 {
742 /* conditions for deselecting: initial file is selected, new file is
743 * selected and either other_side isn't selected/found or we use fill */
744 deselect = (fill || other_site == -1 ||
745 !filelist_entry_select_index_get(files, other_site, CHECK_ALL));
746
747 /* don't change highlight_file here since we either want to deselect active or we want
748 * to walk through a block of selected files without selecting/deselecting anything */
749 params->active_file = active_new;
750 /* but we want to change active if we use fill
751 * (needed to get correct selection bounds) */
752 if (deselect && fill) {
753 active = active_new;
754 }
755 }
756 else {
757 /* regular selection change */
758 params->active_file = active = active_new;
759 }
760 }
761 else {
762 /* select last file */
763 if (ELEM(direction, UI_SELECT_WALK_UP, UI_SELECT_WALK_LEFT)) {
764 params->active_file = active = numfiles - 1;
765 }
766 /* select first file */
767 else if (ELEM(direction, UI_SELECT_WALK_DOWN, UI_SELECT_WALK_RIGHT)) {
768 params->active_file = active = 0;
769 }
770 else {
771 BLI_assert(0);
772 }
773 }
774
775 if (active < 0) {
776 return false;
777 }
778
779 if (extend) {
780 /* highlight the active walker file for extended selection for better visual feedback */
781 params->highlight_file = params->active_file;
782
783 /* unselect '..' parent entry - it's not supposed to be selected if more
784 * than one file is selected */
786 }
787 else {
788 /* deselect all first */
790
791 /* highlight file under mouse pos */
792 params->highlight_file = -1;
794 }
795
796 /* do the actual selection */
797 if (fill) {
798 FileSelection sel = {std::min(active, last_sel), std::max(active, last_sel)};
799
800 /* fill selection between last and first selected file */
802 files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
803 /* entire sel is cleared here, so select active again */
804 if (deselect) {
806 }
807
808 /* unselect '..' parent entry - it's not supposed to be selected if more
809 * than one file is selected */
810 if ((sel.last - sel.first) > 1) {
812 }
813 }
814 else {
817 }
818
819 BLI_assert(IN_RANGE(active, -1, numfiles));
820 fileselect_file_set(C, sfile, params->active_file);
821
822 /* ensure newly selected file is inside viewbounds */
823 file_ensure_inside_viewbounds(region, sfile, params->active_file);
824
825 /* selection changed */
826 return true;
827}
828
833 SpaceFile *sfile,
835 const int direction,
836 const bool extend,
837 const bool fill)
838{
839 wmWindow *win = CTX_wm_window(C);
840 ARegion *region = CTX_wm_region(C);
841 FileList *files = sfile->files;
842 const int numfiles = filelist_files_ensure(files);
843 const bool has_selection = file_is_any_selected(files);
844 const int active_old = params->active_file;
845 int active_new = -1;
846 int other_site = -1; /* file on the other site of active_old */
847
848 /* *** get all needed files for handling selection *** */
849
850 if (numfiles == 0) {
851 /* No files visible, nothing to do. */
852 return false;
853 }
854
855 if (has_selection) {
856 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
857 const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
858
859 if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_UP) ||
860 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_LEFT))
861 {
862 active_new = active_old - 1;
863 other_site = active_old + 1;
864 }
865 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_DOWN) ||
866 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_RIGHT))
867 {
868 active_new = active_old + 1;
869 other_site = active_old - 1;
870 }
871 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_LEFT) ||
872 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_UP))
873 {
874 active_new = active_old - idx_shift;
875 other_site = active_old + idx_shift;
876 }
877 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_RIGHT) ||
878 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_DOWN))
879 {
880
881 active_new = active_old + idx_shift;
882 other_site = active_old - idx_shift;
883 }
884 else {
885 BLI_assert(0);
886 }
887
888 if (!IN_RANGE(active_new, -1, numfiles)) {
889 if (extend) {
890 /* extend to invalid file -> abort */
891 return false;
892 }
893 /* if we don't extend, selecting '..' (index == 0) is allowed so
894 * using key selection to go to parent directory is possible */
895 if (active_new != 0) {
896 /* select initial file */
897 active_new = active_old;
898 }
899 }
900 if (!IN_RANGE(other_site, 0, numfiles)) {
901 other_site = -1;
902 }
903 }
904
906 win,
907 region,
908 sfile,
909 direction,
910 numfiles,
911 active_old,
912 active_new,
913 other_site,
914 has_selection,
915 extend,
916 fill);
917}
918
920 wmOperator *op,
921 const wmEvent * /*event*/)
922{
925 const int direction = RNA_enum_get(op->ptr, "direction");
926 const bool extend = RNA_boolean_get(op->ptr, "extend");
927 const bool fill = RNA_boolean_get(op->ptr, "fill");
928
929 if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
931 return OPERATOR_FINISHED;
932 }
933
934 return OPERATOR_CANCELLED;
935}
936
938{
939 PropertyRNA *prop;
940
941 /* identifiers */
942 ot->name = "Walk Select/Deselect File";
943 ot->description = "Select/Deselect files by walking through them";
944 ot->idname = "FILE_OT_select_walk";
945
946 /* API callbacks. */
947 ot->invoke = file_walk_select_invoke;
948 /* Operator works for file or asset browsing */
950
951 /* properties */
953 prop = RNA_def_boolean(ot->srna,
954 "extend",
955 false,
956 "Extend",
957 "Extend selection instead of deselecting everything first");
959 prop = RNA_def_boolean(
960 ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
963}
964
966
967/* -------------------------------------------------------------------- */
970
972{
973 ScrArea *area = CTX_wm_area(C);
974 SpaceFile *sfile = CTX_wm_space_file(C);
976 FileSelection sel;
977 const int numfiles = filelist_files_ensure(sfile->files);
978 int action = RNA_enum_get(op->ptr, "action");
979
980 if (action == SEL_TOGGLE) {
982 }
983
984 sel.first = 0;
985 sel.last = numfiles - 1;
986
987 FileCheckType check_type;
988 FileSelType filesel_type;
989
990 switch (action) {
991 case SEL_SELECT:
992 case SEL_INVERT: {
993 check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
994 filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD;
995 break;
996 }
997 case SEL_DESELECT: {
998 check_type = CHECK_ALL;
999 filesel_type = FILE_SEL_REMOVE;
1000 break;
1001 }
1002 default: {
1003 BLI_assert(0);
1004 return OPERATOR_CANCELLED;
1005 }
1006 }
1007
1009 sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type);
1010
1011 params->active_file = -1;
1012 if (action != SEL_DESELECT) {
1013 for (int i = 0; i < numfiles; i++) {
1014 if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
1015 params->active_file = i;
1016 break;
1017 }
1018 }
1019 }
1020
1023 ED_area_tag_redraw(area);
1024
1025 return OPERATOR_FINISHED;
1026}
1027
1029{
1030 /* identifiers */
1031 ot->name = "(De)select All Files";
1032 ot->description = "Select or deselect all files";
1033 ot->idname = "FILE_OT_select_all";
1034
1035 /* API callbacks. */
1036 ot->exec = file_select_all_exec;
1037 /* Operator works for file or asset browsing */
1039
1040 /* properties */
1042}
1043
1045
1046/* -------------------------------------------------------------------- */
1049
1051{
1052 SpaceFile *sfile = CTX_wm_space_file(C);
1055
1056 if (sel.first == -1 && sel.last == -1 && params->active_file == -1) {
1057 /* Nothing was selected. */
1058 return OPERATOR_CANCELLED;
1059 }
1060
1061 /* Extend the selection area with the active file, as it may not be selected but still is
1062 * important to have in view. NOTE: active_file gets -1 after a search has been cleared/updated.
1063 */
1064 if (params->active_file != -1) {
1065 if (sel.first == -1 || params->active_file < sel.first) {
1066 sel.first = params->active_file;
1067 }
1068 if (sel.last == -1 || params->active_file > sel.last) {
1069 sel.last = params->active_file;
1070 }
1071 }
1072
1073 ScrArea *area = CTX_wm_area(C);
1074 ARegion *region = CTX_wm_region(C);
1075 file_ensure_selection_inside_viewbounds(region, sfile, &sel);
1076
1079 ED_area_tag_redraw(area);
1080
1081 return OPERATOR_FINISHED;
1082}
1083
1085{
1086 /* identifiers */
1087 ot->name = "Frame Selected";
1088 ot->description = "Scroll the selected files into view";
1089 ot->idname = "FILE_OT_view_selected";
1090
1091 /* API callbacks. */
1093 /* Operator works for file or asset browsing */
1095}
1096
1098
1099/* -------------------------------------------------------------------- */
1102
1103/* Note we could get rid of this one, but it's used by some addon so...
1104 * Does not hurt keeping it around for now. */
1106{
1107 Main *bmain = CTX_data_main(C);
1108 SpaceFile *sfile = CTX_wm_space_file(C);
1109
1110 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "dir");
1112 char entry[256];
1113
1114 RNA_property_string_get(op->ptr, prop, entry);
1115 STRNCPY(params->dir, entry);
1117 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
1119
1121
1122 return OPERATOR_FINISHED;
1123}
1124
1126{
1127 PropertyRNA *prop;
1128
1129 /* identifiers */
1130 ot->name = "Select Directory";
1131 ot->description = "Select a bookmarked directory";
1132 ot->idname = "FILE_OT_select_bookmark";
1133
1134 /* API callbacks. */
1135 ot->exec = bookmark_select_exec;
1136 /* Bookmarks are for file browsing only (not asset browsing). */
1138
1139 /* properties */
1140 prop = RNA_def_string(ot->srna, "dir", nullptr, FILE_MAXDIR, "Directory", "");
1142}
1143
1145
1146/* -------------------------------------------------------------------- */
1149
1151{
1152 ScrArea *area = CTX_wm_area(C);
1153 SpaceFile *sfile = CTX_wm_space_file(C);
1154 FSMenu *fsmenu = ED_fsmenu_get();
1156
1157 if (params->dir[0] != '\0') {
1158
1160 fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, nullptr, ICON_FILE_FOLDER, FS_INSERT_SAVE);
1162 }
1163 return OPERATOR_FINISHED;
1164}
1165
1167{
1168 /* identifiers */
1169 ot->name = "Add Bookmark";
1170 ot->description = "Add a bookmark for the selected/active directory";
1171 ot->idname = "FILE_OT_bookmark_add";
1172
1173 /* API callbacks. */
1174 ot->exec = bookmark_add_exec;
1175 /* Bookmarks are for file browsing only (not asset browsing). */
1177}
1178
1180
1181/* -------------------------------------------------------------------- */
1184
1186{
1187 ScrArea *area = CTX_wm_area(C);
1188 SpaceFile *sfile = CTX_wm_space_file(C);
1189 FSMenu *fsmenu = ED_fsmenu_get();
1190 int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1191
1192 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
1193 const int index = RNA_property_is_set(op->ptr, prop) ? RNA_property_int_get(op->ptr, prop) :
1194 sfile->bookmarknr;
1195 if ((index > -1) && (index < nentries)) {
1198 }
1199
1200 return OPERATOR_FINISHED;
1201}
1202
1204{
1205 PropertyRNA *prop;
1206
1207 /* identifiers */
1208 ot->name = "Delete Bookmark";
1209 ot->description = "Delete selected bookmark";
1210 ot->idname = "FILE_OT_bookmark_delete";
1211
1212 /* API callbacks. */
1213 ot->exec = bookmark_delete_exec;
1214 /* Bookmarks are for file browsing only (not asset browsing). */
1216
1217 /* properties */
1218 prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
1220}
1221
1223
1224/* -------------------------------------------------------------------- */
1227
1229{
1230 ScrArea *area = CTX_wm_area(C);
1231 FSMenu *fsmenu = ED_fsmenu_get();
1232 FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
1233 int index;
1234 bool changed = false;
1235
1236 for (index = 0; fsme; fsme = fsme_next) {
1237 fsme_next = fsme->next;
1238
1239 if (!BLI_is_dir(fsme->path)) {
1241 changed = true;
1242 }
1243 else {
1244 index++;
1245 }
1246 }
1247
1248 if (changed) {
1251 }
1252
1253 return OPERATOR_FINISHED;
1254}
1255
1257{
1258 /* identifiers */
1259 ot->name = "Cleanup Bookmarks";
1260 ot->description = "Delete all invalid bookmarks";
1261 ot->idname = "FILE_OT_bookmark_cleanup";
1262
1263 /* API callbacks. */
1264 ot->exec = bookmark_cleanup_exec;
1265 /* Bookmarks are for file browsing only (not asset browsing). */
1267
1268 /* properties */
1269}
1270
1272
1273/* -------------------------------------------------------------------- */
1276
1277enum {
1282};
1283
1285{
1286 ScrArea *area = CTX_wm_area(C);
1287 SpaceFile *sfile = CTX_wm_space_file(C);
1288 FSMenu *fsmenu = ED_fsmenu_get();
1290 const FSMenuEntry *fsmentry_org = fsmentry;
1291
1292 const int direction = RNA_enum_get(op->ptr, "direction");
1293 const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1294 const int act_index = sfile->bookmarknr;
1295 int new_index;
1296
1297 if (totitems < 2) {
1298 return OPERATOR_CANCELLED;
1299 }
1300
1301 switch (direction) {
1303 new_index = 0;
1304 break;
1306 new_index = totitems - 1;
1307 break;
1310 default:
1311 new_index = (totitems + act_index + direction) % totitems;
1312 break;
1313 }
1314
1315 if (new_index == act_index) {
1316 return OPERATOR_CANCELLED;
1317 }
1318
1319 BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
1320 if (fsmentry != fsmentry_org) {
1322 }
1323
1324 /* Need to update active bookmark number. */
1325 sfile->bookmarknr = new_index;
1326
1328
1329 return OPERATOR_FINISHED;
1330}
1331
1333{
1334 SpaceFile *sfile = CTX_wm_space_file(C);
1335
1336 /* Bookmarks are for file browsing only (not asset browsing). */
1338 return false;
1339 }
1340
1341 return sfile->bookmarknr != -1;
1342}
1343
1345{
1346 static const EnumPropertyItem slot_move[] = {
1347 {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
1348 {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
1349 {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
1350 {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
1351 {0, nullptr, 0, nullptr, nullptr}};
1352
1353 /* identifiers */
1354 ot->name = "Move Bookmark";
1355 ot->idname = "FILE_OT_bookmark_move";
1356 ot->description = "Move the active bookmark up/down in the list";
1357
1358 /* API callbacks. */
1359 ot->exec = bookmark_move_exec;
1361
1362 /* flags */
1363 ot->flag = OPTYPE_REGISTER; /* No undo! */
1364
1365 RNA_def_enum(ot->srna,
1366 "direction",
1367 slot_move,
1368 0,
1369 "Direction",
1370 "Direction to move the active bookmark towards");
1371}
1372
1374
1375/* -------------------------------------------------------------------- */
1378
1380{
1381 ScrArea *area = CTX_wm_area(C);
1382 FSMenu *fsmenu = ED_fsmenu_get();
1383
1384 while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != nullptr) {
1386 }
1387
1389
1390 return OPERATOR_FINISHED;
1391}
1392
1394{
1395 /* identifiers */
1396 ot->name = "Reset Recent";
1397 ot->description = "Reset recent files";
1398 ot->idname = "FILE_OT_reset_recent";
1399
1400 /* API callbacks. */
1401 ot->exec = reset_recent_exec;
1402 /* File browsing only operator (not asset browsing). */
1404}
1405
1407
1408/* -------------------------------------------------------------------- */
1411
1412int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
1413{
1414 View2D *v2d = &region->v2d;
1416 int numfiles, origfile;
1417
1418 /* In case blender starts where the mouse is over a File browser,
1419 * this operator can be invoked when the `sfile` or `sfile->layout` isn't initialized yet. */
1420 if (sfile == nullptr || sfile->files == nullptr || sfile->layout == nullptr) {
1421 return 0;
1422 }
1423
1425 /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
1426 * what creates the params for the current browse mode. See #93508. */
1427 if (!params) {
1428 return false;
1429 }
1430 numfiles = filelist_files_ensure(sfile->files);
1431
1432 origfile = params->highlight_file;
1433
1434 mx -= region->winrct.xmin;
1435 my -= region->winrct.ymin;
1436
1437 if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
1438 float fx, fy;
1439 int highlight_file;
1440
1441 UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
1442
1443 highlight_file = ED_fileselect_layout_offset(
1444 sfile->layout, int(v2d->tot.xmin + fx), int(v2d->tot.ymax - fy));
1445
1446 if ((highlight_file >= 0) && (highlight_file < numfiles)) {
1447 params->highlight_file = highlight_file;
1448 }
1449 else {
1450 params->highlight_file = -1;
1451 }
1452 }
1453 else {
1454 params->highlight_file = -1;
1455 }
1456
1457 return (params->highlight_file != origfile);
1458}
1459
1461 wmOperator * /*op*/,
1462 const wmEvent *event)
1463{
1464 ARegion *region = CTX_wm_region(C);
1465 SpaceFile *sfile = CTX_wm_space_file(C);
1466
1467 if (!file_highlight_set(sfile, region, event->xy[0], event->xy[1])) {
1468 return OPERATOR_PASS_THROUGH;
1469 }
1470
1472
1473 return OPERATOR_PASS_THROUGH;
1474}
1475
1477{
1478 /* identifiers */
1479 ot->name = "Highlight File";
1480 ot->description = "Highlight selected file(s)";
1481 ot->idname = "FILE_OT_highlight";
1482
1483 /* API callbacks. */
1484 ot->invoke = file_highlight_invoke;
1485 /* Operator works for file or asset browsing */
1487}
1488
1490
1491/* -------------------------------------------------------------------- */
1494
1496 wmOperator * /*op*/,
1497 const wmEvent *event)
1498{
1499 const ARegion *region = CTX_wm_region(C);
1500 SpaceFile *sfile = CTX_wm_space_file(C);
1501
1503 &region->v2d, sfile->layout, event->mval[0], event->mval[1]))
1504 {
1507 &region->v2d, params, sfile->layout, event->mval[0]);
1508
1509 if (column_type != COLUMN_NONE) {
1510 const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
1511
1513 if (params->sort == column->sort_type) {
1514 /* Already sorting by selected column -> toggle sort invert (three state logic). */
1515 params->flag ^= FILE_SORT_INVERT;
1516 }
1517 else {
1518 params->sort = column->sort_type;
1519 params->flag &= ~FILE_SORT_INVERT;
1520 }
1521
1523 }
1524 }
1525
1526 return OPERATOR_PASS_THROUGH;
1527}
1528
1530{
1531 /* identifiers */
1532 ot->name = "Sort from Column";
1533 ot->description = "Change sorting to use column under cursor";
1534 ot->idname = "FILE_OT_sort_column_ui_context";
1535
1536 /* API callbacks. */
1538 /* Operator works for file or asset browsing */
1540
1541 ot->flag = OPTYPE_INTERNAL;
1542}
1543
1545
1546/* -------------------------------------------------------------------- */
1549
1551{
1553 SpaceFile *sfile = CTX_wm_space_file(C);
1554
1555 if (!sfile || !sfile->op) {
1556 poll = false;
1557 }
1558
1559 return poll;
1560}
1561
1563{
1565 SpaceFile *sfile = CTX_wm_space_file(C);
1566 wmOperator *op = sfile->op;
1567
1568 sfile->op = nullptr;
1569
1571
1572 return OPERATOR_FINISHED;
1573}
1574
1576{
1577 /* identifiers */
1578 ot->name = "Cancel File Operation";
1579 ot->description = "Cancel file operation";
1580 ot->idname = "FILE_OT_cancel";
1581
1582 /* API callbacks. */
1583 ot->exec = file_cancel_exec;
1584 ot->poll = file_operator_poll;
1585}
1586
1588
1589/* -------------------------------------------------------------------- */
1592
1594 bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
1595{
1597 PropertyRNA *prop;
1598
1599 /* XXX, not real length */
1600 if (params->file[0]) {
1601 BLI_path_join(filepath, FILE_MAX, params->dir, params->file);
1602 }
1603 else {
1604 BLI_strncpy(filepath, params->dir, FILE_MAX);
1606 }
1607
1608 if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
1609 if (RNA_property_boolean_get(op->ptr, prop)) {
1610 BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
1611 }
1612 }
1613
1614 char value[FILE_MAX];
1615 if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1616 RNA_property_string_get(op->ptr, prop, value);
1617 RNA_property_string_set(op->ptr, prop, params->file);
1618 if (RNA_property_update_check(prop) && !STREQ(params->file, value)) {
1619 RNA_property_update(C, op->ptr, prop);
1620 }
1621 }
1622 if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1623 RNA_property_string_get(op->ptr, prop, value);
1624 RNA_property_string_set(op->ptr, prop, params->dir);
1625 if (RNA_property_update_check(prop) && !STREQ(params->dir, value)) {
1626 RNA_property_update(C, op->ptr, prop);
1627 }
1628 }
1629 if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1630 RNA_property_string_get(op->ptr, prop, value);
1631 RNA_property_string_set(op->ptr, prop, filepath);
1632 if (RNA_property_update_check(prop) && !STREQ(filepath, value)) {
1633 RNA_property_update(C, op->ptr, prop);
1634 }
1635 }
1636
1637 /* some ops have multiple files to select */
1638 /* this is called on operators check() so clear collections first since
1639 * they may be already set. */
1640 {
1641 int i, numfiles = filelist_files_ensure(sfile->files);
1642
1643 if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
1644 PointerRNA itemptr;
1645 int num_files = 0;
1647 for (i = 0; i < numfiles; i++) {
1649 FileDirEntry *file = filelist_file(sfile->files, i);
1650 /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
1651 if (!file->redirection_path) {
1652 RNA_property_collection_add(op->ptr, prop, &itemptr);
1653 RNA_string_set(&itemptr, "name", file->relpath);
1654 num_files++;
1655 }
1656 }
1657 }
1658 /* make sure the file specified in the filename button is added even if no
1659 * files selected */
1660 if (0 == num_files) {
1661 RNA_property_collection_add(op->ptr, prop, &itemptr);
1662 RNA_string_set(&itemptr, "name", params->file);
1663 }
1664 }
1665
1666 if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
1667 PointerRNA itemptr;
1668 int num_dirs = 0;
1670 for (i = 0; i < numfiles; i++) {
1672 FileDirEntry *file = filelist_file(sfile->files, i);
1673 RNA_property_collection_add(op->ptr, prop, &itemptr);
1674 RNA_string_set(&itemptr, "name", file->relpath);
1675 num_dirs++;
1676 }
1677 }
1678
1679 /* make sure the directory specified in the button is added even if no
1680 * directory selected */
1681 if (0 == num_dirs) {
1682 RNA_property_collection_add(op->ptr, prop, &itemptr);
1683 RNA_string_set(&itemptr, "name", params->dir);
1684 }
1685 }
1686 }
1687}
1689{
1690 char filepath_dummy[FILE_MAX];
1691
1692 file_sfile_to_operator_ex(C, bmain, op, sfile, filepath_dummy);
1693}
1694
1696{
1698 PropertyRNA *prop;
1699
1700 /* If neither of the above are set, split the filepath back */
1701 if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1702 char filepath[FILE_MAX];
1703 RNA_property_string_get(op->ptr, prop, filepath);
1705 filepath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
1706 }
1707 else {
1708 if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1709 RNA_property_string_get(op->ptr, prop, params->file);
1710 }
1711 if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1712 RNA_property_string_get(op->ptr, prop, params->dir);
1713 }
1714 }
1715
1716 /* we could check for relative_path property which is used when converting
1717 * in the other direction but doesn't hurt to do this every time */
1719
1720 /* XXX, files and dirs updates missing, not really so important though */
1721}
1722
1723void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
1724{
1726 BLI_assert(BLI_exists(filepath));
1727
1728 if (BLI_is_dir(filepath)) {
1729 STRNCPY(params->dir, filepath);
1730 }
1731 else {
1732 if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
1734 filepath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
1735 }
1736 else {
1737 BLI_path_split_dir_part(filepath, params->dir, sizeof(params->dir));
1738 }
1739 }
1740}
1741
1743{
1744 /* May happen when manipulating non-active spaces. */
1745 if (UNLIKELY(area->spacetype != SPACE_FILE)) {
1746 return;
1747 }
1748 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1749 wmOperator *op = sfile->op;
1750 if (op) { /* fail on reload */
1751 if (op->type->check) {
1752 Main *bmain = CTX_data_main(C);
1753 file_sfile_to_operator(C, bmain, op, sfile);
1754
1755 /* redraw */
1756 if (op->type->check(C, op)) {
1757 file_operator_to_sfile(bmain, sfile, op);
1758
1759 /* redraw, else the changed settings won't get updated */
1760 ED_area_tag_redraw(area);
1761 }
1762 }
1763 }
1764}
1765
1767{
1768 ScrArea *area = CTX_wm_area(C);
1769 file_draw_check_ex(C, area);
1770}
1771
1772void file_draw_check_cb(bContext *C, void * /*arg1*/, void * /*arg2*/)
1773{
1775}
1776
1778{
1779 if (sfile->op) { /* fails on reload */
1781 if (params && (params->flag & FILE_CHECK_EXISTING)) {
1782 char filepath[FILE_MAX];
1783 BLI_path_join(filepath, sizeof(filepath), params->dir, params->file);
1784 if (BLI_is_file(filepath)) {
1785 return true;
1786 }
1787 }
1788 }
1789
1790 return false;
1791}
1792
1794
1795/* -------------------------------------------------------------------- */
1798
1800 {FILE_EXTERNAL_OPERATION_OPEN, "OPEN", 0, "Open", "Open the file"},
1801 {FILE_EXTERNAL_OPERATION_FOLDER_OPEN, "FOLDER_OPEN", 0, "Open Folder", "Open the folder"},
1802 {FILE_EXTERNAL_OPERATION_EDIT, "EDIT", 0, "Edit", "Edit the file"},
1803 {FILE_EXTERNAL_OPERATION_NEW, "NEW", 0, "New", "Create a new file of this type"},
1804 {FILE_EXTERNAL_OPERATION_FIND, "FIND", 0, "Find File", "Search for files of this type"},
1805 {FILE_EXTERNAL_OPERATION_SHOW, "SHOW", 0, "Show", "Show this file"},
1806 {FILE_EXTERNAL_OPERATION_PLAY, "PLAY", 0, "Play", "Play this file"},
1807 {FILE_EXTERNAL_OPERATION_BROWSE, "BROWSE", 0, "Browse", "Browse this file"},
1808 {FILE_EXTERNAL_OPERATION_PREVIEW, "PREVIEW", 0, "Preview", "Preview this file"},
1809 {FILE_EXTERNAL_OPERATION_PRINT, "PRINT", 0, "Print", "Print this file"},
1810 {FILE_EXTERNAL_OPERATION_INSTALL, "INSTALL", 0, "Install", "Install this file"},
1811 {FILE_EXTERNAL_OPERATION_RUNAS, "RUNAS", 0, "Run As User", "Run as specific user"},
1813 "PROPERTIES",
1814 0,
1815 "Properties",
1816 "Show OS Properties for this item"},
1818 "FOLDER_FIND",
1819 0,
1820 "Find in Folder",
1821 "Search for items in this folder"},
1823 "CMD",
1824 0,
1825 "Command Prompt Here",
1826 "Open a command prompt here"},
1827 {0, nullptr, 0, nullptr, nullptr}};
1828
1830{
1831 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
1832 char filepath[FILE_MAX];
1833 RNA_property_string_get(op->ptr, prop, filepath);
1834
1836
1837#ifdef WIN32
1839 "operation");
1840 if (BLI_file_external_operation_execute(filepath, operation)) {
1842 return OPERATOR_FINISHED;
1843 }
1844#else
1845 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1846 PointerRNA op_props;
1848 RNA_string_set(&op_props, "filepath", filepath);
1850 C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
1851 WM_operator_properties_free(&op_props);
1852
1853 if (retval == OPERATOR_FINISHED) {
1855 return OPERATOR_FINISHED;
1856 }
1857#endif
1858
1860 op->reports, RPT_ERROR, "Failure to perform external file operation on \"%s\"", filepath);
1862 return OPERATOR_CANCELLED;
1863}
1864
1866 wmOperatorType * /*ot*/,
1867 PointerRNA *ptr)
1868{
1869 const char *description = "";
1870 RNA_enum_description(file_external_operation, RNA_enum_get(ptr, "operation"), &description);
1871 return TIP_(description);
1872}
1873
1875{
1876 PropertyRNA *prop;
1877
1878 /* identifiers */
1879 ot->name = "External File Operation";
1880 ot->idname = "FILE_OT_external_operation";
1881 ot->description = "Perform external operation on a file or folder";
1882
1883 /* API callbacks. */
1886
1887 /* flags */
1888 ot->flag = OPTYPE_REGISTER; /* No undo! */
1889
1890 /* properties */
1891 prop = RNA_def_string(ot->srna, "filepath", nullptr, FILE_MAX, "File or folder path", "");
1894
1895 RNA_def_enum(ot->srna,
1896 "operation",
1899 "Operation",
1900 "Operation to perform on the file or path");
1901}
1902
1905 const char *path,
1906 FileExternalOperation operation)
1907{
1908#ifdef WIN32
1909 if (!BLI_file_external_operation_supported(path, operation)) {
1910 return;
1911 }
1912#else
1914 return;
1915 }
1916#endif
1917
1918 const char *title = "";
1919 RNA_enum_name(file_external_operation, operation, &title);
1920
1921 PointerRNA props_ptr = layout->op(
1922 ot, IFACE_(title), ICON_NONE, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE);
1923 RNA_string_set(&props_ptr, "filepath", path);
1924 if (operation) {
1925 RNA_enum_set(&props_ptr, "operation", operation);
1926 }
1927}
1928
1929static void file_os_operations_menu_draw(const bContext *C_const, Menu *menu)
1930{
1931 bContext *C = (bContext *)C_const;
1932
1933 /* File browsing only operator (not asset browsing). */
1935 return;
1936 }
1937
1938 SpaceFile *sfile = CTX_wm_space_file(C);
1940 if (!sfile || !params) {
1941 return;
1942 }
1943
1944 char dir[FILE_MAX_LIBEXTRA];
1945 if (filelist_islibrary(sfile->files, dir, nullptr)) {
1946 return;
1947 }
1948
1949 int numfiles = filelist_files_ensure(sfile->files);
1950 FileDirEntry *fileentry = nullptr;
1951 int num_selected = 0;
1952
1953 for (int i = 0; i < numfiles; i++) {
1955 fileentry = filelist_file(sfile->files, i);
1956 num_selected++;
1957 }
1958 }
1959
1960 if (!fileentry || num_selected > 1) {
1961 return;
1962 }
1963
1964 char path[FILE_MAX_LIBEXTRA];
1965 filelist_file_get_full_path(sfile->files, fileentry, path);
1966 const char *root = filelist_dir(sfile->files);
1967
1968 uiLayout *layout = menu->layout;
1970 wmOperatorType *ot = WM_operatortype_find("FILE_OT_external_operation", true);
1971
1972 if (fileentry->typeflag & FILE_TYPE_DIR) {
1976 }
1977 else {
1992 }
1993}
1994
1995static bool file_os_operations_menu_poll(const bContext *C_const, MenuType * /*mt*/)
1996{
1997 bContext *C = (bContext *)C_const;
1998
1999 /* File browsing only operator (not asset browsing). */
2001 return false;
2002 }
2003
2004 SpaceFile *sfile = CTX_wm_space_file(C);
2006
2007 if (sfile && params) {
2008 char dir[FILE_MAX_LIBEXTRA];
2009 if (filelist_islibrary(sfile->files, dir, nullptr)) {
2010 return false;
2011 }
2012
2013 int numfiles = filelist_files_ensure(sfile->files);
2014 int num_selected = 0;
2015 for (int i = 0; i < numfiles; i++) {
2017 num_selected++;
2018 }
2019 }
2020
2021 if (num_selected > 1) {
2022 CTX_wm_operator_poll_msg_set(C, "More than one item is selected");
2023 }
2024 else if (num_selected < 1) {
2025 CTX_wm_operator_poll_msg_set(C, "No items are selected");
2026 }
2027 else {
2028 return true;
2029 }
2030 }
2031
2032 return false;
2033}
2034
2036{
2037 MenuType *mt;
2038
2039 mt = MEM_callocN<MenuType>("spacetype file menu file operations");
2040 STRNCPY(mt->idname, "FILEBROWSER_MT_operations_menu");
2041 STRNCPY(mt->label, N_("External"));
2045 WM_menutype_add(mt);
2046}
2047
2049
2050/* -------------------------------------------------------------------- */
2053
2057static bool file_execute(bContext *C, SpaceFile *sfile)
2058{
2059 Main *bmain = CTX_data_main(C);
2061 FileDirEntry *file = filelist_file(sfile->files, params->active_file);
2062
2063 if (file && file->redirection_path) {
2064 /* redirection_path is an absolute path that takes precedence
2065 * over using params->dir + params->file. */
2067 params->dir,
2068 sizeof(params->dir),
2069 params->file,
2070 sizeof(params->file));
2071 /* Update relpath with redirected filename as well so that the alternative
2072 * combination of params->dir + relpath remains valid as well. */
2073 MEM_freeN(file->relpath);
2074 file->relpath = BLI_strdup(params->file);
2075 }
2076
2077 /* directory change */
2078 if (file && (file->typeflag & FILE_TYPE_DIR)) {
2079 if (!file->relpath) {
2080 return false;
2081 }
2082
2083 if (FILENAME_IS_PARENT(file->relpath)) {
2085 }
2086 else {
2089 BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath);
2090 }
2092 }
2093 /* Opening file, sends events now, so things get handled on window-queue level. */
2094 else if (sfile->op) {
2095 ScrArea *area = CTX_wm_area(C);
2096 FSMenu *fsmenu = ED_fsmenu_get();
2097 wmOperator *op = sfile->op;
2098 char filepath[FILE_MAX];
2099
2100 sfile->op = nullptr;
2101
2102 file_sfile_to_operator_ex(C, bmain, op, sfile, filepath);
2103
2104 if (BLI_exists(params->dir)) {
2105 fsmenu_insert_entry(fsmenu,
2107 params->dir,
2108 nullptr,
2109 ICON_FILE_FOLDER,
2111 }
2112
2114
2116 }
2117
2118 return true;
2119}
2120
2122{
2123 SpaceFile *sfile = CTX_wm_space_file(C);
2124
2125 if (!file_execute(C, sfile)) {
2126 return OPERATOR_CANCELLED;
2127 }
2128
2129 return OPERATOR_FINISHED;
2130}
2131
2133 wmOperatorType * /*ot*/,
2134 PointerRNA * /*ptr*/)
2135{
2136 SpaceFile *sfile = CTX_wm_space_file(C);
2137 if (sfile->op && sfile->op->type && sfile->op->type->description) {
2138 /* Return the description of the executed operator. Don't use get_description
2139 * as that will return file details for #WM_OT_open_mainfile. */
2140 return TIP_(sfile->op->type->description);
2141 }
2142 return {};
2143}
2144
2146{
2147 /* identifiers */
2148 ot->name = "Execute File Window";
2149 ot->description = "Execute selected file";
2150 ot->idname = "FILE_OT_execute";
2151 ot->get_description = file_execute_get_description;
2152
2153 /* API callbacks. */
2154 ot->exec = file_exec;
2155 /* Important since handler is on window level.
2156 *
2157 * Avoid using #file_operator_poll since this is also used for entering directories
2158 * which is used even when the file manager doesn't have an operator. */
2160}
2161
2166{
2168 if (file_select(C, &rect, FILE_SEL_ADD, false, false) == FILE_SELECT_NOTHING) {
2169 return false;
2170 }
2171
2172 return true;
2173}
2174
2176 wmOperator * /*op*/,
2177 const wmEvent *event)
2178{
2179 ARegion *region = CTX_wm_region(C);
2180 SpaceFile *sfile = CTX_wm_space_file(C);
2181
2183 sfile->layout, &region->v2d, event->mval[0], event->mval[1]))
2184 {
2186 }
2187
2188 /* Note that this isn't needed practically, because the keymap already activates the hovered item
2189 * on mouse-press. This execute operator is called afterwards on the double-click event then.
2190 * However relying on this would be fragile and could break with keymap changes, so better to
2191 * have this mouse-execute operator that makes sure once more that the hovered file is active. */
2192 if (!file_ensure_hovered_is_active(C, event)) {
2193 return OPERATOR_CANCELLED;
2194 }
2195
2196 if (!file_execute(C, sfile)) {
2197 return OPERATOR_CANCELLED;
2198 }
2199
2200 return OPERATOR_FINISHED;
2201}
2202
2204{
2205 /* identifiers */
2206 ot->name = "Execute File";
2207 ot->description =
2208 "Perform the current execute action for the file under the cursor (e.g. open the file)";
2209 ot->idname = "FILE_OT_mouse_execute";
2210
2211 /* API callbacks. */
2212 ot->invoke = file_execute_mouse_invoke;
2214
2215 ot->flag = OPTYPE_INTERNAL;
2216}
2217
2219
2220/* -------------------------------------------------------------------- */
2223
2225{
2227 SpaceFile *sfile = CTX_wm_space_file(C);
2228 FSMenu *fsmenu = ED_fsmenu_get();
2229
2230 ED_fileselect_clear(wm, sfile);
2231
2232 /* refresh system directory menu */
2234
2235 /* Update bookmarks 'valid' state. */
2237
2239
2240 return OPERATOR_FINISHED;
2241}
2242
2244{
2245 /* identifiers */
2246 ot->name = "Refresh File List";
2247 ot->description = "Refresh the file list";
2248 ot->idname = "FILE_OT_refresh";
2249
2250 /* API callbacks. */
2251 ot->exec = file_refresh_exec;
2252 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2253}
2254
2256
2257/* -------------------------------------------------------------------- */
2260
2262{
2263 Main *bmain = CTX_data_main(C);
2264 SpaceFile *sfile = CTX_wm_space_file(C);
2266
2267 if (params) {
2268 if (BLI_path_parent_dir(params->dir)) {
2270 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
2272 if (params->recursion_level > 1) {
2273 /* Disable `dirtree` recursion when going up in tree. */
2274 params->recursion_level = 0;
2275 filelist_setrecursion(sfile->files, params->recursion_level);
2276 }
2278 }
2279 }
2280
2281 return OPERATOR_FINISHED;
2282}
2283
2285{
2286 /* identifiers */
2287 ot->name = "Parent Directory";
2288 ot->description = "Move to parent directory";
2289 ot->idname = "FILE_OT_parent";
2290
2291 /* API callbacks. */
2292 ot->exec = file_parent_exec;
2293 /* File browsing only operator (not asset browsing). */
2294 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2295}
2296
2298
2299/* -------------------------------------------------------------------- */
2302
2304{
2305 SpaceFile *sfile = CTX_wm_space_file(C);
2307
2308 if (params) {
2312
2314 }
2316
2317 return OPERATOR_FINISHED;
2318}
2319
2321{
2322 /* identifiers */
2323 ot->name = "Previous Folder";
2324 ot->description = "Move to previous folder";
2325 ot->idname = "FILE_OT_previous";
2326
2327 /* API callbacks. */
2328 ot->exec = file_previous_exec;
2329 /* File browsing only operator (not asset browsing). */
2330 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2331}
2332
2334
2335/* -------------------------------------------------------------------- */
2338
2340{
2341 SpaceFile *sfile = CTX_wm_space_file(C);
2343 if (params) {
2346
2347 /* update folders_prev so we can check for it in #folderlist_clear_next() */
2349
2351 }
2353
2354 return OPERATOR_FINISHED;
2355}
2356
2358{
2359 /* identifiers */
2360 ot->name = "Next Folder";
2361 ot->description = "Move to next folder";
2362 ot->idname = "FILE_OT_next";
2363
2364 /* API callbacks. */
2365 ot->exec = file_next_exec;
2366 /* File browsing only operator (not asset browsing). */
2367 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2368}
2369
2371
2372/* -------------------------------------------------------------------- */
2375
2376/* only meant for timer usage */
2378 wmOperator * /*op*/,
2379 const wmEvent *event)
2380{
2381 ScrArea *area = CTX_wm_area(C);
2382 SpaceFile *sfile = CTX_wm_space_file(C);
2383 ARegion *region, *region_ctx = CTX_wm_region(C);
2384 const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
2385 int i;
2386
2387 /* escape if not our timer */
2388 if (sfile->smoothscroll_timer == nullptr || sfile->smoothscroll_timer != event->customdata) {
2389 return OPERATOR_PASS_THROUGH;
2390 }
2391
2392 const int numfiles = filelist_files_ensure(sfile->files);
2393
2394 /* Due to asynchronous nature of file listing, we may execute this code before `file_refresh()`
2395 * editing entry is available in our listing,
2396 * so we also have to handle switching to rename mode here. */
2398 if ((params->rename_flag &
2400 {
2402 }
2403
2404 /* check if we are editing a name */
2405 int edit_idx = -1;
2406 for (i = 0; i < numfiles; i++) {
2409 {
2410 edit_idx = i;
2411 break;
2412 }
2413 }
2414
2416 wmWindow *win = CTX_wm_window(C);
2417
2418 /* if we are not editing, we are done */
2419 if (edit_idx == -1) {
2420 /* Do not invalidate timer if file-rename is still pending,
2421 * we might still be building the filelist and yet have to find edited entry. */
2422 if (params->rename_flag == 0) {
2424 }
2425 return OPERATOR_PASS_THROUGH;
2426 }
2427
2428 /* we need the correct area for scrolling */
2430 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2432 return OPERATOR_PASS_THROUGH;
2433 }
2434
2435 /* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
2436 * in vertical layout).
2437 */
2438 const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
2439
2440 /* Scroll offset is the first file in the row/column we are editing in. */
2441 if (sfile->scroll_offset == 0) {
2442 sfile->scroll_offset = (edit_idx / items_block_size) * items_block_size;
2443 }
2444
2445 const int numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, region);
2446 const int first_visible_item = ED_fileselect_layout_offset(
2447 sfile->layout, int(region->v2d.cur.xmin), int(-region->v2d.cur.ymax));
2448 const int last_visible_item = first_visible_item + numfiles_layout + 1;
2449
2450 /* NOTE: the special case for vertical layout is because filename is at the bottom of items then,
2451 * so we artificially move current row back one step, to ensure we show bottom of
2452 * active item rather than its top (important in case visible height is low). */
2453 const int middle_offset = max_ii(
2454 0, (first_visible_item + last_visible_item) / 2 - (is_horizontal ? 0 : items_block_size));
2455
2456 const int min_middle_offset = numfiles_layout / 2;
2457 const int max_middle_offset = ((numfiles / items_block_size) * items_block_size +
2458 ((numfiles % items_block_size) != 0 ? items_block_size : 0)) -
2459 (numfiles_layout / 2);
2460 /* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the
2461 * beginning/end of the view. */
2462 /* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf...
2463 * that is why we still need to keep the min/max_middle_offset checks too. :( */
2464 const float min_tot_scroll = is_horizontal ? region->v2d.tot.xmin : -region->v2d.tot.ymax;
2465 const float max_tot_scroll = is_horizontal ? region->v2d.tot.xmax : -region->v2d.tot.ymin;
2466 const float min_curr_scroll = is_horizontal ? region->v2d.cur.xmin : -region->v2d.cur.ymax;
2467 const float max_curr_scroll = is_horizontal ? region->v2d.cur.xmax : -region->v2d.cur.ymin;
2468
2469 /* Check if we have reached our final scroll position. */
2470 /* File-list has to be ready, otherwise it makes no sense to stop scrolling yet. */
2471 const bool is_ready = filelist_is_ready(sfile->files);
2472 /* Edited item must be in the 'middle' of shown area (kind of approximated).
2473 * Note that we have to do the check in 'block space', not in 'item space' here. */
2474 const bool is_centered = (abs(middle_offset / items_block_size -
2475 sfile->scroll_offset / items_block_size) == 0);
2476 /* OR edited item must be towards the beginning, and we are scrolled fully to the start. */
2477 const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) &&
2478 (min_curr_scroll - min_tot_scroll < 1.0f) &&
2479 (middle_offset - min_middle_offset < items_block_size));
2480 /* OR edited item must be towards the end, and we are scrolled fully to the end.
2481 * This one is crucial (unlike the one for the beginning), because without it we won't scroll
2482 * fully to the end, and last column or row will end up only partially drawn. */
2483 const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) &&
2484 (max_tot_scroll - max_curr_scroll < 1.0f) &&
2485 (max_middle_offset - middle_offset < items_block_size));
2486
2487 if (is_ready && (is_centered || is_full_start || is_full_end)) {
2489 /* Post-scroll (after rename has been validated by user) is done,
2490 * rename process is totally finished, cleanup. */
2491 if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) {
2493 }
2494 return OPERATOR_FINISHED;
2495 }
2496
2497 /* Temporarily set context to the main window region,
2498 * so that the pan operator works. */
2499 CTX_wm_region_set(C, region);
2500
2501 /* scroll one step in the desired direction */
2502 PointerRNA op_ptr;
2503 int deltax = 0;
2504 int deltay = 0;
2505
2506 /* We adjust speed of scrolling to avoid tens of seconds of it in e.g. directories with tens of
2507 * thousands of folders... See #65782. */
2508 /* This will slow down scrolling when approaching final goal, also avoids going too far and
2509 * having to bounce back... */
2510
2511 /* Number of blocks (columns in horizontal layout, rows otherwise) between current middle of
2512 * screen, and final goal position. */
2513 const int diff_offset = sfile->scroll_offset / items_block_size -
2514 middle_offset / items_block_size;
2515 /* convert diff_offset into pixels. */
2516 const int diff_offset_delta = abs(diff_offset) *
2517 (is_horizontal ?
2518 sfile->layout->tile_w + 2 * sfile->layout->tile_border_x :
2519 sfile->layout->tile_h + 2 * sfile->layout->tile_border_y);
2520 const int scroll_delta = max_ii(2, diff_offset_delta / 15);
2521
2522 if (diff_offset < 0) {
2523 if (is_horizontal) {
2524 deltax = -scroll_delta;
2525 }
2526 else {
2527 deltay = scroll_delta;
2528 }
2529 }
2530 else {
2531 if (is_horizontal) {
2532 deltax = scroll_delta;
2533 }
2534 else {
2535 deltay = -scroll_delta;
2536 }
2537 }
2538 WM_operator_properties_create(&op_ptr, "VIEW2D_OT_pan");
2539 RNA_int_set(&op_ptr, "deltax", deltax);
2540 RNA_int_set(&op_ptr, "deltay", deltay);
2541
2542 WM_operator_name_call(C, "VIEW2D_OT_pan", WM_OP_EXEC_DEFAULT, &op_ptr, event);
2544
2545 ED_region_tag_redraw(region);
2546
2547 /* and restore context */
2548 CTX_wm_region_set(C, region_ctx);
2549
2550 return OPERATOR_FINISHED;
2551}
2552
2554{
2555 /* identifiers */
2556 ot->name = "Smooth Scroll";
2557 ot->idname = "FILE_OT_smoothscroll";
2558 ot->description = "Smooth scroll to make editable file visible";
2559
2560 /* API callbacks. */
2561 ot->invoke = file_smoothscroll_invoke;
2562 /* Operator works for file or asset browsing */
2564}
2565
2567
2568/* -------------------------------------------------------------------- */
2571
2573{
2574 Main *bmain = CTX_data_main(C);
2575 SpaceFile *sfile = CTX_wm_space_file(C);
2576
2577 if (sfile) {
2578 char filepath[FILE_MAX];
2579
2580 RNA_string_get(op->ptr, "filepath", filepath);
2581 if (!BLI_exists(filepath)) {
2582 BKE_report(op->reports, RPT_ERROR, "File does not exist");
2583 return OPERATOR_CANCELLED;
2584 }
2585
2586 file_sfile_filepath_set(sfile, filepath);
2587
2588 if (sfile->op) {
2589 file_sfile_to_operator(C, bmain, sfile->op, sfile);
2591 }
2592
2594 return OPERATOR_FINISHED;
2595 }
2596
2597 return OPERATOR_CANCELLED;
2598}
2599
2601{
2602 ot->name = "File Selector Drop";
2603 ot->idname = "FILE_OT_filepath_drop";
2604
2605 ot->exec = filepath_drop_exec;
2606 /* File browsing only operator (not asset browsing). */
2608
2609 RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", "");
2610}
2611
2613
2614/* -------------------------------------------------------------------- */
2617
2624static bool new_folder_path(const char *parent,
2625 char r_dirpath_full[FILE_MAX],
2626 char r_dirname[FILE_MAXFILE])
2627{
2628 int i = 1;
2629 int len = 0;
2630
2631 BLI_strncpy(r_dirname, "New Folder", FILE_MAXFILE);
2632 BLI_path_join(r_dirpath_full, FILE_MAX, parent, r_dirname);
2633 /* check whether r_dirpath_full with the name already exists, in this case
2634 * add number to the name. Check length of generated name to avoid
2635 * crazy case of huge number of folders each named 'New Folder (x)' */
2636 while (BLI_exists(r_dirpath_full) && (len < FILE_MAXFILE)) {
2637 len = BLI_snprintf(r_dirname, FILE_MAXFILE, "New Folder(%d)", i);
2638 BLI_path_join(r_dirpath_full, FILE_MAX, parent, r_dirname);
2639 i++;
2640 }
2641
2642 return (len < FILE_MAXFILE);
2643}
2644
2646{
2647 char dirname[FILE_MAXFILE];
2648 char dirpath[FILE_MAX];
2649 bool generate_name = true;
2650
2652 SpaceFile *sfile = CTX_wm_space_file(C);
2654 const bool do_diropen = RNA_boolean_get(op->ptr, "open");
2655
2656 if (!params) {
2657 BKE_report(op->reports, RPT_WARNING, "No parent directory given");
2658 return OPERATOR_CANCELLED;
2659 }
2660
2661 dirpath[0] = '\0';
2662
2663 {
2664 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "directory");
2665 RNA_property_string_get(op->ptr, prop, dirpath);
2666 if (dirpath[0] != '\0') {
2667 generate_name = false;
2668 }
2669 }
2670
2671 if (generate_name) {
2672 /* create a new, non-existing folder name */
2673 if (!new_folder_path(params->dir, dirpath, dirname)) {
2674 BKE_report(op->reports, RPT_ERROR, "Could not create new folder name");
2675 return OPERATOR_CANCELLED;
2676 }
2677 }
2678 else { /* We assume we are able to generate a valid name! */
2679 char org_path[FILE_MAX];
2680
2681 STRNCPY(org_path, dirpath);
2682 if (BLI_path_make_safe(dirpath)) {
2683 BKE_reportf(op->reports,
2685 "'%s' given path is OS-invalid, creating '%s' path instead",
2686 org_path,
2687 dirpath);
2688 }
2689 }
2690
2691 /* create the file */
2692 errno = 0;
2693 if (!BLI_dir_create_recursive(dirpath) ||
2694 /* Should no more be needed,
2695 * now that BLI_dir_create_recursive returns a success state - but kept just in case. */
2696 !BLI_exists(dirpath))
2697 {
2698 BKE_reportf(op->reports,
2699 RPT_ERROR,
2700 "Could not create new folder: %s",
2701 errno ? strerror(errno) : "unknown error");
2702 return OPERATOR_CANCELLED;
2703 }
2704
2706
2707 /* If we don't enter the directory directly, remember file to jump into editing. */
2708 if (do_diropen == false) {
2709 BLI_assert_msg(params->rename_id == nullptr,
2710 "File rename handling should immediately clear rename_id when done, "
2711 "because otherwise it will keep taking precedence over renamefile.");
2712 STRNCPY(params->renamefile, dirname);
2713 rename_flag = FILE_PARAMS_RENAME_PENDING;
2714 }
2715
2717 params->rename_flag = rename_flag;
2718
2719 /* reload dir to make sure we're seeing what's in the directory */
2720 ED_fileselect_clear(wm, sfile);
2721
2722 if (do_diropen) {
2723 STRNCPY(params->dir, dirpath);
2725 }
2726
2728
2729 return OPERATOR_FINISHED;
2730}
2731
2733 wmOperator *op,
2734 const wmEvent * /*event*/)
2735{
2736 /* NOTE: confirm is needed because this operator is invoked
2737 * when entering a path from the file selector. Without a confirmation,
2738 * a typo will create the path without any prompt. See #128567. */
2739 if (RNA_boolean_get(op->ptr, "confirm")) {
2741 C, op, IFACE_("Create new directory?"), nullptr, IFACE_("Create"), ALERT_ICON_NONE, false);
2742 }
2743 return file_directory_new_exec(C, op);
2744}
2745
2747{
2748 PropertyRNA *prop;
2749
2750 /* identifiers */
2751 ot->name = "Create New Directory";
2752 ot->description = "Create a new directory";
2753 ot->idname = "FILE_OT_directory_new";
2754
2755 /* API callbacks. */
2756 ot->invoke = file_directory_new_invoke;
2758 /* File browsing only operator (not asset browsing). */
2759 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2760
2762 ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Name of new directory");
2764 prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
2767}
2768
2770
2771/* -------------------------------------------------------------------- */
2774
2776{
2777 /* NOTE: Arbitrary conventions are used here which are OK for user facing logic
2778 * Attempting to resolve the path to *something* valid is OK for user input
2779 * but not suitable for `BLI_path_utils.hh` which is used for lower level path handling. */
2780
2781 /* The path was invalid, fall back to the default root. */
2782 bool do_reset = false;
2783
2784 if (params->dir[0] == '\0') {
2785 do_reset = true;
2786 }
2787 else if (BLI_path_is_rel(params->dir)) { /* `//` literal. */
2788 const char *blendfile_path = BKE_main_blendfile_path(bmain);
2789 if (blendfile_path[0] != '\0') {
2790 BLI_path_abs(params->dir, blendfile_path);
2791 }
2792 else {
2793 /* Ignore relative paths for unsaved files.
2794 * It's enough of a corner case that any attempt to resolve the path
2795 * is more likely to confuse users about the meaning of `//`. */
2796 do_reset = true;
2797 }
2798 }
2799 else if (params->dir[0] == '~') {
2800 /* While path handling expansion typically doesn't support home directory expansion
2801 * in Blender, this is a convenience to be able to type in a single character.
2802 * Even though this is a UNIX convention, it's harmless to expand on WIN32 as well. */
2803 if (const char *home_dir = BLI_dir_home()) {
2804 char tmpstr[sizeof(params->dir) - 1];
2805 STRNCPY(tmpstr, params->dir + 1);
2806 BLI_path_join(params->dir, sizeof(params->dir), home_dir, tmpstr);
2807 }
2808 else {
2809 do_reset = true;
2810 }
2811 }
2812#ifdef WIN32
2813 else if (BLI_path_is_win32_drive_only(params->dir)) {
2814 /* Change `C:` --> `C:\`, see: #28102. */
2815 params->dir[2] = SEP;
2816 params->dir[3] = '\0';
2817 }
2818 else if (BLI_path_is_unc(params->dir)) {
2819 BLI_path_normalize_unc(params->dir, sizeof(params->dir));
2820 }
2821#endif /* WIN32 */
2822
2823 if (do_reset) {
2825 }
2826}
2827
2833{
2834 /* NOTE(@ideasman42): This function checks if the user should be prompted
2835 * to create the path when a non-existent path is entered into the directory field.
2836 *
2837 * Typically when the intention is to create a path, it's simply created only showing
2838 * feedback if the operation failed. In the case of entering a path as text any typo
2839 * in the would immediately be created (if possible) which isn't good, see: #128567.
2840 *
2841 * The reason to treat user input differently here is the user could input anything,
2842 * e.g. values such as a single space. This resolves to the current-working-directory:
2843 * `$PWD/ ` which is a valid path name and could be created
2844 * (this was in fact the behavior until v4.4).
2845 *
2846 * As this can be error prone, performs basic sanity checks on `dir`.
2847 * - Ensure it's an absolute path.
2848 * - It contains a writable parent path.
2849 * - For WIN32: The UNC path is a directory and not a "share".
2850 *
2851 * While these checks don't need to be comprehensive,
2852 * they should prevent accidents and confusing situations. */
2853
2854 /* If the user types in a name with no absolute prefix,
2855 * creating a directory relative to the CWD doesn't make sense from the UI. */
2856 if (!BLI_path_is_abs_from_cwd(dir)) {
2857 return false;
2858 }
2859
2860 /* If none of the parents exist, the directory can't be created.
2861 * This prevents the popup to create a new path showing on WIN32
2862 * for a drive-letter that doesn't exist (for example). */
2863 {
2864 char tdir[FILE_MAX_LIBEXTRA];
2865 STRNCPY(tdir, dir);
2867 return false;
2868 }
2869 }
2870
2871#if defined(WIN32)
2872 /* For UNC paths we need to check whether the parent of the new
2873 * directory is a proper directory itself and not a share or the
2874 * UNC root (server name) itself. Calling #BLI_is_dir does this. */
2875 if (BLI_path_is_unc(dir)) {
2876 char tdir[FILE_MAX_LIBEXTRA];
2877 STRNCPY(tdir, dir);
2878 BLI_path_parent_dir(tdir);
2879 if (!BLI_is_dir(tdir)) {
2880 return false;
2881 }
2882 }
2883#endif /* WIN32 */
2884
2885 return true;
2886}
2887
2888void file_directory_enter_handle(bContext *C, void * /*arg_unused*/, void * /*arg_but*/)
2889{
2890 SpaceFile *sfile = CTX_wm_space_file(C);
2892 if (UNLIKELY(params == nullptr)) {
2893 return;
2894 }
2895
2896 const Main *bmain = CTX_data_main(C);
2897 char old_dir[sizeof(params->dir)];
2898
2899 STRNCPY(old_dir, params->dir);
2900
2902
2903 /* Special case, user may have pasted a path including a file-name into the directory. */
2904 if (!filelist_is_dir(sfile->files, params->dir)) {
2905 char tdir[FILE_MAX_LIBEXTRA];
2906 char *group, *name;
2907
2908 if (BLI_is_file(params->dir)) {
2909 char dirpath[sizeof(params->dir)];
2910 STRNCPY(dirpath, params->dir);
2912 dirpath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
2913 }
2914 else if (BKE_blendfile_library_path_explode(params->dir, tdir, &group, &name)) {
2915 if (group) {
2916 BLI_path_append(tdir, sizeof(tdir), group);
2917 }
2918 STRNCPY(params->dir, tdir);
2919 if (name) {
2920 STRNCPY(params->file, name);
2921 }
2922 else {
2923 params->file[0] = '\0';
2924 }
2925 }
2926 }
2927
2928 /* #file_expand_directory will have made absolute. */
2930 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
2931
2932 if (filelist_is_dir(sfile->files, params->dir)) {
2933 /* Avoids flickering when nothing's changed. */
2934 if (!STREQ(params->dir, old_dir)) {
2935 /* If directory exists, enter it immediately. */
2937 }
2938 }
2939 else if (!can_create_dir_from_user_input(params->dir)) {
2940 const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2941 if (lastdir) {
2942 STRNCPY(params->dir, lastdir);
2943 }
2944 }
2945 else {
2946 const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2947 char tdir[FILE_MAX_LIBEXTRA];
2948
2949 /* If we are "inside" a `.blend` library, we cannot do anything. */
2950 if (lastdir && BKE_blendfile_library_path_explode(lastdir, tdir, nullptr, nullptr)) {
2951 STRNCPY(params->dir, lastdir);
2952 }
2953 else {
2954 /* If not, ask to create it and enter if confirmed. */
2955 wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
2958 RNA_string_set(&ptr, "directory", params->dir);
2959 RNA_boolean_set(&ptr, "open", true);
2960 /* Enable confirmation prompt, else it's too easy to accidentally create new directories. */
2961 RNA_boolean_set(&ptr, "confirm", true);
2962
2963 if (lastdir) {
2964 STRNCPY(params->dir, lastdir);
2965 }
2966
2969 }
2970 }
2971
2973}
2974
2975void file_filename_enter_handle(bContext *C, void * /*arg_unused*/, void *arg_but)
2976{
2977 SpaceFile *sfile = CTX_wm_space_file(C);
2979 if (UNLIKELY(params == nullptr)) {
2980 return;
2981 }
2982
2983 const Main *bmain = CTX_data_main(C);
2984 uiBut *but = static_cast<uiBut *>(arg_but);
2985
2987
2988 char matched_file[FILE_MAX] = "";
2989 int matches = file_select_match(sfile, params->file, matched_file);
2990
2991 /* It's important this runs *after* #file_select_match,
2992 * so making "safe" doesn't remove shell-style globing characters. */
2993 const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
2994 BLI_path_make_safe_filename_ex(params->file, allow_tokens);
2995
2996 if (matches) {
2997 /* Replace the pattern (or filename that the user typed in,
2998 * with the first selected file of the match. */
2999 STRNCPY(params->file, matched_file);
3000
3002
3003 if (matches == 1) {
3004 char filepath[sizeof(params->dir)];
3005 BLI_path_join(filepath, sizeof(params->dir), params->dir, params->file);
3006
3007 /* If directory, open it and empty filename field. */
3008 if (filelist_is_dir(sfile->files, filepath)) {
3009 BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
3010 BLI_path_normalize_dir(filepath, sizeof(filepath));
3011 STRNCPY(params->dir, filepath);
3012 params->file[0] = '\0';
3016 }
3017 }
3018 else {
3019 BLI_assert(matches > 1);
3021 }
3022 }
3023}
3024
3026
3027/* -------------------------------------------------------------------- */
3030
3032{
3034 SpaceFile *sfile = CTX_wm_space_file(C);
3036
3037 if (params) {
3038 params->flag ^= FILE_HIDE_DOT;
3039 ED_fileselect_clear(wm, sfile);
3041 }
3042
3043 return OPERATOR_FINISHED;
3044}
3045
3047{
3048 /* identifiers */
3049 ot->name = "Toggle Hide Dot Files";
3050 ot->description = "Toggle hide hidden dot files";
3051 ot->idname = "FILE_OT_hidedot";
3052
3053 /* API callbacks. */
3054 ot->exec = file_hidedot_exec;
3055 /* File browsing only operator (not asset browsing). */
3056 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
3057}
3058
3060
3061/* -------------------------------------------------------------------- */
3064
3066{
3067 SpaceFile *sfile = CTX_wm_space_file(C);
3068
3069 /* File browsing only operator (not asset browsing). */
3071 return false;
3072 }
3073
3075 return params && (params->flag & FILE_CHECK_EXISTING);
3076}
3077
3082static void filenum_newname(char *filename, size_t filename_maxncpy, int add)
3083{
3084 char head[FILE_MAXFILE], tail[FILE_MAXFILE];
3085 int pic;
3086 ushort digits;
3087
3088 pic = BLI_path_sequence_decode(filename, head, sizeof(head), tail, sizeof(tail), &digits);
3089
3090 /* are we going from 100 -> 99 or from 10 -> 9 */
3091 if (add < 0 && digits > 0) {
3092 int i, exp;
3093 exp = 1;
3094 for (i = digits; i > 1; i--) {
3095 exp *= 10;
3096 }
3097 if (pic >= exp && (pic + add) < exp) {
3098 digits--;
3099 }
3100 }
3101
3102 pic += add;
3103 pic = std::max(pic, 0);
3104 BLI_path_sequence_encode(filename, filename_maxncpy, head, tail, digits, pic);
3105}
3106
3108{
3109 SpaceFile *sfile = CTX_wm_space_file(C);
3111 ScrArea *area = CTX_wm_area(C);
3112
3113 int inc = RNA_int_get(op->ptr, "increment");
3114 if (params && (inc != 0)) {
3115 filenum_newname(params->file, sizeof(params->file), inc);
3116 ED_area_tag_redraw(area);
3118 // WM_event_add_notifier(C, NC_WINDOW, nullptr);
3119 }
3120
3121 return OPERATOR_FINISHED;
3122}
3123
3125{
3126 /* identifiers */
3127 ot->name = "Increment Number in Filename";
3128 ot->description = "Increment number in filename";
3129 ot->idname = "FILE_OT_filenum";
3130
3131 /* API callbacks. */
3132 ot->exec = file_filenum_exec;
3133 ot->poll = file_filenum_poll;
3134
3135 /* props */
3136 RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
3137}
3138
3140
3141/* -------------------------------------------------------------------- */
3144
3145static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
3146{
3147 const int numfiles = filelist_files_ensure(sfile->files);
3148
3149 if ((file_idx >= 0) && (file_idx < numfiles)) {
3150 FileDirEntry *file = filelist_file(sfile->files, file_idx);
3151
3152 if ((require_selected == false) ||
3154 {
3156
3158 sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
3159 STRNCPY(params->renamefile, file->relpath);
3160 /* We can skip the pending state,
3161 * as we can directly set FILE_SEL_EDITING on the expected entry here. */
3162 params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
3163 }
3164 }
3165}
3166
3168{
3169 ScrArea *area = CTX_wm_area(C);
3172
3173 if (params) {
3174 file_rename_state_activate(sfile, params->active_file, false);
3175 ED_area_tag_redraw(area);
3176 }
3177
3178 return OPERATOR_FINISHED;
3179}
3180
3182{
3183 /* identifiers */
3184 ot->name = "Rename File or Directory";
3185 ot->description = "Rename file or file directory";
3186 ot->idname = "FILE_OT_rename";
3187
3188 /* API callbacks. */
3189 ot->exec = file_rename_exec;
3190 /* File browsing only operator (not asset browsing). */
3192}
3193
3195
3196/* -------------------------------------------------------------------- */
3199
3201{
3203 return false;
3204 }
3205
3206 SpaceFile *sfile = CTX_wm_space_file(C);
3208 if (!sfile || !params) {
3209 return false;
3210 }
3211
3212 char dir[FILE_MAX_LIBEXTRA];
3213 if (filelist_islibrary(sfile->files, dir, nullptr)) {
3214 return false;
3215 }
3216
3217 int numfiles = filelist_files_ensure(sfile->files);
3218 for (int i = 0; i < numfiles; i++) {
3220 /* Has a selected file -> the operator can run. */
3221 return true;
3222 }
3223 }
3224
3225 return false;
3226}
3227
3228static bool file_delete_single(const FileList *files,
3229 FileDirEntry *file,
3230 const char **r_error_message)
3231{
3232 char filepath[FILE_MAX_LIBEXTRA];
3233 filelist_file_get_full_path(files, file, filepath);
3234 if (BLI_delete_soft(filepath, r_error_message) != 0 || BLI_exists(filepath)) {
3235 return false;
3236 }
3237
3238 return true;
3239}
3240
3242{
3244 SpaceFile *sfile = CTX_wm_space_file(C);
3245 int numfiles = filelist_files_ensure(sfile->files);
3246
3247 const char *error_message = nullptr;
3248 bool report_error = false;
3249 errno = 0;
3250 for (int i = 0; i < numfiles; i++) {
3252 FileDirEntry *file = filelist_file(sfile->files, i);
3253 if (!file_delete_single(sfile->files, file, &error_message)) {
3254 report_error = true;
3255 }
3256 }
3257 }
3258
3259 if (report_error) {
3260 const char *error_prefix = "Could not delete file or directory: ";
3261 const char *errno_message = errno ? strerror(errno) : "unknown error";
3262 if (error_message != nullptr) {
3263 BKE_reportf(op->reports, RPT_ERROR, "%s%s, %s", error_prefix, error_message, errno_message);
3264 }
3265 else {
3266 BKE_reportf(op->reports, RPT_ERROR, "%s%s", error_prefix, errno_message);
3267 }
3268 }
3269
3270 ED_fileselect_clear(wm, sfile);
3272
3273 return OPERATOR_FINISHED;
3274}
3275
3277{
3279 C, op, IFACE_("Delete selected files?"), nullptr, IFACE_("Delete"), ALERT_ICON_NONE, false);
3280}
3281
3283{
3284 /* identifiers */
3285 ot->name = "Delete Selected Files";
3286 ot->description = "Move selected files to the trash or recycle bin";
3287 ot->idname = "FILE_OT_delete";
3288
3289 /* API callbacks. */
3290 ot->invoke = file_delete_invoke;
3291 ot->exec = file_delete_exec;
3292 ot->poll = file_delete_poll; /* <- important, handler is on window level */
3293}
3294
3296
3297/* -------------------------------------------------------------------- */
3300
3302{
3303 const ScrArea *area = CTX_wm_area(C);
3304 const SpaceFile *sfile = CTX_wm_space_file(C);
3306
3307 if (area) {
3308 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3309 if (UI_textbutton_activate_rna(C, region, params, "filter_search")) {
3310 break;
3311 }
3312 }
3313 }
3314
3315 return OPERATOR_FINISHED;
3316}
3317
3319{
3320 /* identifiers */
3321 ot->name = "Filter";
3322 ot->description = "Start entering filter text";
3323 ot->idname = "FILE_OT_start_filter";
3324
3325 /* API callbacks. */
3326 ot->exec = file_start_filter_exec;
3327 /* Operator works for file or asset browsing */
3329}
3330
3332
3333/* -------------------------------------------------------------------- */
3336
3338{
3339 const ScrArea *area = CTX_wm_area(C);
3340 const SpaceFile *sfile = CTX_wm_space_file(C);
3342
3343 if (area) {
3344 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3345 if (UI_textbutton_activate_rna(C, region, params, "directory")) {
3346 break;
3347 }
3348 }
3349 }
3350
3351 return OPERATOR_FINISHED;
3352}
3353
3355{
3356 /* identifiers */
3357 ot->name = "Edit Directory Path";
3358 ot->description = "Start editing directory field";
3359 ot->idname = "FILE_OT_edit_directory_path";
3360
3361 /* API callbacks. */
3364}
3365
3367
3368/* -------------------------------------------------------------------- */
3371
3373{
3374 // wmOperatorType *ot;
3375 // wmOperatorTypeMacro *otmacro;
3376
3377 /* future macros */
3378}
3379
@ BLENDER_USER_CONFIG
#define BLENDER_BOOKMARK_FILE
const char * BKE_appdir_folder_root() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:152
std::optional< std::string > BKE_appdir_folder_id_create(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:777
bool BKE_blendfile_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition blendfile.cc:90
SpaceFile * CTX_wm_space_file(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
Main * CTX_data_main(const bContext *C)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
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.cc:126
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:840
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
int BLI_delete_soft(const char *filepath, const char **r_error_message) ATTR_NONNULL()
bool BLI_file_external_operation_supported(const char *filepath, FileExternalOperation operation)
Definition fileops_c.cc:146
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
Definition fileops_c.cc:391
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:461
FileExternalOperation
@ FILE_EXTERNAL_OPERATION_FOLDER_OPEN
@ FILE_EXTERNAL_OPERATION_FOLDER_CMD
@ FILE_EXTERNAL_OPERATION_OPEN
@ FILE_EXTERNAL_OPERATION_PRINT
@ FILE_EXTERNAL_OPERATION_INSTALL
@ FILE_EXTERNAL_OPERATION_PLAY
@ FILE_EXTERNAL_OPERATION_BROWSE
@ FILE_EXTERNAL_OPERATION_PREVIEW
@ FILE_EXTERNAL_OPERATION_RUNAS
@ FILE_EXTERNAL_OPERATION_FOLDER_FIND
@ FILE_EXTERNAL_OPERATION_NEW
@ FILE_EXTERNAL_OPERATION_EDIT
@ FILE_EXTERNAL_OPERATION_PROPERTIES
@ FILE_EXTERNAL_OPERATION_FIND
@ FILE_EXTERNAL_OPERATION_SHOW
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:456
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation)
Definition fileops_c.cc:157
const char * BLI_dir_home(void)
Definition storage.cc:110
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
bool BLI_path_parent_dir(char *path) ATTR_NONNULL(1)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(1)
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1)
size_t BLI_path_append(char *__restrict dst, size_t dst_maxncpy, const char *__restrict file) ATTR_NONNULL(1
int BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1)
#define FILE_MAXFILE
#define FILE_MAX
#define BLI_path_join(...)
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILENAME_IS_CURRPAR(_n)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define SEP
int BLI_path_sequence_decode(const char *path, char *head, size_t head_maxncpy, char *tail, size_t tail_maxncpy, unsigned short *r_digits_len)
Definition path_utils.cc:57
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
bool BLI_path_is_win32_drive_only(const char *path)
bool BLI_path_make_safe_filename_ex(char *filename, bool allow_tokens) ATTR_NONNULL(1)
size_t size_t BLI_path_append_dir(char *__restrict dst, size_t dst_maxncpy, const char *__restrict dir) ATTR_NONNULL(1
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
int BLI_path_normalize_native(char *path) ATTR_NONNULL(1)
#define FILE_MAXDIR
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILENAME_IS_PARENT(_n)
void BLI_path_sequence_encode(char *path, size_t path_maxncpy, const char *head, const char *tail, unsigned short numlen, int pic)
int BLI_rcti_length_x(const rcti *rect, int x)
Definition rct.cc:149
int BLI_rcti_length_y(const rcti *rect, int y)
Definition rct.cc:160
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned short ushort
#define UNPACK2(a)
#define IN_RANGE(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
Compatibility-like things for windows.
const char * dirname(char *path)
#define TIP_(msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define BLT_I18NCONTEXT_EDITOR_FILEBROWSER
@ 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
FSMenuEntry * ED_fsmenu_get_entry(FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition fsmenu.cc:111
int ED_fsmenu_get_nentries(FSMenu *fsmenu, FSMenuCategory category)
Definition fsmenu.cc:99
FSMenu * ED_fsmenu_get()
Definition fsmenu.cc:46
#define FILE_LAYOUT_HOR
#define FILE_LAYOUT_VER
@ FS_CATEGORY_RECENT
@ FS_CATEGORY_BOOKMARKS
int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *region)
Definition filesel.cc:742
FileSelectParams * ED_fileselect_get_active_params(const SpaceFile *sfile)
Definition filesel.cc:382
void ED_fsmenu_set_category(FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
Definition fsmenu.cc:78
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
Definition filesel.cc:829
FileLayout * ED_fileselect_get_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1149
FSMenuEntry * ED_fsmenu_get_category(FSMenu *fsmenu, FSMenuCategory category)
Definition fsmenu.cc:54
FSMenuInsert
@ FS_INSERT_SAVE
@ FS_INSERT_FIRST
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *rect)
Definition filesel.cc:777
FileAttributeColumnType
@ COLUMN_NONE
bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
Definition filesel.cc:864
bool ED_fileselect_layout_isect_rect(const FileLayout *layout, const View2D *v2d, const rcti *rect, rcti *r_dst)
Definition filesel.cc:871
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1298
void ED_file_change_dir(bContext *C)
Definition filesel.cc:1190
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:714
bool ED_operator_file_browsing_active(bContext *C)
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:743
bool ED_operator_file_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
eSelectOp
@ SEL_OP_SUB
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ UI_SELECT_WALK_RIGHT
@ UI_SELECT_WALK_UP
@ UI_SELECT_WALK_LEFT
@ UI_SELECT_WALK_DOWN
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
@ PROP_FILEPATH
Definition RNA_types.hh:224
#define C
Definition RandGen.cpp:29
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
@ ALERT_ICON_NONE
#define UI_ITEM_NONE
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void UI_view2d_curRect_validate(View2D *v2d)
Definition view2d.cc:828
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1674
ReportList * reports
Definition WM_types.hh:1025
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
#define ND_SPACE_FILE_PARAMS
Definition WM_types.hh:520
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_SPACE
Definition WM_types.hh:389
#define ND_SPACE_FILE_LIST
Definition WM_types.hh:521
const char * folderlist_peeklastdir(ListBase *folderlist)
void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1361
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1367
bool file_attribute_column_header_is_inside(const View2D *v2d, const FileLayout *layout, int x, int y)
Definition filesel.cc:897
void file_params_renamefile_clear(FileSelectParams *params)
Definition filesel.cc:1397
int file_select_match(SpaceFile *sfile, const char *pattern, char *matched_file)
Definition filesel.cc:1205
void fileselect_file_set(bContext *C, SpaceFile *sfile, int index)
Definition filesel.cc:728
void folderlist_pushdir(ListBase *folderlist, const char *dir)
void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds)
Definition file_utils.cc:19
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, const FileSelectParams *params, FileLayout *layout, int x)
Definition filesel.cc:925
void file_select_deselect_all(SpaceFile *sfile, eDirEntry_SelectFlag flag)
Definition filesel.cc:1196
void folderlist_popdir(ListBase *folderlist, char *dir)
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:1411
void FILE_OT_parent(wmOperatorType *ot)
Definition file_ops.cc:2284
void FILE_OT_select_box(wmOperatorType *ot)
Definition file_ops.cc:533
void FILE_OT_directory_new(wmOperatorType *ot)
Definition file_ops.cc:2746
static wmOperatorStatus file_previous_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2303
void file_draw_check(bContext *C)
Definition file_ops.cc:1766
void FILE_OT_edit_directory_path(wmOperatorType *ot)
Definition file_ops.cc:3354
static wmOperatorStatus file_external_operation_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1829
void FILE_OT_bookmark_add(wmOperatorType *ot)
Definition file_ops.cc:1166
static std::string file_external_operation_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
Definition file_ops.cc:1865
static wmOperatorStatus file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition file_ops.cc:445
void FILE_OT_select_bookmark(wmOperatorType *ot)
Definition file_ops.cc:1125
@ FILE_BOOKMARK_MOVE_UP
Definition file_ops.cc:1279
@ FILE_BOOKMARK_MOVE_DOWN
Definition file_ops.cc:1280
@ FILE_BOOKMARK_MOVE_BOTTOM
Definition file_ops.cc:1281
@ FILE_BOOKMARK_MOVE_TOP
Definition file_ops.cc:1278
static bool file_walk_select_do(bContext *C, SpaceFile *sfile, FileSelectParams *params, const int direction, const bool extend, const bool fill)
Definition file_ops.cc:832
static wmOperatorStatus file_start_filter_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3301
static wmOperatorStatus bookmark_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1105
void file_directory_enter_handle(bContext *C, void *, void *)
Definition file_ops.cc:2888
static wmOperatorStatus bookmark_add_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1150
static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *region, const rcti *rect_region)
Definition file_ops.cc:62
static bool file_walk_select_selection_set(bContext *C, 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.cc:712
static wmOperatorStatus bookmark_cleanup_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1228
void ED_operatormacros_file()
Definition file_ops.cc:3372
void FILE_OT_refresh(wmOperatorType *ot)
Definition file_ops.cc:2243
void FILE_OT_mouse_execute(wmOperatorType *ot)
Definition file_ops.cc:2203
static bool file_bookmark_move_poll(bContext *C)
Definition file_ops.cc:1332
static void filenum_newname(char *filename, size_t filename_maxncpy, int add)
Definition file_ops.cc:3082
static wmOperatorStatus file_highlight_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:1460
static wmOperatorStatus file_delete_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:3241
static bool file_ensure_hovered_is_active(bContext *C, const wmEvent *event)
Definition file_ops.cc:2165
static wmOperatorStatus bookmark_move_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1284
void file_filename_enter_handle(bContext *C, void *, void *arg_but)
Definition file_ops.cc:2975
static bool file_delete_single(const FileList *files, FileDirEntry *file, const char **r_error_message)
Definition file_ops.cc:3228
void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
Definition file_ops.cc:1529
static int file_box_select_find_last_selected(SpaceFile *sfile, ARegion *region, const FileSelection *sel, const int mouse_xy[2])
Definition file_ops.cc:411
static rcti file_select_mval_to_select_rect(const int mval[2])
Definition file_ops.cc:559
static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
Definition file_ops.cc:164
void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
Definition file_ops.cc:1695
static wmOperatorStatus file_filenum_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:3107
void FILE_OT_filepath_drop(wmOperatorType *ot)
Definition file_ops.cc:2600
void FILE_OT_previous(wmOperatorType *ot)
Definition file_ops.cc:2320
static wmOperatorStatus file_directory_new_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:2645
static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
Definition file_ops.cc:3145
static void file_os_operations_menu_draw(const bContext *C_const, Menu *menu)
Definition file_ops.cc:1929
void FILE_OT_bookmark_delete(wmOperatorType *ot)
Definition file_ops.cc:1203
static wmOperatorStatus file_hidedot_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3031
void FILE_OT_external_operation(wmOperatorType *ot)
Definition file_ops.cc:1874
void FILE_OT_select_walk(wmOperatorType *ot)
Definition file_ops.cc:937
void FILE_OT_filenum(wmOperatorType *ot)
Definition file_ops.cc:3124
static bool file_os_operations_menu_poll(const bContext *C_const, MenuType *)
Definition file_ops.cc:1995
static wmOperatorStatus file_next_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2339
static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
Definition file_ops.cc:125
void FILE_OT_delete(wmOperatorType *ot)
Definition file_ops.cc:3282
static void clamp_to_filelist(int numfiles, FileSelection *sel)
Definition file_ops.cc:99
static wmOperatorStatus file_edit_directory_path_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3337
void file_sfile_to_operator_ex(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
Definition file_ops.cc:1593
void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
Definition file_ops.cc:1256
void file_draw_check_ex(bContext *C, ScrArea *area)
Definition file_ops.cc:1742
static wmOperatorStatus file_box_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:501
void file_sfile_to_operator(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile)
Definition file_ops.cc:1688
void FILE_OT_smoothscroll(wmOperatorType *ot)
Definition file_ops.cc:2553
static wmOperatorStatus file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:919
static wmOperatorStatus file_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2121
void FILE_OT_bookmark_move(wmOperatorType *ot)
Definition file_ops.cc:1344
static wmOperatorStatus file_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:3276
void FILE_OT_select_all(wmOperatorType *ot)
Definition file_ops.cc:1028
static bool file_is_any_selected(FileList *files)
Definition file_ops.cc:227
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
Definition file_ops.cc:331
static wmOperatorStatus file_execute_mouse_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:2175
static wmOperatorStatus reset_recent_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1379
static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
Definition file_ops.cc:272
static bool file_operator_poll(bContext *C)
Definition file_ops.cc:1550
void FILE_OT_reset_recent(wmOperatorType *ot)
Definition file_ops.cc:1393
static void file_os_operations_menu_item(uiLayout *layout, wmOperatorType *ot, const char *path, FileExternalOperation operation)
Definition file_ops.cc:1903
static bool file_filenum_poll(bContext *C)
Definition file_ops.cc:3065
int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
Definition file_ops.cc:1412
static wmOperatorStatus file_directory_new_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:2732
static std::string file_execute_get_description(bContext *C, wmOperatorType *, PointerRNA *)
Definition file_ops.cc:2132
void FILE_OT_select(wmOperatorType *ot)
Definition file_ops.cc:651
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
Definition file_ops.cc:1723
static void file_ensure_selection_inside_viewbounds(ARegion *region, SpaceFile *sfile, FileSelection *sel)
Definition file_ops.cc:312
void FILE_OT_start_filter(wmOperatorType *ot)
Definition file_ops.cc:3318
static wmOperatorStatus bookmark_delete_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1185
static wmOperatorStatus filepath_drop_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:2572
static wmOperatorStatus file_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:567
void FILE_OT_execute(wmOperatorType *ot)
Definition file_ops.cc:2145
static FileSelection file_current_selection_range_get(FileList *files)
Definition file_ops.cc:242
void file_draw_check_cb(bContext *C, void *, void *)
Definition file_ops.cc:1772
static wmOperatorStatus file_rename_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3167
static void file_expand_directory(const Main *bmain, FileSelectParams *params)
Definition file_ops.cc:2775
void file_external_operations_menu_register()
Definition file_ops.cc:2035
void FILE_OT_rename(wmOperatorType *ot)
Definition file_ops.cc:3181
static wmOperatorStatus file_view_selected_exec(bContext *C, wmOperator *)
Definition file_ops.cc:1050
static wmOperatorStatus file_select_all_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:971
void FILE_OT_cancel(wmOperatorType *ot)
Definition file_ops.cc:1575
bool file_draw_check_exists(SpaceFile *sfile)
Definition file_ops.cc:1777
void FILE_OT_next(wmOperatorType *ot)
Definition file_ops.cc:2357
static bool can_create_dir_from_user_input(const char dir[FILE_MAX_LIBEXTRA])
Definition file_ops.cc:2832
static wmOperatorStatus file_column_sort_ui_context_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:1495
static bool new_folder_path(const char *parent, char r_dirpath_full[FILE_MAX], char r_dirname[FILE_MAXFILE])
Definition file_ops.cc:2624
static wmOperatorStatus file_parent_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2261
static bool file_execute(bContext *C, SpaceFile *sfile)
Definition file_ops.cc:2057
void FILE_OT_view_selected(wmOperatorType *ot)
Definition file_ops.cc:1084
void FILE_OT_highlight(wmOperatorType *ot)
Definition file_ops.cc:1476
FileSelect
Definition file_ops.cc:93
@ FILE_SELECT_NOTHING
Definition file_ops.cc:94
@ FILE_SELECT_DIR
Definition file_ops.cc:95
@ FILE_SELECT_FILE
Definition file_ops.cc:96
static const EnumPropertyItem file_external_operation[]
Definition file_ops.cc:1799
void FILE_OT_hidedot(wmOperatorType *ot)
Definition file_ops.cc:3046
static wmOperatorStatus file_refresh_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2224
static wmOperatorStatus file_cancel_exec(bContext *C, wmOperator *)
Definition file_ops.cc:1562
static bool file_delete_poll(bContext *C)
Definition file_ops.cc:3200
static bool fsmenu_write_file_and_refresh_or_report_error(FSMenu *fsmenu, ScrArea *area, ReportList *reports)
Definition file_ops.cc:380
static wmOperatorStatus file_smoothscroll_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:2377
eDirEntry_SelectFlag filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition filelist.cc:2981
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:3007
bool filelist_islibrary(FileList *filelist, char *dir, char **r_group)
Definition filelist.cc:3017
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2946
const char * filelist_dir(const FileList *filelist)
Definition filelist.cc:2065
void filelist_setrecursion(FileList *filelist, const int recursion_level)
Definition filelist.cc:2092
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2933
bool filelist_is_dir(const FileList *filelist, const char *path)
Definition filelist.cc:2070
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2138
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition filelist.cc:2994
void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, char r_filepath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:1149
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2255
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2123
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2884
eDirEntry_SelectFlag filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition filelist.cc:2963
FileSelType
Definition filelist.hh:35
@ FILE_SEL_REMOVE
Definition filelist.hh:36
@ FILE_SEL_ADD
Definition filelist.hh:37
@ FILE_SEL_TOGGLE
Definition filelist.hh:38
FileCheckType
Definition filelist.hh:41
@ CHECK_FILES
Definition filelist.hh:43
@ CHECK_DIRS
Definition filelist.hh:42
@ CHECK_ALL
Definition filelist.hh:44
void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu)
Definition fsmenu.cc:686
void fsmenu_remove_entry(FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition fsmenu.cc:369
void fsmenu_refresh_system_category(FSMenu *fsmenu)
Definition fsmenu.cc:513
void fsmenu_insert_entry(FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, int icon, FSMenuInsert flag)
Definition fsmenu.cc:252
bool fsmenu_write_file(FSMenu *fsmenu, const char *filepath)
Definition fsmenu.cc:402
#define active
#define exp
#define abs
#define select(A, B, C)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
return ret
bool RNA_property_update_check(PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **r_description)
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_string_file_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_string_dir_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
FSMenuEntry * next
char * redirection_path
FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX]
void * first
char label[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, MenuType *mt)
char idname[BKE_ST_MAXNAME]
void(* draw)(const bContext *C, Menu *menu)
char translation_context[BKE_ST_MAXNAME]
uiLayout * layout
ListBase spacedata
ListBase regionbase
struct wmTimer * smoothscroll_timer
struct FileLayout * layout
struct wmOperator * op
ListBase * folders_prev
struct FileList * files
ListBase * folders_next
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
void * customdata
Definition WM_types.hh:804
bool(* check)(bContext *C, wmOperator *op)
Definition WM_types.hh:1054
const char * description
Definition WM_types.hh:1036
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
uint len
#define N_(msgid)
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_WAIT
Definition wm_cursors.hh:17
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, const int eventval)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_add_mousemove(wmWindow *win)
@ EVT_FILESELECT_CANCEL
@ EVT_FILESELECT_EXEC
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool WM_menutype_add(MenuType *mt)
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_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)
wmOperatorStatus WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
void WM_operator_properties_free(PointerRNA *ptr)