6f970105f871a92e5a32619f4708adb53142eda1
[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                                         bPoseChannel *pchan;
617                                         TreeElement *ten;
618                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
619                                         
620                                         tenla->name= "Pose";
621                                         
622                                         if(ob!=G.obedit && (ob->flag & OB_POSEMODE)) {  // channels undefined in editmode, but we want the 'tenla' pose icon itself
623                                                 int a= 0, const_index= 1000;    /* ensure unique id for bone constraints */
624                                                 
625                                                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
626                                                         ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
627                                                         ten->name= pchan->name;
628                                                         ten->directdata= pchan;
629                                                         pchan->prev= (bPoseChannel *)ten;
630                                                         
631                                                         if(pchan->constraints.first) {
632                                                                 //Object *target;
633                                                                 bConstraint *con;
634                                                                 TreeElement *ten1;
635                                                                 TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
636                                                                 //char *str;
637                                                                 
638                                                                 tenla1->name= "Constraints";
639                                                                 for(con= pchan->constraints.first; con; con= con->next, const_index++) {
640                                                                         ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
641 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
642                                                                         target= get_constraint_target(con, &str);
643                                                                         if(str && str[0]) ten1->name= str;
644                                                                         else if(target) ten1->name= target->id.name+2;
645                                                                         else ten1->name= con->name;
646 #endif
647                                                                         ten1->name= con->name;
648                                                                         ten1->directdata= con;
649                                                                         /* possible add all other types links? */
650                                                                 }
651                                                         }
652                                                 }
653                                                 /* make hierarchy */
654                                                 ten= tenla->subtree.first;
655                                                 while(ten) {
656                                                         TreeElement *nten= ten->next, *par;
657                                                         tselem= TREESTORE(ten);
658                                                         if(tselem->type==TSE_POSE_CHANNEL) {
659                                                                 pchan= (bPoseChannel *)ten->directdata;
660                                                                 if(pchan->parent) {
661                                                                         BLI_remlink(&tenla->subtree, ten);
662                                                                         par= (TreeElement *)pchan->parent->prev;
663                                                                         BLI_addtail(&par->subtree, ten);
664                                                                         ten->parent= par;
665                                                                 }
666                                                         }
667                                                         ten= nten;
668                                                 }
669                                                 /* restore prev pointers */
670                                                 pchan= ob->pose->chanbase.first;
671                                                 if(pchan) pchan->prev= NULL;
672                                                 for(; pchan; pchan= pchan->next) {
673                                                         if(pchan->next) pchan->next->prev= pchan;
674                                                 }
675                                         }
676                                         
677                                         /* Pose Groups */
678                                         if(ob->pose->agroups.first) {
679                                                 bActionGroup *agrp;
680                                                 TreeElement *ten;
681                                                 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
682                                                 int a= 0;
683                                                 
684                                                 tenla->name= "Bone Groups";
685                                                 for (agrp=ob->pose->agroups.first; agrp; agrp=agrp->next, a++) {
686                                                         ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a);
687                                                         ten->name= agrp->name;
688                                                         ten->directdata= agrp;
689                                                 }
690                                         }
691                                 }
692                                 
693                                 outliner_add_element(soops, &te->subtree, ob->ipo, te, 0, 0);
694                                 outliner_add_element(soops, &te->subtree, ob->action, te, 0, 0);
695                                 
696                                 for(a=0; a<ob->totcol; a++) 
697                                         outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
698                                 
699                                 if(ob->constraints.first) {
700                                         //Object *target;
701                                         bConstraint *con;
702                                         TreeElement *ten;
703                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
704                                         int a= 0;
705                                         //char *str;
706                                         
707                                         tenla->name= "Constraints";
708                                         for(con= ob->constraints.first; con; con= con->next, a++) {
709                                                 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
710 #if 0 /* disabled due to constraints system targets recode... code here needs review */
711                                                 target= get_constraint_target(con, &str);
712                                                 if(str && str[0]) ten->name= str;
713                                                 else if(target) ten->name= target->id.name+2;
714                                                 else ten->name= con->name;
715 #endif
716                                                 ten->name= con->name;
717                                                 ten->directdata= con;
718                                                 /* possible add all other types links? */
719                                         }
720                                 }
721                                 
722                                 if(ob->modifiers.first) {
723                                         ModifierData *md;
724                                         TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
725                                         int index;
726
727                                         temod->name = "Modifiers";
728                                         for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
729                                                 TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
730                                                 te->name= md->name;
731                                                 te->directdata = md;
732
733                                                 if (md->type==eModifierType_Lattice) {
734                                                         outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
735                                                 } else if (md->type==eModifierType_Curve) {
736                                                         outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0);
737                                                 } else if (md->type==eModifierType_Armature) {
738                                                         outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0);
739                                                 } else if (md->type==eModifierType_Hook) {
740                                                         outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0);
741                                                 } else if (md->type==eModifierType_ParticleSystem) {
742                                                         TreeElement *ten;
743                                                         ParticleSystem *psys= ((ParticleSystemModifierData*) md)->psys;
744                                                         
745                                                         ten = outliner_add_element(soops, &te->subtree, ob, te, TSE_LINKED_PSYS, 0);
746                                                         ten->directdata = psys;
747                                                         ten->name = psys->part->id.name+2;
748                                                 }
749                                         }
750                                 }
751                                 if(ob->defbase.first) {
752                                         bDeformGroup *defgroup;
753                                         TreeElement *ten;
754                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
755                                         int a= 0;
756                                         
757                                         tenla->name= "Vertex Groups";
758                                         for (defgroup=ob->defbase.first; defgroup; defgroup=defgroup->next, a++) {
759                                                 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
760                                                 ten->name= defgroup->name;
761                                                 ten->directdata= defgroup;
762                                         }
763                                 }
764                                 if(ob->scriptlink.scripts) {
765                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_SCRIPT_BASE, 0);
766                                         int a= 0;
767                                         
768                                         tenla->name= "Scripts";
769                                         for (a=0; a<ob->scriptlink.totscript; a++) {                                                    /*  ** */
770                                                 outliner_add_element(soops, &tenla->subtree, ob->scriptlink.scripts[a], te, 0, 0);
771                                         }
772                                 }
773                                 
774                                 if(ob->dup_group)
775                                         outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
776
777                                 if(ob->nlastrips.first) {
778                                         bActionStrip *strip;
779                                         TreeElement *ten;
780                                         TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_NLA, 0);
781                                         int a= 0;
782                                         
783                                         tenla->name= "NLA strips";
784                                         for (strip=ob->nlastrips.first; strip; strip=strip->next, a++) {
785                                                 ten= outliner_add_element(soops, &tenla->subtree, strip->act, tenla, TSE_NLA_ACTION, a);
786                                                 if(ten) ten->directdata= strip;
787                                         }
788                                 }
789                                 
790                         }
791                         break;
792                 case ID_ME:
793                         {
794                                 Mesh *me= (Mesh *)id;
795                                 outliner_add_element(soops, &te->subtree, me->ipo, te, 0, 0);
796                                 outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
797                                 for(a=0; a<me->totcol; a++) 
798                                         outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
799                                 /* could do tfaces with image links, but the images are not grouped nicely.
800                                    would require going over all tfaces, sort images in use. etc... */
801                         }
802                         break;
803                 case ID_CU:
804                         {
805                                 Curve *cu= (Curve *)id;
806                                 for(a=0; a<cu->totcol; a++) 
807                                         outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
808                         }
809                         break;
810                 case ID_MB:
811                         {
812                                 MetaBall *mb= (MetaBall *)id;
813                                 for(a=0; a<mb->totcol; a++) 
814                                         outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
815                         }
816                         break;
817                 case ID_MA:
818                 {
819                         Material *ma= (Material *)id;
820                         
821                         outliner_add_element(soops, &te->subtree, ma->ipo, te, 0, 0);
822                         for(a=0; a<MAX_MTEX; a++) {
823                                 if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
824                         }
825                 }
826                         break;
827                 case ID_TE:
828                         {
829                                 Tex *tex= (Tex *)id;
830                                 
831                                 outliner_add_element(soops, &te->subtree, tex->ipo, te, 0, 0);
832                                 outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
833                         }
834                         break;
835                 case ID_CA:
836                         {
837                                 Camera *ca= (Camera *)id;
838                                 outliner_add_element(soops, &te->subtree, ca->ipo, te, 0, 0);
839                         }
840                         break;
841                 case ID_LA:
842                         {
843                                 Lamp *la= (Lamp *)id;
844                                 outliner_add_element(soops, &te->subtree, la->ipo, te, 0, 0);
845                                 for(a=0; a<MAX_MTEX; a++) {
846                                         if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
847                                 }
848                         }
849                         break;
850                 case ID_WO:
851                         {
852                                 World *wrld= (World *)id;
853                                 outliner_add_element(soops, &te->subtree, wrld->ipo, te, 0, 0);
854                                 for(a=0; a<MAX_MTEX; a++) {
855                                         if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
856                                 }
857                         }
858                         break;
859                 case ID_KE:
860                         {
861                                 Key *key= (Key *)id;
862                                 outliner_add_element(soops, &te->subtree, key->ipo, te, 0, 0);
863                         }
864                         break;
865                 case ID_IP:
866                         {
867                                 Ipo *ipo= (Ipo *)id;
868                                 IpoCurve *icu;
869                                 Object *lastadded= NULL;
870                                 
871                                 for (icu= ipo->curve.first; icu; icu= icu->next) {
872                                         if (icu->driver && icu->driver->ob) {
873                                                 if (lastadded != icu->driver->ob) {
874                                                         outliner_add_element(soops, &te->subtree, icu->driver->ob, te, TSE_LINKED_OB, 0);
875                                                         lastadded= icu->driver->ob;
876                                                 }
877                                         }
878                                 }
879                         }
880                         break;
881                 case ID_AC:
882                         {
883                                 bAction *act= (bAction *)id;
884                                 bActionChannel *chan;
885                                 int a= 0;
886                                 
887                                 tselem= TREESTORE(parent);
888                                 for (chan=act->chanbase.first; chan; chan=chan->next, a++) {
889                                         outliner_add_element(soops, &te->subtree, chan->ipo, te, 0, a);
890                                 }
891                         }
892                         break;
893                 case ID_AR:
894                         {
895                                 bArmature *arm= (bArmature *)id;
896                                 int a= 0;
897                                 
898                                 if(G.obedit && G.obedit->data==arm) {
899                                         EditBone *ebone;
900                                         TreeElement *ten;
901                                         
902                                         for (ebone = G.edbo.first; ebone; ebone=ebone->next, a++) {
903                                                 ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
904                                                 ten->directdata= ebone;
905                                                 ten->name= ebone->name;
906                                                 ebone->temp= ten;
907                                         }
908                                         /* make hierarchy */
909                                         ten= te->subtree.first;
910                                         while(ten) {
911                                                 TreeElement *nten= ten->next, *par;
912                                                 ebone= (EditBone *)ten->directdata;
913                                                 if(ebone->parent) {
914                                                         BLI_remlink(&te->subtree, ten);
915                                                         par= ebone->parent->temp;
916                                                         BLI_addtail(&par->subtree, ten);
917                                                         ten->parent= par;
918                                                 }
919                                                 ten= nten;
920                                         }
921                                 }
922                                 else {
923                                         /* do not extend Armature when we have posemode */
924                                         tselem= TREESTORE(te->parent);
925                                         if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->flag & OB_POSEMODE);
926                                         else {
927                                                 Bone *curBone;
928                                                 for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
929                                                         outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
930                                                 }
931                                         }
932                                 }
933                         }
934                         break;
935                 }
936         }
937         else if(type==TSE_SEQUENCE) {
938                 Sequence *seq= (Sequence*) idv;
939                 Sequence *p;
940
941                 /*
942                  * The idcode is a little hack, but the outliner
943                  * only check te->idcode if te->type is equal to zero,
944                  * so this is "safe".
945                  */
946                 te->idcode= seq->type;
947                 te->directdata= seq;
948
949                 if(seq->type<7) {
950                         /*
951                          * This work like the sequence.
952                          * If the sequence have a name (not default name)
953                          * show it, in other case put the filename.
954                          */
955                         if(strcmp(seq->name, "SQ"))
956                                 te->name= seq->name;
957                         else {
958                                 if((seq->strip) && (seq->strip->stripdata))
959                                         te->name= seq->strip->stripdata->name;
960                                 else if((seq->strip) && (seq->strip->tstripdata) && (seq->strip->tstripdata->ibuf))
961                                         te->name= seq->strip->tstripdata->ibuf->name;
962                                 else
963                                         te->name= "SQ None";
964                         }
965
966                         if(seq->type==SEQ_META) {
967                                 te->name= "Meta Strip";
968                                 p= seq->seqbase.first;
969                                 while(p) {
970                                         outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index);
971                                         p= p->next;
972                                 }
973                         }
974                         else
975                                 outliner_add_element(soops, &te->subtree, (void*)seq->strip, te, TSE_SEQ_STRIP, index);
976                 }
977                 else
978                         te->name= "Effect";
979         }
980         else if(type==TSE_SEQ_STRIP) {
981                 Strip *strip= (Strip *)idv;
982
983                 if(strip->dir)
984                         te->name= strip->dir;
985                 else
986                         te->name= "Strip None";
987                 te->directdata= strip;
988         }
989         else if(type==TSE_SEQUENCE_DUP) {
990                 Sequence *seq= (Sequence*)idv;
991
992                 te->idcode= seq->type;
993                 te->directdata= seq;
994                 te->name= seq->strip->stripdata->name;
995         }
996         else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
997                 PointerRNA pptr, propptr, *ptr= (PointerRNA*)idv;
998                 PropertyRNA *prop, *iterprop, *nameprop;
999                 PropertyType proptype;
1000                 PropertySubType propsubtype;
1001                 int a, tot;
1002
1003                 /* we do lazy build, for speed and to avoid infinite recusion */
1004
1005                 if(ptr->data == NULL) {
1006                         te->name= "(empty)";
1007                 }
1008                 else if(type == TSE_RNA_STRUCT) {
1009                         /* struct */
1010                         nameprop= RNA_struct_name_property(ptr);
1011
1012                         if(nameprop) {
1013                                 te->name= RNA_property_string_get_alloc(ptr, nameprop, NULL, 0);
1014                                 te->flag |= TE_FREE_NAME;
1015                         }
1016                         else
1017                                 te->name= (char*)RNA_struct_ui_name(ptr);
1018
1019                         iterprop= RNA_struct_iterator_property(ptr);
1020                         tot= RNA_property_collection_length(ptr, iterprop);
1021
1022                         /* auto open these cases */
1023                         if(!parent || (RNA_property_type(&parent->rnaptr, parent->directdata)) == PROP_POINTER)
1024                                 if(!tselem->used)
1025                                         tselem->flag &= ~TSE_CLOSED;
1026
1027                         if(!(tselem->flag & TSE_CLOSED)) {
1028                                 for(a=0; a<tot; a++)
1029                                         outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_PROPERTY, a);
1030                         }
1031                         else if(tot)
1032                                 te->flag |= TE_LAZY_CLOSED;
1033
1034                         te->rnaptr= *ptr;
1035                 }
1036                 else if(type == TSE_RNA_PROPERTY) {
1037                         /* property */
1038                         iterprop= RNA_struct_iterator_property(ptr);
1039                         RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1040
1041                         prop= propptr.data;
1042                         proptype= RNA_property_type(ptr, prop);
1043
1044                         te->name= (char*)RNA_property_ui_name(ptr, prop);
1045                         te->directdata= prop;
1046                         te->rnaptr= *ptr;
1047
1048                         if(proptype == PROP_POINTER) {
1049                                 RNA_property_pointer_get(ptr, prop, &pptr);
1050
1051                                 if(pptr.data) {
1052                                         if(!(tselem->flag & TSE_CLOSED))
1053                                                 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1);
1054                                         else
1055                                                 te->flag |= TE_LAZY_CLOSED;
1056                                 }
1057                         }
1058                         else if(proptype == PROP_COLLECTION) {
1059                                 tot= RNA_property_collection_length(ptr, prop);
1060
1061                                 if(!(tselem->flag & TSE_CLOSED)) {
1062                                         for(a=0; a<tot; a++) {
1063                                                 RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1064                                                 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1);
1065                                         }
1066                                 }
1067                                 else if(tot)
1068                                         te->flag |= TE_LAZY_CLOSED;
1069                         }
1070                         else if(ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1071                                 tot= RNA_property_array_length(ptr, prop);
1072
1073                                 if(!(tselem->flag & TSE_CLOSED)) {
1074                                         for(a=0; a<tot; a++)
1075                                                 outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1076                                 }
1077                                 else if(tot)
1078                                         te->flag |= TE_LAZY_CLOSED;
1079                         }
1080                 }
1081                 else if(type == TSE_RNA_ARRAY_ELEM) {
1082                         /* array property element */
1083                         static char *vectoritem[4]= {"  x", "  y", "  z", "  w"};
1084                         static char *quatitem[4]= {"  w", "  x", "  y", "  z"};
1085                         static char *coloritem[4]= {"  r", "  g", "  b", "  a"};
1086
1087                         prop= parent->directdata;
1088                         proptype= RNA_property_type(ptr, prop);
1089                         propsubtype= RNA_property_subtype(ptr, prop);
1090                         tot= RNA_property_array_length(ptr, prop);
1091
1092                         te->directdata= prop;
1093                         te->rnaptr= *ptr;
1094                         te->index= index;
1095
1096                         if(tot == 4 && propsubtype == PROP_ROTATION)
1097                                 te->name= quatitem[index];
1098                         else if(tot <= 4 && (propsubtype == PROP_VECTOR || propsubtype == PROP_ROTATION))
1099                                 te->name= vectoritem[index];
1100                         else if(tot <= 4 && propsubtype == PROP_COLOR)
1101                                 te->name= coloritem[index];
1102                         else {
1103                                 te->name= MEM_callocN(sizeof(char)*20, "OutlinerRNAArrayName");
1104                                 sprintf(te->name, "  %d", index+1);
1105                                 te->flag |= TE_FREE_NAME;
1106                         }
1107                 }
1108         }
1109
1110         return te;
1111 }
1112
1113 static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb)
1114 {
1115         TreeElement *te, *ten, *tep;
1116         TreeStoreElem *tselem;
1117
1118         /* build hierarchy */
1119         te= lb->first;
1120         while(te) {
1121                 ten= te->next;
1122                 tselem= TREESTORE(te);
1123                 
1124                 if(tselem->type==0 && te->idcode==ID_OB) {
1125                         Object *ob= (Object *)tselem->id;
1126                         if(ob->parent && ob->parent->id.newid) {
1127                                 BLI_remlink(lb, te);
1128                                 tep= (TreeElement *)ob->parent->id.newid;
1129                                 BLI_addtail(&tep->subtree, te);
1130                                 // set correct parent pointers
1131                                 for(te=tep->subtree.first; te; te= te->next) te->parent= tep;
1132                         }
1133                 }
1134                 te= ten;
1135         }
1136 }
1137
1138 /* Helped function to put duplicate sequence in the same tree. */
1139 int need_add_seq_dup(Sequence *seq)
1140 {
1141         Sequence *p;
1142
1143         if((!seq->strip) || (!seq->strip->stripdata) || (!seq->strip->stripdata->name))
1144                 return(1);
1145
1146         /*
1147          * First check backward, if we found a duplicate
1148          * sequence before this, don't need it, just return.
1149          */
1150         p= seq->prev;
1151         while(p) {
1152                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1153                         p= p->prev;
1154                         continue;
1155                 }
1156
1157                 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1158                         return(2);
1159                 p= p->prev;
1160         }
1161
1162         p= seq->next;
1163         while(p) {
1164                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1165                         p= p->next;
1166                         continue;
1167                 }
1168
1169                 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1170                         return(0);
1171                 p= p->next;
1172         }
1173         return(1);
1174 }
1175
1176 void add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index)
1177 {
1178         TreeElement *ch;
1179         Sequence *p;
1180
1181         p= seq;
1182         while(p) {
1183                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1184                         p= p->next;
1185                         continue;
1186                 }
1187
1188                 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1189                         ch= outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index);
1190                 p= p->next;
1191         }
1192 }
1193
1194 static void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
1195 {
1196         Base *base;
1197         Object *ob;
1198         TreeElement *te=NULL, *ten;
1199         TreeStoreElem *tselem;
1200         int show_opened= soops->treestore==NULL; /* on first view, we open scenes */
1201
1202         if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
1203            return;
1204            
1205         outliner_free_tree(&soops->tree);
1206         outliner_storage_cleanup(soops);
1207         
1208         /* clear ob id.new flags */
1209         for(ob= G.main->object.first; ob; ob= ob->id.next) ob->id.newid= NULL;
1210         
1211         /* options */
1212         if(soops->outlinevis == SO_LIBRARIES) {
1213                 Library *lib;
1214                 
1215                 for(lib= G.main->library.first; lib; lib= lib->id.next) {
1216                         ten= outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
1217                         lib->id.newid= (ID *)ten;
1218                 }
1219                 /* make hierarchy */
1220                 ten= soops->tree.first;
1221                 while(ten) {
1222                         TreeElement *nten= ten->next, *par;
1223                         tselem= TREESTORE(ten);
1224                         lib= (Library *)tselem->id;
1225                         if(lib->parent) {
1226                                 BLI_remlink(&soops->tree, ten);
1227                                 par= (TreeElement *)lib->parent->id.newid;
1228                                 BLI_addtail(&par->subtree, ten);
1229                                 ten->parent= par;
1230                         }
1231                         ten= nten;
1232                 }
1233                 /* restore newid pointers */
1234                 for(lib= G.main->library.first; lib; lib= lib->id.next)
1235                         lib->id.newid= NULL;
1236                 
1237         }
1238         else if(soops->outlinevis == SO_ALL_SCENES) {
1239                 Scene *sce;
1240                 for(sce= G.main->scene.first; sce; sce= sce->id.next) {
1241                         te= outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
1242                         tselem= TREESTORE(te);
1243                         if(sce==scene && show_opened) 
1244                                 tselem->flag &= ~TSE_CLOSED;
1245                         
1246                         for(base= sce->base.first; base; base= base->next) {
1247                                 ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
1248                                 ten->directdata= base;
1249                         }
1250                         outliner_make_hierarchy(soops, &te->subtree);
1251                         /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1252                         for(base= sce->base.first; base; base= base->next) base->object->id.newid= NULL;
1253                 }
1254         }
1255         else if(soops->outlinevis == SO_CUR_SCENE) {
1256                 
1257                 outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
1258                 
1259                 for(base= scene->base.first; base; base= base->next) {
1260                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1261                         ten->directdata= base;
1262                 }
1263                 outliner_make_hierarchy(soops, &soops->tree);
1264         }
1265         else if(soops->outlinevis == SO_VISIBLE) {
1266                 for(base= scene->base.first; base; base= base->next) {
1267                         if(base->lay & scene->lay)
1268                                 outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1269                 }
1270                 outliner_make_hierarchy(soops, &soops->tree);
1271         }
1272         else if(soops->outlinevis == SO_GROUPS) {
1273                 Group *group;
1274                 GroupObject *go;
1275                 
1276                 for(group= G.main->group.first; group; group= group->id.next) {
1277                         if(group->id.us) {
1278                                 te= outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
1279                                 tselem= TREESTORE(te);
1280                                 
1281                                 for(go= group->gobject.first; go; go= go->next) {
1282                                         ten= outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
1283                                         ten->directdata= NULL; /* eh, why? */
1284                                 }
1285                                 outliner_make_hierarchy(soops, &te->subtree);
1286                                 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1287                                 for(go= group->gobject.first; go; go= go->next) go->ob->id.newid= NULL;
1288                         }
1289                 }
1290         }
1291         else if(soops->outlinevis == SO_SAME_TYPE) {
1292                 Object *ob= OBACT;
1293                 if(ob) {
1294                         for(base= scene->base.first; base; base= base->next) {
1295                                 if(base->object->type==ob->type) {
1296                                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1297                                         ten->directdata= base;
1298                                 }
1299                         }
1300                         outliner_make_hierarchy(soops, &soops->tree);
1301                 }
1302         }
1303         else if(soops->outlinevis == SO_SELECTED) {
1304                 for(base= scene->base.first; base; base= base->next) {
1305                         if(base->lay & scene->lay) {
1306                                 if(base==BASACT || (base->flag & SELECT)) {
1307                                         ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1308                                         ten->directdata= base;
1309                                 }
1310                         }
1311                 }
1312                 outliner_make_hierarchy(soops, &soops->tree);
1313         }
1314         else if(soops->outlinevis==SO_SEQUENCE) {
1315                 Sequence *seq;
1316                 Editing *ed;
1317                 int op;
1318
1319                 ed= scene->ed;
1320                 if(!ed)
1321                         return;
1322
1323                 seq= ed->seqbasep->first;
1324                 if(!seq)
1325                         return;
1326
1327                 while(seq) {
1328                         op= need_add_seq_dup(seq);
1329                         if(op==1)
1330                                 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE, 0);
1331                         else if(op==0) {
1332                                 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE_DUP, 0);
1333                                 add_seq_dup(soops, seq, ten, 0);
1334                         }
1335                         seq= seq->next;
1336                 }
1337         }
1338         else if(soops->outlinevis==SO_DATABLOCKS) {
1339                 PointerRNA mainptr;
1340
1341                 RNA_main_pointer_create(mainvar, &mainptr);
1342
1343                 ten= outliner_add_element(soops, &soops->tree, (void*)&mainptr, NULL, TSE_RNA_STRUCT, -1);
1344
1345                 if(show_opened)  {
1346                         tselem= TREESTORE(ten);
1347                         tselem->flag &= ~TSE_CLOSED;
1348                 }
1349         }
1350         else if(soops->outlinevis==SO_USERDEF) {
1351                 PointerRNA userdefptr;
1352
1353                 RNA_pointer_create(NULL, NULL, &RNA_UserPreferences, &U, &userdefptr);
1354
1355                 ten= outliner_add_element(soops, &soops->tree, (void*)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
1356
1357                 if(show_opened)  {
1358                         tselem= TREESTORE(ten);
1359                         tselem->flag &= ~TSE_CLOSED;
1360                 }
1361         }
1362         else {
1363                 ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
1364                 if(ten) ten->directdata= BASACT;
1365         }
1366
1367         outliner_sort(soops, &soops->tree);
1368 }
1369
1370 /* **************** INTERACTIVE ************* */
1371
1372 static int outliner_count_levels(SpaceOops *soops, ListBase *lb, int curlevel)
1373 {
1374         TreeElement *te;
1375         int level=curlevel, lev;
1376         
1377         for(te= lb->first; te; te= te->next) {
1378                 
1379                 lev= outliner_count_levels(soops, &te->subtree, curlevel+1);
1380                 if(lev>level) level= lev;
1381         }
1382         return level;
1383 }
1384
1385 static int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel)
1386 {
1387         TreeElement *te;
1388         TreeStoreElem *tselem;
1389         int level;
1390         
1391         for(te= lb->first; te; te= te->next) {
1392                 tselem= TREESTORE(te);
1393                 if(tselem->flag & flag) return curlevel;
1394                 
1395                 level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1);
1396                 if(level) return level;
1397         }
1398         return 0;
1399 }
1400
1401 static void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
1402 {
1403         TreeElement *te;
1404         TreeStoreElem *tselem;
1405         
1406         for(te= lb->first; te; te= te->next) {
1407                 tselem= TREESTORE(te);
1408                 if(set==0) tselem->flag &= ~flag;
1409                 else tselem->flag |= flag;
1410                 outliner_set_flag(soops, &te->subtree, flag, set);
1411         }
1412 }
1413
1414 void object_toggle_visibility_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1415 {
1416         Scene *scene= NULL;             // XXX
1417         Base *base= (Base *)te->directdata;
1418         
1419         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1420         if(base) {
1421                 base->object->restrictflag^=OB_RESTRICT_VIEW;
1422         }
1423 }
1424
1425 void outliner_toggle_visibility(Scene *scene, SpaceOops *soops)
1426 {
1427
1428         outliner_do_object_operation(scene, soops, &soops->tree, object_toggle_visibility_cb);
1429         
1430         BIF_undo_push("Outliner toggle selectability");
1431
1432         allqueue(REDRAWVIEW3D, 1);
1433         allqueue(REDRAWOOPS, 0);
1434         allqueue(REDRAWINFO, 1);
1435 }
1436
1437 static void object_toggle_selectability_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1438 {
1439         Scene *scene= NULL; // XXX
1440         Base *base= (Base *)te->directdata;
1441         
1442         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1443         if(base) {
1444                 base->object->restrictflag^=OB_RESTRICT_SELECT;
1445         }
1446 }
1447
1448 void outliner_toggle_selectability(Scene *scene, SpaceOops *soops)
1449 {
1450         
1451         outliner_do_object_operation(scene, soops, &soops->tree, object_toggle_selectability_cb);
1452         
1453         BIF_undo_push("Outliner toggle selectability");
1454
1455         allqueue(REDRAWVIEW3D, 1);
1456         allqueue(REDRAWOOPS, 0);
1457         allqueue(REDRAWINFO, 1);
1458 }
1459
1460 void object_toggle_renderability_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1461 {
1462         Scene *scene= NULL;     // XXX
1463         Base *base= (Base *)te->directdata;
1464         
1465         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1466         if(base) {
1467                 base->object->restrictflag^=OB_RESTRICT_RENDER;
1468         }
1469 }
1470
1471 void outliner_toggle_renderability(Scene *scene, SpaceOops *soops)
1472 {
1473
1474         outliner_do_object_operation(scene, soops, &soops->tree, object_toggle_renderability_cb);
1475         
1476         BIF_undo_push("Outliner toggle renderability");
1477
1478         allqueue(REDRAWVIEW3D, 1);
1479         allqueue(REDRAWOOPS, 0);
1480         allqueue(REDRAWINFO, 1);
1481 }
1482
1483 void outliner_toggle_visible(SpaceOops *soops)
1484 {
1485         
1486         if( outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
1487                 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
1488         else 
1489                 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
1490
1491         BIF_undo_push("Outliner toggle visible");
1492 }
1493
1494 void outliner_toggle_selected(ARegion *ar, SpaceOops *soops)
1495 {
1496         
1497         if( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
1498                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
1499         else 
1500                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
1501         
1502         BIF_undo_push("Outliner toggle selected");
1503         soops->storeflag |= SO_TREESTORE_REDRAW;
1504 }
1505
1506
1507 static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
1508 {
1509         TreeElement *te;
1510         TreeStoreElem *tselem;
1511         
1512         for(te= lb->first; te; te= te->next) {
1513                 tselem= TREESTORE(te);
1514                 
1515                 if(open) {
1516                         if(curlevel<=level) tselem->flag &= ~TSE_CLOSED;
1517                 }
1518                 else {
1519                         if(curlevel>=level) tselem->flag |= TSE_CLOSED;
1520                 }
1521                 
1522                 outliner_openclose_level(soops, &te->subtree, curlevel+1, level, open);
1523         }
1524 }
1525
1526 /* return 1 when levels were opened */
1527 static int outliner_open_back(SpaceOops *soops, TreeElement *te)
1528 {
1529         TreeStoreElem *tselem;
1530         int retval= 0;
1531         
1532         for (te= te->parent; te; te= te->parent) {
1533                 tselem= TREESTORE(te);
1534                 if (tselem->flag & TSE_CLOSED) { 
1535                         tselem->flag &= ~TSE_CLOSED;
1536                         retval= 1;
1537                 }
1538         }
1539         return retval;
1540 }
1541
1542 /* This is not used anywhere at the moment */
1543 #if 0
1544 static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
1545 {
1546         TreeElement *te;
1547         TreeStoreElem *tselem;
1548         
1549         for (te= lb->first; te; te= te->next) {
1550                 /* check if this tree-element was the one we're seeking */
1551                 if (te == teFind) {
1552                         *found= 1;
1553                         return;
1554                 }
1555                 
1556                 /* try to see if sub-tree contains it then */
1557                 outliner_open_reveal(soops, &te->subtree, teFind, found);
1558                 if (*found) {
1559                         tselem= TREESTORE(te);
1560                         if (tselem->flag & TSE_CLOSED) 
1561                                 tselem->flag &= ~TSE_CLOSED;
1562                         return;
1563                 }
1564         }
1565 }
1566 #endif
1567
1568 void outliner_one_level(SpaceOops *soops, int add)
1569 {
1570         int level;
1571         
1572         level= outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
1573         if(add==1) {
1574                 if(level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
1575         }
1576         else {
1577                 if(level==0) level= outliner_count_levels(soops, &soops->tree, 0);
1578                 if(level) outliner_openclose_level(soops, &soops->tree, 1, level-1, 0);
1579         }
1580         
1581         BIF_undo_push("Outliner show/hide one level");
1582 }
1583
1584 void outliner_page_up_down(Scene *scene, ARegion *ar, SpaceOops *soops, int up)
1585 {
1586         int dy= ar->v2d.mask.ymax-ar->v2d.mask.ymin;
1587         
1588         if(up == -1) dy= -dy;
1589         ar->v2d.cur.ymin+= dy;
1590         ar->v2d.cur.ymax+= dy;
1591         
1592         soops->storeflag |= SO_TREESTORE_REDRAW;
1593 }
1594
1595 /* **** do clicks on items ******* */
1596
1597 static int tree_element_active_renderlayer(TreeElement *te, TreeStoreElem *tselem, int set)
1598 {
1599         Scene *sce;
1600         
1601         /* paranoia check */
1602         if(te->idcode!=ID_SCE)
1603                 return 0;
1604         sce= (Scene *)tselem->id;
1605         
1606         if(set) {
1607                 sce->r.actlay= tselem->nr;
1608                 allqueue(REDRAWBUTSSCENE, 0);
1609         }
1610         else {
1611                 return sce->r.actlay==tselem->nr;
1612         }
1613         return 0;
1614 }
1615
1616 static void tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te)
1617 {
1618         TreeStoreElem *tselem= TREESTORE(te);
1619         Scene *sce;
1620         Base *base;
1621         Object *ob= NULL;
1622         int shift= 0; // XXX
1623         
1624         /* if id is not object, we search back */
1625         if(te->idcode==ID_OB) ob= (Object *)tselem->id;
1626         else {
1627                 ob= (Object *)outliner_search_back(soops, te, ID_OB);
1628                 if(ob==OBACT) return;
1629         }
1630         if(ob==NULL) return;
1631         
1632         sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
1633         if(sce && scene != sce) {
1634 // XXX          if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1635                 set_scene(sce);
1636         }
1637         
1638         /* find associated base in current scene */
1639         for(base= FIRSTBASE; base; base= base->next) 
1640                 if(base->object==ob) break;
1641         if(base) {
1642                 if(shift) {
1643                         /* swap select */
1644                         if(base->flag & SELECT)
1645                                 ED_base_object_select(base, BA_DESELECT);
1646                         else 
1647                                 ED_base_object_select(base, BA_SELECT);
1648                 }
1649                 else {
1650                         Base *b;
1651                         /* deleselect all */
1652                         for(b= FIRSTBASE; b; b= b->next) {
1653                                 b->flag &= ~SELECT;
1654                                 b->object->flag= b->flag;
1655                         }
1656                         ED_base_object_select(base, BA_SELECT);
1657                 }
1658                 if(C)
1659                         ED_base_object_activate(C, base); /* adds notifier */
1660         }
1661         
1662 // XXX  if(ob!=G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1663 //      else countall(); /* exit_editmode calls f() */
1664 }
1665
1666 static int tree_element_active_material(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1667 {
1668         TreeElement *tes;
1669         Object *ob;
1670         
1671         /* we search for the object parent */
1672         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1673         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1674         
1675         /* searching in ob mat array? */
1676         tes= te->parent;
1677         if(tes->idcode==ID_OB) {
1678                 if(set) {
1679                         ob->actcol= te->index+1;
1680                         ob->colbits |= (1<<te->index);  // make ob material active too
1681                 }
1682                 else {
1683                         if(ob->actcol == te->index+1) 
1684                                 if(ob->colbits & (1<<te->index)) return 1;
1685                 }
1686         }
1687         /* or we search for obdata material */
1688         else {
1689                 if(set) {
1690                         ob->actcol= te->index+1;
1691                         ob->colbits &= ~(1<<te->index); // make obdata material active too
1692                 }
1693                 else {
1694                         if(ob->actcol == te->index+1)
1695                                 if( (ob->colbits & (1<<te->index))==0 ) return 1;
1696                 }
1697         }
1698         if(set) {
1699 // XXX          extern_set_butspace(F5KEY, 0);  // force shading buttons
1700                 BIF_preview_changed(ID_MA);
1701                 allqueue(REDRAWBUTSSHADING, 1);
1702                 allqueue(REDRAWNODE, 0);
1703                 allqueue(REDRAWOOPS, 0);
1704                 allqueue(REDRAWIPO, 0);
1705         }
1706         return 0;
1707 }
1708
1709 static int tree_element_active_texture(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1710 {
1711         TreeElement *tep;
1712         TreeStoreElem *tselem, *tselemp;
1713         Object *ob=OBACT;
1714         SpaceButs *sbuts=NULL;
1715         
1716         if(ob==NULL) return 0; // no active object
1717         
1718         tselem= TREESTORE(te);
1719         
1720         /* find buttons area (note, this is undefined really still, needs recode in blender) */
1721         /* XXX removed finding sbuts */
1722         
1723         /* where is texture linked to? */
1724         tep= te->parent;
1725         tselemp= TREESTORE(tep);
1726         
1727         if(tep->idcode==ID_WO) {
1728                 World *wrld= (World *)tselemp->id;
1729
1730                 if(set) {
1731                         if(sbuts) {
1732                                 sbuts->tabo= TAB_SHADING_TEX;   // hack from header_buttonswin.c
1733                                 sbuts->texfrom= 1;
1734                         }
1735 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1736                         wrld->texact= te->index;
1737                 }
1738                 else if(tselemp->id == (ID *)(scene->world)) {
1739                         if(wrld->texact==te->index) return 1;
1740                 }
1741         }
1742         else if(tep->idcode==ID_LA) {
1743                 Lamp *la= (Lamp *)tselemp->id;
1744                 if(set) {
1745                         if(sbuts) {
1746                                 sbuts->tabo= TAB_SHADING_TEX;   // hack from header_buttonswin.c
1747                                 sbuts->texfrom= 2;
1748                         }
1749 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1750                         la->texact= te->index;
1751                 }
1752                 else {
1753                         if(tselemp->id == ob->data) {
1754                                 if(la->texact==te->index) return 1;
1755                         }
1756                 }
1757         }
1758         else if(tep->idcode==ID_MA) {
1759                 Material *ma= (Material *)tselemp->id;
1760                 if(set) {
1761                         if(sbuts) {
1762                                 //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
1763                                 sbuts->texfrom= 0;
1764                         }
1765 // XXX                  extern_set_butspace(F6KEY, 0);  // force shading buttons texture
1766                         ma->texact= (char)te->index;
1767                         
1768                         /* also set active material */
1769                         ob->actcol= tep->index+1;
1770                 }
1771                 else if(tep->flag & TE_ACTIVE) {        // this is active material
1772                         if(ma->texact==te->index) return 1;
1773                 }
1774         }
1775         
1776         return 0;
1777 }
1778
1779
1780 static int tree_element_active_lamp(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1781 {
1782         Object *ob;
1783         
1784         /* we search for the object parent */
1785         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1786         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1787         
1788         if(set) {
1789 // XXX          extern_set_butspace(F5KEY, 0);
1790                 BIF_preview_changed(ID_LA);
1791                 allqueue(REDRAWBUTSSHADING, 1);
1792                 allqueue(REDRAWOOPS, 0);
1793                 allqueue(REDRAWIPO, 0);
1794         }
1795         else return 1;
1796         
1797         return 0;
1798 }
1799
1800 static int tree_element_active_world(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1801 {
1802         TreeElement *tep;
1803         TreeStoreElem *tselem=NULL;
1804         Scene *sce=NULL;
1805         
1806         tep= te->parent;
1807         if(tep) {
1808                 tselem= TREESTORE(tep);
1809                 sce= (Scene *)tselem->id;
1810         }
1811         
1812         if(set) {       // make new scene active
1813                 if(sce && scene != sce) {
1814 // XXX                  if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
1815                         set_scene(sce);
1816                 }
1817         }
1818         
1819         if(tep==NULL || tselem->id == (ID *)scene) {
1820                 if(set) {
1821 // XXX                  extern_set_butspace(F8KEY, 0);
1822                 }
1823                 else {
1824                         return 1;
1825                 }
1826         }
1827         return 0;
1828 }
1829
1830 static int tree_element_active_ipo(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1831 {
1832         TreeElement *tes;
1833         TreeStoreElem *tselems=NULL;
1834         Object *ob;
1835         
1836         /* we search for the object parent */
1837         ob= (Object *)outliner_search_back(soops, te, ID_OB);
1838         if(ob==NULL || ob!=OBACT) return 0;     // just paranoia
1839         
1840         /* the parent of ipo */
1841         tes= te->parent;
1842         tselems= TREESTORE(tes);
1843         
1844         if(set) {
1845                 if(tes->idcode==ID_AC) {
1846                         if(ob->ipoflag & OB_ACTION_OB)
1847                                 ob->ipowin= ID_OB;
1848                         else if(ob->ipoflag & OB_ACTION_KEY)
1849                                 ob->ipowin= ID_KE;
1850                         else 
1851                                 ob->ipowin= ID_PO;
1852                 }
1853                 else ob->ipowin= tes->idcode;
1854                 
1855                 if(ob->ipowin==ID_MA) tree_element_active_material(scene, soops, tes, 1);
1856                 else if(ob->ipowin==ID_AC) {
1857                         bActionChannel *chan;
1858                         short a=0;
1859                         for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
1860                                 if(a==te->index) break;
1861                                 if(chan->ipo) a++;
1862                         }
1863 // XXX                  deselect_actionchannels(ob->action, 0);
1864 //                      if (chan)
1865 //                              select_channel(ob->action, chan, SELECT_ADD);
1866                         allqueue(REDRAWACTION, ob->ipowin);
1867                         allqueue(REDRAWVIEW3D, ob->ipowin);
1868                 }
1869                 
1870                 allqueue(REDRAWIPO, ob->ipowin);
1871         }
1872         else {
1873                 if(tes->idcode==ID_AC) {
1874                         if(ob->ipoflag & OB_ACTION_OB)
1875                                 return ob->ipowin==ID_OB;
1876                         else if(ob->ipoflag & OB_ACTION_KEY)
1877                                 return ob->ipowin==ID_KE;
1878                         else if(ob->ipowin==ID_AC) {
1879                                 bActionChannel *chan;
1880                                 short a=0;
1881                                 for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
1882                                         if(a==te->index) break;
1883                                         if(chan->ipo) a++;
1884                                 }
1885 // XXX                          if(chan==get_hilighted_action_channel(ob->action)) return 1;
1886                         }
1887                 }
1888                 else if(ob->ipowin==tes->idcode) {
1889                         if(ob->ipowin==ID_MA) {
1890                                 Material *ma= give_current_material(ob, ob->actcol);
1891                                 if(ma==(Material *)tselems->id) return 1;
1892                         }
1893                         else return 1;
1894                 }
1895         }
1896         return 0;
1897 }       
1898
1899 static int tree_element_active_defgroup(Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
1900 {
1901         Object *ob;
1902         
1903         /* id in tselem is object */
1904         ob= (Object *)tselem->id;
1905         if(set) {
1906                 ob->actdef= te->index+1;
1907                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
1908                 allqueue(REDRAWVIEW3D, ob->ipowin);
1909         }
1910         else {
1911                 if(ob==OBACT)
1912                         if(ob->actdef== te->index+1) return 1;
1913         }
1914         return 0;
1915 }
1916
1917 static int tree_element_active_nla_action(TreeElement *te, TreeStoreElem *tselem, int set)
1918 {
1919         if(set) {
1920                 bActionStrip *strip= te->directdata;
1921                 if(strip) {
1922 // XXX                  deselect_nlachannel_keys(0);
1923                         strip->flag |= ACTSTRIP_SELECT;
1924                         allqueue(REDRAWNLA, 0);
1925                 }
1926         }
1927         else {
1928                 /* id in tselem is action */
1929                 bActionStrip *strip= te->directdata;
1930                 if(strip) {
1931                         if(strip->flag & ACTSTRIP_SELECT) return 1;
1932                 }
1933         }
1934         return 0;
1935 }
1936
1937 static int tree_element_active_posegroup(Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
1938 {
1939         Object *ob= (Object *)tselem->id;
1940         
1941         if(set) {
1942                 if (ob->pose) {
1943                         ob->pose->active_group= te->index+1;
1944                         allqueue(REDRAWBUTSEDIT, 0);
1945                 }
1946         }
1947         else {
1948                 if(ob==OBACT && ob->pose) {
1949                         if (ob->pose->active_group== te->index+1) return 1;
1950                 }
1951         }
1952         return 0;
1953 }
1954
1955 static int tree_element_active_posechannel(Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
1956 {
1957         Object *ob= (Object *)tselem->id;
1958         bPoseChannel *pchan= te->directdata;
1959         
1960         if(set) {
1961                 if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
1962                         
1963 // XXX                  if(G.qual & LR_SHIFTKEY) deselectall_posearmature(ob, 2, 0);    // 2 = clear active tag
1964 //                      else deselectall_posearmature(ob, 0, 0);        // 0 = deselect 
1965                         pchan->bone->flag |= BONE_SELECTED|BONE_ACTIVE;
1966                         
1967                         allqueue(REDRAWVIEW3D, 0);
1968                         allqueue(REDRAWOOPS, 0);
1969                         allqueue(REDRAWACTION, 0);
1970                 }
1971         }
1972         else {
1973                 if(ob==OBACT && ob->pose) {
1974                         if (pchan->bone->flag & BONE_SELECTED) return 1;
1975                 }
1976         }
1977         return 0;
1978 }
1979
1980 static int tree_element_active_bone(Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
1981 {
1982         bArmature *arm= (bArmature *)tselem->id;
1983         Bone *bone= te->directdata;
1984         
1985         if(set) {
1986                 if(!(bone->flag & BONE_HIDDEN_P)) {
1987 // XXX                  if(G.qual & LR_SHIFTKEY) deselectall_posearmature(OBACT, 2, 0); // 2 is clear active tag
1988 //                      else deselectall_posearmature(OBACT, 0, 0);
1989                         bone->flag |= BONE_SELECTED|BONE_ACTIVE;
1990                         
1991                         allqueue(REDRAWVIEW3D, 0);
1992                         allqueue(REDRAWOOPS, 0);
1993                         allqueue(REDRAWACTION, 0);
1994                 }
1995         }
1996         else {
1997                 Object *ob= OBACT;
1998                 
1999                 if(ob && ob->data==arm) {
2000                         if (bone->flag & BONE_SELECTED) return 1;
2001                 }
2002         }
2003         return 0;
2004 }
2005
2006
2007 /* ebones only draw in editmode armature */
2008 static int tree_element_active_ebone(TreeElement *te, TreeStoreElem *tselem, int set)
2009 {
2010         EditBone *ebone= te->directdata;
2011 //      int shift= 0; // XXX
2012         
2013         if(set) {
2014                 if(!(ebone->flag & BONE_HIDDEN_A)) {
2015                         
2016 // XXX                  if(shift) deselectall_armature(2, 0);   // only clear active tag
2017 //                      else deselectall_armature(0, 0);        // deselect
2018
2019                         ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL|BONE_ACTIVE;
2020                         // flush to parent?
2021                         if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
2022                         
2023                         allqueue(REDRAWVIEW3D, 0);
2024                         allqueue(REDRAWOOPS, 0);
2025                         allqueue(REDRAWACTION, 0);
2026                 }
2027         }
2028         else {
2029                 if (ebone->flag & BONE_SELECTED) return 1;
2030         }
2031         return 0;
2032 }
2033
2034 static int tree_element_active_modifier(TreeElement *te, TreeStoreElem *tselem, int set)
2035 {
2036         if(set) {
2037 // XXX          extern_set_butspace(F9KEY, 0);
2038         }
2039         
2040         return 0;
2041 }
2042
2043 static int tree_element_active_psys(TreeElement *te, TreeStoreElem *tselem, int set)
2044 {
2045         if(set) {
2046 //              Object *ob= (Object *)tselem->id;
2047 //              ParticleSystem *psys= te->directdata;
2048                 
2049 // XXX          PE_change_act_psys(ob, psys);
2050 // XXX          extern_set_butspace(F7KEY, 0);
2051         }
2052         
2053         return 0;
2054 }
2055
2056 static int tree_element_active_constraint(TreeElement *te, TreeStoreElem *tselem, int set)
2057 {
2058         if(set) {
2059 // XXX          extern_set_butspace(F7KEY, 0);
2060         }
2061         
2062         return 0;
2063 }
2064
2065 static int tree_element_active_text(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
2066 {
2067         // XXX removed
2068         return 0;
2069 }
2070
2071 /* generic call for ID data check or make/check active in UI */
2072 static int tree_element_active(Scene *scene, SpaceOops *soops, TreeElement *te, int set)
2073 {
2074
2075         switch(te->idcode) {
2076                 case ID_MA:
2077                         return tree_element_active_material(scene, soops, te, set);
2078                 case ID_WO:
2079                         return tree_element_active_world(scene, soops, te, set);
2080                 case ID_LA:
2081                         return tree_element_active_lamp(scene, soops, te, set);
2082                 case ID_IP:
2083                         return tree_element_active_ipo(scene, soops, te, set);
2084                 case ID_TE:
2085                         return tree_element_active_texture(scene, soops, te, set);
2086                 case ID_TXT:
2087                         return tree_element_active_text(scene, soops, te, set);
2088         }
2089         return 0;
2090 }
2091
2092 static int tree_element_active_pose(TreeElement *te, TreeStoreElem *tselem, int set)
2093 {
2094         Object *ob= (Object *)tselem->id;
2095         
2096         if(set) {
2097 // XXX          if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2098 //              if(ob->flag & OB_POSEMODE) exit_posemode();
2099 //              else enter_posemode();
2100         }
2101         else {
2102                 if(ob->flag & OB_POSEMODE) return 1;
2103         }
2104         return 0;
2105 }
2106
2107 static int tree_element_active_sequence(TreeElement *te, TreeStoreElem *tselem, int set)
2108 {
2109         Sequence *seq= (Sequence*) te->directdata;
2110
2111         if(set) {
2112 // XXX          select_single_seq(seq, 1);
2113                 allqueue(REDRAWSEQ, 0);
2114         }
2115         else {
2116                 if(seq->flag & SELECT)
2117                         return(1);
2118         }
2119         return(0);
2120 }
2121
2122 static int tree_element_active_sequence_dup(Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2123 {
2124         Sequence *seq, *p;
2125         Editing *ed;
2126
2127         seq= (Sequence*)te->directdata;
2128         if(set==0) {
2129                 if(seq->flag & SELECT)
2130                         return(1);
2131                 return(0);
2132         }
2133
2134 // XXX  select_single_seq(seq, 1);
2135         ed= scene->ed;
2136         p= ed->seqbasep->first;
2137         while(p) {
2138                 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
2139                         p= p->next;
2140                         continue;
2141                 }
2142
2143 //              if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
2144 // XXX                  select_single_seq(p, 0);
2145                 p= p->next;
2146         }
2147         allqueue(REDRAWSEQ, 0);
2148         return(0);
2149 }
2150
2151 /* generic call for non-id data to make/check active in UI */
2152 /* Context can be NULL when set==0 */
2153 static int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
2154 {
2155         
2156         switch(tselem->type) {
2157                 case TSE_NLA_ACTION:
2158                         return tree_element_active_nla_action(te, tselem, set);
2159                 case TSE_DEFGROUP:
2160                         return tree_element_active_defgroup(scene, te, tselem, set);
2161                 case TSE_BONE:
2162                         return tree_element_active_bone(scene, te, tselem, set);
2163                 case TSE_EBONE:
2164                         return tree_element_active_ebone(te, tselem, set);
2165                 case TSE_MODIFIER:
2166                         return tree_element_active_modifier(te, tselem, set);
2167                 case TSE_LINKED_OB:
2168                         if(set) tree_element_set_active_object(C, scene, soops, te);
2169                         else if(tselem->id==(ID *)OBACT) return 1;
2170                         break;
2171                 case TSE_LINKED_PSYS:
2172                         return tree_element_active_psys(te, tselem, set);
2173                         break;
2174                 case TSE_POSE_BASE:
2175                         return tree_element_active_pose(te, tselem, set);
2176                         break;
2177                 case TSE_POSE_CHANNEL:
2178                         return tree_element_active_posechannel(scene, te, tselem, set);
2179                 case TSE_CONSTRAINT:
2180                         return tree_element_active_constraint(te, tselem, set);
2181                 case TSE_R_LAYER:
2182                         return tree_element_active_renderlayer(te, tselem, set);
2183                 case TSE_POSEGRP:
2184                         return tree_element_active_posegroup(scene, te, tselem, set);
2185                 case TSE_SEQUENCE:
2186                         return tree_element_active_sequence(te, tselem, set);
2187                         break;
2188                 case TSE_SEQUENCE_DUP:
2189                         return tree_element_active_sequence_dup(scene, te, tselem, set);
2190                         break;
2191         }
2192         return 0;
2193 }
2194
2195 static int do_outliner_mouse_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, short event, float *mval)
2196 {
2197         int shift= 0, ctrl= 0; // XXX
2198         
2199         if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
2200                 TreeStoreElem *tselem= TREESTORE(te);
2201                 int openclose= 0;
2202
2203                 /* open close icon, three things to check */
2204                 if(event==RETKEY || event==PADENTER) openclose= 1; // enter opens/closes always
2205                 else if((te->flag & TE_ICONROW)==0) {                           // hidden icon, no open/close
2206                         if( mval[0]>te->xs && mval[0]<te->xs+OL_X) openclose= 1;
2207                 }
2208
2209                 if(openclose) {
2210                         
2211                         /* all below close/open? */
2212                         if(shift) {
2213                                 tselem->flag &= ~TSE_CLOSED;
2214                                 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
2215                         }
2216                         else {
2217                                 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
2218                                 else tselem->flag |= TSE_CLOSED;
2219                                 
2220                         }
2221                         
2222                         return 1;
2223                 }
2224                 /* name and first icon */
2225                 else if(mval[0]>te->xs && mval[0]<te->xend) {
2226                         
2227                         /* activate a name button? */
2228                         if(event==LEFTMOUSE) {
2229                         
2230                                 if (ctrl) {
2231                                         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)) 
2232                                                 error("Cannot edit builtin name");
2233                                         else if(ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP))
2234                                                 error("Cannot edit sequence name");
2235                                         else if(tselem->id->lib) {
2236 // XXX                                          error_libdata();
2237                                         } else if(te->idcode == ID_LI && te->parent) {
2238                                                 error("Cannot edit the path of an indirectly linked library");
2239                                         } else {
2240                                                 tselem->flag |= TSE_TEXTBUT;
2241                                         }
2242                                 } else {
2243                                         /* always makes active object */
2244                                         if(tselem->type!=TSE_SEQUENCE && tselem->type!=TSE_SEQ_STRIP && tselem->type!=TSE_SEQUENCE_DUP)
2245                                                 tree_element_set_active_object(C, scene, soops, te);
2246                                         
2247                                         if(tselem->type==0) { // the lib blocks
2248                                                 /* editmode? */
2249                                                 if(te->idcode==ID_SCE) {
2250                                                         if(scene!=(Scene *)tselem->id) {
2251 // XXX                                                          if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2252                                                                 set_scene((Scene *)tselem->id);
2253                                                         }
2254                                                 }
2255                                                 else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
2256 // XXX                                                  if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2257 //                                                      else {
2258 //                                                              enter_editmode(EM_WAITCURSOR);
2259 //                                                              extern_set_butspace(F9KEY, 0);
2260 //                                              }
2261                                                 } else {        // rest of types
2262                                                         tree_element_active(scene, soops, te, 1);
2263                                                 }
2264                                                 
2265                                         }
2266                                         else tree_element_type_active(C, scene, soops, te, tselem, 1);
2267                                 }
2268                         }
2269                         else if(event==RIGHTMOUSE) {
2270                                 /* select object that's clicked on and popup context menu */
2271                                 if (!(tselem->flag & TSE_SELECTED)) {
2272                                 
2273                                         if ( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) )
2274                                                 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
2275                                 
2276                                         tselem->flag |= TSE_SELECTED;
2277                                         /* redraw, same as outliner_select function */
2278                                         soops->storeflag |= SO_TREESTORE_REDRAW;
2279 // XXX                                  screen_swapbuffers();
2280                                 }
2281                                 
2282                                 outliner_operation_menu(scene, ar, soops);
2283                         }
2284                         return 1;
2285                 }
2286         }
2287         
2288         for(te= te->subtree.first; te; te= te->next) {
2289                 if(do_outliner_mouse_event(C, scene, ar, soops, te, event, mval)) return 1;
2290         }
2291         return 0;
2292 }
2293
2294 /* event can enterkey, then it opens/closes */
2295 static int outliner_activate_click(bContext *C, wmOperator *op, wmEvent *event)
2296 {
2297         Scene *scene= CTX_data_scene(C);
2298         ARegion *ar= CTX_wm_region(C);
2299         SpaceOops *soops= (SpaceOops*)CTX_wm_space_data(C);
2300         TreeElement *te;
2301         float fmval[2];
2302         
2303         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, fmval, fmval+1);
2304         
2305         for(te= soops->tree.first; te; te= te->next) {
2306                 if(do_outliner_mouse_event(C, scene, ar, soops, te, event->type, fmval)) break;
2307         }
2308         
2309         if(te) {
2310                 BIF_undo_push("Outliner click event");
2311         }
2312         else 
2313                 outliner_select(ar, soops);
2314         
2315         ED_region_tag_redraw(ar);
2316
2317         return OPERATOR_FINISHED;
2318 }
2319
2320 void OUTLINER_OT_activate_click(wmOperatorType *ot)
2321 {
2322         ot->name= "Activate Click";
2323         ot->idname= "OUTLINER_OT_activate_click";
2324         
2325         ot->invoke= outliner_activate_click;
2326         
2327         ot->poll= ED_operator_outliner_active;
2328 }
2329
2330
2331
2332 /* recursive helper for function below */
2333 static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
2334 {
2335         TreeStoreElem *tselem= TREESTORE(te);
2336         
2337         /* store coord and continue, we need coordinates for elements outside view too */
2338         te->xs= (float)startx;
2339         te->ys= (float)(*starty);
2340         *starty-= OL_H;
2341         
2342         if((tselem->flag & TSE_CLOSED)==0) {
2343                 TreeElement *ten;
2344                 for(ten= te->subtree.first; ten; ten= ten->next) {
2345                         outliner_set_coordinates_element(soops, ten, startx+OL_X, starty);
2346                 }
2347         }
2348         
2349 }
2350
2351 /* to retrieve coordinates with redrawing the entire tree */
2352 static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
2353 {
2354         TreeElement *te;
2355         int starty= (int)(ar->v2d.tot.ymax)-OL_H;
2356         int startx= 0;
2357         
2358         for(te= soops->tree.first; te; te= te->next) {
2359                 outliner_set_coordinates_element(soops, te, startx, &starty);
2360         }
2361 }
2362
2363 static TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
2364 {
2365         TreeElement *te, *tes;
2366         TreeStoreElem *tselem;
2367         
2368         for(te= lb->first; te; te= te->next) {
2369                 tselem= TREESTORE(te);
2370                 if(tselem->type==0) {
2371                         if(tselem->id==id) return te;
2372                         /* only deeper on scene or object */
2373                         if( te->idcode==ID_OB || te->idcode==ID_SCE) { 
2374                                 tes= outliner_find_id(soops, &te->subtree, id);
2375                                 if(tes) return tes;
2376                         }
2377                 }
2378         }
2379         return NULL;
2380 }
2381
2382 void outliner_show_active(Scene *scene, ARegion *ar, SpaceOops *so)
2383 {
2384         TreeElement *te;
2385         int xdelta, ytop;
2386         
2387         if(OBACT == NULL) return;
2388         
2389         te= outliner_find_id(so, &so->tree, (ID *)OBACT);
2390         if(te) {
2391                 /* make te->ys center of view */
2392                 ytop= (int)(te->ys + (ar->v2d.mask.ymax-ar->v2d.mask.ymin)/2);
2393                 if(ytop>0) ytop= 0;
2394                 ar->v2d.cur.ymax= (float)ytop;
2395                 ar->v2d.cur.ymin= (float)(ytop-(ar->v2d.mask.ymax-ar->v2d.mask.ymin));
2396                 
2397                 /* make te->xs ==> te->xend center of view */
2398                 xdelta = (int)(te->xs - ar->v2d.cur.xmin);
2399                 ar->v2d.cur.xmin += xdelta;
2400                 ar->v2d.cur.xmax += xdelta;
2401                 
2402                 so->storeflag |= SO_TREESTORE_REDRAW;
2403         }
2404 }
2405
2406 void outliner_show_selected(Scene *scene, ARegion *ar, SpaceOops *so)
2407 {
2408         TreeElement *te;
2409         int xdelta, ytop;
2410         
2411         te= outliner_find_id(so, &so->tree, (ID *)OBACT);
2412         if(te) {
2413                 /* make te->ys center of view */
2414                 ytop= (int)(te->ys + (ar->v2d.mask.ymax-ar->v2d.mask.ymin)/2);
2415                 if(ytop>0) ytop= 0;
2416                 ar->v2d.cur.ymax= (float)ytop;
2417                 ar->v2d.cur.ymin= (float)(ytop-(ar->v2d.mask.ymax-ar->v2d.mask.ymin));
2418                 
2419                 /* make te->xs ==> te->xend center of view */
2420                 xdelta = (int)(te->xs - ar->v2d.cur.xmin);
2421                 ar->v2d.cur.xmin += xdelta;
2422                 ar->v2d.cur.xmax += xdelta;
2423                 
2424                 so->storeflag |= SO_TREESTORE_REDRAW;
2425         }
2426 }
2427
2428
2429 /* find next element that has this name */
2430 static TreeElement *outliner_find_named(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound)
2431 {
2432         TreeElement *te, *tes;
2433         
2434         for (te= lb->first; te; te= te->next) {
2435                 int found;
2436                 
2437                 /* determine if match */
2438                 if(flags==OL_FIND)
2439                         found= BLI_strcasestr(te->name, name)!=NULL;
2440                 else if(flags==OL_FIND_CASE)
2441                         found= strstr(te->name, name)!=NULL;
2442                 else if(flags==OL_FIND_COMPLETE)
2443                         found= BLI_strcasecmp(te->name, name)==0;
2444                 else
2445                         found= strcmp(te->name, name)==0;
2446                 
2447                 if(found) {
2448                         /* name is right, but is element the previous one? */
2449                         if (prev) {
2450                                 if ((te != prev) && (*prevFound)) 
2451                                         return te;
2452                                 if (te == prev) {
2453                                         *prevFound = 1;
2454                                 }
2455                         }
2456                         else
2457                                 return te;
2458                 }
2459                 
2460                 tes= outliner_find_named(soops, &te->subtree, name, flags, prev, prevFound);
2461                 if(tes) return tes;
2462         }
2463
2464         /* nothing valid found */
2465         return NULL;
2466 }
2467
2468 /* tse is not in the treestore, we use its contents to find a match */
2469 static TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
2470 {
2471         TreeStore *ts= soops->treestore;
2472         TreeStoreElem *tselem;
2473         int a;
2474         
2475         if(tse->id==NULL) return NULL;
2476         
2477         /* check if 'tse' is in treestore */
2478         tselem= ts->data;
2479         for(a=0; a<ts->usedelem; a++, tselem++) {
2480                 if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) {
2481                         if(tselem->id==tse->id) {
2482                                 break;
2483                         }
2484                 }
2485         }
2486         if(tselem) 
2487                 return outliner_find_tree_element(&soops->tree, a);
2488         
2489         return NULL;
2490 }
2491
2492
2493 /* Called to find an item based on name.
2494  */
2495 void outliner_find_panel(Scene *scene, ARegion *ar, SpaceOops *soops, int again, int flags) 
2496 {
2497         TreeElement *te= NULL;
2498         TreeElement *last_find;
2499         TreeStoreElem *tselem;
2500         int ytop, xdelta, prevFound=0;
2501         char name[33];
2502         
2503         /* get last found tree-element based on stored search_tse */
2504         last_find= outliner_find_tse(soops, &soops->search_tse);
2505         
2506         /* determine which type of search to do */
2507         if (again && last_find) {
2508                 /* no popup panel - previous + user wanted to search for next after previous */         
2509                 BLI_strncpy(name, soops->search_string, 33);
2510                 flags= soops->search_flags;
2511                 
2512                 /* try to find matching element */
2513                 te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2514                 if (te==NULL) {
2515                         /* no more matches after previous, start from beginning again */
2516                         prevFound= 1;
2517                         te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2518                 }
2519         }
2520         else {
2521                 /* pop up panel - no previous, or user didn't want search after previous */
2522                 strcpy(name, "");
2523 // XXX          if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
2524 //                      te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound);
2525 //              }
2526 //              else return; /* XXX RETURN! XXX */
2527         }
2528
2529         /* do selection and reveil */
2530         if (te) {
2531                 tselem= TREESTORE(te);
2532                 if (tselem) {
2533                         /* expand branches so that it will be visible, we need to get correct coordinates */
2534                         if( outliner_open_back(soops, te))
2535                                 outliner_set_coordinates(ar, soops);
2536                         
2537                         /* deselect all visible, and select found element */
2538                         outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
2539                         tselem->flag |= TSE_SELECTED;
2540                         
2541                         /* make te->ys center of view */
2542                         ytop= (int)(te->ys + (ar->v2d.mask.ymax-ar->v2d.mask.ymin)/2);
2543                         if(ytop>0) ytop= 0;
2544                         ar->v2d.cur.ymax= (float)ytop;
2545                         ar->v2d.cur.ymin= (float)(ytop-(ar->v2d.mask.ymax-ar->v2d.mask.ymin));
2546                         
2547                         /* make te->xs ==> te->xend center of view */
2548                         xdelta = (int)(te->xs - ar->v2d.cur.xmin);
2549                         ar->v2d.cur.xmin += xdelta;
2550                         ar->v2d.cur.xmax += xdelta;
2551                         
2552                         /* store selection */
2553                         soops->search_tse= *tselem;
2554                         
2555                         BLI_strncpy(soops->search_string, name, 33);
2556                         soops->search_flags= flags;
2557                         
2558                         /* redraw */
2559                         soops->storeflag |= SO_TREESTORE_REDRAW;
2560                 }
2561         }
2562         else {
2563                 /* no tree-element found */
2564                 error("Not found: %s", name);
2565         }
2566 }
2567
2568 static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
2569 {
2570         TreeElement *te;
2571         TreeStoreElem *tselem;
2572         
2573         for(te= lb->first; te; te= te->next) {
2574                 tselem= TREESTORE(te);
2575                 if(tselem->type==0 && te->idcode==ID_OB) return 1;
2576                 if( subtree_has_objects(soops, &te->subtree)) return 1;
2577         }
2578         return 0;
2579 }
2580
2581 static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase *lb)
2582 {
2583         TreeElement *te;
2584         TreeStoreElem *tselem;
2585
2586         /* open all object elems, close others */
2587         for(te= lb->first; te; te= te->next) {
2588                 tselem= TREESTORE(te);
2589                 
2590                 if(tselem->type==0) {
2591                         if(te->idcode==ID_SCE) {
2592                                 if(tselem->id!=(ID *)scene) tselem->flag |= TSE_CLOSED;
2593                                         else tselem->flag &= ~TSE_CLOSED;
2594                         }
2595                         else if(te->idcode==ID_OB) {
2596                                 if(subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
2597                                 else tselem->flag |= TSE_CLOSED;
2598                         }
2599                 }
2600                 else tselem->flag |= TSE_CLOSED;
2601
2602                 if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(scene, soops, &te->subtree);
2603         }
2604         
2605 }
2606
2607 /* show entire object level hierarchy */
2608 void outliner_show_hierarchy(Scene *scene, SpaceOops *soops)
2609 {
2610         
2611         tree_element_show_hierarchy(scene, soops, &soops->tree);
2612         
2613         BIF_undo_push("Outliner show hierarchy");
2614 }
2615
2616 #if 0
2617 static void do_outliner_select(SpaceOops *soops, ListBase *lb, float y1, float y2, short *selecting)
2618 {
2619         TreeElement *te;
2620         TreeStoreElem *tselem;
2621         
2622         if(y1>y2) SWAP(float, y1, y2);
2623         
2624         for(te= lb->first; te; te= te->next) {
2625                 tselem= TREESTORE(te);
2626                 
2627                 if(te->ys + OL_H < y1) return;
2628                 if(te->ys < y2) {
2629                         if((te->flag & TE_ICONROW)==0) {
2630                                 if(*selecting == -1) {
2631                                         if( tselem->flag & TSE_SELECTED) *selecting= 0;
2632                                         else *selecting= 1;
2633                                 }
2634                                 if(*selecting) tselem->flag |= TSE_SELECTED;
2635                                 else tselem->flag &= ~TSE_SELECTED;
2636                         }
2637                 }
2638                 if((tselem->flag & TSE_CLOSED)==0) do_outliner_select(soops, &te->subtree, y1, y2, selecting);
2639         }
2640 }
2641 #endif
2642
2643 /* its own redraw loop... urm */
2644 void outliner_select(ARegion *ar, SpaceOops *so)
2645 {
2646 #if 0
2647         XXX
2648         float fmval[2], y1, y2;
2649         short yo=-1, selecting= -1;
2650         
2651         UI_view2d_region_to_view(&ar->v2d, event->x, event->y, fmval, fmval+1);
2652         
2653         y1= fmval[1];
2654
2655         while (get_mbut() & (L_MOUSE|R_MOUSE)) {
2656                 UI_view2d_region_to_view(&ar->v2d, event->x, event->y, fmval, fmval+1);
2657                 y2= fmval[1];
2658                 
2659                 if(yo!=mval[1]) {
2660                         /* select the 'ouliner row' */
2661                         do_outliner_select(so, &so->tree, y1, y2, &selecting);
2662                         yo= mval[1];
2663                         
2664                         so->storeflag |= SO_TREESTORE_REDRAW;
2665 // XXX                  screen_swapbuffers();
2666                 
2667                         y1= y2;
2668                 }
2669                 else PIL_sleep_ms(30);
2670         }
2671         
2672         BIF_undo_push("Outliner selection");
2673 #endif
2674 }
2675
2676 /* ************ SELECTION OPERATIONS ********* */
2677
2678 static void set_operation_types(SpaceOops *soops, ListBase *lb,
2679                                 int *scenelevel,
2680                                 int *objectlevel,
2681                                 int *idlevel,
2682                                 int *datalevel)
2683 {
2684         TreeElement *te;
2685         TreeStoreElem *tselem;
2686         
2687         for(te= lb->first; te; te= te->next) {
2688                 tselem= TREESTORE(te);
2689                 if(tselem->flag & TSE_SELECTED) {
2690                         if(tselem->type) {
2691                                 if(tselem->type==TSE_SEQUENCE)
2692                                         *datalevel= TSE_SEQUENCE;
2693                                 else if(tselem->type==TSE_SEQ_STRIP)
2694                                         *datalevel= TSE_SEQ_STRIP;
2695                                 else if(tselem->type==TSE_SEQUENCE_DUP)
2696                                         *datalevel= TSE_SEQUENCE_DUP;
2697                                 else if(*datalevel!=tselem->type) *datalevel= -1;
2698                         }
2699                         else {
2700                                 int idcode= GS(tselem->id->name);
2701                                 switch(idcode) {
2702                                         case ID_SCE:
2703                                                 *scenelevel= 1;
2704                                                 break;
2705                                         case ID_OB:
2706                                                 *objectlevel= 1;
2707                                                 break;
2708                                                 
2709                                         case ID_ME: case ID_CU: case ID_MB: case ID_LT:
2710                                         case ID_LA: case ID_AR: case ID_CA:
2711                                         case ID_MA: case ID_TE: case ID_IP: case ID_IM:
2712                                         case ID_SO: case ID_KE: case ID_WO: case ID_AC:
2713                                         case ID_NLA: case ID_TXT: case ID_GR:
2714                                                 if(*idlevel==0) *idlevel= idcode;
2715                                                 else if(*idlevel!=idcode) *idlevel= -1;
2716                                                         break;
2717                                 }
2718                         }
2719                 }
2720                 if((tselem->flag & TSE_CLOSED)==0) {
2721                         set_operation_types(soops, &te->subtree,
2722                                                                 scenelevel, objectlevel, idlevel, datalevel);
2723                 }
2724         }
2725 }
2726
2727 static void unlink_material_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2728 {
2729         Material **matar=NULL;
2730         int a, totcol=0;
2731         
2732         if( GS(tsep->id->name)==ID_OB) {
2733                 Object *ob= (Object *)tsep->id;
2734                 totcol= ob->totcol;
2735                 matar= ob->mat;
2736         }
2737         else if( GS(tsep->id->name)==ID_ME) {
2738                 Mesh *me= (Mesh *)tsep->id;
2739                 totcol= me->totcol;
2740                 matar= me->mat;
2741         }
2742         else if( GS(tsep->id->name)==ID_CU) {
2743                 Curve *cu= (Curve *)tsep->id;
2744                 totcol= cu->totcol;
2745                 matar= cu->mat;
2746         }
2747         else if( GS(tsep->id->name)==ID_MB) {
2748                 MetaBall *mb= (MetaBall *)tsep->id;
2749                 totcol= mb->totcol;
2750                 matar= mb->mat;
2751         }
2752
2753         for(a=0; a<totcol; a++) {
2754                 if(a==te->index && matar[a]) {
2755                         matar[a]->id.us--;
2756                         matar[a]= NULL;
2757                 }
2758         }
2759 }
2760
2761 static void unlink_texture_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2762 {
2763         MTex **mtex= NULL;
2764         int a;
2765         
2766         if( GS(tsep->id->name)==ID_MA) {
2767                 Material *ma= (Material *)tsep->id;
2768                 mtex= ma->mtex;
2769         }
2770         else if( GS(tsep->id->name)==ID_LA) {
2771                 Lamp *la= (Lamp *)tsep->id;
2772                 mtex= la->mtex;
2773         }
2774         else if( GS(tsep->id->name)==ID_WO) {
2775                 World *wrld= (World *)tsep->id;
2776                 mtex= wrld->mtex;
2777         }
2778         else return;
2779         
2780         for(a=0; a<MAX_MTEX; a++) {
2781                 if(a==te->index && mtex[a]) {
2782                         if(mtex[a]->tex) {
2783                                 mtex[a]->tex->id.us--;
2784                                 mtex[a]->tex= NULL;
2785                         }
2786                 }
2787         }
2788 }
2789
2790 static void unlink_group_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2791 {
2792         Group *group= (Group *)tselem->id;
2793         
2794         if(tsep) {
2795                 if( GS(tsep->id->name)==ID_OB) {
2796                         Object *ob= (Object *)tsep->id;
2797                         ob->dup_group= NULL;
2798                         group->id.us--;
2799                 }
2800         }
2801         else {
2802                 unlink_group(group);
2803         }
2804 }
2805
2806 static void outliner_do_libdata_operation(SpaceOops *soops, ListBase *lb, 
2807                                                                                  void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
2808 {
2809         TreeElement *te;
2810         TreeStoreElem *tselem;
2811         
2812         for(te=lb->first; te; te= te->next) {
2813                 tselem= TREESTORE(te);
2814                 if(tselem->flag & TSE_SELECTED) {
2815                         if(tselem->type==0) {
2816                                 TreeStoreElem *tsep= TREESTORE(te->parent);
2817                                 operation_cb(te, tsep, tselem);
2818                         }
2819                 }
2820                 if((tselem->flag & TSE_CLOSED)==0) {
2821                         outliner_do_libdata_operation(soops, &te->subtree, operation_cb);
2822                 }
2823         }
2824 }
2825
2826 /* */
2827
2828 static void object_select_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2829 {
2830         Scene *scene= NULL;     // XXX
2831         Base *base= (Base *)te->directdata;
2832         
2833         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
2834         if(base && ((base->object->restrictflag & OB_RESTRICT_VIEW)==0)) {
2835                 base->flag |= SELECT;
2836                 base->object->flag |= SELECT;
2837         }
2838 }
2839
2840 static void object_deselect_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2841 {
2842         Scene *scene= NULL;
2843         Base *base= (Base *)te->directdata;
2844         
2845         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
2846         if(base) {
2847                 base->flag &= ~SELECT;
2848                 base->object->flag &= ~SELECT;
2849         }
2850 }
2851
2852 static void object_delete_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2853 {
2854         Scene *scene= NULL;
2855         Base *base= (Base *)te->directdata;
2856         
2857         if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
2858         if(base) {
2859                 // check also library later
2860 // XXX          if(G.obedit==base->object) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
2861                 
2862                 if(base==BASACT) {
2863                         G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT+G_SCULPTMODE);
2864 // XXX                  setcursor_space(SPACE_VIEW3D, CURSOR_STD);
2865                 }
2866                 
2867 // XXX          free_and_unlink_base(base);
2868                 te->directdata= NULL;
2869                 tselem->id= NULL;
2870         }
2871 }
2872
2873 static void id_local_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2874 {
2875         if(tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
2876                 tselem->id->lib= NULL;
2877                 tselem->id->flag= LIB_LOCAL;
2878                 new_id(0, tselem->id, 0);
2879         }
2880 }
2881
2882 static void group_linkobs2scene_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
2883 {
2884         Scene *scene= NULL;
2885         Group *group= (Group *)tselem->id;
2886         GroupObject *gob;
2887         Base *base;
2888         
2889         for(gob=group->gobject.first; gob; gob=gob->next) {
2890                 base= object_in_scene(gob->ob, scene);
2891                 if (base) {
2892                         base->object->flag |= SELECT;
2893                         base->flag |= SELECT;
2894                 } else {
2895                         /* link to scene */
2896                         base= MEM_callocN( sizeof(Base), "add_base");
2897                         BLI_addhead(&scene->base, base);
2898                         base->lay= (1<<20)-1; /*v3d->lay;*/ /* would be nice to use the 3d layer but the include's not here */
2899                         gob->ob->flag |= SELECT;
2900                         base->flag = gob->ob->flag;
2901                         base->object= gob->ob;
2902                         id_lib_extern((ID *)gob->ob); /* incase these are from a linked group */
2903                 }
2904         }
2905 }
2906
2907 static void outliner_do_object_operation(Scene *scene, SpaceOops *soops, ListBase *lb, 
2908                                                                                  void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
2909 {
2910         TreeElement *te;
2911         TreeStoreElem *tselem;
2912         
2913         for(te=lb->first; te; te= te->next) {
2914                 tselem= TREESTORE(te);
2915                 if(tselem->flag & TSE_SELECTED) {
2916                         if(tselem->type==0 && te->idcode==ID_OB) {
2917                                 // when objects selected in other scenes... dunno if that should be allowed