Blender V5.0
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_alembic"))) {
267 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_ALEMBIC) : 0;
268 }
269 if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
270 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_USD) : 0;
271 }
272 if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
273 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_OBJECT_IO) : 0;
274 }
275 if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
276 params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_VOLUME) : 0;
277 }
278 if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
279 /* Protection against Python scripts not setting proper size limit. */
280 char *glob = RNA_property_string_get_alloc(op->ptr, prop, nullptr, 0, nullptr);
281 BLI_SCOPED_DEFER([&]() { MEM_freeN(glob); });
282 STRNCPY_UTF8(params->filter_glob, glob);
283 /* Fix stupid things that truncating might have generated,
284 * like last group being a 'match everything' wildcard-only one... */
286 if (glob[0] != '\0') {
288 }
289 }
290 else {
291 params->filter_glob[0] = '\0';
292 }
293
294 if (params->filter != 0) {
295 if (U.uiflag & USER_FILTERFILEEXTS) {
296 params->flag |= FILE_FILTER;
297 }
298 else {
299 params->flag &= ~FILE_FILTER;
300 }
301 }
302
303 if (U.uiflag & USER_HIDE_DOT) {
304 params->flag |= FILE_HIDE_DOT;
305 }
306 else {
307 params->flag &= ~FILE_HIDE_DOT;
308 }
309
310 if (params->type == FILE_LOADLIB) {
311 params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0;
312 params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0;
313 params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
314 }
315
316 if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
318 }
319
320 if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
321 params->display = RNA_property_enum_get(op->ptr, prop);
322 }
323
324 if (params->display == FILE_DEFAULTDISPLAY) {
325 params->display = U_default.file_space_data.display_type;
326 }
327
328 if ((prop = RNA_struct_find_property(op->ptr, "sort_method"))) {
329 params->sort = RNA_property_enum_get(op->ptr, prop);
330 }
331
332 if (params->sort == FILE_SORT_DEFAULT) {
333 params->sort = U_default.file_space_data.sort_type;
334 }
335
336 if (is_relative_path) {
337 if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
338 if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
339 RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS) != 0);
340 }
341 }
342 }
343 }
344 else {
345 /* default values, if no operator */
346 params->type = FILE_UNIX;
347 params->flag |= U_default.file_space_data.flag;
348 params->flag &= ~FILE_DIRSEL_ONLY;
349 params->display = FILE_VERTICALDISPLAY;
350 params->sort = FILE_SORT_ALPHA;
351 params->filter = 0;
352 params->filter_glob[0] = '\0';
353 }
354
356
357 return params;
358}
359
361{
362 switch ((eFileBrowse_Mode)sfile->browse_mode) {
364 if (!sfile->params) {
366 }
367 return sfile->params;
369 if (!sfile->asset_params) {
371 }
372 return &sfile->asset_params->base_params;
373 }
374
375 BLI_assert_msg(0, "Invalid browse mode set in file space.");
376 return nullptr;
377}
378
380{
381 if (!sfile) {
382 /* Sometimes called in poll before space type was checked. */
383 return nullptr;
384 }
385
386 switch ((eFileBrowse_Mode)sfile->browse_mode) {
388 return sfile->params;
390 return (FileSelectParams *)sfile->asset_params;
391 }
392
393 BLI_assert_msg(0, "Invalid browse mode set in file space.");
394 return nullptr;
395}
396
398{
399 return (sfile->browse_mode == FILE_BROWSE_MODE_FILES) ? sfile->params : nullptr;
400}
401
403{
404 return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : nullptr;
405}
406
408{
409 const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
410 if (asset_params == nullptr) {
411 return false;
412 }
413 return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL;
414}
415
417{
418 AssetLibraryReference *library = &asset_params->asset_library_ref;
419 FileSelectParams *base_params = &asset_params->base_params;
420 bUserAssetLibrary *user_library = nullptr;
421
422 /* Ensure valid repository, or fall-back to local one. */
423 if (library->type == ASSET_LIBRARY_CUSTOM) {
424 BLI_assert(library->custom_library_index >= 0);
425
427 if (!user_library) {
428 library->type = ASSET_LIBRARY_ALL;
429 }
430 }
431
432 switch (eAssetLibraryType(library->type)) {
435 base_params->type = FILE_ASSET_LIBRARY;
436 break;
438 base_params->dir[0] = '\0';
439 base_params->type = FILE_ASSET_LIBRARY_ALL;
440 break;
442 base_params->dir[0] = '\0';
443 base_params->type = FILE_MAIN_ASSET;
444 break;
446 BLI_assert(user_library);
447 STRNCPY(base_params->dir, user_library->dirpath);
448 BLI_path_slash_native(base_params->dir);
449 base_params->type = FILE_ASSET_LIBRARY;
450 break;
451 }
452}
453
455{
457 if (asset_params) {
459 }
460}
461
463{
464 return (sfile->browse_mode == FILE_BROWSE_MODE_FILES);
465}
466
468{
469 return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
470}
471
473{
474 if (!ED_fileselect_is_asset_browser(sfile) || !sfile->files) {
475 return nullptr;
476 }
477
478 return filelist_asset_library(sfile->files);
479}
480
482{
483 if (!ED_fileselect_is_asset_browser(sfile)) {
484 return nullptr;
485 }
486
487 if (sfile->files == nullptr) {
488 return nullptr;
489 }
490
492 const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
493 if (file == nullptr) {
494 return nullptr;
495 }
496
497 return filelist_file_get_id(file);
498}
499
500void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
501{
502 if (!ED_fileselect_is_asset_browser(sfile)) {
503 return;
504 }
505
507 params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
508 params->catalog_id = catalog_id;
510}
511
513{
514 if (!ED_fileselect_is_asset_browser(sfile) || !file->asset) {
515 return -1;
516 }
517
518 /* First handle the case where the asset system dictates a certain import method. */
519 if (file->asset->may_override_import_method() == false) {
520 BLI_assert(file->asset->get_import_method().has_value());
521 return *file->asset->get_import_method();
522 }
523
525
526 if (params->import_method == FILE_ASSET_IMPORT_FOLLOW_PREFS) {
527 std::optional import_method = file->asset->get_import_method();
528 return import_method ? *import_method : -1;
529 }
530
531 switch (eFileAssetImportMethod(params->import_method)) {
533 return ASSET_IMPORT_LINK;
535 return ASSET_IMPORT_APPEND;
539 return ASSET_IMPORT_PACK;
540
541 /* Should be handled above already. Break and fail below. */
543 break;
544 }
545
547 return -1;
548}
549
550static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
551{
552 ID *asset_id = (ID *)custom_data;
553 ED_fileselect_activate_by_id(sfile, asset_id, false);
554}
555
556void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
557{
558 if (!ED_fileselect_is_asset_browser(sfile)) {
559 return;
560 }
561
562 /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
563 * there is a fair chance that the to-be-activated ID will only be present after these operations
564 * have completed. Defer activation until then. */
565 if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) {
566 /* This should be thread-safe, as this function is likely called from the main thread, and
567 * notifiers (which cause a call to the on-reload callback function) are handled on the main
568 * thread as well. */
570 return;
571 }
572
574 FileList *files = sfile->files;
575
576 const int file_index = filelist_file_find_id(files, asset_id);
577 const FileDirEntry *file = filelist_file_ex(files, file_index, true);
578 if (file == nullptr) {
579 return;
580 }
581
582 params->active_file = file_index;
584
587}
588
590{
591 const char *relative_path = static_cast<const char *>(custom_data);
592 ED_fileselect_activate_by_relpath(sfile, relative_path);
593}
594
595void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path)
596{
597 /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
598 * there is a fair chance that the to-be-activated file at relative_path will only be present
599 * after these operations have completed. Defer activation until then. */
600 FileList *files = sfile->files;
601 if (files == nullptr || filelist_pending(files) || filelist_needs_force_reset(files)) {
602 /* Casting away the constness of `relative_path` is safe here, because eventually it just ends
603 * up in another call to this function, and then it's a const char* again. */
605 return;
606 }
607
609 const int num_files_filtered = filelist_files_ensure(files);
610
611 for (int file_index = 0; file_index < num_files_filtered; ++file_index) {
612 const FileDirEntry *file = filelist_file(files, file_index);
613
614 if (STREQ(file->relpath, relative_path)) {
615 params->active_file = file_index;
617 }
618 }
620}
621
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_dpi_set_userdef(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{
694 UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
695 UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
696
697 sfile_udata_new->thumbnail_size = params->thumbnail_size;
698 sfile_udata_new->details_flags = params->details_flags;
699 sfile_udata_new->flag = params->flag & PARAMS_FLAGS_REMEMBERED;
700 sfile_udata_new->filter_id = params->filter_id;
701
702 /* In some rare cases, operators ask for a specific display or sort type (e.g. chronological
703 * sorting for "Recover Auto Save"). So the settings are optimized for a specific operation.
704 * Don't let that change the userdef memory for more general cases. */
706 sfile_udata_new->display_type = params->display;
707 }
709 sfile_udata_new->sort_type = params->sort;
710 /* In this case also remember the invert flag. */
711 sfile_udata_new->flag = (sfile_udata_new->flag & ~FILE_SORT_INVERT) |
712 (params->flag & FILE_SORT_INVERT);
713 }
714
715 /* Tag preferences as dirty if something has changed. */
716 if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
717 U.runtime.is_dirty = true;
718 }
719}
720
721void fileselect_file_set(bContext *C, SpaceFile *sfile, const int index)
722{
723 const FileDirEntry *file = filelist_file(sfile->files, index);
724 if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) {
726 STRNCPY(params->file, file->relpath);
727 if (sfile->op) {
728 /* Update the filepath properties of the operator. */
729 Main *bmain = CTX_data_main(C);
730 file_sfile_to_operator(C, bmain, sfile->op, sfile);
731 }
732 }
733}
734
736{
737 int numfiles;
738
739 /* Values in pixels.
740 *
741 * - *_item: size of each (row|col), (including padding)
742 * - *_view: (x|y) size of the view.
743 * - *_over: extra pixels, to take into account, when the fit isn't exact
744 * (needed since you may see the end of the previous column and the beginning of the next).
745 *
746 * Could be more clever and take scrolling into account,
747 * but for now don't bother.
748 */
749 if (layout->flag & FILE_LAYOUT_HOR) {
750 const int x_item = layout->tile_w + (2 * layout->tile_border_x);
751 const int x_view = int(BLI_rctf_size_x(&region->v2d.cur));
752 const int x_over = x_item - (x_view % x_item);
753 numfiles = int(float(x_view + x_over) / float(x_item));
754 return numfiles * layout->rows;
755 }
756
757 const int y_item = layout->tile_h + (2 * layout->tile_border_y);
758 const int y_view = int(BLI_rctf_size_y(&region->v2d.cur)) - layout->offset_top;
759 const int y_over = y_item - (y_view % y_item);
760 numfiles = int(float(y_view + y_over) / float(y_item));
761 return numfiles * layout->flow_columns;
762}
763
764static bool is_inside(int x, int y, int cols, int rows)
765{
766 return ((x >= 0) && (x < cols) && (y >= 0) && (y < rows));
767}
768
770{
771 int colmin, colmax, rowmin, rowmax;
772 FileSelection sel;
773 sel.first = sel.last = -1;
774
775 if (layout == nullptr) {
776 return sel;
777 }
778
779 colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x);
780 rowmin = (rect->ymin - layout->offset_top - layout->list_padding_top) /
781 (layout->tile_h + 2 * layout->tile_border_y);
782 colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x);
783 rowmax = (rect->ymax - layout->offset_top - layout->list_padding_top) /
784 (layout->tile_h + 2 * layout->tile_border_y);
785
786 if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) ||
787 is_inside(colmax, rowmax, layout->flow_columns, layout->rows))
788 {
789 CLAMP(colmin, 0, layout->flow_columns - 1);
790 CLAMP(rowmin, 0, layout->rows - 1);
791 CLAMP(colmax, 0, layout->flow_columns - 1);
792 CLAMP(rowmax, 0, layout->rows - 1);
793 }
794
795 if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) {
796 sel.first = -1;
797 }
798 else {
799 if (layout->flag & FILE_LAYOUT_HOR) {
800 sel.first = layout->rows * colmin + rowmin;
801 }
802 else {
803 sel.first = colmin + layout->flow_columns * rowmin;
804 }
805 }
806 if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) {
807 sel.last = -1;
808 }
809 else {
810 if (layout->flag & FILE_LAYOUT_HOR) {
811 sel.last = layout->rows * colmax + rowmax;
812 }
813 else {
814 sel.last = colmax + layout->flow_columns * rowmax;
815 }
816 }
817
818 return sel;
819}
820
822{
823 int offsetx, offsety;
824 int active_file;
825
826 if (layout == nullptr) {
827 return -1;
828 }
829
830 offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x);
831 offsety = (y - layout->offset_top - layout->list_padding_top) /
832 (layout->tile_h + 2 * layout->tile_border_y);
833
834 if (offsetx > layout->flow_columns - 1) {
835 return -1;
836 }
837 if (offsety > layout->rows - 1) {
838 return -1;
839 }
840
841 if (layout->flag & FILE_LAYOUT_HOR) {
842 active_file = layout->rows * offsetx + offsety;
843 }
844 else {
845 active_file = offsetx + layout->flow_columns * offsety;
846 }
847 return active_file;
848}
849
850void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
851{
852 *r_rect = v2d->mask;
853 r_rect->ymax -= layout->offset_top;
854}
855
856bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
857{
858 rcti maskrect;
859 ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
860 return BLI_rcti_isect_pt(&maskrect, x, y);
861}
862
864 const View2D *v2d,
865 const rcti *rect,
866 rcti *r_dst)
867{
868 rcti maskrect;
869 ED_fileselect_layout_maskrect(layout, v2d, &maskrect);
870 return BLI_rcti_isect(&maskrect, rect, r_dst);
871}
872
873void ED_fileselect_layout_tilepos(const FileLayout *layout, int tile, int *x, int *y)
874{
875 if (layout->flag == FILE_LAYOUT_HOR) {
876 *x = layout->tile_border_x +
877 (tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x);
878 *y = layout->offset_top + layout->list_padding_top + layout->tile_border_y +
879 (tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y);
880 }
881 else {
882 *x = layout->tile_border_x +
883 ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x);
884 *y = layout->offset_top + layout->list_padding_top + layout->tile_border_y +
885 ((tile) / layout->flow_columns) * (layout->tile_h + 2 * layout->tile_border_y);
886 }
887}
888
890 const FileLayout *layout,
891 int x,
892 int y)
893{
894 rcti header_rect = v2d->mask;
895 header_rect.ymin = header_rect.ymax - layout->attribute_column_header_h;
896 return BLI_rcti_isect_pt(&header_rect, x, y);
897}
898
901 const FileLayout *layout)
902{
903 switch (column) {
904 case COLUMN_NAME:
905 /* Always enabled */
906 return true;
907 case COLUMN_DATETIME:
908 return ((params->details_flags & FILE_DETAILS_DATETIME) != 0) &&
909 !FILE_LAYOUT_HIDE_DATE(layout);
910 case COLUMN_SIZE:
911 return ((params->details_flags & FILE_DETAILS_SIZE) != 0) && !FILE_LAYOUT_HIDE_SIZE(layout);
912 default:
913 return false;
914 }
915}
916
919 FileLayout *layout,
920 int x)
921{
922 float mx, my;
923 int offset_tile;
924
925 UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my);
926 offset_tile = ED_fileselect_layout_offset(
927 layout, int(v2d->tot.xmin + mx), int(v2d->tot.ymax - my));
928 if (offset_tile > -1) {
929 int tile_x, tile_y;
930 int pos_x = 0;
931 int rel_x; /* x relative to the hovered tile */
932
933 ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y);
934 /* Column header drawing doesn't use left tile border, so subtract it. */
935 rel_x = mx - (tile_x - layout->tile_border_x);
936
938 column < ATTRIBUTE_COLUMN_MAX;
939 column = FileAttributeColumnType(int(column) + 1))
940 {
941 if (!file_attribute_column_type_enabled(params, column, layout)) {
942 continue;
943 }
944 const int width = layout->attribute_columns[column].width;
945
946 if (IN_RANGE(rel_x, pos_x, pos_x + width)) {
947 return column;
948 }
949
950 pos_x += width;
951 }
952 }
953
954 return COLUMN_NONE;
955}
956
957float file_string_width(const char *str)
958{
959 const uiStyle *style = UI_style_get();
960 UI_fontstyle_set(&style->widget);
962}
963
965{
966 const uiStyle *style = UI_style_get();
967 return UI_fontstyle_height_max(&style->widget);
968}
969
971{
972 FileAttributeColumn *columns = layout->attribute_columns;
973 const int pad = ATTRIBUTE_COLUMN_PADDING * 2;
974 const bool compact = FILE_LAYOUT_COMPACT(layout);
975
976 for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) {
977 layout->attribute_columns[i].width = 0;
978 }
979
980 /* Biggest possible reasonable values... */
982 columns[COLUMN_DATETIME].width = file_string_width(compact ? "23/08/89" :
983 "23 Dec 6789, 23:59") +
984 pad;
985 }
987 columns[COLUMN_SIZE].width = file_string_width(compact ? "369G" : "098.7 MiB") + pad;
988 }
989
990 if (params->display == FILE_IMGDISPLAY) {
991 columns[COLUMN_NAME].width = (float(params->thumbnail_size) / 8.0f) * UI_UNIT_X;
992 }
993 /* Name column uses remaining width */
994 else {
995 int remwidth = layout->tile_w;
996 for (FileAttributeColumnType column_type =
998 column_type >= 0;
999 column_type = FileAttributeColumnType(int(column_type) - 1))
1000 {
1001 if ((column_type == COLUMN_NAME) ||
1002 !file_attribute_column_type_enabled(params, column_type, layout))
1003 {
1004 continue;
1005 }
1006 remwidth -= columns[column_type].width;
1007 }
1008 columns[COLUMN_NAME].width = remwidth;
1009 }
1010}
1011
1029
1031{
1033 FileLayout *layout = nullptr;
1034 View2D *v2d = &region->v2d;
1035 int numfiles;
1036
1037 if (sfile->layout == nullptr) {
1038 sfile->layout = MEM_callocN<FileLayout>("file_layout");
1039 sfile->layout->dirty = true;
1040 }
1041 else if (sfile->layout->dirty == false) {
1042 return;
1043 }
1044
1045 numfiles = filelist_files_ensure(sfile->files);
1046 layout = sfile->layout;
1047 /* Slightly increased than font height for padding. */
1049 layout->text_lines_count = 1;
1050
1051 if (params->display == FILE_IMGDISPLAY) {
1052 /* More compact spacing for asset browser. */
1053 const float pad_fac = ED_fileselect_is_asset_browser(sfile) ? 0.15f : 0.3f;
1054 /* Matches UI_preview_tile_size_x()/_y() by default. */
1055 layout->prv_w = (float(params->thumbnail_size) / 20.0f) * UI_UNIT_X;
1056 layout->prv_h = (float(params->thumbnail_size) / 20.0f) * UI_UNIT_Y;
1057 layout->tile_border_x = pad_fac * UI_UNIT_X;
1058 layout->tile_border_y = pad_fac * UI_UNIT_X;
1059 layout->list_padding_top = 0;
1060 layout->prv_border_x = pad_fac * UI_UNIT_X;
1061 layout->prv_border_y = pad_fac * UI_UNIT_Y;
1062 layout->tile_w = layout->prv_w + 2 * layout->prv_border_x;
1063 layout->text_lines_count = 2;
1064 layout->tile_h = layout->prv_h + 2 * layout->prv_border_y +
1065 layout->text_lines_count * layout->text_line_height;
1066 layout->width = int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1067 layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x);
1068 layout->attribute_column_header_h = 0;
1069 layout->offset_top = 0;
1070 if (layout->flow_columns > 0) {
1071 layout->rows = divide_ceil_u(numfiles, layout->flow_columns);
1072 }
1073 else {
1074 layout->flow_columns = 1;
1075 layout->rows = numfiles;
1076 }
1077 layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
1078 layout->tile_border_y * 2 - layout->offset_top;
1079 layout->flag = FILE_LAYOUT_VER;
1080 }
1081 else if (params->display == FILE_VERTICALDISPLAY) {
1082 int rowcount;
1083
1086 layout->tile_border_x = 0.4f * UI_UNIT_X;
1087 layout->tile_border_y = 0.05f * UI_UNIT_Y;
1088 layout->list_padding_top = 2 * layout->tile_border_y;
1089 layout->tile_h = round_fl_to_int(layout->text_line_height * 1.4f);
1090 layout->width = int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1091 layout->tile_w = layout->width;
1092 layout->flow_columns = 1;
1093 layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y;
1094 layout->offset_top = layout->attribute_column_header_h;
1095 rowcount = int(BLI_rctf_size_y(&v2d->cur) - layout->offset_top -
1096 2 * layout->list_padding_top) /
1097 (layout->tile_h + 2 * layout->tile_border_y);
1099
1100 layout->rows = std::max(rowcount, numfiles);
1101
1102 /* layout->rows can be zero if a very small area is changed to a File Browser. #124168. */
1103
1104 layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
1105 layout->list_padding_top * 2 + layout->offset_top;
1106 layout->flag = FILE_LAYOUT_VER;
1107 }
1108 else if (params->display == FILE_HORIZONTALDISPLAY) {
1109 layout->prv_w = params->list_thumbnail_size * UI_SCALE_FAC;
1110 layout->prv_h = params->list_thumbnail_size * UI_SCALE_FAC;
1111 layout->tile_border_x = 0.4f * UI_UNIT_X;
1112 layout->tile_border_y = 0.05f * UI_UNIT_Y;
1113 layout->list_padding_top = 2 * layout->tile_border_y;
1114 layout->tile_h = std::max(round_fl_to_int(layout->text_line_height * 1.4f), layout->prv_h);
1115 layout->attribute_column_header_h = 0;
1116 layout->offset_top = layout->attribute_column_header_h;
1117 layout->height = int(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y);
1118 /* Padding by full scroll-bar H is too much, can overlap tile border Y. */
1119 layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) /
1120 (layout->tile_h + 2 * layout->tile_border_y);
1121
1122 layout->tile_w = params->list_column_size * UI_SCALE_FAC;
1124
1125 if (layout->rows > 0) {
1126 layout->flow_columns = divide_ceil_u(numfiles, layout->rows);
1127 }
1128 else {
1129 layout->rows = 1;
1130 layout->flow_columns = numfiles;
1131 }
1132 layout->width = (numfiles > 0) ? (sfile->layout->flow_columns *
1133 (layout->tile_w + 2 * layout->tile_border_x) +
1134 layout->tile_border_x * 2) :
1135 int(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x);
1136 layout->flag = FILE_LAYOUT_HOR;
1137 }
1138 layout->dirty = false;
1139}
1140
1142{
1143 if (!sfile->layout) {
1144 ED_fileselect_init_layout(sfile, region);
1145 }
1146 return sfile->layout;
1147}
1148
1150{
1151 /* May happen when manipulating non-active spaces. */
1152 if (UNLIKELY(area->spacetype != SPACE_FILE)) {
1153 return;
1154 }
1155 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1157 if (params) {
1159 ED_fileselect_clear(wm, sfile);
1160
1161 /* Clear search string, it is very rare to want to keep that filter while changing dir,
1162 * and usually very annoying to keep it actually! */
1163 params->filter_search[0] = '\0';
1164 params->active_file = -1;
1165
1166 if (!filelist_is_dir(sfile->files, params->dir)) {
1167 STRNCPY(params->dir, filelist_dir(sfile->files));
1168 /* could return but just refresh the current dir */
1169 }
1170 filelist_setdir(sfile->files, params->dir);
1171
1172 if (folderlist_clear_next(sfile)) {
1174 }
1175
1177
1178 file_draw_check_ex(C, area);
1179 }
1180}
1181
1183{
1184 ScrArea *area = CTX_wm_area(C);
1185 ED_file_change_dir_ex(C, area);
1186}
1187
1189{
1190 FileSelection sel;
1191 sel.first = 0;
1192 sel.last = filelist_files_ensure(sfile->files) - 1;
1193
1195}
1196
1197int file_select_match(SpaceFile *sfile, const char *pattern, char *matched_file)
1198{
1199 int match = 0;
1200
1201 int n = filelist_files_ensure(sfile->files);
1202
1203 /* select any file that matches the pattern, this includes exact match
1204 * if the user selects a single file by entering the filename
1205 */
1206 for (int i = 0; i < n; i++) {
1207 const char *relpath = filelist_entry_get_relpath(sfile->files, i);
1208 /* Do not check whether file is a file or dir here! Causes: #44243
1209 * (we do accept directories at this stage). */
1210 if (fnmatch(pattern, relpath, 0) == 0) {
1212 if (!match) {
1213 BLI_strncpy(matched_file, relpath, FILE_MAX);
1214 }
1215 match++;
1216 }
1217 }
1218
1219 return match;
1220}
1221
1222int autocomplete_directory(bContext *C, char *str, void * /*arg_v*/)
1223{
1224 SpaceFile *sfile = CTX_wm_space_file(C);
1225 int match = AUTOCOMPLETE_NO_MATCH;
1226
1227 /* search if str matches the beginning of name */
1228 if (str[0] && sfile->files) {
1229 char dirname[FILE_MAX];
1230
1231 DIR *dir;
1232 dirent *de;
1233
1235
1237 dir = opendir(dirname);
1238
1239 if (dir) {
1241
1242 while ((de = readdir(dir)) != nullptr) {
1243 if (FILENAME_IS_CURRPAR(de->d_name)) {
1244 /* pass */
1245 }
1246 else {
1247 char dirpath[FILE_MAX];
1249
1250 BLI_path_join(dirpath, sizeof(dirpath), dirname, de->d_name);
1251
1252 if (BLI_stat(dirpath, &status) == 0) {
1253 if (S_ISDIR(status.st_mode)) { /* is subdir */
1254 UI_autocomplete_update_name(autocpl, dirpath);
1255 }
1256 }
1257 }
1258 }
1259 closedir(dir);
1260
1261 match = UI_autocomplete_end(autocpl, str);
1262 if (match == AUTOCOMPLETE_FULL_MATCH) {
1264 }
1265 }
1266 }
1267
1268 return match;
1269}
1270
1271int autocomplete_file(bContext *C, char *str, void * /*arg_v*/)
1272{
1273 SpaceFile *sfile = CTX_wm_space_file(C);
1274 int match = AUTOCOMPLETE_NO_MATCH;
1275
1276 /* search if str matches the beginning of name */
1277 if (str[0] && sfile->files) {
1279 int nentries = filelist_files_ensure(sfile->files);
1280
1281 for (int i = 0; i < nentries; i++) {
1282 const char *relpath = filelist_entry_get_relpath(sfile->files, i);
1283 UI_autocomplete_update_name(autocpl, relpath);
1284 }
1285 match = UI_autocomplete_end(autocpl, str);
1286 }
1287
1288 return match;
1289}
1290
1292{
1293 /* Only null in rare cases, see: #29734. */
1294 if (sfile->files) {
1295 filelist_readjob_stop(sfile->files, wm);
1296 filelist_freelib(sfile->files);
1297 filelist_clear(sfile->files);
1298 }
1299
1301 params->highlight_file = -1;
1303}
1304
1306{
1307 /* Only null in rare cases, see: #29734. */
1308 if (sfile->files) {
1309 filelist_readjob_stop(sfile->files, wm);
1310 filelist_freelib(sfile->files);
1314 }
1315
1317 params->highlight_file = -1;
1319}
1320
1322{
1323 if (!sfile) {
1324 return;
1325 }
1326 if (sfile->op) {
1329 sfile->op = nullptr;
1330 }
1331
1333
1334 if (sfile->files) {
1335 ED_fileselect_clear(wm, sfile);
1336 filelist_free(sfile->files);
1337 sfile->files = nullptr;
1338 }
1339}
1340
1342{
1344 sfile->smoothscroll_timer = nullptr;
1345}
1346
1348{
1350
1352
1353 if (sfile->smoothscroll_timer != nullptr) {
1355 }
1356 sfile->smoothscroll_timer = WM_event_timer_add(wm, win, TIMER1, 1.0 / 1000.0);
1357 sfile->scroll_offset = 0;
1358}
1359
1361 wmWindow *win,
1362 SpaceFile *sfile,
1363 const FileDirEntry *rename_file)
1364{
1366
1368 sfile->files, rename_file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL);
1369
1370 /* Ensure smooth-scroll timer is active, even if not needed, because that way rename state is
1371 * handled properly. */
1373 /* Also always activate the rename file, even if renaming was canceled. */
1375}
1376
1378{
1379 params->renamefile[0] = '\0';
1380 params->rename_id = nullptr;
1381 params->rename_flag = 0;
1382}
1383
1385{
1386 /* Find the file either through the local ID/asset it represents or its relative path. */
1387 return (params->rename_id != nullptr) ? filelist_file_find_id(filelist, params->rename_id) :
1388 filelist_file_find_path(filelist, params->renamefile);
1389}
1390
1392{
1393 BLI_assert(params->rename_flag != 0);
1394
1396 0)
1397 {
1398 return;
1399 }
1400
1401 BLI_assert(params->renamefile[0] != '\0' || params->rename_id != nullptr);
1402
1403 int idx = file_params_find_renamed(params, sfile->files);
1404 if (idx >= 0) {
1405 FileDirEntry *file = filelist_file(sfile->files, idx);
1406 BLI_assert(file != nullptr);
1407
1408 params->active_file = idx;
1410
1411 if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) {
1413 params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
1414 }
1415 else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
1416 /* file_select_deselect_all() will resort and re-filter, so `idx` will probably have changed.
1417 * Need to get the correct #FileDirEntry again. */
1419 idx = file_params_find_renamed(params, sfile->files);
1420 file = filelist_file(sfile->files, idx);
1423 params->active_file = idx;
1426 }
1427 }
1428 /* File listing is now asynchronous, only reset renaming if matching entry is not found
1429 * when file listing is not done. */
1430 else if (filelist_is_ready(sfile->files)) {
1432 }
1433}
1434
1436{
1437 bScreen *screen = WM_window_get_active_screen(win);
1438
1439 ED_screen_areas_iter (win, screen, area) {
1440 if (area->spacetype == SPACE_FILE) {
1441 SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1442
1443 if (sfile->op == file_operator) {
1444 return area;
1445 }
1446 }
1447 }
1448
1449 return nullptr;
1450}
1451
1453{
1454 const bScreen *screen = WM_window_get_active_screen(win);
1455
1456 ED_screen_areas_iter (win, screen, area) {
1457 if (area->spacetype != SPACE_FILE) {
1458 continue;
1459 }
1460
1461 const SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
1462 if (sfile->op) {
1463 return area;
1464 }
1465 }
1466
1467 return nullptr;
1468}
1469
1471{
1472 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
1473 Main *bmain = CTX_data_main(C);
1474 char filepath[FILE_MAX];
1475 const char *blendfile_path = BKE_main_blendfile_path(bmain);
1476
1477 if (blendfile_path[0] == '\0') {
1478 STRNCPY(filepath, DATA_("Untitled"));
1479 }
1480 else {
1481 STRNCPY(filepath, blendfile_path);
1482 }
1483
1484 BLI_path_extension_replace(filepath, sizeof(filepath), extension);
1485 RNA_string_set(op->ptr, "filepath", filepath);
1486 }
1487}
1488
1490{
1492 char path[FILE_MAX_LIBEXTRA];
1493 for (const int i : blender::IndexRange(filelist_files_ensure(sfile->files))) {
1494 if (filelist_entry_is_selected(sfile->files, i)) {
1495 const FileDirEntry *entry = filelist_file(sfile->files, i);
1496 filelist_file_get_full_path(sfile->files, entry, path);
1497 paths.append(path);
1498 }
1499 }
1500 return paths;
1501}
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:887
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:892
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:440
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:802
#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_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
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:693
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 STRNCPY_UTF8(dst, src)
#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)
#define FILTER_ID_ALL
Definition DNA_ID.h:1239
@ ASSET_IMPORT_PACK
@ 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_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_PACK
@ 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_MAX_LIBEXTRA
#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:296
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:1668
#define NA_ACTIVATED
Definition WM_types.hh:590
#define ND_SPACE_ASSET_PARAMS
Definition WM_types.hh:525
#define NC_ASSET
Definition WM_types.hh:404
#define ND_SPACE_FILE_PARAMS
Definition WM_types.hh:523
#define NC_SPACE
Definition WM_types.hh:392
#define NA_SELECTED
Definition WM_types.hh:589
#define ND_SPACE_FILE_LIST
Definition WM_types.hh:524
int pad[32 - sizeof(int)]
#define U
void append(const T &value)
nullptr float
#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:1748
void file_sfile_to_operator(bContext *C, Main *bmain, wmOperator *op, SpaceFile *sfile)
Definition file_ops.cc:1694
#define ATTRIBUTE_COLUMN_PADDING
void folderlist_free(ListBase *folderlist)
#define FILE_LAYOUT_HIDE_DATE(_layout)
void filelist_freelib(FileList *filelist)
Definition filelist.cc:1032
void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, char r_filepath[1282])
const char * filelist_dir(const FileList *filelist)
Definition filelist.cc:1095
FileDirEntry * filelist_file_ex(FileList *filelist, int index, bool use_request)
Definition filelist.cc:1241
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:1027
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:1130
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:988
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:1158
void filelist_setdir(FileList *filelist, char dirpath[1282])
void filelist_entry_select_index_set(FileList *filelist, int index, FileSelType select, eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:1959
void filelist_free(FileList *filelist)
Definition filelist.cc:1002
void filelist_clear(FileList *filelist)
Definition filelist.cc:983
const char * filelist_entry_get_relpath(const FileList *filelist, int index)
Definition filelist.cc:1350
void filelist_tag_reload_asset_library(FileList *filelist)
Definition filelist.cc:1148
ID * filelist_file_get_id(const FileDirEntry *file)
Definition filelist.cc:1345
int filelist_file_find_path(FileList *filelist, const char *filename)
Definition filelist.cc:1290
@ FILE_SEL_REMOVE
Definition filelist.hh:36
@ FILE_SEL_ADD
Definition filelist.hh:37
int filelist_file_find_id(const FileList *filelist, const ID *id)
Definition filelist.cc:1310
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:3356
@ 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
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:1140
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
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 file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1341
bool ED_fileselect_is_file_browser(const SpaceFile *sfile)
Definition filesel.cc:462
void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path)
Definition filesel.cc:595
bool file_attribute_column_type_enabled(const FileSelectParams *params, FileAttributeColumnType column, const FileLayout *layout)
Definition filesel.cc:899
void ED_fileselect_params_to_userdef(SpaceFile *sfile)
Definition filesel.cc:691
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
bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile)
Definition filesel.cc:407
ID * ED_fileselect_active_asset_get(const SpaceFile *sfile)
Definition filesel.cc:481
void file_params_rename_end(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile, const FileDirEntry *rename_file)
Definition filesel.cc:1360
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
Definition filesel.cc:1149
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
Definition filesel.cc:1347
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
Definition filesel.cc:821
float file_string_width(const char *str)
Definition filesel.cc:957
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:889
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:1435
void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id)
Definition filesel.cc:500
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
ScrArea * ED_fileselect_handler_area_find_any_with_op(const wmWindow *win)
Definition filesel.cc:1452
FileSelectParams * ED_fileselect_get_file_params(const SpaceFile *sfile)
Definition filesel.cc:397
static bool is_inside(int x, int y, int cols, int rows)
Definition filesel.cc:764
static void fileselect_initialize_params_common(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:70
void fileselect_refresh_params(SpaceFile *sfile)
Definition filesel.cc:454
FileLayout * ED_fileselect_get_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1141
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, const FileSelectParams *params, FileLayout *layout, int x)
Definition filesel.cc:917
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1470
blender::Vector< std::string > ED_fileselect_selected_files_full_paths(const SpaceFile *sfile)
Definition filesel.cc:1489
FileSelectParams * ED_fileselect_ensure_active_params(SpaceFile *sfile)
Definition filesel.cc:360
void file_select_deselect_all(SpaceFile *sfile, const eDirEntry_SelectFlag flag)
Definition filesel.cc:1188
int autocomplete_file(bContext *C, char *str, void *)
Definition filesel.cc:1271
void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1321
bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
Definition filesel.cc:467
void ED_fileselect_deselect_all(SpaceFile *sfile)
Definition filesel.cc:622
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *rect)
Definition filesel.cc:769
void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
Definition filesel.cc:556
FileAssetSelectParams * ED_fileselect_get_asset_params(const SpaceFile *sfile)
Definition filesel.cc:402
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:1012
float file_font_pointsize()
Definition filesel.cc:964
bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y)
Definition filesel.cc:856
blender::asset_system::AssetLibrary * ED_fileselect_active_asset_library_get(const SpaceFile *sfile)
Definition filesel.cc:472
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:589
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
Definition filesel.cc:416
static int file_params_find_renamed(const FileSelectParams *params, FileList *filelist)
Definition filesel.cc:1384
int autocomplete_directory(bContext *C, char *str, void *)
Definition filesel.cc:1222
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
Definition filesel.cc:1391
void fileselect_file_set(bContext *C, SpaceFile *sfile, const int index)
Definition filesel.cc:721
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:550
static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout)
Definition filesel.cc:970
void ED_fileselect_init_layout(SpaceFile *sfile, ARegion *region)
Definition filesel.cc:1030
void ED_fileselect_clear_main_assets(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1305
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_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
Definition filesel.cc:850
void ED_fileselect_layout_tilepos(const FileLayout *layout, int tile, int *x, int *y)
Definition filesel.cc:873
int ED_fileselect_asset_import_method_get(const SpaceFile *sfile, const FileDirEntry *file)
Definition filesel.cc:512
void ED_file_change_dir(bContext *C)
Definition filesel.cc:1182
static bool file_select_use_default_sort_type(const SpaceFile *sfile)
Definition filesel.cc:653
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
const int status
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_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
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:414
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
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_dpi_set_userdef(const wmWindow *win)
Definition wm_window.cc:654
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
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:145