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_object_types.h" 00054 00055 #include "BLI_blenlib.h" 00056 #include "BLI_utildefines.h" 00057 #include "BLI_math_base.h" 00058 00059 #if defined WIN32 && !defined _LIBC 00060 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ 00061 #else 00062 # ifndef _GNU_SOURCE 00063 # define _GNU_SOURCE 00064 # endif 00065 # include <fnmatch.h> 00066 #endif 00067 00068 00069 #include "BKE_animsys.h" 00070 #include "BKE_context.h" 00071 #include "BKE_deform.h" 00072 #include "BKE_depsgraph.h" 00073 #include "BKE_fcurve.h" 00074 #include "BKE_global.h" 00075 #include "BKE_group.h" 00076 #include "BKE_library.h" 00077 #include "BKE_main.h" 00078 #include "BKE_modifier.h" 00079 #include "BKE_report.h" 00080 #include "BKE_scene.h" 00081 #include "BKE_sequencer.h" 00082 00083 #include "ED_armature.h" 00084 #include "ED_object.h" 00085 #include "ED_screen.h" 00086 #include "ED_util.h" 00087 00088 #include "WM_api.h" 00089 #include "WM_types.h" 00090 00091 #include "BIF_gl.h" 00092 #include "BIF_glutil.h" 00093 00094 #include "UI_interface.h" 00095 #include "UI_interface_icons.h" 00096 #include "UI_resources.h" 00097 #include "UI_view2d.h" 00098 00099 #include "RNA_access.h" 00100 #include "RNA_define.h" 00101 #include "RNA_enum_types.h" 00102 00103 #include "outliner_intern.h" 00104 00105 /* ****************************************************** */ 00106 00107 /* ************ SELECTION OPERATIONS ********* */ 00108 00109 static void set_operation_types(SpaceOops *soops, ListBase *lb, 00110 int *scenelevel, 00111 int *objectlevel, 00112 int *idlevel, 00113 int *datalevel) 00114 { 00115 TreeElement *te; 00116 TreeStoreElem *tselem; 00117 00118 for(te= lb->first; te; te= te->next) { 00119 tselem= TREESTORE(te); 00120 if(tselem->flag & TSE_SELECTED) { 00121 if(tselem->type) { 00122 if(*datalevel==0) 00123 *datalevel= tselem->type; 00124 else if(*datalevel!=tselem->type) 00125 *datalevel= -1; 00126 } 00127 else { 00128 int idcode= GS(tselem->id->name); 00129 switch(idcode) { 00130 case ID_SCE: 00131 *scenelevel= 1; 00132 break; 00133 case ID_OB: 00134 *objectlevel= 1; 00135 break; 00136 00137 case ID_ME: case ID_CU: case ID_MB: case ID_LT: 00138 case ID_LA: case ID_AR: case ID_CA: case ID_SPK: 00139 case ID_MA: case ID_TE: case ID_IP: case ID_IM: 00140 case ID_SO: case ID_KE: case ID_WO: case ID_AC: 00141 case ID_NLA: case ID_TXT: case ID_GR: 00142 if(*idlevel==0) *idlevel= idcode; 00143 else if(*idlevel!=idcode) *idlevel= -1; 00144 break; 00145 } 00146 } 00147 } 00148 if(TSELEM_OPEN(tselem,soops)) { 00149 set_operation_types(soops, &te->subtree, 00150 scenelevel, objectlevel, idlevel, datalevel); 00151 } 00152 } 00153 } 00154 00155 static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem)) 00156 { 00157 /* just set action to NULL */ 00158 BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); 00159 } 00160 00161 static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem)) 00162 { 00163 Material **matar=NULL; 00164 int a, totcol=0; 00165 00166 if( GS(tsep->id->name)==ID_OB) { 00167 Object *ob= (Object *)tsep->id; 00168 totcol= ob->totcol; 00169 matar= ob->mat; 00170 } 00171 else if( GS(tsep->id->name)==ID_ME) { 00172 Mesh *me= (Mesh *)tsep->id; 00173 totcol= me->totcol; 00174 matar= me->mat; 00175 } 00176 else if( GS(tsep->id->name)==ID_CU) { 00177 Curve *cu= (Curve *)tsep->id; 00178 totcol= cu->totcol; 00179 matar= cu->mat; 00180 } 00181 else if( GS(tsep->id->name)==ID_MB) { 00182 MetaBall *mb= (MetaBall *)tsep->id; 00183 totcol= mb->totcol; 00184 matar= mb->mat; 00185 } 00186 00187 for(a=0; a<totcol; a++) { 00188 if(a==te->index && matar[a]) { 00189 matar[a]->id.us--; 00190 matar[a]= NULL; 00191 } 00192 } 00193 } 00194 00195 static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem)) 00196 { 00197 MTex **mtex= NULL; 00198 int a; 00199 00200 if( GS(tsep->id->name)==ID_MA) { 00201 Material *ma= (Material *)tsep->id; 00202 mtex= ma->mtex; 00203 } 00204 else if( GS(tsep->id->name)==ID_LA) { 00205 Lamp *la= (Lamp *)tsep->id; 00206 mtex= la->mtex; 00207 } 00208 else if( GS(tsep->id->name)==ID_WO) { 00209 World *wrld= (World *)tsep->id; 00210 mtex= wrld->mtex; 00211 } 00212 else return; 00213 00214 for(a=0; a<MAX_MTEX; a++) { 00215 if(a==te->index && mtex[a]) { 00216 if(mtex[a]->tex) { 00217 mtex[a]->tex->id.us--; 00218 mtex[a]->tex= NULL; 00219 } 00220 } 00221 } 00222 } 00223 00224 static void unlink_group_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem) 00225 { 00226 Group *group= (Group *)tselem->id; 00227 00228 if(tsep) { 00229 if( GS(tsep->id->name)==ID_OB) { 00230 Object *ob= (Object *)tsep->id; 00231 ob->dup_group= NULL; 00232 } 00233 } 00234 else { 00235 unlink_group(group); 00236 } 00237 } 00238 00239 static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem) 00240 { 00241 Scene *parscene = (Scene *)tsep->id; 00242 World *wo = (World *)tselem->id; 00243 00244 /* need to use parent scene not just scene, otherwise may end up getting wrong one */ 00245 id_us_min(&wo->id); 00246 parscene->world = NULL; 00247 } 00248 00249 static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, 00250 void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *)) 00251 { 00252 TreeElement *te; 00253 TreeStoreElem *tselem; 00254 00255 for(te=lb->first; te; te= te->next) { 00256 tselem= TREESTORE(te); 00257 if(tselem->flag & TSE_SELECTED) { 00258 if(tselem->type==0) { 00259 TreeStoreElem *tsep= TREESTORE(te->parent); 00260 operation_cb(C, scene, te, tsep, tselem); 00261 } 00262 } 00263 if(TSELEM_OPEN(tselem,soops)) { 00264 outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb); 00265 } 00266 } 00267 } 00268 00269 /* */ 00270 00271 static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00272 { 00273 Base *base= (Base *)te->directdata; 00274 00275 if(base==NULL) base= object_in_scene((Object *)tselem->id, scene); 00276 if(base && ((base->object->restrictflag & OB_RESTRICT_VIEW)==0)) { 00277 base->flag |= SELECT; 00278 base->object->flag |= SELECT; 00279 } 00280 } 00281 00282 static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00283 { 00284 Base *base= (Base *)te->directdata; 00285 00286 if(base==NULL) base= object_in_scene((Object *)tselem->id, scene); 00287 if(base) { 00288 base->flag &= ~SELECT; 00289 base->object->flag &= ~SELECT; 00290 } 00291 } 00292 00293 static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00294 { 00295 Base *base= (Base *)te->directdata; 00296 00297 if(base==NULL) 00298 base= object_in_scene((Object *)tselem->id, scene); 00299 if(base) { 00300 // check also library later 00301 if(scene->obedit==base->object) 00302 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO); 00303 00304 ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); 00305 te->directdata= NULL; 00306 tselem->id= NULL; 00307 } 00308 } 00309 00310 static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00311 { 00312 if (tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) { 00313 /* if the ID type has no special local function, 00314 * just clear the lib */ 00315 if (id_make_local(tselem->id, FALSE) == FALSE) { 00316 Main *bmain= CTX_data_main(C); 00317 id_clear_lib_data(bmain, tselem->id); 00318 } 00319 } 00320 } 00321 00322 static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00323 { 00324 ID *id = tselem->id; 00325 00326 if ((id) && ((id->flag & LIB_FAKEUSER) == 0)) { 00327 id->flag |= LIB_FAKEUSER; 00328 id_us_plus(id); 00329 } 00330 } 00331 00332 static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00333 { 00334 ID *id = tselem->id; 00335 00336 if ((id) && (id->flag & LIB_FAKEUSER)) { 00337 id->flag &= ~LIB_FAKEUSER; 00338 id_us_min(id); 00339 } 00340 } 00341 00342 static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem) 00343 { 00344 ID *id = tselem->id; 00345 00346 if (id) { 00347 IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id; 00348 PointerRNA ptr = {{NULL}}; 00349 PropertyRNA *prop; 00350 00351 RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr); 00352 prop = RNA_struct_find_property(&ptr, "action"); 00353 00354 id_single_user(C, id, &ptr, prop); 00355 } 00356 } 00357 00358 static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem) 00359 { 00360 ID *id = tselem->id; 00361 00362 /* need to use parent scene not just scene, otherwise may end up getting wrong one */ 00363 if (id) { 00364 Scene *parscene = (Scene *)tsep->id; 00365 PointerRNA ptr = {{NULL}}; 00366 PropertyRNA *prop; 00367 00368 RNA_id_pointer_create(&parscene->id, &ptr); 00369 prop = RNA_struct_find_property(&ptr, "world"); 00370 00371 id_single_user(C, id, &ptr, prop); 00372 } 00373 } 00374 00375 static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) 00376 { 00377 Group *group= (Group *)tselem->id; 00378 GroupObject *gob; 00379 Base *base; 00380 00381 for(gob=group->gobject.first; gob; gob=gob->next) { 00382 base= object_in_scene(gob->ob, scene); 00383 if (base) { 00384 base->object->flag |= SELECT; 00385 base->flag |= SELECT; 00386 } else { 00387 /* link to scene */ 00388 base= MEM_callocN( sizeof(Base), "add_base"); 00389 BLI_addhead(&scene->base, base); 00390 base->lay= (1<<20)-1; /*v3d->lay;*/ /* would be nice to use the 3d layer but the include's not here */ 00391 gob->ob->flag |= SELECT; 00392 base->flag = gob->ob->flag; 00393 base->object= gob->ob; 00394 id_lib_extern((ID *)gob->ob); /* incase these are from a linked group */ 00395 } 00396 } 00397 } 00398 00399 void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, 00400 void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *)) 00401 { 00402 TreeElement *te; 00403 TreeStoreElem *tselem; 00404 00405 for(te=lb->first; te; te= te->next) { 00406 tselem= TREESTORE(te); 00407 if(tselem->flag & TSE_SELECTED) { 00408 if(tselem->type==0 && te->idcode==ID_OB) { 00409 // when objects selected in other scenes... dunno if that should be allowed 00410 Scene *scene_owner= (Scene *)outliner_search_back(soops, te, ID_SCE); 00411 if(scene_owner && scene_act != scene_owner) { 00412 ED_screen_set_scene(C, scene_owner); 00413 } 00414 /* important to use 'scene_owner' not scene_act else deleting objects can crash. 00415 * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the 00416 * outliner isnt showing scenes: Visible Layer draw mode for eg. */ 00417 operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem); 00418 } 00419 } 00420 if(TSELEM_OPEN(tselem,soops)) { 00421 outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb); 00422 } 00423 } 00424 } 00425 00426 /* ******************************************** */ 00427 00428 static void unlinkact_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem) 00429 { 00430 /* just set action to NULL */ 00431 BKE_animdata_set_action(NULL, tselem->id, NULL); 00432 } 00433 00434 static void cleardrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem) 00435 { 00436 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; 00437 00438 /* just free drivers - stored as a list of F-Curves */ 00439 free_fcurves(&iat->adt->drivers); 00440 } 00441 00442 static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem) 00443 { 00444 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; 00445 FCurve *fcu; 00446 00447 /* loop over drivers, performing refresh (i.e. check graph_buttons.c and rna_fcurve.c for details) */ 00448 for (fcu = iat->adt->drivers.first; fcu; fcu= fcu->next) { 00449 fcu->flag &= ~FCURVE_DISABLED; 00450 00451 if (fcu->driver) 00452 fcu->driver->flag &= ~DRIVER_FLAG_INVALID; 00453 } 00454 } 00455 00456 /* --------------------------------- */ 00457 00458 static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem)) 00459 { 00460 bPoseChannel *pchan= (bPoseChannel *)te->directdata; 00461 00462 if(event==1) 00463 pchan->bone->flag |= BONE_SELECTED; 00464 else if(event==2) 00465 pchan->bone->flag &= ~BONE_SELECTED; 00466 else if(event==3) { 00467 pchan->bone->flag |= BONE_HIDDEN_P; 00468 pchan->bone->flag &= ~BONE_SELECTED; 00469 } 00470 else if(event==4) 00471 pchan->bone->flag &= ~BONE_HIDDEN_P; 00472 } 00473 00474 static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem)) 00475 { 00476 Bone *bone= (Bone *)te->directdata; 00477 00478 if(event==1) 00479 bone->flag |= BONE_SELECTED; 00480 else if(event==2) 00481 bone->flag &= ~BONE_SELECTED; 00482 else if(event==3) { 00483 bone->flag |= BONE_HIDDEN_P; 00484 bone->flag &= ~BONE_SELECTED; 00485 } 00486 else if(event==4) 00487 bone->flag &= ~BONE_HIDDEN_P; 00488 } 00489 00490 static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem)) 00491 { 00492 EditBone *ebone= (EditBone *)te->directdata; 00493 00494 if(event==1) 00495 ebone->flag |= BONE_SELECTED; 00496 else if(event==2) 00497 ebone->flag &= ~BONE_SELECTED; 00498 else if(event==3) { 00499 ebone->flag |= BONE_HIDDEN_A; 00500 ebone->flag &= ~BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; 00501 } 00502 else if(event==4) 00503 ebone->flag &= ~BONE_HIDDEN_A; 00504 } 00505 00506 static void sequence_cb(int event, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tselem)) 00507 { 00508 // Sequence *seq= (Sequence*) te->directdata; 00509 if(event==1) { 00510 // XXX select_single_seq(seq, 1); 00511 } 00512 } 00513 00514 static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, 00515 void (*operation_cb)(int, TreeElement *, TreeStoreElem *)) 00516 { 00517 TreeElement *te; 00518 TreeStoreElem *tselem; 00519 00520 for(te=lb->first; te; te= te->next) { 00521 tselem= TREESTORE(te); 00522 if(tselem->flag & TSE_SELECTED) { 00523 if(tselem->type==type) { 00524 operation_cb(event, te, tselem); 00525 } 00526 } 00527 if(TSELEM_OPEN(tselem,soops)) { 00528 outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb); 00529 } 00530 } 00531 } 00532 00533 /* **************************************** */ 00534 00535 static EnumPropertyItem prop_object_op_types[] = { 00536 {1, "SELECT", 0, "Select", ""}, 00537 {2, "DESELECT", 0, "Deselect", ""}, 00538 {4, "DELETE", 0, "Delete", ""}, 00539 {6, "TOGVIS", 0, "Toggle Visible", ""}, 00540 {7, "TOGSEL", 0, "Toggle Selectable", ""}, 00541 {8, "TOGREN", 0, "Toggle Renderable", ""}, 00542 {9, "RENAME", 0, "Rename", ""}, 00543 {0, NULL, 0, NULL, NULL} 00544 }; 00545 00546 static int outliner_object_operation_exec(bContext *C, wmOperator *op) 00547 { 00548 Main *bmain= CTX_data_main(C); 00549 Scene *scene= CTX_data_scene(C); 00550 SpaceOops *soops= CTX_wm_space_outliner(C); 00551 int event; 00552 const char *str= NULL; 00553 00554 /* check for invalid states */ 00555 if (soops == NULL) 00556 return OPERATOR_CANCELLED; 00557 00558 event= RNA_enum_get(op->ptr, "type"); 00559 00560 if(event==1) { 00561 Scene *sce= scene; // to be able to delete, scenes are set... 00562 outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb); 00563 if(scene != sce) { 00564 ED_screen_set_scene(C, sce); 00565 } 00566 00567 str= "Select Objects"; 00568 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); 00569 } 00570 else if(event==2) { 00571 outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb); 00572 str= "Deselect Objects"; 00573 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); 00574 } 00575 else if(event==4) { 00576 outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb); 00577 00578 /* XXX: tree management normally happens from draw_outliner(), but when 00579 you're clicking to fast on Delete object from context menu in 00580 outliner several mouse events can be handled in one cycle without 00581 handling notifiers/redraw which leads to deleting the same object twice. 00582 cleanup tree here to prevent such cases. */ 00583 outliner_cleanup_tree(soops); 00584 00585 DAG_scene_sort(bmain, scene); 00586 str= "Delete Objects"; 00587 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); 00588 } 00589 else if(event==5) { /* disabled, see above enum (ton) */ 00590 outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); 00591 str= "Localized Objects"; 00592 } 00593 else if(event==6) { 00594 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); 00595 str= "Toggle Visibility"; 00596 WM_event_add_notifier(C, NC_SCENE|ND_OB_VISIBLE, scene); 00597 } 00598 else if(event==7) { 00599 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); 00600 str= "Toggle Selectability"; 00601 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); 00602 } 00603 else if(event==8) { 00604 outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); 00605 str= "Toggle Renderability"; 00606 WM_event_add_notifier(C, NC_SCENE|ND_OB_RENDER, scene); 00607 } 00608 else if(event==9) { 00609 outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb); 00610 str= "Rename Object"; 00611 } 00612 00613 ED_undo_push(C, str); 00614 00615 return OPERATOR_FINISHED; 00616 } 00617 00618 00619 void OUTLINER_OT_object_operation(wmOperatorType *ot) 00620 { 00621 /* identifiers */ 00622 ot->name= "Outliner Object Operation"; 00623 ot->idname= "OUTLINER_OT_object_operation"; 00624 ot->description= ""; 00625 00626 /* callbacks */ 00627 ot->invoke= WM_menu_invoke; 00628 ot->exec= outliner_object_operation_exec; 00629 ot->poll= ED_operator_outliner_active; 00630 00631 ot->flag= 0; 00632 00633 ot->prop= RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); 00634 } 00635 00636 /* **************************************** */ 00637 00638 static EnumPropertyItem prop_group_op_types[] = { 00639 {1, "UNLINK", 0, "Unlink", ""}, 00640 {2, "LOCAL", 0, "Make Local", ""}, 00641 {3, "LINK", 0, "Link Group Objects to Scene", ""}, 00642 {4, "TOGVIS", 0, "Toggle Visible", ""}, 00643 {5, "TOGSEL", 0, "Toggle Selectable", ""}, 00644 {6, "TOGREN", 0, "Toggle Renderable", ""}, 00645 {7, "RENAME", 0, "Rename", ""}, 00646 {0, NULL, 0, NULL, NULL} 00647 }; 00648 00649 static int outliner_group_operation_exec(bContext *C, wmOperator *op) 00650 { 00651 Scene *scene= CTX_data_scene(C); 00652 SpaceOops *soops= CTX_wm_space_outliner(C); 00653 int event; 00654 const char *str= NULL; 00655 00656 /* check for invalid states */ 00657 if (soops == NULL) 00658 return OPERATOR_CANCELLED; 00659 00660 event= RNA_enum_get(op->ptr, "type"); 00661 00662 if(event==1) { 00663 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb); 00664 str= "Unlink group"; 00665 } 00666 else if(event==2) { 00667 outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb); 00668 str= "Localized Data"; 00669 } 00670 else if(event==3) { 00671 outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb); 00672 str= "Link Group Objects to Scene"; 00673 } 00674 else if(event==4) { 00675 outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb); 00676 str= "Toggle Visibility"; 00677 } 00678 else if(event==5) { 00679 outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb); 00680 str= "Toggle Selectability"; 00681 } 00682 else if(event==6) { 00683 outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb); 00684 str= "Toggle Renderability"; 00685 } 00686 else if(event==7) { 00687 outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); 00688 str= "Rename"; 00689 } 00690 00691 00692 ED_undo_push(C, str); 00693 WM_event_add_notifier(C, NC_GROUP, NULL); 00694 00695 return OPERATOR_FINISHED; 00696 } 00697 00698 00699 void OUTLINER_OT_group_operation(wmOperatorType *ot) 00700 { 00701 /* identifiers */ 00702 ot->name= "Outliner Group Operation"; 00703 ot->idname= "OUTLINER_OT_group_operation"; 00704 ot->description= ""; 00705 00706 /* callbacks */ 00707 ot->invoke= WM_menu_invoke; 00708 ot->exec= outliner_group_operation_exec; 00709 ot->poll= ED_operator_outliner_active; 00710 00711 ot->flag= 0; 00712 00713 ot->prop= RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", ""); 00714 } 00715 00716 /* **************************************** */ 00717 00718 typedef enum eOutlinerIdOpTypes { 00719 OUTLINER_IDOP_INVALID = 0, 00720 00721 OUTLINER_IDOP_UNLINK, 00722 OUTLINER_IDOP_LOCAL, 00723 OUTLINER_IDOP_SINGLE, 00724 00725 OUTLINER_IDOP_FAKE_ADD, 00726 OUTLINER_IDOP_FAKE_CLEAR, 00727 OUTLINER_IDOP_RENAME 00728 } eOutlinerIdOpTypes; 00729 00730 // TODO: implement support for changing the ID-block used 00731 static EnumPropertyItem prop_id_op_types[] = { 00732 {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, 00733 {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, 00734 {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, 00735 {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User", "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"}, 00736 {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, 00737 {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""}, 00738 {0, NULL, 0, NULL, NULL} 00739 }; 00740 00741 static int outliner_id_operation_exec(bContext *C, wmOperator *op) 00742 { 00743 Scene *scene= CTX_data_scene(C); 00744 SpaceOops *soops= CTX_wm_space_outliner(C); 00745 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; 00746 eOutlinerIdOpTypes event; 00747 00748 /* check for invalid states */ 00749 if (soops == NULL) 00750 return OPERATOR_CANCELLED; 00751 00752 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); 00753 00754 event= RNA_enum_get(op->ptr, "type"); 00755 00756 switch (event) { 00757 case OUTLINER_IDOP_UNLINK: 00758 { 00759 /* unlink datablock from its parent */ 00760 switch (idlevel) { 00761 case ID_AC: 00762 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb); 00763 00764 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL); 00765 ED_undo_push(C, "Unlink action"); 00766 break; 00767 case ID_MA: 00768 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb); 00769 00770 WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL); 00771 ED_undo_push(C, "Unlink material"); 00772 break; 00773 case ID_TE: 00774 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb); 00775 00776 WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL); 00777 ED_undo_push(C, "Unlink texture"); 00778 break; 00779 case ID_WO: 00780 outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb); 00781 00782 WM_event_add_notifier(C, NC_SCENE|ND_WORLD, NULL); 00783 ED_undo_push(C, "Unlink world"); 00784 break; 00785 default: 00786 BKE_report(op->reports, RPT_WARNING, "Not Yet"); 00787 break; 00788 } 00789 } 00790 break; 00791 00792 case OUTLINER_IDOP_LOCAL: 00793 { 00794 /* make local */ 00795 outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb); 00796 ED_undo_push(C, "Localized Data"); 00797 } 00798 break; 00799 00800 case OUTLINER_IDOP_SINGLE: 00801 { 00802 /* make single user */ 00803 switch (idlevel) { 00804 case ID_AC: 00805 outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb); 00806 00807 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL); 00808 ED_undo_push(C, "Single-User Action"); 00809 break; 00810 00811 case ID_WO: 00812 outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb); 00813 00814 WM_event_add_notifier(C, NC_SCENE|ND_WORLD, NULL); 00815 ED_undo_push(C, "Single-User World"); 00816 break; 00817 00818 default: 00819 BKE_report(op->reports, RPT_WARNING, "Not Yet"); 00820 break; 00821 } 00822 } 00823 break; 00824 00825 case OUTLINER_IDOP_FAKE_ADD: 00826 { 00827 /* set fake user */ 00828 outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb); 00829 00830 WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL); 00831 ED_undo_push(C, "Add Fake User"); 00832 } 00833 break; 00834 00835 case OUTLINER_IDOP_FAKE_CLEAR: 00836 { 00837 /* clear fake user */ 00838 outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb); 00839 00840 WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL); 00841 ED_undo_push(C, "Clear Fake User"); 00842 } 00843 break; 00844 case OUTLINER_IDOP_RENAME: 00845 { 00846 /* rename */ 00847 outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); 00848 00849 WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL); 00850 ED_undo_push(C, "Rename"); 00851 } 00852 break; 00853 00854 default: 00855 // invalid - unhandled 00856 break; 00857 } 00858 00859 /* wrong notifier still... */ 00860 WM_event_add_notifier(C, NC_ID|NA_EDITED, NULL); 00861 00862 // XXX: this is just so that outliner is always up to date 00863 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_OUTLINER, NULL); 00864 00865 return OPERATOR_FINISHED; 00866 } 00867 00868 00869 void OUTLINER_OT_id_operation(wmOperatorType *ot) 00870 { 00871 /* identifiers */ 00872 ot->name= "Outliner ID data Operation"; 00873 ot->idname= "OUTLINER_OT_id_operation"; 00874 ot->description= ""; 00875 00876 /* callbacks */ 00877 ot->invoke= WM_menu_invoke; 00878 ot->exec= outliner_id_operation_exec; 00879 ot->poll= ED_operator_outliner_active; 00880 00881 ot->flag= 0; 00882 00883 ot->prop= RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", ""); 00884 } 00885 00886 /* **************************************** */ 00887 00888 static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid, 00889 void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *)) 00890 { 00891 TreeElement *te; 00892 TreeStoreElem *tselem; 00893 00894 for (te=lb->first; te; te= te->next) { 00895 tselem= TREESTORE(te); 00896 if (tselem->flag & TSE_SELECTED) { 00897 if(tselem->type==type) { 00898 TreeStoreElem *tsep = TREESTORE(te->parent); 00899 operation_cb(te, tselem, tsep, newid); 00900 } 00901 } 00902 if (TSELEM_OPEN(tselem,soops)) { 00903 outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb); 00904 } 00905 } 00906 } 00907 00908 /* ------------------------------------------ */ 00909 00910 static void actionset_id_cb(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId) 00911 { 00912 bAction *act = (bAction *)actId; 00913 00914 if (tselem->type == TSE_ANIM_DATA) { 00915 /* "animation" entries - action is child of this */ 00916 BKE_animdata_set_action(NULL, tselem->id, act); 00917 } 00918 /* TODO: if any other "expander" channels which own actions need to support this menu, 00919 * add: tselem->type = ... 00920 */ 00921 else if (tsep && (tsep->type == TSE_ANIM_DATA)) { 00922 /* "animation" entries case again */ 00923 BKE_animdata_set_action(NULL, tsep->id, act); 00924 } 00925 // TODO: other cases not supported yet 00926 } 00927 00928 static int outliner_action_set_exec(bContext *C, wmOperator *op) 00929 { 00930 SpaceOops *soops= CTX_wm_space_outliner(C); 00931 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; 00932 00933 bAction *act; 00934 00935 /* check for invalid states */ 00936 if (soops == NULL) 00937 return OPERATOR_CANCELLED; 00938 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); 00939 00940 /* get action to use */ 00941 act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action")); 00942 00943 if (act == NULL) { 00944 BKE_report(op->reports, RPT_ERROR, "No valid Action to add"); 00945 return OPERATOR_CANCELLED; 00946 } 00947 else if (act->idroot == 0) { 00948 /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */ 00949 BKE_reportf(op->reports, RPT_WARNING, 00950 "Action '%s' does not specify what datablocks it can be used on. Try setting the 'ID Root Type' setting from the Datablocks Editor for this Action to avoid future problems", 00951 act->id.name+2); 00952 } 00953 00954 /* perform action if valid channel */ 00955 if (datalevel == TSE_ANIM_DATA) 00956 outliner_do_id_set_operation(soops, datalevel, &soops->tree, (ID*)act, actionset_id_cb); 00957 else if (idlevel == ID_AC) 00958 outliner_do_id_set_operation(soops, idlevel, &soops->tree, (ID*)act, actionset_id_cb); 00959 else 00960 return OPERATOR_CANCELLED; 00961 00962 /* set notifier that things have changed */ 00963 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL); 00964 ED_undo_push(C, "Set action"); 00965 00966 /* done */ 00967 return OPERATOR_FINISHED; 00968 } 00969 00970 void OUTLINER_OT_action_set(wmOperatorType *ot) 00971 { 00972 PropertyRNA *prop; 00973 00974 /* identifiers */ 00975 ot->name= "Outliner Set Action"; 00976 ot->idname= "OUTLINER_OT_action_set"; 00977 ot->description= "Change the active action used"; 00978 00979 /* api callbacks */ 00980 ot->invoke= WM_enum_search_invoke; 00981 ot->exec= outliner_action_set_exec; 00982 ot->poll= ED_operator_outliner_active; 00983 00984 /* flags */ 00985 ot->flag= 0; 00986 00987 /* props */ 00988 // TODO: this would be nicer as an ID-pointer... 00989 prop= RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", ""); 00990 RNA_def_enum_funcs(prop, RNA_action_itemf); 00991 ot->prop= prop; 00992 } 00993 00994 /* **************************************** */ 00995 00996 typedef enum eOutliner_AnimDataOps { 00997 OUTLINER_ANIMOP_INVALID = 0, 00998 00999 OUTLINER_ANIMOP_SET_ACT, 01000 OUTLINER_ANIMOP_CLEAR_ACT, 01001 01002 OUTLINER_ANIMOP_REFRESH_DRV, 01003 OUTLINER_ANIMOP_CLEAR_DRV 01004 01005 //OUTLINER_ANIMOP_COPY_DRIVERS, 01006 //OUTLINER_ANIMOP_PASTE_DRIVERS 01007 } eOutliner_AnimDataOps; 01008 01009 static EnumPropertyItem prop_animdata_op_types[] = { 01010 {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""}, 01011 {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""}, 01012 {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""}, 01013 //{OUTLINER_ANIMOP_COPY_DRIVERS, "COPY_DRIVERS", 0, "Copy Drivers", ""}, 01014 //{OUTLINER_ANIMOP_PASTE_DRIVERS, "PASTE_DRIVERS", 0, "Paste Drivers", ""}, 01015 {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""}, 01016 {0, NULL, 0, NULL, NULL} 01017 }; 01018 01019 static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) 01020 { 01021 SpaceOops *soops= CTX_wm_space_outliner(C); 01022 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; 01023 eOutliner_AnimDataOps event; 01024 short updateDeps = 0; 01025 01026 /* check for invalid states */ 01027 if (soops == NULL) 01028 return OPERATOR_CANCELLED; 01029 01030 event= RNA_enum_get(op->ptr, "type"); 01031 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); 01032 01033 if (datalevel != TSE_ANIM_DATA) 01034 return OPERATOR_CANCELLED; 01035 01036 /* perform the core operation */ 01037 switch (event) { 01038 case OUTLINER_ANIMOP_SET_ACT: 01039 /* delegate once again... */ 01040 WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); 01041 break; 01042 01043 case OUTLINER_ANIMOP_CLEAR_ACT: 01044 /* clear active action - using standard rules */ 01045 outliner_do_data_operation(soops, datalevel, event, &soops->tree, unlinkact_animdata_cb); 01046 01047 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL); 01048 ED_undo_push(C, "Unlink action"); 01049 break; 01050 01051 case OUTLINER_ANIMOP_REFRESH_DRV: 01052 outliner_do_data_operation(soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb); 01053 01054 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL); 01055 //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */ 01056 updateDeps = 1; 01057 break; 01058 01059 case OUTLINER_ANIMOP_CLEAR_DRV: 01060 outliner_do_data_operation(soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb); 01061 01062 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN, NULL); 01063 ED_undo_push(C, "Clear Drivers"); 01064 updateDeps = 1; 01065 break; 01066 01067 default: // invalid 01068 break; 01069 } 01070 01071 /* update dependencies */ 01072 if (updateDeps) { 01073 Main *bmain = CTX_data_main(C); 01074 Scene *scene = CTX_data_scene(C); 01075 01076 /* rebuild depsgraph for the new deps */ 01077 DAG_scene_sort(bmain, scene); 01078 01079 /* force an update of depsgraph */ 01080 DAG_ids_flush_update(bmain, 0); 01081 } 01082 01083 return OPERATOR_FINISHED; 01084 } 01085 01086 01087 void OUTLINER_OT_animdata_operation(wmOperatorType *ot) 01088 { 01089 /* identifiers */ 01090 ot->name= "Outliner Animation Data Operation"; 01091 ot->idname= "OUTLINER_OT_animdata_operation"; 01092 ot->description= ""; 01093 01094 /* callbacks */ 01095 ot->invoke= WM_menu_invoke; 01096 ot->exec= outliner_animdata_operation_exec; 01097 ot->poll= ED_operator_outliner_active; 01098 01099 ot->flag= 0; 01100 01101 ot->prop= RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", ""); 01102 } 01103 01104 /* **************************************** */ 01105 01106 static EnumPropertyItem prop_data_op_types[] = { 01107 {1, "SELECT", 0, "Select", ""}, 01108 {2, "DESELECT", 0, "Deselect", ""}, 01109 {3, "HIDE", 0, "Hide", ""}, 01110 {4, "UNHIDE", 0, "Unhide", ""}, 01111 {0, NULL, 0, NULL, NULL} 01112 }; 01113 01114 static int outliner_data_operation_exec(bContext *C, wmOperator *op) 01115 { 01116 SpaceOops *soops= CTX_wm_space_outliner(C); 01117 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; 01118 int event; 01119 01120 /* check for invalid states */ 01121 if (soops == NULL) 01122 return OPERATOR_CANCELLED; 01123 01124 event= RNA_enum_get(op->ptr, "type"); 01125 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); 01126 01127 if(datalevel==TSE_POSE_CHANNEL) { 01128 if(event>0) { 01129 outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb); 01130 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 01131 ED_undo_push(C, "PoseChannel operation"); 01132 } 01133 } 01134 else if(datalevel==TSE_BONE) { 01135 if(event>0) { 01136 outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb); 01137 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 01138 ED_undo_push(C, "Bone operation"); 01139 } 01140 } 01141 else if(datalevel==TSE_EBONE) { 01142 if(event>0) { 01143 outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb); 01144 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 01145 ED_undo_push(C, "EditBone operation"); 01146 } 01147 } 01148 else if(datalevel==TSE_SEQUENCE) { 01149 if(event>0) { 01150 outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb); 01151 } 01152 } 01153 01154 return OPERATOR_FINISHED; 01155 } 01156 01157 01158 void OUTLINER_OT_data_operation(wmOperatorType *ot) 01159 { 01160 /* identifiers */ 01161 ot->name= "Outliner Data Operation"; 01162 ot->idname= "OUTLINER_OT_data_operation"; 01163 ot->description= ""; 01164 01165 /* callbacks */ 01166 ot->invoke= WM_menu_invoke; 01167 ot->exec= outliner_data_operation_exec; 01168 ot->poll= ED_operator_outliner_active; 01169 01170 ot->flag= 0; 01171 01172 ot->prop= RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); 01173 } 01174 01175 01176 /* ******************** */ 01177 01178 01179 static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, wmEvent *event, const float mval[2]) 01180 { 01181 ReportList *reports = CTX_wm_reports(C); // XXX... 01182 01183 if(mval[1]>te->ys && mval[1]<te->ys+UI_UNIT_Y) { 01184 int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; 01185 TreeStoreElem *tselem= TREESTORE(te); 01186 01187 /* select object that's clicked on and popup context menu */ 01188 if (!(tselem->flag & TSE_SELECTED)) { 01189 01190 if ( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) ) 01191 outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0); 01192 01193 tselem->flag |= TSE_SELECTED; 01194 /* redraw, same as outliner_select function */ 01195 soops->storeflag |= SO_TREESTORE_REDRAW; 01196 ED_region_tag_redraw(ar); 01197 } 01198 01199 set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); 01200 01201 if(scenelevel) { 01202 //if(objectlevel || datalevel || idlevel) error("Mixed selection"); 01203 //else pupmenu("Scene Operations%t|Delete"); 01204 } 01205 else if(objectlevel) { 01206 WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); 01207 } 01208 else if(idlevel) { 01209 if(idlevel==-1 || datalevel) BKE_report(reports, RPT_WARNING, "Mixed selection"); 01210 else { 01211 if (idlevel==ID_GR) 01212 WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); 01213 else 01214 WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); 01215 } 01216 } 01217 else if(datalevel) { 01218 if(datalevel==-1) BKE_report(reports, RPT_WARNING, "Mixed selection"); 01219 else { 01220 if (datalevel == TSE_ANIM_DATA) 01221 WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL); 01222 else if (datalevel == TSE_DRIVER_BASE) 01223 /* do nothing... no special ops needed yet */; 01224 else if ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS) 01225 /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/; 01226 else 01227 WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); 01228 } 01229 } 01230 01231 return 1; 01232 } 01233 01234 for(te= te->subtree.first; te; te= te->next) { 01235 if(do_outliner_operation_event(C, scene, ar, soops, te, event, mval)) 01236 return 1; 01237 } 01238 return 0; 01239 } 01240 01241 01242 static int outliner_operation(bContext *C, wmOperator *UNUSED(op), wmEvent *event) 01243 { 01244 Scene *scene= CTX_data_scene(C); 01245 ARegion *ar= CTX_wm_region(C); 01246 SpaceOops *soops= CTX_wm_space_outliner(C); 01247 TreeElement *te; 01248 float fmval[2]; 01249 01250 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval+1); 01251 01252 for(te= soops->tree.first; te; te= te->next) { 01253 if(do_outliner_operation_event(C, scene, ar, soops, te, event, fmval)) break; 01254 } 01255 01256 return OPERATOR_FINISHED; 01257 } 01258 01259 /* Menu only! Calls other operators */ 01260 void OUTLINER_OT_operation(wmOperatorType *ot) 01261 { 01262 ot->name= "Execute Operation"; 01263 ot->idname= "OUTLINER_OT_operation"; 01264 ot->description= "Context menu for item operations"; 01265 01266 ot->invoke= outliner_operation; 01267 01268 ot->poll= ED_operator_outliner_active; 01269 } 01270 01271 /* ****************************************************** */