diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_dopesheet.py | 3 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 39 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_action_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_action.c | 8 |
4 files changed, 49 insertions, 5 deletions
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 47775251955..af40f1f070c 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -51,11 +51,13 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): row.prop(dopesheet, "show_only_matching_fcurves", text="") if dopesheet.show_only_matching_fcurves: row.prop(dopesheet, "filter_fcurve_name", text="") + row.prop(dopesheet, "use_multi_word_filter", text="") else: row = layout.row(align=True) row.prop(dopesheet, "use_filter_text", text="") if dopesheet.use_filter_text: row.prop(dopesheet, "filter_text", text="") + row.prop(dopesheet, "use_multi_word_filter", text="") if not genericFiltersOnly: row = layout.row(align=True) @@ -151,6 +153,7 @@ class DOPESHEET_HT_header(Header): row.prop(st.dopesheet, "use_filter_text", text="") if st.dopesheet.use_filter_text: row.prop(st.dopesheet, "filter_text", text="") + row.prop(st.dopesheet, "use_multi_word_filter", text="") row = layout.row(align=True) row.prop(toolsettings, "use_proportional_action", diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2778a458ca0..910e195173c 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -76,7 +76,9 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_alloca.h" #include "BLI_ghash.h" +#include "BLI_string.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -986,6 +988,35 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id return false; } +/* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */ +static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name) +{ + if (ads->flag & ADS_FLAG_FUZZY_NAMES) { + /* full fuzzy, multi-word, case insensitive matches */ + const size_t str_len = strlen(ads->searchstr); + const int words_max = (str_len / 2) + 1; + + int (*words)[2] = BLI_array_alloca(words, words_max); + const int words_len = BLI_string_find_split_words(ads->searchstr, str_len, ' ', words, words_max); + bool found = false; + + /* match name against all search words */ + for (int index = 0; index < words_len; index++) { + if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) { + found = true; + break; + } + } + + /* if we have a match somewhere, this returns true */ + return found; + } + else { + /* fallback/default - just case insensitive, but starts from start of word */ + return BLI_strcasestr(name, ads->searchstr) != NULL; + } +} + /* (Display-)Name-based F-Curve filtering * NOTE: when this function returns true, the F-Curve is to be skipped */ @@ -1010,7 +1041,7 @@ static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id) /* check for partial match with the match string, assuming case insensitive filtering * if match, this channel shouldn't be ignored! */ - return BLI_strcasestr(name, ads->searchstr) == NULL; + return !name_matches_dopesheet_filter(ads, name); } /* just let this go... */ @@ -1315,12 +1346,12 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop bool track_ok = false, strip_ok = false; /* check if the name of the track, or the strips it has are ok... */ - track_ok = BLI_strcasestr(nlt->name, ads->searchstr); + track_ok = name_matches_dopesheet_filter(ads, nlt->name); if (track_ok == false) { NlaStrip *strip; for (strip = nlt->strips.first; strip; strip = strip->next) { - if (BLI_strcasestr(strip->name, ads->searchstr)) { + if (name_matches_dopesheet_filter(ads, strip->name)) { strip_ok = true; break; } @@ -1520,7 +1551,7 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeShee if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) { /* skip layer if the name doesn't match the filter string */ if ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) { - if (BLI_strcasestr(gpl->info, ads->searchstr) == NULL) + if (name_matches_dopesheet_filter(ads, gpl->info) == false) continue; } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 9c17a1f4f5b..96d7ec3128c 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -606,7 +606,9 @@ typedef enum eDopeSheet_FilterFlag { /* DopeSheet general flags */ typedef enum eDopeSheet_Flag { ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */ - ADS_FLAG_SHOW_DBFILTERS = (1 << 1) /* show filters for datablocks */ + ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */ + + ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */ /* NOTE: datablock filter flags continued (1 << 10) onwards... */ } eDopeSheet_Flag; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 5d90b9fcae8..7c21ce95a1d 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -357,6 +357,14 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* Multi-word fuzzy search option for name/text filters */ + prop = RNA_def_property(srna, "use_multi_word_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_FUZZY_NAMES); + RNA_def_property_ui_text(prop, "Multi-Word Fuzzy Filter", + "Perform fuzzy/multi-word matching (WARNING: May be slow)"); + RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* NLA Specific Settings */ prop = RNA_def_property(srna, "show_missing_nla", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NLA_NOACT); |