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