diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenlib/intern/storage.c | 56 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 79 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_ops.c | 28 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 96 |
4 files changed, 180 insertions, 79 deletions
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 87536ea8116..fbfb258693b 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -55,6 +55,7 @@ # include "utfconv.h" # include <direct.h> # include <io.h> +# include <shobjidl_core.h> # include <stdbool.h> #else # include <pwd.h> @@ -226,12 +227,18 @@ size_t BLI_file_size(const char *path) return stats.st_size; } +/* Return file attributes. Apple version of this function is defined in storage_apple.mm */ #ifndef __APPLE__ eFileAttributes BLI_file_attributes(const char *path) { int ret = 0; # ifdef WIN32 + + if (BLI_path_extension_check(path, ".lnk")) { + return FILE_ATTR_ALIAS; + } + WCHAR wline[FILE_MAXDIR]; if (conv_utf_8_to_16(path, wline, ARRAY_SIZE(wline)) != 0) { return ret; @@ -284,15 +291,52 @@ eFileAttributes BLI_file_attributes(const char *path) } #endif -/** - * Returns the target path of a file-based redirection, like Mac Alias or Win32 Shortcut file. - */ +/* Return alias/shortcut file target. Apple version is defined in storage_apple.mm */ #ifndef __APPLE__ -bool BLI_file_alias_target(char UNUSED(target[FILE_MAXDIR]), const char *UNUSED(filepath)) +bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath) { - /* TODO: Find target in Win32 Shortcut - Shell Link (.lnk) file. - * Format: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ */ +# ifdef WIN32 + if (!BLI_path_extension_check(filepath, ".lnk")) { + return false; + } + + IShellLinkW *Shortcut = NULL; + bool success = false; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + HRESULT hr = CoCreateInstance( + &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID *)&Shortcut); + if (SUCCEEDED(hr)) { + IPersistFile *PersistFile; + hr = Shortcut->lpVtbl->QueryInterface(Shortcut, &IID_IPersistFile, (LPVOID *)&PersistFile); + if (SUCCEEDED(hr)) { + WCHAR path_utf16[FILE_MAXDIR] = {0}; + if (conv_utf_8_to_16(filepath, path_utf16, ARRAY_SIZE(path_utf16)) == 0) { + hr = PersistFile->lpVtbl->Load(PersistFile, path_utf16, STGM_READ); + if (SUCCEEDED(hr)) { + hr = Shortcut->lpVtbl->Resolve(Shortcut, 0, SLR_NO_UI | SLR_UPDATE); + if (SUCCEEDED(hr)) { + wchar_t target_utf16[FILE_MAXDIR] = {0}; + hr = Shortcut->lpVtbl->GetPath(Shortcut, target_utf16, FILE_MAXDIR, NULL, 0); + if (SUCCEEDED(hr)) { + success = (conv_utf_16_to_8(target_utf16, target, FILE_MAXDIR) == 0); + } + } + PersistFile->lpVtbl->Release(PersistFile); + } + } + } + Shortcut->lpVtbl->Release(Shortcut); + } + + return (success && target[0]); +# endif + +# ifdef __linux__ + UNUSED_VARS(target, filepath); + /* File-based redirection not supported. */ return false; +# endif } #endif diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 226e7ae6b22..8d14664c0fa 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block, const bool is_icon, const int typeflags, const bool drag, - const bool dimmed) + const bool dimmed, + const bool is_link) { uiBut *but; float fx, fy; @@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block, GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - if (icon && !(typeflags & FILE_TYPE_FTFONT)) { - /* size of center icon is scaled to fit container and UI scale */ + if (icon && is_icon) { + /* Small icon in the middle of large image, scaled to fit container and UI scale */ float icon_x, icon_y; - - if (is_icon) { - const float icon_size = 16.0f / icon_aspect * U.dpi_fac; - float icon_opacity = 0.3f; - uchar icon_color[4] = {0, 0, 0, 255}; - float bgcolor[4]; - UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); - if (rgb_to_grayscale(bgcolor) < 0.5f) { - icon_color[0] = 255; - icon_color[1] = 255; - icon_color[2] = 255; - } - icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); - icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + const float icon_size = 16.0f / icon_aspect * U.dpi_fac; + float icon_opacity = 0.3f; + uchar icon_color[4] = {0, 0, 0, 255}; + float bgcolor[4]; + UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); + if (rgb_to_grayscale(bgcolor) < 0.5f) { + icon_color[0] = 255; + icon_color[1] = 255; + icon_color[2] = 255; } - else { + icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); + icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); + UI_icon_draw_ex( + icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + } + + if (is_link) { + /* Arrow icon to indicate it is a shortcut, link, or alias. */ + float icon_x, icon_y; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + const int arrow = ICON_LOOP_FORWARDS; + if (!is_icon) { + /* Arrow at very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - - /* Smaller, fainter icon for preview image thumbnail. */ - icon_x = xco + (2.0f * UI_DPI_FAC); - icon_y = yco + (2.0f * UI_DPI_FAC); - - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } + else { + /* Link to folder or non-previewed file. */ + uchar icon_color[4]; + UI_GetThemeColor4ubv(TH_BACK, icon_color); + icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; + icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; + UI_icon_draw_ex( + icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + } + } + else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) { + /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */ + float icon_x, icon_y; + const uchar dark[4] = {0, 0, 0, 255}; + const uchar light[4] = {255, 255, 255, 255}; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } /* Contrasting outline around some preview types. */ @@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region) /* don't drag parent or refresh items */ do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN); + const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK); if (FILE_IMGDISPLAY == params->display) { const int icon = filelist_geticon(files, i, false); @@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region) is_icon, file->typeflag, do_drag, - is_hidden); + is_hidden, + is_link); } else { file_draw_icon(block, diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index a5263378850..41d32fda088 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { FileDirEntry *file = filelist_file(sfile->files, i); - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", file->relpath); - num_files++; + /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */ + if (!file->redirection_path) { + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", file->relpath); + num_files++; + } } } /* make sure the file specified in the filename button is added even if no @@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); char filepath[FILE_MAX]; + if (file && file->redirection_path) { + /* redirection_path is an absolute path that takes precedence + * over using sfile->params->dir + sfile->params->file. */ + BLI_split_dirfile(file->redirection_path, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + /* Update relpath with redirected filename as well so that the alternative + * combination of sfile->params->dir + relpath remains valid as well. */ + MEM_freeN(file->relpath); + file->relpath = BLI_strdup(sfile->params->file); + } + /* directory change */ if (file && (file->typeflag & FILE_TYPE_DIR)) { if (!file->relpath) { @@ -1634,9 +1651,6 @@ static int file_exec(bContext *C, wmOperator *exec_op) BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); BLI_path_slash_ensure(sfile->params->dir); } - if (file->redirection_path) { - STRNCPY(sfile->params->dir, file->redirection_path); - } ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 7f6d0658ec8..d8d7ef01a2e 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file, /* If this path is in System list or path cache then use that icon. */ struct FSMenu *fsmenu = ED_fsmenu_get(); FSMenuCategory categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_OTHER, }; @@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file, for (int i = 0; i < ARRAY_SIZE(categories); i++) { FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]); char fullpath[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); - BLI_path_slash_ensure(fullpath); + char *target = fullpath; + if (file->redirection_path) { + target = file->redirection_path; + } + else { + BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); + BLI_path_slash_ensure(fullpath); + } for (; tfsm; tfsm = tfsm->next) { - if (STREQ(tfsm->path, fullpath)) { + if (STREQ(tfsm->path, target)) { /* Never want a little folder inside a large one. */ return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon; } @@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file, } } - if (file->attributes & FILE_ATTR_ANY_LINK) { - return ICON_LOOP_FORWARDS; - } - else if (file->attributes & FILE_ATTR_OFFLINE) { + if (file->attributes & FILE_ATTR_OFFLINE) { return ICON_ERROR; } else if (file->attributes & FILE_ATTR_TEMPORARY) { @@ -1375,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - BLI_join_dirfile( - preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + + if (entry->redirection_path) { + BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); + } + else { + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + } + preview->index = index; preview->flags = entry->typeflag; preview->img = NULL; @@ -2270,13 +2281,6 @@ int ED_path_extension_type(const char *path) return 0; } -static int file_extension_type(const char *dir, const char *relpath) -{ - char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), dir, relpath); - return ED_path_extension_type(path); -} - int ED_file_extension_icon(const char *path) { const int type = ED_path_extension_type(path); @@ -2475,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root, { struct direntry *files; int nbr_files, nbr_entries = 0; - char path[FILE_MAX]; + /* Full path of the item. */ + char full_path[FILE_MAX]; nbr_files = BLI_filelist_dir_contents(root, &files); if (files) { @@ -2491,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = MEM_dupallocN(files[i].relname); entry->st = files[i].s; - BLI_join_dirfile(path, sizeof(path), root, entry->relpath); + BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath); + char *target = full_path; - /* Set file type. */ + /* Set initial file type and attributes. */ + entry->attributes = BLI_file_attributes(full_path); if (S_ISDIR(files[i].s.st_mode)) { entry->typeflag = FILE_TYPE_DIR; } - else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { - /* If we are considering .blend files as libs, promote them to directory status. */ - entry->typeflag = FILE_TYPE_BLENDER; - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, path) != 0) { - entry->typeflag |= FILE_TYPE_DIR; - } - } - /* Otherwise, do not check extensions for directories! */ - else if (!(entry->typeflag & FILE_TYPE_DIR)) { - entry->typeflag = file_extension_type(root, entry->relpath); - if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { - entry->typeflag |= FILE_TYPE_OPERATOR; - } - } - /* Set file attributes. */ - entry->attributes = BLI_file_attributes(path); + /* Is this a file that points to another file? */ if (entry->attributes & FILE_ATTR_ALIAS) { entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__); - if (BLI_file_alias_target(entry->redirection_path, path)) { + if (BLI_file_alias_target(entry->redirection_path, full_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; + BLI_path_slash_ensure(entry->redirection_path); } - else + else { entry->typeflag = ED_path_extension_type(entry->redirection_path); + } + target = entry->redirection_path; +#ifdef WIN32 + /* On Windows don't show ".lnk" extension for valid shortcuts. */ + BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, ""); +#endif + } + else { + MEM_freeN(entry->redirection_path); + entry->redirection_path = NULL; + entry->attributes |= FILE_ATTR_HIDDEN; + } + } + + if (!(entry->typeflag & FILE_TYPE_DIR)) { + if (do_lib && BLO_has_bfile_extension(target)) { + /* If we are considering .blend files as libs, promote them to directory status. */ + entry->typeflag = FILE_TYPE_BLENDER; + /* prevent current file being used as acceptable dir */ + if (BLI_path_cmp(main_name, target) != 0) { + entry->typeflag |= FILE_TYPE_DIR; + } + } + else { + entry->typeflag = ED_path_extension_type(target); + if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) { + entry->typeflag |= FILE_TYPE_OPERATOR; + } } } |