Patch [#23443] Change outliner filter into search

Shane Ambler (sambler) for this 12-month vintage!

From description:
One thing with the outliner filter box is it only filters items that
are currently visible. To find what you want you need to manually
expand a few levels so that what you want to find is visible.

This small patch expands items when filtering is done - effectively
turning it into a search.

Currently this does not alter the datablocks view as expanding all
entries takes waaaay tooooo long.
I prevent the expansion of RNA entries for userprefs which prevents
infinite recursion but the datablocks list is just too big for this
approach. I think it would need a custom outliner_build_tree for a
full search.
This commit is contained in:
Joshua Leung 2011-09-09 12:46:07 +00:00
parent bef9509565
commit 67ea3180d9
8 changed files with 95 additions and 33 deletions

View File

@ -97,7 +97,7 @@ static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
TreeElement *te= lb->first;
while(te) {
TreeStoreElem *tselem= TREESTORE(te);
if((tselem->flag & TSE_CLOSED)==0)
if(TSELEM_OPEN(tselem,soops))
outliner_height(soops, &te->subtree, h);
(*h) += UI_UNIT_Y;
te= te->next;
@ -112,7 +112,7 @@ static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
// TreeStoreElem *tselem= TREESTORE(te);
// XXX fixme... te->xend is not set yet
if(tselem->flag & TSE_CLOSED) {
if(!TSELEM_OPEN(tselem,soops)) {
if (te->xend > *w)
*w = te->xend;
}
@ -135,7 +135,7 @@ static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int start
if(startx+100 > *w)
*w = startx+100;
if((tselem->flag & TSE_CLOSED)==0)
if(TSELEM_OPEN(tselem,soops))
outliner_rna_width(soops, &te->subtree, w, startx+UI_UNIT_X);
te= te->next;
}
@ -519,7 +519,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
}
}
if((tselem->flag & TSE_CLOSED)==0) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
if(TSELEM_OPEN(tselem,soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
}
}
@ -560,7 +560,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
ptr= &te->rnaptr;
prop= te->directdata;
if(!(RNA_property_type(prop) == PROP_POINTER && (tselem->flag & TSE_CLOSED)==0))
if(!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem,soops))) )
uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, UI_UNIT_Y-1);
}
else if(tselem->type == TSE_RNA_ARRAY_ELEM) {
@ -571,7 +571,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
}
}
if((tselem->flag & TSE_CLOSED)==0) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
if(TSELEM_OPEN(tselem,soops)) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
}
}
@ -828,7 +828,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo
}
}
if((tselem->flag & TSE_CLOSED)==0) outliner_draw_keymapbuts(block, ar, soops, &te->subtree);
if(TSELEM_OPEN(tselem,soops)) outliner_draw_keymapbuts(block, ar, soops, &te->subtree);
}
}
@ -871,7 +871,7 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Spa
}
}
if((tselem->flag & TSE_CLOSED)==0) outliner_buttons(C, block, ar, soops, &te->subtree);
if(TSELEM_OPEN(tselem,soops)) outliner_buttons(C, block, ar, soops, &te->subtree);
}
}
@ -1237,6 +1237,18 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
glEnable(GL_BLEND);
/* start by highlighting search matches
* we don't expand items when searching in the datablocks but we
* still want to highlight any filter matches.
*/
if ( (SEARCHING_OUTLINER(soops) || (soops->outlinevis==SO_DATABLOCKS && soops->search_string[0]!=0)) &&
(tselem->flag & TSE_SEARCHMATCH))
{
/* TODO - add search highlight colour to theme? */
glColor4f(0.2f, 0.5f, 0.2f, 0.3f);
glRecti(startx, *starty+1, ar->v2d.cur.xmax, *starty+UI_UNIT_Y-1);
}
/* colors for active/selected data */
if(tselem->type==0) {
if(te->idcode==ID_SCE) {
@ -1317,10 +1329,10 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
icon_x = startx+5*ufac;
// icons a bit higher
if(tselem->flag & TSE_CLOSED)
UI_icon_draw((float)icon_x, (float)*starty+2*ufac, ICON_DISCLOSURE_TRI_RIGHT);
else
if(TSELEM_OPEN(tselem,soops))
UI_icon_draw((float)icon_x, (float)*starty+2*ufac, ICON_DISCLOSURE_TRI_DOWN);
else
UI_icon_draw((float)icon_x, (float)*starty+2*ufac, ICON_DISCLOSURE_TRI_RIGHT);
}
offsx+= UI_UNIT_X;
@ -1356,7 +1368,7 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
offsx+= (int)(UI_UNIT_X + UI_GetStringWidth(te->name));
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
if(tselem->flag & TSE_CLOSED) {
if(!TSELEM_OPEN(tselem,soops)) {
if(te->subtree.first) {
if(tselem->type==0 && te->idcode==ID_SCE);
else if(tselem->type!=TSE_R_LAYER) { /* this tree element always has same amount of branches, so dont draw */
@ -1382,7 +1394,7 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
te->ys= (float)*starty;
te->xend= startx+offsx;
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
*starty-= UI_UNIT_Y;
for(ten= te->subtree.first; ten; ten= ten->next)
@ -1415,7 +1427,7 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx,
*starty-= UI_UNIT_Y;
if((tselem->flag & TSE_CLOSED)==0)
if(TSELEM_OPEN(tselem,soops))
outliner_draw_hierarchy(soops, &te->subtree, startx+UI_UNIT_X, starty);
}
@ -1439,12 +1451,12 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *
tselem= TREESTORE(te);
/* selection status */
if((tselem->flag & TSE_CLOSED)==0)
if(TSELEM_OPEN(tselem,soops))
if(tselem->type == TSE_RNA_STRUCT)
glRecti(0, *starty+1, (int)ar->v2d.cur.xmax+V2D_SCROLL_WIDTH, *starty+UI_UNIT_Y-1);
*starty-= UI_UNIT_Y;
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
outliner_draw_struct_marks(ar, soops, &te->subtree, starty);
if(tselem->type == TSE_RNA_STRUCT)
fdrawline(0, (float)*starty+UI_UNIT_Y, ar->v2d.cur.xmax+V2D_SCROLL_WIDTH, (float)*starty+UI_UNIT_Y);
@ -1465,7 +1477,7 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb,
glRecti(0, *starty+1, (int)ar->v2d.cur.xmax, *starty+UI_UNIT_Y-1);
}
*starty-= UI_UNIT_Y;
if((tselem->flag & TSE_CLOSED)==0) outliner_draw_selection(ar, soops, &te->subtree, starty);
if(TSELEM_OPEN(tselem,soops)) outliner_draw_selection(ar, soops, &te->subtree, starty);
}
}

View File

@ -687,7 +687,7 @@ static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te,
te->ys= (float)(*starty);
*starty-= UI_UNIT_Y;
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
TreeElement *ten;
for(ten= te->subtree.first; ten; ten= ten->next) {
outliner_set_coordinates_element(soops, ten, startx+UI_UNIT_X, starty);
@ -910,7 +910,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase
}
else tselem->flag |= TSE_CLOSED;
if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(scene, soops, &te->subtree);
if(TSELEM_OPEN(tselem,soops)) tree_element_show_hierarchy(scene, soops, &te->subtree);
}
}
@ -1175,7 +1175,7 @@ static void do_outliner_drivers_editop(SpaceOops *soops, ListBase *tree, ReportL
}
/* go over sub-tree */
if ((tselem->flag & TSE_CLOSED)==0)
if (TSELEM_OPEN(tselem,soops))
do_outliner_drivers_editop(soops, &te->subtree, reports, mode);
}
}
@ -1343,7 +1343,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa
}
/* go over sub-tree */
if ((tselem->flag & TSE_CLOSED)==0)
if (TSELEM_OPEN(tselem,soops))
do_outliner_keyingset_editop(soops, ks, &te->subtree, mode);
}
}

View File

@ -126,6 +126,27 @@ typedef struct TreeElement {
#define OL_RNA_COL_SPACEX (UI_UNIT_X*2.5f)
/* Outliner Searching --
Are we looking for something in the outliner?
If so finding matches in child items makes it more useful
- We want to flag parents to act as being open to filter child matches
- and also flag matches so we can highlight them
- Flags are stored in TreeStoreElem->flag
- Flag options defined in DNA_outliner_types.h
- SO_SEARCH_RECURSIVE defined in DNA_space_types.h
- NOT in datablocks view - searching all datablocks takes way too long
to be useful
- not searching into RNA items helps but isn't the complete solution
*/
#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
/* is the currrent element open? if so we also show children */
#define TSELEM_OPEN(telm,sv) ( (telm->flag & TSE_CLOSED)==0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) )
/* outliner_tree.c ----------------------------------------------- */
void outliner_free_tree(ListBase *lb);

View File

@ -134,7 +134,7 @@ static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *se
change |= 1;
}
}
else if ((tselem->flag & TSE_CLOSED)==0) {
else if (TSELEM_OPEN(tselem,soops)) {
/* Only try selecting sub-elements if we haven't hit the right element yet
*
* Hack warning:

View File

@ -145,7 +145,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
}
}
}
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
set_operation_types(soops, &te->subtree,
scenelevel, objectlevel, idlevel, datalevel);
}
@ -250,7 +250,7 @@ static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *
operation_cb(C, scene, te, tsep, tselem);
}
}
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb);
}
}
@ -397,7 +397,7 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem);
}
}
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb);
}
}
@ -504,7 +504,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
operation_cb(event, te, tselem);
}
}
if((tselem->flag & TSE_CLOSED)==0) {
if(TSELEM_OPEN(tselem,soops)) {
outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb);
}
}
@ -857,7 +857,7 @@ static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *l
operation_cb(te, tselem, tsep, newid);
}
}
if ((tselem->flag & TSE_CLOSED)==0) {
if (TSELEM_OPEN(tselem,soops)) {
outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb);
}
}

View File

@ -827,6 +827,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
check_persistant(soops, te, id, type, index);
tselem= TREESTORE(te);
/* if we are searching for something expand to see child elements */
if(SEARCHING_OUTLINER(soops))
tselem->flag |= TSE_CHILDSEARCH;
te->parent= parent;
te->index= index; // for data arays
if(ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP));
@ -981,6 +985,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else
te->name= (char*)RNA_struct_ui_name(ptr->type);
/* If searching don't expand RNA entries */
if(SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA",te->name)==0) tselem->flag &= ~TSE_CHILDSEARCH;
iterprop= RNA_struct_iterator_property(ptr->type);
tot= RNA_property_collection_length(ptr, iterprop);
@ -989,7 +996,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
if(!tselem->used)
tselem->flag &= ~TSE_CLOSED;
if(!(tselem->flag & TSE_CLOSED)) {
if(TSELEM_OPEN(tselem,soops)) {
for(a=0; a<tot; a++)
outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_PROPERTY, a);
}
@ -1010,11 +1017,14 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata= prop;
te->rnaptr= *ptr;
/* If searching don't expand RNA entries */
if(SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA",te->name)==0) tselem->flag &= ~TSE_CHILDSEARCH;
if(proptype == PROP_POINTER) {
pptr= RNA_property_pointer_get(ptr, prop);
if(pptr.data) {
if(!(tselem->flag & TSE_CLOSED))
if(TSELEM_OPEN(tselem,soops))
outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1);
else
te->flag |= TE_LAZY_CLOSED;
@ -1023,7 +1033,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if(proptype == PROP_COLLECTION) {
tot= RNA_property_collection_length(ptr, prop);
if(!(tselem->flag & TSE_CLOSED)) {
if(TSELEM_OPEN(tselem,soops)) {
for(a=0; a<tot; a++) {
RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, a);
@ -1035,7 +1045,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if(ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
tot= RNA_property_array_length(ptr, prop);
if(!(tselem->flag & TSE_CLOSED)) {
if(TSELEM_OPEN(tselem,soops)) {
for(a=0; a<tot; a++)
outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_ARRAY_ELEM, a);
}
@ -1068,7 +1078,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata= idv;
te->name= km->idname;
if(!(tselem->flag & TSE_CLOSED)) {
if(TSELEM_OPEN(tselem,soops)) {
a= 0;
for (kmi= km->items.first; kmi; kmi= kmi->next, a++) {
@ -1368,7 +1378,10 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
*/
tselem= TREESTORE(te);
if ((tselem->flag & TSE_CLOSED) || outliner_filter_tree(soops, &te->subtree)==0) {
/* flag as not a found item */
tselem->flag &= ~TSE_SEARCHMATCH;
if ((!TSELEM_OPEN(tselem,soops)) || outliner_filter_tree(soops, &te->subtree)==0) {
outliner_free_tree(&te->subtree);
BLI_remlink(lb, te);
@ -1377,6 +1390,11 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
}
}
else {
tselem= TREESTORE(te);
/* flag as a found item - we can then highlight it */
tselem->flag |= TSE_SEARCHMATCH;
/* filter subtree too */
outliner_filter_tree(soops, &te->subtree);
}
@ -1399,6 +1417,14 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
TreeStoreElem *tselem;
int show_opened= (soops->treestore==NULL); /* on first view, we open scenes */
/* Are we looking for something - we want to tag parents to filter child matches
- NOT in datablocks view - searching all datablocks takes way too long to be useful
- this variable is only set once per tree build */
if(soops->search_string[0]!=0 && soops->outlinevis!=SO_DATABLOCKS)
soops->search_flags |= SO_SEARCH_RECURSIVE;
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;

View File

@ -51,6 +51,8 @@ typedef struct TreeStore {
#define TSE_CLOSED 1
#define TSE_SELECTED 2
#define TSE_TEXTBUT 4
#define TSE_CHILDSEARCH 8
#define TSE_SEARCHMATCH 16
/* TreeStoreElem types in BIF_outliner.h */

View File

@ -861,6 +861,7 @@ enum {
/* outliner search flags (SpaceOops->search_flags) */
#define SO_FIND_CASE_SENSITIVE (1<<0)
#define SO_FIND_COMPLETE (1<<1)
#define SO_SEARCH_RECURSIVE (1<<2)
/* headerbuttons: 450-499 */