diff --git a/source/blender/editors/space_buttons/buttons_ops.cc b/source/blender/editors/space_buttons/buttons_ops.cc index 2675a6d11ab..532cba5d529 100644 --- a/source/blender/editors/space_buttons/buttons_ops.cc +++ b/source/blender/editors/space_buttons/buttons_ops.cc @@ -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 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) diff --git a/source/blender/makesrna/RNA_access.hh b/source/blender/makesrna/RNA_access.hh index 1c5c784cce9..9b13329d377 100644 --- a/source/blender/makesrna/RNA_access.hh +++ b/source/blender/makesrna/RNA_access.hh @@ -496,6 +496,14 @@ void RNA_property_string_search( const char *edit_text, blender::FunctionRef visit_fn); +/** + * For filepath properties, get a glob pattern to filter possible files. + * For example: *.csv + */ +std::optional RNA_property_string_path_filter(const bContext *C, + PointerRNA *ptr, + PropertyRNA *prop); + /** * \return the length without `\0` terminator. */ diff --git a/source/blender/makesrna/RNA_define.hh b/source/blender/makesrna/RNA_define.hh index 3bed745ed67..3c2855955b4 100644 --- a/source/blender/makesrna/RNA_define.hh +++ b/source/blender/makesrna/RNA_define.hh @@ -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, diff --git a/source/blender/makesrna/RNA_types.hh b/source/blender/makesrna/RNA_types.hh index 15fd4a3b2d3..47213de47f0 100644 --- a/source/blender/makesrna/RNA_types.hh +++ b/source/blender/makesrna/RNA_types.hh @@ -676,6 +676,14 @@ using StringPropertySearchFunc = const char *edit_text, blender::FunctionRef 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 (*)(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 */ diff --git a/source/blender/makesrna/intern/makesrna.cc b/source/blender/makesrna/intern/makesrna.cc index 71d3e0e983f..0ff927bea41 100644 --- a/source/blender/makesrna/intern/makesrna.cc +++ b/source/blender/makesrna/intern/makesrna.cc @@ -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"); diff --git a/source/blender/makesrna/intern/rna_access.cc b/source/blender/makesrna/intern/rna_access.cc index 6f106efae9b..07861a7b6ad 100644 --- a/source/blender/makesrna/intern/rna_access.cc +++ b/source/blender/makesrna/intern/rna_access.cc @@ -3917,6 +3917,18 @@ void RNA_property_string_search( sprop->search(C, ptr, prop, edit_text, visit_fn); } +std::optional 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; diff --git a/source/blender/makesrna/intern/rna_define.cc b/source/blender/makesrna/intern/rna_define.cc index 87350abc6b1..7d374163d5e 100644 --- a/source/blender/makesrna/intern/rna_define.cc +++ b/source/blender/makesrna/intern/rna_define.cc @@ -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, diff --git a/source/blender/makesrna/intern/rna_internal_types.hh b/source/blender/makesrna/intern/rna_internal_types.hh index daa2519ef6b..c1770c31dc3 100644 --- a/source/blender/makesrna/intern/rna_internal_types.hh +++ b/source/blender/makesrna/intern/rna_internal_types.hh @@ -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; diff --git a/source/blender/makesrna/intern/rna_node_socket.cc b/source/blender/makesrna/intern/rna_node_socket.cc index 1eb7320988e..4e73121797f 100644 --- a/source/blender/makesrna/intern/rna_node_socket.cc +++ b/source/blender/makesrna/intern/rna_node_socket.cc @@ -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 rna_NodeSocketString_filepath_filter(const bContext * /*C*/, + PointerRNA *ptr, + PropertyRNA * /*prop*/) +{ + bNodeSocket *socket = static_cast(ptr->data); + BLI_assert(socket->type == SOCK_STRING); + if (const auto *decl = dynamic_cast( + 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); } diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh index e23107cd608..b0394ff786b 100644 --- a/source/blender/nodes/NOD_socket_declarations.hh +++ b/source/blender/nodes/NOD_socket_declarations.hh @@ -196,6 +196,7 @@ class String : public SocketDeclaration { std::string default_value; PropertySubType subtype = PROP_NONE; + std::optional path_filter; friend StringBuilder; @@ -211,6 +212,7 @@ class StringBuilder : public SocketDeclarationBuilder { public: StringBuilder &default_value(const std::string value); StringBuilder &subtype(PropertySubType subtype); + StringBuilder &path_filter(std::optional filter); }; class MenuBuilder; diff --git a/source/blender/nodes/geometry/nodes/node_geo_import_csv.cc b/source/blender/nodes/geometry/nodes/node_geo_import_csv.cc index 8a9f127655f..0db0ac3b2f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_import_csv.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_import_csv.cc @@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input("Path") .subtype(PROP_FILEPATH) + .path_filter("*.csv") .hide_label() .description("Path to a CSV file"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_import_obj.cc b/source/blender/nodes/geometry/nodes/node_geo_import_obj.cc index 851f7be7047..9104c5cfebd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_import_obj.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_import_obj.cc @@ -18,6 +18,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input("Path") .subtype(PROP_FILEPATH) + .path_filter("*.obj") .hide_label() .description("Path to a OBJ file"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_import_ply.cc b/source/blender/nodes/geometry/nodes/node_geo_import_ply.cc index 979a425717e..ebd8fa85df3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_import_ply.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_import_ply.cc @@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input("Path") .subtype(PROP_FILEPATH) + .path_filter("*.ply") .hide_label() .description("Path to a PLY file"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_import_stl.cc b/source/blender/nodes/geometry/nodes/node_geo_import_stl.cc index 7e5260057f7..5f2f7f88e33 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_import_stl.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_import_stl.cc @@ -17,6 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input("Path") .subtype(PROP_FILEPATH) + .path_filter("*.stl") .hide_label() .description("Path to a STL file"); diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc index 5f5d70291f2..0b0f0a70df4 100644 --- a/source/blender/nodes/intern/node_socket_declarations.cc +++ b/source/blender/nodes/intern/node_socket_declarations.cc @@ -537,6 +537,13 @@ bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket return socket; } +StringBuilder &StringBuilder::path_filter(std::optional filter) +{ + BLI_assert(decl_->subtype == PROP_FILEPATH); + decl_->path_filter = std::move(filter); + return *this; +} + /** \} */ /* -------------------------------------------------------------------- */