Commit: 6a4967ca6e6c6fd2a82c8af2549337e49d32756d
Author: Joshua Leung
Date:   Thu Mar 24 02:44:39 2016 +1300
Branches: master
https://developer.blender.org/rB6a4967ca6e6c6fd2a82c8af2549337e49d32756d

AnimEditors: Fuzzy/Multi-Word Name Filtering

Thanks to D1080 by @rockets, I've now been able to easily implement the
ability to type multiple word snippets/partial words into the text filter
field (in the Animation Editors), and have it filter the channels which
contain just some of those parts (instead of having to match everything).

For example, the following search strings will now work:
* "loc rot" or "lo ro" will now filter all location and rotation FCurves
* "col loc" will filter all location and color FCurves
* "scale" will also work as before to filter all scale FCurves

But, the following will not work:
* "lc rt" will NOT filter all location and rotation, as the fuzzy search only
  breaks down the search string based on whitespace placement

By default, this is not enabled when using name filtering (i.e. magnifying 
glass is checked,
and some filtering text is specified). Instead, you need to enable the "AZ" 
toggle beside
the name field. This fuzzy matching is not enabled by default as it could end 
up being
quite a bit slower on really heavy scenes. (There are probably some optimisation
opportunities, but that's only a future option if someone really needs it)

===================================================================

M       release/scripts/startup/bl_ui/space_dopesheet.py
M       source/blender/editors/animation/anim_filter.c
M       source/blender/makesdna/DNA_action_types.h
M       source/blender/makesrna/intern/rna_action.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py 
b/release/scripts/startup/bl_ui/space_dopesheet.py
index 4777525..af40f1f 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 2778a45..910e195 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 9c17a1f..96d7ec3 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 5d90b9f..7c21ce9 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);

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to