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