diff options
author | Ton Roosendaal <ton@blender.org> | 2006-11-07 17:25:58 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2006-11-07 17:25:58 +0300 |
commit | f34bf8a0cd4f3437f03c1894e507e1b8c2125b9d (patch) | |
tree | c2aa098efe8fd9bf6433dca36ae3c5708fedfeb9 /source | |
parent | 008d6987d0d2b0b2d3bc44c649b769c2d32d6f59 (diff) |
Patch #4980, by Joshua Leung (aligorith)
This enables finding data in the Outliner.
Usage: Fkey (partial strings), CTRL+Fkey (partial strings, case sensitive).
SHIFT+Fkey to repeat a search, this cycles around.
Extra changes:
- button popups to enter strings now starts activated.
- outliner either shows for Armature the Bones, or Posechannels or
Editbones, depending the mode. Was needed to make searches meaningful.
Although Joshua did very good work on the key functions, there were a couple
of issues in his code, and problems in Outliner code, that didn't make it
all work nicely. So, this is quite a revised patch. :)
Full review log can be found in the patch tracker.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 8 | ||||
-rw-r--r-- | source/blender/include/BIF_outliner.h | 9 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_oops_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_space_types.h | 8 | ||||
-rw-r--r-- | source/blender/src/header_oops.c | 65 | ||||
-rw-r--r-- | source/blender/src/outliner.c | 253 | ||||
-rw-r--r-- | source/blender/src/space.c | 16 | ||||
-rw-r--r-- | source/blender/src/toolbox.c | 5 |
8 files changed, 347 insertions, 21 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1ce1f2c7237..675a8f7f81e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -132,8 +132,8 @@ #include "BKE_texture.h" // for open_plugin_tex #include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND -#include "BIF_butspace.h" // for do_versions, patching event codes -#include "BIF_previewrender.h" // for struct RenderInfo +#include "BIF_butspace.h" // badlevel, for do_versions, patching event codes +#include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo #include "BLO_readfile.h" #include "BLO_undofile.h" #include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory @@ -3143,6 +3143,7 @@ static void lib_link_screen(FileData *fd, Main *main) } so->lockpoin= NULL; so->tree.first= so->tree.last= NULL; + so->search_tse.id= newlibadr(fd, NULL, so->search_tse.id); if(so->treestore) { tselem= so->treestore->data; @@ -3302,14 +3303,15 @@ void lib_link_screen_restore(Main *newmain, Scene *curscene) else if(sl->spacetype==SPACE_OOPS) { SpaceOops *so= (SpaceOops *)sl; Oops *oops; - int a; + oops= so->oops.first; while(oops) { oops->id= restore_pointer_by_name(newmain, (ID *)oops->id, 0); oops= oops->next; } so->lockpoin= NULL; + so->search_tse.id= restore_pointer_by_name(newmain, so->search_tse.id, 0); if(so->treestore) { TreeStore *ts= so->treestore; diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h index 539ee055dba..78557796467 100644 --- a/source/blender/include/BIF_outliner.h +++ b/source/blender/include/BIF_outliner.h @@ -38,7 +38,7 @@ struct TreeStoreElem; typedef struct TreeElement { struct TreeElement *next, *prev, *parent; ListBase subtree; - float xs, ys; // doe selection + float xs, ys; // do selection int store_index; // offset in tree store short flag, index; // flag for non-saved stuff, index for data arrays short idcode; // from TreeStore id @@ -72,6 +72,12 @@ typedef struct TreeElement { #define TSE_VERSE_GEOM_NODE 17 /*#endif*/ +/* outliner search flags */ +#define OL_FIND 0 +#define OL_FIND_CASE 1 +#define OL_FIND_COMPLETE 2 +#define OL_FIND_COMPLETE_CASE 3 + /* button events */ #define OL_NAMEBUTTON 1 @@ -86,6 +92,7 @@ extern void outliner_select(struct ScrArea *sa); extern void outliner_toggle_selected(struct ScrArea *sa); extern void outliner_operation_menu(struct ScrArea *sa); extern void outliner_page_up_down(struct ScrArea *sa, int up); +extern void outliner_find_panel(struct ScrArea *sa, int again, int flags); #endif diff --git a/source/blender/makesdna/DNA_oops_types.h b/source/blender/makesdna/DNA_oops_types.h index 0f49ed23b47..aaee18e3249 100644 --- a/source/blender/makesdna/DNA_oops_types.h +++ b/source/blender/makesdna/DNA_oops_types.h @@ -43,7 +43,7 @@ struct ID; typedef struct TreeStoreElem { short type, nr, flag, used; - ID *id; + struct ID *id; } TreeStoreElem; typedef struct TreeStore { @@ -65,7 +65,7 @@ typedef struct Oops { typedef struct OopsLink { struct OopsLink *next, *prev; short type, flag; - ID **idfrom; + struct ID **idfrom; Oops *to, *from; /* from is for temp */ float xof, yof; char name[12]; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index f89f67529a6..731823a0906 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -36,6 +36,7 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +#include "DNA_oops_types.h" /* for TreeStoreElem */ /* Hum ... Not really nice... but needed for spacebuts. */ #include "DNA_view2d_types.h" @@ -47,7 +48,6 @@ struct ImBuf; struct Image; struct SpaceIpo; struct BlendHandle; -struct TreeStore; struct RenderInfo; struct bNodeTree; struct uiBlock; @@ -206,6 +206,12 @@ typedef struct SpaceOops { ListBase tree; struct TreeStore *treestore; + + /* search stuff */ + char search_string[32]; + struct TreeStoreElem search_tse; + int search_flags, pad; + short type, outlinevis, storeflag; short deps_flags; diff --git a/source/blender/src/header_oops.c b/source/blender/src/header_oops.c index c4ebda76eae..fe1e3b89644 100644 --- a/source/blender/src/header_oops.c +++ b/source/blender/src/header_oops.c @@ -348,7 +348,67 @@ static uiBlock *oops_blockmenu(void *arg_unused) return block; } +static void do_oops_searchmenu(void *arg, int event) +{ + int search_flags = OL_FIND, again = 0; + + switch(event) + { + case 0: /* plain new find */ + search_flags = OL_FIND; + break; + case 1: /* case sensitive */ + search_flags = OL_FIND_CASE; + break; + case 2: /* full search */ + search_flags = OL_FIND_COMPLETE; + break; + case 3: /* full case sensitive */ + search_flags = OL_FIND_COMPLETE_CASE; + break; + case 4: /* again */ + again = 1; + break; + default: /* nothing valid */ + return; + } + + /* run search */ + outliner_find_panel(curarea, again, search_flags); +} + +static uiBlock *oops_searchmenu(void *arg_unused) +{ + uiBlock *block; + short yco= 0, menuwidth=120; + + block= uiNewBlock(&curarea->uiblocks, "oops_searchmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); + uiBlockSetButmFunc(block, do_oops_searchmenu, NULL); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find (Case Sensitive)|Ctrl F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Complete|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Complete (Case Sensitive)|Ctrl Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Again|Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, ""); + if(curarea->headertype==HEADERTOP) { + uiBlockSetDirection(block, UI_DOWN); + } + else { + uiBlockSetDirection(block, UI_TOP); + uiBlockFlipOrder(block); + } + + uiTextBoundsBlock(block, 50); + + return block; +} void oops_buttons(void) { @@ -405,6 +465,11 @@ void oops_buttons(void) xco+= xmax; } + else { + xmax= GetButStringLength("Search"); + uiDefPulldownBut(block, oops_searchmenu, NULL, "Search", xco, -2, xmax-3, 24, ""); + xco+= xmax; + } } uiBlockSetEmboss(block, UI_EMBOSS); diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index 45e84c6b735..640958bd3ed 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -127,6 +127,7 @@ extern ListBase session_list; extern ListBase server_list; #endif + /* ******************** PERSISTANT DATA ***************** */ static void outliner_storage_cleanup(SpaceOops *soops) @@ -229,7 +230,7 @@ void outliner_free_tree(ListBase *lb) while(lb->first) { TreeElement *te= lb->first; - + outliner_free_tree(&te->subtree); BLI_remlink(lb, te); MEM_freeN(te); @@ -440,8 +441,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i tenla->name= "Pose"; - if(ob!=G.obedit) { // channels undefined in editmode, but we want the 'tenla' pose icon itself - int a= 0; + if(ob!=G.obedit && (ob->flag & OB_POSEMODE)) { // channels undefined in editmode, but we want the 'tenla' pose icon itself + int a= 0, const_index= 1000; /* ensure unique id for bone constraints */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) { ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a); ten->name= pchan->name; @@ -453,12 +455,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i bConstraint *con; TreeElement *ten1; TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); - int a= 0; char *str; tenla1->name= "Constraints"; - for(con= pchan->constraints.first; con; con= con->next, a++) { - ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, a); + for(con= pchan->constraints.first; con; con= con->next, const_index++) { + ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); target= get_constraint_target(con, &str); if(str && str[0]) ten1->name= str; else if(target) ten1->name= target->id.name+2; @@ -479,6 +480,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i BLI_remlink(&tenla->subtree, ten); par= (TreeElement *)pchan->parent->prev; BLI_addtail(&par->subtree, ten); + ten->parent= par; } } ten= nten; @@ -704,14 +706,20 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i BLI_remlink(&te->subtree, ten); par= ebone->parent->temp; BLI_addtail(&par->subtree, ten); + ten->parent= par; } ten= nten; } } else { - Bone *curBone; - for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ - outliner_add_bone(soops, &te->subtree, id, curBone, te, &a); + /* do not extend Armature when we have posemode */ + tselem= TREESTORE(te->parent); + if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->flag & OB_POSEMODE); + else { + Bone *curBone; + for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ + outliner_add_bone(soops, &te->subtree, id, curBone, te, &a); + } } } } @@ -1031,6 +1039,46 @@ static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curleve } } +/* return 1 when levels were opened */ +static int outliner_open_back(SpaceOops *soops, TreeElement *te) +{ + TreeStoreElem *tselem; + int retval= 0; + + for (te= te->parent; te; te= te->parent) { + tselem= TREESTORE(te); + if (tselem->flag & TSE_CLOSED) { + tselem->flag &= ~TSE_CLOSED; + retval= 1; + } + } + return retval; +} + +static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te= lb->first; te; te= te->next) { + /* check if this tree-element was the one we're seeking */ + if (te == teFind) { + *found= 1; + return; + } + + /* try to see if sub-tree contains it then */ + outliner_open_reveal(soops, &te->subtree, teFind, found); + if (*found) { + tselem= TREESTORE(te); + if (tselem->flag & TSE_CLOSED) + tselem->flag &= ~TSE_CLOSED; + return; + } + } +} + + void outliner_one_level(struct ScrArea *sa, int add) { SpaceOops *soops= sa->spacedata.first; @@ -1767,6 +1815,36 @@ void outliner_mouse_event(ScrArea *sa, short event) outliner_select(sa); } +/* recursive helper for function below */ +static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty) +{ + TreeStoreElem *tselem= TREESTORE(te); + + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs= startx; + te->ys= *starty; + *starty-= OL_H; + + if((tselem->flag & TSE_CLOSED)==0) { + TreeElement *ten; + for(ten= te->subtree.first; ten; ten= ten->next) { + outliner_set_coordinates_element(soops, ten, startx+OL_X, starty); + } + } + +} + +/* to retrieve coordinates with redrawing the entire tree */ +static void outliner_set_coordinates(SpaceOops *soops) +{ + TreeElement *te; + int starty= soops->v2d.tot.ymax-OL_H; + int startx= 0; + + for(te= soops->tree.first; te; te= te->next) { + outliner_set_coordinates_element(soops, te, startx, &starty); + } +} static TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id) { @@ -1804,6 +1882,158 @@ void outliner_show_active(struct ScrArea *sa) } } +void outliner_show_selected(struct ScrArea *sa) +{ + SpaceOops *so= sa->spacedata.first; + TreeElement *te; + int ytop; + + te= outliner_find_id(so, &so->tree, (ID *)OBACT); + if(te) { + /* make te->ys center of view */ + ytop= te->ys + (so->v2d.mask.ymax-so->v2d.mask.ymin)/2; + if(ytop>0) ytop= 0; + so->v2d.cur.ymax= ytop; + so->v2d.cur.ymin= ytop-(so->v2d.mask.ymax-so->v2d.mask.ymin); + scrarea_queue_redraw(sa); + } +} + + +/* find next element that has this name */ +static TreeElement *outliner_find_named(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound) +{ + TreeElement *te, *tes; + + for (te= lb->first; te; te= te->next) { + int found; + + /* determine if match */ + if(flags==OL_FIND) + found= strcasestr(te->name, name)!=NULL; + else if(flags==OL_FIND_CASE) + found= strstr(te->name, name)!=NULL; + else if(flags==OL_FIND_COMPLETE) + found= strcasecmp(te->name, name)==0; + else + found= strcmp(te->name, name)==0; + + if(found) { + /* name is right, but is element the previous one? */ + if (prev) { + if ((te != prev) && (*prevFound)) + return te; + if (te == prev) { + *prevFound = 1; + } + } + else + return te; + } + + tes= outliner_find_named(soops, &te->subtree, name, flags, prev, prevFound); + if(tes) return tes; + } + + /* nothing valid found */ + return NULL; +} + +/* tse is not in the treestore, we use its contents to find a match */ +static TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) +{ + TreeStore *ts= soops->treestore; + TreeStoreElem *tselem; + int a; + + if(tse->id==NULL) return NULL; + + /* check if 'tse' is in treestore */ + tselem= ts->data; + for(a=0; a<ts->usedelem; a++, tselem++) { + if(tselem->id==tse->id) { + if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) { + break; + } + } + } + if(tselem) + return outliner_find_tree_element(&soops->tree, a); + + return NULL; +} + + +/* Called to find an item based on name. + */ +void outliner_find_panel(struct ScrArea *sa, int again, int flags) +{ + SpaceOops *soops= sa->spacedata.first; + TreeElement *te= NULL; + TreeElement *last_find; + TreeStoreElem *tselem; + int ytop, prevFound=0; + char name[33]; + + /* get last found tree-element based on stored search_tse */ + last_find= outliner_find_tse(soops, &soops->search_tse); + + /* determine which type of search to do */ + if (again && last_find) { + /* no popup panel - previous + user wanted to search for next after previous */ + BLI_strncpy(name, soops->search_string, 33); + flags= soops->search_flags; + + /* try to find matching element */ + te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound); + if (te==NULL) { + /* no more matches after previous, start from beginning again */ + prevFound= 1; + te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound); + } + } + else { + /* pop up panel - no previous, or user didn't want search after previous */ + strcpy(name, ""); + if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) { + te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound); + } + else return; /* XXX RETURN! XXX */ + } + + /* do selection and reveil */ + if (te) { + tselem= TREESTORE(te); + if (tselem) { + /* expand branches so that it will be visible, we need to get correct coordinates */ + if( outliner_open_back(soops, te)) + outliner_set_coordinates(soops); + + /* deselect all visible, and select found element */ + outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0); + tselem->flag |= TSE_SELECTED; + + /* make te->ys center of view */ + ytop= te->ys + (soops->v2d.mask.ymax-soops->v2d.mask.ymin)/2; + if(ytop>0) ytop= 0; + soops->v2d.cur.ymax= ytop; + soops->v2d.cur.ymin= ytop-(soops->v2d.mask.ymax-soops->v2d.mask.ymin); + + /* store selection */ + soops->search_tse= *tselem; + + BLI_strncpy(soops->search_string, name, 33); + soops->search_flags= flags; + + /* redraw */ + scrarea_queue_redraw(sa); + } + } + else { + if (name) error("Not found: %s", name); + } +} + static int subtree_has_objects(SpaceOops *soops, ListBase *lb) { TreeElement *te; @@ -2678,7 +2908,7 @@ static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int st } } } - /* store coord and continue */ + /* store coord and continue, we need coordinates for elements outside view too */ te->xs= startx; te->ys= *starty; te->xend= startx+offsx; @@ -2774,9 +3004,9 @@ static void outliner_draw_tree(SpaceOops *soops) for(te= soops->tree.first; te; te= te->next) { outliner_draw_tree_element(soops, te, startx, &starty); } - } + static void outliner_back(SpaceOops *soops) { int ystart; @@ -2881,6 +3111,7 @@ static void outliner_buttons(uiBlock *block, SpaceOops *soops, ListBase *lb) for(te= lb->first; te; te= te->next) { tselem= TREESTORE(te); if(tselem->flag & TSE_TEXTBUT) { + if(tselem->type == TSE_POSE_BASE) continue; // prevent crash when trying to rename 'pose' entry of armature if(tselem->type==TSE_EBONE) len = sizeof(((EditBone*) 0)->name); else if (tselem->type==TSE_MODIFIER) len = sizeof(((ModifierData*) 0)->name); diff --git a/source/blender/src/space.c b/source/blender/src/space.c index d0e0e337e19..ed80eb96eb7 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -4495,6 +4495,19 @@ static void winqreadoopsspace(ScrArea *sa, void *spacedata, BWinEvent *evt) else outliner_toggle_visible(sa); break; + case FKEY: + { + /* search */ + int search_flags=0, again=0; + + /* CTRL=case sensitive, SHIFT=find again, ALT=complete */ + if (G.qual & LR_CTRLKEY) search_flags |= 1; + if (G.qual & LR_ALTKEY) search_flags |= 8; + if (G.qual & LR_SHIFTKEY) again = 1; + + outliner_find_panel(sa, again, search_flags); + } + break; case WKEY: outliner_operation_menu(sa); break; @@ -5045,7 +5058,8 @@ void freespacelist(ScrArea *sa) } } else if(sl->spacetype==SPACE_OOPS) { - free_oopspace((SpaceOops *)sl); + SpaceOops *so= (SpaceOops *) sl; + free_oopspace(so); } else if(sl->spacetype==SPACE_IMASEL) { free_imasel((SpaceImaSel *)sl); diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index df01e6e7346..70e5012b9c6 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -306,11 +306,12 @@ short sbutton(char *var, float min, float max, char *str) x1=mval[0]-150; y1=mval[1]-20; - uiDefButC(block, TEX, 0, str, x1+5,y1+10,125,20, var,(float)min,(float)max, 0, 0, ""); + uiDefButC(block, TEX, 2, str, x1+5,y1+10,125,20, var,(float)min,(float)max, 0, 0, ""); uiDefBut(block, BUT, 1, "OK", x1+136,y1+10,25,20, NULL, 0, 0, 0, 0, ""); uiBoundsBlock(block, 5); - + + mainqenter_ext(BUT_ACTIVATE, 2, 0); /* note, button id '2' is asking for errors some day! */ ret= uiDoBlocks(&listb, 0); if(ret==UI_RETURN_OK) return 1; |