IO: Add support for multiple drag-n-drop files #107230
|
@ -64,7 +64,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path)
|
||||||
if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
|
if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
|
||||||
WM_drag_data_free(but->dragtype, but->dragpoin);
|
WM_drag_data_free(but->dragtype, but->dragpoin);
|
||||||
}
|
}
|
||||||
but->dragpoin = WM_drag_create_path_data(path);
|
but->dragpoin = WM_drag_create_path_data(blender::Span(&path, 1));
|
||||||
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
|
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5907,7 +5907,7 @@ static bool blend_file_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent *
|
||||||
static void blend_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
static void blend_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
{
|
{
|
||||||
/* copy drag path to properties */
|
/* copy drag path to properties */
|
||||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ED_keymap_screen(wmKeyConfig *keyconf)
|
void ED_keymap_screen(wmKeyConfig *keyconf)
|
||||||
|
|
|
@ -536,7 +536,8 @@ static void clip_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
PointerRNA itemptr;
|
PointerRNA itemptr;
|
||||||
char dir[FILE_MAX], file[FILE_MAX];
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
|
||||||
BLI_path_split_dir_file(WM_drag_get_path(drag), dir, sizeof(dir), file, sizeof(file));
|
BLI_path_split_dir_file(
|
||||||
|
WM_drag_get_paths(drag)[0].c_str(), dir, sizeof(dir), file, sizeof(file));
|
||||||
|
|
||||||
RNA_string_set(drop->ptr, "directory", dir);
|
RNA_string_set(drop->ptr, "directory", dir);
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ static bool path_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*eve
|
||||||
static void path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
static void path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
{
|
{
|
||||||
char pathname[FILE_MAX + 2];
|
char pathname[FILE_MAX + 2];
|
||||||
SNPRINTF(pathname, "\"%s\"", WM_drag_get_path(drag));
|
SNPRINTF(pathname, "\"%s\"", WM_drag_get_paths(drag)[0].c_str());
|
||||||
RNA_string_set(drop->ptr, "text", pathname);
|
RNA_string_set(drop->ptr, "text", pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -799,7 +799,7 @@ static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*even
|
||||||
|
|
||||||
static void filepath_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
static void filepath_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
{
|
{
|
||||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* region dropbox definition */
|
/* region dropbox definition */
|
||||||
|
|
|
@ -268,7 +268,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
|
||||||
static void image_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
static void image_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
{
|
{
|
||||||
/* copy drag path to properties */
|
/* copy drag path to properties */
|
||||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* area+region dropbox definition */
|
/* area+region dropbox definition */
|
||||||
|
|
|
@ -725,9 +725,9 @@ static void node_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *path = WM_drag_get_path(drag);
|
const auto paths = WM_drag_get_paths(drag);
|
||||||
if (path) {
|
if (paths.begin()) {
|
||||||
RNA_string_set(drop->ptr, "filepath", path);
|
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
|
||||||
RNA_struct_property_unset(drop->ptr, "name");
|
RNA_struct_property_unset(drop->ptr, "name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,17 +249,17 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *path = WM_drag_get_path(drag);
|
const auto paths = WM_drag_get_paths(drag);
|
||||||
/* Path dropped. */
|
/* Path dropped. */
|
||||||
if (path) {
|
if (paths.begin()) {
|
||||||
if (RNA_struct_find_property(drop->ptr, "filepath")) {
|
if (RNA_struct_find_property(drop->ptr, "filepath")) {
|
||||||
RNA_string_set(drop->ptr, "filepath", path);
|
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
|
||||||
}
|
}
|
||||||
if (RNA_struct_find_property(drop->ptr, "directory")) {
|
if (RNA_struct_find_property(drop->ptr, "directory")) {
|
||||||
PointerRNA itemptr;
|
PointerRNA itemptr;
|
||||||
char dir[FILE_MAX], file[FILE_MAX];
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
|
||||||
BLI_path_split_dir_file(path, dir, sizeof(dir), file, sizeof(file));
|
BLI_path_split_dir_file(paths[0].c_str(), dir, sizeof(dir), file, sizeof(file));
|
||||||
|
|
||||||
RNA_string_set(drop->ptr, "directory", dir);
|
RNA_string_set(drop->ptr, "directory", dir);
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ static void get_drag_path(const bContext *C, wmDrag *drag, char r_path[FILE_MAX]
|
||||||
BLI_path_abs(r_path, BKE_main_blendfile_path_from_global());
|
BLI_path_abs(r_path, BKE_main_blendfile_path_from_global());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BLI_strncpy(r_path, WM_drag_get_path(drag), FILE_MAX);
|
BLI_strncpy(r_path, WM_drag_get_paths(drag)[0].c_str(), FILE_MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,7 @@ static bool text_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*eve
|
||||||
static void text_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
static void text_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||||
{
|
{
|
||||||
/* copy drag path to properties */
|
/* copy drag path to properties */
|
||||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool text_drop_paste_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
static bool text_drop_paste_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||||
|
|
|
@ -927,9 +927,9 @@ static void view3d_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
|
||||||
RNA_struct_property_unset(drop->ptr, "filepath");
|
RNA_struct_property_unset(drop->ptr, "filepath");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const char *path = WM_drag_get_path(drag);
|
const auto paths = WM_drag_get_paths(drag);
|
||||||
if (path) {
|
if (paths.begin()) {
|
||||||
RNA_string_set(drop->ptr, "filepath", path);
|
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
|
||||||
RNA_struct_property_unset(drop->ptr, "image");
|
RNA_struct_property_unset(drop->ptr, "image");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1393,13 +1393,13 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag);
|
||||||
|
|
||||||
const char *WM_drag_get_item_name(wmDrag *drag);
|
const char *WM_drag_get_item_name(wmDrag *drag);
|
||||||
|
|
||||||
/* Path drag and drop. */
|
/* Paths drag and drop. */
|
||||||
/**
|
/**
|
||||||
* \param path: The path to drag. Value will be copied into the drag data so the passed string may
|
* \param paths: The paths to drag. Values will be copied into the drag data so the passed strings
|
||||||
* be destructed.
|
* may be destructed. Only paths that share the same extension of the first file will be copied.
|
||||||
*/
|
*/
|
||||||
wmDragPath *WM_drag_create_path_data(const char *path);
|
wmDragPath *WM_drag_create_path_data(blender::Span<const char *> paths);
|
||||||
const char *WM_drag_get_path(const wmDrag *drag);
|
const blender::Span<std::string> WM_drag_get_paths(const wmDrag *drag);
|
||||||
/**
|
/**
|
||||||
* Note that even though the enum return type uses bit-flags, this should never have multiple
|
* Note that even though the enum return type uses bit-flags, this should never have multiple
|
||||||
* type-bits set, so `ELEM()` like comparison is possible.
|
* type-bits set, so `ELEM()` like comparison is possible.
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct wmWindowManager;
|
||||||
|
|
||||||
#include "BLI_compiler_attrs.h"
|
#include "BLI_compiler_attrs.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
#include "BLI_vector.hh"
|
||||||
#include "DNA_listBase.h"
|
#include "DNA_listBase.h"
|
||||||
#include "DNA_uuid_types.h"
|
#include "DNA_uuid_types.h"
|
||||||
#include "DNA_vec_types.h"
|
#include "DNA_vec_types.h"
|
||||||
|
@ -1125,10 +1126,15 @@ struct wmDragAssetListItem {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wmDragPath {
|
struct wmDragPath {
|
||||||
char *path;
|
const blender::Vector<std::string> paths;
|
||||||
/* Note that even though the enum type uses bit-flags, this should never have multiple type-bits
|
/* Note that even though the enum type uses bit-flags, this should never have multiple type-bits
|
||||||
* set, so `ELEM()` like comparison is possible. */
|
* set, so `ELEM()` like comparison is possible. */
|
||||||
int file_type; /* eFileSel_File_Types */
|
const int file_type; /* eFileSel_File_Types */
|
||||||
|
const std::string tooltip;
|
||||||
|
wmDragPath(const blender::Vector<std::string> &paths, const std::string &tooltip, int file_type)
|
||||||
|
: paths(std::move(paths)), file_type(file_type), tooltip(tooltip)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wmDragGreasePencilLayer {
|
struct wmDragGreasePencilLayer {
|
||||||
|
|
|
@ -760,29 +760,45 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag)
|
||||||
return &drag->asset_items;
|
return &drag->asset_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
wmDragPath *WM_drag_create_path_data(const char *path)
|
wmDragPath *WM_drag_create_path_data(blender::Span<const char *> _paths)
|
||||||
{
|
{
|
||||||
wmDragPath *path_data = MEM_new<wmDragPath>("wmDragPath");
|
const char *ext = BLI_path_extension(_paths[0]);
|
||||||
path_data->path = BLI_strdup(path);
|
blender::Vector<std::string> paths;
|
||||||
path_data->file_type = ED_path_extension_type(path);
|
for (auto path : _paths) {
|
||||||
|
if (STREQ(ext, BLI_path_extension(path))) {
|
||||||
brecht marked this conversation as resolved
Outdated
|
|||||||
|
paths.append(path);
|
||||||
|
}
|
||||||
guishe marked this conversation as resolved
Outdated
Julian Eisel
commented
This is just This is just `const char*` isn't it? In that case `auto` just hides type information with no real benefit, prefer not using it in such cases.
|
|||||||
|
}
|
||||||
|
char *tooltip;
|
||||||
|
if (_paths.size() == 1) {
|
||||||
|
tooltip = BLI_strdup(_paths[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tooltip = BLI_sprintfN(TIP_("Dragging %d %s files."), paths.size());
|
||||||
guishe marked this conversation as resolved
Outdated
Bastien Montagne
commented
There is no reason to use C-strings here. There is no reason to use C-strings here. `std::string` and `fmt::format` (extern library we are using since we are not yet on C++20) should be even easier to use.
Bastien Montagne
commented
No final point in our UI strings: No final point in our UI strings: `"Dragging {} files"`
|
|||||||
|
}
|
||||||
|
|
||||||
|
wmDragPath *path_data = MEM_new<wmDragPath>(
|
||||||
|
"wmDragPath", paths, tooltip, ED_path_extension_type(_paths[0]));
|
||||||
|
|
||||||
|
MEM_freeN(tooltip);
|
||||||
|
|
||||||
return path_data;
|
return path_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wm_drag_free_path_data(wmDragPath **path_data)
|
static void wm_drag_free_path_data(wmDragPath **path_data)
|
||||||
{
|
{
|
||||||
MEM_freeN((*path_data)->path);
|
|
||||||
MEM_delete(*path_data);
|
MEM_delete(*path_data);
|
||||||
*path_data = nullptr;
|
*path_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *WM_drag_get_path(const wmDrag *drag)
|
const blender::Span<std::string> WM_drag_get_paths(const wmDrag *drag)
|
||||||
{
|
{
|
||||||
if (drag->type != WM_DRAG_PATH) {
|
if (drag->type != WM_DRAG_PATH) {
|
||||||
return nullptr;
|
return blender::Span<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
|
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
|
||||||
guishe marked this conversation as resolved
Outdated
Julian Eisel
commented
Same, remove Same, remove `const` from return type.
|
|||||||
return path_data->path;
|
return path_data->paths.as_span();
|
||||||
}
|
}
|
||||||
|
|
||||||
guishe marked this conversation as resolved
Outdated
Bastien Montagne
commented
`return nullptr;`
|
|||||||
int WM_drag_get_path_file_type(const wmDrag *drag)
|
int WM_drag_get_path_file_type(const wmDrag *drag)
|
||||||
|
@ -846,7 +862,7 @@ const char *WM_drag_get_item_name(wmDrag *drag)
|
||||||
}
|
}
|
||||||
case WM_DRAG_PATH: {
|
case WM_DRAG_PATH: {
|
||||||
const wmDragPath *path_drag_data = static_cast<const wmDragPath *>(drag->poin);
|
const wmDragPath *path_drag_data = static_cast<const wmDragPath *>(drag->poin);
|
||||||
return path_drag_data->path;
|
return path_drag_data->tooltip.c_str();
|
||||||
}
|
}
|
||||||
case WM_DRAG_NAME:
|
case WM_DRAG_NAME:
|
||||||
return static_cast<const char *>(drag->poin);
|
return static_cast<const char *>(drag->poin);
|
||||||
|
@ -1039,8 +1055,9 @@ void wm_drags_draw(bContext *C, wmWindow *win)
|
||||||
wmWindowViewport(win);
|
wmWindowViewport(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drawing should be allowed to assume the context from handling and polling (that's why we
|
/* Drawing should be allowed to assume the context from
|
||||||
* restore it above). */
|
* handling and polling (that's why we restore it
|
||||||
|
* above). */
|
||||||
if (drag->drop_state.active_dropbox->draw_droptip) {
|
if (drag->drop_state.active_dropbox->draw_droptip) {
|
||||||
drag->drop_state.active_dropbox->draw_droptip(C, win, drag, xy);
|
drag->drop_state.active_dropbox->draw_droptip(C, win, drag, xy);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1512,14 +1512,14 @@ wm_window_swap_buffers(win);
|
||||||
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
|
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
|
||||||
GHOST_TStringArray *stra = static_cast<GHOST_TStringArray *>(ddd->data);
|
GHOST_TStringArray *stra = static_cast<GHOST_TStringArray *>(ddd->data);
|
||||||
|
|
||||||
for (int a = 0; a < stra->count; a++) {
|
if (stra->count) {
|
||||||
printf("drop file %s\n", stra->strings[a]);
|
printf("drop file %s\n", stra->strings[0]);
|
||||||
/* try to get icon type from extension */
|
/* try to get icon type from extension */
|
||||||
int icon = ED_file_extension_icon((char *)stra->strings[a]);
|
int icon = ED_file_extension_icon((char *)stra->strings[0]);
|
||||||
wmDragPath *path_data = WM_drag_create_path_data((char *)stra->strings[a]);
|
wmDragPath *path_data = WM_drag_create_path_data(
|
||||||
|
blender::Span((char **)stra->strings, stra->count));
|
||||||
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
|
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
|
||||||
/* void poin should point to string, it makes a copy */
|
/* void poin should point to string, it makes a copy */
|
||||||
break; /* only one drop element supported now */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Is there a reason for using string extension instead of the (already computed)
file_type
here (and then comparing to the result ofED_path_extension_type
for all other paths in the loop below)?If yes, should be documented in a comment.
Current approach would also 'fail' (filter out valid paths) e.g. in case of paths to a mix of JPG and PNG images. Or paths containing several USD files with different extensions.
ED_path_extension_type
is only for file types that Blender natively supports, while this system is meant to work for arbitrary add-ons.Initially I had the idea of just the one extension for file handler, but since file handlers could have a list of files they can take, here we can copy all and then see which ones are useful for the file handlers.
path_data->file_type
would only be used internally with the first file, and since these changes don't change the behavior I think it's safe to keep it and collect all the file paths, I'll leave a note that thisfile_type
will just you describe the first path.Ah yes, makes sense, better not do any filtering here then indeed.