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.
4 changed files with 70 additions and 56 deletions
Showing only changes of commit c5d4d90a5d - Show all commits

View File

@ -3501,9 +3501,9 @@ class WM_OT_drop_blend_file(Operator):
class WM_FH_alembic(bpy.types.FileHandler):
bl_idname = "WM_FH_alembic"
bl_label = "alembic"
bl_label = "Import Alembic"
bl_import_operator = "WM_OT_alembic_import"
bl_extensions = [{"name": ".abc"}, {"name": ".abc"}, {"name": ".abc"}]
bl_file_extensions = [{"extension": ".abc"}]
@classmethod
def poll(cls, context):
@ -3512,9 +3512,9 @@ class WM_FH_alembic(bpy.types.FileHandler):
class WM_FH_collada(bpy.types.FileHandler):
bl_idname = "WM_FH_collada"
bl_label = "collada"
bl_label = "Import COLLADA"
bl_import_operator = "WM_OT_collada_import"
bl_extensions = [{"name": ".dae"}]
bl_file_extensions = [{"extension": ".dae"}]
@classmethod
def poll(cls, context):
@ -3523,9 +3523,9 @@ class WM_FH_collada(bpy.types.FileHandler):
class WM_FH_gpencil(bpy.types.FileHandler):
bl_idname = "WM_FH_gpencil"
bl_label = "gpencil"
bl_label = "Import gpencil"
bl_import_operator = "WM_OT_gpencil_import_svg"
bl_extensions = [{"name": ".svg"}]
bl_file_extensions = [{"extension": ".svg"}]
@classmethod
def poll(cls, context):
@ -3534,9 +3534,9 @@ class WM_FH_gpencil(bpy.types.FileHandler):
class WM_FH_obj(bpy.types.FileHandler):
bl_idname = "WM_FH_obj"
bl_label = "obj"
bl_label = "Import Wavefront OBJ"
bl_import_operator = "WM_OT_obj_import"
bl_extensions = [{"name": ".obj"}]
bl_file_extensions = [{"extension": ".obj"}]
@classmethod
def poll(cls, context):
@ -3545,9 +3545,9 @@ class WM_FH_obj(bpy.types.FileHandler):
class WM_FH_ply(bpy.types.FileHandler):
bl_idname = "WM_FH_ply"
bl_label = "ply"
bl_label = "Import PLY"
bl_import_operator = "WM_OT_ply_import"
bl_extensions = [{"name": ".ply"}]
bl_file_extensions = [{"extension": ".ply"}]
@classmethod
def poll(cls, context):
@ -3556,9 +3556,9 @@ class WM_FH_ply(bpy.types.FileHandler):
class WM_FH_stl(bpy.types.FileHandler):
bl_idname = "WM_FH_stl"
bl_label = "stl"
bl_label = "Import STL (experimental)"
bl_import_operator = "WM_OT_stl_import"
bl_extensions = [{"name": ".stl"}]
bl_file_extensions = [{"extension": ".stl"}]
@classmethod
def poll(cls, context):
@ -3567,9 +3567,9 @@ class WM_FH_stl(bpy.types.FileHandler):
class WM_FH_import_mesh_stl(bpy.types.FileHandler):
bl_idname = "WM_FH_import_mesh_stl"
bl_label = "stl"
bl_label = "Import STL"
bl_import_operator = "import_mesh.stl"
bl_extensions = [{"name": ".stl"}]
bl_file_extensions = [{"extension": ".stl"}]
@classmethod
def poll(cls, context):
@ -3578,9 +3578,9 @@ class WM_FH_import_mesh_stl(bpy.types.FileHandler):
class WM_FH_usd(bpy.types.FileHandler):
bl_idname = "WM_FH_usd"
bl_label = "usd"
bl_label = "Import USD"
bl_import_operator = "WM_OT_usd_import"
bl_extensions = [{"name": ".usd"}]
bl_file_extensions = [{"extension": ".usd"}]
guishe marked this conversation as resolved Outdated

There is also usda, usdc, usdz.

There is also `usda`, `usdc`, `usdz`.
@classmethod
def poll(cls, context):

View File

@ -668,15 +668,16 @@ struct bFileExtension {
};
struct FileHandlerType {
char idname[BKE_ST_MAXNAME]; /* unique name */
char idname[BKE_ST_MAXNAME]; /* Unique name. */
char label[BKE_ST_MAXNAME]; /* label */
char label[BKE_ST_MAXNAME]; /* For UI text. */
char import_operator[BKE_ST_MAXNAME]; /* import operator name */
char import_operator[BKE_ST_MAXNAME]; /* Import operator name, same as #OP_MAX_TYPENAME. */
guishe marked this conversation as resolved Outdated

This should move to its own file, BKE_file_handler.h

This should move to its own file, `BKE_file_handler.h`
/** TODO */
/* Check if file handler can be used in a context. */
bool (*poll)(const struct bContext *C, FileHandlerType *file_handle_type);
guishe marked this conversation as resolved Outdated

Leave empty line between struct definitions.

Leave empty line between struct definitions.
/* List of file extensions supported by the file handler. */
blender::Vector<bFileExtension> extensions;
/** Equivalent to datablocks ID properties. */

View File

@ -32,10 +32,10 @@ static bool poll_extension(blender::Span<bFileExtension> file_extensions, const
return false;
}
static blender::Vector<wmOperatorType *> poll_operators_for_extension(const bContext *C,
const char *extension)
static blender::Vector<FileHandlerType *> poll_file_handlers_for_extension(bContext *C,
const char *extension)
{
blender::Vector<wmOperatorType *> operators;
blender::Vector<FileHandlerType *> result;
for (auto *file_handler : BKE_file_handlers()) {
if (!poll_extension(file_handler->extensions, extension)) {
continue;
@ -45,11 +45,12 @@ static blender::Vector<wmOperatorType *> poll_operators_for_extension(const bCon
}
wmOperatorType *test_operator = WM_operatortype_find(file_handler->import_operator, false);
if (!test_operator) {
/* Discard if import operator does not exist. */
continue;
}
operators.append(test_operator);
result.append(file_handler);
}
return operators;
return result;
}
static PointerRNA copy_file_properties_to_operator_type_pointer(wmOperator *op, wmOperatorType *ot)
@ -88,13 +89,15 @@ static int wm_drop_import_helper_exec(bContext *C, wmOperator *op)
{
char extension[MAX_NAME];
RNA_string_get(op->ptr, "extension", extension);
blender::Vector<wmOperatorType *> operators = poll_operators_for_extension(C, extension);
if (operators.size() == 0) {
blender::Vector<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
extension);
if (file_handlers.size() == 0) {
return OPERATOR_CANCELLED;
}
wmOperatorType *ot = operators[0];
wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
PointerRNA op_props = copy_file_properties_to_operator_type_pointer(op, ot);
@ -108,9 +111,10 @@ static int wm_drop_import_helper_invoke(bContext *C, wmOperator *op, const wmEve
char extension[MAX_NAME];
RNA_string_get(op->ptr, "extension", extension);
blender::Vector<wmOperatorType *> operators = poll_operators_for_extension(C, extension);
blender::Vector<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
extension);
if (operators.size() <= 1) {
if (file_handlers.size() == 1) {
return wm_drop_import_helper_exec(C, op);
}
@ -118,11 +122,12 @@ static int wm_drop_import_helper_invoke(bContext *C, wmOperator *op, const wmEve
uiLayout *layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
for (auto *ot : operators) {
for (auto *file_handler : file_handlers) {
wmOperatorType *ot = WM_operatortype_find(file_handler->import_operator, false);
PointerRNA op_props = copy_file_properties_to_operator_type_pointer(op, ot);
uiItemFullO_ptr(layout,
guishe marked this conversation as resolved Outdated

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

Use `IFACE_("Import %s")` for translation.
ot,
nullptr,
file_handler->label,
ICON_NONE,
static_cast<IDProperty *>(op_props.data),
WM_OP_INVOKE_DEFAULT,
@ -137,8 +142,8 @@ void WM_OT_drop_import_helper(wmOperatorType *ot)
{
guishe marked this conversation as resolved Outdated

Leave empty line between function definitions.

Leave empty line between function definitions.
ot->name = "Drop Import Herlper";
ot->description =
"Helper operator that handles file drops events and calls operators that can import files "
"with extension";
"Helper operator that handles file drops and uses file handler information to call "
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"?
"operators that can import a file with extension.";
ot->idname = "WM_OT_drop_import_helper";
ot->exec = wm_drop_import_helper_exec;
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.
@ -187,19 +192,20 @@ static bool poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
const auto paths = WM_drag_get_paths(drag);
const char *extension = BLI_path_extension(paths[0].c_str());
return extension && poll_operators_for_extension(C, extension).size() > 0;
return extension && poll_file_handlers_for_extension(C, extension).size() > 0;
}
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());
blender::Vector<wmOperatorType *> operators = poll_operators_for_extension(C, extension);
if (operators.size() == 0) {
blender::Vector<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
extension);
if (file_handlers.size() == 0) {
return nullptr;
}
if (operators.size() == 1) {
return BLI_strdup(operators[0]->name ? operators[0]->name : operators[0]->idname);
if (file_handlers.size() == 1) {
return BLI_strdup(file_handlers[0]->label);
}
return BLI_strdup("Multiple operators can handle this file(s), drop to pick which to use");

View File

@ -1371,20 +1371,22 @@ static StructRNA *rna_FileHandler_register(Main *bmain,
file_handler_type->id_properties = dummy_file_handler_type.id_properties;
file_handler_type->rna_ext = dummy_file_handler_type.rna_ext;
memcpy(&file_handler_type->rna_ext, &dummy_file_handler_type.rna_ext, sizeof(ExtensionRNA));
int extensions_len = RNA_collection_length(&dummy_file_handler_ptr, "bl_extensions");
PropertyRNA *prop = RNA_struct_find_property(&dummy_file_handler_ptr, "bl_extensions");
/* Load all file extensions defined in the IDProperty. */
int extensions_len = RNA_collection_length(&dummy_file_handler_ptr, "bl_file_extensions");
PropertyRNA *prop = RNA_struct_find_property(&dummy_file_handler_ptr, "bl_file_extensions");
for (int i = 0; i < extensions_len; i++) {
PointerRNA fileptr;
bFileExtension extension;
RNA_property_collection_lookup_int(&dummy_file_handler_ptr, prop, i, &fileptr);
RNA_string_get(&fileptr, "name", extension.extension);
RNA_string_get(&fileptr, "extension", extension.extension);
file_handler_type->extensions.append(extension);
}
RNA_collection_clear(&dummy_file_handler_ptr, "bl_extensions");
RNA_collection_clear(&dummy_file_handler_ptr, "bl_file_extensions");
file_handler_type->rna_ext.srna = RNA_def_struct_ptr(
&BLENDER_RNA, file_handler_type->idname, &RNA_FileHandler);
@ -2228,7 +2230,7 @@ static void rna_def_file_handler_extensions(BlenderRNA *brna, PropertyRNA *cprop
RNA_def_property_srna(cprop, "FileExtensions");
srna = RNA_def_struct(brna, "FileExtensions", nullptr);
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.
RNA_def_struct_sdna(srna, "bFileExtension");
RNA_def_struct_ui_text(srna, "File Extensions", "TODO");
RNA_def_struct_ui_text(srna, "File Extensions", "File extensions for file handlers");
}
static void rna_def_file_handler(BlenderRNA *brna)
@ -2237,16 +2239,17 @@ static void rna_def_file_handler(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "FileHandler", nullptr);
RNA_def_struct_ui_text(srna, "File Handler Type", "TODO");
RNA_def_struct_ui_text(srna, "File Handler Type", "I/O File handler");
RNA_def_struct_sdna(srna, "FileHandler");
RNA_def_struct_refine_func(srna, "rna_FileHandler_refine");
RNA_def_struct_idprops_func(srna, "rna_FileHandler_idprops");
RNA_def_struct_register_funcs(
srna, "rna_FileHandler_register", "rna_FileHandler_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(true); /* 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);
@ -2260,24 +2263,28 @@ static void rna_def_file_handler(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_import_operator", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "type->import_operator");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Operator", "TODO");
RNA_def_property_ui_text(
prop,
"Operator",
"Operator that can handle import files with extension in bl_file_extensions");
prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "type->label");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Label", "TODO");
RNA_def_property_ui_text(prop, "Label", "The file handler label");
prop = RNA_def_property(srna, "bl_extensions", PROP_COLLECTION, PROP_NONE);
prop = RNA_def_property(srna, "bl_file_extensions", PROP_COLLECTION, PROP_NONE);
RNA_def_property_flag(prop, PROP_REGISTER | PROP_IDPROPERTY);
RNA_def_property_struct_type(prop, "FileExtension");
RNA_def_property_ui_text(prop, "Extensions", "TODO");
RNA_def_property_ui_text(prop, "File Extensions", "List of file extensions supported");
rna_def_file_handler_extensions(brna, prop);
PropertyRNA *parm;
FunctionRNA *func;
func = RNA_def_function(srna, "poll", nullptr);
RNA_def_function_ui_description(func, "TODO");
RNA_def_function_ui_description(
func, "If this method returns a non-null output, then the file hanlder can 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", "", "");
@ -2391,12 +2398,12 @@ static void rna_def_file_extension(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "FileExtension", nullptr);
RNA_def_struct_sdna(srna, "bFileExtension");
RNA_def_struct_ui_text(srna, "File Extension", "TODO");
RNA_def_struct_ui_text(srna, "File Extension", "File extension for file handlers");
RNA_define_verify_sdna(false);
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_define_verify_sdna(false); /* not in sdna */
prop = RNA_def_property(srna, "extension", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "extension");
RNA_def_property_ui_text(prop, "Extension", "TODO");
RNA_def_property_ui_text(prop, "Extension", "File extension");
RNA_define_verify_sdna(true);
}
void RNA_def_ui(BlenderRNA *brna)