Nodes: support filepath filter for import nodes

Currently, when selecting a file path using the file browser opened from the
node socket, there is no filter active making it harder than necessary to find
the correct file. This patch adds the proper filter. Something similar is done
when using e.g. the gltf import from the menu.

Supporting this requires changes in a bunch of places:
* `StringPropertyRNA` now has a callback that returns the file path pattern.
  This has to be a callback, because the same property is used on all file path
  sockets, but the valid extension depends on the node.
* The string socket declaration also has the optional path pattern. This can be
  set in the node declarations.

Pull Request: https://projects.blender.org/blender/blender/pulls/134931
This commit is contained in:
Jacques Lucke
2025-02-24 18:52:10 +01:00
parent 589dce871d
commit e05ef4c838
15 changed files with 99 additions and 1 deletions

View File

@@ -34,6 +34,7 @@
#include "ED_undo.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_prototypes.hh"
#include "UI_interface.hh"
@@ -393,6 +394,9 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool is_output_path = (RNA_property_flag(prop) & PROP_PATH_OUTPUT) != 0;
RNA_property_boolean_set(op->ptr, prop_check_existing, is_output_path);
}
if (std::optional<std::string> filter = RNA_property_string_path_filter(C, &ptr, prop)) {
RNA_string_set(op->ptr, "filter_glob", filter->c_str());
}
WM_event_add_fileselect(C, op);
@@ -423,6 +427,11 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "filter_glob", nullptr, 0, "Glob Filter", "Custom filter");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void BUTTONS_OT_directory_browse(wmOperatorType *ot)

View File

@@ -496,6 +496,14 @@ void RNA_property_string_search(
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/**
* For filepath properties, get a glob pattern to filter possible files.
* For example: *.csv
*/
std::optional<std::string> RNA_property_string_path_filter(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop);
/**
* \return the length without `\0` terminator.
*/

View File

@@ -508,6 +508,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
void RNA_def_property_string_search_func(PropertyRNA *prop,
const char *search,
eStringPropertySearchFlag search_flag);
void RNA_def_property_string_filepath_filter_func(PropertyRNA *prop, const char *filter);
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll);
void RNA_def_property_collection_funcs(PropertyRNA *prop,

View File

@@ -676,6 +676,14 @@ using StringPropertySearchFunc =
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/**
* Returns an optional glob pattern (e.g. "*.png") that can be passed to the file browser to filter
* valid files for this property.
*/
using StringPropertyPathFilterFunc = std::optional<std::string> (*)(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop);
using EnumPropertyGetFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using EnumPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int value);
/* same as PropEnumItemFunc */

View File

@@ -4504,7 +4504,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, %s, (eStringPropertySearchFlag)%d, %d, ",
"\t%s, %s, %s, %s, %s, %s, %s, (eStringPropertySearchFlag)%d, %s, %d, ",
rna_function_string(sprop->get),
rna_function_string(sprop->length),
rna_function_string(sprop->set),
@@ -4513,6 +4513,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(sprop->set_ex),
rna_function_string(sprop->search),
int(sprop->search_flag),
rna_function_string(sprop->path_filter),
sprop->maxlength);
rna_print_c_string(f, sprop->defaultvalue);
fprintf(f, "\n");

View File

@@ -3917,6 +3917,18 @@ void RNA_property_string_search(
sprop->search(C, ptr, prop, edit_text, visit_fn);
}
std::optional<std::string> RNA_property_string_path_filter(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop)
{
BLI_assert(prop->type == PROP_STRING);
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (!sprop->path_filter) {
return std::nullopt;
}
return sprop->path_filter(C, ptr, prop);
}
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;

View File

@@ -3536,6 +3536,28 @@ void RNA_def_property_string_search_func(PropertyRNA *prop,
}
}
void RNA_def_property_string_filepath_filter_func(PropertyRNA *prop, const char *filter)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
sprop->path_filter = (StringPropertyPathFilterFunc)filter;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,

View File

@@ -492,6 +492,12 @@ struct StringPropertyRNA {
StringPropertySearchFunc search;
eStringPropertySearchFlag search_flag;
/**
* Used for strings which are #PROP_FILEPATH to have a default filter when opening a file
* browser.
*/
StringPropertyPathFilterFunc path_filter;
int maxlength; /* includes string terminator! */
const char *defaultvalue;

View File

@@ -603,6 +603,20 @@ const EnumPropertyItem *RNA_node_socket_menu_itemf(bContext * /*C*/,
return RNA_node_enum_definition_itemf(*data->enum_items, r_free);
}
std::optional<std::string> rna_NodeSocketString_filepath_filter(const bContext * /*C*/,
PointerRNA *ptr,
PropertyRNA * /*prop*/)
{
bNodeSocket *socket = static_cast<bNodeSocket *>(ptr->data);
BLI_assert(socket->type == SOCK_STRING);
if (const auto *decl = dynamic_cast<const blender::nodes::decl::String *>(
socket->runtime->declaration))
{
return decl->path_filter;
}
return std::nullopt;
}
#else
static void rna_def_node_socket(BlenderRNA *brna)
@@ -1325,6 +1339,10 @@ static void rna_def_node_socket_string(BlenderRNA *brna,
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
if (subtype == PROP_FILEPATH) {
RNA_def_property_string_filepath_filter_func(prop, "rna_NodeSocketString_filepath_filter");
}
RNA_def_struct_sdna_from(srna, "bNodeSocket", nullptr);
}

View File

@@ -196,6 +196,7 @@ class String : public SocketDeclaration {
std::string default_value;
PropertySubType subtype = PROP_NONE;
std::optional<std::string> path_filter;
friend StringBuilder;
@@ -211,6 +212,7 @@ class StringBuilder : public SocketDeclarationBuilder<String> {
public:
StringBuilder &default_value(const std::string value);
StringBuilder &subtype(PropertySubType subtype);
StringBuilder &path_filter(std::optional<std::string> filter);
};
class MenuBuilder;

View File

@@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>("Path")
.subtype(PROP_FILEPATH)
.path_filter("*.csv")
.hide_label()
.description("Path to a CSV file");

View File

@@ -18,6 +18,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>("Path")
.subtype(PROP_FILEPATH)
.path_filter("*.obj")
.hide_label()
.description("Path to a OBJ file");

View File

@@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>("Path")
.subtype(PROP_FILEPATH)
.path_filter("*.ply")
.hide_label()
.description("Path to a PLY file");

View File

@@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>("Path")
.subtype(PROP_FILEPATH)
.path_filter("*.stl")
.hide_label()
.description("Path to a STL file");

View File

@@ -537,6 +537,13 @@ bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
return socket;
}
StringBuilder &StringBuilder::path_filter(std::optional<std::string> filter)
{
BLI_assert(decl_->subtype == PROP_FILEPATH);
decl_->path_filter = std::move(filter);
return *this;
}
/** \} */
/* -------------------------------------------------------------------- */