|
Blender
V2.59
|
00001 /* 00002 * $Id: outliner_tree.c 39294 2011-08-11 06:40:04Z gsrb3d $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2004 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): Joshua Leung 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00034 #include <math.h> 00035 #include <string.h> 00036 #include <stdlib.h> 00037 #include <stddef.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_anim_types.h" 00042 #include "DNA_armature_types.h" 00043 #include "DNA_constraint_types.h" 00044 #include "DNA_camera_types.h" 00045 #include "DNA_group_types.h" 00046 #include "DNA_key_types.h" 00047 #include "DNA_lamp_types.h" 00048 #include "DNA_material_types.h" 00049 #include "DNA_mesh_types.h" 00050 #include "DNA_meta_types.h" 00051 #include "DNA_particle_types.h" 00052 #include "DNA_scene_types.h" 00053 #include "DNA_world_types.h" 00054 #include "DNA_sequence_types.h" 00055 00056 #if 0 // GSOC_PEPPER 00057 00058 #include "DNA_speaker_types.h" 00059 00060 #endif // GSOC_PEPPER 00061 00062 #include "DNA_object_types.h" 00063 00064 #include "BLI_blenlib.h" 00065 #include "BLI_utildefines.h" 00066 #include "BLI_math_base.h" 00067 00068 #if defined WIN32 && !defined _LIBC 00069 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ 00070 #else 00071 # ifndef _GNU_SOURCE 00072 # define _GNU_SOURCE 00073 # endif 00074 # include <fnmatch.h> 00075 #endif 00076 00077 00078 #include "BKE_animsys.h" 00079 #include "BKE_context.h" 00080 #include "BKE_deform.h" 00081 #include "BKE_depsgraph.h" 00082 #include "BKE_fcurve.h" 00083 #include "BKE_global.h" 00084 #include "BKE_group.h" 00085 #include "BKE_library.h" 00086 #include "BKE_main.h" 00087 #include "BKE_modifier.h" 00088 #include "BKE_report.h" 00089 #include "BKE_scene.h" 00090 #include "BKE_sequencer.h" 00091 00092 #include "ED_armature.h" 00093 #include "ED_object.h" 00094 #include "ED_screen.h" 00095 #include "ED_util.h" 00096 00097 #include "WM_api.h" 00098 #include "WM_types.h" 00099 00100 #include "BIF_gl.h" 00101 #include "BIF_glutil.h" 00102 00103 #include "UI_interface.h" 00104 #include "UI_interface_icons.h" 00105 #include "UI_resources.h" 00106 #include "UI_view2d.h" 00107 00108 #include "RNA_access.h" 00109 #include "RNA_define.h" 00110 #include "RNA_enum_types.h" 00111 00112 #include "outliner_intern.h" 00113 00114 /* ********************************************************* */ 00115 /* Defines */ 00116 00117 #define TS_CHUNK 128 00118 00119 /* ********************************************************* */ 00120 /* Persistant Data */ 00121 00122 static void outliner_storage_cleanup(SpaceOops *soops) 00123 { 00124 TreeStore *ts= soops->treestore; 00125 00126 if(ts) { 00127 TreeStoreElem *tselem; 00128 int a, unused= 0; 00129 00130 /* each element used once, for ID blocks with more users to have each a treestore */ 00131 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) tselem->used= 0; 00132 00133 /* cleanup only after reading file or undo step, and always for 00134 * RNA datablocks view in order to save memory */ 00135 if(soops->storeflag & SO_TREESTORE_CLEANUP) { 00136 00137 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) { 00138 if(tselem->id==NULL) unused++; 00139 } 00140 00141 if(unused) { 00142 if(ts->usedelem == unused) { 00143 MEM_freeN(ts->data); 00144 ts->data= NULL; 00145 ts->usedelem= ts->totelem= 0; 00146 } 00147 else { 00148 TreeStoreElem *tsnewar, *tsnew; 00149 00150 tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem"); 00151 for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) { 00152 if(tselem->id) { 00153 *tsnew= *tselem; 00154 tsnew++; 00155 } 00156 } 00157 MEM_freeN(ts->data); 00158 ts->data= tsnewar; 00159 ts->usedelem-= unused; 00160 ts->totelem= ts->usedelem; 00161 } 00162 } 00163 } 00164 } 00165 } 00166 00167 static void check_persistant(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr) 00168 { 00169 TreeStore *ts; 00170 TreeStoreElem *tselem; 00171 int a; 00172 00173 /* case 1; no TreeStore */ 00174 if(soops->treestore==NULL) { 00175 soops->treestore= MEM_callocN(sizeof(TreeStore), "treestore"); 00176 } 00177 ts= soops->treestore; 00178 00179 /* check if 'te' is in treestore */ 00180 tselem= ts->data; 00181 for(a=0; a<ts->usedelem; a++, tselem++) { 00182 if(tselem->id==id && tselem->used==0) { 00183 if((type==0 && tselem->type==0) ||(tselem->type==type && tselem->nr==nr)) { 00184 te->store_index= a; 00185 tselem->used= 1; 00186 return; 00187 } 00188 } 00189 } 00190 00191 /* add 1 element to treestore */ 00192 if(ts->usedelem==ts->totelem) { 00193 TreeStoreElem *tsnew; 00194 00195 tsnew= MEM_mallocN((ts->totelem+TS_CHUNK)*sizeof(TreeStoreElem), "treestore data"); 00196 if(ts->data) { 00197 memcpy(tsnew, ts->data, ts->totelem*sizeof(TreeStoreElem)); 00198 MEM_freeN(ts->data); 00199 } 00200 ts->data= tsnew; 00201 ts->totelem+= TS_CHUNK; 00202 } 00203 00204 tselem= ts->data+ts->usedelem; 00205 00206 tselem->type= type; 00207 if(type) tselem->nr= nr; // we're picky! :) 00208 else tselem->nr= 0; 00209 tselem->id= id; 00210 tselem->used = 0; 00211 tselem->flag= TSE_CLOSED; 00212 te->store_index= ts->usedelem; 00213 00214 ts->usedelem++; 00215 } 00216 00217 /* ********************************************************* */ 00218 /* Tree Management */ 00219 00220 void outliner_free_tree(ListBase *lb) 00221 { 00222 while(lb->first) { 00223 TreeElement *te= lb->first; 00224 00225 outliner_free_tree(&te->subtree); 00226 BLI_remlink(lb, te); 00227 00228 if(te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); 00229 MEM_freeN(te); 00230 } 00231 } 00232 00233 /* Find ith item from the treestore */ 00234 TreeElement *outliner_find_tree_element(ListBase *lb, int store_index) 00235 { 00236 TreeElement *te= lb->first, *tes; 00237 while(te) { 00238 if(te->store_index==store_index) return te; 00239 tes= outliner_find_tree_element(&te->subtree, store_index); 00240 if(tes) return tes; 00241 te= te->next; 00242 } 00243 return NULL; 00244 } 00245 00246 /* tse is not in the treestore, we use its contents to find a match */ 00247 TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) 00248 { 00249 TreeStore *ts= soops->treestore; 00250 TreeStoreElem *tselem; 00251 int a; 00252 00253 if(tse->id==NULL) return NULL; 00254 00255 /* check if 'tse' is in treestore */ 00256 tselem= ts->data; 00257 for(a=0; a<ts->usedelem; a++, tselem++) { 00258 if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) { 00259 if(tselem->id==tse->id) { 00260 break; 00261 } 00262 } 00263 } 00264 if(tselem) 00265 return outliner_find_tree_element(&soops->tree, a); 00266 00267 return NULL; 00268 } 00269 00270 /* Find treestore that refers to given ID */ 00271 TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id) 00272 { 00273 TreeElement *te, *tes; 00274 TreeStoreElem *tselem; 00275 00276 for(te= lb->first; te; te= te->next) { 00277 tselem= TREESTORE(te); 00278 if(tselem->type==0) { 00279 if(tselem->id==id) return te; 00280 /* only deeper on scene or object */ 00281 if( te->idcode==ID_OB || te->idcode==ID_SCE || (soops->outlinevis == SO_GROUPS && te->idcode==ID_GR)) { 00282 tes= outliner_find_id(soops, &te->subtree, id); 00283 if(tes) return tes; 00284 } 00285 } 00286 } 00287 return NULL; 00288 } 00289 00290 00291 ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode) 00292 { 00293 TreeStoreElem *tselem; 00294 te= te->parent; 00295 00296 while(te) { 00297 tselem= TREESTORE(te); 00298 if(tselem->type==0 && te->idcode==idcode) return tselem->id; 00299 te= te->parent; 00300 } 00301 return NULL; 00302 } 00303 00304 00305 /* ********************************************************* */ 00306 00307 /* Prototype, see functions below */ 00308 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 00309 TreeElement *parent, short type, short index); 00310 00311 /* -------------------------------------------------------- */ 00312 00313 /* special handling of hierarchical non-lib data */ 00314 static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone, 00315 TreeElement *parent, int *a) 00316 { 00317 TreeElement *te= outliner_add_element(soops, lb, id, parent, TSE_BONE, *a); 00318 00319 (*a)++; 00320 te->name= curBone->name; 00321 te->directdata= curBone; 00322 00323 for(curBone= curBone->childbase.first; curBone; curBone=curBone->next) { 00324 outliner_add_bone(soops, &te->subtree, id, curBone, te, a); 00325 } 00326 } 00327 00328 /* -------------------------------------------------------- */ 00329 00330 #define LOG2I(x) (int)(log(x)/M_LN2) 00331 00332 static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl) 00333 { 00334 TreeStoreElem *tselem = NULL; 00335 TreeElement *te = NULL; 00336 00337 /* log stuff is to convert bitflags (powers of 2) to small integers, 00338 * in order to not overflow short tselem->nr */ 00339 00340 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED)); 00341 te->name= "Combined"; 00342 te->directdata= &srl->passflag; 00343 00344 /* save cpu cycles, but we add the first to invoke an open/close triangle */ 00345 tselem = TREESTORE(tenla); 00346 if(tselem->flag & TSE_CLOSED) 00347 return; 00348 00349 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z)); 00350 te->name= "Z"; 00351 te->directdata= &srl->passflag; 00352 00353 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR)); 00354 te->name= "Vector"; 00355 te->directdata= &srl->passflag; 00356 00357 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL)); 00358 te->name= "Normal"; 00359 te->directdata= &srl->passflag; 00360 00361 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV)); 00362 te->name= "UV"; 00363 te->directdata= &srl->passflag; 00364 00365 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST)); 00366 te->name= "Mist"; 00367 te->directdata= &srl->passflag; 00368 00369 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB)); 00370 te->name= "Index Object"; 00371 te->directdata= &srl->passflag; 00372 00373 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA)); 00374 te->name= "Index Material"; 00375 te->directdata= &srl->passflag; 00376 00377 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA)); 00378 te->name= "Color"; 00379 te->directdata= &srl->passflag; 00380 00381 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE)); 00382 te->name= "Diffuse"; 00383 te->directdata= &srl->passflag; 00384 00385 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC)); 00386 te->name= "Specular"; 00387 te->directdata= &srl->passflag; 00388 00389 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW)); 00390 te->name= "Shadow"; 00391 te->directdata= &srl->passflag; 00392 00393 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO)); 00394 te->name= "AO"; 00395 te->directdata= &srl->passflag; 00396 00397 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT)); 00398 te->name= "Reflection"; 00399 te->directdata= &srl->passflag; 00400 00401 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT)); 00402 te->name= "Refraction"; 00403 te->directdata= &srl->passflag; 00404 00405 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT)); 00406 te->name= "Indirect"; 00407 te->directdata= &srl->passflag; 00408 00409 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT)); 00410 te->name= "Environment"; 00411 te->directdata= &srl->passflag; 00412 00413 te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT)); 00414 te->name= "Emit"; 00415 te->directdata= &srl->passflag; 00416 } 00417 00418 #undef LOG2I 00419 00420 static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) 00421 { 00422 SceneRenderLayer *srl; 00423 TreeElement *tenla= outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); 00424 int a; 00425 00426 tenla->name= "RenderLayers"; 00427 for(a=0, srl= sce->r.layers.first; srl; srl= srl->next, a++) { 00428 TreeElement *tenlay= outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a); 00429 tenlay->name= srl->name; 00430 tenlay->directdata= &srl->passflag; 00431 00432 if(srl->light_override) 00433 outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0); 00434 if(srl->mat_override) 00435 outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0); 00436 00437 outliner_add_passes(soops, tenlay, &sce->id, srl); 00438 } 00439 00440 // TODO: move this to the front? 00441 if (sce->adt) 00442 outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); 00443 00444 outliner_add_element(soops, lb, sce->world, te, 0, 0); 00445 } 00446 00447 // can be inlined if necessary 00448 static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob) 00449 { 00450 int a = 0; 00451 00452 if (ob->adt) 00453 outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0); 00454 00455 outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this 00456 00457 if (ob->proxy && ob->id.lib==NULL) 00458 outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0); 00459 00460 outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0); 00461 00462 if (ob->pose) { 00463 bArmature *arm= ob->data; 00464 bPoseChannel *pchan; 00465 TreeElement *ten; 00466 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0); 00467 00468 tenla->name= "Pose"; 00469 00470 /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ 00471 if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) { 00472 int a= 0, const_index= 1000; /* ensure unique id for bone constraints */ 00473 00474 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) { 00475 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a); 00476 ten->name= pchan->name; 00477 ten->directdata= pchan; 00478 pchan->prev= (bPoseChannel *)ten; 00479 00480 if(pchan->constraints.first) { 00481 //Object *target; 00482 bConstraint *con; 00483 TreeElement *ten1; 00484 TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); 00485 //char *str; 00486 00487 tenla1->name= "Constraints"; 00488 for(con= pchan->constraints.first; con; con= con->next, const_index++) { 00489 ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); 00490 #if 0 /* disabled as it needs to be reworked for recoded constraints system */ 00491 target= get_constraint_target(con, &str); 00492 if(str && str[0]) ten1->name= str; 00493 else if(target) ten1->name= target->id.name+2; 00494 else ten1->name= con->name; 00495 #endif 00496 ten1->name= con->name; 00497 ten1->directdata= con; 00498 /* possible add all other types links? */ 00499 } 00500 } 00501 } 00502 /* make hierarchy */ 00503 ten= tenla->subtree.first; 00504 while(ten) { 00505 TreeElement *nten= ten->next, *par; 00506 tselem= TREESTORE(ten); 00507 if(tselem->type==TSE_POSE_CHANNEL) { 00508 pchan= (bPoseChannel *)ten->directdata; 00509 if(pchan->parent) { 00510 BLI_remlink(&tenla->subtree, ten); 00511 par= (TreeElement *)pchan->parent->prev; 00512 BLI_addtail(&par->subtree, ten); 00513 ten->parent= par; 00514 } 00515 } 00516 ten= nten; 00517 } 00518 /* restore prev pointers */ 00519 pchan= ob->pose->chanbase.first; 00520 if(pchan) pchan->prev= NULL; 00521 for(; pchan; pchan= pchan->next) { 00522 if(pchan->next) pchan->next->prev= pchan; 00523 } 00524 } 00525 00526 /* Pose Groups */ 00527 if(ob->pose->agroups.first) { 00528 bActionGroup *agrp; 00529 TreeElement *ten; 00530 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0); 00531 int a= 0; 00532 00533 tenla->name= "Bone Groups"; 00534 for (agrp=ob->pose->agroups.first; agrp; agrp=agrp->next, a++) { 00535 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a); 00536 ten->name= agrp->name; 00537 ten->directdata= agrp; 00538 } 00539 } 00540 } 00541 00542 for(a=0; a<ob->totcol; a++) 00543 outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a); 00544 00545 if(ob->constraints.first) { 00546 //Object *target; 00547 bConstraint *con; 00548 TreeElement *ten; 00549 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0); 00550 //char *str; 00551 00552 tenla->name= "Constraints"; 00553 for (con=ob->constraints.first, a=0; con; con= con->next, a++) { 00554 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a); 00555 #if 0 /* disabled due to constraints system targets recode... code here needs review */ 00556 target= get_constraint_target(con, &str); 00557 if(str && str[0]) ten->name= str; 00558 else if(target) ten->name= target->id.name+2; 00559 else ten->name= con->name; 00560 #endif 00561 ten->name= con->name; 00562 ten->directdata= con; 00563 /* possible add all other types links? */ 00564 } 00565 } 00566 00567 if (ob->modifiers.first) { 00568 ModifierData *md; 00569 TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); 00570 int index; 00571 00572 temod->name = "Modifiers"; 00573 for (index=0,md=ob->modifiers.first; md; index++,md=md->next) { 00574 TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index); 00575 te->name= md->name; 00576 te->directdata = md; 00577 00578 if (md->type==eModifierType_Lattice) { 00579 outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0); 00580 } 00581 else if (md->type==eModifierType_Curve) { 00582 outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0); 00583 } 00584 else if (md->type==eModifierType_Armature) { 00585 outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0); 00586 } 00587 else if (md->type==eModifierType_Hook) { 00588 outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0); 00589 } 00590 else if (md->type==eModifierType_ParticleSystem) { 00591 TreeElement *ten; 00592 ParticleSystem *psys= ((ParticleSystemModifierData*) md)->psys; 00593 00594 ten = outliner_add_element(soops, &te->subtree, ob, te, TSE_LINKED_PSYS, 0); 00595 ten->directdata = psys; 00596 ten->name = psys->part->id.name+2; 00597 } 00598 } 00599 } 00600 00601 /* vertex groups */ 00602 if (ob->defbase.first) { 00603 bDeformGroup *defgroup; 00604 TreeElement *ten; 00605 TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); 00606 00607 tenla->name= "Vertex Groups"; 00608 for (defgroup=ob->defbase.first, a=0; defgroup; defgroup=defgroup->next, a++) { 00609 ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a); 00610 ten->name= defgroup->name; 00611 ten->directdata= defgroup; 00612 } 00613 } 00614 00615 /* duplicated group */ 00616 if (ob->dup_group) 00617 outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0); 00618 } 00619 00620 // can be inlined if necessary 00621 static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, ID *id) 00622 { 00623 /* tuck pointer back in object, to construct hierarchy */ 00624 if (GS(id->name)==ID_OB) id->newid= (ID *)te; 00625 00626 /* expand specific data always */ 00627 switch (GS(id->name)) { 00628 case ID_LI: 00629 { 00630 te->name= ((Library *)id)->name; 00631 } 00632 break; 00633 case ID_SCE: 00634 { 00635 outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te); 00636 } 00637 break; 00638 case ID_OB: 00639 { 00640 outliner_add_object_contents(soops, te, tselem, (Object *)id); 00641 } 00642 break; 00643 case ID_ME: 00644 { 00645 Mesh *me= (Mesh *)id; 00646 int a; 00647 00648 if (me->adt) 00649 outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0); 00650 00651 outliner_add_element(soops, &te->subtree, me->key, te, 0, 0); 00652 for(a=0; a<me->totcol; a++) 00653 outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a); 00654 /* could do tfaces with image links, but the images are not grouped nicely. 00655 would require going over all tfaces, sort images in use. etc... */ 00656 } 00657 break; 00658 case ID_CU: 00659 { 00660 Curve *cu= (Curve *)id; 00661 int a; 00662 00663 if (cu->adt) 00664 outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0); 00665 00666 for(a=0; a<cu->totcol; a++) 00667 outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a); 00668 } 00669 break; 00670 case ID_MB: 00671 { 00672 MetaBall *mb= (MetaBall *)id; 00673 int a; 00674 00675 if (mb->adt) 00676 outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0); 00677 00678 for(a=0; a<mb->totcol; a++) 00679 outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a); 00680 } 00681 break; 00682 case ID_MA: 00683 { 00684 Material *ma= (Material *)id; 00685 int a; 00686 00687 if (ma->adt) 00688 outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0); 00689 00690 for(a=0; a<MAX_MTEX; a++) { 00691 if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a); 00692 } 00693 } 00694 break; 00695 case ID_TE: 00696 { 00697 Tex *tex= (Tex *)id; 00698 00699 if (tex->adt) 00700 outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0); 00701 00702 outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0); 00703 } 00704 break; 00705 case ID_CA: 00706 { 00707 Camera *ca= (Camera *)id; 00708 00709 if (ca->adt) 00710 outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0); 00711 } 00712 break; 00713 case ID_LA: 00714 { 00715 Lamp *la= (Lamp *)id; 00716 int a; 00717 00718 if (la->adt) 00719 outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0); 00720 00721 for(a=0; a<MAX_MTEX; a++) { 00722 if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a); 00723 } 00724 } 00725 break; 00726 00727 #if 0 // GSOC_PEPPER 00728 00729 case ID_SPK: 00730 { 00731 Speaker *spk= (Speaker *)id; 00732 00733 if(spk->adt) 00734 outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0); 00735 } 00736 break; 00737 00738 #endif // GSOC_PEPPER 00739 00740 case ID_WO: 00741 { 00742 World *wrld= (World *)id; 00743 int a; 00744 00745 if (wrld->adt) 00746 outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0); 00747 00748 for(a=0; a<MAX_MTEX; a++) { 00749 if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a); 00750 } 00751 } 00752 break; 00753 case ID_KE: 00754 { 00755 Key *key= (Key *)id; 00756 00757 if (key->adt) 00758 outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0); 00759 } 00760 break; 00761 case ID_AC: 00762 { 00763 // XXX do we want to be exposing the F-Curves here? 00764 //bAction *act= (bAction *)id; 00765 } 00766 break; 00767 case ID_AR: 00768 { 00769 bArmature *arm= (bArmature *)id; 00770 int a= 0; 00771 00772 if (arm->adt) 00773 outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0); 00774 00775 if(arm->edbo) { 00776 EditBone *ebone; 00777 TreeElement *ten; 00778 00779 for (ebone = arm->edbo->first; ebone; ebone=ebone->next, a++) { 00780 ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a); 00781 ten->directdata= ebone; 00782 ten->name= ebone->name; 00783 ebone->temp= ten; 00784 } 00785 /* make hierarchy */ 00786 ten= te->subtree.first; 00787 while(ten) { 00788 TreeElement *nten= ten->next, *par; 00789 ebone= (EditBone *)ten->directdata; 00790 if(ebone->parent) { 00791 BLI_remlink(&te->subtree, ten); 00792 par= ebone->parent->temp; 00793 BLI_addtail(&par->subtree, ten); 00794 ten->parent= par; 00795 } 00796 ten= nten; 00797 } 00798 } 00799 else { 00800 /* do not extend Armature when we have posemode */ 00801 tselem= TREESTORE(te->parent); 00802 if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE); 00803 else { 00804 Bone *curBone; 00805 for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){ 00806 outliner_add_bone(soops, &te->subtree, id, curBone, te, &a); 00807 } 00808 } 00809 } 00810 } 00811 break; 00812 } 00813 } 00814 00815 // TODO: this function needs to be split up! It's getting a bit too large... 00816 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 00817 TreeElement *parent, short type, short index) 00818 { 00819 TreeElement *te; 00820 TreeStoreElem *tselem; 00821 ID *id= idv; 00822 int a = 0; 00823 00824 if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { 00825 id= ((PointerRNA*)idv)->id.data; 00826 if(!id) id= ((PointerRNA*)idv)->data; 00827 } 00828 00829 if(id==NULL) return NULL; 00830 00831 te= MEM_callocN(sizeof(TreeElement), "tree elem"); 00832 /* add to the visual tree */ 00833 BLI_addtail(lb, te); 00834 /* add to the storage */ 00835 check_persistant(soops, te, id, type, index); 00836 tselem= TREESTORE(te); 00837 00838 te->parent= parent; 00839 te->index= index; // for data arays 00840 if(ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)); 00841 else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)); 00842 else if(type==TSE_ANIM_DATA); 00843 else { 00844 te->name= id->name+2; // default, can be overridden by Library or non-ID data 00845 te->idcode= GS(id->name); 00846 } 00847 00848 if(type==0) { 00849 /* ID datablock */ 00850 outliner_add_id_contents(soops, te, tselem, id); 00851 } 00852 else if(type==TSE_ANIM_DATA) { 00853 IdAdtTemplate *iat = (IdAdtTemplate *)idv; 00854 AnimData *adt= (AnimData *)iat->adt; 00855 00856 /* this element's info */ 00857 te->name= "Animation"; 00858 te->directdata= adt; 00859 00860 /* Action */ 00861 outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0); 00862 00863 /* Drivers */ 00864 if (adt->drivers.first) { 00865 TreeElement *ted= outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0); 00866 ID *lastadded= NULL; 00867 FCurve *fcu; 00868 00869 ted->name= "Drivers"; 00870 00871 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) { 00872 if (fcu->driver && fcu->driver->variables.first) { 00873 ChannelDriver *driver= fcu->driver; 00874 DriverVar *dvar; 00875 00876 for (dvar= driver->variables.first; dvar; dvar= dvar->next) { 00877 /* loop over all targets used here */ 00878 DRIVER_TARGETS_USED_LOOPER(dvar) 00879 { 00880 if (lastadded != dtar->id) { 00881 // XXX this lastadded check is rather lame, and also fails quite badly... 00882 outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0); 00883 lastadded= dtar->id; 00884 } 00885 } 00886 DRIVER_TARGETS_LOOPER_END 00887 } 00888 } 00889 } 00890 } 00891 00892 /* NLA Data */ 00893 if (adt->nla_tracks.first) { 00894 TreeElement *tenla= outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0); 00895 NlaTrack *nlt; 00896 int a= 0; 00897 00898 tenla->name= "NLA Tracks"; 00899 00900 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 00901 TreeElement *tenlt= outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); 00902 NlaStrip *strip; 00903 TreeElement *ten; 00904 int b= 0; 00905 00906 tenlt->name= nlt->name; 00907 00908 for (strip=nlt->strips.first; strip; strip=strip->next, b++) { 00909 ten= outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b); 00910 if(ten) ten->directdata= strip; 00911 } 00912 } 00913 } 00914 } 00915 else if(type==TSE_SEQUENCE) { 00916 Sequence *seq= (Sequence*) idv; 00917 Sequence *p; 00918 00919 /* 00920 * The idcode is a little hack, but the outliner 00921 * only check te->idcode if te->type is equal to zero, 00922 * so this is "safe". 00923 */ 00924 te->idcode= seq->type; 00925 te->directdata= seq; 00926 00927 if(seq->type<7) { 00928 /* 00929 * This work like the sequence. 00930 * If the sequence have a name (not default name) 00931 * show it, in other case put the filename. 00932 */ 00933 if(strcmp(seq->name, "SQ")) 00934 te->name= seq->name; 00935 else { 00936 if((seq->strip) && (seq->strip->stripdata)) 00937 te->name= seq->strip->stripdata->name; 00938 else 00939 te->name= "SQ None"; 00940 } 00941 00942 if(seq->type==SEQ_META) { 00943 te->name= "Meta Strip"; 00944 p= seq->seqbase.first; 00945 while(p) { 00946 outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index); 00947 p= p->next; 00948 } 00949 } 00950 else 00951 outliner_add_element(soops, &te->subtree, (void*)seq->strip, te, TSE_SEQ_STRIP, index); 00952 } 00953 else 00954 te->name= "Effect"; 00955 } 00956 else if(type==TSE_SEQ_STRIP) { 00957 Strip *strip= (Strip *)idv; 00958 00959 if(strip->dir) 00960 te->name= strip->dir; 00961 else 00962 te->name= "Strip None"; 00963 te->directdata= strip; 00964 } 00965 else if(type==TSE_SEQUENCE_DUP) { 00966 Sequence *seq= (Sequence*)idv; 00967 00968 te->idcode= seq->type; 00969 te->directdata= seq; 00970 te->name= seq->strip->stripdata->name; 00971 } 00972 else if(ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { 00973 PointerRNA pptr, propptr, *ptr= (PointerRNA*)idv; 00974 PropertyRNA *prop, *iterprop; 00975 PropertyType proptype; 00976 int a, tot; 00977 00978 /* we do lazy build, for speed and to avoid infinite recusion */ 00979 00980 if(ptr->data == NULL) { 00981 te->name= "(empty)"; 00982 } 00983 else if(type == TSE_RNA_STRUCT) { 00984 /* struct */ 00985 te->name= RNA_struct_name_get_alloc(ptr, NULL, 0); 00986 00987 if(te->name) 00988 te->flag |= TE_FREE_NAME; 00989 else 00990 te->name= (char*)RNA_struct_ui_name(ptr->type); 00991 00992 iterprop= RNA_struct_iterator_property(ptr->type); 00993 tot= RNA_property_collection_length(ptr, iterprop); 00994 00995 /* auto open these cases */ 00996 if(!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) 00997 if(!tselem->used) 00998 tselem->flag &= ~TSE_CLOSED; 00999 01000 if(!(tselem->flag & TSE_CLOSED)) { 01001 for(a=0; a<tot; a++) 01002 outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_PROPERTY, a); 01003 } 01004 else if(tot) 01005 te->flag |= TE_LAZY_CLOSED; 01006 01007 te->rnaptr= *ptr; 01008 } 01009 else if(type == TSE_RNA_PROPERTY) { 01010 /* property */ 01011 iterprop= RNA_struct_iterator_property(ptr->type); 01012 RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr); 01013 01014 prop= propptr.data; 01015 proptype= RNA_property_type(prop); 01016 01017 te->name= (char*)RNA_property_ui_name(prop); 01018 te->directdata= prop; 01019 te->rnaptr= *ptr; 01020 01021 if(proptype == PROP_POINTER) { 01022 pptr= RNA_property_pointer_get(ptr, prop); 01023 01024 if(pptr.data) { 01025 if(!(tselem->flag & TSE_CLOSED)) 01026 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, -1); 01027 else 01028 te->flag |= TE_LAZY_CLOSED; 01029 } 01030 } 01031 else if(proptype == PROP_COLLECTION) { 01032 tot= RNA_property_collection_length(ptr, prop); 01033 01034 if(!(tselem->flag & TSE_CLOSED)) { 01035 for(a=0; a<tot; a++) { 01036 RNA_property_collection_lookup_int(ptr, prop, a, &pptr); 01037 outliner_add_element(soops, &te->subtree, (void*)&pptr, te, TSE_RNA_STRUCT, a); 01038 } 01039 } 01040 else if(tot) 01041 te->flag |= TE_LAZY_CLOSED; 01042 } 01043 else if(ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { 01044 tot= RNA_property_array_length(ptr, prop); 01045 01046 if(!(tselem->flag & TSE_CLOSED)) { 01047 for(a=0; a<tot; a++) 01048 outliner_add_element(soops, &te->subtree, (void*)ptr, te, TSE_RNA_ARRAY_ELEM, a); 01049 } 01050 else if(tot) 01051 te->flag |= TE_LAZY_CLOSED; 01052 } 01053 } 01054 else if(type == TSE_RNA_ARRAY_ELEM) { 01055 char c; 01056 01057 prop= parent->directdata; 01058 01059 te->directdata= prop; 01060 te->rnaptr= *ptr; 01061 te->index= index; 01062 01063 c= RNA_property_array_item_char(prop, index); 01064 01065 te->name= MEM_callocN(sizeof(char)*20, "OutlinerRNAArrayName"); 01066 if(c) sprintf((char *)te->name, " %c", c); 01067 else sprintf((char *)te->name, " %d", index+1); 01068 te->flag |= TE_FREE_NAME; 01069 } 01070 } 01071 else if(type == TSE_KEYMAP) { 01072 wmKeyMap *km= (wmKeyMap *)idv; 01073 wmKeyMapItem *kmi; 01074 char opname[OP_MAX_TYPENAME]; 01075 01076 te->directdata= idv; 01077 te->name= km->idname; 01078 01079 if(!(tselem->flag & TSE_CLOSED)) { 01080 a= 0; 01081 01082 for (kmi= km->items.first; kmi; kmi= kmi->next, a++) { 01083 const char *key= WM_key_event_string(kmi->type); 01084 01085 if(key[0]) { 01086 wmOperatorType *ot= NULL; 01087 01088 if(kmi->propvalue); 01089 else ot= WM_operatortype_find(kmi->idname, 0); 01090 01091 if(ot || kmi->propvalue) { 01092 TreeElement *ten= outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a); 01093 01094 ten->directdata= kmi; 01095 01096 if(kmi->propvalue) { 01097 ten->name= "Modal map, not yet"; 01098 } 01099 else { 01100 WM_operator_py_idname(opname, ot->idname); 01101 ten->name= BLI_strdup(opname); 01102 ten->flag |= TE_FREE_NAME; 01103 } 01104 } 01105 } 01106 } 01107 } 01108 else 01109 te->flag |= TE_LAZY_CLOSED; 01110 } 01111 01112 return te; 01113 } 01114 01115 /* ======================================================= */ 01116 /* Sequencer mode tree building */ 01117 01118 /* Helped function to put duplicate sequence in the same tree. */ 01119 static int need_add_seq_dup(Sequence *seq) 01120 { 01121 Sequence *p; 01122 01123 if((!seq->strip) || (!seq->strip->stripdata) || (!seq->strip->stripdata->name)) 01124 return(1); 01125 01126 /* 01127 * First check backward, if we found a duplicate 01128 * sequence before this, don't need it, just return. 01129 */ 01130 p= seq->prev; 01131 while(p) { 01132 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) { 01133 p= p->prev; 01134 continue; 01135 } 01136 01137 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) 01138 return(2); 01139 p= p->prev; 01140 } 01141 01142 p= seq->next; 01143 while(p) { 01144 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) { 01145 p= p->next; 01146 continue; 01147 } 01148 01149 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) 01150 return(0); 01151 p= p->next; 01152 } 01153 return(1); 01154 } 01155 01156 static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index) 01157 { 01158 TreeElement *ch; 01159 Sequence *p; 01160 01161 p= seq; 01162 while(p) { 01163 if((!p->strip) || (!p->strip->stripdata) || (!p->strip->stripdata->name)) { 01164 p= p->next; 01165 continue; 01166 } 01167 01168 if(!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) 01169 ch= outliner_add_element(soops, &te->subtree, (void*)p, te, TSE_SEQUENCE, index); 01170 p= p->next; 01171 } 01172 } 01173 01174 /* ======================================================= */ 01175 /* Generic Tree Building helpers - order these are called is top to bottom */ 01176 01177 /* Hierarchy --------------------------------------------- */ 01178 01179 /* make sure elements are correctly nested */ 01180 static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb) 01181 { 01182 TreeElement *te, *ten, *tep; 01183 TreeStoreElem *tselem; 01184 01185 /* build hierarchy */ 01186 // XXX also, set extents here... 01187 te= lb->first; 01188 while(te) { 01189 ten= te->next; 01190 tselem= TREESTORE(te); 01191 01192 if(tselem->type==0 && te->idcode==ID_OB) { 01193 Object *ob= (Object *)tselem->id; 01194 if(ob->parent && ob->parent->id.newid) { 01195 BLI_remlink(lb, te); 01196 tep= (TreeElement *)ob->parent->id.newid; 01197 BLI_addtail(&tep->subtree, te); 01198 // set correct parent pointers 01199 for(te=tep->subtree.first; te; te= te->next) te->parent= tep; 01200 } 01201 } 01202 te= ten; 01203 } 01204 } 01205 01206 /* Sorting ------------------------------------------------------ */ 01207 01208 typedef struct tTreeSort { 01209 TreeElement *te; 01210 ID *id; 01211 const char *name; 01212 short idcode; 01213 } tTreeSort; 01214 01215 /* alphabetical comparator */ 01216 static int treesort_alpha(const void *v1, const void *v2) 01217 { 01218 const tTreeSort *x1= v1, *x2= v2; 01219 int comp; 01220 01221 /* first put objects last (hierarchy) */ 01222 comp= (x1->idcode==ID_OB); 01223 if(x2->idcode==ID_OB) comp+=2; 01224 01225 if(comp==1) return 1; 01226 else if(comp==2) return -1; 01227 else if(comp==3) { 01228 comp= strcmp(x1->name, x2->name); 01229 01230 if( comp>0 ) return 1; 01231 else if( comp<0) return -1; 01232 return 0; 01233 } 01234 return 0; 01235 } 01236 01237 /* this is nice option for later? doesnt look too useful... */ 01238 #if 0 01239 static int treesort_obtype_alpha(const void *v1, const void *v2) 01240 { 01241 const tTreeSort *x1= v1, *x2= v2; 01242 01243 /* first put objects last (hierarchy) */ 01244 if(x1->idcode==ID_OB && x2->idcode!=ID_OB) return 1; 01245 else if(x2->idcode==ID_OB && x1->idcode!=ID_OB) return -1; 01246 else { 01247 /* 2nd we check ob type */ 01248 if(x1->idcode==ID_OB && x2->idcode==ID_OB) { 01249 if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1; 01250 else if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1; 01251 else return 0; 01252 } 01253 else { 01254 int comp= strcmp(x1->name, x2->name); 01255 01256 if( comp>0 ) return 1; 01257 else if( comp<0) return -1; 01258 return 0; 01259 } 01260 } 01261 } 01262 #endif 01263 01264 /* sort happens on each subtree individual */ 01265 static void outliner_sort(SpaceOops *soops, ListBase *lb) 01266 { 01267 TreeElement *te; 01268 TreeStoreElem *tselem; 01269 int totelem=0; 01270 01271 te= lb->last; 01272 if(te==NULL) return; 01273 tselem= TREESTORE(te); 01274 01275 /* sorting rules; only object lists or deformgroups */ 01276 if( (tselem->type==TSE_DEFGROUP) || (tselem->type==0 && te->idcode==ID_OB)) { 01277 01278 /* count first */ 01279 for(te= lb->first; te; te= te->next) totelem++; 01280 01281 if(totelem>1) { 01282 tTreeSort *tear= MEM_mallocN(totelem*sizeof(tTreeSort), "tree sort array"); 01283 tTreeSort *tp=tear; 01284 int skip= 0; 01285 01286 for(te= lb->first; te; te= te->next, tp++) { 01287 tselem= TREESTORE(te); 01288 tp->te= te; 01289 tp->name= te->name; 01290 tp->idcode= te->idcode; 01291 if(tselem->type && tselem->type!=TSE_DEFGROUP) tp->idcode= 0; // dont sort this 01292 tp->id= tselem->id; 01293 } 01294 /* keep beginning of list */ 01295 for(tp= tear, skip=0; skip<totelem; skip++, tp++) 01296 if(tp->idcode) break; 01297 01298 if(skip<totelem) 01299 qsort(tear+skip, totelem-skip, sizeof(tTreeSort), treesort_alpha); 01300 01301 lb->first=lb->last= NULL; 01302 tp= tear; 01303 while(totelem--) { 01304 BLI_addtail(lb, tp->te); 01305 tp++; 01306 } 01307 MEM_freeN(tear); 01308 } 01309 } 01310 01311 for(te= lb->first; te; te= te->next) { 01312 outliner_sort(soops, &te->subtree); 01313 } 01314 } 01315 01316 /* Filtering ----------------------------------------------- */ 01317 01318 static int outliner_filter_has_name(TreeElement *te, const char *name, int flags) 01319 { 01320 #if 0 01321 int found= 0; 01322 01323 /* determine if match */ 01324 if (flags & SO_FIND_CASE_SENSITIVE) { 01325 if (flags & SO_FIND_COMPLETE) 01326 found= strcmp(te->name, name) == 0; 01327 else 01328 found= strstr(te->name, name) != NULL; 01329 } 01330 else { 01331 if (flags & SO_FIND_COMPLETE) 01332 found= BLI_strcasecmp(te->name, name) == 0; 01333 else 01334 found= BLI_strcasestr(te->name, name) != NULL; 01335 } 01336 #else 01337 01338 int fn_flag= 0; 01339 int found= 0; 01340 01341 if ((flags & SO_FIND_CASE_SENSITIVE) == 0) 01342 fn_flag |= FNM_CASEFOLD; 01343 01344 if (flags & SO_FIND_COMPLETE) { 01345 found= fnmatch(name, te->name, fn_flag)==0; 01346 } 01347 else { 01348 char fn_name[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; 01349 sprintf(fn_name, "*%s*", name); 01350 found= fnmatch(fn_name, te->name, fn_flag)==0; 01351 } 01352 return found; 01353 #endif 01354 } 01355 01356 static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) 01357 { 01358 TreeElement *te, *ten; 01359 TreeStoreElem *tselem; 01360 01361 /* although we don't have any search string, we return TRUE 01362 * since the entire tree is ok then... 01363 */ 01364 if (soops->search_string[0]==0) 01365 return 1; 01366 01367 for (te= lb->first; te; te= ten) { 01368 ten= te->next; 01369 01370 if (0==outliner_filter_has_name(te, soops->search_string, soops->search_flags)) { 01371 /* item isn't something we're looking for, but... 01372 * - if the subtree is expanded, check if there are any matches that can be easily found 01373 * so that searching for "cu" in the default scene will still match the Cube 01374 * - otherwise, we can't see within the subtree and the item doesn't match, 01375 * so these can be safely ignored (i.e. the subtree can get freed) 01376 */ 01377 tselem= TREESTORE(te); 01378 01379 if ((tselem->flag & TSE_CLOSED) || outliner_filter_tree(soops, &te->subtree)==0) { 01380 outliner_free_tree(&te->subtree); 01381 BLI_remlink(lb, te); 01382 01383 if(te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); 01384 MEM_freeN(te); 01385 } 01386 } 01387 else { 01388 /* filter subtree too */ 01389 outliner_filter_tree(soops, &te->subtree); 01390 } 01391 } 01392 01393 /* if there are still items in the list, that means that there were still some matches */ 01394 return (lb->first != NULL); 01395 } 01396 01397 /* ======================================================= */ 01398 /* Main Tree Building API */ 01399 01400 /* Main entry point for building the tree data-structure that the outliner represents */ 01401 // TODO: split each mode into its own function? 01402 void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) 01403 { 01404 Base *base; 01405 Object *ob; 01406 TreeElement *te=NULL, *ten; 01407 TreeStoreElem *tselem; 01408 int show_opened= (soops->treestore==NULL); /* on first view, we open scenes */ 01409 01410 if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW)) 01411 return; 01412 01413 outliner_free_tree(&soops->tree); 01414 outliner_storage_cleanup(soops); 01415 01416 /* clear ob id.new flags */ 01417 for(ob= mainvar->object.first; ob; ob= ob->id.next) ob->id.newid= NULL; 01418 01419 /* options */ 01420 if(soops->outlinevis == SO_LIBRARIES) { 01421 Library *lib; 01422 01423 for(lib= mainvar->library.first; lib; lib= lib->id.next) { 01424 ten= outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0); 01425 lib->id.newid= (ID *)ten; 01426 } 01427 /* make hierarchy */ 01428 ten= soops->tree.first; 01429 while(ten) { 01430 TreeElement *nten= ten->next, *par; 01431 tselem= TREESTORE(ten); 01432 lib= (Library *)tselem->id; 01433 if(lib->parent) { 01434 BLI_remlink(&soops->tree, ten); 01435 par= (TreeElement *)lib->parent->id.newid; 01436 BLI_addtail(&par->subtree, ten); 01437 ten->parent= par; 01438 } 01439 ten= nten; 01440 } 01441 /* restore newid pointers */ 01442 for(lib= mainvar->library.first; lib; lib= lib->id.next) 01443 lib->id.newid= NULL; 01444 01445 } 01446 else if(soops->outlinevis == SO_ALL_SCENES) { 01447 Scene *sce; 01448 for(sce= mainvar->scene.first; sce; sce= sce->id.next) { 01449 te= outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0); 01450 tselem= TREESTORE(te); 01451 if(sce==scene && show_opened) 01452 tselem->flag &= ~TSE_CLOSED; 01453 01454 for(base= sce->base.first; base; base= base->next) { 01455 ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0); 01456 ten->directdata= base; 01457 } 01458 outliner_make_hierarchy(soops, &te->subtree); 01459 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ 01460 for(base= sce->base.first; base; base= base->next) base->object->id.newid= NULL; 01461 } 01462 } 01463 else if(soops->outlinevis == SO_CUR_SCENE) { 01464 01465 outliner_add_scene_contents(soops, &soops->tree, scene, NULL); 01466 01467 for(base= scene->base.first; base; base= base->next) { 01468 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); 01469 ten->directdata= base; 01470 } 01471 outliner_make_hierarchy(soops, &soops->tree); 01472 } 01473 else if(soops->outlinevis == SO_VISIBLE) { 01474 for(base= scene->base.first; base; base= base->next) { 01475 if(base->lay & scene->lay) 01476 outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); 01477 } 01478 outliner_make_hierarchy(soops, &soops->tree); 01479 } 01480 else if(soops->outlinevis == SO_GROUPS) { 01481 Group *group; 01482 GroupObject *go; 01483 01484 for(group= mainvar->group.first; group; group= group->id.next) { 01485 if(group->gobject.first) { 01486 te= outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); 01487 01488 for(go= group->gobject.first; go; go= go->next) { 01489 ten= outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0); 01490 ten->directdata= NULL; /* eh, why? */ 01491 } 01492 outliner_make_hierarchy(soops, &te->subtree); 01493 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ 01494 for(go= group->gobject.first; go; go= go->next) go->ob->id.newid= NULL; 01495 } 01496 } 01497 } 01498 else if(soops->outlinevis == SO_SAME_TYPE) { 01499 Object *ob= OBACT; 01500 if(ob) { 01501 for(base= scene->base.first; base; base= base->next) { 01502 if(base->object->type==ob->type) { 01503 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); 01504 ten->directdata= base; 01505 } 01506 } 01507 outliner_make_hierarchy(soops, &soops->tree); 01508 } 01509 } 01510 else if(soops->outlinevis == SO_SELECTED) { 01511 for(base= scene->base.first; base; base= base->next) { 01512 if(base->lay & scene->lay) { 01513 if(base==BASACT || (base->flag & SELECT)) { 01514 ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); 01515 ten->directdata= base; 01516 } 01517 } 01518 } 01519 outliner_make_hierarchy(soops, &soops->tree); 01520 } 01521 else if(soops->outlinevis==SO_SEQUENCE) { 01522 Sequence *seq; 01523 Editing *ed= seq_give_editing(scene, FALSE); 01524 int op; 01525 01526 if(ed==NULL) 01527 return; 01528 01529 seq= ed->seqbasep->first; 01530 if(!seq) 01531 return; 01532 01533 while(seq) { 01534 op= need_add_seq_dup(seq); 01535 if(op==1) 01536 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE, 0); 01537 else if(op==0) { 01538 ten= outliner_add_element(soops, &soops->tree, (void*)seq, NULL, TSE_SEQUENCE_DUP, 0); 01539 outliner_add_seq_dup(soops, seq, ten, 0); 01540 } 01541 seq= seq->next; 01542 } 01543 } 01544 else if(soops->outlinevis==SO_DATABLOCKS) { 01545 PointerRNA mainptr; 01546 01547 RNA_main_pointer_create(mainvar, &mainptr); 01548 01549 ten= outliner_add_element(soops, &soops->tree, (void*)&mainptr, NULL, TSE_RNA_STRUCT, -1); 01550 01551 if(show_opened) { 01552 tselem= TREESTORE(ten); 01553 tselem->flag &= ~TSE_CLOSED; 01554 } 01555 } 01556 else if(soops->outlinevis==SO_USERDEF) { 01557 PointerRNA userdefptr; 01558 01559 RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr); 01560 01561 ten= outliner_add_element(soops, &soops->tree, (void*)&userdefptr, NULL, TSE_RNA_STRUCT, -1); 01562 01563 if(show_opened) { 01564 tselem= TREESTORE(ten); 01565 tselem->flag &= ~TSE_CLOSED; 01566 } 01567 } 01568 else if(soops->outlinevis==SO_KEYMAP) { 01569 wmWindowManager *wm= mainvar->wm.first; 01570 wmKeyMap *km; 01571 01572 for(km= wm->defaultconf->keymaps.first; km; km= km->next) { 01573 ten= outliner_add_element(soops, &soops->tree, (void*)km, NULL, TSE_KEYMAP, 0); 01574 } 01575 } 01576 else { 01577 ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0); 01578 if(ten) ten->directdata= BASACT; 01579 } 01580 01581 outliner_sort(soops, &soops->tree); 01582 outliner_filter_tree(soops, &soops->tree); 01583 } 01584 01585