WIP: Experiment: Drop import operator helper and file drop type #111242
|
@ -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);
|
||||
|
|
|
@ -31,6 +31,8 @@ set(INC
|
|||
../../../intern/opensubdiv
|
||||
../../../extern/fmtlib/include
|
||||
|
||||
../windowmanager
|
||||
|
||||
# RNA_prototypes.h
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
)
|
||||
|
|
|
@ -83,8 +83,6 @@ void BKE_blender_free()
|
|||
IMB_moviecache_destruct();
|
||||
|
||||
BKE_node_system_exit();
|
||||
|
||||
BKE_file_handlers_free();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ set(INC
|
|||
../../io/wavefront_obj
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
|
||||
../../../../extern/fmtlib/include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
@ -36,7 +38,7 @@ set(SRC
|
|||
io_stl_ops.cc
|
||||
io_usd.cc
|
||||
io_utils.cc
|
||||
io_drop_file_import.cc
|
||||
io_drop_import_file.cc
|
||||
|
||||
io_alembic.hh
|
||||
io_cache.hh
|
||||
|
@ -48,7 +50,7 @@ set(SRC
|
|||
io_stl_ops.hh
|
||||
io_usd.hh
|
||||
io_utils.hh
|
||||
io_drop_file_import.hh
|
||||
io_drop_import_file.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
@ -57,6 +59,7 @@ set(LIB
|
|||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
extern_fmtlib
|
||||
)
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_file_handler.hh"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_preferences.h"
|
||||
|
||||
#include "ED_fileselect.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "io_drop_file_import.hh"
|
||||
|
||||
static bool poll_extension(blender::Span<bFileExtension> file_extensions, const char *extension)
|
||||
{
|
||||
for (auto &file_extension : file_extensions) {
|
||||
if (STREQ(extension, file_extension.extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static blender::Vector<FileHandlerType *> poll_file_handlers_for_extension(bContext *C,
|
||||
const char *extension)
|
||||
{
|
||||
blender::Vector<FileHandlerType *> result;
|
||||
for (auto *file_handler : BKE_file_handlers()) {
|
||||
if (!poll_extension(file_handler->file_extensions, extension)) {
|
||||
continue;
|
||||
}
|
||||
if (!(file_handler->poll_drop && file_handler->poll_drop(C, file_handler))) {
|
||||
continue;
|
||||
}
|
||||
wmOperatorType *test_operator = WM_operatortype_find(file_handler->import_operator, false);
|
||||
if (!test_operator) {
|
||||
/* Discard if operators that does not exist. */
|
||||
continue;
|
||||
}
|
||||
result.append(file_handler);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PointerRNA copy_file_properties_to_operator_type_pointer(wmOperator *op, wmOperatorType *ot)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return op_props;
|
||||
}
|
||||
|
||||
static int wm_drop_file_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char extension[MAX_NAME];
|
||||
RNA_string_get(op->ptr, "extension", extension);
|
||||
|
||||
blender::Vector<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
|
||||
extension);
|
||||
|
||||
if (file_handlers.size() == 0) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
|
||||
|
||||
PointerRNA op_props = copy_file_properties_to_operator_type_pointer(op, ot);
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
|
||||
WM_operator_properties_free(&op_props);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int wm_drop_file_import_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
char extension[MAX_NAME];
|
||||
RNA_string_get(op->ptr, "extension", extension);
|
||||
|
||||
blender::Vector<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
|
||||
extension);
|
||||
|
||||
if (file_handlers.size() == 1) {
|
||||
return wm_drop_file_import_exec(C, op);
|
||||
}
|
||||
|
||||
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) {
|
||||
wmOperatorType *ot = WM_operatortype_find(file_handler->import_operator, false);
|
||||
PointerRNA op_props = copy_file_properties_to_operator_type_pointer(op, ot);
|
||||
char *import_label = BLI_sprintfN(IFACE_("Import %s"), file_handler->label);
|
||||
uiItemFullO_ptr(layout,
|
||||
ot,
|
||||
import_label,
|
||||
ICON_NONE,
|
||||
static_cast<IDProperty *>(op_props.data),
|
||||
WM_OP_INVOKE_DEFAULT,
|
||||
UI_ITEM_NONE,
|
||||
nullptr);
|
||||
MEM_freeN(import_label);
|
||||
}
|
||||
|
||||
UI_popup_menu_end(C, pup);
|
||||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
|
||||
void WM_OT_drop_file_import(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Drop File to Import";
|
||||
ot->description =
|
||||
"Operator that handles file drops and uses file handler information to call "
|
||||
"operators that can import a file with extension.";
|
||||
ot->idname = "WM_OT_drop_file_import";
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
ot->exec = wm_drop_file_import_exec;
|
||||
ot->invoke = wm_drop_file_import_invoke;
|
||||
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 drop_file_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 drop_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);
|
||||
const char *extension = BLI_path_extension(paths[0].c_str());
|
||||
|
||||
return extension && poll_file_handlers_for_extension(C, extension).size() > 0;
|
||||
}
|
||||
|
||||
static char *drop_file_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<FileHandlerType *> file_handlers = poll_file_handlers_for_extension(C,
|
||||
extension);
|
||||
if (file_handlers.size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (file_handlers.size() == 1) {
|
||||
return BLI_sprintfN("Import %s", file_handlers[0]->label);
|
||||
}
|
||||
|
||||
return BLI_strdup("Multiple operators can handle this file(s), drop to pick which to use");
|
||||
}
|
||||
|
||||
void ED_dropbox_drop_file_import()
|
||||
{
|
||||
ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
|
||||
WM_dropbox_add(
|
||||
lb, "WM_OT_drop_file_import", drop_file_poll, drop_file_copy, nullptr, drop_file_tooltip);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_drop_file_import(wmOperatorType *ot);
|
||||
void ED_dropbox_drop_file_import();
|
||||
void WM_OT_drop_import_file(wmOperatorType *ot);
|
||||
void ED_dropbox_drop_import_file();
|
|
@ -23,7 +23,7 @@
|
|||
#endif
|
||||
|
||||
#include "io_cache.hh"
|
||||
#include "io_drop_file_import.hh"
|
||||
#include "io_drop_import_file.hh"
|
||||
#include "io_gpencil.hh"
|
||||
#include "io_obj.hh"
|
||||
#include "io_ply_ops.hh"
|
||||
|
@ -75,6 +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_file_import);
|
||||
ED_dropbox_drop_file_import();
|
||||
WM_operatortype_append(WM_OT_drop_import_file);
|
||||
ED_dropbox_drop_import_file();
|
||||
}
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
*/
|
||||
|
||||
#ifdef WITH_IO_STL
|
||||
# include "BLT_translation.h"
|
||||
|
||||
# include "BKE_context.h"
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
# include "WM_api.hh"
|
||||
|
@ -23,11 +22,14 @@
|
|||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
||||
# include "BLT_translation.h"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# 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*/)
|
||||
{
|
||||
|
@ -174,6 +176,10 @@ void WM_OT_stl_export(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return WM_operator_filesel(C, op, event);
|
||||
}
|
||||
|
||||
static int wm_stl_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
@ -231,6 +237,7 @@ 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);
|
||||
|
@ -262,7 +269,7 @@ void WM_OT_stl_import(wmOperatorType *ot)
|
|||
ot->description = "Import an STL file as an object";
|
||||
ot->idname = "WM_OT_stl_import";
|
||||
|
||||
ot->invoke = io_util_import_invoke;
|
||||
ot->invoke = wm_stl_import_invoke;
|
||||
ot->exec = wm_stl_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->check = wm_stl_import_check;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_context.hh"
|
||||
|
||||
guishe marked this conversation as resolved
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
|
|
@ -796,11 +796,6 @@ typedef struct AssetShelf {
|
|||
char _pad[6];
|
||||
} AssetShelf;
|
||||
|
||||
typedef struct FileHandler {
|
||||
DNA_DEFINE_CXX_METHODS(FileHandler)
|
||||
struct FileHandlerType *type; /* runtime */
|
||||
} FileHandler;
|
||||
|
||||
/**
|
||||
* Region-data for the main asset shelf region (#RGN_TYPE_ASSET_SHELF). Managed by the asset shelf
|
||||
* internals.
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "BKE_file_handler.hh"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_screen.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
|
@ -1284,137 +1283,6 @@ static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
|
|||
BLI_assert_msg(0, "setting the bl_description on a non-builtin menu");
|
||||
}
|
||||
}
|
||||
/* File Handler */
|
||||
|
||||
static bool file_handler_poll_drop(const bContext *C, FileHandlerType *file_handler_type)
|
||||
{
|
||||
extern FunctionRNA rna_FileHandler_poll_drop_func;
|
||||
|
||||
PointerRNA ptr = RNA_pointer_create(
|
||||
nullptr, file_handler_type->rna_ext.srna, nullptr); /* dummy */
|
||||
FunctionRNA *func = &rna_FileHandler_poll_drop_func;
|
||||
|
||||
ParameterList list;
|
||||
RNA_parameter_list_create(&list, &ptr, func);
|
||||
RNA_parameter_set_lookup(&list, "context", &C);
|
||||
file_handler_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_FileHandler_unregister(Main * /*bmain*/, StructRNA *type)
|
||||
{
|
||||
FileHandlerType *file_handler_type = static_cast<FileHandlerType *>(
|
||||
RNA_struct_blender_type_get(type));
|
||||
|
||||
if (!file_handler_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RNA_struct_free_extension(type, &file_handler_type->rna_ext);
|
||||
RNA_struct_free(&BLENDER_RNA, type);
|
||||
|
||||
BKE_file_handler_remove(file_handler_type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static StructRNA *rna_FileHandler_register(Main *bmain,
|
||||
ReportList *reports,
|
||||
void *data,
|
||||
const char *identifier,
|
||||
StructValidateFunc validate,
|
||||
StructCallbackFunc call,
|
||||
StructFreeFunc free)
|
||||
{
|
||||
|
||||
FileHandlerType dummy_file_handler_type{};
|
||||
FileHandler dummy_file_handler{};
|
||||
|
||||
dummy_file_handler.type = &dummy_file_handler_type;
|
||||
|
||||
/* setup dummy file handler type to store static properties in */
|
||||
PointerRNA dummy_file_handler_ptr = RNA_pointer_create(
|
||||
nullptr, &RNA_FileHandler, &dummy_file_handler);
|
||||
|
||||
bool have_function[1];
|
||||
|
||||
/* validate the python class */
|
||||
if (validate(&dummy_file_handler_ptr, data, have_function) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (strlen(identifier) >= sizeof(dummy_file_handler_type.idname)) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Registering file handler class: '%s' is too long, maximum length is %d",
|
||||
identifier,
|
||||
(int)sizeof(dummy_file_handler_type.idname));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check if we have registered this file handler type before, and remove it. */
|
||||
for (auto *iter_file_handler_type : BKE_file_handlers()) {
|
||||
if (STREQ(iter_file_handler_type->idname, dummy_file_handler_type.idname)) {
|
||||
if (iter_file_handler_type->rna_ext.srna) {
|
||||
rna_FileHandler_unregister(bmain, iter_file_handler_type->rna_ext.srna);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!RNA_struct_available_or_report(reports, dummy_file_handler_type.idname)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!RNA_struct_bl_idname_ok_or_report(reports, dummy_file_handler_type.idname, "_FH_")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create the new file handler type. */
|
||||
FileHandlerType *file_handler_type = MEM_new<FileHandlerType>(__func__);
|
||||
*file_handler_type = dummy_file_handler_type;
|
||||
|
||||
/* Gather all extensions from a string into a list. */
|
||||
const char char_separator = ';';
|
||||
const char *char_begin = file_handler_type->file_extensions_str;
|
||||
const char *char_end = BLI_strchr_or_end(char_begin, char_separator);
|
||||
while (char_begin[0]) {
|
||||
if (char_end - char_begin > 1) {
|
||||
bFileExtension extension;
|
||||
BLI_strncpy(extension.extension, char_begin, char_end - char_begin + 1);
|
||||
file_handler_type->file_extensions.append(extension);
|
||||
}
|
||||
char_begin = char_end[0] ? char_end + 1 : char_end;
|
||||
char_end = BLI_strchr_or_end(char_begin, char_separator);
|
||||
}
|
||||
|
||||
file_handler_type->rna_ext.srna = RNA_def_struct_ptr(
|
||||
&BLENDER_RNA, file_handler_type->idname, &RNA_FileHandler);
|
||||
file_handler_type->rna_ext.data = data;
|
||||
file_handler_type->rna_ext.call = call;
|
||||
file_handler_type->rna_ext.free = free;
|
||||
RNA_struct_blender_type_set(file_handler_type->rna_ext.srna, file_handler_type);
|
||||
|
||||
file_handler_type->poll_drop = have_function[0] ? file_handler_poll_drop : nullptr;
|
||||
|
||||
BKE_file_handler_add(file_handler_type);
|
||||
|
||||
return file_handler_type->rna_ext.srna;
|
||||
}
|
||||
|
||||
static StructRNA *rna_FileHandler_refine(PointerRNA *file_handler_ptr)
|
||||
{
|
||||
FileHandler *file_handler = (FileHandler *)file_handler_ptr->data;
|
||||
return (file_handler && file_handler->type->rna_ext.srna) ? file_handler->type->rna_ext.srna :
|
||||
&RNA_FileHandler;
|
||||
}
|
||||
|
||||
/* UILayout */
|
||||
|
||||
|
@ -2340,66 +2208,6 @@ static void rna_def_menu(BlenderRNA *brna)
|
|||
RNA_define_verify_sdna(true);
|
||||
}
|
||||
|
||||
static void rna_def_file_handler(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "FileHandler", nullptr);
|
||||
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_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 */
|
||||
|
||||
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 file handler gets a custom ID, otherwise it takes the "
|
||||
"name of the class used to define the file handler (for example, if the "
|
||||
"class name is \"OBJECT_FH_hello\", and bl_idname is not set by the "
|
||||
"script, then bl_idname = \"OBJECT_FH_hello\")");
|
||||
|
||||
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_OPTIONAL);
|
||||
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", "The file handler label");
|
||||
|
||||
prop = RNA_def_property(srna, "bl_file_extensions", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "type->file_extensions_str");
|
||||
RNA_def_property_flag(prop, PROP_REGISTER);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"File Extensions",
|
||||
"List of file extensions supported separated by semicolon.\n"
|
||||
"Example \".blend;.ble\"");
|
||||
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
|
||||
func = RNA_def_function(srna, "poll_drop", nullptr);
|
||||
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", "", "");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
}
|
||||
|
||||
static void rna_def_asset_shelf(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
|
|
@ -214,8 +214,6 @@ void WM_init(bContext *C, int argc, const char **argv)
|
|||
wm_operatortype_init();
|
||||
wm_operatortypes_register();
|
||||
|
||||
BKE_file_handlers_init();
|
||||
|
||||
WM_paneltype_init(); /* Lookup table only. */
|
||||
WM_menutype_init();
|
||||
WM_uilisttype_init();
|
||||
|
|
Loading…
Reference in New Issue
Remove these tests. The code may not be used if none of these are defined, but that's not a problem.