Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorHarley Acheson <harley.acheson@gmail.com>2020-05-26 18:14:41 +0300
committerHarley Acheson <harley.acheson@gmail.com>2020-05-26 18:15:50 +0300
commit1f223b9a1fcef8b6eb69af9e2def351e2255a08e (patch)
tree156276a5ff0713853bd8b8a4eab5892b6b9b957a /source
parent78eae89c390601b1533c99cefb34ad91be15f63d (diff)
UI: Windows Shell Links & Improved Mac Aliases
Adds support for Windows Shell Links (shortcuts) to the File Browser. Extended Mac Alias usage. Better visualization of linked items. Differential Revision: https://developer.blender.org/D7380 Reviewed by Campbell Barton
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenlib/intern/storage.c56
-rw-r--r--source/blender/editors/space_file/file_draw.c79
-rw-r--r--source/blender/editors/space_file/file_ops.c28
-rw-r--r--source/blender/editors/space_file/filelist.c96
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;
+ }
}
}