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.
33 changed files with 691 additions and 69 deletions

View File

@ -3526,6 +3526,94 @@ class WM_OT_drop_blend_file(Operator):
col.operator("wm.append", text="Append...", icon='APPEND_BLEND').filepath = self.filepath
class WM_FH_alembic(bpy.types.FileHandler):
bl_idname = "WM_FH_alembic"
bl_label = "Alembic"
bl_import_operator = "WM_OT_alembic_import"
bl_file_extensions = ".abc"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_collada(bpy.types.FileHandler):
bl_idname = "WM_FH_collada"
bl_label = "COLLADA"
bl_import_operator = "WM_OT_collada_import"
bl_file_extensions = ".dae"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_gpencil(bpy.types.FileHandler):
bl_idname = "WM_FH_gpencil"
bl_label = "gpencil"
bl_import_operator = "WM_OT_gpencil_import_svg"
bl_file_extensions = ".svg"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_obj(bpy.types.FileHandler):
bl_idname = "WM_FH_obj"
bl_label = "Wavefront OBJ"
bl_import_operator = "WM_OT_obj_import"
bl_file_extensions = ".obj"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_ply(bpy.types.FileHandler):
bl_idname = "WM_FH_ply"
bl_label = "PLY"
bl_import_operator = "WM_OT_ply_import"
brecht marked this conversation as resolved

Probably should not have both STL importers here, in the end only one will be used when dropping?

Probably should not have both STL importers here, in the end only one will be used when dropping?

In case there are 2 file handlers that can be used, you can choose which one to use with a menu

But the add-on one can include the file handle registration in its owns files

In case there are 2 file handlers that can be used, you can choose which one to use with a menu <video src="/attachments/d3ccecac-20b6-4388-a3ba-d8df936b33d4" controls></video> But the add-on one can include the file handle registration in its owns files

Ok, that makes sense. It would be better to have to just a single importer that is stable, but that's not a problem to be solved by this PR.

Ok, that makes sense. It would be better to have to just a single importer that is stable, but that's not a problem to be solved by this PR.
bl_file_extensions = ".ply"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
guishe marked this conversation as resolved Outdated

There is also usda, usdc, usdz.

There is also `usda`, `usdc`, `usdz`.
class WM_FH_stl(bpy.types.FileHandler):
bl_idname = "WM_FH_stl"
bl_label = "STL (experimental)"
bl_import_operator = "WM_OT_stl_import"
bl_file_extensions = ".stl"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_import_mesh_stl(bpy.types.FileHandler):
bl_idname = "WM_FH_import_mesh_stl"
bl_label = "STL"
bl_import_operator = "import_mesh.stl"
bl_file_extensions = ".stl"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
class WM_FH_usd(bpy.types.FileHandler):
bl_idname = "WM_FH_usd"
bl_label = "USD"
bl_import_operator = "WM_OT_usd_import"
bl_file_extensions = ".usd;.usda;.usdc;.usdz"
@classmethod
def poll_drop(cls, context):
return context.area.type == "VIEW_3D"
classes = (
WM_OT_context_collection_boolean_set,
WM_OT_context_cycle_array,
@ -3571,5 +3659,14 @@ classes = (
WM_MT_splash_quick_setup,
WM_MT_splash,
WM_MT_splash_about,
WM_MT_region_toggle_pie
WM_MT_region_toggle_pie,
WM_FH_alembic,
WM_FH_collada,
WM_FH_gpencil,
WM_FH_obj,
WM_FH_ply,
WM_FH_stl,
WM_FH_import_mesh_stl,
WM_FH_usd,
)

View File

@ -29,6 +29,18 @@ struct FileHandlerType {
/** RNA integration. */
ExtensionRNA rna_ext;
/** Returns a vector of indices on #paths of those file paths supported by the file handler. */
blender::Vector<int64_t> filter_supported_paths(const blender::Span<std::string> paths) const;
/** Return the import operator associated to the file handler if set and exists, otherwise
* #null_ptr. */
wmOperatorType *get_import_operator() const;
/* Creates a #PointerRNA for the #import_operator and fills it with all file paths supported by
* the file handler. */
PointerRNA import_operator_file_properties_create_ptr(
const blender::Span<std::string> paths) const;
};
/**
@ -49,3 +61,8 @@ void BKE_file_handler_remove(FileHandlerType *file_handler);
/** Return a reference of the #RawVector with all `file_handlers` registered. */
const blender::RawVector<std::unique_ptr<FileHandlerType>> &BKE_file_handlers();
/** Return a vector of file handlers that support any file path in #paths, has a valid
* #import_operator assigned and the call to #poll_drop returns #true. */
blender::Vector<FileHandlerType *> BKE_file_handlers_poll_file_drop(
const bContext *C, const blender::Span<std::string> paths);

View File

@ -31,6 +31,8 @@ set(INC
../../../intern/opensubdiv
../../../extern/fmtlib/include
../windowmanager
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)

View File

@ -29,6 +29,7 @@
#include "BKE_brush.hh"
#include "BKE_cachefile.h"
#include "BKE_callbacks.h"
#include "BKE_file_handler.hh"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@ -70,7 +71,6 @@ void BKE_blender_free()
}
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
IMB_exit();
BKE_cachefiles_exit();
DEG_free_node_types();

View File

@ -2,9 +2,15 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "WM_api.hh"
#include "WM_types.hh"
#include "BKE_file_handler.hh"
#include "BLI_string.h"
#include "RNA_access.hh"
static blender::RawVector<std::unique_ptr<FileHandlerType>> &file_handlers()
{
@ -57,3 +63,104 @@ void BKE_file_handler_remove(FileHandlerType *file_handler)
return test_file_handler.get() == file_handler;
});
}
blender::Vector<FileHandlerType *> BKE_file_handlers_poll_file_drop(
const bContext *C, const blender::Span<std::string> paths)
{
blender::Vector<std::string> path_extensions;
for (const std::string &path : paths) {
const char *extension = BLI_path_extension(path.c_str());
if (!extension) {
continue;
}
path_extensions.append_non_duplicates(extension);
}
blender::Vector<FileHandlerType *> result;
for (const std::unique_ptr<FileHandlerType> &file_handler_ptr : file_handlers()) {
FileHandlerType &file_handler = *file_handler_ptr;
const auto &file_extensions = file_handler.file_extensions;
const bool support_any_extension = std::any_of(
file_extensions.begin(),
file_extensions.end(),
[&path_extensions](const std::string &test_extension) {
return path_extensions.contains(test_extension);
});
if (!support_any_extension) {
continue;
}
if (!(file_handler.poll_drop && file_handler.poll_drop(C, &file_handler))) {
continue;
}
/* File handles can be registered without a import operator, or the import operator can be
* removed and the file handler can still be registered, filter too file handles with valid
* import operators. */
if (!file_handler.get_import_operator()) {
continue;
}
result.append(&file_handler);
}
return result;
}
blender::Vector<int64_t> FileHandlerType::filter_supported_paths(
const blender::Span<std::string> paths) const
{
blender::Vector<int64_t> indices;
for (const int idx : paths.index_range()) {
const char *extension = BLI_path_extension(paths[idx].c_str());
if (!extension) {
continue;
}
if (file_extensions.contains(extension)) {
indices.append(idx);
}
}
return indices;
}
wmOperatorType *FileHandlerType::get_import_operator() const
{
return WM_operatortype_find(import_operator, false);
}
PointerRNA FileHandlerType::import_operator_file_properties_create_ptr(
const blender::Span<std::string> paths) const
{
BLI_assert(get_import_operator());
PointerRNA props;
WM_operator_properties_create_ptr(&props, get_import_operator());
const auto suported_paths = filter_supported_paths(paths);
if (PropertyRNA *prop = RNA_struct_find_property(&props, "filepath")) {
RNA_string_set(&props, "filepath", paths[suported_paths[0]].c_str());
}
if (PropertyRNA *prop = RNA_struct_find_property(&props, "directory")) {
char dir[FILE_MAX];
BLI_path_split_dir_part(paths[0].c_str(), dir, sizeof(dir));
RNA_string_set(&props, "directory", dir);
RNA_collection_clear(&props, "files");
for (const auto &index : suported_paths) {
char file[FILE_MAX];
BLI_path_split_file_part(paths[index].c_str(), file, sizeof(file));
PointerRNA itemptr{};
RNA_collection_add(&props, "files", &itemptr);
RNA_string_set(&itemptr, "name", file);
}
}
return props;
}

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

@ -17,6 +17,8 @@ set(INC
../../io/wavefront_obj
../../makesrna
../../windowmanager
../../../../extern/fmtlib/include
)
set(INC_SYS
@ -35,6 +37,8 @@ set(SRC
io_ply_ops.cc
io_stl_ops.cc
io_usd.cc
io_utils.cc
io_drop_import_file.cc
io_alembic.hh
io_cache.hh
@ -45,6 +49,8 @@ set(SRC
io_ply_ops.hh
io_stl_ops.hh
io_usd.hh
io_utils.hh
io_drop_import_file.hh
)
set(LIB
@ -53,6 +59,7 @@ set(LIB
PRIVATE bf::depsgraph
PRIVATE bf::dna
PRIVATE bf::intern::guardedalloc
extern_fmtlib
)
if(WITH_OPENCOLLADA)

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)
{
io_util_drop_file_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 io_util_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);
io_util_skip_save_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)
{
io_util_drop_file_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 = io_util_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);
io_util_skip_save_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,186 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "DNA_space_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
#include "BLT_translation.h"
#include "BKE_context.hh"
#include "BKE_file_handler.hh"
#include "BKE_main.hh"
#include "BKE_preferences.h"
#include "ED_fileselect.hh"
#include <fmt/format.h>
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "UI_interface.hh"
#include "io_drop_import_file.hh"
/* Retuns the list of file paths stored in #WM_OT_drop_import_file operator properties. */
static blender::Vector<std::string> drop_import_file_paths(const wmOperator *op)
{
blender::Vector<std::string> result;
char dir[FILE_MAX], file[FILE_MAX];
RNA_string_get(op->ptr, "directory", dir);
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "files");
int files_len = RNA_property_collection_length(op->ptr, prop);
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", file);
char file_path[FILE_MAX];
BLI_path_join(file_path, sizeof(file_path), dir, file);
result.append(file_path);
}
return result;
}
static int wm_drop_import_file_exec(bContext *C, wmOperator *op)
{
auto paths = drop_import_file_paths(op);
if (paths.size() < 1) {
return OPERATOR_CANCELLED;
}
auto file_handlers = BKE_file_handlers_poll_file_drop(C, paths);
if (file_handlers.size() == 0) {
return OPERATOR_CANCELLED;
}
PointerRNA file_props = file_handlers[0]->import_operator_file_properties_create_ptr(paths);
WM_operator_name_call_ptr(
C, file_handlers[0]->get_import_operator(), WM_OP_INVOKE_DEFAULT, &file_props, nullptr);
WM_operator_properties_free(&file_props);
return OPERATOR_FINISHED;
}
static int wm_drop_import_file_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
const auto paths = drop_import_file_paths(op);
if (paths.size() < 1) {
return OPERATOR_CANCELLED;
}
auto file_handlers = BKE_file_handlers_poll_file_drop(C, paths);
/** Execute directly if the files are only supported by a file handler. */
if (file_handlers.size() == 1) {
return wm_drop_import_file_exec(C, op);
}
/** Create a menu with file handler import operators that can support the files and let user
* decide what to use. */
uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
for (auto *file_handler : file_handlers) {
PointerRNA file_props = file_handler->import_operator_file_properties_create_ptr(paths);
std::string label = fmt::format(TIP_("Import {}"), file_handler->label);
uiItemFullO_ptr(layout,
file_handler->get_import_operator(),
label.c_str(),
ICON_NONE,
static_cast<IDProperty *>(file_props.data),
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
nullptr);
}
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
void WM_OT_drop_import_file(wmOperatorType *ot)
{
ot->name = "Drop to Import File";
ot->description = "Manages file ";
ot->idname = "WM_OT_drop_import_file";
ot->flag = OPTYPE_INTERNAL;
ot->exec = wm_drop_import_file_exec;
ot->invoke = wm_drop_import_file_invoke;
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 drop_import_file_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
{
const auto paths = WM_drag_get_paths(drag);
char dir[FILE_MAX];
BLI_path_split_dir_part(paths[0].c_str(), dir, sizeof(dir));
RNA_string_set(drop->ptr, "directory", dir);
RNA_collection_clear(drop->ptr, "files");
for (const auto &path : paths) {
char file[FILE_MAX];
BLI_path_split_file_part(path.c_str(), file, sizeof(file));
PointerRNA itemptr{};
RNA_collection_add(drop->ptr, "files", &itemptr);
RNA_string_set(&itemptr, "name", file);
}
}
static bool drop_import_file_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
{
if (drag->type != WM_DRAG_PATH) {
return false;
}
const auto paths = WM_drag_get_paths(drag);
return BKE_file_handlers_poll_file_drop(C, paths).size() > 0;
}
static char *drop_import_file_tooltip(bContext *C,
wmDrag *drag,
const int /*xy*/[2],
wmDropBox * /*drop*/)
{
const auto paths = WM_drag_get_paths(drag);
const auto file_handlers = BKE_file_handlers_poll_file_drop(C, paths);
if (file_handlers.size() == 0) {
return nullptr;
}
if (file_handlers.size() == 1) {
std::string label = fmt::format(TIP_("Import {}"), file_handlers[0]->label);
return BLI_strdup(label.c_str());
}
return BLI_strdup(TIP_("Multiple file handlers can be used, drop to pick which to use"));
}
void ED_dropbox_drop_import_file()
{
ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
WM_dropbox_add(lb,
"WM_OT_drop_import_file",
drop_import_file_poll,
drop_import_file_copy,
nullptr,
drop_import_file_tooltip);
}

View File

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

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)
{
io_util_drop_file_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 = io_util_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);
io_util_skip_save_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.hh"
# 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"},
@ -385,12 +386,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{};
@ -485,9 +480,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 = io_util_import_invoke;
ot->exec = wm_obj_import_exec;
ot->poll = WM_operator_winactive;
ot->ui = wm_obj_import_draw;
@ -501,6 +496,9 @@ void WM_OT_obj_import(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
io_util_skip_save_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_file.hh"
#include "io_gpencil.hh"
#include "io_obj.hh"
#include "io_ply_ops.hh"
@ -74,4 +75,6 @@ void ED_operatortypes_io()
WM_operatortype_append(WM_OT_stl_import);
WM_operatortype_append(WM_OT_stl_export);
#endif
WM_operatortype_append(WM_OT_drop_import_file);
ED_dropbox_drop_import_file();
}

View File

@ -37,6 +37,7 @@
# include "IO_ply.hh"
# 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"},
@ -236,11 +237,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{};
@ -286,6 +282,29 @@ 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)
{
wmWindowManager *wm = CTX_wm_manager(C);
PointerRNA ptr = RNA_pointer_create(&wm->id, op->type->srna, op->properties);
io_util_drop_file_label_draw(C, op, ICON_FILE_3D, ".ply");
ui_ply_import_settings(op->layout, &ptr);
}
void WM_OT_ply_import(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -294,10 +313,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 = io_util_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,
@ -307,6 +327,8 @@ void WM_OT_ply_import(wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
io_util_skip_save_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

@ -29,6 +29,7 @@
# include "IO_stl.hh"
# include "io_stl_ops.hh"
# include "io_utils.hh"
static int wm_stl_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
@ -237,6 +238,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)
{
wmWindowManager *wm = CTX_wm_manager(C);
PointerRNA ptr = RNA_pointer_create(&wm->id, op->type->srna, op->properties);
io_util_drop_file_label_draw(C, op, ICON_FILE_3D, ".stl");
ui_stl_import_settings(op->layout, &ptr);
}
void WM_OT_stl_import(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -249,7 +273,8 @@ void WM_OT_stl_import(wmOperatorType *ot)
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,
@ -259,6 +284,8 @@ void WM_OT_stl_import(wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
io_util_skip_save_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.hh"
# include "io_usd.hh"
# include "io_utils.hh"
# include "usd.h"
# include <cstdio>
@ -393,7 +394,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 io_util_import_invoke(C, op, event);
}
static int wm_usd_import_exec(bContext *C, wmOperator *op)
@ -532,11 +533,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;
io_util_drop_file_label_draw(C, op, ICON_FILE_3D, ".usd");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@ -608,7 +611,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,
@ -617,6 +620,7 @@ void WM_OT_usd_import(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
io_util_skip_save_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,82 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_context.hh"
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 "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 io_util_import_invoke(bContext *C, wmOperator *op, const wmEvent * /* event */)
{
PropertyRNA *filepath_prop = RNA_struct_find_property(op->ptr, "filepath");
PropertyRNA *directory_prop = RNA_struct_find_property(op->ptr, "directory");
if ((filepath_prop && RNA_property_is_set(op->ptr, filepath_prop)) ||
(directory_prop && RNA_property_is_set(op->ptr, directory_prop)))
{
return WM_operator_props_dialog_popup(C, op, 300);
}
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
void io_util_skip_save_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 io_util_drop_file_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);
}

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "WM_types.hh"
struct wmOperator;
struct wmOperatorType;
struct wmDrag;
struct wmDropBox;
int io_util_import_invoke(bContext *C, wmOperator *op, const wmEvent *event);
void io_util_skip_save_filesel_props(wmOperatorType *ot, const eFileSel_Flag flag);
void io_util_drop_file_label_draw(bContext *C, wmOperator *op, int icon, const char *extension);

View File

@ -5944,7 +5944,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_single_path(drag));
}
void ED_keymap_screen(wmKeyConfig *keyconf)

View File

@ -536,7 +536,7 @@ 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_single_path(drag), 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_single_path(drag));
RNA_string_set(drop->ptr, "text", pathname);
}

View File

@ -797,7 +797,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_single_path(drag));
}
/* 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_single_path(drag));
}
/* area+region dropbox definition */

View File

@ -897,7 +897,7 @@ static void node_id_path_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
return;
}
const char *path = WM_drag_get_path(drag);
const char *path = WM_drag_get_single_path(drag);
if (path) {
RNA_string_set(drop->ptr, "filepath", path);
RNA_struct_property_unset(drop->ptr, "name");

View File

@ -249,7 +249,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
return;
}
const char *path = WM_drag_get_path(drag);
const char *path = WM_drag_get_single_path(drag);
/* Path dropped. */
if (path) {
if (RNA_struct_find_property(drop->ptr, "filepath")) {
@ -335,7 +335,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_single_path(drag), 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_single_path(drag));
}
static bool text_drop_paste_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)

View File

@ -893,7 +893,7 @@ 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);
const char *path = WM_drag_get_single_path(drag);
if (path) {
RNA_string_set(drop->ptr, "filepath", path);
RNA_struct_property_unset(drop->ptr, "image");

View File

@ -1424,13 +1424,14 @@ 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 char *WM_drag_get_single_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
* type-bits set, so `ELEM()` like comparison is possible.

View File

@ -111,6 +111,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"
@ -1179,10 +1180,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

@ -762,29 +762,57 @@ 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 char *WM_drag_get_single_path(const wmDrag *drag)
{
if (drag->type != WM_DRAG_PATH) {
return nullptr;
nullptr;
}
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
return path_data->path;
return path_data->paths[0].c_str();
}
const blender::Span<std::string> WM_drag_get_paths(const wmDrag *drag)
{
if (drag->type != WM_DRAG_PATH) {
return blender::Span<std::string>();
}
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
return path_data->paths.as_span();
}
int WM_drag_get_path_file_type(const wmDrag *drag)
@ -848,7 +876,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

@ -54,6 +54,7 @@
#include "BKE_addon.h"
#include "BKE_appdir.h"
#include "BKE_file_handler.hh"
#include "BKE_mask.h" /* free mask clipboard */
#include "BKE_material.h" /* BKE_material_copybuf_clear */
#include "BKE_studiolight.h"

View File

@ -1571,11 +1571,12 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
const GHOST_TStringArray *stra = static_cast<const 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 */