4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2004 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
34 #include "MEM_guardedalloc.h"
36 #include "DNA_anim_types.h"
37 #include "DNA_action_types.h"
38 #include "DNA_armature_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_camera_types.h"
42 #include "DNA_image_types.h"
43 #include "DNA_ipo_types.h"
44 #include "DNA_group_types.h"
45 #include "DNA_key_types.h"
46 #include "DNA_lamp_types.h"
47 #include "DNA_material_types.h"
48 #include "DNA_mesh_types.h"
49 #include "DNA_meta_types.h"
50 #include "DNA_modifier_types.h"
51 #include "DNA_nla_types.h"
52 #include "DNA_object_types.h"
53 #include "DNA_outliner_types.h"
54 #include "DNA_particle_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_texture_types.h"
59 #include "DNA_text_types.h"
60 #include "DNA_world_types.h"
61 #include "DNA_sequence_types.h"
63 #include "BLI_blenlib.h"
65 #include "IMB_imbuf_types.h"
67 #include "BKE_animsys.h"
68 #include "BKE_constraint.h"
69 #include "BKE_context.h"
70 #include "BKE_deform.h"
71 #include "BKE_depsgraph.h"
72 #include "BKE_fcurve.h"
73 #include "BKE_global.h"
74 #include "BKE_group.h"
75 #include "BKE_library.h"
77 #include "BKE_material.h"
78 #include "BKE_modifier.h"
79 #include "BKE_object.h"
80 #include "BKE_report.h"
81 #include "BKE_screen.h"
82 #include "BKE_scene.h"
83 #include "BKE_sequencer.h"
84 #include "BKE_utildefines.h"
86 #include "ED_armature.h"
87 #include "ED_object.h"
88 #include "ED_screen.h"
96 #include "BIF_glutil.h"
98 #include "UI_interface.h"
99 #include "UI_interface_icons.h"
100 #include "UI_resources.h"
101 #include "UI_view2d.h"
103 #include "RNA_access.h"
104 #include "RNA_define.h"
106 #include "ED_armature.h"
107 #include "ED_keyframing.h"
108 #include "ED_object.h"
109 #include "ED_particle.h"
110 #include "ED_screen.h"
111 #include "ED_view3d.h"
113 #include "outliner_intern.h"
115 #include "PIL_time.h"
121 #define OL_TOG_RESTRICT_VIEWX 54
122 #define OL_TOG_RESTRICT_SELECTX 36
123 #define OL_TOG_RESTRICT_RENDERX 18
125 #define OL_TOGW OL_TOG_RESTRICT_VIEWX
127 #define OL_RNA_COLX 300
128 #define OL_RNA_COL_SIZEX 150
129 #define OL_RNA_COL_SPACEX 50
133 #define TREESTORE(a) ((a)?soops->treestore->data+(a)->store_index:NULL)
135 /* ************* XXX **************** */
137 static void error() {}
139 /* ********************************** */
142 /* ******************** PROTOTYPES ***************** */
143 static void outliner_draw_tree_element(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int startx, int *starty);
144 static void outliner_do_object_operation(bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
145 void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *));
148 /* ******************** PERSISTANT DATA ***************** */
150 static void outliner_storage_cleanup(SpaceOops *soops)
152 TreeStore *ts= soops->treestore;
155 TreeStoreElem *tselem;
158 /* each element used once, for ID blocks with more users to have each a treestore */
159 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) tselem->used= 0;
161 /* cleanup only after reading file or undo step, and always for
162 * RNA datablocks view in order to save memory */
163 if(soops->storeflag & SO_TREESTORE_CLEANUP) {
165 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
166 if(tselem->id==NULL) unused++;
170 if(ts->usedelem == unused) {
173 ts->usedelem= ts->totelem= 0;
176 TreeStoreElem *tsnewar, *tsnew;
178 tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem");
179 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
187 ts->usedelem-= unused;
188 ts->totelem= ts->usedelem;
195 static void check_persistant(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
198 TreeStoreElem *tselem;
201 /* case 1; no TreeStore */
202 if(soops->treestore==NULL) {
203 ts= soops->treestore= MEM_callocN(sizeof(TreeStore), "treestore");
205 ts= soops->treestore;
207 /* check if 'te' is in treestore */
209 for(a=0; a<ts->usedelem; a++, tselem++) {
210 if(tselem->id==id && tselem->used==0) {
211 if((type==0 && tselem->type==0) ||(tselem->type==type && tselem->nr==nr)) {
219 /* add 1 element to treestore */
220 if(ts->usedelem==ts->totelem) {
221 TreeStoreElem *tsnew;
223 tsnew= MEM_mallocN((ts->totelem+TS_CHUNK)*sizeof(TreeStoreElem), "treestore data");
225 memcpy(tsnew, ts->data, ts->totelem*sizeof(TreeStoreElem));
229 ts->totelem+= TS_CHUNK;
232 tselem= ts->data+ts->usedelem;
235 if(type) tselem->nr= nr; // we're picky! :)
239 tselem->flag= TSE_CLOSED;
240 te->store_index= ts->usedelem;
245 /* ******************** TREE MANAGEMENT ****************** */
247 void outliner_free_tree(ListBase *lb)
251 TreeElement *te= lb->first;
253 outliner_free_tree(&te->subtree);
256 if(te->flag & TE_FREE_NAME) MEM_freeN(te->name);
261 static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
263 TreeElement *te= lb->first;
265 TreeStoreElem *tselem= TREESTORE(te);
266 if((tselem->flag & TSE_CLOSED)==0)
267 outliner_height(soops, &te->subtree, h);
273 #if 0 // XXX this is currently disabled until te->xend is set correctly
274 static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
276 TreeElement *te= lb->first;
278 // TreeStoreElem *tselem= TREESTORE(te);
280 // XXX fixme... te->xend is not set yet
281 if(tselem->flag & TSE_CLOSED) {
285 outliner_width(soops, &te->subtree, w);
291 static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int startx)
293 TreeElement *te= lb->first;
295 TreeStoreElem *tselem= TREESTORE(te);
296 // XXX fixme... (currently, we're using a fixed length of 100)!
304 if((tselem->flag & TSE_CLOSED)==0)
305 outliner_rna_width(soops, &te->subtree, w, startx+OL_X);
310 static TreeElement *outliner_find_tree_element(ListBase *lb, int store_index)
312 TreeElement *te= lb->first, *tes;
314 if(te->store_index==store_index) return te;
315 tes= outliner_find_tree_element(&te->subtree, store_index);
324 static ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode)
326 TreeStoreElem *tselem;
330 tselem= TREESTORE(te);
331 if(tselem->type==0 && te->idcode==idcode) return tselem->id;
344 static int treesort_alpha(const void *v1, const void *v2)
346 const struct treesort *x1= v1, *x2= v2;
349 /* first put objects last (hierarchy) */
350 comp= (x1->idcode==ID_OB);
351 if(x2->idcode==ID_OB) comp+=2;
353 if(comp==1) return 1;
354 else if(comp==2) return -1;
356 int comp= strcmp(x1->name, x2->name);
358 if( comp>0 ) return 1;
359 else if( comp<0) return -1;
365 /* this is nice option for later? doesnt look too useful... */
367 static int treesort_obtype_alpha(const void *v1, const void *v2)
369 const struct treesort *x1= v1, *x2= v2;
371 /* first put objects last (hierarchy) */
372 if(x1->idcode==ID_OB && x2->idcode!=ID_OB) return 1;
373 else if(x2->idcode==ID_OB && x1->idcode!=ID_OB) return -1;
375 /* 2nd we check ob type */
376 if(x1->idcode==ID_OB && x2->idcode==ID_OB) {
377 if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
378 else if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
382 int comp= strcmp(x1->name, x2->name);
384 if( comp>0 ) return 1;
385 else if( comp<0) return -1;
392 /* sort happens on each subtree individual */
393 static void outliner_sort(SpaceOops *soops, ListBase *lb)
396 TreeStoreElem *tselem;
401 tselem= TREESTORE(te);
403 /* sorting rules; only object lists or deformgroups */
404 if( (tselem->type==TSE_DEFGROUP) || (tselem->type==0 && te->idcode==ID_OB)) {
407 for(te= lb->first; te; te= te->next) totelem++;
410 struct treesort *tear= MEM_mallocN(totelem*sizeof(struct treesort), "tree sort array");
411 struct treesort *tp=tear;
414 for(te= lb->first; te; te= te->next, tp++) {
415 tselem= TREESTORE(te);
418 tp->idcode= te->idcode;
419 if(tselem->type && tselem->type!=TSE_DEFGROUP) tp->idcode= 0; // dont sort this
422 /* keep beginning of list */
423 for(tp= tear, skip=0; skip<totelem; skip++, tp++)
424 if(tp->idcode) break;
427 qsort(tear+skip, totelem-skip, sizeof(struct treesort), treesort_alpha);
429 lb->first=lb->last= NULL;
432 BLI_addtail(lb, tp->te);
439 for(te= lb->first; te; te= te->next) {
440 outliner_sort(soops, &te->subtree);
444 /* Prototype, see functions below */
445 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
446 TreeElement *parent, short type, short index);
449 static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
451 TreeStoreElem *tselem= TREESTORE(tenla);
454 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_COMBINED);
455 te->name= "Combined";
456 te->directdata= &srl->passflag;
458 /* save cpu cycles, but we add the first to invoke an open/close triangle */
459 if(tselem->flag & TSE_CLOSED)
462 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_Z);
464 te->directdata= &srl->passflag;
466 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_VECTOR);
468 te->directdata= &srl->passflag;
470 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_NORMAL);
472 te->directdata= &srl->passflag;
474 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_UV);
476 te->directdata= &srl->passflag;
478 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_MIST);
480 te->directdata= &srl->passflag;
482 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_INDEXOB);
483 te->name= "Index Object";
484 te->directdata= &srl->passflag;
486 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RGBA);
488 te->directdata= &srl->passflag;
490 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_DIFFUSE);
492 te->directdata= &srl->passflag;
494 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SPEC);
495 te->name= "Specular";
496 te->directdata= &srl->passflag;
498 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SHADOW);
500 te->directdata= &srl->passflag;
502 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_AO);
504 te->directdata= &srl->passflag;
506 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFLECT);
507 te->name= "Reflection";
508 te->directdata= &srl->passflag;
510 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFRACT);
511 te->name= "Refraction";
512 te->directdata= &srl->passflag;
514 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RADIO);
515 te->name= "Radiosity";
516 te->directdata= &srl->passflag;
521 /* special handling of hierarchical non-lib data */
522 static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
523 TreeElement *parent, int *a)
525 TreeElement *te= outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
528 te->name= curBone->name;
529 te->directdata= curBone;
531 for(curBone= curBone->childbase.first; curBone; curBone=curBone->next) {
532 outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
536 static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
538 SceneRenderLayer *srl;
539 TreeElement *tenla= outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
542 tenla->name= "RenderLayers";
543 for(a=0, srl= sce->r.layers.first; srl; srl= srl->next, a++) {
544 TreeElement *tenlay= outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
545 tenlay->name= srl->name;
546 tenlay->directdata= &srl->passflag;
548 if(srl->light_override)
549 outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
550 if(srl->mat_override)
551 outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
553 outliner_add_passes(soops, tenlay, &sce->id, srl);
556 outliner_add_element(soops, lb, sce->world, te, 0, 0);
559 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
560 TreeElement *parent, short type, short index)
563 TreeStoreElem *tselem;
567 if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
568 id= ((PointerRNA*)idv)->id.data;
569 if(!id) id= ((PointerRNA*)idv)->data;
572 if(id==NULL) return NULL;
574 te= MEM_callocN(sizeof(TreeElement), "tree elem");
575 /* add to the visual tree */
577 /* add to the storage */
578 check_persistant(soops, te, id, type, index);
579 tselem= TREESTORE(te);
582 te->index= index; // for data arays
583 if(ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP));
584 else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM));
585 else if(type==TSE_ANIM_DATA);
587 te->name= id->name+2; // default, can be overridden by Library or non-ID data
588 te->idcode= GS(id->name);
593 /* tuck pointer back in object, to construct hierarchy */
594 if(GS(id->name)==ID_OB) id->newid= (ID *)te;
596 /* expand specific data always */
597 switch(GS(id->name)) {
599 te->name= ((Library *)id)->name;
602 outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
606 Object *ob= (Object *)id;
608 outliner_add_element(soops, &te->subtree, ob->adt, te, TSE_ANIM_DATA, 0);
609 outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
611 if(ob->proxy && ob->id.lib==NULL)
612 outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
614 outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
617 bArmature *arm= ob->data;
620 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
624 if(arm->edbo==NULL && (ob->mode & OB_MODE_POSE)) { // channels undefined in editmode, but we want the 'tenla' pose icon itself
625 int a= 0, const_index= 1000; /* ensure unique id for bone constraints */
627 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
628 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
629 ten->name= pchan->name;
630 ten->directdata= pchan;
631 pchan->prev= (bPoseChannel *)ten;
633 if(pchan->constraints.first) {
637 TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
640 tenla1->name= "Constraints";
641 for(con= pchan->constraints.first; con; con= con->next, const_index++) {
642 ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
643 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
644 target= get_constraint_target(con, &str);
645 if(str && str[0]) ten1->name= str;
646 else if(target) ten1->name= target->id.name+2;
647 else ten1->name= con->name;
649 ten1->name= con->name;
650 ten1->directdata= con;
651 /* possible add all other types links? */
656 ten= tenla->subtree.first;
658 TreeElement *nten= ten->next, *par;
659 tselem= TREESTORE(ten);
660 if(tselem->type==TSE_POSE_CHANNEL) {
661 pchan= (bPoseChannel *)ten->directdata;
663 BLI_remlink(&tenla->subtree, ten);
664 par= (TreeElement *)pchan->parent->prev;
665 BLI_addtail(&par->subtree, ten);
671 /* restore prev pointers */
672 pchan= ob->pose->chanbase.first;
673 if(pchan) pchan->prev= NULL;
674 for(; pchan; pchan= pchan->next) {
675 if(pchan->next) pchan->next->prev= pchan;
680 if(ob->pose->agroups.first) {
683 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
686 tenla->name= "Bone Groups";
687 for (agrp=ob->pose->agroups.first; agrp; agrp=agrp->next, a++) {
688 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a);
689 ten->name= agrp->name;
690 ten->directdata= agrp;
695 for(a=0; a<ob->totcol; a++)
696 outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
698 if(ob->constraints.first) {
702 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
706 tenla->name= "Constraints";
707 for(con= ob->constraints.first; con; con= con->next, a++) {
708 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
709 #if 0 /* disabled due to constraints system targets recode... code here needs review */
710 target= get_constraint_target(con, &str);
711 if(str && str[0]) ten->name= str;
712 else if(target) ten->name= target->id.name+2;
713 else ten->name= con->name;
715 ten->name= con->name;
716 ten->directdata= con;
717 /* possible add all other types links? */
721 if(ob->modifiers.first) {
723 TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
726 temod->name = "Modifiers";
727 for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
728 TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
732 if (md->type==eModifierType_Lattice) {
733 outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
734 } else if (md->type==eModifierType_Curve) {
735 outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0);
736 } else if (md->type==eModifierType_Armature) {
737 outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0);
738 } else if (md->type==eModifierType_Hook) {
739 outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0);
740 } else if (md->type==eModifierType_ParticleSystem) {
742 ParticleSystem *psys= ((ParticleSystemModifierData*) md)->psys;
744 ten = outliner_add_element(soops, &te->subtree, ob, te, TSE_LINKED_PSYS, 0);
745 ten->directdata = psys;
746 ten->name = psys->part->id.name+2;
750 if(ob->defbase.first) {
751 bDeformGroup *defgroup;
753 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
756 tenla->name= "Vertex Groups";
757 for (defgroup=ob->defbase.first; defgroup; defgroup=defgroup->next, a++) {
758 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
759 ten->name= defgroup->name;
760 ten->directdata= defgroup;
765 outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
771 Mesh *me= (Mesh *)id;
773 //outliner_add_element(soops, &te->subtree, me->adt, te, TSE_ANIM_DATA, 0);
775 outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
776 for(a=0; a<me->totcol; a++)
777 outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
778 /* could do tfaces with image links, but the images are not grouped nicely.
779 would require going over all tfaces, sort images in use. etc... */
784 Curve *cu= (Curve *)id;
786 outliner_add_element(soops, &te->subtree, cu->adt, te, TSE_ANIM_DATA, 0);
788 for(a=0; a<cu->totcol; a++)
789 outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
794 MetaBall *mb= (MetaBall *)id;
795 for(a=0; a<mb->totcol; a++)
796 outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
801 Material *ma= (Material *)id;
803 outliner_add_element(soops, &te->subtree, ma->adt, te, TSE_ANIM_DATA, 0);
805 for(a=0; a<MAX_MTEX; a++) {
806 if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
814 outliner_add_element(soops, &te->subtree, tex->adt, te, TSE_ANIM_DATA, 0);
815 outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
820 Camera *ca= (Camera *)id;
821 outliner_add_element(soops, &te->subtree, ca->adt, te, TSE_ANIM_DATA, 0);
826 Lamp *la= (Lamp *)id;
828 outliner_add_element(soops, &te->subtree, la->adt, te, TSE_ANIM_DATA, 0);
830 for(a=0; a<MAX_MTEX; a++) {
831 if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
837 World *wrld= (World *)id;
839 outliner_add_element(soops, &te->subtree, wrld->adt, te, TSE_ANIM_DATA, 0);
841 for(a=0; a<MAX_MTEX; a++) {
842 if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
850 outliner_add_element(soops, &te->subtree, key->adt, te, TSE_ANIM_DATA, 0);
855 // XXX do we want to be exposing the F-Curves here?
856 //bAction *act= (bAction *)id;
861 bArmature *arm= (bArmature *)id;
868 for (ebone = arm->edbo->first; ebone; ebone=ebone->next, a++) {
869 ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
870 ten->directdata= ebone;
871 ten->name= ebone->name;
875 ten= te->subtree.first;
877 TreeElement *nten= ten->next, *par;
878 ebone= (EditBone *)ten->directdata;
880 BLI_remlink(&te->subtree, ten);
881 par= ebone->parent->temp;
882 BLI_addtail(&par->subtree, ten);
889 /* do not extend Armature when we have posemode */
890 tselem= TREESTORE(te->parent);
891 if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE);
894 for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
895 outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
903 else if(type==TSE_ANIM_DATA) {
904 AnimData *adt= (AnimData *)idv;
906 /* this element's info */
907 te->name= "Animation";
910 outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
913 if (adt->drivers.first) {
914 TreeElement *ted= outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
918 ted->name= "Drivers";
920 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
921 if (fcu->driver && fcu->driver->variables.first) {
922 ChannelDriver *driver= fcu->driver;
925 for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
926 /* loop over all targets used here */
927 DRIVER_TARGETS_USED_LOOPER(dvar)
929 if (lastadded != dtar->id) {
930 // XXX this lastadded check is rather lame, and also fails quite badly...
931 outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
935 DRIVER_TARGETS_LOOPER_END
942 if (adt->nla_tracks.first) {
943 TreeElement *tenla= outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
947 tenla->name= "NLA Tracks";
949 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
950 TreeElement *tenlt= outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
955 tenlt->name= nlt->name;
957 for (strip=nlt->strips.first; strip; strip=strip->next, b++) {
958 ten= outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
959 if(ten) ten->directdata= strip;
964 else if(type==TSE_SEQUENCE) {
965 Sequence *seq= (Sequence*) idv;
969 * The idcode is a little hack, but the outliner
970 * only check te->idcode if te->type is equal to zero,
973 te->idcode= seq->type;
978 * This work like the sequence.
979 * If the sequence have a name (not default name)
980 * show it, in other case put the filename.
982 if(strcmp(seq->name, "SQ"))
985 if((seq->strip) && (seq->strip->stripdata))
986 te->name= seq->strip->stripdata->name;
987 else if((seq->strip) && (seq->strip->tstripdata) && (seq->strip->tstripdata->ibuf))
988 te->name= seq->strip->tstripdata->ibuf->name;
993 if(seq->type==SEQ_META) {
994 te->name= "Meta Strip";
995 p= seq->seqbase.first;
997 outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index);
1002 outliner_add_element(soops, &te->subtree, (void*)seq->strip, te, TSE_SEQ_STRIP, index);
1007 else if(type==TSE_SEQ_STRIP) {
1008 Strip *strip= (Strip *)idv;
1011 te->name= strip->dir;
1013 te->name= "Strip None";
1014 te->directdata= strip;
1016 else if(type==TSE_SEQUENCE_DUP) {
1017 Sequence *seq= (Sequence*)idv;
1019 te->idcode= seq->type;
1020 te->directdata= seq;
1021 te->name= seq->strip->stripdata->name;
1023 else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
1024 PointerRNA pptr, propptr, *ptr= (PointerRNA*)idv;
1025 PropertyRNA *prop, *iterprop;
1026 PropertyType proptype;
1029 /* we do lazy build, for speed and to avoid infinite recusion */
1031 if(ptr->data == NULL) {
1032 te->name= "(empty)";
1034 else if(type == TSE_RNA_STRUCT) {
1036 te->name= RNA_struct_name_get_alloc(ptr, NULL, 0);
1039 te->flag |= TE_FREE_NAME;
1041 te->name= (char*)RNA_struct_ui_name(ptr->type);
1043 iterprop= RNA_struct_iterator_property(ptr->type);
1044 tot= RNA_property_collection_length(ptr, iterprop);
1046 /* auto open these cases */
1047 if(!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
1049 tselem->flag &= ~TSE_CLOSED;
1051 if(!(tselem->flag & TSE_CLOSED)) {
1052 for(a=0; a<tot; a++)
1053 outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_PROPERTY, a);
1056 te->flag |= TE_LAZY_CLOSED;
1060 else if(type == TSE_RNA_PROPERTY) {
1062 iterprop= RNA_struct_iterator_property(ptr->type);
1063 RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1066 proptype= RNA_property_type(prop);
1068 te->name= (char*)RNA_property_ui_name(prop);
1069 te->directdata= prop;
1072 if(proptype == PROP_POINTER) {
1073 pptr= RNA_property_pointer_get(ptr, prop);
1076 if(!(tselem->flag & TSE_CLOSED))
1077 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1);
1079 te->flag |= TE_LAZY_CLOSED;
1082 else if(proptype == PROP_COLLECTION) {
1083 tot= RNA_property_collection_length(ptr, prop);
1085 if(!(tselem->flag & TSE_CLOSED)) {
1086 for(a=0; a<tot; a++) {
1087 RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1088 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1);
1092 te->flag |= TE_LAZY_CLOSED;
1094 else if(ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1095 tot= RNA_property_array_length(ptr, prop);
1097 if(!(tselem->flag & TSE_CLOSED)) {
1098 for(a=0; a<tot; a++)
1099 outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1102 te->flag |= TE_LAZY_CLOSED;
1105 else if(type == TSE_RNA_ARRAY_ELEM) {
1108 prop= parent->directdata;
1110 te->directdata= prop;
1114 c= RNA_property_array_item_char(prop, index);
1116 te->name= MEM_callocN(sizeof(char)*20, "OutlinerRNAArrayName");
1117 if(c) sprintf(te->name, " %c", c);
1118 else sprintf(te->name, " %d", index+1);
1119 te->flag |= TE_FREE_NAME;
1122 else if(type == TSE_KEYMAP) {
1123 wmKeyMap *km= (wmKeyMap *)idv;
1125 char opname[OP_MAX_TYPENAME];
1127 te->directdata= idv;
1128 te->name= km->idname;
1130 if(!(tselem->flag & TSE_CLOSED)) {
1133 for (kmi= km->items.first; kmi; kmi= kmi->next, a++) {
1134 const char *key= WM_key_event_string(kmi->type);
1137 wmOperatorType *ot= NULL;
1140 else ot= WM_operatortype_find(kmi->idname, 0);
1142 if(ot || kmi->propvalue) {
1143 TreeElement *ten= outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a);
1145 ten->directdata= kmi;
1147 if(kmi->propvalue) {
1148 ten->name= "Modal map, not yet";
1151 WM_operator_py_idname(opname, ot->idname);
1152 ten->name= BLI_strdup(opname);
1153 ten->flag |= TE_FREE_NAME;
1160 te->flag |= TE_LAZY_CLOSED;
1166 static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb)
1168 TreeElement *te, *ten, *tep;
1169 TreeStoreElem *tselem;
1171 /* build hierarchy */
1172 // XXX also, set extents here...
1176 tselem= TREESTORE(te);
1178 if(tselem->type==0 && te->idcode==ID_OB) {
1179 Object *ob= (Object *)tselem->id;
1180 if(ob->parent && ob->parent->id.newid) {
1181 BLI_remlink(lb, te);
1182 tep= (TreeElement *)ob->parent->id.newid;
1183 BLI_addtail(&tep->subtree, te);
1184 // set correct parent pointers
1185 for(te=tep->subtree.first; te; te= te->next) te->parent= tep;
1192 /* Helped function to put duplicate sequence in the same tree. */
1193 int need_add_seq_dup(Sequence *seq)
1197 if((!seq->strip) || (!seq->strip->stripdata) || (!seq->strip->stripdata->name))
1201 * First check backward, if we found a duplicate
1202 * sequence before this, don't need it, just return.
1206 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1211 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1218 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1223 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1230 void add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index)
1237 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
1242 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
1243 ch= outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index);
1248 static void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
1252 TreeElement *te=NULL, *ten;
1253 TreeStoreElem *tselem;
1254 int show_opened= (soops->treestore==NULL); /* on first view, we open scenes */
1256 if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
1259 outliner_free_tree(&soops->tree);
1260 outliner_storage_cleanup(soops);
1262 /* clear ob id.new flags */
1263 for(ob= mainvar->object.first; ob; ob= ob->id.next) ob->id.newid= NULL;
1266 if(soops->outlinevis == SO_LIBRARIES) {
1269 for(lib= mainvar->library.first; lib; lib= lib->id.next) {
1270 ten= outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
1271 lib->id.newid= (ID *)ten;
1273 /* make hierarchy */
1274 ten= soops->tree.first;
1276 TreeElement *nten= ten->next, *par;
1277 tselem= TREESTORE(ten);
1278 lib= (Library *)tselem->id;
1280 BLI_remlink(&soops->tree, ten);
1281 par= (TreeElement *)lib->parent->id.newid;
1282 BLI_addtail(&par->subtree, ten);
1287 /* restore newid pointers */
1288 for(lib= mainvar->library.first; lib; lib= lib->id.next)
1289 lib->id.newid= NULL;
1292 else if(soops->outlinevis == SO_ALL_SCENES) {
1294 for(sce= mainvar->scene.first; sce; sce= sce->id.next) {
1295 te= outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
1296 tselem= TREESTORE(te);
1297 if(sce==scene && show_opened)
1298 tselem->flag &= ~TSE_CLOSED;
1300 for(base= sce->base.first; base; base= base->next) {
1301 ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
1302 ten->directdata= base;
1304 outliner_make_hierarchy(soops, &te->subtree);
1305 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1306 for(base= sce->base.first; base; base= base->next) base->object->id.newid= NULL;
1309 else if(soops->outlinevis == SO_CUR_SCENE) {
1311 outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
1313 for(base= scene->base.first; base; base= base->next) {
1314 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1315 ten->directdata= base;
1317 outliner_make_hierarchy(soops, &soops->tree);
1319 else if(soops->outlinevis == SO_VISIBLE) {
1320 for(base= scene->base.first; base; base= base->next) {
1321 if(base->lay & scene->lay)
1322 outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1324 outliner_make_hierarchy(soops, &soops->tree);
1326 else if(soops->outlinevis == SO_GROUPS) {
1330 for(group= mainvar->group.first; group; group= group->id.next) {
1332 te= outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
1333 tselem= TREESTORE(te);
1335 for(go= group->gobject.first; go; go= go->next) {
1336 ten= outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
1337 ten->directdata= NULL; /* eh, why? */
1339 outliner_make_hierarchy(soops, &te->subtree);
1340 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1341 for(go= group->gobject.first; go; go= go->next) go->ob->id.newid= NULL;
1345 else if(soops->outlinevis == SO_SAME_TYPE) {
1348 for(base= scene->base.first; base; base= base->next) {
1349 if(base->object->type==ob->type) {
1350 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1351 ten->directdata= base;
1354 outliner_make_hierarchy(soops, &soops->tree);
1357 else if(soops->outlinevis == SO_SELECTED) {
1358 for(base= scene->base.first; base; base= base->next) {
1359 if(base->lay & scene->lay) {
1360 if(base==BASACT || (base->flag & SELECT)) {
1361 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1362 ten->directdata= base;
1366 outliner_make_hierarchy(soops, &soops->tree);
1368 else if(soops->outlinevis==SO_SEQUENCE) {
1370 Editing *ed= seq_give_editing(scene, FALSE);
1376 seq= ed->seqbasep->first;
1381 op= need_add_seq_dup(seq);
1383 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE, 0);
1385 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE_DUP, 0);
1386 add_seq_dup(soops, seq, ten, 0);
1391 else if(soops->outlinevis==SO_DATABLOCKS) {
1394 RNA_main_pointer_create(mainvar, &mainptr);
1396 ten= outliner_add_element(soops, &soops->tree, (void*)&mainptr, NULL, TSE_RNA_STRUCT, -1);
1399 tselem= TREESTORE(ten);
1400 tselem->flag &= ~TSE_CLOSED;
1403 else if(soops->outlinevis==SO_USERDEF) {
1404 PointerRNA userdefptr;
1406 RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
1408 ten= outliner_add_element(soops, &soops->tree, (void*)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
1411 tselem= TREESTORE(ten);
1412 tselem->flag &= ~TSE_CLOSED;
1415 else if(soops->outlinevis==SO_KEYMAP) {
1416 wmWindowManager *wm= mainvar->wm.first;
1419 for(km= wm->defaultconf->keymaps.first; km; km= km->next) {
1420 ten= outliner_add_element(soops, &soops->tree, (void*)km, NULL, TSE_KEYMAP, 0);
1424 ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
1425 if(ten) ten->directdata= BASACT;
1428 outliner_sort(soops, &soops->tree);
1431 /* **************** INTERACTIVE ************* */
1433 static int outliner_count_levels(SpaceOops *soops, ListBase *lb, int curlevel)
1436 int level=curlevel, lev;
1438 for(te= lb->first; te; te= te->next) {
1440 lev= outliner_count_levels(soops, &te->subtree, curlevel+1);
1441 if(lev>level) level= lev;
1446 static int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel)
1449 TreeStoreElem *tselem;
1452 for(te= lb->first; te; te= te->next) {
1453 tselem= TREESTORE(te);
1454 if(tselem->flag & flag) return curlevel;
1456 level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1);
1457 if(level) return level;
1462 static void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
1465 TreeStoreElem *tselem;
1467 for(te= lb->first; te; te= te->next) {
1468 tselem= TREESTORE(te);
1469 if(set==0) tselem->flag &= ~flag;
1470 else tselem->flag |= flag;
1471 outliner_set_flag(soops, &te->subtree, flag, set);
1477 void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1479 Base *base= (Base *)te->directdata;
1481 if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1483 base->object->restrictflag^=OB_RESTRICT_VIEW;
1487 static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op)
1489 SpaceOops *soops= CTX_wm_space_outliner(C);
1490 Scene *scene= CTX_data_scene(C);
1491 ARegion *ar= CTX_wm_region(C);
1493 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
1495 ED_region_tag_redraw(ar);
1497 return OPERATOR_FINISHED;
1500 void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
1503 ot->name= "Toggle Visability";
1504 ot->idname= "OUTLINER_OT_visibility_toggle";
1505 ot->description= "Toggle the visibility of selected items.";
1508 ot->exec= outliner_toggle_visibility_exec;
1509 ot->poll= ED_operator_outliner_active;
1511 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1516 static void object_toggle_selectability_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1518 Base *base= (Base *)te->directdata;
1520 if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1522 base->object->restrictflag^=OB_RESTRICT_SELECT;
1526 static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op)
1528 SpaceOops *soops= CTX_wm_space_outliner(C);
1529 Scene *scene= CTX_data_scene(C);
1530 ARegion *ar= CTX_wm_region(C);
1532 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
1534 ED_region_tag_redraw(ar);
1536 return OPERATOR_FINISHED;
1539 void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
1542 ot->name= "Toggle Selectability";
1543 ot->idname= "OUTLINER_OT_selectability_toggle";
1544 ot->description= "Toggle the selectability";
1547 ot->exec= outliner_toggle_selectability_exec;
1548 ot->poll= ED_operator_outliner_active;
1550 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1555 void object_toggle_renderability_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
1557 Base *base= (Base *)te->directdata;
1559 if(base==NULL) base= object_in_scene((Object *)tselem->id, scene);
1561 base->object->restrictflag^=OB_RESTRICT_RENDER;
1565 static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op)
1567 SpaceOops *soops= CTX_wm_space_outliner(C);
1568 Scene *scene= CTX_data_scene(C);
1569 ARegion *ar= CTX_wm_region(C);
1571 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
1573 ED_region_tag_redraw(ar);
1575 return OPERATOR_FINISHED;
1578 void OUTLINER_OT_renderability_toggle(wmOperatorType *ot)
1581 ot->name= "Toggle Renderability";
1582 ot->idname= "OUTLINER_OT_renderability_toggle";
1583 ot->description= "Toggle the renderbility of selected items.";
1586 ot->exec= outliner_toggle_renderability_exec;
1587 ot->poll= ED_operator_outliner_active;
1589 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1594 static int outliner_toggle_expanded_exec(bContext *C, wmOperator *op)
1596 SpaceOops *soops= CTX_wm_space_outliner(C);
1597 ARegion *ar= CTX_wm_region(C);
1599 if (outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
1600 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
1602 outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
1604 ED_region_tag_redraw(ar);
1606 return OPERATOR_FINISHED;
1609 void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
1612 ot->name= "Expand/Collapse All";
1613 ot->idname= "OUTLINER_OT_expanded_toggle";
1614 ot->description= "Expand/Collapse all items.";
1617 ot->exec= outliner_toggle_expanded_exec;
1618 ot->poll= ED_operator_outliner_active;
1620 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1625 static int outliner_toggle_selected_exec(bContext *C, wmOperator *op)
1627 SpaceOops *soops= CTX_wm_space_outliner(C);
1628 ARegion *ar= CTX_wm_region(C);
1630 if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
1631 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
1633 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
1635 soops->storeflag |= SO_TREESTORE_REDRAW;
1637 ED_region_tag_redraw(ar);
1639 return OPERATOR_FINISHED;
1642 void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
1645 ot->name= "Toggle Selected";
1646 ot->idname= "OUTLINER_OT_selected_toggle";
1647 ot->description= "Toggle the Outliner selection of items.";
1650 ot->exec= outliner_toggle_selected_exec;
1651 ot->poll= ED_operator_outliner_active;
1653 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1658 /* helper function for Show/Hide one level operator */
1659 static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
1662 TreeStoreElem *tselem;
1664 for(te= lb->first; te; te= te->next) {
1665 tselem= TREESTORE(te);
1668 if(curlevel<=level) tselem->flag &= ~TSE_CLOSED;
1671 if(curlevel>=level) tselem->flag |= TSE_CLOSED;
1674 outliner_openclose_level(soops, &te->subtree, curlevel+1, level, open);
1678 static int outliner_one_level_exec(bContext *C, wmOperator *op)
1680 SpaceOops *soops= CTX_wm_space_outliner(C);
1681 ARegion *ar= CTX_wm_region(C);
1682 int add= RNA_boolean_get(op->ptr, "open");
1685 level= outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
1687 if(level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
1690 if(level==0) level= outliner_count_levels(soops, &soops->tree, 0);
1691 if(level) outliner_openclose_level(soops, &soops->tree, 1, level-1, 0);
1694 ED_region_tag_redraw(ar);
1696 return OPERATOR_FINISHED;
1699 void OUTLINER_OT_show_one_level(wmOperatorType *ot)
1702 ot->name= "Show/Hide One Level";
1703 ot->idname= "OUTLINER_OT_show_one_level";
1706 ot->exec= outliner_one_level_exec;
1707 ot->poll= ED_operator_outliner_active;
1709 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1712 RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep.");
1715 /* return 1 when levels were opened */
1716 static int outliner_open_back(SpaceOops *soops, TreeElement *te)
1718 TreeStoreElem *tselem;
1721 for (te= te->parent; te; te= te->parent) {
1722 tselem= TREESTORE(te);
1723 if (tselem->flag & TSE_CLOSED) {
1724 tselem->flag &= ~TSE_CLOSED;
1731 /* This is not used anywhere at the moment */
1733 static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
1736 TreeStoreElem *tselem;
1738 for (te= lb->first; te; te= te->next) {
1739 /* check if this tree-element was the one we're seeking */
1745 /* try to see if sub-tree contains it then */
1746 outliner_open_reveal(soops, &te->subtree, teFind, found);
1748 tselem= TREESTORE(te);
1749 if (tselem->flag & TSE_CLOSED)
1750 tselem->flag &= ~TSE_CLOSED;
1757 // XXX just use View2D ops for this?
1758 void outliner_page_up_down(Scene *scene, ARegion *ar, SpaceOops *soops, int up)
1760 int dy= ar->v2d.mask.ymax-ar->v2d.mask.ymin;
1762 if(up == -1) dy= -dy;
1763 ar->v2d.cur.ymin+= dy;
1764 ar->v2d.cur.ymax+= dy;
1766 soops->storeflag |= SO_TREESTORE_REDRAW;
1769 /* **** do clicks on items ******* */
1771 static int tree_element_active_renderlayer(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
1775 /* paranoia check */
1776 if(te->idcode!=ID_SCE)
1778 sce= (Scene *)tselem->id;
1781 sce->r.actlay= tselem->nr;
1782 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, sce);
1785 return sce->r.actlay==tselem->nr;
1790 static void tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1792 TreeStoreElem *tselem= TREESTORE(te);
1797 /* if id is not object, we search back */
1798 if(te->idcode==ID_OB) ob= (Object *)tselem->id;
1800 ob= (Object *)outliner_search_back(soops, te, ID_OB);
1801 if(ob==OBACT) return;
1803 if(ob==NULL) return;
1805 sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
1806 if(sce && scene != sce) {
1807 ED_screen_set_scene(C, sce);
1810 /* find associated base in current scene */
1811 for(base= FIRSTBASE; base; base= base->next)
1812 if(base->object==ob) break;
1816 if(base->flag & SELECT)
1817 ED_base_object_select(base, BA_DESELECT);
1819 ED_base_object_select(base, BA_SELECT);
1823 /* deleselect all */
1824 for(b= FIRSTBASE; b; b= b->next) {
1826 b->object->flag= b->flag;
1828 ED_base_object_select(base, BA_SELECT);
1831 ED_base_object_activate(C, base); /* adds notifier */
1834 if(ob!=scene->obedit)
1835 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
1837 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
1841 static int tree_element_active_material(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1846 /* we search for the object parent */
1847 ob= (Object *)outliner_search_back(soops, te, ID_OB);
1848 if(ob==NULL || ob!=OBACT) return 0; // just paranoia
1850 /* searching in ob mat array? */
1852 if(tes->idcode==ID_OB) {
1854 ob->actcol= te->index+1;
1855 ob->matbits[te->index]= 1; // make ob material active too
1856 ob->colbits |= (1<<te->index);
1859 if(ob->actcol == te->index+1)
1860 if(ob->matbits[te->index]) return 1;
1863 /* or we search for obdata material */
1866 ob->actcol= te->index+1;
1867 ob->matbits[te->index]= 0; // make obdata material active too
1868 ob->colbits &= ~(1<<te->index);
1871 if(ob->actcol == te->index+1)
1872 if(ob->matbits[te->index]==0) return 1;
1876 WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL);
1881 static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1884 TreeStoreElem *tselem, *tselemp;
1886 SpaceButs *sbuts=NULL;
1888 if(ob==NULL) return 0; // no active object
1890 tselem= TREESTORE(te);
1892 /* find buttons area (note, this is undefined really still, needs recode in blender) */
1893 /* XXX removed finding sbuts */
1895 /* where is texture linked to? */
1897 tselemp= TREESTORE(tep);
1899 if(tep->idcode==ID_WO) {
1900 World *wrld= (World *)tselemp->id;
1904 // XXX sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
1905 // XXX sbuts->texfrom= 1;
1907 // XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
1908 wrld->texact= te->index;
1910 else if(tselemp->id == (ID *)(scene->world)) {
1911 if(wrld->texact==te->index) return 1;
1914 else if(tep->idcode==ID_LA) {
1915 Lamp *la= (Lamp *)tselemp->id;
1918 // XXX sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
1919 // XXX sbuts->texfrom= 2;
1921 // XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
1922 la->texact= te->index;
1925 if(tselemp->id == ob->data) {
1926 if(la->texact==te->index) return 1;
1930 else if(tep->idcode==ID_MA) {
1931 Material *ma= (Material *)tselemp->id;
1934 //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
1935 // XXX sbuts->texfrom= 0;
1937 // XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
1938 ma->texact= (char)te->index;
1940 /* also set active material */
1941 ob->actcol= tep->index+1;
1943 else if(tep->flag & TE_ACTIVE) { // this is active material
1944 if(ma->texact==te->index) return 1;
1952 static int tree_element_active_lamp(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1956 /* we search for the object parent */
1957 ob= (Object *)outliner_search_back(soops, te, ID_OB);
1958 if(ob==NULL || ob!=OBACT) return 0; // just paranoia
1961 // XXX extern_set_butspace(F5KEY, 0);
1968 static int tree_element_active_world(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
1971 TreeStoreElem *tselem=NULL;
1976 tselem= TREESTORE(tep);
1977 sce= (Scene *)tselem->id;
1980 if(set) { // make new scene active
1981 if(sce && scene != sce) {
1982 ED_screen_set_scene(C, sce);
1986 if(tep==NULL || tselem->id == (ID *)scene) {
1988 // XXX extern_set_butspace(F8KEY, 0);
1997 static int tree_element_active_defgroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2001 /* id in tselem is object */
2002 ob= (Object *)tselem->id;
2004 ob->actdef= te->index+1;
2005 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2006 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
2010 if(ob->actdef== te->index+1) return 1;
2015 static int tree_element_active_posegroup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2017 Object *ob= (Object *)tselem->id;
2021 ob->pose->active_group= te->index+1;
2022 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
2026 if(ob==OBACT && ob->pose) {
2027 if (ob->pose->active_group== te->index+1) return 1;
2033 static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2035 Object *ob= (Object *)tselem->id;
2036 bArmature *arm= ob->data;
2037 bPoseChannel *pchan= te->directdata;
2040 if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
2042 if(set==2) ED_pose_deselectall(ob, 2, 0); // 2 = clear active tag
2043 else ED_pose_deselectall(ob, 0, 0); // 0 = deselect
2045 if(set==2 && (pchan->bone->flag & BONE_SELECTED)) {
2046 pchan->bone->flag &= ~BONE_SELECTED;
2047 if(arm->act_bone==pchan->bone)
2048 arm->act_bone= NULL;
2050 pchan->bone->flag |= BONE_SELECTED;
2051 arm->act_bone= pchan->bone;
2054 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, ob);
2059 if(ob==OBACT && ob->pose) {
2060 if (pchan->bone->flag & BONE_SELECTED) return 1;
2066 static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2068 bArmature *arm= (bArmature *)tselem->id;
2069 Bone *bone= te->directdata;
2072 if(!(bone->flag & BONE_HIDDEN_P)) {
2073 if(set==2) ED_pose_deselectall(OBACT, 2, 0); // 2 is clear active tag
2074 else ED_pose_deselectall(OBACT, 0, 0);
2076 if(set==2 && (bone->flag & BONE_SELECTED)) {
2077 bone->flag &= ~BONE_SELECTED;
2078 if(arm->act_bone==bone)
2079 arm->act_bone= NULL;
2081 bone->flag |= BONE_SELECTED;
2082 arm->act_bone= bone;
2085 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, OBACT);
2091 if(ob && ob->data==arm) {
2092 if (bone->flag & BONE_SELECTED) return 1;
2099 /* ebones only draw in editmode armature */
2100 static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2102 EditBone *ebone= te->directdata;
2105 if(!(ebone->flag & BONE_HIDDEN_A)) {
2106 bArmature *arm= scene->obedit->data;
2107 if(set==2) ED_armature_deselectall(scene->obedit, 2, 0); // only clear active tag
2108 else ED_armature_deselectall(scene->obedit, 0, 0); // deselect
2110 ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL;
2111 arm->act_edbone= ebone;
2114 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
2116 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, scene->obedit);
2120 if (ebone->flag & BONE_SELECTED) return 1;
2125 static int tree_element_active_modifier(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
2128 Object *ob= (Object *)tselem->id;
2130 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
2132 // XXX extern_set_butspace(F9KEY, 0);
2138 static int tree_element_active_psys(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2141 Object *ob= (Object *)tselem->id;
2143 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2145 // XXX extern_set_butspace(F7KEY, 0);
2151 static int tree_element_active_constraint(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
2154 Object *ob= (Object *)tselem->id;
2156 WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
2157 // XXX extern_set_butspace(F7KEY, 0);
2163 static int tree_element_active_text(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
2169 /* generic call for ID data check or make/check active in UI */
2170 static int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set)
2173 switch(te->idcode) {
2175 return tree_element_active_material(C, scene, soops, te, set);
2177 return tree_element_active_world(C, scene, soops, te, set);
2179 return tree_element_active_lamp(C, scene, soops, te, set);
2181 return tree_element_active_texture(C, scene, soops, te, set);
2183 return tree_element_active_text(C, scene, soops, te, set);
2188 static int tree_element_active_pose(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2190 Object *ob= (Object *)tselem->id;
2191 Base *base= object_in_scene(ob, scene);
2195 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
2197 if(ob->mode & OB_MODE_POSE)
2198 ED_armature_exit_posemode(C, base);
2200 ED_armature_enter_posemode(C, base);
2203 if(ob->mode & OB_MODE_POSE) return 1;
2208 static int tree_element_active_sequence(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
2210 Sequence *seq= (Sequence*) te->directdata;
2213 // XXX select_single_seq(seq, 1);
2216 if(seq->flag & SELECT)
2222 static int tree_element_active_sequence_dup(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set)
2225 Editing *ed= seq_give_editing(scene, FALSE);
2227 seq= (Sequence*)te->directdata;
2229 if(seq->flag & SELECT)
2234 // XXX select_single_seq(seq, 1);
2235 p= ed->seqbasep->first;
2237 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) {
2242 // if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
2243 // XXX select_single_seq(p, 0);
2249 static int tree_element_active_keymap_item(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set)
2251 wmKeyMapItem *kmi= te->directdata;
2254 if(kmi->flag & KMI_INACTIVE) return 0;
2258 kmi->flag ^= KMI_INACTIVE;
2264 /* generic call for non-id data to make/check active in UI */
2265 /* Context can be NULL when set==0 */
2266 static int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
2269 switch(tselem->type) {
2271 return tree_element_active_defgroup(C, scene, te, tselem, set);
2273 return tree_element_active_bone(C, scene, te, tselem, set);
2275 return tree_element_active_ebone(C, scene, te, tselem, set);
2277 return tree_element_active_modifier(C, te, tselem, set);
2279 if(set) tree_element_set_active_object(C, scene, soops, te, set);
2280 else if(tselem->id==(ID *)OBACT) return 1;
2282 case TSE_LINKED_PSYS:
2283 return tree_element_active_psys(C, scene, te, tselem, set);
2285 return tree_element_active_pose(C, scene, te, tselem, set);
2286 case TSE_POSE_CHANNEL:
2287 return tree_element_active_posechannel(C, scene, te, tselem, set);
2288 case TSE_CONSTRAINT:
2289 return tree_element_active_constraint(C, te, tselem, set);
2291 return tree_element_active_renderlayer(C, te, tselem, set);
2293 return tree_element_active_posegroup(C, scene, te, tselem, set);
2295 return tree_element_active_sequence(C, te, tselem, set);
2296 case TSE_SEQUENCE_DUP:
2297 return tree_element_active_sequence_dup(C, scene, te, tselem, set);
2298 case TSE_KEYMAP_ITEM:
2299 return tree_element_active_keymap_item(C, te, tselem, set);
2305 static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int extend, float *mval)
2308 if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
2309 TreeStoreElem *tselem= TREESTORE(te);
2312 /* open close icon */
2313 if((te->flag & TE_ICONROW)==0) { // hidden icon, no open/close
2314 if( mval[0]>te->xs && mval[0]<te->xs+OL_X)
2319 /* all below close/open? */
2321 tselem->flag &= ~TSE_CLOSED;
2322 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
2325 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
2326 else tselem->flag |= TSE_CLOSED;
2332 /* name and first icon */
2333 else if(mval[0]>te->xs && mval[0]<te->xend) {
2335 /* always makes active object */
2336 if(tselem->type!=TSE_SEQUENCE && tselem->type!=TSE_SEQ_STRIP && tselem->type!=TSE_SEQUENCE_DUP)
2337 tree_element_set_active_object(C, scene, soops, te, 1 + (extend!=0 && tselem->type==0));
2339 if(tselem->type==0) { // the lib blocks
2341 if(te->idcode==ID_SCE) {
2342 if(scene!=(Scene *)tselem->id) {
2343 ED_screen_set_scene(C, (Scene *)tselem->id);
2346 else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
2347 Object *obedit= CTX_data_edit_object(C);
2349 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
2351 ED_object_enter_editmode(C, EM_WAITCURSOR);
2352 // XXX extern_set_butspace(F9KEY, 0);
2354 } else { // rest of types
2355 tree_element_active(C, scene, soops, te, 1);
2359 else tree_element_type_active(C, scene, soops, te, tselem, 1+(extend!=0));
2365 for(te= te->subtree.first; te; te= te->next) {
2366 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1;
2371 /* event can enterkey, then it opens/closes */
2372 static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event)
2374 Scene *scene= CTX_data_scene(C);
2375 ARegion *ar= CTX_wm_region(C);
2376 SpaceOops *soops= CTX_wm_space_outliner(C);
2379 int extend= RNA_boolean_get(op->ptr, "extend");
2381 UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, fmval, fmval+1);
2383 for(te= soops->tree.first; te; te= te->next) {
2384 if(do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break;
2388 ED_undo_push(C, "Outliner click event");
2391 short selecting= -1;
2394 /* get row number - 100 here is just a dummy value since we don't need the column */
2395 UI_view2d_listview_view_to_cell(&ar->v2d, 1000, OL_H, 0.0f, 0.0f,
2396 fmval[0], fmval[1], NULL, &row);
2398 /* select relevant row */
2399 outliner_select(soops, &soops->tree, &row, &selecting);
2401 soops->storeflag |= SO_TREESTORE_REDRAW;
2403 ED_undo_push(C, "Outliner selection event");
2406 ED_region_tag_redraw(ar);
2408 return OPERATOR_FINISHED;
2411 void OUTLINER_OT_item_activate(wmOperatorType *ot)
2413 ot->name= "Activate Item";
2414 ot->idname= "OUTLINER_OT_item_activate";
2416 ot->invoke= outliner_item_activate;
2418 ot->poll= ED_operator_outliner_active;
2420 RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation.");
2425 static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement *te, int all, float *mval)
2428 if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
2429 TreeStoreElem *tselem= TREESTORE(te);
2431 /* all below close/open? */
2433 tselem->flag &= ~TSE_CLOSED;
2434 outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
2437 if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
2438 else tselem->flag |= TSE_CLOSED;
2444 for(te= te->subtree.first; te; te= te->next) {
2445 if(do_outliner_item_openclose(C, soops, te, all, mval))
2452 /* event can enterkey, then it opens/closes */
2453 static int outliner_item_openclose(bContext *C, wmOperator *op, wmEvent *event)
2455 ARegion *ar= CTX_wm_region(C);
2456 SpaceOops *soops= CTX_wm_space_outliner(C);
2459 int all= RNA_boolean_get(op->ptr, "all");
2461 UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, fmval, fmval+1);
2463 for(te= soops->tree.first; te; te= te->next) {
2464 if(do_outliner_item_openclose(C, soops, te, all, fmval))
2468 ED_region_tag_redraw(ar);
2470 return OPERATOR_FINISHED;
2473 void OUTLINER_OT_item_openclose(wmOperatorType *ot)
2475 ot->name= "Open/Close Item";
2476 ot->idname= "OUTLINER_OT_item_openclose";
2478 ot->invoke= outliner_item_openclose;
2480 ot->poll= ED_operator_outliner_active;
2482 RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items.");
2487 /* ********************************************** */
2489 static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, float *mval)
2492 if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
2493 TreeStoreElem *tselem= TREESTORE(te);
2495 /* name and first icon */
2496 if(mval[0]>te->xs && mval[0]<te->xend) {
2498 /* can't rename rna datablocks entries */
2499 if(ELEM3(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))
2501 else if(ELEM10(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, TSE_SCRIPT_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
2502 error("Cannot edit builtin name");
2503 else if(ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP))
2504 error("Cannot edit sequence name");
2505 else if(tselem->id->lib) {
2506 // XXX error_libdata();
2507 } else if(te->idcode == ID_LI && te->parent) {
2508 error("Cannot edit the path of an indirectly linked library");
2510 tselem->flag |= TSE_TEXTBUT;
2511 ED_region_tag_redraw(ar);
2517 for(te= te->subtree.first; te; te= te->next) {
2518 if(do_outliner_item_rename(C, ar, soops, te, mval)) return 1;
2523 static int outliner_item_rename(bContext *C, wmOperator *op, wmEvent *event)
2525 ARegion *ar= CTX_wm_region(C);
2526 SpaceOops *soops= CTX_wm_space_outliner(C);
2530 UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, fmval, fmval+1);
2532 for(te= soops->tree.first; te; te= te->next) {
2533 if(do_outliner_item_rename(C, ar, soops, te, fmval)) break;
2536 return OPERATOR_FINISHED;
2540 void OUTLINER_OT_item_rename(wmOperatorType *ot)
2542 ot->name= "Rename Item";
2543 ot->idname= "OUTLINER_OT_item_rename";
2545 ot->invoke= outliner_item_rename;
2547 ot->poll= ED_operator_outliner_active;
2552 /* recursive helper for function below */
2553 static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
2555 TreeStoreElem *tselem= TREESTORE(te);
2557 /* store coord and continue, we need coordinates for elements outside view too */
2558 te->xs= (float)startx;
2559 te->ys= (float)(*starty);
2562 if((tselem->flag & TSE_CLOSED)==0) {
2564 for(ten= te->subtree.first; ten; ten= ten->next) {
2565 outliner_set_coordinates_element(soops, ten, startx+OL_X, starty);
2571 /* to retrieve coordinates with redrawing the entire tree */
2572 static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
2575 int starty= (int)(ar->v2d.tot.ymax)-OL_H;
2578 for(te= soops->tree.first; te; te= te->next) {
2579 outliner_set_coordinates_element(soops, te, startx, &starty);
2583 static TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
2585 TreeElement *te, *tes;
2586 TreeStoreElem *tselem;
2588 for(te= lb->first; te; te= te->next) {
2589 tselem= TREESTORE(te);
2590 if(tselem->type==0) {
2591 if(tselem->id==id) return te;
2592 /* only deeper on scene or object */
2593 if( te->idcode==ID_OB || te->idcode==ID_SCE) {
2594 tes= outliner_find_id(soops, &te->subtree, id);
2602 static int outliner_show_active_exec(bContext *C, wmOperator *op)
2604 SpaceOops *so= CTX_wm_space_outliner(C);
2605 Scene *scene= CTX_data_scene(C);
2606 ARegion *ar= CTX_wm_region(C);
2607 View2D *v2d= &ar->v2d;
2612 // TODO: make this get this info from context instead...
2614 return OPERATOR_CANCELLED;
2616 te= outliner_find_id(so, &so->tree, (ID *)OBACT);
2618 /* make te->ys center of view */
2619 ytop= (int)(te->ys + (v2d->mask.ymax - v2d->mask.ymin)/2);
2620 if (ytop>0) ytop= 0;
2622 v2d->cur.ymax= (float)ytop;
2623 v2d->cur.ymin= (float)(ytop-(v2d->mask.ymax - v2d->mask.ymin));
2625 /* make te->xs ==> te->xend center of view */
2626 xdelta = (int)(te->xs - v2d->cur.xmin);
2627 v2d->cur.xmin += xdelta;
2628 v2d->cur.xmax += xdelta;
2630 so->storeflag |= SO_TREESTORE_REDRAW;
2633 ED_region_tag_redraw(ar);
2635 return OPERATOR_FINISHED;
2638 void OUTLINER_OT_show_active(wmOperatorType *ot)
2641 ot->name= "Show Active";
2642 ot->idname= "OUTLINER_OT_show_active";
2643 ot->description= "Adjust the view so that the active Object is shown centered.";
2646 ot->exec= outliner_show_active_exec;
2647 ot->poll= ED_operator_outliner_active;
2649 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2652 /* find next element that has this name */
2653 static TreeElement *outliner_find_named(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound)
2655 TreeElement *te, *tes;
2657 for (te= lb->first; te; te= te->next) {
2660 /* determine if match */
2662 found= BLI_strcasestr(te->name, name)!=NULL;
2663 else if(flags==OL_FIND_CASE)
2664 found= strstr(te->name, name)!=NULL;
2665 else if(flags==OL_FIND_COMPLETE)
2666 found= BLI_strcasecmp(te->name, name)==0;
2668 found= strcmp(te->name, name)==0;
2671 /* name is right, but is element the previous one? */
2673 if ((te != prev) && (*prevFound))
2683 tes= outliner_find_named(soops, &te->subtree, name, flags, prev, prevFound);
2687 /* nothing valid found */
2691 /* tse is not in the treestore, we use its contents to find a match */
2692 static TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
2694 TreeStore *ts= soops->treestore;
2695 TreeStoreElem *tselem;
2698 if(tse->id==NULL) return NULL;
2700 /* check if 'tse' is in treestore */
2702 for(a=0; a<ts->usedelem; a++, tselem++) {
2703 if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) {
2704 if(tselem->id==tse->id) {
2710 return outliner_find_tree_element(&soops->tree, a);
2716 /* Called to find an item based on name.
2718 void outliner_find_panel(Scene *scene, ARegion *ar, SpaceOops *soops, int again, int flags)
2720 TreeElement *te= NULL;
2721 TreeElement *last_find;
2722 TreeStoreElem *tselem;
2723 int ytop, xdelta, prevFound=0;
2726 /* get last found tree-element based on stored search_tse */
2727 last_find= outliner_find_tse(soops, &soops->search_tse);
2729 /* determine which type of search to do */
2730 if (again && last_find) {
2731 /* no popup panel - previous + user wanted to search for next after previous */
2732 BLI_strncpy(name, soops->search_string, 33);
2733 flags= soops->search_flags;
2735 /* try to find matching element */
2736 te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2738 /* no more matches after previous, start from beginning again */
2740 te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
2744 /* pop up panel - no previous, or user didn't want search after previous */
2746 // XXX if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
2747 // te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound);
2749 // else return; /* XXX RETURN! XXX */
2752 /* do selection and reveal */
2754 tselem= TREESTORE(te);
2756 /* expand branches so that it will be visible, we need to get correct coordinates */
2757 if( outliner_open_back(soops, te))
2758 outliner_set_coordinates(ar, soops);
2760 /* deselect all visible, and select found element */
2761 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
2762 tselem->flag |= TSE_SELECTED;
2764 /* make te->ys center of view */
2765 ytop= (int)(te->ys + (ar->v2d.mask.ymax-ar->v2d.mask.ymin)/2);
2767 ar->v2d.cur.ymax= (float)ytop;
2768 ar->v2d.cur.ymin= (float)(ytop-(ar->v2d.mask.ymax-ar->v2d.mask.ymin));
2770 /* make te->xs ==> te->xend center of view */
2771 xdelta = (int)(te->xs - ar->v2d.cur.xmin);
2772 ar->v2d.cur.xmin += xdelta;
2773 ar->v2d.cur.xmax += xdelta;
2775 /* store selection */
2776 soops->search_tse= *tselem;
2778 BLI_strncpy(soops->search_string, name, 33);
2779 soops->search_flags= flags;
2782 soops->storeflag |= SO_TREESTORE_REDRAW;
2786 /* no tree-element found */
2787 error("Not found: %s", name);
2791 /* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/
2792 static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
2795 TreeStoreElem *tselem;
2797 for(te= lb->first; te; te= te->next) {
2798 tselem= TREESTORE(te);
2799 if(tselem->type==0 && te->idcode==ID_OB) return 1;
2800 if( subtree_has_objects(soops, &te->subtree)) return 1;
2805 /* recursive helper function for Show Hierarchy operator */
2806 static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase *lb)
2809 TreeStoreElem *tselem;
2811 /* open all object elems, close others */
2812 for(te= lb->first; te; te= te->next) {
2813 tselem= TREESTORE(te);
2815 if(tselem->type==0) {
2816 if(te->idcode==ID_SCE) {
2817 if(tselem->id!=(ID *)scene) tselem->flag |= TSE_CLOSED;
2818 else tselem->flag &= ~TSE_CLOSED;
2820 else if(te->idcode==ID_OB) {
2821 if(subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
2822 else tselem->flag |= TSE_CLOSED;
2825 else tselem->flag |= TSE_CLOSED;
2827 if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(scene, soops, &te->subtree);
2831 /* show entire object level hierarchy */
2832 static int outliner_show_hierarchy_exec(bContext *C, wmOperator *op)
2834 SpaceOops *soops= CTX_wm_space_outliner(C);
2835 ARegion *ar= CTX_wm_region(C);
2836 Scene *scene= CTX_data_scene(C);
2838 /* recursively open/close levels */
2839 tree_element_show_hierarchy(scene, soops, &soops->tree);
2841 ED_region_tag_redraw(ar);
2843 return OPERATOR_FINISHED;
2846 void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
2849 ot->name= "Show Hierarchy";
2850 ot->idname= "OUTLINER_OT_show_hierarchy";
2851 ot->description= "Open all object entries and close all others.";
2854 ot->exec= outliner_show_hierarchy_exec;
2855 ot->poll= ED_operator_outliner_active; // TODO: shouldn't be allowed in RNA views...
2857 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2860 void outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
2863 TreeStoreElem *tselem;
2865 for (te= lb->first; te && *index >= 0; te=te->next, (*index)--) {
2866 tselem= TREESTORE(te);
2868 /* if we've encountered the right item, set its 'Outliner' selection status */
2870 /* this should be the last one, so no need to do anything with index */
2871 if ((te->flag & TE_ICONROW)==0) {
2872 /* -1 value means toggle testing for now... */
2873 if (*selecting == -1) {
2874 if (tselem->flag & TSE_SELECTED)
2882 tselem->flag |= TSE_SELECTED;
2884 tselem->flag &= ~TSE_SELECTED;