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