Blender V4.3
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
9#include "BLI_utildefines.h"
10
11#include "BLI_blenlib.h"
12#include "BLI_linklist.h"
13
14#include "BKE_appdir.hh"
15#include "BKE_blendfile.hh"
16#include "BKE_context.hh"
17#include "BKE_main.hh"
18#include "BKE_report.hh"
19#include "BKE_screen.hh"
20
21#include "BLT_translation.hh"
22
23#ifdef WIN32
24# include "BLI_winstuff.h"
25#endif
26
27#include "ED_fileselect.hh"
28#include "ED_screen.hh"
29#include "ED_select_utils.hh"
30
31#include "UI_interface.hh"
32#include "UI_interface_icons.hh"
33#include "UI_resources.hh"
34
35#include "MEM_guardedalloc.h"
36
37#include "RNA_access.hh"
38#include "RNA_define.hh"
39
40#include "UI_view2d.hh"
41
42#include "WM_api.hh"
43#include "WM_types.hh"
44
45#include "file_intern.hh"
46#include "filelist.hh"
47#include "fsmenu.h"
48
49#include <cctype>
50#include <cerrno>
51#include <cstdio>
52#include <cstdlib>
53#include <cstring>
54
55/* -------------------------------------------------------------------- */
60 ARegion *region,
61 const rcti *rect_region)
62{
63 FileSelection sel;
64
65 View2D *v2d = &region->v2d;
66 rcti rect_view;
67 rctf rect_view_fl;
68 rctf rect_region_fl;
69
70 BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
71
72 /* Okay, manipulating v2d rects here is hacky... */
73 v2d->mask.ymax -= sfile->layout->offset_top;
74 v2d->cur.ymax -= sfile->layout->offset_top;
75 UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
76 v2d->mask.ymax += sfile->layout->offset_top;
77 v2d->cur.ymax += sfile->layout->offset_top;
78
79 BLI_rcti_init(&rect_view,
80 int(v2d->tot.xmin + rect_view_fl.xmin),
81 int(v2d->tot.xmin + rect_view_fl.xmax),
82 int(v2d->tot.ymax - rect_view_fl.ymin),
83 int(v2d->tot.ymax - rect_view_fl.ymax));
84
85 sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
86
87 return sel;
88}
89
95
96static void clamp_to_filelist(int numfiles, FileSelection *sel)
97{
98 /* box select before the first file */
99 if ((sel->first < 0) && (sel->last >= 0)) {
100 sel->first = 0;
101 }
102 /* don't select if everything is outside filelist */
103 if ((sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles))) {
104 sel->first = -1;
105 sel->last = -1;
106 }
107
108 /* fix if last file invalid */
109 if ((sel->first > 0) && (sel->last < 0)) {
110 sel->last = numfiles - 1;
111 }
112
113 /* clamp */
114 if (sel->first >= numfiles) {
115 sel->first = numfiles - 1;
116 }
117 if (sel->last >= numfiles) {
118 sel->last = numfiles - 1;
119 }
120}
121
122static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
123{
124 ARegion *region = CTX_wm_region(C);
125 SpaceFile *sfile = CTX_wm_space_file(C);
126 int numfiles = filelist_files_ensure(sfile->files);
127 FileSelection sel;
128
129 sel = find_file_mouse_rect(sfile, region, rect);
130 if (!((sel.first == -1) && (sel.last == -1))) {
131 clamp_to_filelist(numfiles, &sel);
132 }
133
134 /* if desired, fill the selection up from the last selected file to the current one */
135 if (fill && (sel.last >= 0) && (sel.last < numfiles)) {
136 int f;
137 /* Try to find a smaller-index selected item. */
138 for (f = sel.last; f >= 0; f--) {
140 break;
141 }
142 }
143 if (f >= 0) {
144 sel.first = f + 1;
145 }
146 /* If none found, try to find a higher-index selected item. */
147 else {
148 for (f = sel.first; f < numfiles; f++) {
150 break;
151 }
152 }
153 if (f < numfiles) {
154 sel.last = f - 1;
155 }
156 }
157 }
158 return sel;
159}
160
161static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
162{
163 Main *bmain = CTX_data_main(C);
165 SpaceFile *sfile = CTX_wm_space_file(C);
167 int numfiles = filelist_files_ensure(sfile->files);
168 const FileDirEntry *file;
169
170 /* make the selected file active */
171 if ((selected_idx >= 0) && (selected_idx < numfiles) &&
172 (file = filelist_file(sfile->files, selected_idx)))
173 {
174 params->highlight_file = selected_idx;
175 params->active_file = selected_idx;
176
177 if (file->typeflag & FILE_TYPE_DIR) {
178 const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
179
180 if (do_diropen == false) {
181 retval = FILE_SELECT_DIR;
182 }
183 /* the path is too long and we are not going up! */
184 else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
185 // XXX error("Path too long, cannot enter this directory");
186 }
187 else {
188 if (is_parent_dir) {
189 /* avoids /../../ */
191
192 if (params->recursion_level > 1) {
193 /* Disable 'dirtree' recursion when going up in tree. */
194 params->recursion_level = 0;
195 filelist_setrecursion(sfile->files, params->recursion_level);
196 }
197 }
198 else if (file->redirection_path) {
199 STRNCPY(params->dir, file->redirection_path);
201 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
202 }
203 else {
205 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
206 BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath);
207 }
208
210 retval = FILE_SELECT_DIR;
211 }
212 }
213 else {
214 retval = FILE_SELECT_FILE;
215 }
216 fileselect_file_set(C, sfile, selected_idx);
217 }
218 return retval;
219}
220
225{
226 const int numfiles = filelist_files_ensure(files);
227 int i;
228
229 /* Is any file selected ? */
230 for (i = 0; i < numfiles; i++) {
232 return true;
233 }
234 }
235
236 return false;
237}
238
240{
241 const int numfiles = filelist_files_ensure(files);
242 FileSelection selection = {-1, -1};
243
244 /* Iterate over the files once but in two loops, one to find the first selected file, and the
245 * other to find the last. */
246
247 int file_index;
248 for (file_index = 0; file_index < numfiles; file_index++) {
249 if (filelist_entry_is_selected(files, file_index)) {
250 /* First selected entry found. */
251 selection.first = file_index;
252 break;
253 }
254 }
255
256 for (; file_index < numfiles; file_index++) {
257 if (filelist_entry_is_selected(files, file_index)) {
258 selection.last = file_index;
259 /* Keep looping, we may find more selected files. */
260 }
261 }
262
263 return selection;
264}
265
269static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
270{
271 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
272 rctf *cur = &region->v2d.cur;
273 rcti rect;
274 bool changed = true;
275
276 file_tile_boundbox(region, layout, file, &rect);
277
278 /* down - also use if tile is higher than viewbounds so view is aligned to file name */
279 if (cur->ymin > rect.ymin || layout->tile_h > region->winy) {
280 cur->ymin = rect.ymin - (2 * layout->tile_border_y);
281 cur->ymax = cur->ymin + region->winy;
282 }
283 /* up */
284 else if ((cur->ymax - layout->offset_top) < rect.ymax) {
285 cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
286 cur->ymin = cur->ymax - region->winy;
287 }
288 /* left - also use if tile is wider than viewbounds so view is aligned to file name */
289 else if (cur->xmin > rect.xmin || layout->tile_w > region->winx) {
290 cur->xmin = rect.xmin - layout->tile_border_x;
291 cur->xmax = cur->xmin + region->winx;
292 }
293 /* right */
294 else if (cur->xmax < rect.xmax) {
295 cur->xmax = rect.xmax + (2 * layout->tile_border_x);
296 cur->xmin = cur->xmax - region->winx;
297 }
298 else {
299 BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
300 (cur->ymax - layout->offset_top) >= rect.ymax);
301 changed = false;
302 }
303
304 if (changed) {
305 UI_view2d_curRect_validate(&region->v2d);
306 }
307}
308
310 SpaceFile *sfile,
311 FileSelection *sel)
312{
313 const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
314
315 if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) &&
316 ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h)))
317 {
318 return;
319 }
320
321 /* Adjust view to display selection. Doing iterations for first and last
322 * selected item makes view showing as much of the selection possible.
323 * Not really useful if tiles are (almost) bigger than viewbounds though. */
324 file_ensure_inside_viewbounds(region, sfile, sel->last);
325 file_ensure_inside_viewbounds(region, sfile, sel->first);
326}
327
329 bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
330{
331 SpaceFile *sfile = CTX_wm_space_file(C);
334 FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
335 const FileCheckType check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
336
337 /* flag the files as selected in the filelist */
339 sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
340
341 /* Don't act on multiple selected files */
342 if (sel.first != sel.last) {
343 select = FileSelType(0);
344 }
345
346 /* Do we have a valid selection and are we actually selecting */
347 if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
348 /* Check last selection, if selected, act on the file or dir */
349 if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
350 retval = file_select_do(C, sel.last, do_diropen);
351 }
352 }
353
354 if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
355 params->active_file = -1;
356 }
357 else if (sel.last >= 0) {
358 ARegion *region = CTX_wm_region(C);
359 file_ensure_selection_inside_viewbounds(region, sfile, &sel);
360 }
361
362 /* update operator for name change event */
364
365 return retval;
366}
367
370/* -------------------------------------------------------------------- */
378 ScrArea *area,
379 ReportList *reports)
380{
381 /* NOTE: use warning instead of error here, because the bookmark operation may be part of
382 * other actions which should not cause the operator to fail entirely. */
383 const std::optional<std::string> cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG,
384 nullptr);
385 if (!cfgdir.has_value()) {
386 BKE_report(reports, RPT_ERROR, "Unable to create configuration directory to write bookmarks");
387 return false;
388 }
389
390 char filepath[FILE_MAX];
391 BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_BOOKMARK_FILE);
392 if (!fsmenu_write_file(fsmenu, filepath)) {
393 BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath);
394 return false;
395 }
396
398 ED_area_tag_redraw(area);
399 return true;
400}
401
404/* -------------------------------------------------------------------- */
409 ARegion *region,
410 const FileSelection *sel,
411 const int mouse_xy[2])
412{
413 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
414 rcti bounds_first, bounds_last;
415 int dist_first, dist_last;
416 float mouseco_view[2];
417
418 UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
419
420 file_tile_boundbox(region, layout, sel->first, &bounds_first);
421 file_tile_boundbox(region, layout, sel->last, &bounds_last);
422
423 /* are first and last in the same column (horizontal layout)/row (vertical layout)? */
424 if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
425 (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin))
426 {
427 /* use vertical distance */
428 const int my_loc = int(mouseco_view[1]);
429 dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
430 dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
431 }
432 else {
433 /* use horizontal distance */
434 const int mx_loc = int(mouseco_view[0]);
435 dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
436 dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
437 }
438
439 return (dist_first < dist_last) ? sel->first : sel->last;
440}
441
442static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
443{
444 ARegion *region = CTX_wm_region(C);
445 SpaceFile *sfile = CTX_wm_space_file(C);
447 FileSelection sel;
448 rcti rect;
449
450 int result;
451
452 result = WM_gesture_box_modal(C, op, event);
453
454 if (result == OPERATOR_RUNNING_MODAL) {
456
457 ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
458
459 sel = file_selection_get(C, &rect, false);
460 if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
461 int idx;
462
467
468 for (idx = sel.last; idx >= 0; idx--) {
469 const FileDirEntry *file = filelist_file(sfile->files, idx);
470
471 /* Don't highlight read-only file (".." or ".") on box select. */
472 if (FILENAME_IS_CURRPAR(file->relpath)) {
475 }
476
477 /* make sure highlight_file is no readonly file */
478 if (sel.last == idx) {
479 params->highlight_file = idx;
480 }
481 }
482 }
483 params->sel_first = sel.first;
484 params->sel_last = sel.last;
485 params->active_file = file_box_select_find_last_selected(sfile, region, &sel, event->mval);
486 }
487 else {
488 params->highlight_file = -1;
489 params->sel_first = params->sel_last = -1;
490 fileselect_file_set(C, sfile, params->active_file);
493 }
494
495 return result;
496}
497
499{
500 ARegion *region = CTX_wm_region(C);
501 SpaceFile *sfile = CTX_wm_space_file(C);
502 rcti rect;
504
506
507 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
508 const bool select = (sel_op != SEL_OP_SUB);
509 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
511 }
512
513 ED_fileselect_layout_isect_rect(sfile->layout, &region->v2d, &rect, &rect);
514
515 ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
516
517 /* unselect '..' parent entry - it's not supposed to be selected if more than
518 * one file is selected */
520
521 if (FILE_SELECT_DIR == ret) {
523 }
524 else if (FILE_SELECT_FILE == ret) {
526 }
527 return OPERATOR_FINISHED;
528}
529
531{
532 /* identifiers */
533 ot->name = "Box Select";
534 ot->description = "Activate/select the file(s) contained in the border";
535 ot->idname = "FILE_OT_select_box";
536
537 /* api callbacks */
541 /* Operator works for file or asset browsing */
544
545 /* properties */
548}
549
552/* -------------------------------------------------------------------- */
556static rcti file_select_mval_to_select_rect(const int mval[2])
557{
558 rcti rect;
559 rect.xmin = rect.xmax = mval[0];
560 rect.ymin = rect.ymax = mval[1];
561 return rect;
562}
563
565{
566 ARegion *region = CTX_wm_region(C);
567 SpaceFile *sfile = CTX_wm_space_file(C);
569 rcti rect;
570 const bool extend = RNA_boolean_get(op->ptr, "extend");
571 const bool fill = RNA_boolean_get(op->ptr, "fill");
572 const bool do_diropen = RNA_boolean_get(op->ptr, "open");
573 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
574 const bool only_activate_if_selected = RNA_boolean_get(op->ptr, "only_activate_if_selected");
575 /* Used so right mouse clicks can do both, activate and spawn the context menu. */
576 const bool pass_through = RNA_boolean_get(op->ptr, "pass_through");
577 bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
578
579 if (region->regiontype != RGN_TYPE_WINDOW) {
580 return OPERATOR_CANCELLED;
581 }
582
583 int mval[2];
584 mval[0] = RNA_int_get(op->ptr, "mouse_x");
585 mval[1] = RNA_int_get(op->ptr, "mouse_y");
587
588 if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &region->v2d, rect.xmin, rect.ymin)) {
590 }
591
592 if (extend || fill) {
593 wait_to_deselect_others = false;
594 }
595
596 int ret_val = OPERATOR_FINISHED;
597
599 if (params) {
600 int idx = params->highlight_file;
601 int numfiles = filelist_files_ensure(sfile->files);
602
603 if ((idx >= 0) && (idx < numfiles)) {
604 const bool is_selected = filelist_entry_select_index_get(sfile->files, idx, CHECK_ALL) &
606 if (only_activate_if_selected && is_selected) {
607 /* Don't deselect other items. */
608 }
609 else if (wait_to_deselect_others && is_selected) {
610 ret_val = OPERATOR_RUNNING_MODAL;
611 }
612 /* single select, deselect all selected first */
613 else if (!extend) {
615 }
616 }
617 }
618
619 ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
620
621 if (extend) {
622 /* unselect '..' parent entry - it's not supposed to be selected if more
623 * than one file is selected */
625 }
626
627 if (ret == FILE_SELECT_NOTHING) {
628 if (deselect_all) {
630 }
631 }
632 else if (ret == FILE_SELECT_DIR) {
634 }
635 else if (ret == FILE_SELECT_FILE) {
637 }
638
639 WM_event_add_mousemove(CTX_wm_window(C)); /* for directory changes */
641
642 if ((ret_val == OPERATOR_FINISHED) && pass_through) {
643 ret_val |= OPERATOR_PASS_THROUGH;
644 }
645 return ret_val;
646}
647
649{
650 PropertyRNA *prop;
651
652 /* identifiers */
653 ot->name = "Select";
654 ot->idname = "FILE_OT_select";
655 ot->description = "Handle mouse clicks to select and activate items";
656
657 /* api callbacks */
661 /* Operator works for file or asset browsing */
663
664 /* properties */
666 prop = RNA_def_boolean(ot->srna,
667 "extend",
668 false,
669 "Extend",
670 "Extend selection instead of deselecting everything first");
672 prop = RNA_def_boolean(
673 ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
675 prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
677 prop = RNA_def_boolean(ot->srna,
678 "deselect_all",
679 false,
680 "Deselect On Nothing",
681 "Deselect all when nothing under the cursor");
683 prop = RNA_def_boolean(ot->srna,
684 "only_activate_if_selected",
685 false,
686 "Only Activate if Selected",
687 "Do not change selection if the item under the cursor is already "
688 "selected, only activate it");
690 prop = RNA_def_boolean(ot->srna,
691 "pass_through",
692 false,
693 "Pass Through",
694 "Even on successful execution, pass the event on so other operators can "
695 "execute on it as well");
697}
698
701/* -------------------------------------------------------------------- */
709 wmWindow *win,
710 ARegion *region,
711 SpaceFile *sfile,
712 const int direction,
713 const int numfiles,
714 const int active_old,
715 const int active_new,
716 const int other_site,
717 const bool has_selection,
718 const bool extend,
719 const bool fill)
720{
722 FileList *files = sfile->files;
723 const int last_sel = params->active_file; /* store old value */
724 int active = active_old; /* could use active_old instead, just for readability */
725 bool deselect = false;
726
728
729 if (numfiles == 0) {
730 /* No files visible, nothing to do. */
731 return false;
732 }
733
734 if (has_selection) {
735 if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
736 filelist_entry_select_index_get(files, active_new, CHECK_ALL))
737 {
738 /* conditions for deselecting: initial file is selected, new file is
739 * selected and either other_side isn't selected/found or we use fill */
740 deselect = (fill || other_site == -1 ||
741 !filelist_entry_select_index_get(files, other_site, CHECK_ALL));
742
743 /* don't change highlight_file here since we either want to deselect active or we want
744 * to walk through a block of selected files without selecting/deselecting anything */
745 params->active_file = active_new;
746 /* but we want to change active if we use fill
747 * (needed to get correct selection bounds) */
748 if (deselect && fill) {
749 active = active_new;
750 }
751 }
752 else {
753 /* regular selection change */
754 params->active_file = active = active_new;
755 }
756 }
757 else {
758 /* select last file */
759 if (ELEM(direction, UI_SELECT_WALK_UP, UI_SELECT_WALK_LEFT)) {
760 params->active_file = active = numfiles - 1;
761 }
762 /* select first file */
763 else if (ELEM(direction, UI_SELECT_WALK_DOWN, UI_SELECT_WALK_RIGHT)) {
764 params->active_file = active = 0;
765 }
766 else {
767 BLI_assert(0);
768 }
769 }
770
771 if (active < 0) {
772 return false;
773 }
774
775 if (extend) {
776 /* highlight the active walker file for extended selection for better visual feedback */
777 params->highlight_file = params->active_file;
778
779 /* unselect '..' parent entry - it's not supposed to be selected if more
780 * than one file is selected */
782 }
783 else {
784 /* deselect all first */
786
787 /* highlight file under mouse pos */
788 params->highlight_file = -1;
790 }
791
792 /* do the actual selection */
793 if (fill) {
794 FileSelection sel = {std::min(active, last_sel), std::max(active, last_sel)};
795
796 /* fill selection between last and first selected file */
798 files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
799 /* entire sel is cleared here, so select active again */
800 if (deselect) {
802 }
803
804 /* unselect '..' parent entry - it's not supposed to be selected if more
805 * than one file is selected */
806 if ((sel.last - sel.first) > 1) {
808 }
809 }
810 else {
812 files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
813 }
814
815 BLI_assert(IN_RANGE(active, -1, numfiles));
816 fileselect_file_set(C, sfile, params->active_file);
817
818 /* ensure newly selected file is inside viewbounds */
819 file_ensure_inside_viewbounds(region, sfile, params->active_file);
820
821 /* selection changed */
822 return true;
823}
824
829 SpaceFile *sfile,
831 const int direction,
832 const bool extend,
833 const bool fill)
834{
835 wmWindow *win = CTX_wm_window(C);
836 ARegion *region = CTX_wm_region(C);
837 FileList *files = sfile->files;
838 const int numfiles = filelist_files_ensure(files);
839 const bool has_selection = file_is_any_selected(files);
840 const int active_old = params->active_file;
841 int active_new = -1;
842 int other_site = -1; /* file on the other site of active_old */
843
844 /* *** get all needed files for handling selection *** */
845
846 if (numfiles == 0) {
847 /* No files visible, nothing to do. */
848 return false;
849 }
850
851 if (has_selection) {
852 FileLayout *layout = ED_fileselect_get_layout(sfile, region);
853 const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
854
855 if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_UP) ||
856 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_LEFT))
857 {
858 active_new = active_old - 1;
859 other_site = active_old + 1;
860 }
861 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_DOWN) ||
862 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_RIGHT))
863 {
864 active_new = active_old + 1;
865 other_site = active_old - 1;
866 }
867 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_LEFT) ||
868 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_UP))
869 {
870 active_new = active_old - idx_shift;
871 other_site = active_old + idx_shift;
872 }
873 else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_RIGHT) ||
874 (layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_DOWN))
875 {
876
877 active_new = active_old + idx_shift;
878 other_site = active_old - idx_shift;
879 }
880 else {
881 BLI_assert(0);
882 }
883
884 if (!IN_RANGE(active_new, -1, numfiles)) {
885 if (extend) {
886 /* extend to invalid file -> abort */
887 return false;
888 }
889 /* if we don't extend, selecting '..' (index == 0) is allowed so
890 * using key selection to go to parent directory is possible */
891 if (active_new != 0) {
892 /* select initial file */
893 active_new = active_old;
894 }
895 }
896 if (!IN_RANGE(other_site, 0, numfiles)) {
897 other_site = -1;
898 }
899 }
900
902 win,
903 region,
904 sfile,
905 direction,
906 numfiles,
907 active_old,
908 active_new,
909 other_site,
910 has_selection,
911 extend,
912 fill);
913}
914
915static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
916{
919 const int direction = RNA_enum_get(op->ptr, "direction");
920 const bool extend = RNA_boolean_get(op->ptr, "extend");
921 const bool fill = RNA_boolean_get(op->ptr, "fill");
922
923 if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
925 return OPERATOR_FINISHED;
926 }
927
928 return OPERATOR_CANCELLED;
929}
930
932{
933 PropertyRNA *prop;
934
935 /* identifiers */
936 ot->name = "Walk Select/Deselect File";
937 ot->description = "Select/Deselect files by walking through them";
938 ot->idname = "FILE_OT_select_walk";
939
940 /* api callbacks */
942 /* Operator works for file or asset browsing */
944
945 /* properties */
947 prop = RNA_def_boolean(ot->srna,
948 "extend",
949 false,
950 "Extend",
951 "Extend selection instead of deselecting everything first");
953 prop = RNA_def_boolean(
954 ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
956}
957
960/* -------------------------------------------------------------------- */
965{
966 ScrArea *area = CTX_wm_area(C);
967 SpaceFile *sfile = CTX_wm_space_file(C);
969 FileSelection sel;
970 const int numfiles = filelist_files_ensure(sfile->files);
971 int action = RNA_enum_get(op->ptr, "action");
972
973 if (action == SEL_TOGGLE) {
975 }
976
977 sel.first = 0;
978 sel.last = numfiles - 1;
979
980 FileCheckType check_type;
981 FileSelType filesel_type;
982
983 switch (action) {
984 case SEL_SELECT:
985 case SEL_INVERT: {
986 check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
987 filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD;
988 break;
989 }
990 case SEL_DESELECT: {
991 check_type = CHECK_ALL;
992 filesel_type = FILE_SEL_REMOVE;
993 break;
994 }
995 default: {
996 BLI_assert(0);
997 return OPERATOR_CANCELLED;
998 }
999 }
1000
1002 sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type);
1003
1004 params->active_file = -1;
1005 if (action != SEL_DESELECT) {
1006 for (int i = 0; i < numfiles; i++) {
1007 if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
1008 params->active_file = i;
1009 break;
1010 }
1011 }
1012 }
1013
1014 file_draw_check(C);
1016 ED_area_tag_redraw(area);
1017
1018 return OPERATOR_FINISHED;
1019}
1020
1022{
1023 /* identifiers */
1024 ot->name = "(De)select All Files";
1025 ot->description = "Select or deselect all files";
1026 ot->idname = "FILE_OT_select_all";
1027
1028 /* api callbacks */
1030 /* Operator works for file or asset browsing */
1032
1033 /* properties */
1035}
1036
1039/* -------------------------------------------------------------------- */
1044{
1045 SpaceFile *sfile = CTX_wm_space_file(C);
1048
1049 if (sel.first == -1 && sel.last == -1 && params->active_file == -1) {
1050 /* Nothing was selected. */
1051 return OPERATOR_CANCELLED;
1052 }
1053
1054 /* Extend the selection area with the active file, as it may not be selected but still is
1055 * important to have in view. */
1056 if (sel.first == -1 || params->active_file < sel.first) {
1057 sel.first = params->active_file;
1058 }
1059 if (sel.last == -1 || params->active_file > sel.last) {
1060 sel.last = params->active_file;
1061 }
1062
1063 ScrArea *area = CTX_wm_area(C);
1064 ARegion *region = CTX_wm_region(C);
1065 file_ensure_selection_inside_viewbounds(region, sfile, &sel);
1066
1067 file_draw_check(C);
1069 ED_area_tag_redraw(area);
1070
1071 return OPERATOR_FINISHED;
1072}
1073
1075{
1076 /* identifiers */
1077 ot->name = "Frame Selected";
1078 ot->description = "Scroll the selected files into view";
1079 ot->idname = "FILE_OT_view_selected";
1080
1081 /* api callbacks */
1083 /* Operator works for file or asset browsing */
1085}
1086
1089/* -------------------------------------------------------------------- */
1093/* Note we could get rid of this one, but it's used by some addon so...
1094 * Does not hurt keeping it around for now. */
1096{
1097 Main *bmain = CTX_data_main(C);
1098 SpaceFile *sfile = CTX_wm_space_file(C);
1099
1100 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "dir");
1102 char entry[256];
1103
1104 RNA_property_string_get(op->ptr, prop, entry);
1105 STRNCPY(params->dir, entry);
1107 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
1109
1111
1112 return OPERATOR_FINISHED;
1113}
1114
1116{
1117 PropertyRNA *prop;
1118
1119 /* identifiers */
1120 ot->name = "Select Directory";
1121 ot->description = "Select a bookmarked directory";
1122 ot->idname = "FILE_OT_select_bookmark";
1123
1124 /* api callbacks */
1126 /* Bookmarks are for file browsing only (not asset browsing). */
1128
1129 /* properties */
1130 prop = RNA_def_string(ot->srna, "dir", nullptr, FILE_MAXDIR, "Directory", "");
1132}
1133
1136/* -------------------------------------------------------------------- */
1141{
1142 ScrArea *area = CTX_wm_area(C);
1143 SpaceFile *sfile = CTX_wm_space_file(C);
1144 FSMenu *fsmenu = ED_fsmenu_get();
1146
1147 if (params->dir[0] != '\0') {
1148
1150 fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, nullptr, ICON_FILE_FOLDER, FS_INSERT_SAVE);
1152 }
1153 return OPERATOR_FINISHED;
1154}
1155
1157{
1158 /* identifiers */
1159 ot->name = "Add Bookmark";
1160 ot->description = "Add a bookmark for the selected/active directory";
1161 ot->idname = "FILE_OT_bookmark_add";
1162
1163 /* api callbacks */
1165 /* Bookmarks are for file browsing only (not asset browsing). */
1167}
1168
1171/* -------------------------------------------------------------------- */
1176{
1177 ScrArea *area = CTX_wm_area(C);
1178 SpaceFile *sfile = CTX_wm_space_file(C);
1179 FSMenu *fsmenu = ED_fsmenu_get();
1180 int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1181
1182 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
1183 const int index = RNA_property_is_set(op->ptr, prop) ? RNA_property_int_get(op->ptr, prop) :
1184 sfile->bookmarknr;
1185 if ((index > -1) && (index < nentries)) {
1188 }
1189
1190 return OPERATOR_FINISHED;
1191}
1192
1194{
1195 PropertyRNA *prop;
1196
1197 /* identifiers */
1198 ot->name = "Delete Bookmark";
1199 ot->description = "Delete selected bookmark";
1200 ot->idname = "FILE_OT_bookmark_delete";
1201
1202 /* api callbacks */
1204 /* Bookmarks are for file browsing only (not asset browsing). */
1206
1207 /* properties */
1208 prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
1210}
1211
1214/* -------------------------------------------------------------------- */
1219{
1220 ScrArea *area = CTX_wm_area(C);
1221 FSMenu *fsmenu = ED_fsmenu_get();
1222 FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
1223 int index;
1224 bool changed = false;
1225
1226 for (index = 0; fsme; fsme = fsme_next) {
1227 fsme_next = fsme->next;
1228
1229 if (!BLI_is_dir(fsme->path)) {
1231 changed = true;
1232 }
1233 else {
1234 index++;
1235 }
1236 }
1237
1238 if (changed) {
1241 }
1242
1243 return OPERATOR_FINISHED;
1244}
1245
1247{
1248 /* identifiers */
1249 ot->name = "Cleanup Bookmarks";
1250 ot->description = "Delete all invalid bookmarks";
1251 ot->idname = "FILE_OT_bookmark_cleanup";
1252
1253 /* api callbacks */
1255 /* Bookmarks are for file browsing only (not asset browsing). */
1257
1258 /* properties */
1259}
1260
1263/* -------------------------------------------------------------------- */
1267enum {
1272};
1273
1275{
1276 ScrArea *area = CTX_wm_area(C);
1277 SpaceFile *sfile = CTX_wm_space_file(C);
1278 FSMenu *fsmenu = ED_fsmenu_get();
1280 const FSMenuEntry *fsmentry_org = fsmentry;
1281
1282 const int direction = RNA_enum_get(op->ptr, "direction");
1283 const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
1284 const int act_index = sfile->bookmarknr;
1285 int new_index;
1286
1287 if (totitems < 2) {
1288 return OPERATOR_CANCELLED;
1289 }
1290
1291 switch (direction) {
1293 new_index = 0;
1294 break;
1296 new_index = totitems - 1;
1297 break;
1300 default:
1301 new_index = (totitems + act_index + direction) % totitems;
1302 break;
1303 }
1304
1305 if (new_index == act_index) {
1306 return OPERATOR_CANCELLED;
1307 }
1308
1309 BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
1310 if (fsmentry != fsmentry_org) {
1312 }
1313
1314 /* Need to update active bookmark number. */
1315 sfile->bookmarknr = new_index;
1316
1318
1319 return OPERATOR_FINISHED;
1320}
1321
1323{
1324 SpaceFile *sfile = CTX_wm_space_file(C);
1325
1326 /* Bookmarks are for file browsing only (not asset browsing). */
1328 return false;
1329 }
1330
1331 return sfile->bookmarknr != -1;
1332}
1333
1335{
1336 static const EnumPropertyItem slot_move[] = {
1337 {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
1338 {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
1339 {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
1340 {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
1341 {0, nullptr, 0, nullptr, nullptr}};
1342
1343 /* identifiers */
1344 ot->name = "Move Bookmark";
1345 ot->idname = "FILE_OT_bookmark_move";
1346 ot->description = "Move the active bookmark up/down in the list";
1347
1348 /* api callbacks */
1351
1352 /* flags */
1353 ot->flag = OPTYPE_REGISTER; /* No undo! */
1354
1356 "direction",
1357 slot_move,
1358 0,
1359 "Direction",
1360 "Direction to move the active bookmark towards");
1361}
1362
1365/* -------------------------------------------------------------------- */
1370{
1371 ScrArea *area = CTX_wm_area(C);
1372 FSMenu *fsmenu = ED_fsmenu_get();
1373
1374 while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != nullptr) {
1376 }
1377
1379
1380 return OPERATOR_FINISHED;
1381}
1382
1384{
1385 /* identifiers */
1386 ot->name = "Reset Recent";
1387 ot->description = "Reset recent files";
1388 ot->idname = "FILE_OT_reset_recent";
1389
1390 /* api callbacks */
1392 /* File browsing only operator (not asset browsing). */
1394}
1395
1398/* -------------------------------------------------------------------- */
1402int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
1403{
1404 View2D *v2d = &region->v2d;
1406 int numfiles, origfile;
1407
1408 /* In case blender starts where the mouse is over a File browser,
1409 * this operator can be invoked when the `sfile` or `sfile->layout` isn't initialized yet. */
1410 if (sfile == nullptr || sfile->files == nullptr || sfile->layout == nullptr) {
1411 return 0;
1412 }
1413
1415 /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
1416 * what creates the params for the current browse mode. See #93508. */
1417 if (!params) {
1418 return false;
1419 }
1420 numfiles = filelist_files_ensure(sfile->files);
1421
1422 origfile = params->highlight_file;
1423
1424 mx -= region->winrct.xmin;
1425 my -= region->winrct.ymin;
1426
1427 if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
1428 float fx, fy;
1429 int highlight_file;
1430
1431 UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
1432
1433 highlight_file = ED_fileselect_layout_offset(
1434 sfile->layout, int(v2d->tot.xmin + fx), int(v2d->tot.ymax - fy));
1435
1436 if ((highlight_file >= 0) && (highlight_file < numfiles)) {
1437 params->highlight_file = highlight_file;
1438 }
1439 else {
1440 params->highlight_file = -1;
1441 }
1442 }
1443 else {
1444 params->highlight_file = -1;
1445 }
1446
1447 return (params->highlight_file != origfile);
1448}
1449
1450static int file_highlight_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
1451{
1452 ARegion *region = CTX_wm_region(C);
1453 SpaceFile *sfile = CTX_wm_space_file(C);
1454
1455 if (!file_highlight_set(sfile, region, event->xy[0], event->xy[1])) {
1456 return OPERATOR_PASS_THROUGH;
1457 }
1458
1460
1461 return OPERATOR_PASS_THROUGH;
1462}
1463
1465{
1466 /* identifiers */
1467 ot->name = "Highlight File";
1468 ot->description = "Highlight selected file(s)";
1469 ot->idname = "FILE_OT_highlight";
1470
1471 /* api callbacks */
1473 /* Operator works for file or asset browsing */
1475}
1476
1479/* -------------------------------------------------------------------- */
1484 wmOperator * /*op*/,
1485 const wmEvent *event)
1486{
1487 const ARegion *region = CTX_wm_region(C);
1488 SpaceFile *sfile = CTX_wm_space_file(C);
1489
1491 &region->v2d, sfile->layout, event->mval[0], event->mval[1]))
1492 {
1495 &region->v2d, params, sfile->layout, event->mval[0]);
1496
1497 if (column_type != COLUMN_NONE) {
1498 const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
1499
1501 if (params->sort == column->sort_type) {
1502 /* Already sorting by selected column -> toggle sort invert (three state logic). */
1503 params->flag ^= FILE_SORT_INVERT;
1504 }
1505 else {
1506 params->sort = column->sort_type;
1507 params->flag &= ~FILE_SORT_INVERT;
1508 }
1509
1511 }
1512 }
1513
1514 return OPERATOR_PASS_THROUGH;
1515}
1516
1518{
1519 /* identifiers */
1520 ot->name = "Sort from Column";
1521 ot->description = "Change sorting to use column under cursor";
1522 ot->idname = "FILE_OT_sort_column_ui_context";
1523
1524 /* api callbacks */
1526 /* Operator works for file or asset browsing */
1528
1530}
1531
1534/* -------------------------------------------------------------------- */
1539{
1540 bool poll = ED_operator_file_browsing_active(C);
1541 SpaceFile *sfile = CTX_wm_space_file(C);
1542
1543 if (!sfile || !sfile->op) {
1544 poll = false;
1545 }
1546
1547 return poll;
1548}
1549
1550static int file_cancel_exec(bContext *C, wmOperator * /*unused*/)
1551{
1553 SpaceFile *sfile = CTX_wm_space_file(C);
1554 wmOperator *op = sfile->op;
1555
1556 sfile->op = nullptr;
1557
1559
1560 return OPERATOR_FINISHED;
1561}
1562
1564{
1565 /* identifiers */
1566 ot->name = "Cancel File Load";
1567 ot->description = "Cancel loading of selected file";
1568 ot->idname = "FILE_OT_cancel";
1569
1570 /* api callbacks */
1573}
1574
1577/* -------------------------------------------------------------------- */
1582 bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
1583{
1585 PropertyRNA *prop;
1586
1587 /* XXX, not real length */
1588 if (params->file[0]) {
1589 BLI_path_join(filepath, FILE_MAX, params->dir, params->file);
1590 }
1591 else {
1592 BLI_strncpy(filepath, params->dir, FILE_MAX);
1594 }
1595
1596 if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
1597 if (RNA_property_boolean_get(op->ptr, prop)) {
1598 BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
1599 }
1600 }
1601
1602 char value[FILE_MAX];
1603 if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1604 RNA_property_string_get(op->ptr, prop, value);
1605 RNA_property_string_set(op->ptr, prop, params->file);
1606 if (RNA_property_update_check(prop) && !STREQ(params->file, value)) {
1607 RNA_property_update(C, op->ptr, prop);
1608 }
1609 }
1610 if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1611 RNA_property_string_get(op->ptr, prop, value);
1612 RNA_property_string_set(op->ptr, prop, params->dir);
1613 if (RNA_property_update_check(prop) && !STREQ(params->dir, value)) {
1614 RNA_property_update(C, op->ptr, prop);
1615 }
1616 }
1617 if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1618 RNA_property_string_get(op->ptr, prop, value);
1619 RNA_property_string_set(op->ptr, prop, filepath);
1620 if (RNA_property_update_check(prop) && !STREQ(filepath, value)) {
1621 RNA_property_update(C, op->ptr, prop);
1622 }
1623 }
1624
1625 /* some ops have multiple files to select */
1626 /* this is called on operators check() so clear collections first since
1627 * they may be already set. */
1628 {
1629 int i, numfiles = filelist_files_ensure(sfile->files);
1630
1631 if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
1632 PointerRNA itemptr;
1633 int num_files = 0;
1635 for (i = 0; i < numfiles; i++) {
1637 FileDirEntry *file = filelist_file(sfile->files, i);
1638 /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
1639 if (!file->redirection_path) {
1640 RNA_property_collection_add(op->ptr, prop, &itemptr);
1641 RNA_string_set(&itemptr, "name", file->relpath);
1642 num_files++;
1643 }
1644 }
1645 }
1646 /* make sure the file specified in the filename button is added even if no
1647 * files selected */
1648 if (0 == num_files) {
1649 RNA_property_collection_add(op->ptr, prop, &itemptr);
1650 RNA_string_set(&itemptr, "name", params->file);
1651 }
1652 }
1653
1654 if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
1655 PointerRNA itemptr;
1656 int num_dirs = 0;
1658 for (i = 0; i < numfiles; i++) {
1660 FileDirEntry *file = filelist_file(sfile->files, i);
1661 RNA_property_collection_add(op->ptr, prop, &itemptr);
1662 RNA_string_set(&itemptr, "name", file->relpath);
1663 num_dirs++;
1664 }
1665 }
1666
1667 /* make sure the directory specified in the button is added even if no
1668 * directory selected */
1669 if (0 == num_dirs) {
1670 RNA_property_collection_add(op->ptr, prop, &itemptr);
1671 RNA_string_set(&itemptr, "name", params->dir);
1672 }
1673 }
1674 }
1675}
1677{
1678 char filepath_dummy[FILE_MAX];
1679
1680 file_sfile_to_operator_ex(C, bmain, op, sfile, filepath_dummy);
1681}
1682
1684{
1686 PropertyRNA *prop;
1687
1688 /* If neither of the above are set, split the filepath back */
1689 if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
1690 char filepath[FILE_MAX];
1691 RNA_property_string_get(op->ptr, prop, filepath);
1693 filepath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
1694 }
1695 else {
1696 if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
1697 RNA_property_string_get(op->ptr, prop, params->file);
1698 }
1699 if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
1700 RNA_property_string_get(op->ptr, prop, params->dir);
1701 }
1702 }
1703
1704 /* we could check for relative_path property which is used when converting
1705 * in the other direction but doesn't hurt to do this every time */
1707
1708 /* XXX, files and dirs updates missing, not really so important though */
1709}
1710
1711void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
1712{
1714 BLI_assert(BLI_exists(filepath));
1715
1716 if (BLI_is_dir(filepath)) {
1717 STRNCPY(params->dir, filepath);
1718 }
1719 else {
1720 if ((params->flag & FILE_DIRSEL_ONLY) == 0) {
1722 filepath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
1723 }
1724 else {
1725 BLI_path_split_dir_part(filepath, params->dir, sizeof(params->dir));
1726 }
1727 }
1728}
1729
1731{
1732 /* May happen when manipulating non-active spaces. */
1733 if (UNLIKELY(area->spacetype != SPACE_FILE)) {
1734 return;
1735 }
1736 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1737 wmOperator *op = sfile->op;
1738 if (op) { /* fail on reload */
1739 if (op->type->check) {
1740 Main *bmain = CTX_data_main(C);
1741 file_sfile_to_operator(C, bmain, op, sfile);
1742
1743 /* redraw */
1744 if (op->type->check(C, op)) {
1745 file_operator_to_sfile(bmain, sfile, op);
1746
1747 /* redraw, else the changed settings won't get updated */
1748 ED_area_tag_redraw(area);
1749 }
1750 }
1751 }
1752}
1753
1755{
1756 ScrArea *area = CTX_wm_area(C);
1757 file_draw_check_ex(C, area);
1758}
1759
1760void file_draw_check_cb(bContext *C, void * /*arg1*/, void * /*arg2*/)
1761{
1762 file_draw_check(C);
1763}
1764
1766{
1767 if (sfile->op) { /* fails on reload */
1769 if (params && (params->flag & FILE_CHECK_EXISTING)) {
1770 char filepath[FILE_MAX];
1771 BLI_path_join(filepath, sizeof(filepath), params->dir, params->file);
1772 if (BLI_is_file(filepath)) {
1773 return true;
1774 }
1775 }
1776 }
1777
1778 return false;
1779}
1780
1783/* -------------------------------------------------------------------- */
1788 {FILE_EXTERNAL_OPERATION_OPEN, "OPEN", 0, "Open", "Open the file"},
1789 {FILE_EXTERNAL_OPERATION_FOLDER_OPEN, "FOLDER_OPEN", 0, "Open Folder", "Open the folder"},
1790 {FILE_EXTERNAL_OPERATION_EDIT, "EDIT", 0, "Edit", "Edit the file"},
1791 {FILE_EXTERNAL_OPERATION_NEW, "NEW", 0, "New", "Create a new file of this type"},
1792 {FILE_EXTERNAL_OPERATION_FIND, "FIND", 0, "Find File", "Search for files of this type"},
1793 {FILE_EXTERNAL_OPERATION_SHOW, "SHOW", 0, "Show", "Show this file"},
1794 {FILE_EXTERNAL_OPERATION_PLAY, "PLAY", 0, "Play", "Play this file"},
1795 {FILE_EXTERNAL_OPERATION_BROWSE, "BROWSE", 0, "Browse", "Browse this file"},
1796 {FILE_EXTERNAL_OPERATION_PREVIEW, "PREVIEW", 0, "Preview", "Preview this file"},
1797 {FILE_EXTERNAL_OPERATION_PRINT, "PRINT", 0, "Print", "Print this file"},
1798 {FILE_EXTERNAL_OPERATION_INSTALL, "INSTALL", 0, "Install", "Install this file"},
1799 {FILE_EXTERNAL_OPERATION_RUNAS, "RUNAS", 0, "Run As User", "Run as specific user"},
1801 "PROPERTIES",
1802 0,
1803 "Properties",
1804 "Show OS Properties for this item"},
1806 "FOLDER_FIND",
1807 0,
1808 "Find in Folder",
1809 "Search for items in this folder"},
1811 "CMD",
1812 0,
1813 "Command Prompt Here",
1814 "Open a command prompt here"},
1815 {0, nullptr, 0, nullptr, nullptr}};
1816
1818{
1819 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
1820 char filepath[FILE_MAX];
1821 RNA_property_string_get(op->ptr, prop, filepath);
1822
1824
1825#ifdef WIN32
1827 "operation");
1828 if (BLI_file_external_operation_execute(filepath, operation)) {
1830 return OPERATOR_FINISHED;
1831 }
1832#else
1833 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1834 PointerRNA op_props;
1836 RNA_string_set(&op_props, "filepath", filepath);
1837 const int retval = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
1838 WM_operator_properties_free(&op_props);
1839
1840 if (retval == OPERATOR_FINISHED) {
1842 return OPERATOR_FINISHED;
1843 }
1844#endif
1845
1847 op->reports, RPT_ERROR, "Failure to perform external file operation on \"%s\"", filepath);
1849 return OPERATOR_CANCELLED;
1850}
1851
1853 wmOperatorType * /*ot*/,
1854 PointerRNA *ptr)
1855{
1856 const char *description = "";
1857 RNA_enum_description(file_external_operation, RNA_enum_get(ptr, "operation"), &description);
1858 return TIP_(description);
1859}
1860
1862{
1863 PropertyRNA *prop;
1864
1865 /* identifiers */
1866 ot->name = "External File Operation";
1867 ot->idname = "FILE_OT_external_operation";
1868 ot->description = "Perform external operation on a file or folder";
1869
1870 /* api callbacks */
1873
1874 /* flags */
1875 ot->flag = OPTYPE_REGISTER; /* No undo! */
1876
1877 /* properties */
1878 prop = RNA_def_string(ot->srna, "filepath", nullptr, FILE_MAX, "File or folder path", "");
1880
1882 "operation",
1885 "Operation",
1886 "Operation to perform on the file or path");
1887}
1888
1891 const char *path,
1892 FileExternalOperation operation)
1893{
1894#ifdef WIN32
1895 if (!BLI_file_external_operation_supported(path, operation)) {
1896 return;
1897 }
1898#else
1900 return;
1901 }
1902#endif
1903
1904 const char *title = "";
1905 RNA_enum_name(file_external_operation, operation, &title);
1906
1907 PointerRNA props_ptr;
1908 uiItemFullO_ptr(layout,
1909 ot,
1910 IFACE_(title),
1911 ICON_NONE,
1912 nullptr,
1915 &props_ptr);
1916 RNA_string_set(&props_ptr, "filepath", path);
1917 if (operation) {
1918 RNA_enum_set(&props_ptr, "operation", operation);
1919 }
1920}
1921
1922static void file_os_operations_menu_draw(const bContext *C_const, Menu *menu)
1923{
1924 bContext *C = (bContext *)C_const;
1925
1926 /* File browsing only operator (not asset browsing). */
1928 return;
1929 }
1930
1931 SpaceFile *sfile = CTX_wm_space_file(C);
1933 if (!sfile || !params) {
1934 return;
1935 }
1936
1937 char dir[FILE_MAX_LIBEXTRA];
1938 if (filelist_islibrary(sfile->files, dir, nullptr)) {
1939 return;
1940 }
1941
1942 int numfiles = filelist_files_ensure(sfile->files);
1943 FileDirEntry *fileentry = nullptr;
1944 int num_selected = 0;
1945
1946 for (int i = 0; i < numfiles; i++) {
1948 fileentry = filelist_file(sfile->files, i);
1949 num_selected++;
1950 }
1951 }
1952
1953 if (!fileentry || num_selected > 1) {
1954 return;
1955 }
1956
1957 char path[FILE_MAX_LIBEXTRA];
1958 filelist_file_get_full_path(sfile->files, fileentry, path);
1959 const char *root = filelist_dir(sfile->files);
1960
1961 uiLayout *layout = menu->layout;
1963 wmOperatorType *ot = WM_operatortype_find("FILE_OT_external_operation", true);
1964
1965 if (fileentry->typeflag & FILE_TYPE_DIR) {
1969 }
1970 else {
1985 }
1986}
1987
1988static bool file_os_operations_menu_poll(const bContext *C_const, MenuType * /*mt*/)
1989{
1990 bContext *C = (bContext *)C_const;
1991
1992 /* File browsing only operator (not asset browsing). */
1994 return false;
1995 }
1996
1997 SpaceFile *sfile = CTX_wm_space_file(C);
1999
2000 if (sfile && params) {
2001 char dir[FILE_MAX_LIBEXTRA];
2002 if (filelist_islibrary(sfile->files, dir, nullptr)) {
2003 return false;
2004 }
2005
2006 int numfiles = filelist_files_ensure(sfile->files);
2007 int num_selected = 0;
2008 for (int i = 0; i < numfiles; i++) {
2010 num_selected++;
2011 }
2012 }
2013
2014 if (num_selected > 1) {
2015 CTX_wm_operator_poll_msg_set(C, "More than one item is selected");
2016 }
2017 else if (num_selected < 1) {
2018 CTX_wm_operator_poll_msg_set(C, "No items are selected");
2019 }
2020 else {
2021 return true;
2022 }
2023 }
2024
2025 return false;
2026}
2027
2029{
2030 MenuType *mt;
2031
2032 mt = static_cast<MenuType *>(
2033 MEM_callocN(sizeof(MenuType), "spacetype file menu file operations"));
2034 STRNCPY(mt->idname, "FILEBROWSER_MT_operations_menu");
2035 STRNCPY(mt->label, N_("External"));
2039 WM_menutype_add(mt);
2040}
2041
2044/* -------------------------------------------------------------------- */
2051static bool file_execute(bContext *C, SpaceFile *sfile)
2052{
2053 Main *bmain = CTX_data_main(C);
2055 FileDirEntry *file = filelist_file(sfile->files, params->active_file);
2056
2057 if (file && file->redirection_path) {
2058 /* redirection_path is an absolute path that takes precedence
2059 * over using params->dir + params->file. */
2060 BLI_path_split_dir_file(file->redirection_path,
2061 params->dir,
2062 sizeof(params->dir),
2063 params->file,
2064 sizeof(params->file));
2065 /* Update relpath with redirected filename as well so that the alternative
2066 * combination of params->dir + relpath remains valid as well. */
2067 MEM_freeN(file->relpath);
2068 file->relpath = BLI_strdup(params->file);
2069 }
2070
2071 /* directory change */
2072 if (file && (file->typeflag & FILE_TYPE_DIR)) {
2073 if (!file->relpath) {
2074 return false;
2075 }
2076
2077 if (FILENAME_IS_PARENT(file->relpath)) {
2079 }
2080 else {
2083 BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath);
2084 }
2086 }
2087 /* Opening file, sends events now, so things get handled on window-queue level. */
2088 else if (sfile->op) {
2089 ScrArea *area = CTX_wm_area(C);
2090 FSMenu *fsmenu = ED_fsmenu_get();
2091 wmOperator *op = sfile->op;
2092 char filepath[FILE_MAX];
2093
2094 sfile->op = nullptr;
2095
2096 file_sfile_to_operator_ex(C, bmain, op, sfile, filepath);
2097
2098 if (BLI_exists(params->dir)) {
2099 fsmenu_insert_entry(fsmenu,
2101 params->dir,
2102 nullptr,
2103 ICON_FILE_FOLDER,
2105 }
2106
2108
2110 }
2111
2112 return true;
2113}
2114
2115static int file_exec(bContext *C, wmOperator * /*op*/)
2116{
2117 SpaceFile *sfile = CTX_wm_space_file(C);
2118
2119 if (!file_execute(C, sfile)) {
2120 return OPERATOR_CANCELLED;
2121 }
2122
2123 return OPERATOR_FINISHED;
2124}
2125
2127{
2128 /* identifiers */
2129 ot->name = "Execute File Window";
2130 ot->description = "Execute selected file";
2131 ot->idname = "FILE_OT_execute";
2132
2133 /* api callbacks */
2134 ot->exec = file_exec;
2135 /* Important since handler is on window level.
2136 *
2137 * Avoid using #file_operator_poll since this is also used for entering directories
2138 * which is used even when the file manager doesn't have an operator. */
2140}
2141
2146{
2148 if (file_select(C, &rect, FILE_SEL_ADD, false, false) == FILE_SELECT_NOTHING) {
2149 return false;
2150 }
2151
2152 return true;
2153}
2154
2155static int file_execute_mouse_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2156{
2157 ARegion *region = CTX_wm_region(C);
2158 SpaceFile *sfile = CTX_wm_space_file(C);
2159
2161 sfile->layout, &region->v2d, event->mval[0], event->mval[1]))
2162 {
2164 }
2165
2166 /* Note that this isn't needed practically, because the keymap already activates the hovered item
2167 * on mouse-press. This execute operator is called afterwards on the double-click event then.
2168 * However relying on this would be fragile and could break with keymap changes, so better to
2169 * have this mouse-execute operator that makes sure once more that the hovered file is active. */
2170 if (!file_ensure_hovered_is_active(C, event)) {
2171 return OPERATOR_CANCELLED;
2172 }
2173
2174 if (!file_execute(C, sfile)) {
2175 return OPERATOR_CANCELLED;
2176 }
2177
2178 return OPERATOR_FINISHED;
2179}
2180
2182{
2183 /* identifiers */
2184 ot->name = "Execute File";
2185 ot->description =
2186 "Perform the current execute action for the file under the cursor (e.g. open the file)";
2187 ot->idname = "FILE_OT_mouse_execute";
2188
2189 /* api callbacks */
2192
2194}
2195
2198/* -------------------------------------------------------------------- */
2202static int file_refresh_exec(bContext *C, wmOperator * /*unused*/)
2203{
2205 SpaceFile *sfile = CTX_wm_space_file(C);
2206 FSMenu *fsmenu = ED_fsmenu_get();
2207
2208 ED_fileselect_clear(wm, sfile);
2209
2210 /* refresh system directory menu */
2212
2213 /* Update bookmarks 'valid' state. */
2215
2217
2218 return OPERATOR_FINISHED;
2219}
2220
2222{
2223 /* identifiers */
2224 ot->name = "Refresh File List";
2225 ot->description = "Refresh the file list";
2226 ot->idname = "FILE_OT_refresh";
2227
2228 /* api callbacks */
2230 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2231}
2232
2235/* -------------------------------------------------------------------- */
2239static int file_parent_exec(bContext *C, wmOperator * /*unused*/)
2240{
2241 Main *bmain = CTX_data_main(C);
2242 SpaceFile *sfile = CTX_wm_space_file(C);
2244
2245 if (params) {
2246 if (BLI_path_parent_dir(params->dir)) {
2248 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
2250 if (params->recursion_level > 1) {
2251 /* Disable 'dirtree' recursion when going up in tree. */
2252 params->recursion_level = 0;
2253 filelist_setrecursion(sfile->files, params->recursion_level);
2254 }
2256 }
2257 }
2258
2259 return OPERATOR_FINISHED;
2260}
2261
2263{
2264 /* identifiers */
2265 ot->name = "Parent Directory";
2266 ot->description = "Move to parent directory";
2267 ot->idname = "FILE_OT_parent";
2268
2269 /* api callbacks */
2271 /* File browsing only operator (not asset browsing). */
2272 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2273}
2274
2277/* -------------------------------------------------------------------- */
2282{
2283 SpaceFile *sfile = CTX_wm_space_file(C);
2285
2286 if (params) {
2290
2292 }
2294
2295 return OPERATOR_FINISHED;
2296}
2297
2299{
2300 /* identifiers */
2301 ot->name = "Previous Folder";
2302 ot->description = "Move to previous folder";
2303 ot->idname = "FILE_OT_previous";
2304
2305 /* api callbacks */
2307 /* File browsing only operator (not asset browsing). */
2308 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2309}
2310
2313/* -------------------------------------------------------------------- */
2317static int file_next_exec(bContext *C, wmOperator * /*unused*/)
2318{
2319 SpaceFile *sfile = CTX_wm_space_file(C);
2321 if (params) {
2324
2325 /* update folders_prev so we can check for it in #folderlist_clear_next() */
2327
2329 }
2331
2332 return OPERATOR_FINISHED;
2333}
2334
2336{
2337 /* identifiers */
2338 ot->name = "Next Folder";
2339 ot->description = "Move to next folder";
2340 ot->idname = "FILE_OT_next";
2341
2342 /* api callbacks */
2344 /* File browsing only operator (not asset browsing). */
2345 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2346}
2347
2350/* -------------------------------------------------------------------- */
2354/* only meant for timer usage */
2355static int file_smoothscroll_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
2356{
2357 ScrArea *area = CTX_wm_area(C);
2358 SpaceFile *sfile = CTX_wm_space_file(C);
2359 ARegion *region, *region_ctx = CTX_wm_region(C);
2360 const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
2361 int i;
2362
2363 /* escape if not our timer */
2364 if (sfile->smoothscroll_timer == nullptr || sfile->smoothscroll_timer != event->customdata) {
2365 return OPERATOR_PASS_THROUGH;
2366 }
2367
2368 const int numfiles = filelist_files_ensure(sfile->files);
2369
2370 /* Due to asynchronous nature of file listing, we may execute this code before `file_refresh()`
2371 * editing entry is available in our listing,
2372 * so we also have to handle switching to rename mode here. */
2374 if ((params->rename_flag &
2376 {
2378 }
2379
2380 /* check if we are editing a name */
2381 int edit_idx = -1;
2382 for (i = 0; i < numfiles; i++) {
2385 {
2386 edit_idx = i;
2387 break;
2388 }
2389 }
2390
2392 wmWindow *win = CTX_wm_window(C);
2393
2394 /* if we are not editing, we are done */
2395 if (edit_idx == -1) {
2396 /* Do not invalidate timer if file-rename is still pending,
2397 * we might still be building the filelist and yet have to find edited entry. */
2398 if (params->rename_flag == 0) {
2400 }
2401 return OPERATOR_PASS_THROUGH;
2402 }
2403
2404 /* we need the correct area for scrolling */
2406 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2408 return OPERATOR_PASS_THROUGH;
2409 }
2410
2411 /* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
2412 * in vertical layout).
2413 */
2414 const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
2415
2416 /* Scroll offset is the first file in the row/column we are editing in. */
2417 if (sfile->scroll_offset == 0) {
2418 sfile->scroll_offset = (edit_idx / items_block_size) * items_block_size;
2419 }
2420
2421 const int numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, region);
2422 const int first_visible_item = ED_fileselect_layout_offset(
2423 sfile->layout, int(region->v2d.cur.xmin), int(-region->v2d.cur.ymax));
2424 const int last_visible_item = first_visible_item + numfiles_layout + 1;
2425
2426 /* NOTE: the special case for vertical layout is because filename is at the bottom of items then,
2427 * so we artificially move current row back one step, to ensure we show bottom of
2428 * active item rather than its top (important in case visible height is low). */
2429 const int middle_offset = max_ii(
2430 0, (first_visible_item + last_visible_item) / 2 - (is_horizontal ? 0 : items_block_size));
2431
2432 const int min_middle_offset = numfiles_layout / 2;
2433 const int max_middle_offset = ((numfiles / items_block_size) * items_block_size +
2434 ((numfiles % items_block_size) != 0 ? items_block_size : 0)) -
2435 (numfiles_layout / 2);
2436 /* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the
2437 * beginning/end of the view. */
2438 /* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf...
2439 * that is why we still need to keep the min/max_middle_offset checks too. :( */
2440 const float min_tot_scroll = is_horizontal ? region->v2d.tot.xmin : -region->v2d.tot.ymax;
2441 const float max_tot_scroll = is_horizontal ? region->v2d.tot.xmax : -region->v2d.tot.ymin;
2442 const float min_curr_scroll = is_horizontal ? region->v2d.cur.xmin : -region->v2d.cur.ymax;
2443 const float max_curr_scroll = is_horizontal ? region->v2d.cur.xmax : -region->v2d.cur.ymin;
2444
2445 /* Check if we have reached our final scroll position. */
2446 /* File-list has to be ready, otherwise it makes no sense to stop scrolling yet. */
2447 const bool is_ready = filelist_is_ready(sfile->files);
2448 /* Edited item must be in the 'middle' of shown area (kind of approximated).
2449 * Note that we have to do the check in 'block space', not in 'item space' here. */
2450 const bool is_centered = (abs(middle_offset / items_block_size -
2451 sfile->scroll_offset / items_block_size) == 0);
2452 /* OR edited item must be towards the beginning, and we are scrolled fully to the start. */
2453 const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) &&
2454 (min_curr_scroll - min_tot_scroll < 1.0f) &&
2455 (middle_offset - min_middle_offset < items_block_size));
2456 /* OR edited item must be towards the end, and we are scrolled fully to the end.
2457 * This one is crucial (unlike the one for the beginning), because without it we won't scroll
2458 * fully to the end, and last column or row will end up only partially drawn. */
2459 const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) &&
2460 (max_tot_scroll - max_curr_scroll < 1.0f) &&
2461 (max_middle_offset - middle_offset < items_block_size));
2462
2463 if (is_ready && (is_centered || is_full_start || is_full_end)) {
2465 /* Post-scroll (after rename has been validated by user) is done,
2466 * rename process is totally finished, cleanup. */
2467 if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) {
2469 }
2470 return OPERATOR_FINISHED;
2471 }
2472
2473 /* Temporarily set context to the main window region,
2474 * so that the pan operator works. */
2475 CTX_wm_region_set(C, region);
2476
2477 /* scroll one step in the desired direction */
2478 PointerRNA op_ptr;
2479 int deltax = 0;
2480 int deltay = 0;
2481
2482 /* We adjust speed of scrolling to avoid tens of seconds of it in e.g. directories with tens of
2483 * thousands of folders... See #65782. */
2484 /* This will slow down scrolling when approaching final goal, also avoids going too far and
2485 * having to bounce back... */
2486
2487 /* Number of blocks (columns in horizontal layout, rows otherwise) between current middle of
2488 * screen, and final goal position. */
2489 const int diff_offset = sfile->scroll_offset / items_block_size -
2490 middle_offset / items_block_size;
2491 /* convert diff_offset into pixels. */
2492 const int diff_offset_delta = abs(diff_offset) *
2493 (is_horizontal ?
2494 sfile->layout->tile_w + 2 * sfile->layout->tile_border_x :
2495 sfile->layout->tile_h + 2 * sfile->layout->tile_border_y);
2496 const int scroll_delta = max_ii(2, diff_offset_delta / 15);
2497
2498 if (diff_offset < 0) {
2499 if (is_horizontal) {
2500 deltax = -scroll_delta;
2501 }
2502 else {
2503 deltay = scroll_delta;
2504 }
2505 }
2506 else {
2507 if (is_horizontal) {
2508 deltax = scroll_delta;
2509 }
2510 else {
2511 deltay = -scroll_delta;
2512 }
2513 }
2514 WM_operator_properties_create(&op_ptr, "VIEW2D_OT_pan");
2515 RNA_int_set(&op_ptr, "deltax", deltax);
2516 RNA_int_set(&op_ptr, "deltay", deltay);
2517
2518 WM_operator_name_call(C, "VIEW2D_OT_pan", WM_OP_EXEC_DEFAULT, &op_ptr, event);
2520
2521 ED_region_tag_redraw(region);
2522
2523 /* and restore context */
2524 CTX_wm_region_set(C, region_ctx);
2525
2526 return OPERATOR_FINISHED;
2527}
2528
2530{
2531 /* identifiers */
2532 ot->name = "Smooth Scroll";
2533 ot->idname = "FILE_OT_smoothscroll";
2534 ot->description = "Smooth scroll to make editable file visible";
2535
2536 /* api callbacks */
2538 /* Operator works for file or asset browsing */
2540}
2541
2544/* -------------------------------------------------------------------- */
2549{
2550 Main *bmain = CTX_data_main(C);
2551 SpaceFile *sfile = CTX_wm_space_file(C);
2552
2553 if (sfile) {
2554 char filepath[FILE_MAX];
2555
2556 RNA_string_get(op->ptr, "filepath", filepath);
2557 if (!BLI_exists(filepath)) {
2558 BKE_report(op->reports, RPT_ERROR, "File does not exist");
2559 return OPERATOR_CANCELLED;
2560 }
2561
2562 file_sfile_filepath_set(sfile, filepath);
2563
2564 if (sfile->op) {
2565 file_sfile_to_operator(C, bmain, sfile->op, sfile);
2566 file_draw_check(C);
2567 }
2568
2570 return OPERATOR_FINISHED;
2571 }
2572
2573 return OPERATOR_CANCELLED;
2574}
2575
2577{
2578 ot->name = "File Selector Drop";
2579 ot->idname = "FILE_OT_filepath_drop";
2580
2582 /* File browsing only operator (not asset browsing). */
2584
2585 RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", "");
2586}
2587
2590/* -------------------------------------------------------------------- */
2600static bool new_folder_path(const char *parent,
2601 char r_dirpath_full[FILE_MAX],
2602 char r_dirname[FILE_MAXFILE])
2603{
2604 int i = 1;
2605 int len = 0;
2606
2607 BLI_strncpy(r_dirname, "New Folder", FILE_MAXFILE);
2608 BLI_path_join(r_dirpath_full, FILE_MAX, parent, r_dirname);
2609 /* check whether r_dirpath_full with the name already exists, in this case
2610 * add number to the name. Check length of generated name to avoid
2611 * crazy case of huge number of folders each named 'New Folder (x)' */
2612 while (BLI_exists(r_dirpath_full) && (len < FILE_MAXFILE)) {
2613 len = BLI_snprintf(r_dirname, FILE_MAXFILE, "New Folder(%d)", i);
2614 BLI_path_join(r_dirpath_full, FILE_MAX, parent, r_dirname);
2615 i++;
2616 }
2617
2618 return (len < FILE_MAXFILE);
2619}
2620
2622{
2623 char dirname[FILE_MAXFILE];
2624 char dirpath[FILE_MAX];
2625 bool generate_name = true;
2626
2628 SpaceFile *sfile = CTX_wm_space_file(C);
2630 const bool do_diropen = RNA_boolean_get(op->ptr, "open");
2631
2632 if (!params) {
2633 BKE_report(op->reports, RPT_WARNING, "No parent directory given");
2634 return OPERATOR_CANCELLED;
2635 }
2636
2637 dirpath[0] = '\0';
2638
2639 {
2640 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "directory");
2641 RNA_property_string_get(op->ptr, prop, dirpath);
2642 if (dirpath[0] != '\0') {
2643 generate_name = false;
2644 }
2645 }
2646
2647 if (generate_name) {
2648 /* create a new, non-existing folder name */
2649 if (!new_folder_path(params->dir, dirpath, dirname)) {
2650 BKE_report(op->reports, RPT_ERROR, "Could not create new folder name");
2651 return OPERATOR_CANCELLED;
2652 }
2653 }
2654 else { /* We assume we are able to generate a valid name! */
2655 char org_path[FILE_MAX];
2656
2657 STRNCPY(org_path, dirpath);
2658 if (BLI_path_make_safe(dirpath)) {
2659 BKE_reportf(op->reports,
2661 "'%s' given path is OS-invalid, creating '%s' path instead",
2662 org_path,
2663 dirpath);
2664 }
2665 }
2666
2667 /* create the file */
2668 errno = 0;
2669 if (!BLI_dir_create_recursive(dirpath) ||
2670 /* Should no more be needed,
2671 * now that BLI_dir_create_recursive returns a success state - but kept just in case. */
2672 !BLI_exists(dirpath))
2673 {
2674 BKE_reportf(op->reports,
2675 RPT_ERROR,
2676 "Could not create new folder: %s",
2677 errno ? strerror(errno) : "unknown error");
2678 return OPERATOR_CANCELLED;
2679 }
2680
2682
2683 /* If we don't enter the directory directly, remember file to jump into editing. */
2684 if (do_diropen == false) {
2685 BLI_assert_msg(params->rename_id == nullptr,
2686 "File rename handling should immediately clear rename_id when done, "
2687 "because otherwise it will keep taking precedence over renamefile.");
2688 STRNCPY(params->renamefile, dirname);
2689 rename_flag = FILE_PARAMS_RENAME_PENDING;
2690 }
2691
2693 params->rename_flag = rename_flag;
2694
2695 /* reload dir to make sure we're seeing what's in the directory */
2696 ED_fileselect_clear(wm, sfile);
2697
2698 if (do_diropen) {
2699 STRNCPY(params->dir, dirpath);
2701 }
2702
2704
2705 return OPERATOR_FINISHED;
2706}
2707
2708static int file_directory_new_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2709{
2710 /* NOTE: confirm is needed because this operator is invoked
2711 * when entering a path from the file selector. Without a confirmation,
2712 * a typo will create the path without any prompt. See #128567. */
2713 if (RNA_boolean_get(op->ptr, "confirm")) {
2715 C, op, IFACE_("Create new directory?"), nullptr, IFACE_("Create"), ALERT_ICON_NONE, false);
2716 }
2717 return file_directory_new_exec(C, op);
2718}
2719
2721{
2722 PropertyRNA *prop;
2723
2724 /* identifiers */
2725 ot->name = "Create New Directory";
2726 ot->description = "Create a new directory";
2727 ot->idname = "FILE_OT_directory_new";
2728
2729 /* api callbacks */
2732 /* File browsing only operator (not asset browsing). */
2733 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2734
2736 ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Name of new directory");
2738 prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
2741}
2742
2745/* -------------------------------------------------------------------- */
2749/* TODO: This should go to BLI_path_utils. */
2751{
2752 Main *bmain = CTX_data_main(C);
2753 SpaceFile *sfile = CTX_wm_space_file(C);
2755
2756 if (params) {
2757 if (BLI_path_is_rel(params->dir)) {
2758 /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
2759 const char *blendfile_path = BKE_main_blendfile_path(bmain);
2760 BLI_path_abs(params->dir,
2761 (blendfile_path[0] != '\0') ? blendfile_path :
2763 }
2764 else if (params->dir[0] == '~') {
2765 /* While path handling expansion typically doesn't support home directory expansion
2766 * in Blender, this is a convenience to be able to type in a single character.
2767 * Even though this is a UNIX convention, it's harmless to expand on WIN32 as well. */
2768 if (const char *home_dir = BKE_appdir_folder_home()) {
2769 char tmpstr[sizeof(params->dir) - 1];
2770 STRNCPY(tmpstr, params->dir + 1);
2771 BLI_path_join(params->dir, sizeof(params->dir), home_dir, tmpstr);
2772 }
2773 else {
2774 /* Fall back to the default root. */
2775 params->dir[0] = '\0';
2776 }
2777 }
2778
2779 if (params->dir[0] == '\0')
2780#ifndef WIN32
2781 {
2782 params->dir[0] = '/';
2783 params->dir[1] = '\0';
2784 }
2785#else
2786 {
2788 }
2789 /* Change `C:` --> `C:\`, #28102. */
2790 else if (BLI_path_is_win32_drive_only(params->dir)) {
2791 params->dir[2] = SEP;
2792 params->dir[3] = '\0';
2793 }
2794 else if (BLI_path_is_unc(params->dir)) {
2795 BLI_path_normalize_unc(params->dir, FILE_MAX_LIBEXTRA);
2796 }
2797#endif
2798 }
2799}
2800
2801/* TODO: check we still need this, it's annoying to have OS-specific code here... :/. */
2802#if defined(WIN32)
2803static bool can_create_dir(const char *dir)
2804{
2805 /* for UNC paths we need to check whether the parent of the new
2806 * directory is a proper directory itself and not a share or the
2807 * UNC root (server name) itself. Calling BLI_is_dir does this
2808 */
2809 if (BLI_path_is_unc(dir)) {
2810 char parent[PATH_MAX];
2811 BLI_strncpy(parent, dir, PATH_MAX);
2812 BLI_path_parent_dir(parent);
2813 return BLI_is_dir(parent);
2814 }
2815 return true;
2816}
2817#endif
2818
2819void file_directory_enter_handle(bContext *C, void * /*arg_unused*/, void * /*arg_but*/)
2820{
2821 Main *bmain = CTX_data_main(C);
2822 SpaceFile *sfile = CTX_wm_space_file(C);
2824
2825 if (params) {
2826 char old_dir[sizeof(params->dir)];
2827
2828 STRNCPY(old_dir, params->dir);
2829
2831
2832 /* special case, user may have pasted a filepath into the directory */
2833 if (!filelist_is_dir(sfile->files, params->dir)) {
2834 char tdir[FILE_MAX_LIBEXTRA];
2835 char *group, *name;
2836
2837 if (BLI_is_file(params->dir)) {
2838 char dirpath[sizeof(params->dir)];
2839 STRNCPY(dirpath, params->dir);
2841 dirpath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
2842 }
2843 else if (BKE_blendfile_library_path_explode(params->dir, tdir, &group, &name)) {
2844 if (group) {
2845 BLI_path_append(tdir, sizeof(tdir), group);
2846 }
2847 STRNCPY(params->dir, tdir);
2848 if (name) {
2849 STRNCPY(params->file, name);
2850 }
2851 else {
2852 params->file[0] = '\0';
2853 }
2854 }
2855 }
2856
2858 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
2859
2860 if (filelist_is_dir(sfile->files, params->dir)) {
2861 if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
2862 /* if directory exists, enter it immediately */
2864 }
2865
2866 /* don't do for now because it selects entire text instead of
2867 * placing cursor at the end */
2868 // UI_textbutton_activate_but(C, but);
2869 }
2870#if defined(WIN32)
2871 else if (!can_create_dir(params->dir)) {
2872 const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2873 if (lastdir) {
2874 STRNCPY(params->dir, lastdir);
2875 }
2876 }
2877#endif
2878 else {
2879 const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
2880 char tdir[FILE_MAX_LIBEXTRA];
2881
2882 /* If we are 'inside' a blend library, we cannot do anything... */
2883 if (lastdir && BKE_blendfile_library_path_explode(lastdir, tdir, nullptr, nullptr)) {
2884 STRNCPY(params->dir, lastdir);
2885 }
2886 else {
2887 /* if not, ask to create it and enter if confirmed */
2888 wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
2891 RNA_string_set(&ptr, "directory", params->dir);
2892 RNA_boolean_set(&ptr, "open", true);
2893 /* Enable confirmation prompt, else it's too easy
2894 * to accidentally create new directories. */
2895 RNA_boolean_set(&ptr, "confirm", true);
2896
2897 if (lastdir) {
2898 STRNCPY(params->dir, lastdir);
2899 }
2900
2903 }
2904 }
2905
2907 }
2908}
2909
2910void file_filename_enter_handle(bContext *C, void * /*arg_unused*/, void *arg_but)
2911{
2912 Main *bmain = CTX_data_main(C);
2913 SpaceFile *sfile = CTX_wm_space_file(C);
2915 uiBut *but = static_cast<uiBut *>(arg_but);
2916 char matched_file[FILE_MAX];
2917
2918 if (params) {
2919 char filepath[sizeof(params->dir)];
2920 int matches;
2921 matched_file[0] = '\0';
2922 filepath[0] = '\0';
2923
2925
2926 matches = file_select_match(sfile, params->file, matched_file);
2927
2928 /* *After* file_select_match! */
2929 const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
2930 BLI_path_make_safe_filename_ex(params->file, allow_tokens);
2931
2932 if (matches) {
2933 /* replace the pattern (or filename that the user typed in,
2934 * with the first selected file of the match */
2935 STRNCPY(params->file, matched_file);
2936
2938 }
2939
2940 if (matches == 1) {
2941 BLI_path_join(filepath, sizeof(params->dir), params->dir, params->file);
2942
2943 /* if directory, open it and empty filename field */
2944 if (filelist_is_dir(sfile->files, filepath)) {
2945 BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
2946 BLI_path_normalize_dir(filepath, sizeof(filepath));
2947 STRNCPY(params->dir, filepath);
2948 params->file[0] = '\0';
2952 }
2953 }
2954 else if (matches > 1) {
2955 file_draw_check(C);
2956 }
2957 }
2958}
2959
2962/* -------------------------------------------------------------------- */
2966static int file_hidedot_exec(bContext *C, wmOperator * /*unused*/)
2967{
2969 SpaceFile *sfile = CTX_wm_space_file(C);
2971
2972 if (params) {
2973 params->flag ^= FILE_HIDE_DOT;
2974 ED_fileselect_clear(wm, sfile);
2976 }
2977
2978 return OPERATOR_FINISHED;
2979}
2980
2982{
2983 /* identifiers */
2984 ot->name = "Toggle Hide Dot Files";
2985 ot->description = "Toggle hide hidden dot files";
2986 ot->idname = "FILE_OT_hidedot";
2987
2988 /* api callbacks */
2990 /* File browsing only operator (not asset browsing). */
2991 ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */
2992}
2993
2996/* -------------------------------------------------------------------- */
3001{
3002 SpaceFile *sfile = CTX_wm_space_file(C);
3003
3004 /* File browsing only operator (not asset browsing). */
3006 return false;
3007 }
3008
3010 return params && (params->flag & FILE_CHECK_EXISTING);
3011}
3012
3017static void filenum_newname(char *filename, size_t filename_maxncpy, int add)
3018{
3019 char head[FILE_MAXFILE], tail[FILE_MAXFILE];
3020 int pic;
3021 ushort digits;
3022
3023 pic = BLI_path_sequence_decode(filename, head, sizeof(head), tail, sizeof(tail), &digits);
3024
3025 /* are we going from 100 -> 99 or from 10 -> 9 */
3026 if (add < 0 && digits > 0) {
3027 int i, exp;
3028 exp = 1;
3029 for (i = digits; i > 1; i--) {
3030 exp *= 10;
3031 }
3032 if (pic >= exp && (pic + add) < exp) {
3033 digits--;
3034 }
3035 }
3036
3037 pic += add;
3038 if (pic < 0) {
3039 pic = 0;
3040 }
3041 BLI_path_sequence_encode(filename, filename_maxncpy, head, tail, digits, pic);
3042}
3043
3045{
3046 SpaceFile *sfile = CTX_wm_space_file(C);
3048 ScrArea *area = CTX_wm_area(C);
3049
3050 int inc = RNA_int_get(op->ptr, "increment");
3051 if (params && (inc != 0)) {
3052 filenum_newname(params->file, sizeof(params->file), inc);
3053 ED_area_tag_redraw(area);
3054 file_draw_check(C);
3055 // WM_event_add_notifier(C, NC_WINDOW, nullptr);
3056 }
3057
3058 return OPERATOR_FINISHED;
3059}
3060
3062{
3063 /* identifiers */
3064 ot->name = "Increment Number in Filename";
3065 ot->description = "Increment number in filename";
3066 ot->idname = "FILE_OT_filenum";
3067
3068 /* api callbacks */
3071
3072 /* props */
3073 RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
3074}
3075
3078/* -------------------------------------------------------------------- */
3082static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
3083{
3084 const int numfiles = filelist_files_ensure(sfile->files);
3085
3086 if ((file_idx >= 0) && (file_idx < numfiles)) {
3087 FileDirEntry *file = filelist_file(sfile->files, file_idx);
3088
3089 if ((require_selected == false) ||
3091 {
3093
3095 sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
3096 STRNCPY(params->renamefile, file->relpath);
3097 /* We can skip the pending state,
3098 * as we can directly set FILE_SEL_EDITING on the expected entry here. */
3099 params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
3100 }
3101 }
3102}
3103
3104static int file_rename_exec(bContext *C, wmOperator * /*op*/)
3105{
3106 ScrArea *area = CTX_wm_area(C);
3107 SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
3109
3110 if (params) {
3111 file_rename_state_activate(sfile, params->active_file, false);
3112 ED_area_tag_redraw(area);
3113 }
3114
3115 return OPERATOR_FINISHED;
3116}
3117
3119{
3120 /* identifiers */
3121 ot->name = "Rename File or Directory";
3122 ot->description = "Rename file or file directory";
3123 ot->idname = "FILE_OT_rename";
3124
3125 /* api callbacks */
3127 /* File browsing only operator (not asset browsing). */
3129}
3130
3133/* -------------------------------------------------------------------- */
3138{
3140 return false;
3141 }
3142
3143 SpaceFile *sfile = CTX_wm_space_file(C);
3145 if (!sfile || !params) {
3146 return false;
3147 }
3148
3149 char dir[FILE_MAX_LIBEXTRA];
3150 if (filelist_islibrary(sfile->files, dir, nullptr)) {
3151 return false;
3152 }
3153
3154 int numfiles = filelist_files_ensure(sfile->files);
3155 for (int i = 0; i < numfiles; i++) {
3157 /* Has a selected file -> the operator can run. */
3158 return true;
3159 }
3160 }
3161
3162 return false;
3163}
3164
3165static bool file_delete_single(const FileList *files,
3166 FileDirEntry *file,
3167 const char **r_error_message)
3168{
3169 char filepath[FILE_MAX_LIBEXTRA];
3170 filelist_file_get_full_path(files, file, filepath);
3171 if (BLI_delete_soft(filepath, r_error_message) != 0 || BLI_exists(filepath)) {
3172 return false;
3173 }
3174
3175 return true;
3176}
3177
3179{
3181 SpaceFile *sfile = CTX_wm_space_file(C);
3182 int numfiles = filelist_files_ensure(sfile->files);
3183
3184 const char *error_message = nullptr;
3185 bool report_error = false;
3186 errno = 0;
3187 for (int i = 0; i < numfiles; i++) {
3189 FileDirEntry *file = filelist_file(sfile->files, i);
3190 if (!file_delete_single(sfile->files, file, &error_message)) {
3191 report_error = true;
3192 }
3193 }
3194 }
3195
3196 if (report_error) {
3197 const char *error_prefix = "Could not delete file or directory: ";
3198 const char *errno_message = errno ? strerror(errno) : "unknown error";
3199 if (error_message != nullptr) {
3200 BKE_reportf(op->reports, RPT_ERROR, "%s%s, %s", error_prefix, error_message, errno_message);
3201 }
3202 else {
3203 BKE_reportf(op->reports, RPT_ERROR, "%s%s", error_prefix, errno_message);
3204 }
3205 }
3206
3207 ED_fileselect_clear(wm, sfile);
3209
3210 return OPERATOR_FINISHED;
3211}
3212
3213static int file_delete_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
3214{
3216 C, op, IFACE_("Delete selected files?"), nullptr, IFACE_("Delete"), ALERT_ICON_NONE, false);
3217}
3218
3220{
3221 /* identifiers */
3222 ot->name = "Delete Selected Files";
3223 ot->description = "Move selected files to the trash or recycle bin";
3224 ot->idname = "FILE_OT_delete";
3225
3226 /* api callbacks */
3229 ot->poll = file_delete_poll; /* <- important, handler is on window level */
3230}
3231
3234/* -------------------------------------------------------------------- */
3239{
3240 const ScrArea *area = CTX_wm_area(C);
3241 const SpaceFile *sfile = CTX_wm_space_file(C);
3243
3244 if (area) {
3245 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3246 if (UI_textbutton_activate_rna(C, region, params, "filter_search")) {
3247 break;
3248 }
3249 }
3250 }
3251
3252 return OPERATOR_FINISHED;
3253}
3254
3256{
3257 /* identifiers */
3258 ot->name = "Filter";
3259 ot->description = "Start entering filter text";
3260 ot->idname = "FILE_OT_start_filter";
3261
3262 /* api callbacks */
3264 /* Operator works for file or asset browsing */
3266}
3267
3270/* -------------------------------------------------------------------- */
3275{
3276 const ScrArea *area = CTX_wm_area(C);
3277 const SpaceFile *sfile = CTX_wm_space_file(C);
3279
3280 if (area) {
3281 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3282 if (UI_textbutton_activate_rna(C, region, params, "directory")) {
3283 break;
3284 }
3285 }
3286 }
3287
3288 return OPERATOR_FINISHED;
3289}
3290
3292{
3293 /* identifiers */
3294 ot->name = "Edit Directory Path";
3295 ot->description = "Start editing directory field";
3296 ot->idname = "FILE_OT_edit_directory_path";
3297
3298 /* api callbacks */
3301}
3302
3305/* -------------------------------------------------------------------- */
3310{
3311 // wmOperatorType *ot;
3312 // wmOperatorTypeMacro *otmacro;
3313
3314 /* future macros */
3315}
3316
#define BLENDER_BOOKMARK_FILE
@ BLENDER_USER_CONFIG
const char * BKE_appdir_folder_home()
Definition appdir.cc:172
const char * BKE_appdir_folder_default_or_root() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:163
std::optional< std::string > BKE_appdir_folder_id_create(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:764
bool BKE_blendfile_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition blendfile.cc:89
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:832
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:125
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
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:438
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:433
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation)
Definition fileops_c.cc:157
#define PATH_MAX
Definition BLI_fileops.h:30
#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_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(...)
#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.c:149
int BLI_rcti_length_y(const rcti *rect, int y)
Definition rct.c:160
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
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.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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.
void BLI_windows_get_default_root_dir(char root_dir[4])
const char * dirname(char *path)
#define TIP_(msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
@ 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_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
FSMenuEntry * ED_fsmenu_get_entry(FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition fsmenu.cc:110
int ED_fsmenu_get_nentries(FSMenu *fsmenu, FSMenuCategory category)
Definition fsmenu.cc:98
FSMenu * ED_fsmenu_get()
Definition fsmenu.cc:45
#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:739
FileSelectParams * ED_fileselect_get_active_params(const SpaceFile *sfile)
Definition filesel.cc:380
void ED_fsmenu_set_category(FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
Definition fsmenu.cc:77
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
Definition filesel.cc:823
FileLayout * ED_fileselect_get_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1140
FSMenuEntry * ED_fsmenu_get_category(FSMenu *fsmenu, FSMenuCategory category)
Definition fsmenu.cc:53
FSMenuInsert
@ FS_INSERT_SAVE
@ FS_INSERT_FIRST
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *rect)
Definition filesel.cc:773
FileAttributeColumnType
@ COLUMN_NONE
bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
Definition filesel.cc:857
bool ED_fileselect_layout_isect_rect(const FileLayout *layout, const View2D *v2d, const rcti *rect, rcti *r_dst)
Definition filesel.cc:864
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1289
void ED_file_change_dir(bContext *C)
Definition filesel.cc:1181
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
bool ED_operator_file_browsing_active(bContext *C)
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:737
bool ED_operator_file_active(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ UI_SELECT_WALK_RIGHT
@ UI_SELECT_WALK_UP
@ UI_SELECT_WALK_LEFT
@ UI_SELECT_WALK_DOWN
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
eSelectOp
@ SEL_OP_SUB
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_ITEM_NONE
bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
@ ALERT_ICON_NONE
void UI_view2d_curRect_validate(View2D *v2d)
Definition view2d.cc:824
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:1663
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1670
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:160
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define ND_SPACE_FILE_PARAMS
Definition WM_types.hh:489
#define NC_SPACE
Definition WM_types.hh:359
#define ND_SPACE_FILE_LIST
Definition WM_types.hh:490
FILE * file
int len
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
const char * folderlist_peeklastdir(ListBase *folderlist)
void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1337
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1343
bool file_attribute_column_header_is_inside(const View2D *v2d, const FileLayout *layout, int x, int y)
Definition filesel.cc:890
void file_params_renamefile_clear(FileSelectParams *params)
Definition filesel.cc:1373
int file_select_match(SpaceFile *sfile, const char *pattern, char *matched_file)
Definition filesel.cc:1196
void fileselect_file_set(bContext *C, SpaceFile *sfile, int index)
Definition filesel.cc:725
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:918
void file_select_deselect_all(SpaceFile *sfile, eDirEntry_SelectFlag flag)
Definition filesel.cc:1187
void folderlist_popdir(ListBase *folderlist, char *dir)
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:1387
void FILE_OT_parent(wmOperatorType *ot)
Definition file_ops.cc:2262
void FILE_OT_select_box(wmOperatorType *ot)
Definition file_ops.cc:530
void FILE_OT_directory_new(wmOperatorType *ot)
Definition file_ops.cc:2720
void file_draw_check(bContext *C)
Definition file_ops.cc:1754
void FILE_OT_edit_directory_path(wmOperatorType *ot)
Definition file_ops.cc:3291
void FILE_OT_bookmark_add(wmOperatorType *ot)
Definition file_ops.cc:1156
static int file_refresh_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2202
static std::string file_external_operation_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
Definition file_ops.cc:1852
static int file_next_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2317
void FILE_OT_select_bookmark(wmOperatorType *ot)
Definition file_ops.cc:1115
static int file_highlight_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:1450
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:828
static int file_previous_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2281
void file_directory_enter_handle(bContext *C, void *, void *)
Definition file_ops.cc:2819
static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *region, const rcti *rect_region)
Definition file_ops.cc:59
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:708
static int file_cancel_exec(bContext *C, wmOperator *)
Definition file_ops.cc:1550
void ED_operatormacros_file()
Definition file_ops.cc:3309
void FILE_OT_refresh(wmOperatorType *ot)
Definition file_ops.cc:2221
static int file_rename_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3104
void FILE_OT_mouse_execute(wmOperatorType *ot)
Definition file_ops.cc:2181
static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition file_ops.cc:442
static bool file_bookmark_move_poll(bContext *C)
Definition file_ops.cc:1322
static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:915
static void filenum_newname(char *filename, size_t filename_maxncpy, int add)
Definition file_ops.cc:3017
static int file_box_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:498
static bool file_ensure_hovered_is_active(bContext *C, const wmEvent *event)
Definition file_ops.cc:2145
static int file_directory_new_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:2621
static int file_parent_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2239
void file_filename_enter_handle(bContext *C, void *, void *arg_but)
Definition file_ops.cc:2910
static bool file_delete_single(const FileList *files, FileDirEntry *file, const char **r_error_message)
Definition file_ops.cc:3165
void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
Definition file_ops.cc:1517
static int file_box_select_find_last_selected(SpaceFile *sfile, ARegion *region, const FileSelection *sel, const int mouse_xy[2])
Definition file_ops.cc:408
static rcti file_select_mval_to_select_rect(const int mval[2])
Definition file_ops.cc:556
static int file_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2115
static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
Definition file_ops.cc:161
void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
Definition file_ops.cc:1683
void FILE_OT_filepath_drop(wmOperatorType *ot)
Definition file_ops.cc:2576
void FILE_OT_previous(wmOperatorType *ot)
Definition file_ops.cc:2298
static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
Definition file_ops.cc:3082
static void file_os_operations_menu_draw(const bContext *C_const, Menu *menu)
Definition file_ops.cc:1922
static int bookmark_cleanup_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1218
void FILE_OT_bookmark_delete(wmOperatorType *ot)
Definition file_ops.cc:1193
void FILE_OT_external_operation(wmOperatorType *ot)
Definition file_ops.cc:1861
void FILE_OT_select_walk(wmOperatorType *ot)
Definition file_ops.cc:931
static int filepath_drop_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:2548
void FILE_OT_filenum(wmOperatorType *ot)
Definition file_ops.cc:3061
static bool file_os_operations_menu_poll(const bContext *C_const, MenuType *)
Definition file_ops.cc:1988
static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
Definition file_ops.cc:122
void FILE_OT_delete(wmOperatorType *ot)
Definition file_ops.cc:3219
static void clamp_to_filelist(int numfiles, FileSelection *sel)
Definition file_ops.cc:96
void file_sfile_to_operator_ex(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath)
Definition file_ops.cc:1581
void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
Definition file_ops.cc:1246
void file_draw_check_ex(bContext *C, ScrArea *area)
Definition file_ops.cc:1730
void file_sfile_to_operator(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile)
Definition file_ops.cc:1676
static int file_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:3213
void FILE_OT_smoothscroll(wmOperatorType *ot)
Definition file_ops.cc:2529
void FILE_OT_bookmark_move(wmOperatorType *ot)
Definition file_ops.cc:1334
void FILE_OT_select_all(wmOperatorType *ot)
Definition file_ops.cc:1021
static bool file_is_any_selected(FileList *files)
Definition file_ops.cc:224
static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
Definition file_ops.cc:328
static int file_delete_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:3178
static int reset_recent_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1369
static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
Definition file_ops.cc:269
static bool file_operator_poll(bContext *C)
Definition file_ops.cc:1538
void FILE_OT_reset_recent(wmOperatorType *ot)
Definition file_ops.cc:1383
static void file_os_operations_menu_item(uiLayout *layout, wmOperatorType *ot, const char *path, FileExternalOperation operation)
Definition file_ops.cc:1889
static bool file_filenum_poll(bContext *C)
Definition file_ops.cc:3000
int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
Definition file_ops.cc:1402
static int file_start_filter_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3238
void FILE_OT_select(wmOperatorType *ot)
Definition file_ops.cc:648
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
Definition file_ops.cc:1711
static void file_ensure_selection_inside_viewbounds(ARegion *region, SpaceFile *sfile, FileSelection *sel)
Definition file_ops.cc:309
static int file_select_all_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:964
void FILE_OT_start_filter(wmOperatorType *ot)
Definition file_ops.cc:3255
void FILE_OT_execute(wmOperatorType *ot)
Definition file_ops.cc:2126
static FileSelection file_current_selection_range_get(FileList *files)
Definition file_ops.cc:239
void file_draw_check_cb(bContext *C, void *, void *)
Definition file_ops.cc:1760
void file_external_operations_menu_register()
Definition file_ops.cc:2028
static int file_edit_directory_path_exec(bContext *C, wmOperator *)
Definition file_ops.cc:3274
void FILE_OT_rename(wmOperatorType *ot)
Definition file_ops.cc:3118
static int bookmark_add_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1140
static void file_expand_directory(bContext *C)
Definition file_ops.cc:2750
static int file_hidedot_exec(bContext *C, wmOperator *)
Definition file_ops.cc:2966
void FILE_OT_cancel(wmOperatorType *ot)
Definition file_ops.cc:1563
bool file_draw_check_exists(SpaceFile *sfile)
Definition file_ops.cc:1765
static int file_directory_new_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition file_ops.cc:2708
static int file_column_sort_ui_context_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:1483
void FILE_OT_next(wmOperatorType *ot)
Definition file_ops.cc:2335
@ FILE_BOOKMARK_MOVE_UP
Definition file_ops.cc:1269
@ FILE_BOOKMARK_MOVE_DOWN
Definition file_ops.cc:1270
@ FILE_BOOKMARK_MOVE_BOTTOM
Definition file_ops.cc:1271
@ FILE_BOOKMARK_MOVE_TOP
Definition file_ops.cc:1268
static bool new_folder_path(const char *parent, char r_dirpath_full[FILE_MAX], char r_dirname[FILE_MAXFILE])
Definition file_ops.cc:2600
static bool file_execute(bContext *C, SpaceFile *sfile)
Definition file_ops.cc:2051
void FILE_OT_view_selected(wmOperatorType *ot)
Definition file_ops.cc:1074
static int file_execute_mouse_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:2155
static int bookmark_delete_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1175
void FILE_OT_highlight(wmOperatorType *ot)
Definition file_ops.cc:1464
FileSelect
Definition file_ops.cc:90
@ FILE_SELECT_NOTHING
Definition file_ops.cc:91
@ FILE_SELECT_DIR
Definition file_ops.cc:92
@ FILE_SELECT_FILE
Definition file_ops.cc:93
static int file_external_operation_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1817
static int file_view_selected_exec(bContext *C, wmOperator *)
Definition file_ops.cc:1043
static int file_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:564
static const EnumPropertyItem file_external_operation[]
Definition file_ops.cc:1787
void FILE_OT_hidedot(wmOperatorType *ot)
Definition file_ops.cc:2981
static int bookmark_select_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1095
static int bookmark_move_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:1274
static bool file_delete_poll(bContext *C)
Definition file_ops.cc:3137
static bool fsmenu_write_file_and_refresh_or_report_error(FSMenu *fsmenu, ScrArea *area, ReportList *reports)
Definition file_ops.cc:377
static int file_smoothscroll_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition file_ops.cc:2355
static int file_filenum_exec(bContext *C, wmOperator *op)
Definition file_ops.cc:3044
eDirEntry_SelectFlag filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition filelist.cc:3001
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:3027
bool filelist_islibrary(FileList *filelist, char *dir, char **r_group)
Definition filelist.cc:3037
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2966
const char * filelist_dir(const FileList *filelist)
Definition filelist.cc:2075
void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, char r_filepath[])
Definition filelist.cc:1146
void filelist_setrecursion(FileList *filelist, const int recursion_level)
Definition filelist.cc:2102
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2953
bool filelist_is_dir(const FileList *filelist, const char *path)
Definition filelist.cc:2080
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2148
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition filelist.cc:3014
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2265
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2133
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2904
eDirEntry_SelectFlag filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition filelist.cc:2983
FileSelType
Definition filelist.hh:30
@ FILE_SEL_REMOVE
Definition filelist.hh:31
@ FILE_SEL_ADD
Definition filelist.hh:32
@ FILE_SEL_TOGGLE
Definition filelist.hh:33
FileCheckType
Definition filelist.hh:36
@ CHECK_FILES
Definition filelist.hh:38
@ CHECK_DIRS
Definition filelist.hh:37
@ CHECK_ALL
Definition filelist.hh:39
void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu)
Definition fsmenu.cc:684
void fsmenu_remove_entry(FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition fsmenu.cc:367
void fsmenu_refresh_system_category(FSMenu *fsmenu)
Definition fsmenu.cc:511
void fsmenu_insert_entry(FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, int icon, FSMenuInsert flag)
Definition fsmenu.cc:251
bool fsmenu_write_file(FSMenu *fsmenu, const char *filepath)
Definition fsmenu.cc:400
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:227
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
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_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)
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
FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX]
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
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
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
void * customdata
Definition WM_types.hh:772
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
bool(* check)(bContext *C, wmOperator *op)
Definition WM_types.hh:1014
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
ccl_device_inline int abs(int x)
Definition util/math.h:120
#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
int 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)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_mousemove(wmWindow *win)
@ EVT_FILESELECT_CANCEL
@ EVT_FILESELECT_EXEC
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
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)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
void WM_operator_properties_free(PointerRNA *ptr)