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