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