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