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