diff options
author | Ton Roosendaal <ton@blender.org> | 2004-10-10 15:33:19 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2004-10-10 15:33:19 +0400 |
commit | 851c5781be6e347d7e0c7198e225e9bce8479c65 (patch) | |
tree | 343bf4b974e5cf03023c7913463e7c776b7854fb /source | |
parent | 7028b1eb99336b74d298f6561165f4f71ced9e39 (diff) |
- Added Outliner selection
As a means to indicate items in the Outliner to do operations on, you can
select with RMB items. Works like FileSelect here. Since selection in
Outliner is only on outliner level, no further UI updates happen. That is
reserved for LMB actions.
Implemented right now are only few operations... they can be called up with
the WKEY (the famous spare key :)
- if objects selected, a menu appears with choices
- if materials or textures selected, a meny appears to unlink them
If you make mixed or confusing selections you get a warning message.
TODO: add selection color in theme, and of course more operations.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 8 | ||||
-rw-r--r-- | source/blender/include/BIF_outliner.h | 6 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_oops_types.h | 2 | ||||
-rw-r--r-- | source/blender/src/header_oops.c | 2 | ||||
-rw-r--r-- | source/blender/src/outliner.c | 482 | ||||
-rw-r--r-- | source/blender/src/space.c | 10 |
6 files changed, 453 insertions, 57 deletions
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 40cc3b1fa61..c40b64295f6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -349,11 +349,19 @@ void unlink_object(Object *ob) else if(sl->spacetype==SPACE_OOPS) { SpaceOops *so= (SpaceOops *)sl; Oops *oops; + oops= so->oops.first; while(oops) { if(oops->id==(ID *)ob) oops->id= NULL; oops= oops->next; } + if(so->treestore) { + TreeStoreElem *tselem= so->treestore->data; + int a; + for(a=0; a<so->treestore->usedelem; a++, tselem++) { + if(tselem->id==(ID *)ob) tselem->id= NULL; + } + } } } diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h index 22830009e1c..ec44e9aa3f4 100644 --- a/source/blender/include/BIF_outliner.h +++ b/source/blender/include/BIF_outliner.h @@ -33,6 +33,7 @@ #ifndef BIF_OUTLINER_H #define BIF_OUTLINER_H +struct TreeStoreElem; typedef struct TreeElement { struct TreeElement *next, *prev, *parent; @@ -43,7 +44,7 @@ typedef struct TreeElement { short idcode; // from TreeStore id short xend; // width of item display, for select char *name; - void *directdata; // Armature Bones, ... + void *directdata; // Armature Bones, Base, ... } TreeElement; /* TreeElement->flag */ @@ -69,6 +70,9 @@ extern void outliner_toggle_visible(struct ScrArea *sa); extern void outliner_show_active(struct ScrArea *sa); extern void outliner_show_hierarchy(struct ScrArea *sa); extern void outliner_one_level(struct ScrArea *sa, int add); +extern void outliner_select(struct ScrArea *sa); +extern void outliner_toggle_selected(struct ScrArea *sa); +extern void outliner_operation_menu(struct ScrArea *sa); #endif diff --git a/source/blender/makesdna/DNA_oops_types.h b/source/blender/makesdna/DNA_oops_types.h index 5e6707577d7..6b4ed9a3128 100644 --- a/source/blender/makesdna/DNA_oops_types.h +++ b/source/blender/makesdna/DNA_oops_types.h @@ -77,7 +77,7 @@ typedef struct OopsLink { /* TreeStoreElem->flag */ #define TSE_CLOSED 1 -#define TSE_LASTCLICKED 2 +#define TSE_SELECTED 2 /* TreeStoreElem types in BIF_outliner.h */ diff --git a/source/blender/src/header_oops.c b/source/blender/src/header_oops.c index c38534f471a..32752c63b55 100644 --- a/source/blender/src/header_oops.c +++ b/source/blender/src/header_oops.c @@ -169,7 +169,7 @@ static uiBlock *oops_viewmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); - uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show/Hide All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show/Hide All", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hierarchy|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Active|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); } diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index 698cd5d196f..7ff20484635 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -76,7 +76,9 @@ #include "BIF_editarmature.h" #include "BIF_editnla.h" #include "BIF_editview.h" +#include "BIF_editconstraint.h" #include "BIF_gl.h" +#include "BIF_graphics.h" #include "BIF_interface.h" #include "BIF_mywindow.h" #include "BIF_outliner.h" @@ -87,6 +89,7 @@ #include "BIF_resources.h" #include "BIF_screen.h" #include "BIF_space.h" +#include "BIF_toolbox.h" #ifdef INTERNATIONAL #include "FTF_Api.h" @@ -94,6 +97,7 @@ #include "BDR_editobject.h" #include "BSE_drawipo.h" +#include "BSE_edit.h" #include "BSE_editaction.h" #include "blendef.h" @@ -112,40 +116,45 @@ /* ******************** PERSISTANT DATA ***************** */ -/* for now only called after reading file or undo step */ static void outliner_storage_cleanup(SpaceOops *soops) { TreeStore *ts= soops->treestore; - if(ts && (soops->storeflag & SO_TREESTORE_CLEANUP)) { - TreeStoreElem *tselem= ts->data; + if(ts) { + TreeStoreElem *tselem; int a, unused= 0; - for(a=0; a<ts->usedelem; a++, tselem++) { - if(tselem->id==NULL) unused++; - } - - if(unused) { - if(ts->usedelem == unused) { - MEM_freeN(ts->data); - ts->data= NULL; - ts->usedelem= ts->totelem= 0; + /* each element used once, for ID blocks with more users to have each a treestore */ + for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) tselem->used= 0; + + /* cleanup only after reading file or undo step */ + if(soops->storeflag & SO_TREESTORE_CLEANUP) { + + for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) { + if(tselem->id==NULL) unused++; } - else { - TreeStoreElem *tsnewar, *tsnew; - - tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem"); - tselem= ts->data; - for(a=0; a<ts->usedelem; a++, tselem++) { - if(tselem->id) { - *tsnew= *tselem; - tsnew++; + + if(unused) { + if(ts->usedelem == unused) { + MEM_freeN(ts->data); + ts->data= NULL; + ts->usedelem= ts->totelem= 0; + } + else { + TreeStoreElem *tsnewar, *tsnew; + + tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem"); + for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) { + if(tselem->id) { + *tsnew= *tselem; + tsnew++; + } } + MEM_freeN(ts->data); + ts->data= tsnewar; + ts->usedelem-= unused; + ts->totelem= ts->usedelem; } - MEM_freeN(ts->data); - ts->data= tsnewar; - ts->usedelem-= unused; - ts->totelem= ts->usedelem; } } } @@ -166,9 +175,10 @@ static void check_persistant(SpaceOops *soops, TreeElement *te, ID *id, short ty /* check if 'te' is in treestore */ tselem= ts->data; for(a=0; a<ts->usedelem; a++, tselem++) { - if(tselem->id==id) { + if(tselem->id==id && tselem->used==0) { if(type==0 ||(tselem->type==type && tselem->nr==nr)) { te->store_index= a; + tselem->used= 1; return; } } @@ -423,7 +433,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i tenla->name= "Hooks"; for(hook=ob->hooks.first; hook; hook= hook->next, a++) { ten= outliner_add_element(soops, &tenla->subtree, hook->parent, tenla, TE_HOOK, a); - ten->name= hook->name; + if(ten) ten->name= hook->name; } } if(ob->defbase.first) { @@ -593,6 +603,8 @@ static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb) BLI_remlink(lb, te); tep= (TreeElement *)ob->parent->id.newid; BLI_addtail(&tep->subtree, te); + // set correct parent pointers + for(te=tep->subtree.first; te; te= te->next) te->parent= tep; } } te= ten; @@ -604,7 +616,7 @@ static void outliner_build_tree(SpaceOops *soops) Scene *sce; Base *base; Object *ob; - TreeElement *te; + TreeElement *te, *ten; TreeStoreElem *tselem; outliner_free_tree(&soops->tree); @@ -620,7 +632,8 @@ static void outliner_build_tree(SpaceOops *soops) tselem= TREESTORE(te); for(base= sce->base.first; base; base= base->next) { - outliner_add_element(soops, &te->subtree, base->object, te, 0, 0); + ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0); + ten->directdata= base; } outliner_make_hierarchy(soops, &te->subtree); } @@ -629,7 +642,8 @@ static void outliner_build_tree(SpaceOops *soops) outliner_add_element(soops, &soops->tree, G.scene->world, NULL, 0, 0); for(base= G.scene->base.first; base; base= base->next) { - outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + ten->directdata= base; } outliner_make_hierarchy(soops, &soops->tree); } @@ -645,7 +659,8 @@ static void outliner_build_tree(SpaceOops *soops) if(ob) { for(base= G.scene->base.first; base; base= base->next) { if(base->object->type==ob->type) { - outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + ten->directdata= base; } } outliner_make_hierarchy(soops, &soops->tree); @@ -654,14 +669,17 @@ static void outliner_build_tree(SpaceOops *soops) else if(soops->outlinevis == SO_SELECTED) { for(base= G.scene->base.first; base; base= base->next) { if(base->lay & G.scene->lay) { - if(base==BASACT || (base->flag & SELECT)) - outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + if(base==BASACT || (base->flag & SELECT)) { + ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + ten->directdata= base; + } } } outliner_make_hierarchy(soops, &soops->tree); } else { - outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); + ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); + if(ten) ten->directdata= BASACT; } outliner_sort(soops, &soops->tree); @@ -682,7 +700,7 @@ static int outliner_count_levels(SpaceOops *soops, ListBase *lb, int curlevel) return level; } -static int outliner_has_one_closed(SpaceOops *soops, ListBase *lb, int curlevel) +static int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel) { TreeElement *te; TreeStoreElem *tselem; @@ -690,24 +708,24 @@ static int outliner_has_one_closed(SpaceOops *soops, ListBase *lb, int curlevel) for(te= lb->first; te; te= te->next) { tselem= TREESTORE(te); - if(tselem->flag & TSE_CLOSED) return curlevel; + if(tselem->flag & flag) return curlevel; - level= outliner_has_one_closed(soops, &te->subtree, curlevel+1); + level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1); if(level) return level; } return 0; } -static void outliner_open_close(SpaceOops *soops, ListBase *lb, int open) +static void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set) { TreeElement *te; TreeStoreElem *tselem; for(te= lb->first; te; te= te->next) { tselem= TREESTORE(te); - if(open) tselem->flag &= ~TSE_CLOSED; - else tselem->flag |= TSE_CLOSED; - outliner_open_close(soops, &te->subtree, open); + if(set==0) tselem->flag &= ~flag; + else tselem->flag |= flag; + outliner_set_flag(soops, &te->subtree, flag, set); } } @@ -715,14 +733,27 @@ void outliner_toggle_visible(struct ScrArea *sa) { SpaceOops *soops= sa->spacedata.first; - if( outliner_has_one_closed(soops, &soops->tree, 1)) - outliner_open_close(soops, &soops->tree, 1); + if( outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1)) + outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0); else - outliner_open_close(soops, &soops->tree, 0); + outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1); scrarea_queue_redraw(curarea); } +void outliner_toggle_selected(struct ScrArea *sa) +{ + SpaceOops *soops= sa->spacedata.first; + + if( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1)) + outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0); + else + outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1); + + scrarea_queue_redraw(curarea); +} + + static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open) { TreeElement *te; @@ -747,7 +778,7 @@ void outliner_one_level(struct ScrArea *sa, int add) SpaceOops *soops= sa->spacedata.first; int level; - level= outliner_has_one_closed(soops, &soops->tree, 1); + level= outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1); if(add==1) { if(level) outliner_openclose_level(soops, &soops->tree, 1, level, 1); } @@ -778,12 +809,13 @@ static void tree_element_active_object(SpaceOops *soops, TreeElement *te) if(ob==NULL) return; sce= (Scene *)outliner_search_back(soops, te, ID_SCE); - if(G.scene != sce) { + if(sce && G.scene != sce) { if(G.obedit) exit_editmode(2); + if(G.obpose) exit_posemode(1); set_scene(sce); } - /* find associated base */ + /* find associated base in current scene */ for(base= FIRSTBASE; base; base= base->next) if(base->object==ob) break; if(base) { @@ -811,6 +843,7 @@ static void tree_element_active_object(SpaceOops *soops, TreeElement *te) } if(ob!=G.obedit) exit_editmode(2); + if(ob!=G.obpose) exit_posemode(1); } static int tree_element_active_material(SpaceOops *soops, TreeElement *te, int set) @@ -1157,7 +1190,7 @@ static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short even /* all below close/open? */ if( (G.qual & LR_SHIFTKEY) ) { tselem->flag &= ~TSE_CLOSED; - outliner_open_close(soops, &te->subtree, outliner_has_one_closed(soops, &te->subtree, 1)); + outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1)); } else { if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED; @@ -1178,10 +1211,12 @@ static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short even if(te->idcode==ID_SCE) { if(G.scene!=(Scene *)tselem->id) { if(G.obedit) exit_editmode(2); + if(G.obpose) exit_posemode(1); set_scene((Scene *)tselem->id); } } else if(ELEM4(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT)) { + if(G.obpose) exit_posemode(1); if(G.obedit) exit_editmode(2); else { enter_editmode(); @@ -1311,6 +1346,320 @@ void outliner_show_hierarchy(struct ScrArea *sa) scrarea_queue_redraw(sa); } +static void do_outliner_select(SpaceOops *soops, ListBase *lb, float y1, float y2, short *selecting) +{ + TreeElement *te; + TreeStoreElem *tselem; + + if(y1>y2) SWAP(float, y1, y2); + + for(te= lb->first; te; te= te->next) { + tselem= TREESTORE(te); + + if(te->ys + OL_H < y1) return; + if(te->ys < y2) { + if((te->flag & TE_ICONROW)==0) { + if(*selecting == -1) { + if( tselem->flag & TSE_SELECTED) *selecting= 0; + else *selecting= 1; + } + if(*selecting) tselem->flag |= TSE_SELECTED; + else tselem->flag &= ~TSE_SELECTED; + } + } + if((tselem->flag & TSE_CLOSED)==0) do_outliner_select(soops, &te->subtree, y1, y2, selecting); + } +} + +/* its own redraw loop... urm */ +void outliner_select(struct ScrArea *sa ) +{ + SpaceOops *so= sa->spacedata.first; + float fmval[2], y1, y2; + short mval[2], yo=-1, selecting= -1; + + getmouseco_areawin(mval); + fmval[0]= mval[0]; + fmval[1]= mval[1]; + areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1); + y1= fmval[1]; + + while (get_mbut() & R_MOUSE) { + getmouseco_areawin(mval); + fmval[0]= mval[0]; + fmval[1]= mval[1]; + areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1); + y2= fmval[1]; + if(yo!=mval[1]) { + do_outliner_select(so, &so->tree, y1, y2, &selecting); + yo= mval[1]; + scrarea_do_windraw(sa); + screen_swapbuffers(); + + y1= y2; + } + } + +} + +/* ************ SELECTION OPERATIONS ********* */ + +static int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; // globals, euh... you can do better + +static void set_operation_types(SpaceOops *soops, ListBase *lb) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for(te= lb->first; te; te= te->next) { + tselem= TREESTORE(te); + if(tselem->flag & TSE_SELECTED) { + if(tselem->type) { + if(datalevel==0) datalevel= tselem->type; + else if(datalevel!=tselem->type) datalevel= -1; + } + else { + int idcode= GS(tselem->id->name); + switch(idcode) { + case ID_SCE: + scenelevel= 1; + break; + case ID_OB: + objectlevel= 1; + break; + + case ID_ME: case ID_CU: case ID_MB: case ID_LT: + case ID_LA: case ID_AR: case ID_CA: + idlevel= -2; + break; + + case ID_MA: case ID_TE: case ID_IP: case ID_IM: + case ID_SO: case ID_KE: case ID_WO: case ID_AC: + case ID_NLA: case ID_TXT: + if(idlevel==0) idlevel= idcode; + else if(idlevel!=idcode) idlevel= -1; + break; + } + } + } + if((tselem->flag & TSE_CLOSED)==0) set_operation_types(soops, &te->subtree); + } +} + +static void unlink_material_cb(TreeElement *te, TreeStoreElem *tsep) +{ + Material **matar=NULL; + int a, totcol=0; + + if( GS(tsep->id->name)==ID_OB) { + Object *ob= (Object *)tsep->id; + totcol= ob->totcol; + matar= ob->mat; + } + else if( GS(tsep->id->name)==ID_ME) { + Mesh *me= (Mesh *)tsep->id; + totcol= me->totcol; + matar= me->mat; + } + else if( GS(tsep->id->name)==ID_CU) { + Curve *cu= (Curve *)tsep->id; + totcol= cu->totcol; + matar= cu->mat; + } + else if( GS(tsep->id->name)==ID_MB) { + MetaBall *mb= (MetaBall *)tsep->id; + totcol= mb->totcol; + matar= mb->mat; + } + + for(a=0; a<totcol; a++) { + if(a==te->index && matar[a]) { + matar[a]->id.us--; + matar[a]= NULL; + } + } +} + +static void unlink_texture_cb(TreeElement *te, TreeStoreElem *tsep) +{ + MTex **mtex= NULL; + int tottex= 0; + int a; + + if( GS(tsep->id->name)==ID_MA) { + Material *ma= (Material *)tsep->id; + mtex= ma->mtex; + tottex= 8; + } + else if( GS(tsep->id->name)==ID_LA) { + Lamp *la= (Lamp *)tsep->id; + mtex= la->mtex; + tottex= 6; + } + else if( GS(tsep->id->name)==ID_WO) { + World *wrld= (World *)tsep->id; + mtex= wrld->mtex; + tottex= 6; + } + for(a=0; a<tottex; a++) { + if(a==te->index && mtex[a]) { + if(mtex[a]->tex) { + mtex[a]->tex->id.us--; + mtex[a]->tex= NULL; + } + } + } +} + +static void outliner_do_libdata_operation(SpaceOops *soops, ListBase *lb, + void (*operation_cb)(TreeElement *, TreeStoreElem *)) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for(te=lb->first; te; te= te->next) { + tselem= TREESTORE(te); + if(tselem->flag & TSE_SELECTED) { + if(tselem->type==0) { + TreeStoreElem *tsep= TREESTORE(te->parent); + operation_cb(te, tsep); + } + } + if((tselem->flag & TSE_CLOSED)==0) { + outliner_do_libdata_operation(soops, &te->subtree, operation_cb); + } + } +} + +/* */ + +static void object_select_cb(TreeElement *te, TreeStoreElem *tselem) +{ + Base *base= (Base *)te->directdata; + + base->flag |= SELECT; + base->object->flag |= SELECT; +} + +static void object_deselect_cb(TreeElement *te, TreeStoreElem *tselem) +{ + Base *base= (Base *)te->directdata; + + base->flag &= ~SELECT; + base->object->flag &= ~SELECT; +} + +static void object_delete_cb(TreeElement *te, TreeStoreElem *tselem) +{ + Base *base= (Base *)te->directdata; + + if(base) { + // check also library later + if(G.obpose==base->object) exit_posemode(1); + if(G.obedit==base->object) exit_editmode(2); + + if(base==BASACT) { + G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT); + setcursor_space(SPACE_VIEW3D, CURSOR_STD); + } + + free_and_unlink_base(base); + te->directdata= NULL; + tselem->id= NULL; + } +} + + +static void outliner_do_object_operation(SpaceOops *soops, ListBase *lb, + void (*operation_cb)(TreeElement *, TreeStoreElem *)) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for(te=lb->first; te; te= te->next) { + tselem= TREESTORE(te); + if(tselem->flag & TSE_SELECTED) { + if(tselem->type==0 && te->idcode==ID_OB) + operation_cb(te, tselem); + } + if((tselem->flag & TSE_CLOSED)==0) { + outliner_do_object_operation(soops, &te->subtree, operation_cb); + } + } +} + +void outliner_operation_menu(ScrArea *sa) +{ + SpaceOops *soops= sa->spacedata.first; + + // globals + scenelevel= objectlevel= idlevel= datalevel=0; + + set_operation_types(soops, &soops->tree); + + if(scenelevel) { + if(objectlevel || datalevel || idlevel) error("Mixed selection"); + else pupmenu("Scene Operations%t|Delete"); + } + else if(objectlevel) { + short event= pupmenu("Object Operations%t|Select%x1|Deselect%x2|Delete%x4"); + if(event>0) { + char *str=""; + + if(event==1) { + outliner_do_object_operation(soops, &soops->tree, object_select_cb); + str= "Select Objects"; + } + else if(event==2) { + outliner_do_object_operation(soops, &soops->tree, object_deselect_cb); + str= "Deselect Objects"; + } + else if(event==4) { + outliner_do_object_operation(soops, &soops->tree, object_delete_cb); + str= "Delete Objects"; + } + + countall(); + test_scene_constraints(); // for delete + + BIF_undo_push(str); + allqueue(REDRAWALL, 0); // yah... to be sure :) + } + } + else if(idlevel) { + if(idlevel==-1 || datalevel) error("Mixed selection"); + else if(idlevel==-2) error("No operations available"); + else { + short event= pupmenu("Data Operations%t|Unlink"); + + if(event==1) { + switch(idlevel) { + case ID_MA: + outliner_do_libdata_operation(soops, &soops->tree, unlink_material_cb); + allqueue(REDRAWBUTSSHADING, 1); + break; + case ID_TE: + outliner_do_libdata_operation(soops, &soops->tree, unlink_texture_cb); + allqueue(REDRAWBUTSSHADING, 1); + break; + default: + error("Not yet..."); + } + allqueue(REDRAWOOPS, 0); + } + } + } + else if(datalevel) { + if(datalevel==-1) error("Mixed selection"); + else { + pupmenu("Data Operations%t|Delete"); + } + } + else error("Nothing selected"); + +} + + /* ***************** DRAW *************** */ static void tselem_draw_icon(TreeStoreElem *tselem) @@ -1492,7 +1841,10 @@ static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int st /* open/close icon, only when sublevels, except for scene */ if(te->subtree.first || te->idcode==ID_SCE) { - glRasterPos2i(startx, *starty+2); // icons a bit higher + if(tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE)) + glRasterPos2i(startx, *starty+2); // icons a bit higher + else + glRasterPos2i(startx+5, *starty+2); // icons a bit higher if(tselem->flag & TSE_CLOSED) BIF_draw_icon(ICON_TRIA_CLOSED); else @@ -1571,10 +1923,31 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, outliner_draw_hierarchy(soops, &te->subtree, startx+OL_X, starty); } + /* vertical line */ te= lb->last; if(te->parent || lb->first!=lb->last) { tselem= TREESTORE(te); - if(tselem->type==0 && te->idcode==ID_OB) glRecti(startx, y1+OL_H, startx+1, y2); + if(tselem->type==0 && te->idcode==ID_OB) { + + glRecti(startx, y1+OL_H, startx+1, y2); + } + } +} + +static void outliner_draw_selection(SpaceOops *soops, ListBase *lb, int *starty) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for(te= lb->first; te; te= te->next) { + tselem= TREESTORE(te); + + /* selection status */ + if(tselem->flag & TSE_SELECTED) { + glRecti(0, *starty+1, (int)soops->v2d.mask.xmax, *starty+OL_H-1); + } + *starty-= OL_H; + if((tselem->flag & TSE_CLOSED)==0) outliner_draw_selection(soops, &te->subtree, starty); } } @@ -1588,13 +1961,19 @@ static void outliner_draw_tree(SpaceOops *soops) #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once + + // selection first + glColor3ub(125, 150, 175); + starty= soops->v2d.tot.ymax-OL_H; + outliner_draw_selection(soops, &soops->tree, &starty); - //BIF_ThemeColorShade(TH_BACK, -20); + // black hierarchy lines glColor3ub(0,0,0); starty= soops->v2d.tot.ymax-OL_H/2; startx= 6; outliner_draw_hierarchy(soops, &soops->tree, startx, &starty); + // items themselves starty= soops->v2d.tot.ymax-OL_H; startx= 0; for(te= soops->tree.first; te; te= te->next) { @@ -1617,7 +1996,6 @@ static void outliner_back(SpaceOops *soops) } } - void draw_outliner(ScrArea *sa, SpaceOops *soops) { int sizey; diff --git a/source/blender/src/space.c b/source/blender/src/space.c index fc9df9f94e2..5c786927491 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -3802,11 +3802,17 @@ static void winqreadoopsspace(ScrArea *sa, void *spacedata, BWinEvent *evt) case WHEELDOWNMOUSE: view2dmove(event); /* in drawipo.c */ break; + case RIGHTMOUSE: + outliner_select(sa); + break; case AKEY: - outliner_toggle_visible(sa); + outliner_toggle_selected(sa); break; - + case WKEY: + outliner_operation_menu(sa); + break; + case HOMEKEY: outliner_show_hierarchy(sa); break; |