WIP: Experiment: Drop import operator helper and file drop type #111242

Closed
Guillermo Venegas wants to merge 23 commits from guishe/blender:drop-helper into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
31 changed files with 733 additions and 80 deletions
Showing only changes of commit 84a43bcb76 - Show all commits

View File

@ -3494,6 +3494,76 @@ class WM_OT_drop_blend_file(Operator):
col.operator("wm.append", text="Append...", icon='APPEND_BLEND').filepath = self.filepath
class WM_FDT_alembic(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_alembic"
bl_operator = "WM_OT_alembic_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".abc"
class WM_FDT_collada(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_collada"
bl_operator = "WM_OT_collada_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".dae"
class WM_FDT_gpencil(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_gpencil"
bl_operator = "WM_OT_gpencil_import_svg"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".svg"
class WM_FDT_obj(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_obj"
bl_operator = "WM_OT_obj_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".obj"
class WM_FDT_ply(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_ply"
bl_operator = "WM_OT_ply_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".ply"
class WM_FDT_stl(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_stl"
bl_operator = "WM_OT_stl_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".stl"
class WM_FDT_usd(bpy.types.FileDrop):
bl_space_type = "VIEW_3D"
bl_idname = "WM_FDT_usd"
bl_operator = "WM_OT_usd_import"
@classmethod
def poll_extension(cls, context, extension):
return extension == ".usd"
classes = (
WM_OT_context_collection_boolean_set,
WM_OT_context_cycle_array,
@ -3539,5 +3609,13 @@ classes = (
WM_MT_splash_quick_setup,
WM_MT_splash,
WM_MT_splash_about,
WM_MT_region_toggle_pie
WM_MT_region_toggle_pie,
WM_FDT_alembic,
WM_FDT_collada,
WM_FDT_gpencil,
WM_FDT_obj,
WM_FDT_ply,
WM_FDT_stl,
WM_FDT_usd,
)

View File

@ -139,6 +139,9 @@ typedef struct SpaceType {
/** Asset shelf type definitions. */
ListBase asset_shelf_types; /* #AssetShelfType */
/** File drop type definitions. */
ListBase file_drop_types; /* #FileDropType */
/* read and write... */
/** Default key-maps to add. */
@ -461,6 +464,28 @@ typedef struct AssetShelfType {
ExtensionRNA rna_ext;
} AssetShelfType;
typedef struct FileDropType {
struct FileDropType *next, *prev;
char idname[BKE_ST_MAXNAME]; /* unique name */
char op_name[BKE_ST_MAXNAME]; /* operator name */
int space_type;
/** Determine if the operator can handle a specific file extension. */
bool (*poll_extension)(const struct bContext *C,
FileDropType *file_drop_type,
const char *extension);
/* RNA integration */
ExtensionRNA rna_ext;
} FileDropType;
typedef struct FileDrop {
struct FileDropType *type; /* runtime */
} FileDrop;
/* Space-types. */
struct SpaceType *BKE_spacetype_from_id(int spaceid);

View File

@ -225,6 +225,7 @@ static void spacetype_free(SpaceType *st)
BLI_freelistN(&st->regiontypes);
BLI_freelistN(&st->asset_shelf_types);
BLI_freelistN(&st->file_drop_types);
}
void BKE_spacetypes_free()

View File

@ -64,7 +64,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path)
if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
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;
}

View File

@ -36,6 +36,8 @@ set(SRC
io_ply_ops.cc
io_stl_ops.cc
io_usd.cc
io_utils.cc
io_drop_import_helper.cc
io_alembic.hh
io_cache.hh
@ -46,6 +48,8 @@ set(SRC
io_ply_ops.hh
io_stl_ops.hh
io_usd.hh
io_utils.hh
io_drop_import_helper.hh
)
set(LIB

View File

@ -55,6 +55,8 @@
# include "ABC_alembic.h"
# include "io_utils.hh"
const EnumPropertyItem rna_enum_abc_export_evaluation_mode_items[] = {
{DAG_EVAL_RENDER,
"RENDER",
@ -584,8 +586,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "always_add_cache_reader", UI_ITEM_NONE, nullptr, ICON_NONE);
}
static void wm_alembic_import_draw(bContext * /*C*/, wmOperator *op)
static void wm_alembic_import_draw(bContext *C, wmOperator *op)
{
files_drop_label_draw(C, op, ICON_FILE_3D, ".abc");
ui_alembic_import_settings(op->layout, op->ptr);
}
@ -595,7 +598,7 @@ static int wm_alembic_import_invoke(bContext *C, wmOperator *op, const wmEvent *
if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
RNA_boolean_set(op->ptr, "as_background_job", true);
}
return WM_operator_filesel(C, op, event);
return wm_io_import_invoke(C, op, event);
}
static int wm_alembic_import_exec(bContext *C, wmOperator *op)
@ -651,7 +654,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
ot->name = "Import Alembic";
ot->description = "Load an Alembic archive";
ot->idname = "WM_OT_alembic_import";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_alembic_import_invoke;
ot->exec = wm_alembic_import_exec;
@ -665,6 +668,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.abc", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);

View File

@ -22,6 +22,7 @@
# include "ED_fileselect.hh"
# include "ED_object.hh"
# include "ED_outliner.hh"
# include "RNA_access.hh"
# include "RNA_define.hh"
@ -35,6 +36,7 @@
# include "collada.h"
# include "io_collada.hh"
# include "io_utils.hh"
static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
@ -747,6 +749,11 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
if (collada_import(C, &import_settings)) {
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS);
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@ -782,8 +789,9 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(box, imfptr, "keep_bind_info", UI_ITEM_NONE, nullptr, ICON_NONE);
}
static void wm_collada_import_draw(bContext * /*C*/, wmOperator *op)
static void wm_collada_import_draw(bContext *C, wmOperator *op)
{
files_drop_label_draw(C, op, ICON_FILE_3D, "dae");
uiCollada_importSettings(op->layout, op->ptr);
}
@ -792,9 +800,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->name = "Import COLLADA";
ot->description = "Load a Collada file";
ot->idname = "WM_OT_collada_import";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = WM_operator_filesel;
ot->invoke = wm_io_import_invoke;
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
@ -807,6 +815,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.dae", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);

View File

@ -0,0 +1,155 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "DNA_space_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_preferences.h"
#include "BKE_screen.h"
#include "ED_fileselect.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "io_drop_import_helper.hh"
static wmOperatorType *get_operator_type_for_extension(const bContext *C, const char *extension)
{
ScrArea *area = CTX_wm_area(C);
SpaceType *st = area->type;
FileDropType *file_drop_type = nullptr;
LISTBASE_FOREACH (FileDropType *, file_drop_test, &st->file_drop_types) {
if (file_drop_test->poll_extension &&
file_drop_test->poll_extension(C, file_drop_test, extension)) {
file_drop_type = file_drop_test;
}
};
return file_drop_type ? WM_operatortype_find(file_drop_type->op_name, false) : nullptr;
}
static int wm_drop_import_helper_exec(bContext *C, wmOperator *op)
{
char extension[MAX_NAME];
RNA_string_get(op->ptr, "extension", extension);
wmOperatorType *ot = get_operator_type_for_extension(C, extension);
if (!ot) {
return OPERATOR_CANCELLED;
}
PointerRNA op_props;
WM_operator_properties_create_ptr(&op_props, ot);
char filepath[FILE_MAX];
if (RNA_struct_find_property(&op_props, "filepath")) {
RNA_string_get(op->ptr, "filepath", filepath);
RNA_string_set(&op_props, "filepath", filepath);
}
if (RNA_struct_find_property(&op_props, "directory")) {
RNA_string_get(op->ptr, "directory", filepath);
RNA_string_set(&op_props, "directory", filepath);
RNA_collection_clear(&op_props, "files");
int files_len = RNA_collection_length(op->ptr, "files");
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "files");
for (int i = 0; i < files_len; i++) {
PointerRNA fileptr;
RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", filepath);
PointerRNA itemptr{};
RNA_collection_add(&op_props, "files", &itemptr);
RNA_string_set(&itemptr, "name", filepath);
}
}
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
WM_operator_properties_free(&op_props);
return OPERATOR_FINISHED;
}
void WM_OT_drop_import_helper(wmOperatorType *ot)
{
ot->name = "Drop Import Herlper";
ot->description =
"Helper operator that handles file drops events and calls operators that can import files "
"with extension";
ot->idname = "WM_OT_drop_import_helper";
ot->exec = wm_drop_import_helper_exec;
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "extension", nullptr, MAX_NAME, "extension", "extension");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY |
WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
void files_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
{
const auto paths = WM_drag_get_paths(drag);
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
char dir[FILE_MAX], file[FILE_MAX];
RNA_string_set(drop->ptr, "extension", BLI_path_extension(paths[0].c_str()));
BLI_path_split_dir_file(paths[0].c_str(), dir, sizeof(dir), file, sizeof(file));
RNA_string_set(drop->ptr, "directory", dir);
RNA_collection_clear(drop->ptr, "files");
for (const auto &path : paths) {
BLI_path_split_dir_file(path.c_str(), dir, sizeof(dir), file, sizeof(file));
PointerRNA itemptr{};
RNA_collection_add(drop->ptr, "files", &itemptr);
RNA_string_set(&itemptr, "name", file);
}
}
static bool poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
guishe marked this conversation as resolved Outdated

Use IFACE_("Import %s") for translation.

Use `IFACE_("Import %s")` for translation.
{
if (drag->type != WM_DRAG_PATH) {
return false;
}
const auto paths = WM_drag_get_paths(drag);
const char *extension = BLI_path_extension(paths[0].c_str());
return extension && get_operator_type_for_extension(C, extension);
}
static char *tooltip(bContext *C, wmDrag *drag, const int /*xy*/[2], wmDropBox * /*drop*/)
{
const auto paths = WM_drag_get_paths(drag);
const char *extension = BLI_path_extension(paths[0].c_str());
guishe marked this conversation as resolved Outdated

Leave empty line between function definitions.

Leave empty line between function definitions.
wmOperatorType *ot = get_operator_type_for_extension(C, extension);
if (!ot || (!ot->name || !ot->description)) {
brecht marked this conversation as resolved Outdated

Herlper -> Helper

But I would not put "helper" in the name, lots of operators are helpers in some way and it doesn't really explain much.

Maybe "Drop to Import File"?

Herlper -> Helper But I would not put "helper" in the name, lots of operators are helpers in some way and it doesn't really explain much. Maybe "Drop to Import File"?
return nullptr;
}
return BLI_strdup(ot->name ? ot->name : ot->description);
}
guishe marked this conversation as resolved Outdated

Add ot->flag = OPTYPE_INTERNAL;, this does not need to appear in search.

Add `ot->flag = OPTYPE_INTERNAL;`, this does not need to appear in search.
void ED_dropbox_import_helper()
{
ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
WM_dropbox_add(lb, "WM_OT_drop_import_helper", poll, files_drop_copy, nullptr, tooltip);
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
struct wmOperatorType;
void WM_OT_drop_import_helper(wmOperatorType *ot);
void ED_dropbox_import_helper();

View File

@ -36,6 +36,7 @@
# include "ED_gpencil_legacy.hh"
# include "io_gpencil.hh"
# include "io_utils.hh"
# include "gpencil_io.h"
@ -55,13 +56,6 @@ static bool wm_gpencil_import_svg_common_check(bContext * /*C*/, wmOperator *op)
return false;
}
static int wm_gpencil_import_svg_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@ -136,13 +130,15 @@ static void ui_gpencil_import_svg_settings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiLayout *col = uiLayoutColumn(layout, false);
uiLayout *box = uiLayoutBox(layout);
uiLayout *col = uiLayoutColumn(box, false);
uiItemR(col, imfptr, "resolution", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, imfptr, "scale", UI_ITEM_NONE, nullptr, ICON_NONE);
}
static void wm_gpencil_import_svg_draw(bContext * /*C*/, wmOperator *op)
static void wm_gpencil_import_svg_draw(bContext *C, wmOperator *op)
{
files_drop_label_draw(C, op, ICON_FILE_3D, ".svg");
ui_gpencil_import_svg_settings(op->layout, op->ptr);
}
@ -161,7 +157,7 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
ot->description = "Import SVG into grease pencil";
ot->idname = "WM_OT_gpencil_import_svg";
ot->invoke = wm_gpencil_import_svg_invoke;
ot->invoke = wm_io_import_invoke;
ot->exec = wm_gpencil_import_svg_exec;
ot->poll = wm_gpencil_import_svg_poll;
ot->ui = wm_gpencil_import_svg_draw;
@ -175,6 +171,8 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(
ot, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES);
RNA_def_int(ot->srna,
"resolution",

View File

@ -41,6 +41,7 @@
# include "IO_wavefront_obj.h"
# include "io_obj.hh"
# include "io_utils.hh"
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
@ -386,12 +387,6 @@ void WM_OT_obj_export(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int wm_obj_import_exec(bContext *C, wmOperator *op)
{
OBJImportParams import_params{};
@ -473,6 +468,7 @@ static void wm_obj_import_draw(bContext *C, wmOperator *op)
PointerRNA ptr;
wmWindowManager *wm = CTX_wm_manager(C);
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
files_drop_label_draw(C, op, ICON_FILE_3D, ".obj");
ui_obj_import_settings(op->layout, &ptr);
}
@ -483,9 +479,9 @@ void WM_OT_obj_import(wmOperatorType *ot)
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
ot->invoke = wm_obj_import_invoke;
ot->invoke = wm_io_import_invoke;
ot->exec = wm_obj_import_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_obj_import_draw;
@ -499,6 +495,8 @@ void WM_OT_obj_import(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES);
RNA_def_float(
ot->srna,
"global_scale",

View File

@ -23,6 +23,7 @@
#endif
#include "io_cache.hh"
#include "io_drop_import_helper.hh"
#include "io_gpencil.hh"
#include "io_obj.hh"
#include "io_ply_ops.hh"
@ -73,4 +74,6 @@ void ED_operatortypes_io()
#ifdef WITH_IO_STL
WM_operatortype_append(WM_OT_stl_import);
#endif
WM_operatortype_append(WM_OT_drop_import_helper);
ED_dropbox_import_helper();
}

View File

@ -37,6 +37,7 @@
# include "IO_ply.h"
# include "io_ply_ops.hh"
# include "io_utils.hh"
static const EnumPropertyItem ply_vertex_colors_mode[] = {
{PLY_VERTEX_COLOR_NONE, "NONE", 0, "None", "Do not import/export color attributes"},
@ -231,11 +232,6 @@ void WM_OT_ply_export(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int wm_ply_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return WM_operator_filesel(C, op, event);
}
static int wm_ply_import_exec(bContext *C, wmOperator *op)
{
PLYImportParams params{};
@ -280,6 +276,30 @@ static int wm_ply_import_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ui_ply_import_settings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiLayout *box = uiLayoutBox(layout);
uiLayout *col = uiLayoutColumn(box, false);
uiItemR(col, imfptr, "global_scale", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "use_scene_unit", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(col, imfptr, "up_axis", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "merge_verts", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "import_colors", UI_ITEM_NONE, NULL, ICON_NONE);
}
static void wm_ply_import_draw(bContext *C, wmOperator *op)
{
PointerRNA ptr;
wmWindowManager *wm = CTX_wm_manager(C);
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
files_drop_label_draw(C, op, ICON_FILE_3D, ".ply");
ui_ply_import_settings(op->layout, &ptr);
}
void WM_OT_ply_import(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -288,10 +308,11 @@ void WM_OT_ply_import(wmOperatorType *ot)
ot->description = "Import an PLY file as an object";
ot->idname = "WM_OT_ply_import";
ot->invoke = wm_ply_import_invoke;
ot->invoke = wm_io_import_invoke;
ot->exec = wm_ply_import_exec;
ot->poll = WM_operator_winactive;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->ui = wm_ply_import_draw;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
@ -301,6 +322,7 @@ void WM_OT_ply_import(wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY);
RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
RNA_def_boolean(ot->srna,

View File

@ -8,6 +8,8 @@
#ifdef WITH_IO_STL
# include "BLT_translation.h"
# include "BKE_context.h"
# include "BKE_report.h"
@ -21,13 +23,12 @@
# include "RNA_access.hh"
# include "RNA_define.hh"
# include "UI_interface.hh"
# include "UI_resources.hh"
# include "IO_stl.h"
# include "io_stl_ops.hh"
static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return WM_operator_filesel(C, op, event);
}
# include "io_utils.hh"
static int wm_stl_import_exec(bContext *C, wmOperator *op)
{
@ -85,6 +86,29 @@ static bool wm_stl_import_check(bContext * /*C*/, wmOperator *op)
}
return false;
}
static void ui_stl_import_settings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiLayout *box = uiLayoutBox(layout);
uiLayout *col = uiLayoutColumn(box, false);
uiItemR(col, imfptr, "global_scale", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "use_scene_unit", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "use_facet_normal", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(col, imfptr, "up_axis", UI_ITEM_NONE, NULL, ICON_NONE);
uiItemR(col, imfptr, "use_mesh_validate", UI_ITEM_NONE, NULL, ICON_NONE);
}
static void wm_stl_import_draw(bContext *C, wmOperator *op)
{
PointerRNA ptr;
wmWindowManager *wm = CTX_wm_manager(C);
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
files_drop_label_draw(C, op, ICON_FILE_3D, ".stl");
ui_stl_import_settings(op->layout, &ptr);
}
void WM_OT_stl_import(wmOperatorType *ot)
{
@ -94,11 +118,12 @@ void WM_OT_stl_import(wmOperatorType *ot)
ot->description = "Import an STL file as an object";
ot->idname = "WM_OT_stl_import";
ot->invoke = wm_stl_import_invoke;
ot->invoke = wm_io_import_invoke;
ot->exec = wm_stl_import_exec;
ot->poll = WM_operator_winactive;
ot->check = wm_stl_import_check;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->ui = wm_stl_import_draw;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
@ -108,6 +133,7 @@ void WM_OT_stl_import(wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY);
RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
RNA_def_boolean(ot->srna,

View File

@ -42,6 +42,7 @@
# include "DEG_depsgraph.h"
# include "io_usd.hh"
# include "io_utils.hh"
# include "usd.h"
# include <cstdio>
@ -386,7 +387,7 @@ static int wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *even
options->as_background_job = true;
op->customdata = options;
return WM_operator_filesel(C, op, event);
return wm_io_import_invoke(C, op, event);
}
static int wm_usd_import_exec(bContext *C, wmOperator *op)
@ -525,11 +526,13 @@ static void wm_usd_import_cancel(bContext * /*C*/, wmOperator *op)
free_operator_customdata(op);
}
static void wm_usd_import_draw(bContext * /*C*/, wmOperator *op)
static void wm_usd_import_draw(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
PointerRNA *ptr = op->ptr;
files_drop_label_draw(C, op, ICON_FILE_3D, ".usd");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@ -601,7 +604,7 @@ void WM_OT_usd_import(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_usd_import_draw;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
@ -610,6 +613,7 @@ void WM_OT_usd_import(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
skip_filesel_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH);
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.usd", 0, "", "");
RNA_def_property_flag(prop, PROP_HIDDEN);

View File

@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \
defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD)
guishe marked this conversation as resolved

Remove these tests. The code may not be used if none of these are defined, but that's not a problem.

Remove these tests. The code may not be used if none of these are defined, but that's not a problem.
# include "BKE_context.h"
# include "BLI_path_util.h"
# include "BLI_string.h"
# include "BLI_utildefines.h"
# include "BLT_translation.h"
# include "DNA_space_types.h"
# include "ED_fileselect.hh"
# include "RNA_access.hh"
# include "RNA_define.hh"
# include "UI_interface.hh"
# include "WM_api.hh"
# include "io_utils.hh"
int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent * /* event */)
{
char filepath[FILE_MAX];
RNA_string_get(op->ptr, "filepath", filepath);
if (filepath[0]) {
return WM_operator_props_dialog_popup(C, op, 300);
}
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
void skip_filesel_props(wmOperatorType *ot, const eFileSel_Flag flag)
{
PropertyRNA *prop;
if (flag & WM_FILESEL_FILEPATH) {
prop = RNA_struct_type_find_property(ot->srna, "filepath");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
if (flag & WM_FILESEL_FILENAME) {
prop = RNA_struct_type_find_property(ot->srna, "filename");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
if (flag & WM_FILESEL_DIRECTORY) {
prop = RNA_struct_type_find_property(ot->srna, "directory");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
if (flag & WM_FILESEL_FILES) {
prop = RNA_struct_type_find_property(ot->srna, "files");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
if (flag & WM_FILESEL_RELPATH) {
prop = RNA_struct_type_find_property(ot->srna, "relative_path");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
}
void files_drop_label_draw(bContext *C, wmOperator *op, int icon, const char *extension)
{
ScrArea *area = CTX_wm_area(C);
if (area->spacetype == SPACE_FILE) {
return;
}
char label[FILE_MAX];
RNA_string_get(op->ptr, "filepath", label);
if (RNA_struct_find_property(op->ptr, "directory") &&
RNA_collection_length(op->ptr, "files") > 1) {
sprintf(label, "%d %s files dropped.", RNA_collection_length(op->ptr, "files"), extension);
}
uiLayout *box = uiLayoutBox(op->layout);
uiItemL(box, label, icon);
}
#endif

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \
defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD)
# include "WM_types.hh"
struct wmOperator;
struct wmOperatorType;
struct wmDrag;
struct wmDropBox;
int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent *event);
void skip_filesel_props(wmOperatorType *ot, const eFileSel_Flag flag);
void files_drop_label_draw(bContext *C, wmOperator *op, int icon, const char *extension);
guishe marked this conversation as resolved Outdated

These names are bit generic to put in global namespace. The wm_ prefix would also imply that the function is defined in the window_manager_module.

Maybe use a io_util_ prefix?

These names are bit generic to put in global namespace. The `wm_` prefix would also imply that the function is defined in the `window_manager_module`. Maybe use a `io_util_` prefix?
#endif

View File

@ -5913,7 +5913,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)
{
/* 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)

View File

@ -536,7 +536,8 @@ static void clip_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
PointerRNA itemptr;
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);

View File

@ -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)
{
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);
}

View File

@ -800,7 +800,7 @@ static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*even
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 */

View File

@ -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)
{
/* 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 */

View File

@ -726,9 +726,9 @@ static void node_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
return;
}
const char *path = WM_drag_get_path(drag);
if (path) {
RNA_string_set(drop->ptr, "filepath", path);
const auto paths = WM_drag_get_paths(drag);
if (paths.begin()) {
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
RNA_struct_property_unset(drop->ptr, "name");
return;
}

View File

@ -249,17 +249,17 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
return;
}
const char *path = WM_drag_get_path(drag);
const auto paths = WM_drag_get_paths(drag);
/* Path dropped. */
if (path) {
if (paths.begin()) {
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")) {
PointerRNA itemptr;
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);
@ -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());
}
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);
}
}

View File

@ -316,7 +316,7 @@ static bool text_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*eve
static void text_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
{
/* 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*/)

View File

@ -929,9 +929,9 @@ static void view3d_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
RNA_struct_property_unset(drop->ptr, "filepath");
return;
}
const char *path = WM_drag_get_path(drag);
if (path) {
RNA_string_set(drop->ptr, "filepath", path);
const auto paths = WM_drag_get_paths(drag);
if (paths.begin()) {
RNA_string_set(drop->ptr, "filepath", paths[0].c_str());
RNA_struct_property_unset(drop->ptr, "image");
}
}

View File

@ -1282,6 +1282,138 @@ static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
/* UILayout */
/* File Drop */
static bool file_drop_poll(const bContext *C, FileDropType *file_drop_type, const char *extension)
{
extern FunctionRNA rna_FileDrop_poll_extension_func;
PointerRNA ptr;
RNA_pointer_create(nullptr, file_drop_type->rna_ext.srna, nullptr, &ptr); /* dummy */
/* RNA_struct_find_function(&ptr, "poll"); */
FunctionRNA *func = &rna_FileDrop_poll_extension_func;
ParameterList list;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "extension", &extension);
file_drop_type->rna_ext.call((bContext *)C, &ptr, func, &list);
void *ret;
RNA_parameter_get_lookup(&list, "visible", &ret);
/* Get the value before freeing. */
const bool is_visible = *(bool *)ret;
RNA_parameter_list_free(&list);
return is_visible;
}
static bool rna_FileDrop_unregister(Main * /*bmain*/, StructRNA *type)
{
FileDropType *file_drop_type = static_cast<FileDropType *>(RNA_struct_blender_type_get(type));
if (!file_drop_type) {
return false;
}
SpaceType *space_type = BKE_spacetype_from_id(file_drop_type->space_type);
if (!space_type) {
return false;
}
RNA_struct_free_extension(type, &file_drop_type->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&space_type->file_drop_types, file_drop_type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, nullptr);
return true;
}
static StructRNA *rna_FileDrop_register(Main *bmain,
ReportList *reports,
void *data,
const char *identifier,
StructValidateFunc validate,
StructCallbackFunc call,
StructFreeFunc free)
{
FileDropType dummy_file_drop_type = {};
FileDrop dummy_file_drop = {};
PointerRNA dummy_file_drop_ptr;
dummy_file_drop.type = &dummy_file_drop_type;
/* setup dummy file drop type to store static properties in */
RNA_pointer_create(nullptr, &RNA_FileDrop, &dummy_file_drop, &dummy_file_drop_ptr);
bool have_function[1];
/* validate the python class */
if (validate(&dummy_file_drop_ptr, data, have_function) != 0) {
return nullptr;
}
if (strlen(identifier) >= sizeof(dummy_file_drop_type.idname)) {
BKE_reportf(reports,
RPT_ERROR,
"Registering file drop class: '%s' is too long, maximum length is %d",
identifier,
(int)sizeof(dummy_file_drop_type.idname));
return nullptr;
}
SpaceType *space_type = BKE_spacetype_from_id(dummy_file_drop_type.space_type);
if (!space_type) {
BLI_assert_unreachable();
return nullptr;
}
/* Check if we have registered this file drop type before, and remove it. */
LISTBASE_FOREACH (FileDropType *, iter_file_drop_type, &space_type->file_drop_types) {
if (STREQ(iter_file_drop_type->idname, dummy_file_drop_type.idname)) {
if (iter_file_drop_type->rna_ext.srna) {
rna_FileDrop_unregister(bmain, iter_file_drop_type->rna_ext.srna);
}
break;
}
}
if (!RNA_struct_available_or_report(reports, dummy_file_drop_type.idname)) {
return nullptr;
}
if (!RNA_struct_bl_idname_ok_or_report(reports, dummy_file_drop_type.idname, "_FDT_")) {
return nullptr;
}
/* Create the new file drop type. */
FileDropType *file_drop_type = MEM_cnew<FileDropType>(__func__);
memcpy(file_drop_type, &dummy_file_drop_type, sizeof(*file_drop_type));
file_drop_type->rna_ext.srna = RNA_def_struct_ptr(
&BLENDER_RNA, file_drop_type->idname, &RNA_FileDrop);
file_drop_type->rna_ext.data = data;
file_drop_type->rna_ext.call = call;
file_drop_type->rna_ext.free = free;
RNA_struct_blender_type_set(file_drop_type->rna_ext.srna, file_drop_type);
file_drop_type->poll_extension = have_function[0] ? file_drop_poll : nullptr;
BLI_addtail(&space_type->file_drop_types, file_drop_type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, nullptr);
return file_drop_type->rna_ext.srna;
}
static StructRNA *rna_FileDrop_refine(PointerRNA *file_drop_ptr)
{
FileDrop *file_drop = (FileDrop *)file_drop_ptr->data;
return (file_drop && file_drop->type->rna_ext.srna) ? file_drop->type->rna_ext.srna :
&RNA_FileDrop;
}
static bool rna_UILayout_active_get(PointerRNA *ptr)
{
return uiLayoutGetActive(static_cast<uiLayout *>(ptr->data));
@ -2073,6 +2205,61 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_define_verify_sdna(true);
}
static void rna_def_file_drop(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "FileDrop", nullptr);
RNA_def_struct_ui_text(srna, "File Drop Type", "File drop polling function class");
RNA_def_struct_sdna(srna, "FileDrop");
RNA_def_struct_refine_func(srna, "rna_FileDrop_refine");
RNA_def_struct_register_funcs(srna, "rna_FileDrop_register", "rna_FileDrop_unregister", nullptr);
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* registration */
RNA_define_verify_sdna(false); /* not in sdna */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "type->idname");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop,
"ID Name",
"If this is set, the asset gets a custom ID, otherwise it takes the "
"name of the class used to define the menu (for example, if the "
"class name is \"OBJECT_FDT_hello\", and bl_idname is not set by the "
"script, then bl_idname = \"OBJECT_FDT_hello\")");
brecht marked this conversation as resolved Outdated

I'm not sure about this mechanism. We don't have a good way to pass a list of strings here currently, but the easier workaround to me seems to have a string of extensions separated by ; or something like that.

I'm not sure about this mechanism. We don't have a good way to pass a list of strings here currently, but the easier workaround to me seems to have a string of extensions separated by `;` or something like that.

I changed it to be just a string separated by ;, and also eliminated the IDProperty because it was only used for that purpose.

I changed it to be just a string separated by `;`, and also eliminated the `IDProperty` because it was only used for that purpose.
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "type->space_type");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(
prop, "Space Type", "The space type where file dropped cin be used by the operator");
prop = RNA_def_property(srna, "bl_operator", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "type->op_name");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(
prop, "Operator", "Operator to call if the poll_extension is successful");
PropertyRNA *parm;
FunctionRNA *func;
func = RNA_def_function(srna, "poll_extension", nullptr);
RNA_def_function_ui_description(
func, "If this method returns a non-null output, the file importer will be used");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", true, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_string(
func, "extension", nullptr, 256, "extension", "Extension to test for dropped file");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
RNA_define_verify_sdna(true);
}
static void rna_def_asset_shelf(BlenderRNA *brna)
{
StructRNA *srna;
@ -2182,6 +2369,7 @@ void RNA_def_ui(BlenderRNA *brna)
rna_def_header(brna);
rna_def_menu(brna);
rna_def_asset_shelf(brna);
rna_def_file_drop(brna);
}
#endif /* RNA_RUNTIME */

View File

@ -1405,13 +1405,13 @@ const ListBase *WM_drag_asset_list_get(const 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
* be destructed.
* \param paths: The paths to drag. Values will be copied into the drag data so the passed strings
* 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);
const char *WM_drag_get_path(const wmDrag *drag);
wmDragPath *WM_drag_create_path_data(blender::Span<const char *> paths);
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
* type-bits set, so `ELEM()` like comparison is possible.

View File

@ -108,6 +108,7 @@ struct wmWindowManager;
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "DNA_listBase.h"
#include "DNA_uuid_types.h"
#include "DNA_vec_types.h"
@ -1129,10 +1130,15 @@ struct wmDragAssetListItem {
};
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
* 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 {

View File

@ -768,29 +768,47 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag)
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");
path_data->path = BLI_strdup(path);
path_data->file_type = ED_path_extension_type(path);
const char *extension = BLI_path_extension(paths[0]);
blender::Vector<std::string> filtered_paths;
for (auto path : paths) {
const char *test_ext = BLI_path_extension(path);
if (extension == test_ext || (extension && test_ext && STREQ(extension, test_ext))) {
filtered_paths.append(path);
}
}
const char *tooltip = paths[0];
char tooltip_buffer[256];
if (filtered_paths.size() > 1) {
BLI_snprintf(tooltip_buffer,
ARRAY_SIZE(tooltip_buffer),
TIP_("Dragging %d %s files."),
filtered_paths.size(),
extension ? extension : TIP_("Folder"));
tooltip = tooltip_buffer;
}
wmDragPath *path_data = MEM_new<wmDragPath>(
"wmDragPath", filtered_paths, tooltip, ED_path_extension_type(paths[0]));
return path_data;
}
static void wm_drag_free_path_data(wmDragPath **path_data)
{
MEM_freeN((*path_data)->path);
MEM_delete(*path_data);
*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) {
return nullptr;
return blender::Span<std::string>();
}
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
return path_data->path;
return path_data->paths.as_span();
}
int WM_drag_get_path_file_type(const wmDrag *drag)
@ -854,7 +872,7 @@ const char *WM_drag_get_item_name(wmDrag *drag)
}
case WM_DRAG_PATH: {
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:
return static_cast<const char *>(drag->poin);

View File

@ -1511,11 +1511,12 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
GHOST_TStringArray *stra = static_cast<GHOST_TStringArray *>(ddd->data);
for (int a = 0; a < stra->count; a++) {
printf("drop file %s\n", stra->strings[a]);
if (stra->count) {
printf("drop file %s\n", stra->strings[0]);
/* try to get icon type from extension */
int icon = ED_file_extension_icon((char *)stra->strings[a]);
wmDragPath *path_data = WM_drag_create_path_data((char *)stra->strings[a]);
int icon = ED_file_extension_icon((char *)stra->strings[0]);
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);
/* Void pointer should point to string, it makes a copy. */
break; /* only one drop element supported now */