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