Added new render pass: "Mist".
[blender.git] / source / blender / src / outliner.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2004 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_action_types.h"
36 #include "DNA_armature_types.h"
37 #include "DNA_constraint_types.h"
38 #include "DNA_curve_types.h"
39 #include "DNA_camera_types.h"
40 #include "DNA_image_types.h"
41 #include "DNA_ipo_types.h"
42 #include "DNA_group_types.h"
43 #include "DNA_key_types.h"
44 #include "DNA_lamp_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_mesh_types.h"
47 #include "DNA_meta_types.h"
48 #include "DNA_modifier_types.h"
49 #include "DNA_nla_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_oops_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_texture_types.h"
56 #include "DNA_text_types.h"
57 #include "DNA_world_types.h"
58
59 #include "BLI_blenlib.h"
60
61 #include "BKE_constraint.h"
62 #include "BKE_deform.h"
63 #include "BKE_depsgraph.h"
64 #include "BKE_global.h"
65 #include "BKE_group.h"
66 #include "BKE_library.h"
67 #include "BKE_main.h"
68 #include "BKE_material.h"
69 #include "BKE_modifier.h"
70 #include "BKE_screen.h"
71 #include "BKE_scene.h"
72 #include "BKE_utildefines.h"
73
74 #ifdef WITH_VERSE
75 #include "BKE_verse.h"
76 #endif
77
78 #include "BIF_butspace.h"
79 #include "BIF_drawscene.h"
80 #include "BIF_drawtext.h"
81 #include "BIF_editaction.h"
82 #include "BIF_editarmature.h"
83 #include "BIF_editdeform.h"
84 #include "BIF_editnla.h"
85 #include "BIF_editview.h"
86 #include "BIF_editconstraint.h"
87 #include "BIF_gl.h"
88 #include "BIF_graphics.h"
89 #include "BIF_interface.h"
90 #include "BIF_interface_icons.h"
91 #include "BIF_mywindow.h"
92 #include "BIF_outliner.h"
93 #include "BIF_language.h"
94 #include "BIF_mainqueue.h"
95 #include "BIF_poseobject.h"
96 #include "BIF_previewrender.h"
97 #include "BIF_resources.h"
98 #include "BIF_screen.h"
99 #include "BIF_space.h"
100 #include "BIF_toolbox.h"
101
102 #ifdef WITH_VERSE
103 #include "BIF_verse.h"
104 #endif
105
106 #ifdef INTERNATIONAL
107 #include "FTF_Api.h"
108 #endif
109
110 #include "BDR_editobject.h"
111 #include "BSE_drawipo.h"
112 #include "BSE_edit.h"
113 #include "BSE_view.h"
114
115 #include "PIL_time.h" 
116
117 #include "blendef.h"
118 #include "mydevice.h"
119
120 #define OL_H    19
121 #define OL_X    18
122
123 #define OL_TOG_RESTRICT_VIEWX   54
124 #define OL_TOG_RESTRICT_SELECTX 36
125 #define OL_TOG_RESTRICT_RENDERX 18
126
127 #define OL_TOGW                         OL_TOG_RESTRICT_VIEWX
128
129 #define TS_CHUNK        128
130
131 #define TREESTORE(a) ((a)?soops->treestore->data+(a)->store_index:NULL)
132
133 #ifdef WITH_VERSE
134 extern ListBase session_list;
135 extern ListBase server_list;
136 #endif
137
138
139 /* ******************** PROTOTYPES ***************** */
140 static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int startx, int *starty);
141
142
143 /* ******************** PERSISTANT DATA ***************** */
144
145 static void outliner_storage_cleanup(SpaceOops *soops)
146 {
147         TreeStore *ts= soops->treestore;
148         
149         if(ts) {
150                 TreeStoreElem *tselem;
151                 int a, unused= 0;
152                 
153                 /* each element used once, for ID blocks with more users to have each a treestore */
154                 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) tselem->used= 0;
155
156                 /* cleanup only after reading file or undo step */
157                 if(soops->storeflag & SO_TREESTORE_CLEANUP) {
158                         
159                         for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
160                                 if(tselem->id==NULL) unused++;
161                         }
162
163                         if(unused) {
164                                 if(ts->usedelem == unused) {
165                                         MEM_freeN(ts->data);
166                                         ts->data= NULL;
167                                         ts->usedelem= ts->totelem= 0;
168                                 }
169                                 else {
170                                         TreeStoreElem *tsnewar, *tsnew;
171                                         
172                                         tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem");
173                                         for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
174                                                 if(tselem->id) {
175                                                         *tsnew= *tselem;
176                                                         tsnew++;
177                                                 }
178                                         }
179                                         MEM_freeN(ts->data);
180                                         ts->data= tsnewar;
181                                         ts->usedelem-= unused;
182                                         ts->totelem= ts->usedelem;
183                                 }
184                         }
185                 }
186         }
187 }
188
189 static void check_persistant(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
190 {
191         TreeStore *ts;
192         TreeStoreElem *tselem;
193         int a;
194         
195         /* case 1; no TreeStore */
196         if(soops->treestore==NULL) {
197                 ts= soops->treestore= MEM_callocN(sizeof(TreeStore), "treestore");
198         }
199         ts= soops->treestore;
200         
201         /* check if 'te' is in treestore */
202         tselem= ts->data;
203         for(a=0; a<ts->usedelem; a++, tselem++) {
204                 if(tselem->id==id && tselem->used==0) {
205                         if((type==0 && tselem->type==0) ||(tselem->type==type && tselem->nr==nr)) {
206                                 te->store_index= a;
207                                 tselem->used= 1;
208                                 return;
209                         }
210                 }
211         }
212         
213         /* add 1 element to treestore */
214         if(ts->usedelem==ts->totelem) {
215                 TreeStoreElem *tsnew;
216                 
217                 tsnew= MEM_mallocN((ts->totelem+TS_CHUNK)*sizeof(TreeStoreElem), "treestore data");
218                 if(ts->data) {
219                         memcpy(tsnew, ts->data, ts->totelem*sizeof(TreeStoreElem));
220                         MEM_freeN(ts->data);
221                 }
222                 ts->data= tsnew;
223                 ts->totelem+= TS_CHUNK;
224         }
225         
226         tselem= ts->data+ts->usedelem;
227         
228         tselem->type= type;
229         if(type) tselem->nr= nr; // we're picky! :)
230         else tselem->nr= 0;
231         tselem->id= id;
232         tselem->used = 0;
233         tselem->flag= TSE_CLOSED;
234         te->store_index= ts->usedelem;
235         
236         ts->usedelem++;
237 }
238
239 /* ******************** TREE MANAGEMENT ****************** */
240
241 void outliner_free_tree(ListBase *lb)
242 {
243         
244         while(lb->first) {
245                 TreeElement *te= lb->first;
246                 
247                 outliner_free_tree(&te->subtree);
248                 BLI_remlink(lb, te);
249                 MEM_freeN(te);
250         }
251 }
252
253 static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
254 {
255         TreeElement *te= lb->first;
256         while(te) {
257                 TreeStoreElem *tselem= TREESTORE(te);
258                 if((tselem->flag & TSE_CLOSED)==0) 
259                         outliner_height(soops, &te->subtree, h);
260                 (*h)++;
261                 te= te->next;
262         }
263 }
264
265 static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
266 {
267         TreeElement *te= lb->first;
268         while(te) {
269                 TreeStoreElem *tselem= TREESTORE(te);
270                 if(tselem->flag & TSE_CLOSED) {
271                         if (te->xend > *w)
272                                 *w = te->xend;
273                 }
274                 outliner_width(soops, &te->subtree, w);
275                 te= te->next;
276         }
277 }
278
279 static TreeElement *outliner_find_tree_element(ListBase *lb, int store_index)
280 {
281         TreeElement *te= lb->first, *tes;
282         while(te) {
283                 if(te->store_index==store_index) return te;
284                 tes= outliner_find_tree_element(&te->subtree, store_index);
285                 if(tes) return tes;
286                 te= te->next;
287         }
288         return NULL;
289 }
290
291
292
293 static ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode)
294 {
295         TreeStoreElem *tselem;
296         te= te->parent;
297         
298         while(te) {
299                 tselem= TREESTORE(te);
300                 if(te->idcode==idcode && tselem->type==0) return tselem->id;
301                 te= te->parent;
302         }
303         return NULL;
304 }
305
306 struct treesort {
307         TreeElement *te;
308         ID *id;
309         char *name;
310         short idcode;
311 };
312
313 static int treesort_alpha(const void *v1, const void *v2)
314 {
315         const struct treesort *x1= v1, *x2= v2;
316         int comp;
317         
318         /* first put objects last (hierarchy) */
319         comp= (x1->idcode==ID_OB);
320         if(x2->idcode==ID_OB) comp+=2;
321         
322         if(comp==1) return 1;
323         else if(comp==2) return -1;
324         else if(comp==3) {
325                 int comp= strcmp(x1->name, x2->name);
326                 
327                 if( comp>0 ) return 1;
328                 else if( comp<0) return -1;
329                 return 0;
330         }
331         return 0;
332 }
333
334 /* this is nice option for later? doesnt look too useful... */
335 #if 0
336 static int treesort_obtype_alpha(const void *v1, const void *v2)
337 {
338         const struct treesort *x1= v1, *x2= v2;
339         
340         /* first put objects last (hierarchy) */
341         if(x1->idcode==ID_OB && x2->idcode!=ID_OB) return 1;
342         else if(x2->idcode==ID_OB && x1->idcode!=ID_OB) return -1;
343         else {
344                 /* 2nd we check ob type */
345                 if(x1->idcode==ID_OB && x2->idcode==ID_OB) {
346                         if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
347                         else if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
348                         else return 0;
349                 }
350                 else {
351                         int comp= strcmp(x1->name, x2->name);
352                         
353                         if( comp>0 ) return 1;
354                         else if( comp<0) return -1;
355                         return 0;
356                 }
357         }
358 }
359 #endif
360
361 /* sort happens on each subtree individual */
362 static void outliner_sort(SpaceOops *soops, ListBase *lb)
363 {
364         TreeElement *te;
365         TreeStoreElem *tselem;
366         int totelem=0;
367         
368         te= lb->last;
369         if(te==NULL) return;
370         tselem= TREESTORE(te);
371         
372         /* sorting rules; only object lists or deformgroups */
373         if( (tselem->type==TSE_DEFGROUP) || (tselem->type==0 && te->idcode==ID_OB)) {
374                 
375                 /* count first */
376                 for(te= lb->first; te; te= te->next) totelem++;
377                 
378                 if(totelem>1) {
379                         struct treesort *tear= MEM_mallocN(totelem*sizeof(struct treesort), "tree sort array");
380                         struct treesort *tp=tear;
381                         int skip= 0;
382                         
383                         for(te= lb->first; te; te= te->next, tp++) {
384                                 tselem= TREESTORE(te);
385                                 tp->te= te;
386                                 tp->name= te->name;
387                                 tp->idcode= te->idcode;
388                                 if(tselem->type && tselem->type!=TSE_DEFGROUP) tp->idcode= 0;   // dont sort this
389                                 tp->id= tselem->id;
390                         }
391                         /* keep beginning of list */
392                         for(tp= tear, skip=0; skip<totelem; skip++, tp++)
393                                 if(tp->idcode) break;
394                         
395                         if(skip<totelem)
396                                 qsort(tear+skip, totelem-skip, sizeof(struct treesort), treesort_alpha);
397                         
398                         lb->first=lb->last= NULL;
399                         tp= tear;
400                         while(totelem--) {
401                                 BLI_addtail(lb, tp->te);
402                                 tp++;
403                         }
404                         MEM_freeN(tear);
405                 }
406         }
407         
408         for(te= lb->first; te; te= te->next) {
409                 outliner_sort(soops, &te->subtree);
410         }
411 }
412
413 /* Prototype, see functions below */
414 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 
415                                                                                  TreeElement *parent, short type, short index);
416
417
418 static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
419 {
420         TreeStoreElem *tselem= TREESTORE(tenla);
421         TreeElement *te;
422         
423         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_COMBINED);
424         te->name= "Combined";
425         te->directdata= &srl->passflag;
426         
427         /* save cpu cycles, but we add the first to invoke an open/close triangle */
428         if(tselem->flag & TSE_CLOSED)
429                 return;
430         
431         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_Z);
432         te->name= "Z";
433         te->directdata= &srl->passflag;
434         
435         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_VECTOR);
436         te->name= "Vector";
437         te->directdata= &srl->passflag;
438         
439         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_NORMAL);
440         te->name= "Normal";
441         te->directdata= &srl->passflag;
442         
443         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_UV);
444         te->name= "UV";
445         te->directdata= &srl->passflag;
446         
447         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_MIST);
448         te->name= "Mist";
449         te->directdata= &srl->passflag;
450         
451         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_INDEXOB);
452         te->name= "Index Object";
453         te->directdata= &srl->passflag;
454         
455         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RGBA);
456         te->name= "Color";
457         te->directdata= &srl->passflag;
458         
459         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_DIFFUSE);
460         te->name= "Diffuse";
461         te->directdata= &srl->passflag;
462         
463         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SPEC);
464         te->name= "Specular";
465         te->directdata= &srl->passflag;
466         
467         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SHADOW);
468         te->name= "Shadow";
469         te->directdata= &srl->passflag;
470         
471         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_AO);
472         te->name= "AO";
473         te->directdata= &srl->passflag;
474         
475         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFLECT);
476         te->name= "Reflection";
477         te->directdata= &srl->passflag;
478         
479         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFRACT);
480         te->name= "Refraction";
481         te->directdata= &srl->passflag;
482         
483         te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RADIO);
484         te->name= "Radiosity";
485         te->directdata= &srl->passflag;
486         
487 }
488
489
490 /* special handling of hierarchical non-lib data */
491 static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone, 
492                                                           TreeElement *parent, int *a)
493 {
494         TreeElement *te= outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
495         
496         (*a)++;
497         te->name= curBone->name;
498         te->directdata= curBone;
499         
500         for(curBone= curBone->childbase.first; curBone; curBone=curBone->next) {
501                 outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
502         }
503 }
504
505 static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
506 {
507         SceneRenderLayer *srl;
508         TreeElement *tenla= outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
509         int a;
510         
511         tenla->name= "RenderLayers";
512         for(a=0, srl= sce->r.layers.first; srl; srl= srl->next, a++) {
513                 TreeElement *tenlay= outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
514                 tenlay->name= srl->name;
515                 tenlay->directdata= &srl->passflag;
516                 
517                 if(srl->light_override)
518                         outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
519                 if(srl->mat_override)
520                         outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
521                 
522                 outliner_add_passes(soops, tenlay, &sce->id, srl);
523         }
524         
525         outliner_add_element(soops,  lb, sce->world, te, 0, 0);
526         
527         if(sce->scriptlink.scripts) {
528                 int a= 0;
529                 tenla= outliner_add_element(soops,  lb, sce, te, TSE_SCRIPT_BASE, 0);
530                 tenla->name= "Scripts";
531                 for (a=0; a<sce->scriptlink.totscript; a++) {
532                         outliner_add_element(soops, &tenla->subtree, sce->scriptlink.scripts[a], tenla, 0, 0);
533                 }
534         }
535
536 }
537
538 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 
539                                                                                  TreeElement *parent, short type, short index)
540 {
541         TreeElement *te;
542         TreeStoreElem *tselem;
543         ID *id= idv;
544         int a;
545         
546         if(id==NULL) return NULL;
547
548         te= MEM_callocN(sizeof(TreeElement), "tree elem");
549         /* add to the visual tree */
550         BLI_addtail(lb, te);
551         /* add to the storage */
552         check_persistant(soops, te, id, type, index);
553         tselem= TREESTORE(te);  
554         
555         te->parent= parent;
556         te->index= index;       // for data arays
557         te->name= id->name+2; // default, can be overridden by Library or non-ID data
558         te->idcode= GS(id->name);
559         
560         if(type==0) {
561
562                 /* tuck pointer back in object, to construct hierarchy */
563                 if(GS(id->name)==ID_OB) id->newid= (ID *)te;
564                 
565                 /* expand specific data always */
566                 switch(GS(id->name)) {
567                 case ID_LI:
568                         te->name= ((Library *)id)->name;
569                         break;
570                 case ID_SCE:
571                         outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
572                         break;
573                 case ID_OB:
574                         {
575                                 Object *ob= (Object *)id;
576                                 
577                                 if(ob->proxy && ob->id.lib==NULL)
578                                         outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
579                                 
580                                 outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
581                                 
582                                 if(ob->pose) {
583                                         bPoseChannel *pchan;
584                                         TreeElement *ten;
585                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
586                                         
587                                         tenla->name= "Pose";
588                                         
589                                         if(ob!=G.obedit && (ob->flag & OB_POSEMODE)) {  // channels undefined in editmode, but we want the 'tenla' pose icon itself
590                                                 int a= 0, const_index= 1000;    /* ensure unique id for bone constraints */
591                                                 
592                                                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
593                                                         ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
594                                                         ten->name= pchan->name;
595                                                         ten->directdata= pchan;
596                                                         pchan->prev= (bPoseChannel *)ten;
597                                                         
598                                                         if(pchan->constraints.first) {
599                                                                 //Object *target;
600                                                                 bConstraint *con;
601                                                                 TreeElement *ten1;
602                                                                 TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
603                                                                 //char *str;
604                                                                 
605                                                                 tenla1->name= "Constraints";
606                                                                 for(con= pchan->constraints.first; con; con= con->next, const_index++) {
607                                                                         ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
608 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
609                                                                         target= get_constraint_target(con, &str);
610                                                                         if(str && str[0]) ten1->name= str;
611                                                                         else if(target) ten1->name= target->id.name+2;
612                                                                         else ten1->name= con->name;
613 #endif
614                                                                         ten1->name= con->name;
615                                                                         ten1->directdata= con;
616                                                                         /* possible add all other types links? */
617                                                                 }
618                                                         }
619                                                 }
620                                                 /* make hierarchy */
621                                                 ten= tenla->subtree.first;
622                                                 while(ten) {
623                                                         TreeElement *nten= ten->next, *par;
624                                                         tselem= TREESTORE(ten);
625                                                         if(tselem->type==TSE_POSE_CHANNEL) {
626                                                                 pchan= (bPoseChannel *)ten->directdata;
627                                                                 if(pchan->parent) {
628                                                                         BLI_remlink(&tenla->subtree, ten);
629                                                                         par= (TreeElement *)pchan->parent->prev;
630                                                                         BLI_addtail(&par->subtree, ten);
631                                                                         ten->parent= par;
632                                                                 }
633                                                         }
634                                                         ten= nten;
635                                                 }
636                                                 /* restore prev pointers */
637                                                 pchan= ob->pose->chanbase.first;
638                                                 if(pchan) pchan->prev= NULL;
639                                                 for(; pchan; pchan= pchan->next) {
640                                                         if(pchan->next) pchan->next->prev= pchan;
641                                                 }
642                                         }
643                                 }
644                                 
645                                 outliner_add_element(soops, &te->subtree, ob->ipo, te, 0, 0);
646                                 outliner_add_element(soops, &te->subtree, ob->action, te, 0, 0);
647                                 
648                                 for(a=0; a<ob->totcol; a++) 
649                                         outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
650                                 
651                                 if(ob->constraints.first) {
652                                         //Object *target;
653                                         bConstraint *con;
654                                         TreeElement *ten;
655                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
656                                         int a= 0;
657                                         //char *str;
658                                         
659                                         tenla->name= "Constraints";
660                                         for(con= ob->constraints.first; con; con= con->next, a++) {
661                                                 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
662 #if 0 /* disabled due to constraints system targets recode... code here needs review */
663                                                 target= get_constraint_target(con, &str);
664                                                 if(str && str[0]) ten->name= str;
665                                                 else if(target) ten->name= target->id.name+2;
666                                                 else ten->name= con->name;
667 #endif
668                                                 ten->name= con->name;
669                                                 ten->directdata= con;
670                                                 /* possible add all other types links? */
671                                         }
672                                 }
673                                 
674                                 if(ob->modifiers.first) {
675                                         ModifierData *md;
676                                         TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
677                                         int index;
678
679                                         temod->name = "Modifiers";
680                                         for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
681                                                 TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
682                                                 te->name= md->name;
683
684                                                 if (md->type==eModifierType_Lattice) {
685                                                         outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
686                                                 } else if (md->type==eModifierType_Curve) {
687                                                         outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0);
688                                                 } else if (md->type==eModifierType_Armature) {
689                                                         outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0);
690                                                 } else if (md->type==eModifierType_Hook) {
691                                                         outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0);
692                                                 }
693                                         }
694                                 }
695                                 if(ob->defbase.first) {
696                                         bDeformGroup *defgroup;
697                                         TreeElement *ten;
698                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
699                                         int a= 0;
700                                         
701                                         tenla->name= "Vertex Groups";
702                                         for (defgroup=ob->defbase.first; defgroup; defgroup=defgroup->next, a++) {
703                                                 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
704                                                 ten->name= defgroup->name;
705                                                 ten->directdata= defgroup;
706                                         }
707                                 }
708                                 if(ob->scriptlink.scripts) {
709                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_SCRIPT_BASE, 0);
710                                         int a= 0;
711                                         
712                                         tenla->name= "Scripts";
713                                         for (a=0; a<ob->scriptlink.totscript; a++) {                                                    /*  ** */
714                                                 outliner_add_element(soops, &tenla->subtree, ob->scriptlink.scripts[a], te, 0, 0);
715                                         }
716                                 }
717                                 
718                                 if(ob->dup_group)
719                                         outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
720
721                                 if(ob->nlastrips.first) {
722                                         bActionStrip *strip;
723                                         TreeElement *ten;
724                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_NLA, 0);
725                                         int a= 0;
726                                         
727                                         tenla->name= "NLA strips";
728                                         for (strip=ob->nlastrips.first; strip; strip=strip->next, a++) {
729                                                 ten= outliner_add_element(soops, &tenla->subtree, strip->act, tenla, TSE_NLA_ACTION, a);
730                                                 if(ten) ten->directdata= strip;
731                                         }
732                                 }
733                                 
734                         }
735                         break;
736                 case ID_ME:
737                         {
738                                 Mesh *me= (Mesh *)id;
739                                 outliner_add_element(soops, &te->subtree, me->ipo, te, 0, 0);
740                                 outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
741                                 for(a=0; a<me->totcol; a++) 
742                                         outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
743                                 /* could do tfaces with image links, but the images are not grouped nicely.
744                                    would require going over all tfaces, sort images in use. etc... */
745                         }
746                         break;
747                 case ID_CU:
748                         {
749                                 Curve *cu= (Curve *)id;
750                                 for(a=0; a<cu->totcol; a++) 
751                                         outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
752                         }
753                         break;
754                 case ID_MB:
755                         {
756                                 MetaBall *mb= (MetaBall *)id;
757                                 for(a=0; a<mb->totcol; a++) 
758                                         outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
759                         }
760                         break;
761                 case ID_MA:
762                 {
763                         Material *ma= (Material *)id;
764                         
765                         outliner_add_element(soops, &te->subtree, ma->ipo, te, 0, 0);
766                         for(a=0; a<MAX_MTEX; a++) {
767                                 if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
768                         }
769                 }
770                         break;
771                 case ID_TE:
772                         {
773                                 Tex *tex= (Tex *)id;
774                                 
775                                 outliner_add_element(soops, &te->subtree, tex->ipo, te, 0, 0);
776                                 outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
777                         }
778                         break;
779                 case ID_CA:
780                         {
781                                 Camera *ca= (Camera *)id;
782                                 outliner_add_element(soops, &te->subtree, ca->ipo, te, 0, 0);
783                         }
784                         break;
785                 case ID_LA:
786                         {
787                                 Lamp *la= (Lamp *)id;
788                                 outliner_add_element(soops, &te->subtree, la->ipo, te, 0, 0);
789                                 for(a=0; a<MAX_MTEX; a++) {
790                                         if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
791                                 }
792                         }
793                         break;
794                 case ID_WO:
795                         {
796                                 World *wrld= (World *)id;
797                                 outliner_add_element(soops, &te->subtree, wrld->ipo, te, 0, 0);
798                                 for(a=0; a<MAX_MTEX; a++) {
799                                         if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
800                                 }
801                         }
802                         break;
803                 case ID_KE:
804                         {
805                                 Key *key= (Key *)id;
806                                 outliner_add_element(soops, &te->subtree, key->ipo, te, 0, 0);
807                         }
808                         break;
809                 case ID_IP:
810                         {
811                                 Ipo *ipo= (Ipo *)id;
812                                 IpoCurve *icu;
813                                 Object *lastadded= NULL;
814                                 
815                                 for(icu= ipo->curve.first; icu; icu= icu->next) {
816                                         if(icu->driver && icu->driver->ob) {
817                                                 if(lastadded!=icu->driver->ob) {
818                                                         outliner_add_element(soops, &te->subtree, icu->driver->ob, te, TSE_LINKED_OB, 0);
819                                                         lastadded= icu->driver->ob;
820                                                 }
821                                         }
822                                 }
823                         }
824                 case ID_AC:
825                         {
826                                 bAction *act= (bAction *)id;
827                                 bActionChannel *chan;
828                                 int a= 0;
829                                 
830                                 tselem= TREESTORE(parent);
831                                 for (chan=act->chanbase.first; chan; chan=chan->next, a++) {
832                                         outliner_add_element(soops, &te->subtree, chan->ipo, te, 0, a);
833                                 }
834                         }
835                         break;
836                 case ID_AR:
837                         {
838                                 bArmature *arm= (bArmature *)id;
839                                 int a= 0;
840                                 
841                                 if(G.obedit && G.obedit->data==arm) {
842                                         EditBone *ebone;
843                                         TreeElement *ten;
844                                         
845                                         for (ebone = G.edbo.first; ebone; ebone=ebone->next, a++) {
846                                                 ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
847                                                 ten->directdata= ebone;
848                                                 ten->name= ebone->name;
849                                                 ebone->temp= ten;
850                                         }
851                                         /* make hierarchy */
852                                         ten= te->subtree.first;
853                                         while(ten) {
854                                                 TreeElement *nten= ten->next, *par;
855                                                 ebone= (EditBone *)ten->directdata;
856                                                 if(ebone->parent) {
857                                                         BLI_remlink(&te->subtree, ten);
858                                                         par= ebone->parent->temp;
859                                                         BLI_addtail(&par->subtree, ten);
860                                                         ten->parent= par;
861                                                 }
862                                                 ten= nten;
863                                         }
864                                 }
865                                 else {
866                                         /* do not extend Armature when we have posemode */
867                                         tselem= TREESTORE(te->parent);
868                                         if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->flag & OB_POSEMODE);
869                                         else {
870                                                 Bone *curBone;
871                                                 for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
872                                                         outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
873                                                 }
874                                         }
875                                 }
876                         }
877                         break;
878                 }
879         }
880 #ifdef WITH_VERSE
881         else if(type==ID_VS) {
882                 struct VerseSession *session = (VerseSession*)idv;
883                 te->name = session->address;
884                 te->directdata = (void*)session;
885                 te->idcode = ID_VS;
886         }
887         else if(type==ID_MS) {
888                 te->name = "Available Verse Servers";
889                 te->idcode = ID_MS;
890         }
891         else if(type==ID_SS) {
892                 struct VerseServer *server = (VerseServer *)idv;
893                 te->name = server->name;
894                 te->directdata = (void *)server;
895                 te->idcode = ID_SS;
896         }
897         else if(type==ID_VN) {
898                 struct VNode *vnode = (VNode*)idv;
899                 te->name = vnode->name;
900                 te->idcode = ID_VN;
901                 if(vnode->type==V_NT_OBJECT) {
902                         struct TreeElement *ten;
903                         struct VNode *child_node;
904                         struct VLink *vlink;
905                         
906                         vlink = ((VObjectData*)vnode->data)->links.lb.first;
907                         while(vlink) {
908                                 child_node = vlink->target;
909                                 if(child_node && child_node->type==V_NT_GEOMETRY) {
910                                         ten = outliner_add_element(soops, &te->subtree, child_node, te, ID_VN, 0);
911                                         ten->directdata = child_node;
912                                 }
913                                 vlink = vlink->next;
914                         }
915                 }
916         }
917 #endif
918         return te;
919 }
920
921 static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb)
922 {
923         TreeElement *te, *ten, *tep;
924         TreeStoreElem *tselem;
925
926         /* build hierarchy */
927         te= lb->first;
928         while(te) {
929                 ten= te->next;
930                 tselem= TREESTORE(te);
931                 
932                 if(tselem->type==0 && te->idcode==ID_OB) {
933                         Object *ob= (Object *)tselem->id;
934                         if(ob->parent && ob->parent->id.newid) {
935                                 BLI_remlink(lb, te);
936                                 tep= (TreeElement *)ob->parent->id.newid;
937                                 BLI_addtail(&tep->subtree, te);
938                                 // set correct parent pointers
939                                 for(te=tep->subtree.first; te; te= te->next) te->parent= tep;
940                         }
941                 }
942                 te= ten;
943         }
944 }
945
946 static void outliner_build_tree(SpaceOops *soops)
947 {
948         Base *base;
949         Object *ob;
950         TreeElement *te, *ten;
951         TreeStoreElem *tselem;
952         int show_opened= soops->treestore==NULL; /* on first view, we open scenes */
953 #ifdef WITH_VERSE
954         struct VerseSession *session;
955 #endif
956
957         if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
958            return;
959            
960         outliner_free_tree(&soops->tree);
961         outliner_storage_cleanup(soops);
962                                                    
963         /* clear ob id.new flags */
964         for(ob= G.main->object.first; ob; ob= ob->id.next) ob->id.newid= NULL;
965         
966         /* options */
967         if(soops->outlinevis == SO_LIBRARIES) {
968                 Library *lib;
969                 
970                 for(lib= G.main->library.first; lib; lib= lib->id.next) {
971                         ten= outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
972                         lib->id.newid= (ID *)ten;
973                 }
974                 /* make hierarchy */
975                 ten= soops->tree.first;
976                 while(ten) {
977                         TreeElement *nten= ten->next, *par;
978                         tselem= TREESTORE(ten);
979                         lib= (Library *)tselem->id;
980                         if(lib->parent) {
981                                 BLI_remlink(&soops->tree, ten);
982                                 par= (TreeElement *)lib->parent->id.newid;
983                                 BLI_addtail(&par->subtree, ten);
984                                 ten->parent= par;
985                         }
986                         ten= nten;
987                 }
988                 /* restore newid pointers */
989                 for(lib= G.main->library.first; lib; lib= lib->id.next)
990                         lib->id.newid= NULL;
991                 
992         }
993         else if(soops->outlinevis == SO_ALL_SCENES) {
994                 Scene *sce;
995                 for(sce= G.main->scene.first; sce; sce= sce->id.next) {
996                         te= outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
997                         tselem= TREESTORE(te);
998                         if(sce==G.scene && show_opened) 
999                                 tselem->flag &= ~TSE_CLOSED;
1000                         
1001                         for(base= sce->base.first; base; base= base->next) {
1002                                 ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
1003                                 ten->directdata= base;
1004                         }
1005                         outliner_make_hierarchy(soops, &te->subtree);
1006                         /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1007                         for(base= sce->base.first; base; base= base->next) base->object->id.newid= NULL;
1008                 }
1009         }
1010         else if(soops->outlinevis == SO_CUR_SCENE) {
1011                 
1012                 outliner_add_scene_contents(soops, &soops->tree, G.scene, NULL);
1013                 
1014                 for(base= G.scene->base.first; base; base= base->next) {
1015                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1016                         ten->directdata= base;
1017                 }
1018                 outliner_make_hierarchy(soops, &soops->tree);
1019         }
1020         else if(soops->outlinevis == SO_VISIBLE) {
1021                 for(base= G.scene->base.first; base; base= base->next) {
1022                         if(base->lay & G.scene->lay)
1023                                 outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1024                 }
1025                 outliner_make_hierarchy(soops, &soops->tree);
1026         }
1027         else if(soops->outlinevis == SO_GROUPS) {
1028                 Group *group;
1029                 GroupObject *go;
1030                 
1031                 for(group= G.main->group.first; group; group= group->id.next) {
1032                         if(group->id.us) {
1033                                 te= outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
1034                                 tselem= TREESTORE(te);
1035                                 
1036                                 for(go= group->gobject.first; go; go= go->next) {
1037                                         ten= outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
1038                                         ten->directdata= NULL; /* eh, why? */
1039                                 }
1040                                 outliner_make_hierarchy(soops, &te->subtree);
1041                                 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1042                                 for(go= group->gobject.first; go; go= go->next) go->ob->id.newid= NULL;
1043                         }
1044                 }
1045         }
1046         else if(soops->outlinevis == SO_SAME_TYPE) {
1047                 Object *ob= OBACT;
1048                 if(ob) {
1049                         for(base= G.scene->base.first; base; base= base->next) {
1050                                 if(base->object->type==ob->type) {
1051                                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1052                                         ten->directdata= base;
1053                                 }
1054                         }
1055                         outliner_make_hierarchy(soops, &soops->tree);
1056                 }
1057         }
1058         else if(soops->outlinevis == SO_SELECTED) {
1059                 for(base= G.scene->base.first; base; base= base->next) {
1060                         if(base->lay & G.scene->lay) {
1061                                 if(base==BASACT || (base->flag & SELECT)) {
1062                                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1063                                         ten->directdata= base;
1064                                 }
1065                         }
1066                 }
1067                 outliner_make_hierarchy(soops, &soops->tree);
1068         }
1069 #ifdef WITH_VERSE
1070         else if(soops->outlinevis == SO_VERSE_SESSION) {
1071                 /* add all session to the "root" of hierarchy */
1072                 for(session=session_list.first; session; session = session->next) {
1073                         struct VNode *vnode;
1074                         if(session->flag & VERSE_CONNECTED) {
1075                                 te= outliner_add_element(soops, &soops->tree, session, NULL, ID_VS, 0);
1076                                 /* add all object nodes as childreen of session */
1077                                 for(vnode=session->nodes.lb.first; vnode; vnode=vnode->next) {
1078                                         if(vnode->type==V_NT_OBJECT) {
1079                                                 ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
1080                                                 ten->directdata= vnode;
1081                                         }
1082                                         else if(vnode->type==V_NT_BITMAP) {
1083                                                 ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
1084                                                 ten->directdata= vnode;
1085                                         }
1086                                 }
1087                         }
1088                 }
1089         }
1090         else if(soops->outlinevis == SO_VERSE_MS) {
1091                 te= outliner_add_element(soops, &soops->tree, "MS", NULL, ID_MS, 0);
1092                 if(server_list.first!=NULL) {
1093                         struct VerseServer *server;
1094                         /* add one main entry to root of hierarchy */
1095                         for(server=server_list.first; server; server=server->next) {
1096                                 ten= outliner_add_element(soops, &te->subtree, server, te, ID_SS, 0);
1097                                 ten->directdata= server;
1098                         }
1099                 }
1100         }
1101 #endif
1102         else {
1103                 ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
1104                 if(ten) ten->directdata= BASACT;
1105         }
1106
1107
1108         outliner_sort(soops, &soops->tree);
1109 }
1110
1111 /* **************** INTERACTIVE ************* */
1112
1113 static int outliner_count_levels(SpaceOops *soops, ListBase *lb, int curlevel)
1114 {
1115         TreeElement *te;
1116         int level=curlevel, lev;
1117         
1118         for(te= lb->first; te; te= te->next) {
1119                 
1120                 lev= outliner_count_levels(soops, &te->subtree, curlevel+1);
1121                 if(lev>level) level= lev;
1122         }
1123         return level;
1124 }
1125
1126 static int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel)
1127 {
1128         TreeElement *te;
1129         TreeStoreElem *tselem;
1130         int level;
1131         
1132         for(te= lb->first; te; te= te->next) {
1133                 tselem= TREESTORE(te);
1134                 if(tselem->flag & flag) return curlevel;
1135                 
1136                 level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1);
1137                 if(level) return level;
1138         }
1139         return 0;
1140 }
1141
1142 static void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
1143 {
1144         TreeElement *te;
1145         TreeStoreElem *tselem;
1146         
1147         for(te= lb->first; te; te= te->next) {
1148                 tselem= TREESTORE(te);
1149                 if(set==0) tselem->flag &= ~flag;
1150                 else tselem->flag |= flag;
1151                 outliner_set_flag(soops, &te->subtree, flag, set);
1152         }
1153 }
1154
1155 void outliner_toggle_visible(struct ScrArea *sa)
1156 {
1157         SpaceOops *soops= sa->spacedata.first;
1158         
1159         if( outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
1160                 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
1161         else 
1162                 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
1163
1164         BIF_undo_push("Outliner toggle visible");
1165         scrarea_queue_redraw(sa);
1166 }
1167
1168 void outliner_toggle_selected(struct ScrArea *sa)
1169 {
1170         SpaceOops *soops= sa->spacedata.first;
1171         
1172         if( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
1173                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
1174         else 
1175                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
1176         
1177         BIF_undo_push("Outliner toggle selected");
1178         soops->storeflag |= SO_TREESTORE_REDRAW;
1179         scrarea_queue_redraw(sa);
1180 }
1181
1182
1183 static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
1184 {
1185         TreeElement *te;
1186         TreeStoreElem *tselem;
1187         
1188         for(te= lb->first; te; te= te->next) {
1189                 tselem= TREESTORE(te);
1190                 
1191                 if(open) {
1192                         if(curlevel<=level) tselem->flag &= ~TSE_CLOSED;
1193                 }
1194                 else {
1195                         if(curlevel>=level) tselem->flag |= TSE_CLOSED;
1196                 }
1197                 
1198                 outliner_openclose_level(soops, &te->subtree, curlevel+1, level, open);
1199         }
1200 }
1201
1202 /* return 1 when levels were opened */
1203 static int outliner_open_back(SpaceOops *soops, TreeElement *te)
1204 {
1205         TreeStoreElem *tselem;
1206         int retval= 0;
1207         
1208         for (te= te->parent; te; te= te->parent) {
1209                 tselem= TREESTORE(te);
1210                 if (tselem->flag & TSE_CLOSED) { 
1211                         tselem->flag &= ~TSE_CLOSED;
1212                         retval= 1;
1213                 }
1214         }
1215         return retval;
1216 }
1217
1218 static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
1219 {
1220         TreeElement *te;
1221         TreeStoreElem *tselem;
1222         
1223         for (te= lb->first; te; te= te->next) {
1224                 /* check if this tree-element was the one we're seeking */
1225                 if (te == teFind) {
1226                         *found= 1;
1227                         return;
1228                 }
1229                 
1230                 /* try to see if sub-tree contains it then */
1231                 outliner_open_reveal(soops, &te->subtree, teFind, found);
1232                 if (*found) {
1233                         tselem= TREESTORE(te);
1234                         if (tselem->flag & TSE_CLOSED) 
1235                                 tselem->flag &= ~TSE_CLOSED;
1236                         return;
1237                 }
1238         }
1239 }
1240
1241
1242 void outliner_one_level(struct ScrArea *sa, int add)
1243 {
1244         SpaceOops *soops= sa->spacedata.first;
1245         int level;
1246         
1247         level= outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
1248         if(add==1) {
1249                 if(level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
1250         }
1251         else {
1252                 if(level==0) level= outliner_count_levels(soops, &soops->tree, 0);
1253                 if(level) outliner_openclose_level(soops, &soops->tree, 1, level-1, 0);
1254         }
1255         
1256         BIF_undo_push("Outliner show/hide one level");
1257         scrarea_queue_redraw(sa);
1258 }
1259
1260 void outliner_page_up_down(ScrArea *sa, int up)
1261 {
1262         SpaceOops *soops= sa->spacedata.first;
1263         int dy= soops->v2d.mask.ymax-soops->v2d.mask.ymin;
1264         
1265         if(up == -1) dy= -dy;
1266         soops->v2d.cur.ymin+= dy;
1267         soops->v2d.cur.ymax+= dy;
1268         
1269         soops->storeflag |= SO_TREESTORE_REDRAW;
1270         scrarea_queue_redraw(sa);
1271 }
1272
1273 /* **** do clicks on items ******* */
1274
1275 static int tree_element_active_renderlayer(TreeElement *te, TreeStoreElem *tselem, int set)
1276 {
1277         Scene *sce;
1278         
1279         /* paranoia check */
1280         if(te->idcode!=ID_SCE)
1281                 return 0;
1282         sce= (Scene *)tselem->id;
1283         
1284         if(set) {
1285                 sce->r.actlay= tselem->nr;
1286                 allqueue(REDRAWBUTSSCENE, 0);
1287         }
1288         else {
1289                 return sce->r.actlay==tselem->nr;
1290         }
1291         return 0;
1292 }
1293
1294 static void tree_element_active_object(SpaceOops *soops, TreeElement *te)
1295 {
1296         TreeStoreElem *tselem= TREESTORE(te);
1297         Scene *sce;
1298         Base *base;
1299         Object *ob= NULL;
1300         
1301         /* if id is not object, we search back */
1302         if(te->idcode==ID_OB) ob= (Object *)tselem->id;
1303         else {
1304                 ob= (Object *)outliner_search_back(soops, te, ID_OB);
1305                 if(ob==OBACT) return;
1306         }
1307         if(ob==NULL) return;
1308         
1309         sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
1310         if(sce && G.scene != sce) {
1311                 if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1312                 set_scene(sce);
1313         }
1314         
1315         /* find associated base in current scene */
1316         for(base= FIRSTBASE; base; base= base->next) 
1317                 if(base->object==ob) break;
1318         if(base) {
1319                 if(G.qual & LR_SHIFTKEY) {
1320                         /* swap select */
1321                         if(base->flag & SELECT) base->flag &= ~SELECT;
1322                         else if ((base->object->restrictflag & OB_RESTRICT_VIEW)==0) base->flag |= SELECT;
1323                         base->object->flag= base->flag;
1324                 }
1325                 else {
1326                         Base *b;
1327                         /* deleselect all */
1328                         for(b= FIRSTBASE; b; b= b->next) {
1329                                 b->flag &= ~SELECT;
1330                                 b->object->flag= b->flag;
1331                         }
1332                         if ((base->object->restrictflag & OB_RESTRICT_VIEW)==0) {
1333                                 base->flag |= SELECT;
1334                                 base->object->flag |= SELECT;
1335                         }
1336                 }
1337                 set_active_base(base);  /* editview.c */
1338                 
1339                 allqueue(REDRAWVIEW3D, 1);
1340                 allqueue(REDRAWOOPS, 0);
1341                 allqueue(REDRAWINFO, 1);
1342         }
1343         
1344         if(ob!=G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1345 }
1346
1347 static int tree_element_active_material(SpaceOops *soops, TreeElement *te, int set)
1348 {
1349         TreeElement *tes;
1350         Object *ob;
1351         
1352         /* we search for the object parent */
1353         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1354         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1355         
1356         /* searching in ob mat array? */
1357         tes= te->parent;
1358         if(tes->idcode==ID_OB) {
1359                 if(set) {
1360                         ob->actcol= te->index+1;
1361                         ob->colbits |= (1<<te->index);  // make ob material active too
1362                 }
1363                 else {
1364                         if(ob->actcol == te->index+1) 
1365                                 if(ob->colbits & (1<<te->index)) return 1;
1366                 }
1367         }
1368         /* or we search for obdata material */
1369         else {
1370                 if(set) {
1371                         ob->actcol= te->index+1;
1372                         ob->colbits &= ~(1<<te->index); // make obdata material active too
1373                 }
1374                 else {
1375                         if(ob->actcol == te->index+1)
1376                                 if( (ob->colbits & (1<<te->index))==0 ) return 1;
1377                 }
1378         }
1379         if(set) {
1380                 extern_set_butspace(F5KEY, 0);  // force shading buttons
1381                 BIF_preview_changed(ID_MA);
1382                 allqueue(REDRAWBUTSSHADING, 1);
1383                 allqueue(REDRAWNODE, 0);
1384                 allqueue(REDRAWOOPS, 0);
1385                 allqueue(REDRAWIPO, 0);
1386         }
1387         return 0;
1388 }
1389
1390 static int tree_element_active_texture(SpaceOops *soops, TreeElement *te, int set)
1391 {
1392         TreeElement *tep;
1393         TreeStoreElem *tselem, *tselemp;
1394         Object *ob=OBACT;
1395         ScrArea *sa;
1396         SpaceButs *sbuts=NULL;
1397         
1398         if(ob==NULL) return 0; // no active object
1399         
1400         tselem= TREESTORE(te);
1401         
1402         /* find buttons area (note, this is undefined really still, needs recode in blender) */
1403         sa= G.curscreen->areabase.first;
1404         while(sa) {
1405                 if(sa->spacetype==SPACE_BUTS) break;
1406                 sa= sa->next;
1407         }
1408         if(sa) sbuts= sa->spacedata.first;
1409         
1410         /* where is texture linked to? */
1411         tep= te->parent;
1412         tselemp= TREESTORE(tep);
1413         
1414         if(tep->idcode==ID_WO) {
1415                 World *wrld= (World *)tselemp->id;
1416
1417                 if(set) {
1418                         if(sbuts) {
1419                                 sbuts->tabo= TAB_SHADING_TEX;   // hack from header_buttonswin.c
1420                                 sbuts->texfrom= 1;
1421                         }
1422                         extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1423                         wrld->texact= te->index;
1424                 }
1425                 else if(tselemp->id == (ID *)(G.scene->world)) {
1426                         if(wrld->texact==te->index) return 1;
1427                 }
1428         }
1429         else if(tep->idcode==ID_LA) {
1430                 Lamp *la= (Lamp *)tselemp->id;
1431                 if(set) {
1432                         if(sbuts) {
1433                                 sbuts->tabo= TAB_SHADING_TEX;   // hack from header_buttonswin.c
1434                                 sbuts->texfrom= 2;
1435                         }
1436                         extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1437                         la->texact= te->index;
1438                 }
1439                 else {
1440                         if(tselemp->id == ob->data) {
1441                                 if(la->texact==te->index) return 1;
1442                         }
1443                 }
1444         }
1445         else if(tep->idcode==ID_MA) {
1446                 Material *ma= (Material *)tselemp->id;
1447                 if(set) {
1448                         if(sbuts) {
1449                                 //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
1450                                 sbuts->texfrom= 0;
1451                         }
1452                         extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1453                         ma->texact= te->index;
1454                         
1455                         /* also set active material */
1456                         ob->actcol= tep->index+1;
1457                 }
1458                 else if(tep->flag & TE_ACTIVE) {        // this is active material
1459                         if(ma->texact==te->index) return 1;
1460                 }
1461         }
1462         
1463         return 0;
1464 }
1465
1466
1467 static int tree_element_active_lamp(SpaceOops *soops, TreeElement *te, int set)
1468 {
1469         Object *ob;
1470         
1471         /* we search for the object parent */
1472         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1473         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1474         
1475         if(set) {
1476                 extern_set_butspace(F5KEY, 0);
1477                 BIF_preview_changed(ID_LA);
1478                 allqueue(REDRAWBUTSSHADING, 1);
1479                 allqueue(REDRAWOOPS, 0);
1480                 allqueue(REDRAWIPO, 0);
1481         }
1482         else return 1;
1483         
1484         return 0;
1485 }
1486
1487 static int tree_element_active_world(SpaceOops *soops, TreeElement *te, int set)
1488 {
1489         TreeElement *tep;
1490         TreeStoreElem *tselem=NULL;
1491         Scene *sce=NULL;
1492         
1493         tep= te->parent;
1494         if(tep) {
1495                 tselem= TREESTORE(tep);
1496                 sce= (Scene *)tselem->id;
1497         }
1498         
1499         if(set) {       // make new scene active
1500                 if(sce && G.scene != sce) {
1501                         if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1502                         set_scene(sce);
1503                 }
1504         }
1505         
1506         if(tep==NULL || tselem->id == (ID *)G.scene) {
1507                 if(set) {
1508                         extern_set_butspace(F8KEY, 0);
1509                 }
1510                 else {
1511                         return 1;
1512                 }
1513         }
1514         return 0;
1515 }
1516
1517 static int tree_element_active_ipo(SpaceOops *soops, TreeElement *te, int set)
1518 {
1519         TreeElement *tes;
1520         TreeStoreElem *tselems=NULL;
1521         Object *ob;
1522         
1523         /* we search for the object parent */
1524         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1525         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1526         
1527         /* the parent of ipo */
1528         tes= te->parent;
1529         tselems= TREESTORE(tes);
1530         
1531         if(set) {
1532                 if(tes->idcode==ID_AC) {
1533                         if(ob->ipoflag & OB_ACTION_OB)
1534                                 ob->ipowin= ID_OB;
1535                         else if(ob->ipoflag & OB_ACTION_KEY)
1536                                 ob->ipowin= ID_KE;
1537                         else 
1538                                 ob->ipowin= ID_PO;
1539                 }
1540                 else ob->ipowin= tes->idcode;
1541                 
1542                 if(ob->ipowin==ID_MA) tree_element_active_material(soops, tes, 1);
1543                 else if(ob->ipowin==ID_AC) {
1544                         bActionChannel *chan;
1545                         short a=0;
1546                         for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
1547                                 if(a==te->index) break;
1548                                 if(chan->ipo) a++;
1549                         }
1550                         deselect_actionchannels(ob->action, 0);
1551                         select_channel(ob->action, chan, SELECT_ADD);
1552                         allqueue(REDRAWACTION, ob->ipowin);
1553                         allqueue(REDRAWVIEW3D, ob->ipowin);
1554                 }
1555                 
1556                 allqueue(REDRAWIPO, ob->ipowin);
1557         }
1558         else {
1559                 if(tes->idcode==ID_AC) {
1560                         if(ob->ipoflag & OB_ACTION_OB)
1561                                 return ob->ipowin==ID_OB;
1562                         else if(ob->ipoflag & OB_ACTION_KEY)
1563                                 return ob->ipowin==ID_KE;
1564                         else if(ob->ipowin==ID_AC) {
1565                                 bActionChannel *chan;
1566                                 short a=0;
1567                                 for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
1568                                         if(a==te->index) break;
1569                                         if(chan->ipo) a++;
1570                                 }
1571                                 if(chan==get_hilighted_action_channel(ob->action)) return 1;
1572                         }
1573                 }
1574                 else if(ob->ipowin==tes->idcode) {
1575                         if(ob->ipowin==ID_MA) {
1576                                 Material *ma= give_current_material(ob, ob->actcol);
1577                                 if(ma==(Material *)tselems->id) return 1;
1578                         }
1579                         else return 1;
1580                 }
1581         }
1582         return 0;
1583 }       
1584
1585 static int tree_element_active_defgroup(TreeElement *te, TreeStoreElem *tselem, int set)
1586 {
1587         Object *ob;
1588         
1589         /* id in tselem is object */
1590         ob= (Object *)tselem->id;
1591         if(set) {
1592                 ob->actdef= te->index+1;
1593                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1594                 allqueue(REDRAWVIEW3D, ob->ipowin);
1595         }
1596         else {
1597                 if(ob==OBACT)
1598                         if(ob->actdef== te->index+1) return 1;
1599         }
1600         return 0;
1601 }
1602
1603 static int tree_element_active_nla_action(TreeElement *te, TreeStoreElem *tselem, int set)
1604 {
1605         if(set) {
1606                 bActionStrip *strip= te->directdata;
1607                 if(strip) {
1608                         deselect_nlachannel_keys(0);
1609                         strip->flag |= ACTSTRIP_SELECT;
1610                         allqueue(REDRAWNLA, 0);
1611                 }
1612         }
1613         else {
1614                 /* id in tselem is action */
1615                 bActionStrip *strip= te->directdata;
1616                 if(strip) {
1617                         if(strip->flag & ACTSTRIP_SELECT) return 1;
1618                 }
1619         }
1620         return 0;
1621 }
1622
1623 static int tree_element_active_posechannel(TreeElement *te, TreeStoreElem *tselem, int set)
1624 {
1625         Object *ob= (Object *)tselem->id;
1626         bPoseChannel *pchan= te->directdata;
1627         
1628         if(set) {
1629                 if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
1630                         
1631                         if(G.qual & LR_SHIFTKEY) deselectall_posearmature(ob, 2, 0);    // 2 = clear active tag
1632                         else deselectall_posearmature(ob, 0, 0);        // 0 = deselect 
1633                         pchan->bone->flag |= BONE_SELECTED|BONE_ACTIVE;
1634                         
1635                         allqueue(REDRAWVIEW3D, 0);
1636                         allqueue(REDRAWOOPS, 0);
1637                         allqueue(REDRAWACTION, 0);
1638                 }
1639         }
1640         else {
1641                 if(ob==OBACT && ob->pose) {
1642                         if (pchan->bone->flag & BONE_SELECTED) return 1;
1643                 }
1644         }
1645         return 0;
1646 }
1647
1648 static int tree_element_active_bone(TreeElement *te, TreeStoreElem *tselem, int set)
1649 {
1650         bArmature *arm= (bArmature *)tselem->id;
1651         Bone *bone= te->directdata;
1652         
1653         if(set) {
1654                 if(!(bone->flag & BONE_HIDDEN_P)) {
1655                         if(G.qual & LR_SHIFTKEY) deselectall_posearmature(OBACT, 2, 0); // 2 is clear active tag
1656                         else deselectall_posearmature(OBACT, 0, 0);
1657                         bone->flag |= BONE_SELECTED|BONE_ACTIVE;
1658                         
1659                         allqueue(REDRAWVIEW3D, 0);
1660                         allqueue(REDRAWOOPS, 0);
1661                         allqueue(REDRAWACTION, 0);
1662                 }
1663         }
1664         else {
1665                 Object *ob= OBACT;
1666                 
1667                 if(ob && ob->data==arm) {
1668                         if (bone->flag & BONE_SELECTED) return 1;
1669                 }
1670         }
1671         return 0;
1672 }
1673
1674
1675 /* ebones only draw in editmode armature */
1676 static int tree_element_active_ebone(TreeElement *te, TreeStoreElem *tselem, int set)
1677 {
1678         EditBone *ebone= te->directdata;
1679         
1680         if(set) {
1681                 if(!(ebone->flag & BONE_HIDDEN_A)) {
1682                         
1683                         if(G.qual & LR_SHIFTKEY) deselectall_armature(2, 0);    // only clear active tag
1684                         else deselectall_armature(0, 0);        // deselect
1685
1686                         ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL|BONE_ACTIVE;
1687                         // flush to parent?
1688                         if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
1689                         
1690                         allqueue(REDRAWVIEW3D, 0);
1691                         allqueue(REDRAWOOPS, 0);
1692                         allqueue(REDRAWACTION, 0);
1693                 }
1694         }
1695         else {
1696                 if (ebone->flag & BONE_SELECTED) return 1;
1697         }
1698         return 0;
1699 }
1700
1701 static int tree_element_active_modifier(TreeElement *te, TreeStoreElem *tselem, int set)
1702 {
1703         if(set) {
1704                 extern_set_butspace(F9KEY, 0);
1705         }
1706         
1707         return 0;
1708 }
1709
1710 static int tree_element_active_constraint(TreeElement *te, TreeStoreElem *tselem, int set)
1711 {
1712         if(set) {
1713                 extern_set_butspace(F7KEY, 0);
1714         }
1715         
1716         return 0;
1717 }
1718
1719 static int tree_element_active_text(SpaceOops *soops, TreeElement *te, int set)
1720 {
1721         ScrArea *sa=NULL;
1722         
1723         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1724                 if(sa->spacetype==SPACE_TEXT) break;
1725         }
1726         if(sa) {
1727                 SpaceText *st= sa->spacedata.first;
1728                 TreeStoreElem *tselem= TREESTORE(te);
1729                 
1730                 if(set) {
1731                         st->text= (Text *)tselem->id;
1732                         st->top= 0;
1733                         scrarea_queue_redraw(sa);
1734                 }
1735                 else if(st->text==(Text *)tselem->id) return 1;
1736         }
1737         return 0;
1738 }
1739
1740 /* generic call for ID data check or make/check active in UI */
1741 static int tree_element_active(SpaceOops *soops, TreeElement *te, int set)
1742 {
1743
1744         switch(te->idcode) {
1745                 case ID_MA:
1746                         return tree_element_active_material(soops, te, set);
1747                 case ID_WO:
1748                         return tree_element_active_world(soops, te, set);
1749                 case ID_LA:
1750                         return tree_element_active_lamp(soops, te, set);
1751                 case ID_IP:
1752                         return tree_element_active_ipo(soops, te, set);
1753                 case ID_TE:
1754                         return tree_element_active_texture(soops, te, set);
1755                 case ID_TXT:
1756                         return tree_element_active_text(soops, te, set);
1757         }
1758         return 0;
1759 }
1760
1761 static int tree_element_active_pose(TreeElement *te, TreeStoreElem *tselem, int set)
1762 {
1763         Object *ob= (Object *)tselem->id;
1764         
1765         if(set) {
1766                 if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1767                 if(ob->flag & OB_POSEMODE) exit_posemode();
1768                 else enter_posemode();
1769         }
1770         else {
1771                 if(ob->flag & OB_POSEMODE) return 1;
1772         }
1773         return 0;
1774 }
1775
1776 /* generic call for non-id data to make/check active in UI */
1777 static int tree_element_type_active(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
1778 {
1779         
1780         switch(tselem->type) {
1781                 case TSE_NLA_ACTION:
1782                         return tree_element_active_nla_action(te, tselem, set);
1783                 case TSE_DEFGROUP:
1784                         return tree_element_active_defgroup(te, tselem, set);
1785                 case TSE_BONE:
1786                         return tree_element_active_bone(te, tselem, set);
1787                 case TSE_EBONE:
1788                         return tree_element_active_ebone(te, tselem, set);
1789                 case TSE_MODIFIER:
1790                         return tree_element_active_modifier(te, tselem, set);
1791                 case TSE_LINKED_OB:
1792                         if(set) tree_element_active_object(soops, te);
1793                         else if(tselem->id==(ID *)OBACT) return 1;
1794                         break;
1795                 case TSE_POSE_BASE:
1796                         return tree_element_active_pose(te, tselem, set);
1797                         break;
1798                 case TSE_POSE_CHANNEL:
1799                         return tree_element_active_posechannel(te, tselem, set);
1800                 case TSE_CONSTRAINT:
1801                         return tree_element_active_constraint(te, tselem, set);
1802                 case TSE_R_LAYER:
1803                         return tree_element_active_renderlayer(te, tselem, set);
1804         }
1805         return 0;
1806 }
1807
1808 #ifdef WITH_VERSE
1809 static void verse_operation_menu(TreeElement *te)
1810 {
1811         short event=0;
1812         if(te->idcode==ID_VS) {
1813                 struct VerseSession *session = (VerseSession*)te->directdata;
1814                 struct VNode *vnode;
1815                 if(!(session->flag & VERSE_AUTOSUBSCRIBE)) {
1816                         event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Start Autosubscribe %x3");
1817                 }
1818                 else {
1819                         event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Stop Autosubscribe %x4");
1820                 }
1821                 switch(event) {
1822                         case 1:
1823                                 end_verse_session(session);
1824                                 break;
1825                         case 2:
1826                                 vnode = session->nodes.lb.first;
1827                                 while(vnode) {
1828                                         b_verse_pop_node(vnode);
1829                                         vnode = vnode->next;
1830                                 }
1831                                 break;
1832                         case 3:
1833                                 vnode = session->nodes.lb.first;
1834                                 while(vnode) {
1835                                         b_verse_pop_node(vnode);
1836                                         vnode = vnode->next;
1837                                 }
1838                                 session->flag |= VERSE_AUTOSUBSCRIBE;
1839                                 break;
1840                         case 4:
1841                                 session->flag &= ~VERSE_AUTOSUBSCRIBE;
1842                                 break;
1843                 }
1844         }
1845         else if(te->idcode==ID_VN) {
1846                 struct VNode *vnode = (VNode*)te->directdata;
1847                 event = pupmenu("VerseNode %t| Subscribe %x1| Unsubscribe %x2");
1848                 switch(event) {
1849                         case 1:
1850                                 b_verse_pop_node(vnode);
1851                                 break;
1852                         case 2:
1853                                 /* Global */
1854                                 b_verse_unsubscribe(vnode);
1855                                 break;
1856                 }
1857         }
1858         else if(te->idcode==ID_MS) {
1859                         event = pupmenu("Verse Master Server %t| Refresh %x1");
1860                         b_verse_ms_get();
1861         }
1862         else if(te->idcode==ID_SS) {
1863                 struct VerseServer *vserver = (VerseServer*)te->directdata;
1864
1865                 if(!(vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
1866                         event = pupmenu("VerseServer %t| Connect %x1");
1867                 } else if((vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
1868                         event = pupmenu("VerseServer %t| Connecting %x2");
1869                 } else if(!(vserver->flag & VERSE_CONNECTING) && (vserver->flag & VERSE_CONNECTED)) {
1870                         event = pupmenu("VerseServer %t| Disconnect %x3");
1871                 }
1872                 switch(event) {
1873                         case 1:
1874                                 b_verse_connect(vserver->ip);
1875                                 vserver->flag |= VERSE_CONNECTING;
1876                                 break;
1877                         case 2:
1878                                 break;
1879                         case 3:
1880                                 end_verse_session(vserver->session);
1881                                 break;
1882                 }
1883         }
1884 }
1885 #endif
1886
1887
1888 static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short event, float *mval)
1889 {
1890         
1891         if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
1892                 TreeStoreElem *tselem= TREESTORE(te);
1893                 int openclose= 0;
1894
1895                 /* open close icon, three things to check */
1896                 if(event==RETKEY || event==PADENTER) openclose= 1; // enter opens/closes always
1897                 else if((te->flag & TE_ICONROW)==0) {                           // hidden icon, no open/close
1898                         if( mval[0]>te->xs && mval[0]<te->xs+OL_X) openclose= 1;
1899                 }
1900
1901                 if(openclose) {
1902                         
1903                         /* all below close/open? */
1904                         if( (G.qual & LR_SHIFTKEY) ) {
1905                                 tselem->flag &= ~TSE_CLOSED;
1906                                 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
1907                         }
1908                         else {
1909                                 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
1910                                 else tselem->flag |= TSE_CLOSED;
1911                                 
1912                         }
1913                         
1914                         return 1;
1915                 }
1916                 /* name and first icon */
1917                 else if(mval[0]>te->xs && mval[0]<te->xend) {
1918                         
1919                         /* activate a name button? */
1920                         if(event==LEFTMOUSE) {
1921                         
1922                                 if (G.qual & LR_CTRLKEY) {
1923                                         if(ELEM8(tselem->type, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, TSE_SCRIPT_BASE, TSE_POSE_BASE, TSE_R_LAYER_BASE, TSE_R_PASS)) 
1924                                                 error("Cannot edit builtin name");
1925                                         else if(tselem->id->lib) {
1926                                                 error_libdata();
1927                                         } else if(te->idcode == ID_LI && te->parent) {
1928                                                 error("Cannot edit the path of an indirectly linked library");
1929                                         } else {
1930                                                 tselem->flag |= TSE_TEXTBUT;
1931                                         }
1932                                 } else {
1933                                         
1934                                         if (G.qual & LR_SHIFTKEY) {
1935                                                 if(tselem->id->lib && tselem->type==0) {
1936                                                         notice(tselem->id->lib->name);
1937                                                 }
1938                                         }
1939                                         /* always makes active object */
1940                                         tree_element_active_object(soops, te);
1941                                         
1942                                         if(tselem->type==0) { // the lib blocks
1943                                                 /* editmode? */
1944                                                 if(te->idcode==ID_SCE) {
1945                                                         if(G.scene!=(Scene *)tselem->id) {
1946                                                                 if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1947                                                                 set_scene((Scene *)tselem->id);
1948                                                         }
1949                                                 }
1950                                                 else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
1951                                                         if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1952                                                         else {
1953                                                                 enter_editmode(EM_WAITCURSOR);
1954                                                                 extern_set_butspace(F9KEY, 0);
1955                                                         }
1956                                                 } else {        // rest of types
1957                                                         tree_element_active(soops, te, 1);
1958                                                 }
1959                                                 
1960                                         }
1961                                         else tree_element_type_active(soops, te, tselem, 1);
1962                                 }
1963                         }
1964                         else if(event==RIGHTMOUSE) {
1965 #ifdef WITH_VERSE
1966                                 if(ELEM4(te->idcode, ID_VS, ID_VN, ID_MS, ID_SS))
1967                                         verse_operation_menu(te);
1968                                 else
1969 #endif
1970                                 /* select object that's clicked on and popup context menu */
1971                                 if (!(tselem->flag & TSE_SELECTED)) {
1972                                 
1973                                         if ( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) )
1974                                                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
1975                                 
1976                                         tselem->flag |= TSE_SELECTED;
1977                                         /* redraw, same as outliner_select function */
1978                                         soops->storeflag |= SO_TREESTORE_REDRAW;
1979                                         scrarea_do_windraw(soops->area);
1980                                         screen_swapbuffers();
1981                                 }
1982                                 
1983                                 outliner_operation_menu(soops->area);
1984                         }
1985                         return 1;
1986                 }
1987         }
1988         
1989         for(te= te->subtree.first; te; te= te->next) {
1990                 if(do_outliner_mouse_event(soops, te, event, mval)) return 1;
1991         }
1992         return 0;
1993 }
1994
1995 /* event can enterkey, then it opens/closes */
1996 void outliner_mouse_event(ScrArea *sa, short event)
1997 {
1998         SpaceOops *soops= sa->spacedata.first;
1999         TreeElement *te;
2000         float fmval[2];
2001         short mval[2];
2002         
2003         getmouseco_areawin(mval);
2004         areamouseco_to_ipoco(&soops->v2d, mval, fmval, fmval+1);
2005         
2006         for(te= soops->tree.first; te; te= te->next) {
2007                 if(do_outliner_mouse_event(soops, te, event, fmval)) break;
2008         }
2009         
2010         if(te) {
2011                 BIF_undo_push("Outliner click event");
2012                 allqueue(REDRAWOOPS, 0);
2013         }
2014         else 
2015                 outliner_select(sa);
2016
2017 }
2018 /* recursive helper for function below */
2019 static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
2020 {
2021         TreeStoreElem *tselem= TREESTORE(te);
2022         
2023         /* store coord and continue, we need coordinates for elements outside view too */
2024         te->xs= startx;
2025         te->ys= *starty;
2026         *starty-= OL_H;
2027         
2028         if((tselem->flag & TSE_CLOSED)==0) {
2029                 TreeElement *ten;
2030                 for(ten= te->subtree.first; ten; ten= ten->next) {
2031                         outliner_set_coordinates_element(soops, ten, startx+OL_X, starty);
2032                 }
2033         }
2034         
2035 }
2036
2037 /* to retrieve coordinates with redrawing the entire tree */
2038 static void outliner_set_coordinates(SpaceOops *soops)
2039 {
2040         TreeElement *te;
2041         int starty= soops->v2d.tot.ymax-OL_H;
2042         int startx= 0;
2043         
2044         for(te= soops->tree.first; te; te= te->next) {
2045                 outliner_set_coordinates_element(soops, te, startx, &starty);
2046         }
2047 }
2048
2049 static TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
2050 {
2051         TreeElement *te, *tes;
2052         TreeStoreElem *tselem;
2053         
2054         for(te= lb->first; te; te= te->next) {
2055                 tselem= TREESTORE(te);
2056                 if(tselem->type==0) {
2057                         if(tselem->id==id) return te;
2058                         /* only deeper on scene or object */
2059                         if( te->idcode==ID_OB || te->idcode==ID_SCE) { 
2060                                 tes= outliner_find_id(soops, &te->subtree, id);
2061                                 if(tes) return tes;
2062                         }
2063                 }
2064         }
2065         return NULL;
2066 }
2067
2068 void outliner_show_active(struct ScrArea *sa)
2069 {
2070         SpaceOops *so= sa->spacedata.first;
2071         TreeElement *te;
2072         int xdelta, ytop;
2073         
2074         if(OBACT == NULL) return;
2075         
2076         te= outliner_find_id(so, &so->tree, (ID *)OBACT);
2077         if(te) {
2078                 /* make te->ys center of view */
2079                 ytop= te->ys + (so->v2d.mask.ymax-so->v2d.mask.ymin)/2;
2080                 if(ytop>0) ytop= 0;
2081                 so->v2d.cur.ymax= ytop;
2082                 so->v2d.cur.ymin= ytop-(so->v2d.mask.ymax-so->v2d.mask.ymin);
2083                 
2084                 /* make te->xs ==> te->xend center of view */
2085                 xdelta = te->xs - so->v2d.cur.xmin;
2086                 so->v2d.cur.xmin += xdelta;
2087                 so->v2d.cur.xmax += xdelta;
2088                 
2089                 so->storeflag |= SO_TREESTORE_REDRAW;
2090                 scrarea_queue_redraw(sa);
2091         }
2092 }
2093
2094 void outliner_show_selected(struct ScrArea *sa)
2095 {
2096         SpaceOops *so= sa->spacedata.first;
2097         TreeElement *te;
2098         int xdelta, ytop;
2099         
2100         te= outliner_find_id(so, &so->tree, (ID *)OBACT);
2101         if(te) {
2102                 /* make te->ys center of view */
2103                 ytop= te->ys + (so->v2d.mask.ymax-so->v2d.mask.ymin)/2;
2104                 if(ytop>0) ytop= 0;
2105                 so->v2d.cur.ymax= ytop;
2106                 so->v2d.cur.ymin= ytop-(so->v2d.mask.ymax-so->v2d.mask.ymin);
2107                 
2108                 /* make te->xs ==> te->xend center of view */
2109                 xdelta = te->xs - so->v2d.cur.xmin;
2110                 so->v2d.cur.xmin += xdelta;
2111                 so->v2d.cur.xmax += xdelta;
2112                 
2113                 so->storeflag |= SO_TREESTORE_REDRAW;
2114                 scrarea_queue_redraw(sa);
2115         }
2116 }
2117
2118
2119 /* find next element that has this name */
2120 static TreeElement *outliner_find_named(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound)
2121 {
2122         TreeElement *te, *tes;
2123         
2124         for (te= lb->first; te; te= te->next) {
2125                 int found;
2126                 
2127                 /* determine if match */
2128                 if(flags==OL_FIND)
2129                         found= BLI_strcasestr(te->name, name)!=NULL;
2130                 else if(flags==OL_FIND_CASE)
2131                         found= strstr(te->name, name)!=NULL;
2132                 else if(flags==OL_FIND_COMPLETE)
2133                         found= BLI_strcasecmp(te->name, name)==0;
2134                 else
2135                         found= strcmp(te->name, name)==0;
2136                 
2137                 if(found) {
2138                         /* name is right, but is element the previous one? */
2139                         if (prev) {
2140                                 if ((te != prev) && (*prevFound)) 
2141                                         return te;
2142                                 if (te == prev) {
2143                                         *prevFound = 1;
2144                                 }
2145                         }
2146                         else
2147                                 return te;
2148                 }
2149                 
2150                 tes= outliner_find_named(soops, &te->subtree, name, flags, prev, prevFound);
2151                 if(tes) return tes;
2152         }
2153
2154         /* nothing valid found */
2155         return NULL;
2156 }
2157
2158 /* tse is not in the treestore, we use its contents to find a match */
2159 static TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
2160 {
2161         TreeStore *ts= soops->treestore;
2162         TreeStoreElem *tselem;
2163         int a;
2164         
2165         if(tse->id==NULL) return NULL;
2166         
2167         /* check if 'tse' is in treestore */
2168         tselem= ts->data;
2169         for(a=0; a<ts->usedelem; a++, tselem++) {
2170                 if(tselem->id==tse->id) {
2171                         if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) {
2172                                 break;
2173                         }
2174                 }
2175         }
2176         if(tselem) 
2177                 return outliner_find_tree_element(&soops->tree, a);
2178         
2179         return NULL;
2180 }
2181
2182
2183 /* Called to find an item based on name.
2184  */
2185 void outliner_find_panel(struct ScrArea *sa, int again, int flags) 
2186 {
2187         SpaceOops *soops= sa->spacedata.first;
2188         TreeElement *te= NULL;
2189         TreeElement *last_find;
2190         TreeStoreElem *tselem;
2191         int ytop, xdelta, prevFound=0;
2192         char name[33];
2193         
2194         /* get last found tree-element based on stored search_tse */
2195         last_find= outliner_find_tse(soops, &soops->search_tse);
2196         
2197         /* determine which type of search to do */
2198         if (again && last_find) {
2199                 /* no popup panel - previous + user wanted to search for next after previous */         
2200                 BLI_strncpy(name, soops->search_string, 33);
2201                 flags= soops->search_flags;
2202                 
2203                 /* try to find matching element */
2204                 te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2205                 if (te==NULL) {
2206                         /* no more matches after previous, start from beginning again */
2207                         prevFound= 1;
2208                         te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2209                 }
2210         }
2211         else {
2212                 /* pop up panel - no previous, or user didn't want search after previous */
2213                 strcpy(name, "");
2214                 if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
2215                         te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound);
2216                 }
2217                 else return; /* XXX RETURN! XXX */
2218         }
2219
2220         /* do selection and reveil */
2221         if (te) {
2222                 tselem= TREESTORE(te);
2223                 if (tselem) {
2224                         /* expand branches so that it will be visible, we need to get correct coordinates */
2225                         if( outliner_open_back(soops, te))
2226                                 outliner_set_coordinates(soops);
2227                         
2228                         /* deselect all visible, and select found element */
2229                         outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
2230                         tselem->flag |= TSE_SELECTED;
2231                         
2232                         /* make te->ys center of view */
2233                         ytop= te->ys + (soops->v2d.mask.ymax-soops->v2d.mask.ymin)/2;
2234                         if(ytop>0) ytop= 0;
2235                         soops->v2d.cur.ymax= ytop;
2236                         soops->v2d.cur.ymin= ytop-(soops->v2d.mask.ymax-soops->v2d.mask.ymin);
2237                         
2238                         /* make te->xs ==> te->xend center of view */
2239                         xdelta = te->xs - soops->v2d.cur.xmin;
2240                         soops->v2d.cur.xmin += xdelta;
2241                         soops->v2d.cur.xmax += xdelta;
2242                         
2243                         /* store selection */
2244                         soops->search_tse= *tselem;
2245                         
2246                         BLI_strncpy(soops->search_string, name, 33);
2247                         soops->search_flags= flags;
2248                         
2249                         /* redraw */
2250                         soops->storeflag |= SO_TREESTORE_REDRAW;
2251                         scrarea_queue_redraw(sa);
2252                 }
2253         }
2254         else {
2255                 /* no tree-element found */
2256                 error("Not found: %s", name);
2257         }
2258 }
2259
2260 static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
2261 {
2262         TreeElement *te;
2263         TreeStoreElem *tselem;
2264         
2265         for(te= lb->first; te; te= te->next) {
2266                 tselem= TREESTORE(te);
2267                 if(tselem->type==0 && te->idcode==ID_OB) return 1;
2268                 if( subtree_has_objects(soops, &te->subtree)) return 1;
2269         }
2270         return 0;
2271 }
2272
2273 static void tree_element_show_hierarchy(SpaceOops *soops, ListBase *lb)
2274 {
2275         TreeElement *te;
2276         TreeStoreElem *tselem;
2277
2278         /* open all object elems, close others */
2279         for(te= lb->first; te; te= te->next) {
2280                 tselem= TREESTORE(te);
2281                 
2282                 if(tselem->type==0) {
2283                         if(te->idcode==ID_SCE) {
2284                                 if(tselem->id!=(ID *)G.scene) tselem->flag |= TSE_CLOSED;
2285                                         else tselem->flag &= ~TSE_CLOSED;
2286                         }
2287                         else if(te->idcode==ID_OB) {
2288                                 if(subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
2289                                 else tselem->flag |= TSE_CLOSED;
2290                         }
2291                 }
2292                 else tselem->flag |= TSE_CLOSED;
2293
2294                 if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(soops, &te->subtree);
2295         }
2296         
2297 }
2298
2299 /* show entire object level hierarchy */
2300 void outliner_show_hierarchy(struct ScrArea *sa)
2301 {
2302         SpaceOops *so= sa->spacedata.first;
2303         
2304         tree_element_show_hierarchy(so, &so->tree);
2305         scrarea_queue_redraw(sa);
2306         
2307         BIF_undo_push("Outliner show hierarchy");
2308 }
2309
2310 static void do_outliner_select(SpaceOops *soops, ListBase *lb, float y1, float y2, short *selecting)
2311 {
2312         TreeElement *te;
2313         TreeStoreElem *tselem;
2314         
2315         if(y1>y2) SWAP(float, y1, y2);
2316         
2317         for(te= lb->first; te; te= te->next) {
2318                 tselem= TREESTORE(te);
2319                 
2320                 if(te->ys + OL_H < y1) return;
2321                 if(te->ys < y2) {
2322                         if((te->flag & TE_ICONROW)==0) {
2323                                 if(*selecting == -1) {
2324                                         if( tselem->flag & TSE_SELECTED) *selecting= 0;
2325                                         else *selecting= 1;
2326                                 }
2327                                 if(*selecting) tselem->flag |= TSE_SELECTED;
2328                                 else tselem->flag &= ~TSE_SELECTED;
2329                         }
2330                 }
2331                 if((tselem->flag & TSE_CLOSED)==0) do_outliner_select(soops, &te->subtree, y1, y2, selecting);
2332         }
2333 }
2334
2335 /* its own redraw loop... urm */
2336 void outliner_select(struct ScrArea *sa )
2337 {
2338         SpaceOops *so= sa->spacedata.first;
2339         float fmval[2], y1, y2;
2340         short mval[2], yo=-1, selecting= -1;
2341         
2342         getmouseco_areawin(mval);
2343         areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1);
2344         y1= fmval[1];
2345
2346         while (get_mbut() & (L_MOUSE|R_MOUSE)) {
2347                 getmouseco_areawin(mval);
2348                 areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1);
2349                 y2= fmval[1];
2350                 
2351                 if(yo!=mval[1]) {
2352                         /* select the 'ouliner row' */
2353                         do_outliner_select(so, &so->tree, y1, y2, &selecting);
2354                         yo= mval[1];
2355                         
2356                         so->storeflag |= SO_TREESTORE_REDRAW;
2357                         scrarea_do_windraw(sa);
2358                         screen_swapbuffers();
2359                 
2360                         y1= y2;
2361                 }
2362                 else PIL_sleep_ms(30);
2363         }
2364         
2365         BIF_undo_push("Outliner selection");
2366
2367 }
2368
2369 /* ************ SELECTION OPERATIONS ********* */
2370
2371 static int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; // globals, euh... you can do better
2372
2373 static void set_operation_types(SpaceOops *soops, ListBase *lb)
2374 {
2375         TreeElement *te;
2376         TreeStoreElem *tselem;
2377         
2378         for(te= lb->first; te; te= te->next) {
2379                 tselem= TREESTORE(te);
2380                 if(tselem->flag & TSE_SELECTED) {
2381                         if(tselem->type) {
2382 #ifdef WITH_VERSE
2383                                 if(te->idcode==ID_VS) datalevel= TSE_VERSE_SESSION;
2384                                 else if(te->idcode==ID_VN) datalevel= TSE_VERSE_OBJ_NODE;
2385                                 else if(datalevel==0) datalevel= tselem->type;
2386 #else
2387                                 if(datalevel==0) datalevel= tselem->type;
2388 #endif
2389                                 else if(datalevel!=tselem->type) datalevel= -1;
2390                         }
2391                         else {
2392                                 int idcode= GS(tselem->id->name);
2393                                 switch(idcode) {
2394                                         case ID_SCE:
2395                                                 scenelevel= 1;
2396                                                 break;
2397                                         case ID_OB:
2398                                                 objectlevel= 1;
2399                                                 break;
2400                                                 
2401                                         case ID_ME: case ID_CU: case ID_MB: case ID_LT:
2402                                         case ID_LA: case ID_AR: case ID_CA:
2403                                         case ID_MA: case ID_TE: case ID_IP: case ID_IM:
2404                                         case ID_SO: case ID_KE: case ID_WO: case ID_AC:
2405                                         case ID_NLA: case ID_TXT: case ID_GR:
2406                                                 if(idlevel==0) idlevel= idcode;
2407                                                 else if(idlevel!=idcode) idlevel= -1;
2408                                                         break;
2409                                 }
2410                         }
2411                 }
2412                 if((tselem->flag & TSE_CLOSED)==0) set_operation_types(soops, &te->subtree);
2413         }
2414 }
2415
2416 static void unlink_material_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2417 {
2418         Material **matar=NULL;
2419         int a, totcol=0;
2420         
2421         if( GS(tsep->id->name)==ID_OB) {
2422                 Object *ob= (Object *)tsep->id;
2423                 totcol= ob->totcol;
2424                 matar= ob->mat;
2425         }
2426         else if( GS(tsep->id->name)==ID_ME) {
2427                 Mesh *me= (Mesh *)tsep->id;
2428                 totcol= me->totcol;
2429                 matar= me->mat;
2430         }
2431         else if( GS(tsep->id->name)==ID_CU) {
2432                 Curve *cu= (Curve *)tsep->id;
2433                 totcol= cu->totcol;
2434                 matar= cu->mat;
2435         }
2436         else if( GS(tsep->id->name)==ID_MB) {
2437                 MetaBall *mb= (MetaBall *)tsep->id;
2438                 totcol= mb->totcol;
2439                 matar= mb->mat;
2440         }
2441
2442         for(a=0; a<totcol; a++) {
2443                 if(a==te->index && matar[a]) {
2444                         matar[a]->id.us--;
2445                         matar[a]= NULL;
2446                 }
2447         }
2448 }
2449
2450 static void unlink_texture_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2451 {
2452         MTex **mtex= NULL;
2453         int a;
2454         
2455         if( GS(tsep->id->name)==ID_MA) {
2456                 Material *ma= (Material *)tsep->id;
2457                 mtex= ma->mtex;
2458         }
2459         else if( GS(tsep->id->name)==ID_LA) {
2460                 Lamp *la= (Lamp *)tsep->id;
2461                 mtex= la->mtex;
2462         }
2463         else if( GS(tsep->id->name)==ID_WO) {
2464                 World *wrld= (World *)tsep->id;
2465                 mtex= wrld->mtex;
2466         }
2467         else return;
2468         
2469         for(a=0; a<MAX_MTEX; a++) {
2470                 if(a==te->index && mtex[a]) {
2471                         if(mtex[a]->tex) {
2472                                 mtex[a]->tex->id.us--;
2473                                 mtex[a]->tex= NULL;
2474                         }
2475                 }
2476         }
2477 }
2478
2479 static void unlink_group_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2480 {
2481         Group *group= (Group *)tselem->id;
2482         
2483         if(tsep) {
2484                 if( GS(tsep->id->name)==ID_OB) {
2485                         Object *ob= (Object *)tsep->id;
2486                         ob->dup_group= NULL;
2487                         group->id.us--;
2488                 }
2489         }
2490         else {
2491                 unlink_group(group);
2492         }
2493 }
2494
2495 static void outliner_do_libdata_operation(SpaceOops *soops, ListBase *lb, 
2496                                                                                  void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
2497 {
2498         TreeElement *te;
2499         TreeStoreElem *tselem;
2500         
2501         for(te=lb->first; te; te= te->next) {
2502                 tselem= TREESTORE(te);
2503                 if(tselem->flag & TSE_SELECTED) {
2504                         if(tselem->type==0) {
2505                                 TreeStoreElem *tsep= TREESTORE(te->parent);
2506                                 operation_cb(te, tsep, tselem);
2507                         }
2508                 }
2509                 if((tselem->flag & TSE_CLOSED)==0) {
2510                         outliner_do_libdata_operation(soops, &te->subtree, operation_cb);
2511                 }
2512         }
2513 }
2514
2515 /* */
2516
2517 static void object_select_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2518 {
2519         Base *base= (Base *)te->directdata;
2520         
2521         if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
2522         if(base && ((base->object->restrictflag & OB_RESTRICT_VIEW)==0)) {
2523                 base->flag |= SELECT;
2524                 base->object->flag |= SELECT;
2525         }
2526 }
2527
2528 static void object_deselect_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2529 {
2530         Base *base= (Base *)te->directdata;
2531         
2532         if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
2533         if(base) {
2534                 base->flag &= ~SELECT;
2535                 base->object->flag &= ~SELECT;
2536         }
2537 }
2538
2539 static void object_delete_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2540 {
2541         Base *base= (Base *)te->directdata;
2542         
2543         if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
2544         if(base) {
2545                 // check also library later
2546                 if(G.obedit==base->object) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2547                 
2548                 if(base==BASACT) {
2549                         G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT);
2550                         setcursor_space(SPACE_VIEW3D, CURSOR_STD);
2551                 }
2552                 
2553                 free_and_unlink_base(base);
2554                 te->directdata= NULL;
2555                 tselem->id= NULL;
2556         }
2557 }
2558
2559 static void id_local_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2560 {
2561         if(tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
2562                 tselem->id->lib= NULL;
2563                 tselem->id->flag= LIB_LOCAL;
2564                 new_id(0, tselem->id, 0);
2565         }
2566 }
2567
2568 static void outliner_do_object_operation(SpaceOops *soops, ListBase *lb, 
2569                                                                                  void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
2570 {
2571         TreeElement *te;
2572         TreeStoreElem *tselem;
2573         
2574         for(te=lb->first; te; te= te->next) {
2575                 tselem= TREESTORE(te);
2576                 if(tselem->flag & TSE_SELECTED) {
2577                         if(tselem->type==0 && te->idcode==ID_OB) {
2578                                 // when objects selected in other scenes... dunno if that should be allowed
2579                                 Scene *sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
2580                                 if(sce && G.scene != sce) set_scene(sce);
2581                                 
2582                                 operation_cb(te, NULL, tselem);
2583                         }
2584                 }
2585                 if((tselem->flag & TSE_CLOSED)==0) {
2586                         outliner_do_object_operation(soops, &te->subtree, operation_cb);
2587                 }
2588         }
2589 }
2590
2591 static void pchan_cb(int event, TreeElement *te, TreeStoreElem *tselem)
2592 {
2593         bPoseChannel *pchan= (bPoseChannel *)te->directdata;
2594         
2595         if(event==1)
2596                 pchan->bone->flag |= BONE_SELECTED;
2597         else if(event==2)
2598                 pchan->bone->flag &= ~BONE_SELECTED;
2599         else if(event==3) {
2600                 pchan->bone->flag |= BONE_HIDDEN_P;
2601                 pchan->bone->flag &= ~BONE_SELECTED;
2602         }
2603         else if(event==4)
2604                 pchan->bone->flag &= ~BONE_HIDDEN_P;
2605 }
2606
2607 static void bone_cb(int event, TreeElement *te, TreeStoreElem *tselem)
2608 {
2609         Bone *bone= (Bone *)te->directdata;
2610         
2611         if(event==1)
2612                 bone->flag |= BONE_SELECTED;
2613         else if(event==2)
2614                 bone->flag &= ~BONE_SELECTED;
2615         else if(event==3) {
2616                 bone->flag |= BONE_HIDDEN_P;
2617                 bone->flag &= ~BONE_SELECTED;
2618         }
2619         else if(event==4)
2620                 bone->flag &= ~BONE_HIDDEN_P;
2621 }
2622
2623 static void ebone_cb(int event, TreeElement *te, TreeStoreElem *tselem)
2624 {
2625         EditBone *ebone= (EditBone *)te->directdata;
2626         
2627         if(event==1)
2628                 ebone->flag |= BONE_SELECTED;
2629         else if(event==2)
2630                 ebone->flag &= ~BONE_SELECTED;
2631         else if(event==3) {
2632                 ebone->flag |= BONE_HIDDEN_A;
2633                 ebone->flag &= ~BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
2634         }
2635         else if(event==4)
2636                 ebone->flag &= ~BONE_HIDDEN_A;
2637 }
2638
2639 #ifdef WITH_VERSE
2640 static void vsession_cb(int event, TreeElement *te, TreeStoreElem *tselem)
2641 {
2642 /*      struct VerseSession *vsession =(VerseSession*)te->directdata;*/
2643
2644         if(event==1) {
2645                 printf("\tending verse session\n");
2646         }
2647 }
2648 #endif
2649
2650 static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, 
2651                                                                                  void (*operation_cb)(int, TreeElement *, TreeStoreElem *))
2652 {
2653         TreeElement *te;
2654         TreeStoreElem *tselem;
2655         
2656         for(te=lb->first; te; te= te->next) {
2657                 tselem= TREESTORE(te);
2658                 if(tselem->flag & TSE_SELECTED) {
2659                         if(tselem->type==type) {
2660                                 operation_cb(event, te, tselem);
2661                         }
2662                 }
2663                 if((tselem->flag & TSE_CLOSED)==0) {
2664                         outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb);
2665                 }
2666         }
2667 }
2668
2669 void outliner_del(ScrArea *sa)
2670 {
2671         SpaceOops *soops= sa->spacedata.first;
2672         outliner_do_object_operation(soops, &soops->tree, object_delete_cb);
2673         DAG_scene_sort(G.scene);
2674         countall();     
2675         BIF_undo_push("Delete Objects");
2676         allqueue(REDRAWALL, 0); 
2677 }
2678
2679
2680 void outliner_operation_menu(ScrArea *sa)
2681 {
2682         SpaceOops *soops= sa->spacedata.first;
2683         
2684         // bad globals
2685         scenelevel= objectlevel= idlevel= datalevel=0;
2686         
2687         set_operation_types(soops, &soops->tree);
2688         
2689         if(scenelevel) {
2690                 if(objectlevel || datalevel || idlevel) error("Mixed selection");
2691                 //else pupmenu("Scene Operations%t|Delete");
2692         }
2693         else if(objectlevel) {
2694                 short event= pupmenu("Select%x1|Deselect%x2|Delete%x4");        /* make local: does not work... it doesn't set lib_extern flags... so data gets lost */
2695                 if(event>0) {
2696                         char *str="";
2697                         
2698                         if(event==1) {
2699                                 Scene *sce= G.scene;    // to be able to delete, scenes are set...
2700                                 outliner_do_object_operation(soops, &soops->tree, object_select_cb);
2701                                 if(G.scene != sce) set_scene(sce);
2702                                 
2703                                 str= "Select Objects";
2704                         }
2705                         else if(event==2) {
2706                                 outliner_do_object_operation(soops, &soops->tree, object_deselect_cb);
2707                                 str= "Deselect Objects";
2708                         }
2709                         else if(event==4) {
2710                                 outliner_do_object_operation(soops, &soops->tree, object_delete_cb);
2711                                 DAG_scene_sort(G.scene);
2712                                 str= "Delete Objects";
2713                         }
2714                         else if(event==5) {     /* disabled, see above (ton) */
2715                                 outliner_do_object_operation(soops, &soops->tree, id_local_cb);
2716                                 str= "Localized Objects";
2717                         }
2718                         
2719                         countall();
2720                         
2721                         BIF_undo_push(str);
2722                         allqueue(REDRAWALL, 0);
2723                 }
2724         }
2725         else if(idlevel) {
2726                 if(idlevel==-1 || datalevel) error("Mixed selection");
2727                 else {
2728                         short event= pupmenu("Unlink %x1|Make Local %x2");
2729                         
2730                         if(event==1) {
2731                                 switch(idlevel) {
2732                                         case ID_MA:
2733                                                 outliner_do_libdata_operation(soops, &soops->tree, unlink_material_cb);
2734                                                 BIF_undo_push("Unlink material");
2735                                                 allqueue(REDRAWBUTSSHADING, 1);
2736                                                 break;
2737                                         case ID_TE:
2738                                                 outliner_do_libdata_operation(soops, &soops->tree, unlink_texture_cb);
2739                                                 allqueue(REDRAWBUTSSHADING, 1);
2740                                                 BIF_undo_push("Unlink texture");
2741                                                 break;
2742                                         case ID_GR:
2743                                                 outliner_do_libdata_operation(soops, &soops->tree, unlink_group_cb);
2744                                                 BIF_undo_push("Unlink group");
2745                                                 break;
2746                                         default:
2747                                                 error("Not yet...");
2748                                 }
2749                                 allqueue(REDRAWALL, 0);
2750                         }
2751                         else if(event==2) {
2752                                 outliner_do_libdata_operation(soops, &soops->tree, id_local_cb);
2753                                 BIF_undo_push("Localized Data");
2754                                 allqueue(REDRAWALL, 0); 
2755                         }
2756                 }
2757         }
2758         else if(datalevel) {
2759                 if(datalevel==-1) error("Mixed selection");
2760                 else {
2761                         if(datalevel==TSE_POSE_CHANNEL) {
2762                                 short event= pupmenu("PoseChannel Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
2763                                 if(event>0) {
2764                                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb);
2765                                         BIF_undo_push("PoseChannel operation");
2766                                 }
2767                         }
2768                         else if(datalevel==TSE_BONE) {
2769                                 short event= pupmenu("Bone Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
2770                                 if(event>0) {
2771                                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb);
2772                                         BIF_undo_push("Bone operation");
2773                                 }
2774                         }
2775                         else if(datalevel==TSE_EBONE) {
2776                                 short event= pupmenu("EditBone Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
2777                                 if(event>0) {
2778                                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb);
2779                                         BIF_undo_push("EditBone operation");
2780                                 }
2781                         }
2782 #ifdef WITH_VERSE
2783                         else if(datalevel==TSE_VERSE_SESSION) {
2784                                 short event= pupmenu("VerseSession %t| End %x1");
2785                                 if(event>0) {
2786                                         outliner_do_data_operation(soops, datalevel, event, &soops->tree, vsession_cb);
2787                                 }
2788                         }
2789 #endif
2790                         
2791                         allqueue(REDRAWOOPS, 0);
2792                         allqueue(REDRAWBUTSALL, 0);
2793                         allqueue(REDRAWVIEW3D, 0);
2794                 }
2795         }
2796 }
2797
2798
2799 /* ***************** DRAW *************** */
2800
2801 static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElement *te)
2802 {
2803         if(tselem->type) {
2804                 switch( tselem->type) {
2805                         case TSE_NLA:
2806                                 BIF_icon_draw(x, y, ICON_NLA); break;
2807                         case TSE_NLA_ACTION:
2808                                 BIF_icon_draw(x, y, ICON_ACTION); break;
2809                         case TSE_DEFGROUP_BASE:
2810                                 BIF_icon_draw(x, y, ICON_VERTEXSEL); break;
2811                         case TSE_BONE:
2812                         case TSE_EBONE:
2813                                 BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
2814                         case TSE_CONSTRAINT_BASE:
2815                                 BIF_icon_draw(x, y, ICON_CONSTRAINT); break;
2816                         case TSE_MODIFIER_BASE:
2817                                 BIF_icon_draw(x, y, ICON_MODIFIER); break;
2818                         case TSE_LINKED_OB:
2819                                 BIF_icon_draw(x, y, ICON_OBJECT); break;
2820                         case TSE_MODIFIER:
2821                         {
2822                                 Object *ob= (Object *)tselem->id;
2823                                 ModifierData *md= BLI_findlink(&ob->modifiers, tselem->nr);
2824                                 switch(md->type) {
2825                                         case eModifierType_Subsurf: 
2826                                                 BIF_icon_draw(x, y, ICON_MOD_SUBSURF); break;
2827                                         case eModifierType_Armature: 
2828                                                 BIF_icon_draw(x, y, ICON_ARMATURE); break;
2829                                         case eModifierType_Lattice: 
2830                                                 BIF_icon_draw(x, y, ICON_LATTICE); break;
2831                                         case eModifierType_Curve: 
2832                                                 BIF_icon_draw(x, y, ICON_CURVE); break;
2833                                         case eModifierType_Build: 
2834                                                 BIF_icon_draw(x, y, ICON_MOD_BUILD); break;
2835                                         case eModifierType_Mirror: 
2836                                                 BIF_icon_draw(x, y, ICON_MOD_MIRROR); break;
2837                                         case eModifierType_Decimate: 
2838                                                 BIF_icon_draw(x, y, ICON_MOD_DECIM); break;
2839                                         case eModifierType_Wave: 
2840                                                 BIF_icon_draw(x, y, ICON_MOD_WAVE); break;
2841                                         case eModifierType_Hook: 
2842                                                 BIF_icon_draw(x, y, ICON_HOOK); break;
2843                                         case eModifierType_Softbody: 
2844                                                 BIF_icon_draw(x, y, ICON_MOD_SOFT); break;
2845                                         case eModifierType_Boolean: 
2846                                                 BIF_icon_draw(x, y, ICON_MOD_BOOLEAN); break;
2847                                         default:
2848                                                 BIF_icon_draw(x, y, ICON_DOT); break;
2849                                 }
2850                                 break;
2851                         }
2852                         case TSE_SCRIPT_BASE:
2853                                 BIF_icon_draw(x, y, ICON_TEXT); break;
2854                         case TSE_POSE_BASE:
2855                                 BIF_icon_draw(x, y, ICON_ARMATURE_DEHLT); break;
2856                         case TSE_POSE_CHANNEL:
2857                                 BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
2858                         case TSE_PROXY:
2859                                 BIF_icon_draw(x, y, ICON_GHOST); break;
2860                         case TSE_R_LAYER_BASE:
2861                                 BIF_icon_draw(x, y, ICON_RESTRICT_RENDER_OFF); break;
2862                         case TSE_R_LAYER:
2863                                 BIF_icon_draw(x, y, ICON_IMAGE_DEHLT); break;
2864                         case TSE_LINKED_LAMP:
2865                                 BIF_icon_draw(x, y, ICON_LAMP_DEHLT); break;
2866                         case TSE_LINKED_MAT:
2867                                 BIF_icon_draw(x, y, ICON_MATERIAL_DEHLT); break;
2868                                 
2869 #ifdef WITH_VERSE
2870                         case ID_VS:
2871                         case ID_MS:
2872                         case ID_SS:
2873                                 BIF_icon_draw(x, y, ICON_VERSE); break;
2874                         case ID_VN:
2875                                 BIF_icon_draw(x, y, ICON_VERSE); break;
2876 #endif
2877                         default:
2878                                 BIF_icon_draw(x, y, ICON_DOT); break;
2879                 }
2880         }
2881         else {
2882                 switch( GS(tselem->id->name)) {
2883                         case ID_SCE:
2884                                 BIF_icon_draw(x, y, ICON_SCENE_DEHLT); break;
2885                         case ID_OB:
2886                                 BIF_icon_draw(x, y, ICON_OBJECT); break;
2887                         case ID_ME:
2888                                 BIF_icon_draw(x, y, ICON_MESH); break;
2889                         case ID_CU:
2890                                 BIF_icon_draw(x, y, ICON_CURVE); break;
2891                         case ID_MB:
2892                                 BIF_icon_draw(x, y, ICON_MBALL); break;
2893                         case ID_LT:
2894                                 BIF_icon_draw(x, y, ICON_LATTICE); break;
2895                         case ID_LA:
2896                                 BIF_icon_draw(x, y, ICON_LAMP_DEHLT); break;
2897                         case ID_MA:
2898                                 BIF_icon_draw(x, y, ICON_MATERIAL_DEHLT); break;
2899                         case ID_TE:
2900                                 BIF_icon_draw(x, y, ICON_TEXTURE_DEHLT); break;
2901                         case ID_IP:
2902                                 BIF_icon_draw(x, y, ICON_IPO_DEHLT); break;
2903                         case ID_IM:
2904                                 BIF_icon_draw(x, y, ICON_IMAGE_DEHLT); break;
2905                         case ID_SO:
2906                                 BIF_icon_draw(x, y, ICON_SPEAKER); break;
2907                         case ID_AR:
2908                                 BIF_icon_draw(x, y, ICON_ARMATURE); break;
2909                         case ID_CA:
2910                                 BIF_icon_draw(x, y, ICON_CAMERA_DEHLT); break;
2911                         case ID_KE:
2912                                 BIF_icon_draw(x, y, ICON_EDIT_DEHLT); break;
2913                         case ID_WO:
2914                                 BIF_icon_draw(x, y, ICON_WORLD_DEHLT); break;
2915                         case ID_AC:
2916                                 BIF_icon_draw(x, y, ICON_ACTION); break;
2917                         case ID_NLA:
2918                                 BIF_icon_draw(x, y, ICON_NLA); break;
2919                         case ID_TXT:
2920                                 BIF_icon_draw(x, y, ICON_SCRIPT); break;
2921                         case ID_GR:
2922                                 BIF_icon_draw(x, y, ICON_CIRCLE_DEHLT); break;
2923                         case ID_LI:
2924                                 BIF_icon_draw(x, y, ICON_LIBRARY_DEHLT); break;
2925                 }
2926         }
2927 }
2928
2929 static void outliner_draw_iconrow(SpaceOops *soops, ListBase *lb, int level, int *offsx, int ys)
2930 {
2931         TreeElement *te;
2932         TreeStoreElem *tselem;
2933         int active;
2934
2935         for(te= lb->first; te; te= te->next) {
2936                 tselem= TREESTORE(te);
2937                 
2938                 /* object hierarchy always, further constrained on level */
2939                 if(level<1 || (tselem->type==0 && te->idcode==ID_OB)) {
2940
2941                         /* active blocks get white circle */
2942                         active= 0;
2943                         if(tselem->type==0) {
2944                                 if(te->idcode==ID_OB) active= (OBACT==(Object *)tselem->id);
2945                                 else if(G.obedit && G.obedit->data==tselem->id) active= 1;
2946                                 else active= tree_element_active(soops, te, 0);
2947                         }
2948                         else active= tree_element_type_active(soops, te, tselem, 0);
2949                         
2950                         if(active) {
2951                                 uiSetRoundBox(15);
2952                                 glColor4ub(255, 255, 255, 100);
2953                                 uiRoundBox( (float)*offsx-0.5, (float)ys-1.0, (float)*offsx+OL_H-3.0, (float)ys+OL_H-3.0, OL_H/2.0-2.0);
2954                                 glEnable(GL_BLEND);
2955                         }
2956                         
2957                         tselem_draw_icon(*offsx, ys, tselem, te);
2958                         te->xs= *offsx;
2959                         te->ys= ys;
2960                         te->xend= *offsx+OL_X;
2961                         te->flag |= TE_ICONROW; // for click
2962                         
2963                         (*offsx) += OL_X;
2964                 }
2965                 
2966                 /* this tree element always has same amount of branches, so dont draw */
2967                 if(tselem->type!=TSE_R_LAYER)
2968                         outliner_draw_iconrow(soops, &te->subtree, level+1, offsx, ys);
2969         }
2970         
2971 }
2972
2973 static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
2974 {
2975         TreeElement *ten;
2976         TreeStoreElem *tselem;
2977         int offsx= 0, active=0; // active=1 active obj, else active data
2978         
2979         tselem= TREESTORE(te);
2980
2981         if(*starty >= soops->v2d.cur.ymin && *starty<= soops->v2d.cur.ymax) {
2982         
2983                 glEnable(GL_BLEND);
2984
2985                 /* colors for active/selected data */
2986                 if(tselem->type==0) {
2987                         if(te->idcode==ID_SCE) {
2988                                 if(tselem->id == (ID *)G.scene) {
2989                                         glColor4ub(255, 255, 255, 100);
2990                                         active= 2;
2991                                 }
2992                         }
2993                         else if(te->idcode==ID_OB) {
2994                                 Object *ob= (Object *)tselem->id;
2995                                 
2996                                 if(ob==OBACT || (ob->flag & SELECT)) {
2997                                         char col[4];
2998                                         
2999                                         active= 2;
3000                                         if(ob==OBACT) {
3001                                                 BIF_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
3002                                                 /* so black text is drawn when active and not selected */
3003                                                 if (ob->flag & SELECT) active= 1;
3004                                         }
3005                                         else BIF_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
3006                                         col[3]= 100;
3007                                         glColor4ubv((GLubyte *)col);
3008                                 }
3009
3010 #ifdef WITH_VERSE
3011                                 if(ob->vnode) {
3012                                         if (active==0) active=2;
3013                                         if (ob==OBACT)
3014                                                 glColor4ub(0,255,0,100);
3015                                         else
3016                                                 glColor4ub(0,128,0,100);
3017                                 }
3018 #endif
3019                         }
3020                         else if(G.obedit && G.obedit->data==tselem->id) {
3021                                 glColor4ub(255, 255, 255, 100);
3022                                 active= 2;
3023                         }
3024                         else {