Blender V4.5
filesel.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 <cstring>
10
11#include <sys/stat.h>
12#include <sys/types.h>
13
14/* path/file handling stuff */
15#ifdef WIN32
16# include "BLI_winstuff.h"
17# include <direct.h>
18# include <io.h>
19#else
20# include <dirent.h>
21# include <sys/times.h>
22# include <unistd.h>
23#endif
24
26
27#include "DNA_screen_types.h"
28#include "DNA_space_types.h"
29#include "DNA_userdef_types.h"
30
31#include "MEM_guardedalloc.h"
32
33#include "BLI_fileops.h"
34#include "BLI_fnmatch.h"
35#include "BLI_math_base.h"
36#include "BLI_path_utils.hh"
37#include "BLI_string.h"
38#include "BLI_string_utf8.h"
39#include "BLI_utildefines.h"
40
41#include "BLT_translation.hh"
42
43#include "BKE_appdir.hh"
44#include "BKE_context.hh"
45#include "BKE_idtype.hh"
46#include "BKE_main.hh"
47#include "BKE_preferences.h"
48
49#include "BLO_userdef_default.h"
50
51#include "BLF_api.hh"
52
53#include "ED_fileselect.hh"
54#include "ED_screen.hh"
55
56#include "WM_api.hh"
57#include "WM_types.hh"
58
59#include "RNA_access.hh"
60
61#include "UI_interface.hh"
62#include "UI_interface_icons.hh"
63#include "UI_view2d.hh"
64
66
67#include "file_intern.hh"
68#include "filelist.hh"
69
71{
72 const char *blendfile_path = BKE_main_blendfile_path_from_global();
73
74 /* operator has no setting for this */
75 params->active_file = -1;
76
77 if (!params->dir[0]) {
78 if (blendfile_path[0] != '\0') {
79 BLI_path_split_dir_part(blendfile_path, params->dir, sizeof(params->dir));
80 }
81 else {
82 const char *doc_path = BKE_appdir_folder_default();
83 if (doc_path) {
84 STRNCPY(params->dir, doc_path);
85 }
86 }
87 }
88
91
92 /* Switching thumbnails needs to recalc layout #28809. */
93 if (sfile->layout) {
94 sfile->layout->dirty = true;
95 }
96}
97
99{
101 BLI_assert(sfile->op == nullptr);
102
103 FileAssetSelectParams *asset_params = sfile->asset_params;
104
105 if (!asset_params) {
106 asset_params = sfile->asset_params = static_cast<FileAssetSelectParams *>(
107 MEM_callocN(sizeof(*asset_params), "FileAssetSelectParams"));
108 asset_params->base_params.details_flags = U_default.file_space_data.details_flags;
110 asset_params->asset_library_ref.custom_library_index = -1;
113 }
114
115 FileSelectParams *base_params = &asset_params->base_params;
116 base_params->file[0] = '\0';
117 base_params->filter_glob[0] = '\0';
118 base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER;
119 base_params->flag &= ~FILE_DIRSEL_ONLY;
120 base_params->filter |= FILE_TYPE_BLENDERLIB;
121 base_params->filter_id = FILTER_ID_ALL;
122 base_params->display = FILE_IMGDISPLAY;
123 base_params->sort = FILE_SORT_ASSET_CATALOG;
124 /* No details columns supported for assets (wouldn't contain anything), disable them all. */
125 base_params->details_flags = 0;
126 /* Asset libraries include all sub-directories, so enable maximal recursion. */
128 /* 'SMALL' size by default. More reasonable since this is typically used as regular editor,
129 * space is more of an issue here. */
130 base_params->thumbnail_size = 96;
131 base_params->list_thumbnail_size = 32;
132 base_params->list_column_size = 220;
133
134 fileselect_initialize_params_common(sfile, base_params);
135}
136
142{
144
146 wmOperator *op = sfile->op;
147
148 const char *blendfile_path = BKE_main_blendfile_path_from_global();
149
150 /* create new parameters if necessary */
151 if (!sfile->params) {
152 sfile->params = MEM_callocN<FileSelectParams>("fileselparams");
153 /* set path to most recently opened .blend */
154 BLI_path_split_dir_file(blendfile_path,
155 sfile->params->dir,
156 sizeof(sfile->params->dir),
157 sfile->params->file,
158 sizeof(sfile->params->file));
159 sfile->params->filter_glob[0] = '\0';
160 sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
161 sfile->params->details_flags = U_default.file_space_data.details_flags;
162 sfile->params->filter_id = U_default.file_space_data.filter_id;
163 sfile->params->list_thumbnail_size = 16;
164 sfile->params->list_column_size = 500;
165 }
166
167 params = sfile->params;
168
169 /* set the parameters from the operator, if it exists */
170 if (op) {
171 PropertyRNA *prop;
172 const bool is_files = (RNA_struct_find_property(op->ptr, "files") != nullptr);
173 const bool is_filepath = (RNA_struct_find_property(op->ptr, "filepath") != nullptr);
174 const bool is_filename = (RNA_struct_find_property(op->ptr, "filename") != nullptr);
175 const bool is_directory = (RNA_struct_find_property(op->ptr, "directory") != nullptr);
176 const bool is_relative_path = (RNA_struct_find_property(op->ptr, "relative_path") != nullptr);
177
179 params->title, WM_operatortype_name(op->type, op->ptr).c_str(), sizeof(params->title));
180
181 if ((prop = RNA_struct_find_property(op->ptr, "filemode"))) {
182 params->type = RNA_property_int_get(op->ptr, prop);
183 }
184 else {
185 params->type = FILE_SPECIAL;
186 }
187
188 if (is_filepath && RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
189 char filepath[FILE_MAX];
190 RNA_string_get(op->ptr, "filepath", filepath);
191 if (params->type == FILE_LOADLIB) {
192 STRNCPY(params->dir, filepath);
193 params->file[0] = '\0';
194 }
195 else {
197 filepath, params->dir, sizeof(params->dir), params->file, sizeof(params->file));
198 }
199 }
200 else {
201 if (is_directory && RNA_struct_property_is_set_ex(op->ptr, "directory", false)) {
202 RNA_string_get(op->ptr, "directory", params->dir);
203 params->file[0] = '\0';
204 }
205
206 if (is_filename && RNA_struct_property_is_set_ex(op->ptr, "filename", false)) {
207 RNA_string_get(op->ptr, "filename", params->file);
208 }
209 }
210
211 if (params->dir[0]) {
212 BLI_path_abs(params->dir, blendfile_path);
213 BLI_path_normalize_dir(params->dir, sizeof(params->dir));
214 }
215
216 params->flag = 0;
217 if (is_directory == true && is_filename == false && is_filepath == false && is_files == false)
218 {
219 params->flag |= FILE_DIRSEL_ONLY;
220 }
221 if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
222 params->flag |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_CHECK_EXISTING) : 0;
223 }
224 if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
225 params->flag |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_HIDE_TOOL_PROPS) : 0;
226 }
227
228 params->filter = 0;
229 if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) {
230 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_BLENDER) : 0;
231 }
232 if ((prop = RNA_struct_find_property(op->ptr, "filter_blenlib"))) {
233 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_BLENDERLIB) : 0;
234 }
235 if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) {
236 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_BLENDER_BACKUP) :
237 0;
238 }
239 if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) {
240 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_IMAGE) : 0;
241 }
242 if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) {
243 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_MOVIE) : 0;
244 }
245 if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) {
246 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_PYSCRIPT) : 0;
247 }
248 if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) {
249 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_FTFONT) : 0;
250 }
251 if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) {
252 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_SOUND) : 0;
253 }
254 if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) {
255 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_TEXT) : 0;
256 }
257 if ((prop = RNA_struct_find_property(op->ptr, "filter_archive"))) {
258 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_ARCHIVE) : 0;
259 }
260 if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) {
261 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_FOLDER) : 0;
262 }
263 if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) {
264 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_BTX) : 0;
265 }
266 if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) {
267 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_COLLADA) : 0;
268 }
269 if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) {
270 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_ALEMBIC) : 0;
271 }
272 if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
273 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_USD) : 0;
274 }
275 if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
276 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_OBJECT_IO) : 0;
277 }
278 if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
279 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_VOLUME) : 0;
280 }
281 if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
282 /* Protection against Python scripts not setting proper size limit. */
283 char *glob = RNA_property_string_get_alloc(op->ptr, prop, nullptr, 0, nullptr);
284 BLI_SCOPED_DEFER([&]() { MEM_freeN(glob); });
285 STRNCPY(params->filter_glob, glob);
286 /* Fix stupid things that truncating might have generated,
287 * like last group being a 'match everything' wildcard-only one... */
289 if (glob[0] != '\0') {
291 }
292 }
293 else {
294 params->filter_glob[0] = '\0';
295 }
296
297 if (params->filter != 0) {
298 if (U.uiflag & USER_FILTERFILEEXTS) {
299 params->flag |= FILE_FILTER;
300 }
301 else {
302 params->flag &= ~FILE_FILTER;
303 }
304 }
305
306 if (U.uiflag & USER_HIDE_DOT) {
307 params->flag |= FILE_HIDE_DOT;
308 }
309 else {
310 params->flag &= ~FILE_HIDE_DOT;
311 }
312
313 if (params->type == FILE_LOADLIB) {
314 params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0;
315 params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0;
316 params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
317 }
318
319 if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
321 }
322
323 if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
324 params->display = RNA_property_enum_get(op->ptr, prop);
325 }
326
327 if (params->display == FILE_DEFAULTDISPLAY) {
328 params->display = U_default.file_space_data.display_type;
329 }
330
331 if ((prop = RNA_struct_find_property(op->ptr, "sort_method"))) {
332 params->sort = RNA_property_enum_get(op->ptr, prop);
333 }
334
335 if (params->sort == FILE_SORT_DEFAULT) {
336 params->sort = U_default.file_space_data.sort_type;
337 }
338
339 if (is_relative_path) {
340 if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
341 if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
342 RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS) != 0);
343 }
344 }
345 }
346 }
347 else {
348 /* default values, if no operator */
349 params->type = FILE_UNIX;
350 params->flag |= U_default.file_space_data.flag;
351 params->flag &= ~FILE_DIRSEL_ONLY;
352 params->display = FILE_VERTICALDISPLAY;
353 params->sort = FILE_SORT_ALPHA;
354 params->filter = 0;
355 params->filter_glob[0] = '\0';
356 }
357
359
360 return params;
361}
362
364{
365 switch ((eFileBrowse_Mode)sfile->browse_mode) {
367 if (!sfile->params) {
369 }
370 return sfile->params;
372 if (!sfile->asset_params) {
374 }
375 return &sfile->asset_params->base_params;
376 }
377
378 BLI_assert_msg(0, "Invalid browse mode set in file space.");
379 return nullptr;
380}
381
383{
384 if (!sfile) {
385 /* Sometimes called in poll before space type was checked. */
386 return nullptr;
387 }
388
389 switch ((eFileBrowse_Mode)sfile->browse_mode) {
391 return sfile->params;
393 return (FileSelectParams *)sfile->asset_params;
394 }
395
396 BLI_assert_msg(0, "Invalid browse mode set in file space.");
397 return nullptr;
398}
399
401{
402 return (sfile->browse_mode == FILE_BROWSE_MODE_FILES) ? sfile->params : nullptr;
403}
404
406{
407 return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : nullptr;
408}
409
411{
412 const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
413 if (asset_params == nullptr) {
414 return false;
415 }
416 return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL;
417}
418
420{
421 AssetLibraryReference *library = &asset_params->asset_library_ref;
422 FileSelectParams *base_params = &asset_params->base_params;
423 bUserAssetLibrary *user_library = nullptr;
424
425 /* Ensure valid repository, or fall-back to local one. */
426 if (library->type == ASSET_LIBRARY_CUSTOM) {
427 BLI_assert(library->custom_library_index >= 0);
428
430 if (!user_library) {
431 library->type = ASSET_LIBRARY_ALL;
432 }
433 }
434
435 switch (eAssetLibraryType(library->type)) {
438 base_params->type = FILE_ASSET_LIBRARY;
439 break;
441 base_params->dir[0] = '\0';
442 base_params->type = FILE_ASSET_LIBRARY_ALL;
443 break;
445 base_params->dir[0] = '\0';
446 base_params->type = FILE_MAIN_ASSET;
447 break;
449 BLI_assert(user_library);
450 STRNCPY(base_params->dir, user_library->dirpath);
451 BLI_path_slash_native(base_params->dir);
452 base_params->type = FILE_ASSET_LIBRARY;
453 break;
454 }
455}
456
458{
460 if (asset_params) {
462 }
463}
464
466{
467 return (sfile->browse_mode == FILE_BROWSE_MODE_FILES);
468}
469
471{
472 return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
473}
474
476{
477 if (!ED_fileselect_is_asset_browser(sfile) || !sfile->files) {
478 return nullptr;
479 }
480
481 return filelist_asset_library(sfile->files);
482}
483
485{
486 if (!ED_fileselect_is_asset_browser(sfile)) {
487 return nullptr;
488 }
489
490 if (sfile->files == nullptr) {
491 return nullptr;
492 }
493
495 const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
496 if (file == nullptr) {
497 return nullptr;
498 }
499
500 return filelist_file_get_id(file);
501}
502
503void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
504{
505 if (!ED_fileselect_is_asset_browser(sfile)) {
506 return;
507 }
508
510 params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
511 params->catalog_id = catalog_id;
513}
514
516{
517 if (!ED_fileselect_is_asset_browser(sfile) || !file->asset) {
518 return -1;
519 }
520
521 /* First handle the case where the asset system dictates a certain import method. */
522 if (file->asset->may_override_import_method() == false) {
523 BLI_assert(file->asset->get_import_method().has_value());
524 return *file->asset->get_import_method();
525 }
526
528
529 if (params->import_method == FILE_ASSET_IMPORT_FOLLOW_PREFS) {
530 std::optional import_method = file->asset->get_import_method();
531 return import_method ? *import_method : -1;
532 }
533
534 switch (eFileAssetImportMethod(params->import_method)) {
536 return ASSET_IMPORT_LINK;
538 return ASSET_IMPORT_APPEND;
541
542 /* Should be handled above already. Break and fail below. */
544 break;
545 }
546
548 return -1;
549}
550
551static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
552{
553 ID *asset_id = (ID *)custom_data;
554 ED_fileselect_activate_by_id(sfile, asset_id, false);
555}
556
557void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
558{
559 if (!ED_fileselect_is_asset_browser(sfile)) {
560 return;
561 }
562
563 /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
564 * there is a fair chance that the to-be-activated ID will only be present after these operations
565 * have completed. Defer activation until then. */
566 if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) {
567 /* This should be thread-safe, as this function is likely called from the main thread, and
568 * notifiers (which cause a call to the on-reload callback function) are handled on the main
569 * thread as well. */
571 return;
572 }
573
575 FileList *files = sfile->files;
576
577 const int file_index = filelist_file_find_id(files, asset_id);
578 const FileDirEntry *file = filelist_file_ex(files, file_index, true);
579 if (file == nullptr) {
580 return;
581 }
582
583 params->active_file = file_index;
585
588}
589
591{
592 const char *relative_path = static_cast<const char *>(custom_data);
593 ED_fileselect_activate_by_relpath(sfile, relative_path);
594}
595
596void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path)
597{
598 /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
599 * there is a fair chance that the to-be-activated file at relative_path will only be present
600 * after these operations have completed. Defer activation until then. */
601 FileList *files = sfile->files;
602 if (files == nullptr || filelist_pending(files) || filelist_needs_force_reset(files)) {
603 /* Casting away the constness of `relative_path` is safe here, because eventually it just ends
604 * up in another call to this function, and then it's a const char* again. */
606 return;
607 }
608
610 const int num_files_filtered = filelist_files_ensure(files);
611
612 for (int file_index = 0; file_index < num_files_filtered; ++file_index) {
613 const FileDirEntry *file = filelist_file(files, file_index);
614
615 if (STREQ(file->relpath, relative_path)) {
616 params->active_file = file_index;
618 }
619 }
621}
622
628
629/* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA
630 * may also be remembered, but only conditionally. */
631#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT)
632
633void ED_fileselect_window_params_get(const wmWindow *win, int r_win_size[2], bool *r_is_maximized)
634{
635 /* Get DPI/pixel-size independent size to be stored in preferences. */
636 WM_window_set_dpi(win); /* Ensure the DPI is taken from the right window. */
637
638 const blender::int2 win_size = WM_window_native_pixel_size(win);
639 r_win_size[0] = win_size[0] / UI_SCALE_FAC;
640 r_win_size[1] = win_size[1] / UI_SCALE_FAC;
641
642 *r_is_maximized = WM_window_is_maximized(win);
643}
644
646{
647 PropertyRNA *prop;
648 return (sfile->op == nullptr) ||
649 !(prop = RNA_struct_find_property(sfile->op->ptr, "display_type")) ||
651}
652
654{
655 PropertyRNA *prop;
656 return (sfile->op == nullptr) ||
657 !(prop = RNA_struct_find_property(sfile->op->ptr, "sort_method")) ||
658 (RNA_property_enum_get(sfile->op->ptr, prop) == FILE_SORT_DEFAULT);
659}
660
662{
663 wmOperator *op = sfile->op;
664 UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
665
667
669 if (!op) {
670 return;
671 }
672
673 params->thumbnail_size = sfile_udata->thumbnail_size;
674 params->details_flags = sfile_udata->details_flags;
675 params->filter_id = sfile_udata->filter_id;
676
677 /* Combine flags we take from params with the flags we take from userdef. */
678 params->flag = (params->flag & ~PARAMS_FLAGS_REMEMBERED) |
679 (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
680
682 params->display = sfile_udata->display_type;
683 }
685 params->sort = sfile_udata->sort_type;
686 /* For the default sorting, also take invert flag from userdef. */
687 params->flag = (params->flag & ~FILE_SORT_INVERT) | (sfile_udata->flag & FILE_SORT_INVERT);
688 }
689}
690
692 const int temp_win_size[2],
693 const bool is_maximized)
694{
696 UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
697 UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
698
699 sfile_udata_new->thumbnail_size = params->thumbnail_size;
700 sfile_udata_new->details_flags = params->details_flags;
701 sfile_udata_new->flag = params->flag & PARAMS_FLAGS_REMEMBERED;
702 sfile_udata_new->filter_id = params->filter_id;
703
704 /* In some rare cases, operators ask for a specific display or sort type (e.g. chronological
705 * sorting for "Recover Auto Save"). So the settings are optimized for a specific operation.
706 * Don't let that change the userdef memory for more general cases. */
708 sfile_udata_new->display_type = params->display;
709 }
711 sfile_udata_new->sort_type = params->sort;
712 /* In this case also remember the invert flag. */
713 sfile_udata_new->flag = (sfile_udata_new->flag & ~FILE_SORT_INVERT) |
714 (params->flag & FILE_SORT_INVERT);
715 }
716
717 if (temp_win_size && !is_maximized) {
718 sfile_udata_new->temp_win_sizex = temp_win_size[0];
719 sfile_udata_new->temp_win_sizey = temp_win_size[1];
720 }
721
722 /* Tag preferences as dirty if something has changed. */
723 if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
724 U.runtime.is_dirty = true;
725 }
726}
727
728void fileselect_file_set(bContext *C, SpaceFile *sfile, const int index)
729{
730 const FileDirEntry *file = filelist_file(sfile->files, index);
731 if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) {
733 STRNCPY(params->file, file->relpath);
734 if (sfile->op) {
735 /* Update the filepath properties of the operator. */
736 Main *bmain = CTX_data_main(C);
737 file_sfile_to_operator(C, bmain, sfile->op, sfile);
738 }
739 }
740}
741
743{
744 int numfiles;
745
746 /* Values in pixels.
747 *
748 * - *_item: size of each (row|col), (including padding)
749 * - *_view: (x|y) size of the view.
750 * - *_over: extra pixels, to take into account, when the fit isn't exact
751 * (needed since you may see the end of the previous column and the beginning of the next).
752 *
753 * Could be more clever and take scrolling into account,
754 * but for now don't bother.
755 */
756 if (layout->flag & FILE_LAYOUT_HOR) {
757 const int x_item = layout->tile_w + (2 * layout->tile_border_x);
758 const int x_view = int(BLI_rctf_size_x(&region->v2d.cur));
759 const int x_over = x_item - (x_view % x_item);
760 numfiles = int(float(x_view + x_over) / float(x_item));
761 return numfiles * layout->rows;
762 }
763
764 const int y_item = layout->tile_h + (2 * layout->tile_border_y);
765 const int y_view = int(BLI_rctf_size_y(&region->v2d.cur)) - layout->offset_top -
766 layout->list_padding_top;
767 const int y_over = y_item - (y_view % y_item);
768 numfiles = int(float(y_view + y_over) / float(y_item));
769 return numfiles * layout->flow_columns;
770}
771
772static bool is_inside(int x, int y, int cols, int rows)
773{
774 return ((x >= 0) && (x < cols) && (y >= 0) && (y < rows));
775}
776
778{
779 int colmin, colmax, rowmin, rowmax;
780 FileSelection sel;
781 sel.first = sel.last = -1;
782
783 if (layout == nullptr) {
784 return sel;
785 }
786
787 colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x);
788 rowmin = (rect->ymin - layout->offset_top - layout->list_padding_top) /
789 (layout->tile_h + 2 * layout->tile_border_y);
790 colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x);
791 rowmax = (rect->ymax - layout->offset_top - layout->list_padding_top) /
792 (layout->tile_h + 2 * layout->tile_border_y);
793
794 if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) ||
795 is_inside(colmax, rowmax, layout->flow_columns, layout->rows))
796 {
797 CLAMP(colmin, 0, layout->flow_columns - 1);
798 CLAMP(rowmin, 0, layout->rows - 1);
799 CLAMP(colmax, 0, layout->flow_columns - 1);
800 CLAMP(rowmax, 0, layout->rows - 1);
801 }
802
803 if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) {
804 sel.first = -1;
805 }
806 else {
807 if (layout->flag & FILE_LAYOUT_HOR) {
808 sel.first = layout->rows * colmin + rowmin;
809 }
810 else {
811 sel.first = colmin + layout->flow_columns * rowmin;
812 }
813 }
814 if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) {
815 sel.last = -1;
816 }
817 else {
818 if (layout->flag & FILE_LAYOUT_HOR) {
819 sel.last = layout->rows * colmax + rowmax;
820 }
821 else {
822 sel.last = colmax + layout->flow_columns * rowmax;
823 }
824 }
825
826 return sel;
827}
828
830{
831 int offsetx, offsety;
832 int active_file;
833
834 if (layout == nullptr) {
835 return -1;
836 }
837
838 offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x);
839 offsety = (y - layout->offset_top - layout->list_padding_top) /
840 (layout->tile_h + 2 * layout->tile_border_y);
841
842 if (offsetx > layout->flow_columns - 1) {
843 return -1;
844 }
845 if (offsety > layout->rows - 1) {
846 return -1;
847 }
848
849 if (layout->flag & FILE_LAYOUT_HOR) {
850 active_file = layout->rows * offsetx + offsety;
851 }
852 else {
853 active_file = offsetx + layout->flow_columns * offsety;
854 }
855 return active_file;
856}
857
858void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
859{
860 *r_rect = v2d->mask;
861 r_rect->ymax -= layout->offset_top;
862}
863
864bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
865{
866 rcti maskrect;
867 ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
868 return BLI_rcti_isect_pt(&maskrect, x, y);
869}
870
872 const View2D *v2d,
873 const rcti *rect,
874 rcti *r_dst)
875{
876 rcti maskrect;
877 ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
878 return BLI_rcti_isect(&maskrect, rect, r_dst);
879}
880
881void ED_fileselect_layout_tilepos(const FileLayout *layout, int tile, int *x, int *y)
882{
883 if (layout->flag == FILE_LAYOUT_HOR) {
884 *x = layout->tile_border_x +
885 (tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x);
886 *y = layout->offset_top + layout->list_padding_top + layout->tile_border_y +
887 (tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y);
888 }
889 else {
890 *x = layout->tile_border_x +
891 ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x);
892 *y = layout->offset_top + layout->list_padding_top + layout->tile_border_y +
893 ((tile) / layout->flow_columns) * (layout->tile_h + 2 * layout->tile_border_y);
894 }
895}
896
898 const FileLayout *layout,
899 int x,
900 int y)
901{
902 rcti header_rect = v2d->mask;
903 header_rect.ymin = header_rect.ymax - layout->attribute_column_header_h;
904 return BLI_rcti_isect_pt(&header_rect, x, y);
905}
906
909 const FileLayout *layout)
910{
911 switch (column) {
912 case COLUMN_NAME:
913 /* Always enabled */
914 return true;
915 case COLUMN_DATETIME:
916 return ((params->details_flags & FILE_DETAILS_DATETIME) != 0) &&
917 !FILE_LAYOUT_HIDE_DATE(layout);
918 case COLUMN_SIZE:
919 return ((params->details_flags & FILE_DETAILS_SIZE) != 0) && !FILE_LAYOUT_HIDE_SIZE(layout);
920 default:
921 return false;
922 }
923}
924
927 FileLayout *layout,
928 int x)
929{
930 float mx, my;
931 int offset_tile;
932
933 UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my);
934 offset_tile = ED_fileselect_layout_offset(
935 layout, int(v2d->tot.xmin + mx), int(v2d->tot.ymax - my));
936 if (offset_tile > -1) {
937 int tile_x, tile_y;
938 int pos_x = 0;
939 int rel_x; /* x relative to the hovered tile */
940
941 ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y);
942 /* Column header drawing doesn't use left tile border, so subtract it. */
943 rel_x = mx - (tile_x - layout->tile_border_x);
944
946 column < ATTRIBUTE_COLUMN_MAX;
947 column = FileAttributeColumnType(int(column) + 1))
948 {
949 if (!file_attribute_column_type_enabled(params, column, layout)) {
950 continue;
951 }
952 const int width = layout->attribute_columns[column].width;
953
954 if (IN_RANGE(rel_x, pos_x, pos_x + width)) {
955 return column;
956 }
957
958 pos_x += width;
959 }
960 }
961
962 return COLUMN_NONE;
963}
964
965float file_string_width(const char *str)
966{
967 const uiStyle *style = UI_style_get();
968 UI_fontstyle_set(&style->widget);
970}
971
973{
974 const uiStyle *style = UI_style_get();
975 return UI_fontstyle_height_max(&style->widget);
976}
977
979{
980 FileAttributeColumn *columns = layout->attribute_columns;
981 const int pad = ATTRIBUTE_COLUMN_PADDING * 2;
982 const bool compact = FILE_LAYOUT_COMPACT(layout);
983
984 for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) {
985 layout->attribute_columns[i].width = 0;
986 }
987
988 /* Biggest possible reasonable values... */
990 columns[COLUMN_DATETIME].width = file_string_width(compact ? "23/08/89" :
991 "23 Dec 6789, 23:59") +
992 pad;
993 }
995 columns[COLUMN_SIZE].width = file_string_width(compact ? "369G" : "098.7 MiB") + pad;
996 }
997
998 if (params->display == FILE_IMGDISPLAY) {
999 columns[COLUMN_NAME].width = (float(params->thumbnail_size) / 8.0f) * UI_UNIT_X;
1000 }
1001 /* Name column uses remaining width */
1002 else {
1003 int remwidth = layout->tile_w;
1004 for (FileAttributeColumnType column_type =
1006 column_type >= 0;
1007 column_type = FileAttributeColumnType(int(column_type) - 1))
1008 {
1009 if ((column_type == COLUMN_NAME) ||
1010 !file_attribute_column_type_enabled(params, column_type, layout))
1011 {
1012 continue;
1013 }
1014 remwidth -= columns[column_type].width;
1015 }
1016 columns[COLUMN_NAME].width = remwidth;
1017 }
1018}
1019
1037
1039{
1041 FileLayout *layout = nullptr;
1042 View2D *v2d = &region->v2d;
1043 int numfiles;
1044
1045 if (sfile->layout == nullptr) {
1046 sfile->layout = MEM_callocN<FileLayout>("file_layout");
1047 sfile->layout->dirty = true;
1048 }
1049 else if (sfile->layout->dirty == false) {
1050 return;
1051 }
1052
1053 numfiles = filelist_files_ensure(sfile->files);
1054 layout = sfile->layout;
1055 /* Slightly increased than font height for padding. */
1057 layout->text_lines_count = 1;
1058
1059 if (params->display == FILE_IMGDISPLAY) {
1060 /* More compact spacing for asset browser. */
1061 const float pad_fac = ED_fileselect_is_asset_browser(sfile) ? 0.15f : 0.3f;
1062 /* Matches UI_preview_tile_size_x()/_y() by default. */
1063 layout->prv_w = (float(params->thumbnail_size) / 20.0f) * UI_UNIT_X;
1064 layout->prv_h = (float(params->thumbnail_size) / 20.0f) * UI_UNIT_Y;
1065 layout->tile_border_x = pad_fac * UI_UNIT_X;
1066 layout->tile_border_y = pad_fac * UI_UNIT_X;
1067 layout->list_padding_top = 0;
1068 layout->prv_border_x = pad_fac * UI_UNIT_X;
1069 layout->prv_border_y = pad_fac * UI_UNIT_Y;
1070 layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
1071 layout->text_lines_count = 2;
1072 layout->tile_h = layout->prv_h + 2 * layout->prv_border_y +
1073 layout->text_lines_count * layout->text_line_height;
1074 layout->width = int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1075 layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
1076 layout->attribute_column_header_h = 0;
1077 layout->offset_top = 0;
1078 if (layout->flow_columns > 0) {
1079 layout->rows = divide_ceil_u(numfiles, layout->flow_columns);
1080 }
1081 else {
1082 layout->flow_columns = 1;
1083 layout->rows = numfiles;
1084 }
1085 layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
1086 layout->tile_border_y * 2 - layout->offset_top;
1087 layout->flag = FILE_LAYOUT_VER;
1088 }
1089 else if (params->display == FILE_VERTICALDISPLAY) {
1090 int rowcount;
1091
1094 layout->tile_border_x = 0.4f * UI_UNIT_X;
1095 layout->tile_border_y = 0.05f * UI_UNIT_Y;
1096 layout->list_padding_top = 2 * layout->tile_border_y;
1097 layout->tile_h = round_fl_to_int(layout->text_line_height * 1.4f);
1098 layout->width = int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1099 layout->tile_w = layout->width;
1100 layout->flow_columns = 1;
1101 layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
1102 layout->offset_top = layout->attribute_column_header_h;
1103 rowcount = int(BLI_rctf_size_y(&v2d->cur) - layout->offset_top -
1104 2 * layout->list_padding_top) /
1105 (layout->tile_h + 2 * layout->tile_border_y);
1107
1108 layout->rows = std::max(rowcount, numfiles);
1109
1110 /* layout->rows can be zero if a very small area is changed to a File Browser. #124168. */
1111
1112 layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
1113 layout->list_padding_top * 2 + layout->offset_top;
1114 layout->flag = FILE_LAYOUT_VER;
1115 }
1116 else if (params->display == FILE_HORIZONTALDISPLAY) {
1117 layout->prv_w = params->list_thumbnail_size * UI_SCALE_FAC;
1118 layout->prv_h = params->list_thumbnail_size * UI_SCALE_FAC;
1119 layout->tile_border_x = 0.4f * UI_UNIT_X;
1120 layout->tile_border_y = 0.05f * UI_UNIT_Y;
1121 layout->list_padding_top = 2 * layout->tile_border_y;
1122 layout->tile_h = std::max(round_fl_to_int(layout->text_line_height * 1.4f), layout->prv_h);
1123 layout->attribute_column_header_h = 0;
1124 layout->offset_top = layout->attribute_column_header_h;
1125 layout->height = int(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
1126 /* Padding by full scroll-bar H is too much, can overlap tile border Y. */
1127 layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) /
1128 (layout->tile_h + 2 * layout->tile_border_y);
1129
1130 layout->tile_w = params->list_column_size * UI_SCALE_FAC;
1132
1133 if (layout->rows > 0) {
1134 layout->flow_columns = divide_ceil_u(numfiles, layout->rows);
1135 }
1136 else {
1137 layout->rows = 1;
1138 layout->flow_columns = numfiles;
1139 }
1140 layout->width = (numfiles > 0) ? (sfile->layout->flow_columns *
1141 (layout->tile_w + 2 * layout->tile_border_x) +
1142 layout->tile_border_x * 2) :
1143 int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1144 layout->flag = FILE_LAYOUT_HOR;
1145 }
1146 layout->dirty = false;
1147}
1148
1150{
1151 if (!sfile->layout) {
1152 ED_fileselect_init_layout(sfile, region);
1153 }
1154 return sfile->layout;
1155}
1156
1158{
1159 /* May happen when manipulating non-active spaces. */
1160 if (UNLIKELY(area->spacetype != SPACE_FILE)) {
1161 return;
1162 }
1163 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1165 if (params) {
1167 ED_fileselect_clear(wm, sfile);
1168
1169 /* Clear search string, it is very rare to want to keep that filter while changing dir,
1170 * and usually very annoying to keep it actually! */
1171 params->filter_search[0] = '\0';
1172 params->active_file = -1;
1173
1174 if (!filelist_is_dir(sfile->files, params->dir)) {
1175 STRNCPY(params->dir, filelist_dir(sfile->files));
1176 /* could return but just refresh the current dir */
1177 }
1178 filelist_setdir(sfile->files, params->dir);
1179
1180 if (folderlist_clear_next(sfile)) {
1182 }
1183
1185
1186 file_draw_check_ex(C, area);
1187 }
1188}
1189
1191{
1192 ScrArea *area = CTX_wm_area(C);
1193 ED_file_change_dir_ex(C, area);
1194}
1195
1197{
1198 FileSelection sel;
1199 sel.first = 0;
1200 sel.last = filelist_files_ensure(sfile->files) - 1;
1201
1203}
1204
1205int file_select_match(SpaceFile *sfile, const char *pattern, char *matched_file)
1206{
1207 int match = 0;
1208
1209 int n = filelist_files_ensure(sfile->files);
1210
1211 /* select any file that matches the pattern, this includes exact match
1212 * if the user selects a single file by entering the filename
1213 */
1214 for (int i = 0; i < n; i++) {
1215 const char *relpath = filelist_entry_get_relpath(sfile->files, i);
1216 /* Do not check whether file is a file or dir here! Causes: #44243
1217 * (we do accept directories at this stage). */
1218 if (fnmatch(pattern, relpath, 0) == 0) {
1220 if (!match) {
1221 BLI_strncpy(matched_file, relpath, FILE_MAX);
1222 }
1223 match++;
1224 }
1225 }
1226
1227 return match;
1228}
1229
1230int autocomplete_directory(bContext *C, char *str, void * /*arg_v*/)
1231{
1232 SpaceFile *sfile = CTX_wm_space_file(C);
1233 int match = AUTOCOMPLETE_NO_MATCH;
1234
1235 /* search if str matches the beginning of name */
1236 if (str[0] && sfile->files) {
1237 char dirname[FILE_MAX];
1238
1239 DIR *dir;
1240 dirent *de;
1241
1243
1244 dir = opendir(dirname);
1245
1246 if (dir) {
1248
1249 while ((de = readdir(dir)) != nullptr) {
1250 if (FILENAME_IS_CURRPAR(de->d_name)) {
1251 /* pass */
1252 }
1253 else {
1254 char dirpath[FILE_MAX];
1255 BLI_stat_t status;
1256
1257 BLI_path_join(dirpath, sizeof(dirpath), dirname, de->d_name);
1258
1259 if (BLI_stat(dirpath, &status) == 0) {
1260 if (S_ISDIR(status.st_mode)) { /* is subdir */
1261 UI_autocomplete_update_name(autocpl, dirpath);
1262 }
1263 }
1264 }
1265 }
1266 closedir(dir);
1267
1268 match = UI_autocomplete_end(autocpl, str);
1269 if (match == AUTOCOMPLETE_FULL_MATCH) {
1271 }
1272 }
1273 }
1274
1275 return match;
1276}
1277
1278int autocomplete_file(bContext *C, char *str, void * /*arg_v*/)
1279{
1280 SpaceFile *sfile = CTX_wm_space_file(C);
1281 int match = AUTOCOMPLETE_NO_MATCH;
1282
1283 /* search if str matches the beginning of name */
1284 if (str[0] && sfile->files) {
1286 int nentries = filelist_files_ensure(sfile->files);
1287
1288 for (int i = 0; i < nentries; i++) {
1289 const char *relpath = filelist_entry_get_relpath(sfile->files, i);
1290 UI_autocomplete_update_name(autocpl, relpath);
1291 }
1292 match = UI_autocomplete_end(autocpl, str);
1293 }
1294
1295 return match;
1296}
1297
1299{
1300 /* Only null in rare cases, see: #29734. */
1301 if (sfile->files) {
1302 filelist_readjob_stop(sfile->files, wm);
1303 filelist_freelib(sfile->files);
1304 filelist_clear(sfile->files);
1305 }
1306
1308 params->highlight_file = -1;
1310}
1311
1313{
1314 /* Only null in rare cases, see: #29734. */
1315 if (sfile->files) {
1316 filelist_readjob_stop(sfile->files, wm);
1317 filelist_freelib(sfile->files);
1321 }
1322
1324 params->highlight_file = -1;
1326}
1327
1329{
1330 if (!sfile) {
1331 return;
1332 }
1333 if (sfile->op) {
1334 wmWindow *temp_win = (wm->winactive && WM_window_is_temp_screen(wm->winactive)) ?
1335 wm->winactive :
1336 nullptr;
1337 if (temp_win) {
1338 int win_size[2];
1339 bool is_maximized;
1340
1341 ED_fileselect_window_params_get(temp_win, win_size, &is_maximized);
1342 ED_fileselect_params_to_userdef(sfile, win_size, is_maximized);
1343 }
1344 else {
1345 ED_fileselect_params_to_userdef(sfile, nullptr, false);
1346 }
1347
1349 sfile->op = nullptr;
1350 }
1351
1353
1354 if (sfile->files) {
1355 ED_fileselect_clear(wm, sfile);
1356 filelist_free(sfile->files);
1357 sfile->files = nullptr;
1358 }
1359}
1360
1362{
1364 sfile->smoothscroll_timer = nullptr;
1365}
1366
1368{
1370
1372
1373 if (sfile->smoothscroll_timer != nullptr) {
1375 }
1376 sfile->smoothscroll_timer = WM_event_timer_add(wm, win, TIMER1, 1.0 / 1000.0);
1377 sfile->scroll_offset = 0;
1378}
1379
1381 wmWindow *win,
1382 SpaceFile *sfile,
1383 const FileDirEntry *rename_file)
1384{
1386
1388 sfile->files, rename_file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
1389
1390 /* Ensure smooth-scroll timer is active, even if not needed, because that way rename state is
1391 * handled properly. */
1393 /* Also always activate the rename file, even if renaming was canceled. */
1395}
1396
1398{
1399 params->renamefile[0] = '\0';
1400 params->rename_id = nullptr;
1401 params->rename_flag = 0;
1402}
1403
1405{
1406 /* Find the file either through the local ID/asset it represents or its relative path. */
1407 return (params->rename_id != nullptr) ? filelist_file_find_id(filelist, params->rename_id) :
1408 filelist_file_find_path(filelist, params->renamefile);
1409}
1410
1412{
1413 BLI_assert(params->rename_flag != 0);
1414
1416 0)
1417 {
1418 return;
1419 }
1420
1421 BLI_assert(params->renamefile[0] != '\0' || params->rename_id != nullptr);
1422
1423 int idx = file_params_find_renamed(params, sfile->files);
1424 if (idx >= 0) {
1425 FileDirEntry *file = filelist_file(sfile->files, idx);
1426 BLI_assert(file != nullptr);
1427
1428 params->active_file = idx;
1430
1431 if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) {
1433 params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
1434 }
1435 else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
1436 /* file_select_deselect_all() will resort and re-filter, so `idx` will probably have changed.
1437 * Need to get the correct #FileDirEntry again. */
1439 idx = file_params_find_renamed(params, sfile->files);
1440 file = filelist_file(sfile->files, idx);
1443 params->active_file = idx;
1446 }
1447 }
1448 /* File listing is now asynchronous, only reset renaming if matching entry is not found
1449 * when file listing is not done. */
1450 else if (filelist_is_ready(sfile->files)) {
1452 }
1453}
1454
1456{
1457 bScreen *screen = WM_window_get_active_screen(win);
1458
1459 ED_screen_areas_iter (win, screen, area) {
1460 if (area->spacetype == SPACE_FILE) {
1461 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1462
1463 if (sfile->op == file_operator) {
1464 return area;
1465 }
1466 }
1467 }
1468
1469 return nullptr;
1470}
1471
1473{
1474 const bScreen *screen = WM_window_get_active_screen(win);
1475
1476 ED_screen_areas_iter (win, screen, area) {
1477 if (area->spacetype != SPACE_FILE) {
1478 continue;
1479 }
1480
1481 const SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1482 if (sfile->op) {
1483 return area;
1484 }
1485 }
1486
1487 return nullptr;
1488}
1489
1491{
1492 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
1493 Main *bmain = CTX_data_main(C);
1494 char filepath[FILE_MAX];
1495 const char *blendfile_path = BKE_main_blendfile_path(bmain);
1496
1497 if (blendfile_path[0] == '\0') {
1498 STRNCPY(filepath, DATA_("Untitled"));
1499 }
1500 else {
1501 STRNCPY(filepath, blendfile_path);
1502 }
1503
1504 BLI_path_extension_replace(filepath, sizeof(filepath), extension);
1505 RNA_string_set(op->ptr, "filepath", filepath);
1506 }
1507}
Main runtime representation of an asset.
const char * BKE_appdir_folder_default() ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:137
SpaceFile * CTX_wm_space_file(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:877
struct bUserAssetLibrary * BKE_preferences_asset_library_find_index(const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:468
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:805
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#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_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct stat BLI_stat_t
MINLINE int round_fl_to_int(float a)
MINLINE uint divide_ceil_u(uint a, uint b)
#define BLI_SCOPED_DEFER(function_to_defer)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
int BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1)
#define FILE_MAX
bool BLI_path_extension_replace(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
void BLI_path_slash_native(char *path) ATTR_NONNULL(1)
#define BLI_path_join(...)
#define FILENAME_IS_CURRPAR(_n)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL(1)
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define CLAMP(a, b, c)
#define IN_RANGE(a, b, c)
#define UNLIKELY(x)
#define STREQ(a, b)
Compatibility-like things for windows.
struct __dirstream DIR
struct dirent * readdir(DIR *dp)
int closedir(DIR *dp)
#define S_ISDIR(x)
const char * dirname(char *path)
DIR * opendir(const char *path)
const UserDef U_default
#define DATA_(msgid)
@ ASSET_IMPORT_LINK
@ ASSET_IMPORT_APPEND_REUSE
@ ASSET_IMPORT_APPEND
eAssetLibraryType
@ ASSET_LIBRARY_CUSTOM
@ ASSET_LIBRARY_ESSENTIALS
@ ASSET_LIBRARY_LOCAL
@ ASSET_LIBRARY_ALL
@ FILE_SORT_ASSET_CATALOG
@ FILE_SORT_DEFAULT
@ FILE_SORT_ALPHA
@ FILE_SORT_TIME
@ FILE_SORT_SIZE
@ FILE_LOADLIB
@ FILE_ASSET_LIBRARY
@ FILE_SPECIAL
@ FILE_UNIX
@ FILE_MAIN_ASSET
@ FILE_ASSET_LIBRARY_ALL
@ FILE_TYPE_BTX
@ FILE_TYPE_BLENDER
@ FILE_TYPE_ALEMBIC
@ FILE_TYPE_ARCHIVE
@ FILE_TYPE_TEXT
@ FILE_TYPE_COLLADA
@ FILE_TYPE_PYSCRIPT
@ FILE_TYPE_BLENDER_BACKUP
@ FILE_TYPE_VOLUME
@ FILE_TYPE_MOVIE
@ FILE_TYPE_SOUND
@ FILE_TYPE_OBJECT_IO
@ FILE_TYPE_FOLDER
@ FILE_TYPE_FTFONT
@ FILE_TYPE_BLENDERLIB
@ FILE_TYPE_OPERATOR
@ FILE_TYPE_USD
@ FILE_TYPE_IMAGE
@ FILE_TYPE_DIR
@ SPACE_FILE
@ FILE_PARAMS_RENAME_POSTSCROLL_PENDING
@ FILE_PARAMS_RENAME_ACTIVE
@ FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE
@ FILE_PARAMS_RENAME_PENDING
@ FILE_DETAILS_DATETIME
@ FILE_DETAILS_SIZE
eFileAssetImportMethod
@ FILE_ASSET_IMPORT_APPEND_REUSE
@ FILE_ASSET_IMPORT_APPEND
@ FILE_ASSET_IMPORT_LINK
@ FILE_ASSET_IMPORT_FOLLOW_PREFS
@ FILE_SHOW_ASSETS_FROM_CATALOG
eFileBrowse_Mode
@ FILE_BROWSE_MODE_ASSETS
@ FILE_BROWSE_MODE_FILES
eDirEntry_SelectFlag
@ FILE_SEL_EDITING
@ FILE_SEL_HIGHLIGHTED
@ FILE_SEL_SELECTED
@ FILE_VERTICALDISPLAY
@ FILE_IMGDISPLAY
@ FILE_HORIZONTALDISPLAY
@ FILE_DEFAULTDISPLAY
@ FILE_ACTIVE_COLLECTION
@ FILE_HIDE_TOOL_PROPS
@ FILE_CHECK_EXISTING
@ FILE_AUTOSELECT
@ FILE_FILTER
@ FILE_SORT_INVERT
@ FILE_DIRSEL_ONLY
@ FILE_LINK
@ FILE_ASSETS_ONLY
@ FILE_HIDE_DOT
@ FILE_PATH_TOKENS_ALLOW
@ FILE_ASSET_IMPORT_INSTANCE_COLLECTIONS_ON_LINK
#define FILE_SELECT_MAX_RECURSIONS
#define UI_SCALE_FAC
@ USER_HIDE_DOT
@ USER_FILTERFILEEXTS
@ USER_RELPATHS
#define FILE_LAYOUT_HOR
#define FILE_LAYOUT_VER
FileAttributeColumnType
@ COLUMN_DATETIME
@ ATTRIBUTE_COLUMN_MAX
@ COLUMN_NAME
@ COLUMN_NONE
@ COLUMN_SIZE
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:288
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
#define AUTOCOMPLETE_FULL_MATCH
#define AUTOCOMPLETE_NO_MATCH
int UI_fontstyle_height_max(const uiFontStyle *fs)
@ UI_STYLE_TEXT_LEFT
@ UI_STYLE_TEXT_RIGHT
int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
const uiStyle * UI_style_get()
void UI_fontstyle_set(const uiFontStyle *fs)
void UI_autocomplete_update_name(AutoComplete *autocpl, blender::StringRef name)
#define UI_UNIT_X
AutoComplete * UI_autocomplete_begin(const char *startname, size_t maxncpy)
#define ICON_DEFAULT_WIDTH_SCALE
#define ICON_DEFAULT_HEIGHT_SCALE
#define V2D_SCROLL_HEIGHT
Definition UI_view2d.hh:53
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
#define NA_ACTIVATED
Definition WM_types.hh:587
#define ND_SPACE_ASSET_PARAMS
Definition WM_types.hh:522
#define NC_ASSET
Definition WM_types.hh:401
#define ND_SPACE_FILE_PARAMS
Definition WM_types.hh:520
#define NC_SPACE
Definition WM_types.hh:389
#define NA_SELECTED
Definition WM_types.hh:586
#define ND_SPACE_FILE_LIST
Definition WM_types.hh:521
int pad[32 - sizeof(int)]
#define U
#define str(s)
bool folderlist_clear_next(SpaceFile *sfile)
void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile)
#define FILE_LAYOUT_HIDE_SIZE(_layout)
#define FILE_LAYOUT_COMPACT(_layout)
void file_on_reload_callback_register(SpaceFile *sfile, onReloadFn callback, onReloadFnData custom_data)
void folder_history_list_free(SpaceFile *sfile)
void * onReloadFnData
void folderlist_pushdir(ListBase *folderlist, const char *dir)
void file_draw_check_ex(bContext *C, ScrArea *area)
Definition file_ops.cc:1742
void file_sfile_to_operator(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile)
Definition file_ops.cc:1688
#define ATTRIBUTE_COLUMN_PADDING
void folderlist_free(ListBase *folderlist)
#define FILE_LAYOUT_HIDE_DATE(_layout)
void filelist_freelib(FileList *filelist)
Definition filelist.cc:2002
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2946
const char * filelist_dir(const FileList *filelist)
Definition filelist.cc:2065
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:1997
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:2100
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:1958
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:2128
void filelist_free(FileList *filelist)
Definition filelist.cc:1972
void filelist_clear(FileList *filelist)
Definition filelist.cc:1953
const char * filelist_entry_get_relpath(const FileList *filelist, int index)
Definition filelist.cc:2320
void filelist_setdir(FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:2075
void filelist_tag_reload_asset_library(FileList *filelist)
Definition filelist.cc:2118
ID * filelist_file_get_id(const FileDirEntry *file)
Definition filelist.cc:2315
int filelist_file_find_path(FileList *filelist, const char *filename)
Definition filelist.cc:2260
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2933
int filelist_file_find_id(const FileList *filelist, const ID *id)
Definition filelist.cc:2280
FileDirEntry * filelist_file_ex(FileList *filelist, const int index, const bool use_request)
Definition filelist.cc:2211
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:4327
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:2110
bool filelist_is_dir(const FileList *filelist, const char *path)
Definition filelist.cc:2070
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2138
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2255
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2123
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2884
@ FILE_SEL_REMOVE
Definition filelist.hh:36
@ FILE_SEL_ADD
Definition filelist.hh:37
@ CHECK_ALL
Definition filelist.hh:44
void ED_fileselect_params_to_userdef(SpaceFile *sfile, const int temp_win_size[2], const bool is_maximized)
Definition filesel.cc:691
void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1361
bool ED_fileselect_is_file_browser(const SpaceFile *sfile)
Definition filesel.cc:465
void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path)
Definition filesel.cc:596
bool file_attribute_column_type_enabled(const FileSelectParams *params, FileAttributeColumnType column, const FileLayout *layout)
Definition filesel.cc:907
int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *region)
Definition filesel.cc:742
FileSelectParams * ED_fileselect_get_active_params(const SpaceFile *sfile)
Definition filesel.cc:382
bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile)
Definition filesel.cc:410
ID * ED_fileselect_active_asset_get(const SpaceFile *sfile)
Definition filesel.cc:484
void file_params_rename_end(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile, const FileDirEntry *rename_file)
Definition filesel.cc:1380
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
Definition filesel.cc:1157
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1367
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
Definition filesel.cc:829
float file_string_width(const char *str)
Definition filesel.cc:965
static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
Definition filesel.cc:98
bool file_attribute_column_header_is_inside(const View2D *v2d, const FileLayout *layout, int x, int y)
Definition filesel.cc:897
static FileSelectParams * fileselect_ensure_updated_file_params(SpaceFile *sfile)
Definition filesel.cc:141
ScrArea * ED_fileselect_handler_area_find(const wmWindow *win, const wmOperator *file_operator)
Definition filesel.cc:1455
void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
Definition filesel.cc:503
void file_params_renamefile_clear(FileSelectParams *params)
Definition filesel.cc:1397
int file_select_match(SpaceFile *sfile, const char *pattern, char *matched_file)
Definition filesel.cc:1205
ScrArea * ED_fileselect_handler_area_find_any_with_op(const wmWindow *win)
Definition filesel.cc:1472
FileSelectParams * ED_fileselect_get_file_params(const SpaceFile *sfile)
Definition filesel.cc:400
static bool is_inside(int x, int y, int cols, int rows)
Definition filesel.cc:772
static void fileselect_initialize_params_common(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:70
void fileselect_refresh_params(SpaceFile *sfile)
Definition filesel.cc:457
FileLayout * ED_fileselect_get_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1149
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, const FileSelectParams *params, FileLayout *layout, int x)
Definition filesel.cc:925
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1490
FileSelectParams * ED_fileselect_ensure_active_params(SpaceFile *sfile)
Definition filesel.cc:363
void file_select_deselect_all(SpaceFile *sfile, const eDirEntry_SelectFlag flag)
Definition filesel.cc:1196
int autocomplete_file(bContext *C, char *str, void *)
Definition filesel.cc:1278
void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1328
bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
Definition filesel.cc:470
void ED_fileselect_deselect_all(SpaceFile *sfile)
Definition filesel.cc:623
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *rect)
Definition filesel.cc:777
void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
Definition filesel.cc:557
FileAssetSelectParams * ED_fileselect_get_asset_params(const SpaceFile *sfile)
Definition filesel.cc:405
void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
Definition filesel.cc:661
static void file_attribute_columns_init(const FileSelectParams *params, FileLayout *layout)
Definition filesel.cc:1020
float file_font_pointsize()
Definition filesel.cc:972
bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
Definition filesel.cc:864
blender::asset_system::AssetLibrary * ED_fileselect_active_asset_library_get(const SpaceFile *sfile)
Definition filesel.cc:475
void ED_fileselect_window_params_get(const wmWindow *win, int r_win_size[2], bool *r_is_maximized)
Definition filesel.cc:633
#define PARAMS_FLAGS_REMEMBERED
Definition filesel.cc:631
static void on_reload_select_by_relpath(SpaceFile *sfile, onReloadFnData custom_data)
Definition filesel.cc:590
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
Definition filesel.cc:419
static int file_params_find_renamed(const FileSelectParams *params, FileList *filelist)
Definition filesel.cc:1404
int autocomplete_directory(bContext *C, char *str, void *)
Definition filesel.cc:1230
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:1411
void fileselect_file_set(bContext *C, SpaceFile *sfile, const int index)
Definition filesel.cc:728
static bool file_select_use_default_display_type(const SpaceFile *sfile)
Definition filesel.cc:645
static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
Definition filesel.cc:551
static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout)
Definition filesel.cc:978
void ED_fileselect_init_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1038
void ED_fileselect_clear_main_assets(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1312
bool ED_fileselect_layout_isect_rect(const FileLayout *layout, const View2D *v2d, const rcti *rect, rcti *r_dst)
Definition filesel.cc:871
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1298
void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
Definition filesel.cc:858
void ED_fileselect_layout_tilepos(const FileLayout *layout, int tile, int *x, int *y)
Definition filesel.cc:881
int ED_fileselect_asset_import_method_get(const SpaceFile *sfile, const FileDirEntry *file)
Definition filesel.cc:515
void ED_file_change_dir(bContext *C)
Definition filesel.cc:1190
static bool file_select_use_default_sort_type(const SpaceFile *sfile)
Definition filesel.cc:653
#define FILTER_ID_ALL
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
const ccl_global KernelWorkTile * tile
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
StringRefNull essentials_directory_path()
VecBase< int32_t, 2 > int2
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost)
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
AssetLibraryReference asset_library_ref
FileSelectParams base_params
AssetRepresentationHandle * asset
FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX]
int attribute_column_header_h
unsigned short list_column_size
unsigned short list_thumbnail_size
unsigned short thumbnail_size
Definition DNA_ID.h:404
void * first
ListBase spacedata
struct wmTimer * smoothscroll_timer
struct FileLayout * layout
struct wmOperator * op
ListBase * folders_prev
struct FileList * files
FileSelectParams * params
FileAssetSelectParams * asset_params
ListBase * folders_next
Universally Unique Identifier according to RFC4122.
char * d_name
float xmin
float ymax
int ymin
int ymax
int xmin
int xmax
uiFontStyle widget
struct wmOperatorType * type
struct PointerRNA * ptr
struct wmWindow * winactive
i
Definition text_draw.cc:230
#define N_(msgid)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, const int eventval)
@ EVT_FILESELECT_EXTERNAL_CANCEL
@ TIMER1
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)
void WM_window_set_dpi(const wmWindow *win)
Definition wm_window.cc:575
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
bool WM_window_is_temp_screen(const wmWindow *win)
bool WM_window_is_maximized(const wmWindow *win)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:139