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) 2007 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * 00022 * Contributor(s): Blender Foundation 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 #include <float.h> 00033 #include <string.h> 00034 #include <ctype.h> 00035 #include <stdio.h> 00036 #include <stddef.h> 00037 #include <assert.h> 00038 00039 #include "GHOST_C-api.h" 00040 00041 #include "MEM_guardedalloc.h" 00042 00043 #include "DNA_ID.h" 00044 #include "DNA_object_types.h" 00045 #include "DNA_screen_types.h" 00046 #include "DNA_scene_types.h" 00047 #include "DNA_userdef_types.h" 00048 #include "DNA_windowmanager_types.h" 00049 #include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */ 00050 00051 #include "BLF_translation.h" 00052 00053 #include "PIL_time.h" 00054 00055 #include "BLI_blenlib.h" 00056 #include "BLI_dynstr.h" /*for WM_operator_pystring */ 00057 #include "BLI_math.h" 00058 #include "BLI_utildefines.h" 00059 #include "BLI_ghash.h" 00060 00061 #include "BLO_readfile.h" 00062 00063 #include "BKE_blender.h" 00064 #include "BKE_brush.h" 00065 #include "BKE_context.h" 00066 #include "BKE_depsgraph.h" 00067 #include "BKE_idprop.h" 00068 #include "BKE_library.h" 00069 #include "BKE_global.h" 00070 #include "BKE_main.h" 00071 #include "BKE_report.h" 00072 #include "BKE_scene.h" 00073 #include "BKE_screen.h" /* BKE_ST_MAXNAME */ 00074 00075 #include "BKE_idcode.h" 00076 00077 #include "BIF_gl.h" 00078 #include "BIF_glutil.h" /* for paint cursor */ 00079 #include "BLF_api.h" 00080 00081 #include "IMB_imbuf_types.h" 00082 #include "IMB_imbuf.h" 00083 00084 #include "ED_screen.h" 00085 #include "ED_util.h" 00086 00087 #include "RNA_access.h" 00088 #include "RNA_define.h" 00089 #include "RNA_enum_types.h" 00090 00091 #include "UI_interface.h" 00092 #include "UI_resources.h" 00093 00094 #include "WM_api.h" 00095 #include "WM_types.h" 00096 00097 #include "wm.h" 00098 #include "wm_draw.h" 00099 #include "wm_event_system.h" 00100 #include "wm_event_types.h" 00101 #include "wm_subwindow.h" 00102 #include "wm_window.h" 00103 00104 static GHash *global_ops_hash= NULL; 00105 00106 /* ************ operator API, exported ********** */ 00107 00108 00109 wmOperatorType *WM_operatortype_find(const char *idname, int quiet) 00110 { 00111 if(idname[0]) { 00112 wmOperatorType *ot; 00113 00114 /* needed to support python style names without the _OT_ syntax */ 00115 char idname_bl[OP_MAX_TYPENAME]; 00116 WM_operator_bl_idname(idname_bl, idname); 00117 00118 ot= BLI_ghash_lookup(global_ops_hash, idname_bl); 00119 if(ot) { 00120 return ot; 00121 } 00122 00123 if(!quiet) { 00124 printf("search for unknown operator '%s', '%s'\n", idname_bl, idname); 00125 } 00126 } 00127 else { 00128 if(!quiet) { 00129 printf("search for empty operator\n"); 00130 } 00131 } 00132 00133 return NULL; 00134 } 00135 00136 /* caller must free */ 00137 GHashIterator *WM_operatortype_iter(void) 00138 { 00139 return BLI_ghashIterator_new(global_ops_hash); 00140 } 00141 00142 /* all ops in 1 list (for time being... needs evaluation later) */ 00143 void WM_operatortype_append(void (*opfunc)(wmOperatorType*)) 00144 { 00145 wmOperatorType *ot; 00146 00147 ot= MEM_callocN(sizeof(wmOperatorType), "operatortype"); 00148 ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties"); 00149 opfunc(ot); 00150 00151 if(ot->name==NULL) { 00152 fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname); 00153 ot->name= IFACE_("Dummy Name"); 00154 } 00155 00156 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:IFACE_("(undocumented operator)")); // XXX All ops should have a description but for now allow them not to. 00157 RNA_def_struct_identifier(ot->srna, ot->idname); 00158 00159 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); 00160 } 00161 00162 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata) 00163 { 00164 wmOperatorType *ot; 00165 00166 ot= MEM_callocN(sizeof(wmOperatorType), "operatortype"); 00167 ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties"); 00168 opfunc(ot, userdata); 00169 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:IFACE_("(undocumented operator)")); 00170 RNA_def_struct_identifier(ot->srna, ot->idname); 00171 00172 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); 00173 } 00174 00175 /* ********************* macro operator ******************** */ 00176 00177 typedef struct { 00178 int retval; 00179 } MacroData; 00180 00181 static void wm_macro_start(wmOperator *op) 00182 { 00183 if (op->customdata == NULL) { 00184 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData"); 00185 } 00186 } 00187 00188 static int wm_macro_end(wmOperator *op, int retval) 00189 { 00190 if (retval & OPERATOR_CANCELLED) { 00191 MacroData *md = op->customdata; 00192 00193 if (md->retval & OPERATOR_FINISHED) { 00194 retval |= OPERATOR_FINISHED; 00195 retval &= ~OPERATOR_CANCELLED; 00196 } 00197 } 00198 00199 /* if modal is ending, free custom data */ 00200 if (retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) { 00201 if (op->customdata) { 00202 MEM_freeN(op->customdata); 00203 op->customdata = NULL; 00204 } 00205 } 00206 00207 return retval; 00208 } 00209 00210 /* macro exec only runs exec calls */ 00211 static int wm_macro_exec(bContext *C, wmOperator *op) 00212 { 00213 wmOperator *opm; 00214 int retval= OPERATOR_FINISHED; 00215 00216 wm_macro_start(op); 00217 00218 for(opm= op->macro.first; opm; opm= opm->next) { 00219 00220 if(opm->type->exec) { 00221 retval= opm->type->exec(C, opm); 00222 OPERATOR_RETVAL_CHECK(retval); 00223 00224 if (retval & OPERATOR_FINISHED) { 00225 MacroData *md = op->customdata; 00226 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ 00227 } else { 00228 break; /* operator didn't finish, end macro */ 00229 } 00230 } 00231 } 00232 00233 return wm_macro_end(op, retval); 00234 } 00235 00236 static int wm_macro_invoke_internal(bContext *C, wmOperator *op, wmEvent *event, wmOperator *opm) 00237 { 00238 int retval= OPERATOR_FINISHED; 00239 00240 /* start from operator received as argument */ 00241 for( ; opm; opm= opm->next) { 00242 if(opm->type->invoke) 00243 retval= opm->type->invoke(C, opm, event); 00244 else if(opm->type->exec) 00245 retval= opm->type->exec(C, opm); 00246 00247 OPERATOR_RETVAL_CHECK(retval); 00248 00249 BLI_movelisttolist(&op->reports->list, &opm->reports->list); 00250 00251 if (retval & OPERATOR_FINISHED) { 00252 MacroData *md = op->customdata; 00253 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ 00254 } else { 00255 break; /* operator didn't finish, end macro */ 00256 } 00257 } 00258 00259 return wm_macro_end(op, retval); 00260 } 00261 00262 static int wm_macro_invoke(bContext *C, wmOperator *op, wmEvent *event) 00263 { 00264 wm_macro_start(op); 00265 return wm_macro_invoke_internal(C, op, event, op->macro.first); 00266 } 00267 00268 static int wm_macro_modal(bContext *C, wmOperator *op, wmEvent *event) 00269 { 00270 wmOperator *opm = op->opm; 00271 int retval= OPERATOR_FINISHED; 00272 00273 if(opm==NULL) 00274 printf("%s: macro error, calling NULL modal()\n", __func__); 00275 else { 00276 retval = opm->type->modal(C, opm, event); 00277 OPERATOR_RETVAL_CHECK(retval); 00278 00279 /* if this one is done but it's not the last operator in the macro */ 00280 if ((retval & OPERATOR_FINISHED) && opm->next) { 00281 MacroData *md = op->customdata; 00282 00283 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ 00284 00285 retval = wm_macro_invoke_internal(C, op, event, opm->next); 00286 00287 /* if new operator is modal and also added its own handler */ 00288 if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) { 00289 wmWindow *win = CTX_wm_window(C); 00290 wmEventHandler *handler = NULL; 00291 00292 for (handler = win->modalhandlers.first; handler; handler = handler->next) { 00293 /* first handler in list is the new one */ 00294 if (handler->op == op) 00295 break; 00296 } 00297 00298 if (handler) { 00299 BLI_remlink(&win->modalhandlers, handler); 00300 wm_event_free_handler(handler); 00301 } 00302 00303 /* if operator is blocking, grab cursor 00304 * This may end up grabbing twice, but we don't care. 00305 * */ 00306 if(op->opm->type->flag & OPTYPE_BLOCKING) { 00307 int bounds[4] = {-1,-1,-1,-1}; 00308 int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER)); 00309 00310 if(wrap) { 00311 ARegion *ar= CTX_wm_region(C); 00312 if(ar) { 00313 bounds[0]= ar->winrct.xmin; 00314 bounds[1]= ar->winrct.ymax; 00315 bounds[2]= ar->winrct.xmax; 00316 bounds[3]= ar->winrct.ymin; 00317 } 00318 } 00319 00320 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds); 00321 } 00322 } 00323 } 00324 } 00325 00326 return wm_macro_end(op, retval); 00327 } 00328 00329 static int wm_macro_cancel(bContext *C, wmOperator *op) 00330 { 00331 /* call cancel on the current modal operator, if any */ 00332 if (op->opm && op->opm->type->cancel) { 00333 op->opm->type->cancel(C, op->opm); 00334 } 00335 00336 return wm_macro_end(op, OPERATOR_CANCELLED); 00337 } 00338 00339 /* Names have to be static for now */ 00340 wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, int flag) 00341 { 00342 wmOperatorType *ot; 00343 00344 if(WM_operatortype_find(idname, TRUE)) { 00345 printf("%s: macro error: operator %s exists\n", __func__, idname); 00346 return NULL; 00347 } 00348 00349 ot= MEM_callocN(sizeof(wmOperatorType), "operatortype"); 00350 ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties"); 00351 00352 ot->idname= idname; 00353 ot->name= name; 00354 ot->flag= OPTYPE_MACRO|flag; 00355 00356 ot->exec= wm_macro_exec; 00357 ot->invoke= wm_macro_invoke; 00358 ot->modal= wm_macro_modal; 00359 ot->cancel= wm_macro_cancel; 00360 ot->poll= NULL; 00361 00362 if(!ot->description) 00363 ot->description= IFACE_("(undocumented operator)"); 00364 00365 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); // XXX All ops should have a description but for now allow them not to. 00366 RNA_def_struct_identifier(ot->srna, ot->idname); 00367 00368 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); 00369 00370 return ot; 00371 } 00372 00373 void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata) 00374 { 00375 wmOperatorType *ot; 00376 00377 ot= MEM_callocN(sizeof(wmOperatorType), "operatortype"); 00378 ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties"); 00379 00380 ot->flag= OPTYPE_MACRO; 00381 ot->exec= wm_macro_exec; 00382 ot->invoke= wm_macro_invoke; 00383 ot->modal= wm_macro_modal; 00384 ot->cancel= wm_macro_cancel; 00385 ot->poll= NULL; 00386 00387 if(!ot->description) 00388 ot->description= IFACE_("(undocumented operator)"); 00389 00390 opfunc(ot, userdata); 00391 00392 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); 00393 RNA_def_struct_identifier(ot->srna, ot->idname); 00394 00395 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); 00396 } 00397 00398 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname) 00399 { 00400 wmOperatorTypeMacro *otmacro= MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro"); 00401 00402 BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME); 00403 00404 /* do this on first use, since operatordefinitions might have been not done yet */ 00405 WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname); 00406 WM_operator_properties_sanitize(otmacro->ptr, 1); 00407 00408 BLI_addtail(&ot->macro, otmacro); 00409 00410 { 00411 /* operator should always be found but in the event its not. dont segfault */ 00412 wmOperatorType *otsub = WM_operatortype_find(idname, 0); 00413 if(otsub) { 00414 RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna, 00415 otsub->name, otsub->description); 00416 } 00417 } 00418 00419 return otmacro; 00420 } 00421 00422 static void wm_operatortype_free_macro(wmOperatorType *ot) 00423 { 00424 wmOperatorTypeMacro *otmacro; 00425 00426 for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) { 00427 if(otmacro->ptr) { 00428 WM_operator_properties_free(otmacro->ptr); 00429 MEM_freeN(otmacro->ptr); 00430 } 00431 } 00432 BLI_freelistN(&ot->macro); 00433 } 00434 00435 00436 int WM_operatortype_remove(const char *idname) 00437 { 00438 wmOperatorType *ot = WM_operatortype_find(idname, 0); 00439 00440 if (ot==NULL) 00441 return 0; 00442 00443 RNA_struct_free(&BLENDER_RNA, ot->srna); 00444 00445 if(ot->macro.first) 00446 wm_operatortype_free_macro(ot); 00447 00448 BLI_ghash_remove(global_ops_hash, (void *)ot->idname, NULL, NULL); 00449 00450 MEM_freeN(ot); 00451 return 1; 00452 } 00453 00454 /* SOME_OT_op -> some.op */ 00455 void WM_operator_py_idname(char *to, const char *from) 00456 { 00457 char *sep= strstr(from, "_OT_"); 00458 if(sep) { 00459 int ofs= (sep-from); 00460 00461 /* note, we use ascii tolower instead of system tolower, because the 00462 latter depends on the locale, and can lead to idname mistmatch */ 00463 memcpy(to, from, sizeof(char)*ofs); 00464 BLI_ascii_strtolower(to, ofs); 00465 00466 to[ofs] = '.'; 00467 BLI_strncpy(to+(ofs+1), sep+4, OP_MAX_TYPENAME); 00468 } 00469 else { 00470 /* should not happen but support just incase */ 00471 BLI_strncpy(to, from, OP_MAX_TYPENAME); 00472 } 00473 } 00474 00475 /* some.op -> SOME_OT_op */ 00476 void WM_operator_bl_idname(char *to, const char *from) 00477 { 00478 if (from) { 00479 char *sep= strchr(from, '.'); 00480 00481 if(sep) { 00482 int ofs= (sep-from); 00483 00484 memcpy(to, from, sizeof(char)*ofs); 00485 BLI_ascii_strtoupper(to, ofs); 00486 00487 BLI_strncpy(to+ofs, "_OT_", OP_MAX_TYPENAME); 00488 BLI_strncpy(to+(ofs+4), sep+1, OP_MAX_TYPENAME); 00489 } 00490 else { 00491 /* should not happen but support just incase */ 00492 BLI_strncpy(to, from, OP_MAX_TYPENAME); 00493 } 00494 } 00495 else 00496 to[0]= 0; 00497 } 00498 00499 /* print a string representation of the operator, with the args that it runs 00500 * so python can run it again, 00501 * 00502 * When calling from an existing wmOperator do. 00503 * WM_operator_pystring(op->type, op->ptr); 00504 */ 00505 char *WM_operator_pystring(bContext *C, wmOperatorType *ot, PointerRNA *opptr, int all_args) 00506 { 00507 const char *arg_name= NULL; 00508 char idname_py[OP_MAX_TYPENAME]; 00509 00510 PropertyRNA *prop, *iterprop; 00511 00512 /* for building the string */ 00513 DynStr *dynstr= BLI_dynstr_new(); 00514 char *cstring, *buf; 00515 int first_iter=1, ok= 1; 00516 00517 00518 /* only to get the orginal props for comparisons */ 00519 PointerRNA opptr_default; 00520 PropertyRNA *prop_default; 00521 char *buf_default; 00522 if(all_args==0 || opptr==NULL) { 00523 WM_operator_properties_create_ptr(&opptr_default, ot); 00524 00525 if(opptr==NULL) 00526 opptr = &opptr_default; 00527 } 00528 00529 00530 WM_operator_py_idname(idname_py, ot->idname); 00531 BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py); 00532 00533 iterprop= RNA_struct_iterator_property(opptr->type); 00534 00535 RNA_PROP_BEGIN(opptr, propptr, iterprop) { 00536 prop= propptr.data; 00537 arg_name= RNA_property_identifier(prop); 00538 00539 if (strcmp(arg_name, "rna_type")==0) continue; 00540 00541 buf= RNA_property_as_string(C, opptr, prop); 00542 00543 ok= 1; 00544 00545 if(!all_args) { 00546 /* not verbose, so only add in attributes that use non-default values 00547 * slow but good for tooltips */ 00548 prop_default= RNA_struct_find_property(&opptr_default, arg_name); 00549 00550 if(prop_default) { 00551 buf_default= RNA_property_as_string(C, &opptr_default, prop_default); 00552 00553 if(strcmp(buf, buf_default)==0) 00554 ok= 0; /* values match, dont bother printing */ 00555 00556 MEM_freeN(buf_default); 00557 } 00558 00559 } 00560 if(ok) { 00561 BLI_dynstr_appendf(dynstr, first_iter?"%s=%s":", %s=%s", arg_name, buf); 00562 first_iter = 0; 00563 } 00564 00565 MEM_freeN(buf); 00566 00567 } 00568 RNA_PROP_END; 00569 00570 if(all_args==0 || opptr==&opptr_default ) 00571 WM_operator_properties_free(&opptr_default); 00572 00573 BLI_dynstr_append(dynstr, ")"); 00574 00575 cstring = BLI_dynstr_get_cstring(dynstr); 00576 BLI_dynstr_free(dynstr); 00577 return cstring; 00578 } 00579 00580 void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot) 00581 { 00582 RNA_pointer_create(NULL, ot->srna, NULL, ptr); 00583 } 00584 00585 void WM_operator_properties_create(PointerRNA *ptr, const char *opstring) 00586 { 00587 wmOperatorType *ot= WM_operatortype_find(opstring, 0); 00588 00589 if(ot) 00590 WM_operator_properties_create_ptr(ptr, ot); 00591 else 00592 RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr); 00593 } 00594 00595 /* similar to the function above except its uses ID properties 00596 * used for keymaps and macros */ 00597 void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring) 00598 { 00599 if(*properties==NULL) { 00600 IDPropertyTemplate val = {0}; 00601 *properties= IDP_New(IDP_GROUP, &val, "wmOpItemProp"); 00602 } 00603 00604 if(*ptr==NULL) { 00605 *ptr= MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr"); 00606 WM_operator_properties_create(*ptr, opstring); 00607 } 00608 00609 (*ptr)->data= *properties; 00610 00611 } 00612 00613 void WM_operator_properties_sanitize(PointerRNA *ptr, const short no_context) 00614 { 00615 RNA_STRUCT_BEGIN(ptr, prop) { 00616 switch(RNA_property_type(prop)) { 00617 case PROP_ENUM: 00618 if (no_context) 00619 RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); 00620 else 00621 RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT); 00622 break; 00623 case PROP_POINTER: 00624 { 00625 StructRNA *ptype= RNA_property_pointer_type(ptr, prop); 00626 00627 /* recurse into operator properties */ 00628 if (RNA_struct_is_a(ptype, &RNA_OperatorProperties)) { 00629 PointerRNA opptr = RNA_property_pointer_get(ptr, prop); 00630 WM_operator_properties_sanitize(&opptr, no_context); 00631 } 00632 break; 00633 } 00634 default: 00635 break; 00636 } 00637 } 00638 RNA_STRUCT_END; 00639 } 00640 00641 /* remove all props without PROP_SKIP_SAVE */ 00642 void WM_operator_properties_reset(wmOperator *op) 00643 { 00644 if (op->ptr->data) { 00645 PropertyRNA *iterprop; 00646 iterprop= RNA_struct_iterator_property(op->type->srna); 00647 00648 RNA_PROP_BEGIN(op->ptr, itemptr, iterprop) { 00649 PropertyRNA *prop= itemptr.data; 00650 00651 if((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) { 00652 const char *identifier = RNA_property_identifier(prop); 00653 RNA_struct_idprops_unset(op->ptr, identifier); 00654 } 00655 } 00656 RNA_PROP_END; 00657 } 00658 } 00659 00660 void WM_operator_properties_free(PointerRNA *ptr) 00661 { 00662 IDProperty *properties= ptr->data; 00663 00664 if(properties) { 00665 IDP_FreeProperty(properties); 00666 MEM_freeN(properties); 00667 ptr->data= NULL; /* just incase */ 00668 } 00669 } 00670 00671 /* ************ default op callbacks, exported *********** */ 00672 00673 /* invoke callback, uses enum property named "type" */ 00674 int WM_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00675 { 00676 PropertyRNA *prop= op->type->prop; 00677 uiPopupMenu *pup; 00678 uiLayout *layout; 00679 00680 if(prop==NULL) { 00681 printf("%s: %s has no enum property set\n", __func__, op->type->idname); 00682 } 00683 else if (RNA_property_type(prop) != PROP_ENUM) { 00684 printf("%s: %s \"%s\" is not an enum property\n", 00685 __func__, op->type->idname, RNA_property_identifier(prop)); 00686 } 00687 else if (RNA_property_is_set(op->ptr, prop)) { 00688 const int retval= op->type->exec(C, op); 00689 OPERATOR_RETVAL_CHECK(retval); 00690 return retval; 00691 } 00692 else { 00693 pup= uiPupMenuBegin(C, op->type->name, ICON_NONE); 00694 layout= uiPupMenuLayout(pup); 00695 uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0); 00696 uiPupMenuEnd(C, pup); 00697 } 00698 00699 return OPERATOR_CANCELLED; 00700 } 00701 00702 00703 /* generic enum search invoke popup */ 00704 static void operator_enum_search_cb(const struct bContext *C, void *arg_ot, const char *str, uiSearchItems *items) 00705 { 00706 wmOperatorType *ot = (wmOperatorType *)arg_ot; 00707 PropertyRNA *prop= ot->prop; 00708 00709 if(prop==NULL) { 00710 printf("%s: %s has no enum property set\n", 00711 __func__, ot->idname); 00712 } 00713 else if (RNA_property_type(prop) != PROP_ENUM) { 00714 printf("%s: %s \"%s\" is not an enum property\n", 00715 __func__, ot->idname, RNA_property_identifier(prop)); 00716 } 00717 else { 00718 PointerRNA ptr; 00719 00720 EnumPropertyItem *item, *item_array; 00721 int do_free; 00722 00723 RNA_pointer_create(NULL, ot->srna, NULL, &ptr); 00724 RNA_property_enum_items((bContext *)C, &ptr, prop, &item_array, NULL, &do_free); 00725 00726 for(item= item_array; item->identifier; item++) { 00727 /* note: need to give the intex rather than the dientifier because the enum can be freed */ 00728 if(BLI_strcasestr(item->name, str)) 00729 if(0==uiSearchItemAdd(items, item->name, SET_INT_IN_POINTER(item->value), 0)) 00730 break; 00731 } 00732 00733 if(do_free) 00734 MEM_freeN(item_array); 00735 } 00736 } 00737 00738 static void operator_enum_call_cb(struct bContext *C, void *arg1, void *arg2) 00739 { 00740 wmOperatorType *ot= arg1; 00741 00742 if(ot) { 00743 if(ot->prop) { 00744 PointerRNA props_ptr; 00745 WM_operator_properties_create_ptr(&props_ptr, ot); 00746 RNA_property_enum_set(&props_ptr, ot->prop, GET_INT_FROM_POINTER(arg2)); 00747 WM_operator_name_call(C, ot->idname, WM_OP_EXEC_DEFAULT, &props_ptr); 00748 WM_operator_properties_free(&props_ptr); 00749 } 00750 else { 00751 printf("%s: op->prop for '%s' is NULL\n", __func__, ot->idname); 00752 } 00753 } 00754 } 00755 00756 static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op) 00757 { 00758 static char search[256]= ""; 00759 wmEvent event; 00760 wmWindow *win= CTX_wm_window(C); 00761 uiBlock *block; 00762 uiBut *but; 00763 wmOperator *op= (wmOperator *)arg_op; 00764 00765 block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); 00766 uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT); 00767 00768 //uiDefBut(block, LABEL, 0, op->type->name, 10, 10, 180, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); // ok, this isnt so easy... 00769 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9*UI_UNIT_X, UI_UNIT_Y, 0, 0, ""); 00770 uiButSetSearchFunc(but, operator_enum_search_cb, op->type, operator_enum_call_cb, NULL); 00771 00772 /* fake button, it holds space for search items */ 00773 uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxhHeight(), 9*UI_UNIT_X, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL); 00774 00775 uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ 00776 uiEndBlock(C, block); 00777 00778 event= *(win->eventstate); /* XXX huh huh? make api call */ 00779 event.type= EVT_BUT_OPEN; 00780 event.val= KM_PRESS; 00781 event.customdata= but; 00782 event.customdatafree= FALSE; 00783 wm_event_add(win, &event); 00784 00785 return block; 00786 } 00787 00788 00789 int WM_enum_search_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00790 { 00791 uiPupBlock(C, wm_enum_search_menu, op); 00792 return OPERATOR_CANCELLED; 00793 } 00794 00795 /* Can't be used as an invoke directly, needs message arg (can be NULL) */ 00796 int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message) 00797 { 00798 uiPopupMenu *pup; 00799 uiLayout *layout; 00800 IDProperty *properties= op->ptr->data; 00801 00802 if(properties && properties->len) 00803 properties= IDP_CopyProperty(op->ptr->data); 00804 else 00805 properties= NULL; 00806 00807 pup= uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION); 00808 layout= uiPupMenuLayout(pup); 00809 uiItemFullO(layout, op->type->idname, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0); 00810 uiPupMenuEnd(C, pup); 00811 00812 return OPERATOR_CANCELLED; 00813 } 00814 00815 00816 int WM_operator_confirm(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00817 { 00818 return WM_operator_confirm_message(C, op, NULL); 00819 } 00820 00821 /* op->invoke, opens fileselect if path property not set, otherwise executes */ 00822 int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00823 { 00824 if (RNA_struct_property_is_set(op->ptr, "filepath")) { 00825 return WM_operator_call_notest(C, op); /* call exec direct */ 00826 } 00827 else { 00828 WM_event_add_fileselect(C, op); 00829 return OPERATOR_RUNNING_MODAL; 00830 } 00831 } 00832 00833 /* default properties for fileselect */ 00834 void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag) 00835 { 00836 PropertyRNA *prop; 00837 00838 00839 if(flag & WM_FILESEL_FILEPATH) 00840 RNA_def_string_file_path(ot->srna, "filepath", "", FILE_MAX, "File Path", "Path to file"); 00841 00842 if(flag & WM_FILESEL_DIRECTORY) 00843 RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Directory of the file"); 00844 00845 if(flag & WM_FILESEL_FILENAME) 00846 RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "File Name", "Name of the file"); 00847 00848 if(flag & WM_FILESEL_FILES) 00849 RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); 00850 00851 if (action == FILE_SAVE) { 00852 prop= RNA_def_boolean(ot->srna, "check_existing", 1, "Check Existing", "Check and warn on overwriting existing files"); 00853 RNA_def_property_flag(prop, PROP_HIDDEN); 00854 } 00855 00856 prop= RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", ""); 00857 RNA_def_property_flag(prop, PROP_HIDDEN); 00858 prop= RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", ""); 00859 RNA_def_property_flag(prop, PROP_HIDDEN); 00860 prop= RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", ""); 00861 RNA_def_property_flag(prop, PROP_HIDDEN); 00862 prop= RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", ""); 00863 RNA_def_property_flag(prop, PROP_HIDDEN); 00864 prop= RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", ""); 00865 RNA_def_property_flag(prop, PROP_HIDDEN); 00866 prop= RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", ""); 00867 RNA_def_property_flag(prop, PROP_HIDDEN); 00868 prop= RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", ""); 00869 RNA_def_property_flag(prop, PROP_HIDDEN); 00870 prop= RNA_def_boolean(ot->srna, "filter_btx", (filter & BTXFILE), "Filter btx files", ""); 00871 RNA_def_property_flag(prop, PROP_HIDDEN); 00872 prop= RNA_def_boolean(ot->srna, "filter_collada", (filter & COLLADAFILE), "Filter COLLADA files", ""); 00873 RNA_def_property_flag(prop, PROP_HIDDEN); 00874 prop= RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", ""); 00875 RNA_def_property_flag(prop, PROP_HIDDEN); 00876 00877 prop= RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, 00878 "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file", 00879 FILE_LOADLIB, FILE_SPECIAL); 00880 RNA_def_property_flag(prop, PROP_HIDDEN); 00881 00882 if(flag & WM_FILESEL_RELPATH) 00883 RNA_def_boolean(ot->srna, "relative_path", TRUE, "Relative Path", "Select the file relative to the blend file"); 00884 } 00885 00886 void WM_operator_properties_select_all(wmOperatorType *ot) 00887 { 00888 static EnumPropertyItem select_all_actions[] = { 00889 {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"}, 00890 {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"}, 00891 {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"}, 00892 {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"}, 00893 {0, NULL, 0, NULL, NULL} 00894 }; 00895 00896 RNA_def_enum(ot->srna, "action", select_all_actions, SEL_TOGGLE, "Action", "Selection action to execute"); 00897 } 00898 00899 void WM_operator_properties_gesture_border(wmOperatorType *ot, int extend) 00900 { 00901 RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); 00902 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); 00903 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); 00904 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); 00905 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); 00906 00907 if(extend) 00908 RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first"); 00909 } 00910 00911 void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) 00912 { 00913 RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX); 00914 RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX); 00915 RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX); 00916 RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX); 00917 00918 if(cursor) 00919 RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX, "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX); 00920 } 00921 00922 00923 /* op->poll */ 00924 int WM_operator_winactive(bContext *C) 00925 { 00926 if(CTX_wm_window(C)==NULL) return 0; 00927 return 1; 00928 } 00929 00930 /* return FALSE, if the UI should be disabled */ 00931 int WM_operator_check_ui_enabled(const bContext *C, const char *idname) 00932 { 00933 wmWindowManager *wm= CTX_wm_manager(C); 00934 Scene *scene= CTX_data_scene(C); 00935 00936 return !(ED_undo_valid(C, idname)==0 || WM_jobs_test(wm, scene)); 00937 } 00938 00939 wmOperator *WM_operator_last_redo(const bContext *C) 00940 { 00941 wmWindowManager *wm= CTX_wm_manager(C); 00942 wmOperator *op; 00943 00944 /* only for operators that are registered and did an undo push */ 00945 for(op= wm->operators.last; op; op= op->prev) 00946 if((op->type->flag & OPTYPE_REGISTER) && (op->type->flag & OPTYPE_UNDO)) 00947 break; 00948 00949 return op; 00950 } 00951 00952 static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) 00953 { 00954 wmOperator *op= arg_op; 00955 uiBlock *block; 00956 uiLayout *layout; 00957 uiStyle *style= UI_GetStyle(); 00958 int width= 300; 00959 00960 00961 block= uiBeginBlock(C, ar, __func__, UI_EMBOSS); 00962 uiBlockClearFlag(block, UI_BLOCK_LOOP); 00963 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT); 00964 00965 /* if register is not enabled, the operator gets freed on OPERATOR_FINISHED 00966 * ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */ 00967 assert(op->type->flag & OPTYPE_REGISTER); 00968 00969 uiBlockSetHandleFunc(block, ED_undo_operator_repeat_cb_evt, arg_op); 00970 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, style); 00971 00972 if (!WM_operator_check_ui_enabled(C, op->type->name)) 00973 uiLayoutSetEnabled(layout, 0); 00974 00975 if(op->type->flag & OPTYPE_MACRO) { 00976 for(op= op->macro.first; op; op= op->next) { 00977 uiItemL(layout, op->type->name, ICON_NONE); 00978 uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); 00979 } 00980 } 00981 else { 00982 uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); 00983 } 00984 00985 00986 uiPopupBoundsBlock(block, 4, 0, 0); 00987 uiEndBlock(C, block); 00988 00989 return block; 00990 } 00991 00992 typedef struct wmOpPopUp 00993 { 00994 wmOperator *op; 00995 int width; 00996 int height; 00997 int free_op; 00998 } wmOpPopUp; 00999 01000 /* Only invoked by OK button in popups created with wm_block_dialog_create() */ 01001 static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) 01002 { 01003 wmOpPopUp *data= arg1; 01004 uiBlock *block= arg2; 01005 01006 WM_operator_call(C, data->op); 01007 01008 /* let execute handle freeing it */ 01009 //data->free_op= FALSE; 01010 //data->op= NULL; 01011 01012 /* in this case, wm_operator_ui_popup_cancel wont run */ 01013 MEM_freeN(data); 01014 01015 uiPupBlockClose(C, block); 01016 } 01017 01018 static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) 01019 { 01020 wmOperator *op= op_ptr; 01021 if(op->type->check) { 01022 if(op->type->check(C, op)) { 01023 /* refresh */ 01024 } 01025 } 01026 } 01027 01028 /* Dialogs are popups that require user verification (click OK) before exec */ 01029 static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) 01030 { 01031 wmOpPopUp *data= userData; 01032 wmOperator *op= data->op; 01033 uiBlock *block; 01034 uiLayout *layout; 01035 uiStyle *style= UI_GetStyle(); 01036 01037 block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); 01038 uiBlockClearFlag(block, UI_BLOCK_LOOP); 01039 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT); 01040 01041 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, style); 01042 01043 uiBlockSetFunc(block, dialog_check_cb, op, NULL); 01044 01045 uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); 01046 01047 /* clear so the OK button is left alone */ 01048 uiBlockSetFunc(block, NULL, NULL, NULL); 01049 01050 /* new column so as not to interfear with custom layouts [#26436] */ 01051 { 01052 uiBlock *col_block; 01053 uiLayout *col; 01054 uiBut *btn; 01055 01056 col= uiLayoutColumn(layout, FALSE); 01057 col_block= uiLayoutGetBlock(col); 01058 /* Create OK button, the callback of which will execute op */ 01059 btn= uiDefBut(col_block, BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 01060 uiButSetFunc(btn, dialog_exec_cb, data, col_block); 01061 } 01062 01063 /* center around the mouse */ 01064 uiPopupBoundsBlock(block, 4, data->width/-2, data->height/2); 01065 uiEndBlock(C, block); 01066 01067 return block; 01068 } 01069 01070 static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) 01071 { 01072 wmOpPopUp *data= userData; 01073 wmOperator *op= data->op; 01074 uiBlock *block; 01075 uiLayout *layout; 01076 uiStyle *style= UI_GetStyle(); 01077 01078 block= uiBeginBlock(C, ar, __func__, UI_EMBOSS); 01079 uiBlockClearFlag(block, UI_BLOCK_LOOP); 01080 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT); 01081 01082 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, style); 01083 01084 /* since ui is defined the auto-layout args are not used */ 01085 uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0); 01086 01087 uiPopupBoundsBlock(block, 4, 0, 0); 01088 uiEndBlock(C, block); 01089 01090 return block; 01091 } 01092 01093 static void wm_operator_ui_popup_cancel(void *userData) 01094 { 01095 wmOpPopUp *data= userData; 01096 if(data->free_op && data->op) { 01097 wmOperator *op= data->op; 01098 WM_operator_free(op); 01099 } 01100 01101 MEM_freeN(data); 01102 } 01103 01104 static void wm_operator_ui_popup_ok(struct bContext *C, void *arg, int retval) 01105 { 01106 wmOpPopUp *data= arg; 01107 wmOperator *op= data->op; 01108 01109 if(op && retval > 0) 01110 WM_operator_call(C, op); 01111 } 01112 01113 int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height) 01114 { 01115 wmOpPopUp *data= MEM_callocN(sizeof(wmOpPopUp), "WM_operator_ui_popup"); 01116 data->op= op; 01117 data->width= width; 01118 data->height= height; 01119 data->free_op= TRUE; /* if this runs and gets registered we may want not to free it */ 01120 uiPupBlockEx(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data); 01121 return OPERATOR_RUNNING_MODAL; 01122 } 01123 01124 /* operator menu needs undo, for redo callback */ 01125 int WM_operator_props_popup(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01126 { 01127 01128 if((op->type->flag & OPTYPE_REGISTER)==0) { 01129 BKE_reportf(op->reports, RPT_ERROR, "Operator '%s' does not have register enabled, incorrect invoke function.", op->type->idname); 01130 return OPERATOR_CANCELLED; 01131 } 01132 01133 ED_undo_push_op(C, op); 01134 wm_operator_register(C, op); 01135 01136 uiPupBlock(C, wm_block_create_redo, op); 01137 01138 return OPERATOR_RUNNING_MODAL; 01139 } 01140 01141 int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int height) 01142 { 01143 wmOpPopUp *data= MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup"); 01144 01145 data->op= op; 01146 data->width= width; 01147 data->height= height; 01148 data->free_op= TRUE; /* if this runs and gets registered we may want not to free it */ 01149 01150 /* op is not executed until popup OK but is clicked */ 01151 uiPupBlockEx(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data); 01152 01153 return OPERATOR_RUNNING_MODAL; 01154 } 01155 01156 int WM_operator_redo_popup(bContext *C, wmOperator *op) 01157 { 01158 /* CTX_wm_reports(C) because operator is on stack, not active in event system */ 01159 if((op->type->flag & OPTYPE_REGISTER)==0) { 01160 BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s' does not have register enabled, incorrect invoke function.", op->type->idname); 01161 return OPERATOR_CANCELLED; 01162 } 01163 if(op->type->poll && op->type->poll(C)==0) { 01164 BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context.", op->type->idname); 01165 return OPERATOR_CANCELLED; 01166 } 01167 01168 uiPupBlock(C, wm_block_create_redo, op); 01169 01170 return OPERATOR_CANCELLED; 01171 } 01172 01173 /* ***************** Debug menu ************************* */ 01174 01175 static int wm_debug_menu_exec(bContext *C, wmOperator *op) 01176 { 01177 G.rt= RNA_int_get(op->ptr, "debug_value"); 01178 ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C)); 01179 WM_event_add_notifier(C, NC_WINDOW, NULL); 01180 01181 return OPERATOR_FINISHED; 01182 } 01183 01184 static int wm_debug_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01185 { 01186 RNA_int_set(op->ptr, "debug_value", G.rt); 01187 return WM_operator_props_dialog_popup(C, op, 9*UI_UNIT_X, UI_UNIT_Y); 01188 } 01189 01190 static void WM_OT_debug_menu(wmOperatorType *ot) 01191 { 01192 ot->name= "Debug Menu"; 01193 ot->idname= "WM_OT_debug_menu"; 01194 ot->description= "Open a popup to set the debug level"; 01195 01196 ot->invoke= wm_debug_menu_invoke; 01197 ot->exec= wm_debug_menu_exec; 01198 ot->poll= WM_operator_winactive; 01199 01200 RNA_def_int(ot->srna, "debug_value", 0, -10000, 10000, "Debug Value", "", INT_MIN, INT_MAX); 01201 } 01202 01203 01204 /* ***************** Splash Screen ************************* */ 01205 01206 static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg)) 01207 { 01208 uiPupBlockClose(C, arg_block); 01209 } 01210 01211 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused); 01212 01213 /* XXX: hack to refresh splash screen with updated prest menu name, 01214 * since popup blocks don't get regenerated like panels do */ 01215 static void wm_block_splash_refreshmenu (bContext *UNUSED(C), void *UNUSED(arg_block), void *UNUSED(arg)) 01216 { 01217 /* ugh, causes crashes in other buttons, disabling for now until 01218 * a better fix 01219 uiPupBlockClose(C, arg_block); 01220 uiPupBlock(C, wm_block_create_splash, NULL); 01221 */ 01222 } 01223 01224 static int wm_resource_check_prev(void) 01225 { 01226 01227 char *res= BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, TRUE); 01228 01229 // if(res) printf("USER: %s\n", res); 01230 01231 #if 0 /* ignore the local folder */ 01232 if(res == NULL) { 01233 /* with a local dir, copying old files isnt useful since local dir get priority for config */ 01234 res= BLI_get_folder_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, TRUE); 01235 } 01236 #endif 01237 01238 // if(res) printf("LOCAL: %s\n", res); 01239 if(res) { 01240 return FALSE; 01241 } 01242 else { 01243 return (BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, TRUE) != NULL); 01244 } 01245 } 01246 01247 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg)) 01248 { 01249 uiBlock *block; 01250 uiBut *but; 01251 uiLayout *layout, *split, *col; 01252 uiStyle *style= UI_GetStyle(); 01253 struct RecentFile *recent; 01254 int i; 01255 MenuType *mt= WM_menutype_find("USERPREF_MT_splash", TRUE); 01256 char url[96]; 01257 01258 #ifndef WITH_HEADLESS 01259 extern char datatoc_splash_png[]; 01260 extern int datatoc_splash_png_size; 01261 01262 ImBuf *ibuf= IMB_ibImageFromMemory((unsigned char*)datatoc_splash_png, datatoc_splash_png_size, IB_rect, "<splash screen>"); 01263 #else 01264 ImBuf *ibuf= NULL; 01265 #endif 01266 01267 01268 #ifdef WITH_BUILDINFO 01269 int ver_width, rev_width; 01270 char *version_str = NULL; 01271 char *revision_str = NULL; 01272 char version_buf[128]; 01273 char revision_buf[128]; 01274 extern char build_rev[]; 01275 01276 version_str = &version_buf[0]; 01277 revision_str = &revision_buf[0]; 01278 01279 BLI_snprintf(version_str, sizeof(version_str), 01280 "%d.%02d.%d", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION); 01281 BLI_snprintf(revision_str, sizeof(revision_str), "r%s", build_rev); 01282 01283 BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.dpi); 01284 ver_width = (int)BLF_width(style->widgetlabel.uifont_id, version_str) + 5; 01285 rev_width = (int)BLF_width(style->widgetlabel.uifont_id, revision_str) + 5; 01286 #endif //WITH_BUILDINFO 01287 01288 block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); 01289 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); 01290 01291 but= uiDefBut(block, BUT_IMAGE, 0, "", 0, 10, 501, 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */ 01292 uiButSetFunc(but, wm_block_splash_close, block, NULL); 01293 uiBlockSetFunc(block, wm_block_splash_refreshmenu, block, NULL); 01294 01295 #ifdef WITH_BUILDINFO 01296 uiDefBut(block, LABEL, 0, version_str, 494-ver_width, 282-24, ver_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); 01297 uiDefBut(block, LABEL, 0, revision_str, 494-rev_width, 282-36, rev_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); 01298 #endif //WITH_BUILDINFO 01299 01300 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, 480, 110, style); 01301 01302 uiBlockSetEmboss(block, UI_EMBOSS); 01303 /* show the splash menu (containing interaction presets), using python */ 01304 if (mt) { 01305 Menu menu= {NULL}; 01306 menu.layout= layout; 01307 menu.type= mt; 01308 mt->draw(C, &menu); 01309 01310 // wmWindowManager *wm= CTX_wm_manager(C); 01311 // uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE); 01312 } 01313 01314 uiBlockSetEmboss(block, UI_EMBOSSP); 01315 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); 01316 01317 split = uiLayoutSplit(layout, 0, 0); 01318 col = uiLayoutColumn(split, 0); 01319 uiItemL(col, "Links", ICON_NONE); 01320 uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/blenderorg/blender-foundation/donation-payment"); 01321 uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/development/credits"); 01322 uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/development/release-logs/blender-261"); 01323 uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url", "http://wiki.blender.org/index.php/Doc:2.5/Manual"); 01324 uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org"); 01325 uiItemStringO(col, IFACE_("User Community"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/community/user-community"); 01326 if(strcmp(STRINGIFY(BLENDER_VERSION_CYCLE), "release")==0) { 01327 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d" STRINGIFY(BLENDER_VERSION_CHAR) "_release", BLENDER_VERSION/100, BLENDER_VERSION%100); 01328 } 01329 else { 01330 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d_%d", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION); 01331 } 01332 uiItemStringO(col, IFACE_("Python API Reference"), ICON_URL, "WM_OT_url_open", "url", url); 01333 uiItemL(col, "", ICON_NONE); 01334 01335 col = uiLayoutColumn(split, 0); 01336 01337 if(wm_resource_check_prev()) { 01338 uiItemO(col, NULL, ICON_NEW, "WM_OT_copy_prev_settings"); 01339 uiItemS(col); 01340 } 01341 01342 uiItemL(col, IFACE_("Recent"), ICON_NONE); 01343 for(recent = G.recent_files.first, i=0; (i<5) && (recent); recent = recent->next, i++) { 01344 uiItemStringO(col, BLI_path_basename(recent->filepath), ICON_FILE_BLEND, "WM_OT_open_mainfile", "filepath", recent->filepath); 01345 } 01346 01347 uiItemS(col); 01348 uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session"); 01349 uiItemL(col, "", ICON_NONE); 01350 01351 uiCenteredBoundsBlock(block, 0); 01352 uiEndBlock(C, block); 01353 01354 return block; 01355 } 01356 01357 static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) 01358 { 01359 uiPupBlock(C, wm_block_create_splash, NULL); 01360 01361 return OPERATOR_FINISHED; 01362 } 01363 01364 static void WM_OT_splash(wmOperatorType *ot) 01365 { 01366 ot->name= "Splash Screen"; 01367 ot->idname= "WM_OT_splash"; 01368 ot->description= "Opens a blocking popup region with release info"; 01369 01370 ot->invoke= wm_splash_invoke; 01371 ot->poll= WM_operator_winactive; 01372 } 01373 01374 01375 /* ***************** Search menu ************************* */ 01376 static void operator_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2) 01377 { 01378 wmOperatorType *ot= arg2; 01379 01380 if(ot) 01381 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL); 01382 } 01383 01384 static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items) 01385 { 01386 GHashIterator *iter= WM_operatortype_iter(); 01387 01388 for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { 01389 wmOperatorType *ot= BLI_ghashIterator_getValue(iter); 01390 01391 if((ot->flag & OPTYPE_INTERNAL) && (G.f & G_DEBUG) == 0) 01392 continue; 01393 01394 if(BLI_strcasestr(ot->name, str)) { 01395 if(WM_operator_poll((bContext*)C, ot)) { 01396 char name[256]; 01397 int len= strlen(ot->name); 01398 01399 /* display name for menu, can hold hotkey */ 01400 BLI_strncpy(name, ot->name, sizeof(name)); 01401 01402 /* check for hotkey */ 01403 if (len < sizeof(name) - 6) { 01404 if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, TRUE, 01405 &name[len+1], sizeof(name)-len-1)) 01406 { 01407 name[len]= '|'; 01408 } 01409 } 01410 01411 if(0==uiSearchItemAdd(items, name, ot, 0)) 01412 break; 01413 } 01414 } 01415 } 01416 BLI_ghashIterator_free(iter); 01417 } 01418 01419 static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_op)) 01420 { 01421 static char search[256]= ""; 01422 wmEvent event; 01423 wmWindow *win= CTX_wm_window(C); 01424 uiBlock *block; 01425 uiBut *but; 01426 01427 block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); 01428 uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT); 01429 01430 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9*UI_UNIT_X, UI_UNIT_Y, 0, 0, ""); 01431 uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL); 01432 01433 /* fake button, it holds space for search items */ 01434 uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxhHeight(), 9*UI_UNIT_X, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL); 01435 01436 uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ 01437 uiEndBlock(C, block); 01438 01439 event= *(win->eventstate); /* XXX huh huh? make api call */ 01440 event.type= EVT_BUT_OPEN; 01441 event.val= KM_PRESS; 01442 event.customdata= but; 01443 event.customdatafree= FALSE; 01444 wm_event_add(win, &event); 01445 01446 return block; 01447 } 01448 01449 static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) 01450 { 01451 return OPERATOR_FINISHED; 01452 } 01453 01454 static int wm_search_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01455 { 01456 uiPupBlock(C, wm_block_search_menu, op); 01457 01458 return OPERATOR_CANCELLED; 01459 } 01460 01461 /* op->poll */ 01462 static int wm_search_menu_poll(bContext *C) 01463 { 01464 if(CTX_wm_window(C)==NULL) { 01465 return 0; 01466 } 01467 else { 01468 ScrArea *sa= CTX_wm_area(C); 01469 if(sa) { 01470 if(sa->spacetype==SPACE_CONSOLE) return 0; // XXX - so we can use the shortcut in the console 01471 if(sa->spacetype==SPACE_TEXT) return 0; // XXX - so we can use the spacebar in the text editor 01472 } 01473 else { 01474 Object *editob= CTX_data_edit_object(C); 01475 if(editob && editob->type==OB_FONT) return 0; // XXX - so we can use the spacebar for entering text 01476 } 01477 } 01478 return 1; 01479 } 01480 01481 static void WM_OT_search_menu(wmOperatorType *ot) 01482 { 01483 ot->name= "Search Menu"; 01484 ot->idname= "WM_OT_search_menu"; 01485 01486 ot->invoke= wm_search_menu_invoke; 01487 ot->exec= wm_search_menu_exec; 01488 ot->poll= wm_search_menu_poll; 01489 } 01490 01491 static int wm_call_menu_exec(bContext *C, wmOperator *op) 01492 { 01493 char idname[BKE_ST_MAXNAME]; 01494 RNA_string_get(op->ptr, "name", idname); 01495 01496 uiPupMenuInvoke(C, idname); 01497 01498 return OPERATOR_CANCELLED; 01499 } 01500 01501 static void WM_OT_call_menu(wmOperatorType *ot) 01502 { 01503 ot->name= "Call Menu"; 01504 ot->idname= "WM_OT_call_menu"; 01505 01506 ot->exec= wm_call_menu_exec; 01507 ot->poll= WM_operator_winactive; 01508 01509 ot->flag= OPTYPE_INTERNAL; 01510 01511 RNA_def_string(ot->srna, "name", "", BKE_ST_MAXNAME, "Name", "Name of the menu"); 01512 } 01513 01514 /* ************ window / screen operator definitions ************** */ 01515 01516 /* this poll functions is needed in place of WM_operator_winactive 01517 * while it crashes on full screen */ 01518 static int wm_operator_winactive_normal(bContext *C) 01519 { 01520 wmWindow *win= CTX_wm_window(C); 01521 01522 if(win==NULL || win->screen==NULL || win->screen->full != SCREENNORMAL) 01523 return 0; 01524 01525 return 1; 01526 } 01527 01528 static void WM_OT_window_duplicate(wmOperatorType *ot) 01529 { 01530 ot->name= "Duplicate Window"; 01531 ot->idname= "WM_OT_window_duplicate"; 01532 ot->description="Duplicate the current Blender window"; 01533 01534 ot->exec= wm_window_duplicate_exec; 01535 ot->poll= wm_operator_winactive_normal; 01536 } 01537 01538 static void WM_OT_save_homefile(wmOperatorType *ot) 01539 { 01540 ot->name= "Save User Settings"; 01541 ot->idname= "WM_OT_save_homefile"; 01542 ot->description="Make the current file the default .blend file"; 01543 01544 ot->invoke= WM_operator_confirm; 01545 ot->exec= WM_write_homefile; 01546 ot->poll= WM_operator_winactive; 01547 } 01548 01549 static void WM_OT_read_homefile(wmOperatorType *ot) 01550 { 01551 ot->name= "Reload Start-Up File"; 01552 ot->idname= "WM_OT_read_homefile"; 01553 ot->description="Open the default file (doesn't save the current file)"; 01554 01555 ot->invoke= WM_operator_confirm; 01556 ot->exec= WM_read_homefile_exec; 01557 /* ommit poll to run in background mode */ 01558 } 01559 01560 static void WM_OT_read_factory_settings(wmOperatorType *ot) 01561 { 01562 ot->name= "Load Factory Settings"; 01563 ot->idname= "WM_OT_read_factory_settings"; 01564 ot->description="Load default file and user preferences"; 01565 01566 ot->invoke= WM_operator_confirm; 01567 ot->exec= WM_read_homefile_exec; 01568 /* ommit poll to run in background mode */ 01569 } 01570 01571 /* *************** open file **************** */ 01572 01573 static void open_set_load_ui(wmOperator *op) 01574 { 01575 if(!RNA_struct_property_is_set(op->ptr, "load_ui")) 01576 RNA_boolean_set(op->ptr, "load_ui", !(U.flag & USER_FILENOUI)); 01577 } 01578 01579 static void open_set_use_scripts(wmOperator *op) 01580 { 01581 if(!RNA_struct_property_is_set(op->ptr, "use_scripts")) { 01582 /* use G_SCRIPT_AUTOEXEC rather than the userpref because this means if 01583 * the flag has been disabled from the command line, then opening 01584 * from the menu wont enable this setting. */ 01585 RNA_boolean_set(op->ptr, "use_scripts", (G.f & G_SCRIPT_AUTOEXEC)); 01586 } 01587 } 01588 01589 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01590 { 01591 const char *openname= G.main->name; 01592 01593 if(CTX_wm_window(C) == NULL) { 01594 /* in rare cases this could happen, when trying to invoke in background 01595 * mode on load for example. Don't use poll for this because exec() 01596 * can still run without a window */ 01597 BKE_report(op->reports, RPT_ERROR, "Context window not set"); 01598 return OPERATOR_CANCELLED; 01599 } 01600 01601 /* if possible, get the name of the most recently used .blend file */ 01602 if (G.recent_files.first) { 01603 struct RecentFile *recent = G.recent_files.first; 01604 openname = recent->filepath; 01605 } 01606 01607 RNA_string_set(op->ptr, "filepath", openname); 01608 open_set_load_ui(op); 01609 open_set_use_scripts(op); 01610 01611 WM_event_add_fileselect(C, op); 01612 01613 return OPERATOR_RUNNING_MODAL; 01614 } 01615 01616 static int wm_open_mainfile_exec(bContext *C, wmOperator *op) 01617 { 01618 char path[FILE_MAX]; 01619 01620 RNA_string_get(op->ptr, "filepath", path); 01621 open_set_load_ui(op); 01622 open_set_use_scripts(op); 01623 01624 if(RNA_boolean_get(op->ptr, "load_ui")) 01625 G.fileflags &= ~G_FILE_NO_UI; 01626 else 01627 G.fileflags |= G_FILE_NO_UI; 01628 01629 if(RNA_boolean_get(op->ptr, "use_scripts")) 01630 G.f |= G_SCRIPT_AUTOEXEC; 01631 else 01632 G.f &= ~G_SCRIPT_AUTOEXEC; 01633 01634 // XXX wm in context is not set correctly after WM_read_file -> crash 01635 // do it before for now, but is this correct with multiple windows? 01636 WM_event_add_notifier(C, NC_WINDOW, NULL); 01637 01638 WM_read_file(C, path, op->reports); 01639 01640 return OPERATOR_FINISHED; 01641 } 01642 01643 static void WM_OT_open_mainfile(wmOperatorType *ot) 01644 { 01645 ot->name= "Open Blender File"; 01646 ot->idname= "WM_OT_open_mainfile"; 01647 ot->description="Open a Blender file"; 01648 01649 ot->invoke= wm_open_mainfile_invoke; 01650 ot->exec= wm_open_mainfile_exec; 01651 /* ommit window poll so this can work in background mode */ 01652 01653 WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH); 01654 01655 RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file"); 01656 RNA_def_boolean(ot->srna, "use_scripts", 1, "Trusted Source", "Allow blend file execute scripts automatically, default available from system preferences"); 01657 } 01658 01659 /* **************** link/append *************** */ 01660 01661 int wm_link_append_poll(bContext *C) 01662 { 01663 if(WM_operator_winactive(C)) { 01664 /* linking changes active object which is pretty useful in general, 01665 but which totally confuses edit mode (i.e. it becoming not so obvious 01666 to leave from edit mode and inwalid tools in toolbar might be displayed) 01667 so disable link/append when in edit mode (sergey) */ 01668 if(CTX_data_edit_object(C)) 01669 return 0; 01670 01671 return 1; 01672 } 01673 01674 return 0; 01675 } 01676 01677 static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01678 { 01679 if(RNA_struct_property_is_set(op->ptr, "filepath")) { 01680 return WM_operator_call_notest(C, op); 01681 } 01682 else { 01683 /* XXX TODO solve where to get last linked library from */ 01684 if(G.lib[0] != '\0') { 01685 RNA_string_set(op->ptr, "filepath", G.lib); 01686 } 01687 else if(G.relbase_valid) { 01688 char path[FILE_MAX]; 01689 BLI_strncpy(path, G.main->name, sizeof(G.main->name)); 01690 BLI_parent_dir(path); 01691 RNA_string_set(op->ptr, "filepath", path); 01692 } 01693 WM_event_add_fileselect(C, op); 01694 return OPERATOR_RUNNING_MODAL; 01695 } 01696 } 01697 01698 static short wm_link_append_flag(wmOperator *op) 01699 { 01700 short flag= 0; 01701 01702 if(RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; 01703 if(RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY; 01704 if(RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH; 01705 if(RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK; 01706 if(RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE; 01707 01708 return flag; 01709 } 01710 01711 static int wm_link_append_exec(bContext *C, wmOperator *op) 01712 { 01713 Main *bmain= CTX_data_main(C); 01714 Scene *scene= CTX_data_scene(C); 01715 Main *mainl= NULL; 01716 BlendHandle *bh; 01717 PropertyRNA *prop; 01718 char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX]; 01719 int idcode, totfiles=0; 01720 short flag; 01721 01722 RNA_string_get(op->ptr, "filename", name); 01723 RNA_string_get(op->ptr, "directory", dir); 01724 01725 /* test if we have a valid data */ 01726 if(BLO_is_a_library(dir, libname, group) == 0) { 01727 BKE_report(op->reports, RPT_ERROR, "Not a library"); 01728 return OPERATOR_CANCELLED; 01729 } 01730 else if(group[0] == 0) { 01731 BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); 01732 return OPERATOR_CANCELLED; 01733 } 01734 else if(BLI_path_cmp(bmain->name, libname) == 0) { 01735 BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library"); 01736 return OPERATOR_CANCELLED; 01737 } 01738 01739 /* check if something is indicated for append/link */ 01740 prop = RNA_struct_find_property(op->ptr, "files"); 01741 if(prop) { 01742 totfiles= RNA_property_collection_length(op->ptr, prop); 01743 if(totfiles == 0) { 01744 if(name[0] == '\0') { 01745 BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); 01746 return OPERATOR_CANCELLED; 01747 } 01748 } 01749 } 01750 else if(name[0] == '\0') { 01751 BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); 01752 return OPERATOR_CANCELLED; 01753 } 01754 01755 bh = BLO_blendhandle_from_file(libname, op->reports); 01756 01757 if(bh == NULL) { 01758 /* unlikely since we just browsed it, but possible 01759 * error reports will have been made by BLO_blendhandle_from_file() */ 01760 return OPERATOR_CANCELLED; 01761 } 01762 01763 01764 /* from here down, no error returns */ 01765 01766 idcode = BKE_idcode_from_name(group); 01767 01768 /* now we have or selected, or an indicated file */ 01769 if(RNA_boolean_get(op->ptr, "autoselect")) 01770 scene_deselect_all(scene); 01771 01772 01773 flag = wm_link_append_flag(op); 01774 01775 /* sanity checks for flag */ 01776 if(scene->id.lib && (flag & FILE_GROUP_INSTANCE)) { 01777 /* TODO, user never gets this message */ 01778 BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name+2); 01779 flag &= ~FILE_GROUP_INSTANCE; 01780 } 01781 01782 01783 /* tag everything, all untagged data can be made local 01784 * its also generally useful to know what is new 01785 * 01786 * take extra care flag_all_listbases_ids(LIB_LINK_TAG, 0) is called after! */ 01787 flag_all_listbases_ids(LIB_PRE_EXISTING, 1); 01788 01789 /* here appending/linking starts */ 01790 mainl = BLO_library_append_begin(bmain, &bh, libname); 01791 if(totfiles == 0) { 01792 BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); 01793 } 01794 else { 01795 RNA_BEGIN(op->ptr, itemptr, "files") { 01796 RNA_string_get(&itemptr, "name", name); 01797 BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); 01798 } 01799 RNA_END; 01800 } 01801 BLO_library_append_end(C, mainl, &bh, idcode, flag); 01802 01803 /* mark all library linked objects to be updated */ 01804 recalc_all_library_objects(bmain); 01805 01806 /* append, rather than linking */ 01807 if((flag & FILE_LINK)==0) { 01808 Library *lib= BLI_findstring(&bmain->library, libname, offsetof(Library, filepath)); 01809 if(lib) BKE_library_make_local(bmain, lib, 1); 01810 else BLI_assert(!"cant find name of just added library!"); 01811 } 01812 01813 /* important we unset, otherwise these object wont 01814 * link into other scenes from this blend file */ 01815 flag_all_listbases_ids(LIB_PRE_EXISTING, 0); 01816 01817 /* recreate dependency graph to include new objects */ 01818 DAG_scene_sort(bmain, scene); 01819 DAG_ids_flush_update(bmain, 0); 01820 01821 BLO_blendhandle_close(bh); 01822 01823 /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ 01824 BLI_strncpy(G.lib, dir, FILE_MAX); 01825 01826 WM_event_add_notifier(C, NC_WINDOW, NULL); 01827 01828 return OPERATOR_FINISHED; 01829 } 01830 01831 static void WM_OT_link_append(wmOperatorType *ot) 01832 { 01833 ot->name= "Link/Append from Library"; 01834 ot->idname= "WM_OT_link_append"; 01835 ot->description= "Link or Append from a Library .blend file"; 01836 01837 ot->invoke= wm_link_append_invoke; 01838 ot->exec= wm_link_append_exec; 01839 ot->poll= wm_link_append_poll; 01840 01841 ot->flag |= OPTYPE_UNDO; 01842 01843 WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_DIRECTORY|WM_FILESEL_FILENAME| WM_FILESEL_RELPATH|WM_FILESEL_FILES); 01844 01845 RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending"); 01846 RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects"); 01847 RNA_def_boolean(ot->srna, "active_layer", 1, "Active Layer", "Put the linked objects on the active layer"); 01848 RNA_def_boolean(ot->srna, "instance_groups", 1, "Instance Groups", "Create instances for each group as a DupliGroup"); 01849 } 01850 01851 /* *************** recover last session **************** */ 01852 01853 static int wm_recover_last_session_exec(bContext *C, wmOperator *op) 01854 { 01855 char filename[FILE_MAX]; 01856 01857 G.fileflags |= G_FILE_RECOVER; 01858 01859 // XXX wm in context is not set correctly after WM_read_file -> crash 01860 // do it before for now, but is this correct with multiple windows? 01861 WM_event_add_notifier(C, NC_WINDOW, NULL); 01862 01863 /* load file */ 01864 BLI_make_file_string("/", filename, BLI_temporary_dir(), "quit.blend"); 01865 WM_read_file(C, filename, op->reports); 01866 01867 G.fileflags &= ~G_FILE_RECOVER; 01868 return OPERATOR_FINISHED; 01869 } 01870 01871 static void WM_OT_recover_last_session(wmOperatorType *ot) 01872 { 01873 ot->name= "Recover Last Session"; 01874 ot->idname= "WM_OT_recover_last_session"; 01875 ot->description="Open the last closed file (\"quit.blend\")"; 01876 01877 ot->exec= wm_recover_last_session_exec; 01878 ot->poll= WM_operator_winactive; 01879 } 01880 01881 /* *************** recover auto save **************** */ 01882 01883 static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) 01884 { 01885 char path[FILE_MAX]; 01886 01887 RNA_string_get(op->ptr, "filepath", path); 01888 01889 G.fileflags |= G_FILE_RECOVER; 01890 01891 // XXX wm in context is not set correctly after WM_read_file -> crash 01892 // do it before for now, but is this correct with multiple windows? 01893 WM_event_add_notifier(C, NC_WINDOW, NULL); 01894 01895 /* load file */ 01896 WM_read_file(C, path, op->reports); 01897 01898 G.fileflags &= ~G_FILE_RECOVER; 01899 01900 return OPERATOR_FINISHED; 01901 } 01902 01903 static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01904 { 01905 char filename[FILE_MAX]; 01906 01907 wm_autosave_location(filename); 01908 RNA_string_set(op->ptr, "filepath", filename); 01909 WM_event_add_fileselect(C, op); 01910 01911 return OPERATOR_RUNNING_MODAL; 01912 } 01913 01914 static void WM_OT_recover_auto_save(wmOperatorType *ot) 01915 { 01916 ot->name= "Recover Auto Save"; 01917 ot->idname= "WM_OT_recover_auto_save"; 01918 ot->description="Open an automatically saved file to recover it"; 01919 01920 ot->exec= wm_recover_auto_save_exec; 01921 ot->invoke= wm_recover_auto_save_invoke; 01922 ot->poll= WM_operator_winactive; 01923 01924 WM_operator_properties_filesel(ot, BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH); 01925 } 01926 01927 /* *************** save file as **************** */ 01928 01929 static void untitled(char *name) 01930 { 01931 if(G.save_over == 0 && strlen(name) < FILE_MAX-16) { 01932 char *c= BLI_last_slash(name); 01933 01934 if(c) 01935 strcpy(&c[1], "untitled.blend"); 01936 else 01937 strcpy(name, "untitled.blend"); 01938 } 01939 } 01940 01941 static void save_set_compress(wmOperator *op) 01942 { 01943 if(!RNA_struct_property_is_set(op->ptr, "compress")) { 01944 if(G.save_over) /* keep flag for existing file */ 01945 RNA_boolean_set(op->ptr, "compress", G.fileflags & G_FILE_COMPRESS); 01946 else /* use userdef for new file */ 01947 RNA_boolean_set(op->ptr, "compress", U.flag & USER_FILECOMPRESS); 01948 } 01949 } 01950 01951 static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01952 { 01953 char name[FILE_MAX]; 01954 01955 save_set_compress(op); 01956 01957 /* if not saved before, get the name of the most recently used .blend file */ 01958 if(G.main->name[0]==0 && G.recent_files.first) { 01959 struct RecentFile *recent = G.recent_files.first; 01960 BLI_strncpy(name, recent->filepath, FILE_MAX); 01961 } 01962 else 01963 BLI_strncpy(name, G.main->name, FILE_MAX); 01964 01965 untitled(name); 01966 RNA_string_set(op->ptr, "filepath", name); 01967 01968 WM_event_add_fileselect(C, op); 01969 01970 return OPERATOR_RUNNING_MODAL; 01971 } 01972 01973 /* function used for WM_OT_save_mainfile too */ 01974 static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) 01975 { 01976 char path[FILE_MAX]; 01977 int fileflags; 01978 int copy=0; 01979 01980 save_set_compress(op); 01981 01982 if(RNA_struct_property_is_set(op->ptr, "filepath")) 01983 RNA_string_get(op->ptr, "filepath", path); 01984 else { 01985 BLI_strncpy(path, G.main->name, FILE_MAX); 01986 untitled(path); 01987 } 01988 01989 if(RNA_struct_property_is_set(op->ptr, "copy")) 01990 copy = RNA_boolean_get(op->ptr, "copy"); 01991 01992 fileflags= G.fileflags; 01993 01994 /* set compression flag */ 01995 if(RNA_boolean_get(op->ptr, "compress")) fileflags |= G_FILE_COMPRESS; 01996 else fileflags &= ~G_FILE_COMPRESS; 01997 if(RNA_boolean_get(op->ptr, "relative_remap")) fileflags |= G_FILE_RELATIVE_REMAP; 01998 else fileflags &= ~G_FILE_RELATIVE_REMAP; 01999 #ifdef USE_BMESH_SAVE_AS_COMPAT 02000 if(RNA_boolean_get(op->ptr, "use_mesh_compat")) fileflags |= G_FILE_MESH_COMPAT; 02001 else fileflags &= ~G_FILE_MESH_COMPAT; 02002 #endif 02003 02004 if ( WM_write_file(C, path, fileflags, op->reports, copy) != 0) 02005 return OPERATOR_CANCELLED; 02006 02007 WM_event_add_notifier(C, NC_WM|ND_FILESAVE, NULL); 02008 02009 return OPERATOR_FINISHED; 02010 } 02011 02012 /* function used for WM_OT_save_mainfile too */ 02013 static int blend_save_check(bContext *UNUSED(C), wmOperator *op) 02014 { 02015 char filepath[FILE_MAX]; 02016 RNA_string_get(op->ptr, "filepath", filepath); 02017 if(!BLO_has_bfile_extension(filepath)) { 02018 /* some users would prefer BLI_replace_extension(), 02019 * we keep getting knit-picking bug reports about this - campbell */ 02020 BLI_ensure_extension(filepath, FILE_MAX, ".blend"); 02021 RNA_string_set(op->ptr, "filepath", filepath); 02022 return TRUE; 02023 } 02024 return FALSE; 02025 } 02026 02027 static void WM_OT_save_as_mainfile(wmOperatorType *ot) 02028 { 02029 ot->name= "Save As Blender File"; 02030 ot->idname= "WM_OT_save_as_mainfile"; 02031 ot->description="Save the current file in the desired location"; 02032 02033 ot->invoke= wm_save_as_mainfile_invoke; 02034 ot->exec= wm_save_as_mainfile_exec; 02035 ot->check= blend_save_check; 02036 /* ommit window poll so this can work in background mode */ 02037 02038 WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH); 02039 RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file"); 02040 RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", "Remap relative paths when saving in a different directory"); 02041 RNA_def_boolean(ot->srna, "copy", 0, "Save Copy", "Save a copy of the actual working state but does not make saved file active"); 02042 #ifdef USE_BMESH_SAVE_AS_COMPAT 02043 RNA_def_boolean(ot->srna, "use_mesh_compat", 0, "Legacy Mesh Format", "Save using legacy mesh format (no ngons)"); 02044 #endif 02045 } 02046 02047 /* *************** save file directly ******** */ 02048 02049 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 02050 { 02051 char name[FILE_MAX]; 02052 int check_existing=1; 02053 int ret; 02054 02055 /* cancel if no active window */ 02056 if (CTX_wm_window(C) == NULL) 02057 return OPERATOR_CANCELLED; 02058 02059 save_set_compress(op); 02060 02061 /* if not saved before, get the name of the most recently used .blend file */ 02062 if(G.main->name[0]==0 && G.recent_files.first) { 02063 struct RecentFile *recent = G.recent_files.first; 02064 BLI_strncpy(name, recent->filepath, FILE_MAX); 02065 } 02066 else 02067 BLI_strncpy(name, G.main->name, FILE_MAX); 02068 02069 untitled(name); 02070 02071 RNA_string_set(op->ptr, "filepath", name); 02072 02073 if (RNA_struct_find_property(op->ptr, "check_existing")) 02074 if (RNA_boolean_get(op->ptr, "check_existing")==0) 02075 check_existing = 0; 02076 02077 if (G.save_over) { 02078 if (check_existing && BLI_exists(name)) { 02079 uiPupMenuSaveOver(C, op, name); 02080 ret= OPERATOR_RUNNING_MODAL; 02081 } 02082 else { 02083 ret= wm_save_as_mainfile_exec(C, op); 02084 } 02085 } 02086 else { 02087 WM_event_add_fileselect(C, op); 02088 ret= OPERATOR_RUNNING_MODAL; 02089 } 02090 02091 return ret; 02092 } 02093 02094 static void WM_OT_save_mainfile(wmOperatorType *ot) 02095 { 02096 ot->name= "Save Blender File"; 02097 ot->idname= "WM_OT_save_mainfile"; 02098 ot->description="Save the current Blender file"; 02099 02100 ot->invoke= wm_save_mainfile_invoke; 02101 ot->exec= wm_save_as_mainfile_exec; 02102 ot->check= blend_save_check; 02103 /* ommit window poll so this can work in background mode */ 02104 02105 WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH); 02106 RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file"); 02107 RNA_def_boolean(ot->srna, "relative_remap", 0, "Remap Relative", "Remap relative paths when saving in a different directory"); 02108 } 02109 02110 /* XXX: move these collada operators to a more appropriate place */ 02111 #ifdef WITH_COLLADA 02112 02113 #include "../../collada/collada.h" 02114 02115 static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 02116 { 02117 if(!RNA_struct_property_is_set(op->ptr, "filepath")) { 02118 char filepath[FILE_MAX]; 02119 BLI_strncpy(filepath, G.main->name, sizeof(filepath)); 02120 BLI_replace_extension(filepath, sizeof(filepath), ".dae"); 02121 RNA_string_set(op->ptr, "filepath", filepath); 02122 } 02123 02124 WM_event_add_fileselect(C, op); 02125 02126 return OPERATOR_RUNNING_MODAL; 02127 } 02128 02129 /* function used for WM_OT_save_mainfile too */ 02130 static int wm_collada_export_exec(bContext *C, wmOperator *op) 02131 { 02132 char filename[FILE_MAX]; 02133 int selected; 02134 02135 if(!RNA_struct_property_is_set(op->ptr, "filepath")) { 02136 BKE_report(op->reports, RPT_ERROR, "No filename given"); 02137 return OPERATOR_CANCELLED; 02138 } 02139 02140 RNA_string_get(op->ptr, "filepath", filename); 02141 selected = RNA_boolean_get(op->ptr, "selected"); 02142 if(collada_export(CTX_data_scene(C), filename, selected)) { 02143 return OPERATOR_FINISHED; 02144 } 02145 else { 02146 return OPERATOR_CANCELLED; 02147 } 02148 } 02149 02150 static void WM_OT_collada_export(wmOperatorType *ot) 02151 { 02152 ot->name= "Export COLLADA"; 02153 ot->idname= "WM_OT_collada_export"; 02154 02155 ot->invoke= wm_collada_export_invoke; 02156 ot->exec= wm_collada_export_exec; 02157 ot->poll= WM_operator_winactive; 02158 02159 WM_operator_properties_filesel(ot, FOLDERFILE|COLLADAFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH); 02160 RNA_def_boolean(ot->srna, "selected", 0, "Export only selected", 02161 "Export only selected elements"); 02162 } 02163 02164 /* function used for WM_OT_save_mainfile too */ 02165 static int wm_collada_import_exec(bContext *C, wmOperator *op) 02166 { 02167 char filename[FILE_MAX]; 02168 02169 if(!RNA_struct_property_is_set(op->ptr, "filepath")) { 02170 BKE_report(op->reports, RPT_ERROR, "No filename given"); 02171 return OPERATOR_CANCELLED; 02172 } 02173 02174 RNA_string_get(op->ptr, "filepath", filename); 02175 if(collada_import(C, filename)) return OPERATOR_FINISHED; 02176 02177 BKE_report(op->reports, RPT_ERROR, "Errors found during parsing COLLADA document. Please see console for error log."); 02178 02179 return OPERATOR_FINISHED; 02180 } 02181 02182 static void WM_OT_collada_import(wmOperatorType *ot) 02183 { 02184 ot->name= "Import COLLADA"; 02185 ot->idname= "WM_OT_collada_import"; 02186 02187 ot->invoke= WM_operator_filesel; 02188 ot->exec= wm_collada_import_exec; 02189 ot->poll= WM_operator_winactive; 02190 02191 WM_operator_properties_filesel(ot, FOLDERFILE|COLLADAFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH); 02192 } 02193 02194 #endif 02195 02196 02197 /* *********************** */ 02198 02199 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot) 02200 { 02201 ot->name= "Toggle Fullscreen"; 02202 ot->idname= "WM_OT_window_fullscreen_toggle"; 02203 ot->description="Toggle the current window fullscreen"; 02204 02205 ot->exec= wm_window_fullscreen_toggle_exec; 02206 ot->poll= WM_operator_winactive; 02207 } 02208 02209 static int wm_exit_blender_op(bContext *C, wmOperator *op) 02210 { 02211 WM_operator_free(op); 02212 02213 WM_exit(C); 02214 02215 return OPERATOR_FINISHED; 02216 } 02217 02218 static void WM_OT_quit_blender(wmOperatorType *ot) 02219 { 02220 ot->name= "Quit Blender"; 02221 ot->idname= "WM_OT_quit_blender"; 02222 ot->description= "Quit Blender"; 02223 02224 ot->invoke= WM_operator_confirm; 02225 ot->exec= wm_exit_blender_op; 02226 ot->poll= WM_operator_winactive; 02227 } 02228 02229 /* *********************** */ 02230 02231 #if defined(WIN32) 02232 02233 static int wm_console_toggle_op(bContext *UNUSED(C), wmOperator *UNUSED(op)) 02234 { 02235 GHOST_toggleConsole(2); 02236 return OPERATOR_FINISHED; 02237 } 02238 02239 static void WM_OT_console_toggle(wmOperatorType *ot) 02240 { 02241 ot->name= "Toggle System Console"; 02242 ot->idname= "WM_OT_console_toggle"; 02243 ot->description= "Toggle System Console"; 02244 02245 ot->exec= wm_console_toggle_op; 02246 ot->poll= WM_operator_winactive; 02247 } 02248 02249 #endif 02250 02251 /* ************ default paint cursors, draw always around cursor *********** */ 02252 /* 02253 - returns handler to free 02254 - poll(bContext): returns 1 if draw should happen 02255 - draw(bContext): drawing callback for paint cursor 02256 */ 02257 02258 void *WM_paint_cursor_activate(wmWindowManager *wm, int (*poll)(bContext *C), 02259 wmPaintCursorDraw draw, void *customdata) 02260 { 02261 wmPaintCursor *pc= MEM_callocN(sizeof(wmPaintCursor), "paint cursor"); 02262 02263 BLI_addtail(&wm->paintcursors, pc); 02264 02265 pc->customdata = customdata; 02266 pc->poll= poll; 02267 pc->draw= draw; 02268 02269 return pc; 02270 } 02271 02272 void WM_paint_cursor_end(wmWindowManager *wm, void *handle) 02273 { 02274 wmPaintCursor *pc; 02275 02276 for(pc= wm->paintcursors.first; pc; pc= pc->next) { 02277 if(pc == (wmPaintCursor *)handle) { 02278 BLI_remlink(&wm->paintcursors, pc); 02279 MEM_freeN(pc); 02280 return; 02281 } 02282 } 02283 } 02284 02285 /* ************ window gesture operator-callback definitions ************** */ 02286 /* 02287 * These are default callbacks for use in operators requiring gesture input 02288 */ 02289 02290 /* **************** Border gesture *************** */ 02291 02292 /* Border gesture has two types: 02293 1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border 02294 2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends 02295 02296 It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type) 02297 */ 02298 02299 static int border_apply_rect(wmOperator *op) 02300 { 02301 wmGesture *gesture= op->customdata; 02302 rcti *rect= gesture->customdata; 02303 02304 if(rect->xmin==rect->xmax || rect->ymin==rect->ymax) 02305 return 0; 02306 02307 02308 /* operator arguments and storage. */ 02309 RNA_int_set(op->ptr, "xmin", MIN2(rect->xmin, rect->xmax) ); 02310 RNA_int_set(op->ptr, "ymin", MIN2(rect->ymin, rect->ymax) ); 02311 RNA_int_set(op->ptr, "xmax", MAX2(rect->xmin, rect->xmax) ); 02312 RNA_int_set(op->ptr, "ymax", MAX2(rect->ymin, rect->ymax) ); 02313 02314 return 1; 02315 } 02316 02317 static int border_apply(bContext *C, wmOperator *op, int gesture_mode) 02318 { 02319 if (!border_apply_rect(op)) 02320 return 0; 02321 02322 /* XXX weak; border should be configured for this without reading event types */ 02323 if( RNA_struct_find_property(op->ptr, "gesture_mode") ) 02324 RNA_int_set(op->ptr, "gesture_mode", gesture_mode); 02325 02326 op->type->exec(C, op); 02327 return 1; 02328 } 02329 02330 static void wm_gesture_end(bContext *C, wmOperator *op) 02331 { 02332 wmGesture *gesture= op->customdata; 02333 02334 WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */ 02335 op->customdata= NULL; 02336 02337 ED_area_tag_redraw(CTX_wm_area(C)); 02338 02339 if( RNA_struct_find_property(op->ptr, "cursor") ) 02340 WM_cursor_restore(CTX_wm_window(C)); 02341 } 02342 02343 int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event) 02344 { 02345 if(ISTWEAK(event->type)) 02346 op->customdata= WM_gesture_new(C, event, WM_GESTURE_RECT); 02347 else 02348 op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT); 02349 02350 /* add modal handler */ 02351 WM_event_add_modal_handler(C, op); 02352 02353 wm_gesture_tag_redraw(C); 02354 02355 return OPERATOR_RUNNING_MODAL; 02356 } 02357 02358 int WM_border_select_modal(bContext *C, wmOperator *op, wmEvent *event) 02359 { 02360 wmGesture *gesture= op->customdata; 02361 rcti *rect= gesture->customdata; 02362 int sx, sy; 02363 02364 if(event->type== MOUSEMOVE) { 02365 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy); 02366 02367 if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) { 02368 rect->xmin= rect->xmax= event->x - sx; 02369 rect->ymin= rect->ymax= event->y - sy; 02370 } 02371 else { 02372 rect->xmax= event->x - sx; 02373 rect->ymax= event->y - sy; 02374 } 02375 border_apply_rect(op); 02376 02377 wm_gesture_tag_redraw(C); 02378 } 02379 else if (event->type==EVT_MODAL_MAP) { 02380 switch (event->val) { 02381 case GESTURE_MODAL_BEGIN: 02382 if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) { 02383 gesture->mode= 1; 02384 wm_gesture_tag_redraw(C); 02385 } 02386 break; 02387 case GESTURE_MODAL_SELECT: 02388 case GESTURE_MODAL_DESELECT: 02389 case GESTURE_MODAL_IN: 02390 case GESTURE_MODAL_OUT: 02391 if(border_apply(C, op, event->val)) { 02392 wm_gesture_end(C, op); 02393 return OPERATOR_FINISHED; 02394 } 02395 wm_gesture_end(C, op); 02396 return OPERATOR_CANCELLED; 02397 break; 02398 02399 case GESTURE_MODAL_CANCEL: 02400 wm_gesture_end(C, op); 02401 return OPERATOR_CANCELLED; 02402 } 02403 02404 } 02405 // // Allow view navigation??? 02406 // else { 02407 // return OPERATOR_PASS_THROUGH; 02408 // } 02409 02410 return OPERATOR_RUNNING_MODAL; 02411 } 02412 02413 int WM_border_select_cancel(bContext *C, wmOperator *op) 02414 { 02415 wm_gesture_end(C, op); 02416 02417 return OPERATOR_CANCELLED; 02418 } 02419 02420 /* **************** circle gesture *************** */ 02421 /* works now only for selection or modal paint stuff, calls exec while hold mouse, exit on release */ 02422 02423 #ifdef GESTURE_MEMORY 02424 int circle_select_size= 25; // XXX - need some operator memory thing\! 02425 #endif 02426 02427 int WM_gesture_circle_invoke(bContext *C, wmOperator *op, wmEvent *event) 02428 { 02429 op->customdata= WM_gesture_new(C, event, WM_GESTURE_CIRCLE); 02430 02431 /* add modal handler */ 02432 WM_event_add_modal_handler(C, op); 02433 02434 wm_gesture_tag_redraw(C); 02435 02436 return OPERATOR_RUNNING_MODAL; 02437 } 02438 02439 static void gesture_circle_apply(bContext *C, wmOperator *op) 02440 { 02441 wmGesture *gesture= op->customdata; 02442 rcti *rect= gesture->customdata; 02443 02444 if(RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_NOP) 02445 return; 02446 02447 /* operator arguments and storage. */ 02448 RNA_int_set(op->ptr, "x", rect->xmin); 02449 RNA_int_set(op->ptr, "y", rect->ymin); 02450 RNA_int_set(op->ptr, "radius", rect->xmax); 02451 02452 if(op->type->exec) 02453 op->type->exec(C, op); 02454 #ifdef GESTURE_MEMORY 02455 circle_select_size= rect->xmax; 02456 #endif 02457 } 02458 02459 int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event) 02460 { 02461 wmGesture *gesture= op->customdata; 02462 rcti *rect= gesture->customdata; 02463 int sx, sy; 02464 02465 if(event->type== MOUSEMOVE) { 02466 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy); 02467 02468 rect->xmin= event->x - sx; 02469 rect->ymin= event->y - sy; 02470 02471 wm_gesture_tag_redraw(C); 02472 02473 if(gesture->mode) 02474 gesture_circle_apply(C, op); 02475 } 02476 else if (event->type==EVT_MODAL_MAP) { 02477 switch (event->val) { 02478 case GESTURE_MODAL_CIRCLE_ADD: 02479 rect->xmax += 2 + rect->xmax/10; 02480 wm_gesture_tag_redraw(C); 02481 break; 02482 case GESTURE_MODAL_CIRCLE_SUB: 02483 rect->xmax -= 2 + rect->xmax/10; 02484 if(rect->xmax < 1) rect->xmax= 1; 02485 wm_gesture_tag_redraw(C); 02486 break; 02487 case GESTURE_MODAL_SELECT: 02488 case GESTURE_MODAL_DESELECT: 02489 case GESTURE_MODAL_NOP: 02490 if(RNA_struct_find_property(op->ptr, "gesture_mode")) 02491 RNA_int_set(op->ptr, "gesture_mode", event->val); 02492 02493 if(event->val != GESTURE_MODAL_NOP) { 02494 /* apply first click */ 02495 gesture_circle_apply(C, op); 02496 gesture->mode= 1; 02497 wm_gesture_tag_redraw(C); 02498 } 02499 break; 02500 02501 case GESTURE_MODAL_CANCEL: 02502 case GESTURE_MODAL_CONFIRM: 02503 wm_gesture_end(C, op); 02504 return OPERATOR_FINISHED; /* use finish or we dont get an undo */ 02505 } 02506 } 02507 // // Allow view navigation??? 02508 // else { 02509 // return OPERATOR_PASS_THROUGH; 02510 // } 02511 02512 return OPERATOR_RUNNING_MODAL; 02513 } 02514 02515 int WM_gesture_circle_cancel(bContext *C, wmOperator *op) 02516 { 02517 wm_gesture_end(C, op); 02518 02519 return OPERATOR_CANCELLED; 02520 } 02521 02522 #if 0 02523 /* template to copy from */ 02524 void WM_OT_circle_gesture(wmOperatorType *ot) 02525 { 02526 ot->name= "Circle Gesture"; 02527 ot->idname= "WM_OT_circle_gesture"; 02528 ot->description="Enter rotate mode with a circular gesture"; 02529 02530 ot->invoke= WM_gesture_circle_invoke; 02531 ot->modal= WM_gesture_circle_modal; 02532 02533 ot->poll= WM_operator_winactive; 02534 02535 RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE); 02536 RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE); 02537 RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE); 02538 02539 } 02540 #endif 02541 02542 /* **************** Tweak gesture *************** */ 02543 02544 static void tweak_gesture_modal(bContext *C, wmEvent *event) 02545 { 02546 wmWindow *window= CTX_wm_window(C); 02547 wmGesture *gesture= window->tweak; 02548 rcti *rect= gesture->customdata; 02549 int sx, sy, val; 02550 02551 switch(event->type) { 02552 case MOUSEMOVE: 02553 case INBETWEEN_MOUSEMOVE: 02554 02555 wm_subwindow_getorigin(window, gesture->swinid, &sx, &sy); 02556 02557 rect->xmax= event->x - sx; 02558 rect->ymax= event->y - sy; 02559 02560 if((val= wm_gesture_evaluate(gesture))) { 02561 wmEvent tevent; 02562 02563 tevent= *(window->eventstate); 02564 if(gesture->event_type==LEFTMOUSE) 02565 tevent.type= EVT_TWEAK_L; 02566 else if(gesture->event_type==RIGHTMOUSE) 02567 tevent.type= EVT_TWEAK_R; 02568 else 02569 tevent.type= EVT_TWEAK_M; 02570 tevent.val= val; 02571 /* mouse coords! */ 02572 wm_event_add(window, &tevent); 02573 02574 WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */ 02575 } 02576 02577 break; 02578 02579 case LEFTMOUSE: 02580 case RIGHTMOUSE: 02581 case MIDDLEMOUSE: 02582 if(gesture->event_type==event->type) { 02583 WM_gesture_end(C, gesture); 02584 02585 /* when tweak fails we should give the other keymap entries a chance */ 02586 event->val= KM_RELEASE; 02587 } 02588 break; 02589 default: 02590 if(!ISTIMER(event->type)) { 02591 WM_gesture_end(C, gesture); 02592 } 02593 break; 02594 } 02595 } 02596 02597 /* standard tweak, called after window handlers passed on event */ 02598 void wm_tweakevent_test(bContext *C, wmEvent *event, int action) 02599 { 02600 wmWindow *win= CTX_wm_window(C); 02601 02602 if(win->tweak==NULL) { 02603 if(CTX_wm_region(C)) { 02604 if(event->val==KM_PRESS) { 02605 if( ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) ) 02606 win->tweak= WM_gesture_new(C, event, WM_GESTURE_TWEAK); 02607 } 02608 } 02609 } 02610 else { 02611 /* no tweaks if event was handled */ 02612 if((action & WM_HANDLER_BREAK)) { 02613 WM_gesture_end(C, win->tweak); 02614 } 02615 else 02616 tweak_gesture_modal(C, event); 02617 } 02618 } 02619 02620 /* *********************** lasso gesture ****************** */ 02621 02622 int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, wmEvent *event) 02623 { 02624 op->customdata= WM_gesture_new(C, event, WM_GESTURE_LASSO); 02625 02626 /* add modal handler */ 02627 WM_event_add_modal_handler(C, op); 02628 02629 wm_gesture_tag_redraw(C); 02630 02631 if( RNA_struct_find_property(op->ptr, "cursor") ) 02632 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); 02633 02634 return OPERATOR_RUNNING_MODAL; 02635 } 02636 02637 int WM_gesture_lines_invoke(bContext *C, wmOperator *op, wmEvent *event) 02638 { 02639 op->customdata= WM_gesture_new(C, event, WM_GESTURE_LINES); 02640 02641 /* add modal handler */ 02642 WM_event_add_modal_handler(C, op); 02643 02644 wm_gesture_tag_redraw(C); 02645 02646 if( RNA_struct_find_property(op->ptr, "cursor") ) 02647 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); 02648 02649 return OPERATOR_RUNNING_MODAL; 02650 } 02651 02652 02653 static void gesture_lasso_apply(bContext *C, wmOperator *op) 02654 { 02655 wmGesture *gesture= op->customdata; 02656 PointerRNA itemptr; 02657 float loc[2]; 02658 int i; 02659 short *lasso= gesture->customdata; 02660 02661 /* operator storage as path. */ 02662 02663 for(i=0; i<gesture->points; i++, lasso+=2) { 02664 loc[0]= lasso[0]; 02665 loc[1]= lasso[1]; 02666 RNA_collection_add(op->ptr, "path", &itemptr); 02667 RNA_float_set_array(&itemptr, "loc", loc); 02668 } 02669 02670 wm_gesture_end(C, op); 02671 02672 if(op->type->exec) 02673 op->type->exec(C, op); 02674 } 02675 02676 int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event) 02677 { 02678 wmGesture *gesture= op->customdata; 02679 int sx, sy; 02680 02681 switch(event->type) { 02682 case MOUSEMOVE: 02683 case INBETWEEN_MOUSEMOVE: 02684 02685 wm_gesture_tag_redraw(C); 02686 02687 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy); 02688 02689 if(gesture->points == gesture->size) { 02690 short *old_lasso = gesture->customdata; 02691 gesture->customdata= MEM_callocN(2*sizeof(short)*(gesture->size + WM_LASSO_MIN_POINTS), "lasso points"); 02692 memcpy(gesture->customdata, old_lasso, 2*sizeof(short)*gesture->size); 02693 gesture->size = gesture->size + WM_LASSO_MIN_POINTS; 02694 MEM_freeN(old_lasso); 02695 // printf("realloc\n"); 02696 } 02697 02698 { 02699 int x, y; 02700 short *lasso= gesture->customdata; 02701 02702 lasso += (2 * gesture->points - 2); 02703 x = (event->x - sx - lasso[0]); 02704 y = (event->y - sy - lasso[1]); 02705 02706 /* make a simple distance check to get a smoother lasso 02707 add only when at least 2 pixels between this and previous location */ 02708 if((x*x+y*y) > 4) { 02709 lasso += 2; 02710 lasso[0] = event->x - sx; 02711 lasso[1] = event->y - sy; 02712 gesture->points++; 02713 } 02714 } 02715 break; 02716 02717 case LEFTMOUSE: 02718 case MIDDLEMOUSE: 02719 case RIGHTMOUSE: 02720 if(event->val==KM_RELEASE) { /* key release */ 02721 gesture_lasso_apply(C, op); 02722 return OPERATOR_FINISHED; 02723 } 02724 break; 02725 case ESCKEY: 02726 wm_gesture_end(C, op); 02727 return OPERATOR_CANCELLED; 02728 } 02729 return OPERATOR_RUNNING_MODAL; 02730 } 02731 02732 int WM_gesture_lines_modal(bContext *C, wmOperator *op, wmEvent *event) 02733 { 02734 return WM_gesture_lasso_modal(C, op, event); 02735 } 02736 02737 int WM_gesture_lasso_cancel(bContext *C, wmOperator *op) 02738 { 02739 wm_gesture_end(C, op); 02740 02741 return OPERATOR_CANCELLED; 02742 } 02743 02744 int WM_gesture_lines_cancel(bContext *C, wmOperator *op) 02745 { 02746 wm_gesture_end(C, op); 02747 02748 return OPERATOR_CANCELLED; 02749 } 02750 02751 #if 0 02752 /* template to copy from */ 02753 02754 static int gesture_lasso_exec(bContext *C, wmOperator *op) 02755 { 02756 RNA_BEGIN(op->ptr, itemptr, "path") { 02757 float loc[2]; 02758 02759 RNA_float_get_array(&itemptr, "loc", loc); 02760 printf("Location: %f %f\n", loc[0], loc[1]); 02761 } 02762 RNA_END; 02763 02764 return OPERATOR_FINISHED; 02765 } 02766 02767 void WM_OT_lasso_gesture(wmOperatorType *ot) 02768 { 02769 PropertyRNA *prop; 02770 02771 ot->name= "Lasso Gesture"; 02772 ot->idname= "WM_OT_lasso_gesture"; 02773 ot->description="Select objects within the lasso as you move the pointer"; 02774 02775 ot->invoke= WM_gesture_lasso_invoke; 02776 ot->modal= WM_gesture_lasso_modal; 02777 ot->exec= gesture_lasso_exec; 02778 02779 ot->poll= WM_operator_winactive; 02780 02781 prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE); 02782 RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath); 02783 } 02784 #endif 02785 02786 /* *********************** straight line gesture ****************** */ 02787 02788 static int straightline_apply(bContext *C, wmOperator *op) 02789 { 02790 wmGesture *gesture= op->customdata; 02791 rcti *rect= gesture->customdata; 02792 02793 if(rect->xmin==rect->xmax && rect->ymin==rect->ymax) 02794 return 0; 02795 02796 /* operator arguments and storage. */ 02797 RNA_int_set(op->ptr, "xstart", rect->xmin); 02798 RNA_int_set(op->ptr, "ystart", rect->ymin); 02799 RNA_int_set(op->ptr, "xend", rect->xmax); 02800 RNA_int_set(op->ptr, "yend", rect->ymax); 02801 02802 if(op->type->exec) 02803 op->type->exec(C, op); 02804 02805 return 1; 02806 } 02807 02808 02809 int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, wmEvent *event) 02810 { 02811 op->customdata= WM_gesture_new(C, event, WM_GESTURE_STRAIGHTLINE); 02812 02813 /* add modal handler */ 02814 WM_event_add_modal_handler(C, op); 02815 02816 wm_gesture_tag_redraw(C); 02817 02818 if( RNA_struct_find_property(op->ptr, "cursor") ) 02819 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); 02820 02821 return OPERATOR_RUNNING_MODAL; 02822 } 02823 02824 int WM_gesture_straightline_modal(bContext *C, wmOperator *op, wmEvent *event) 02825 { 02826 wmGesture *gesture= op->customdata; 02827 rcti *rect= gesture->customdata; 02828 int sx, sy; 02829 02830 if(event->type== MOUSEMOVE) { 02831 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy); 02832 02833 if(gesture->mode==0) { 02834 rect->xmin= rect->xmax= event->x - sx; 02835 rect->ymin= rect->ymax= event->y - sy; 02836 } 02837 else { 02838 rect->xmax= event->x - sx; 02839 rect->ymax= event->y - sy; 02840 straightline_apply(C, op); 02841 } 02842 02843 wm_gesture_tag_redraw(C); 02844 } 02845 else if (event->type==EVT_MODAL_MAP) { 02846 switch (event->val) { 02847 case GESTURE_MODAL_BEGIN: 02848 if(gesture->mode==0) { 02849 gesture->mode= 1; 02850 wm_gesture_tag_redraw(C); 02851 } 02852 break; 02853 case GESTURE_MODAL_SELECT: 02854 if(straightline_apply(C, op)) { 02855 wm_gesture_end(C, op); 02856 return OPERATOR_FINISHED; 02857 } 02858 wm_gesture_end(C, op); 02859 return OPERATOR_CANCELLED; 02860 break; 02861 02862 case GESTURE_MODAL_CANCEL: 02863 wm_gesture_end(C, op); 02864 return OPERATOR_CANCELLED; 02865 } 02866 02867 } 02868 02869 return OPERATOR_RUNNING_MODAL; 02870 } 02871 02872 int WM_gesture_straightline_cancel(bContext *C, wmOperator *op) 02873 { 02874 wm_gesture_end(C, op); 02875 02876 return OPERATOR_CANCELLED; 02877 } 02878 02879 #if 0 02880 /* template to copy from */ 02881 void WM_OT_straightline_gesture(wmOperatorType *ot) 02882 { 02883 PropertyRNA *prop; 02884 02885 ot->name= "Straight Line Gesture"; 02886 ot->idname= "WM_OT_straightline_gesture"; 02887 ot->description="Draw a straight line as you move the pointer"; 02888 02889 ot->invoke= WM_gesture_straightline_invoke; 02890 ot->modal= WM_gesture_straightline_modal; 02891 ot->exec= gesture_straightline_exec; 02892 02893 ot->poll= WM_operator_winactive; 02894 02895 WM_operator_properties_gesture_straightline(ot, 0); 02896 } 02897 #endif 02898 02899 /* *********************** radial control ****************** */ 02900 02901 static const int WM_RADIAL_CONTROL_DISPLAY_SIZE = 200; 02902 02903 typedef struct { 02904 PropertyType type; 02905 PropertySubType subtype; 02906 PointerRNA ptr, col_ptr, fill_col_ptr, rot_ptr, zoom_ptr, image_id_ptr; 02907 PropertyRNA *prop, *col_prop, *fill_col_prop, *rot_prop, *zoom_prop; 02908 StructRNA *image_id_srna; 02909 float initial_value, current_value, min_value, max_value; 02910 int initial_mouse[2]; 02911 unsigned int gltex; 02912 ListBase orig_paintcursors; 02913 void *cursor; 02914 } RadialControl; 02915 02916 static void radial_control_set_initial_mouse(RadialControl *rc, wmEvent *event) 02917 { 02918 float d[2] = {0, 0}; 02919 float zoom[2] = {1, 1}; 02920 02921 rc->initial_mouse[0]= event->x; 02922 rc->initial_mouse[1]= event->y; 02923 02924 switch(rc->subtype) { 02925 case PROP_DISTANCE: 02926 d[0] = rc->initial_value; 02927 break; 02928 case PROP_FACTOR: 02929 d[0] = WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - rc->initial_value); 02930 break; 02931 case PROP_ANGLE: 02932 d[0] = WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(rc->initial_value); 02933 d[1] = WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(rc->initial_value); 02934 break; 02935 default: 02936 return; 02937 } 02938 02939 if(rc->zoom_prop) { 02940 RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); 02941 d[0] *= zoom[0]; 02942 d[1] *= zoom[1]; 02943 } 02944 02945 rc->initial_mouse[0]-= d[0]; 02946 rc->initial_mouse[1]-= d[1]; 02947 } 02948 02949 static void radial_control_set_tex(RadialControl *rc) 02950 { 02951 ImBuf *ibuf; 02952 02953 switch(RNA_type_to_ID_code(rc->image_id_ptr.type)) { 02954 case ID_BR: 02955 if((ibuf = brush_gen_radial_control_imbuf(rc->image_id_ptr.data))) { 02956 glGenTextures(1, &rc->gltex); 02957 glBindTexture(GL_TEXTURE_2D, rc->gltex); 02958 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ibuf->x, ibuf->y, 0, 02959 GL_ALPHA, GL_FLOAT, ibuf->rect_float); 02960 MEM_freeN(ibuf->rect_float); 02961 MEM_freeN(ibuf); 02962 } 02963 break; 02964 default: 02965 break; 02966 } 02967 } 02968 02969 static void radial_control_paint_tex(RadialControl *rc, float radius, float alpha) 02970 { 02971 float col[3] = {0, 0, 0}; 02972 float rot; 02973 02974 /* set fill color */ 02975 if(rc->fill_col_prop) 02976 RNA_property_float_get_array(&rc->fill_col_ptr, rc->fill_col_prop, col); 02977 glColor4f(col[0], col[1], col[2], alpha); 02978 02979 if(rc->gltex) { 02980 glBindTexture(GL_TEXTURE_2D, rc->gltex); 02981 02982 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 02983 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 02984 02985 /* set up rotation if available */ 02986 if(rc->rot_prop) { 02987 rot = RNA_property_float_get(&rc->rot_ptr, rc->rot_prop); 02988 glPushMatrix(); 02989 glRotatef(RAD2DEGF(rot), 0, 0, 1); 02990 } 02991 02992 /* draw textured quad */ 02993 glEnable(GL_TEXTURE_2D); 02994 glBegin(GL_QUADS); 02995 glTexCoord2f(0,0); 02996 glVertex2f(-radius, -radius); 02997 glTexCoord2f(1,0); 02998 glVertex2f(radius, -radius); 02999 glTexCoord2f(1,1); 03000 glVertex2f(radius, radius); 03001 glTexCoord2f(0,1); 03002 glVertex2f(-radius, radius); 03003 glEnd(); 03004 glDisable(GL_TEXTURE_2D); 03005 03006 /* undo rotation */ 03007 if(rc->rot_prop) 03008 glPopMatrix(); 03009 } 03010 else { 03011 /* flat color if no texture available */ 03012 glutil_draw_filled_arc(0, M_PI * 2, radius, 40); 03013 } 03014 } 03015 03016 static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata) 03017 { 03018 RadialControl *rc = customdata; 03019 ARegion *ar = CTX_wm_region(C); 03020 float r1=0.0f, r2=0.0f, tex_radius, alpha; 03021 float zoom[2], col[3] = {1, 1, 1}; 03022 03023 switch(rc->subtype) { 03024 case PROP_DISTANCE: 03025 r1= rc->current_value; 03026 r2= rc->initial_value; 03027 tex_radius= r1; 03028 alpha = 0.75; 03029 break; 03030 case PROP_FACTOR: 03031 r1= (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_SIZE; 03032 r2= tex_radius= WM_RADIAL_CONTROL_DISPLAY_SIZE; 03033 alpha = rc->current_value / 2.0f + 0.5f; 03034 break; 03035 case PROP_ANGLE: 03036 r1= r2= tex_radius= WM_RADIAL_CONTROL_DISPLAY_SIZE; 03037 alpha = 0.75; 03038 break; 03039 default: 03040 tex_radius= WM_RADIAL_CONTROL_DISPLAY_SIZE; /* note, this is a dummy value */ 03041 alpha = 0.75; 03042 break; 03043 } 03044 03045 /* Keep cursor in the original place */ 03046 x = rc->initial_mouse[0] - ar->winrct.xmin; 03047 y = rc->initial_mouse[1] - ar->winrct.ymin; 03048 glTranslatef((float)x, (float)y, 0.0f); 03049 03050 glEnable(GL_BLEND); 03051 glEnable(GL_LINE_SMOOTH); 03052 03053 /* apply zoom if available */ 03054 if(rc->zoom_prop) { 03055 RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); 03056 glScalef(zoom[0], zoom[1], 1); 03057 } 03058 03059 /* draw rotated texture */ 03060 radial_control_paint_tex(rc, tex_radius, alpha); 03061 03062 /* set line color */ 03063 if(rc->col_prop) 03064 RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col); 03065 glColor4f(col[0], col[1], col[2], 0.5); 03066 03067 if(rc->subtype == PROP_ANGLE) { 03068 glPushMatrix(); 03069 /* draw original angle line */ 03070 glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1); 03071 fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); 03072 /* draw new angle line */ 03073 glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1); 03074 fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); 03075 glPopMatrix(); 03076 } 03077 03078 /* draw circles on top */ 03079 glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r1, 40); 03080 glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r2, 40); 03081 03082 glDisable(GL_BLEND); 03083 glDisable(GL_LINE_SMOOTH); 03084 } 03085 03086 typedef enum { 03087 RC_PROP_ALLOW_MISSING = 1, 03088 RC_PROP_REQUIRE_FLOAT = 2, 03089 RC_PROP_REQUIRE_BOOL = 4, 03090 } RCPropFlags; 03091 03092 /* attempt to retrieve the rna pointer/property from an rna path; 03093 returns 0 for failure, 1 for success, and also 1 if property is not 03094 set */ 03095 static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op, 03096 const char *name, PointerRNA *r_ptr, 03097 PropertyRNA **r_prop, int req_length, RCPropFlags flags) 03098 { 03099 PropertyRNA *unused_prop; 03100 int len; 03101 char *str; 03102 03103 /* check flags */ 03104 if((flags & RC_PROP_REQUIRE_BOOL) && (flags & RC_PROP_REQUIRE_FLOAT)) { 03105 BKE_reportf(op->reports, RPT_ERROR, "Property can't be both boolean and float"); 03106 return 0; 03107 } 03108 03109 /* get an rna string path from the operator's properties */ 03110 if(!(str = RNA_string_get_alloc(op->ptr, name, NULL, 0))) 03111 return 1; 03112 03113 if(str[0] == '\0') { 03114 if(r_prop) *r_prop = NULL; 03115 MEM_freeN(str); 03116 return 1; 03117 } 03118 03119 if(!r_prop) 03120 r_prop = &unused_prop; 03121 03122 /* get rna from path */ 03123 if(!RNA_path_resolve(ctx_ptr, str, r_ptr, r_prop)) { 03124 MEM_freeN(str); 03125 if(flags & RC_PROP_ALLOW_MISSING) 03126 return 1; 03127 else { 03128 BKE_reportf(op->reports, RPT_ERROR, "Couldn't resolve path %s", name); 03129 return 0; 03130 } 03131 } 03132 03133 /* check property type */ 03134 if(flags & (RC_PROP_REQUIRE_BOOL | RC_PROP_REQUIRE_FLOAT)) { 03135 PropertyType prop_type = RNA_property_type(*r_prop); 03136 03137 if(((flags & RC_PROP_REQUIRE_BOOL) && (prop_type != PROP_BOOLEAN)) || 03138 ((flags & RC_PROP_REQUIRE_FLOAT) && prop_type != PROP_FLOAT)) { 03139 MEM_freeN(str); 03140 BKE_reportf(op->reports, RPT_ERROR, 03141 "Property from path %s is not a float", name); 03142 return 0; 03143 } 03144 } 03145 03146 /* check property's array length */ 03147 if(*r_prop && (len = RNA_property_array_length(r_ptr, *r_prop)) != req_length) { 03148 MEM_freeN(str); 03149 BKE_reportf(op->reports, RPT_ERROR, 03150 "Property from path %s has length %d instead of %d", 03151 name, len, req_length); 03152 return 0; 03153 } 03154 03155 /* success */ 03156 MEM_freeN(str); 03157 return 1; 03158 } 03159 03160 /* initialize the rna pointers and properties using rna paths */ 03161 static int radial_control_get_properties(bContext *C, wmOperator *op) 03162 { 03163 RadialControl *rc = op->customdata; 03164 PointerRNA ctx_ptr, use_secondary_ptr; 03165 PropertyRNA *use_secondary_prop; 03166 const char *data_path; 03167 03168 RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr); 03169 03170 /* check if we use primary or secondary path */ 03171 if(!radial_control_get_path(&ctx_ptr, op, "use_secondary", 03172 &use_secondary_ptr, &use_secondary_prop, 03173 0, (RC_PROP_ALLOW_MISSING| 03174 RC_PROP_REQUIRE_BOOL))) { 03175 return 0; 03176 } 03177 else { 03178 if(use_secondary_prop && 03179 RNA_property_boolean_get(&use_secondary_ptr, use_secondary_prop)) 03180 data_path = "data_path_secondary"; 03181 else 03182 data_path = "data_path_primary"; 03183 } 03184 03185 if(!radial_control_get_path(&ctx_ptr, op, data_path, &rc->ptr, &rc->prop, 0, 0)) 03186 return 0; 03187 03188 /* data path is required */ 03189 if(!rc->prop) 03190 return 0; 03191 03192 if(!radial_control_get_path(&ctx_ptr, op, "rotation_path", &rc->rot_ptr, &rc->rot_prop, 0, RC_PROP_REQUIRE_FLOAT)) 03193 return 0; 03194 if(!radial_control_get_path(&ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT)) 03195 return 0; 03196 if(!radial_control_get_path(&ctx_ptr, op, "fill_color_path", &rc->fill_col_ptr, &rc->fill_col_prop, 3, RC_PROP_REQUIRE_FLOAT)) 03197 return 0; 03198 03199 /* slightly ugly; allow this property to not resolve 03200 correctly. needed because 3d texture paint shares the same 03201 keymap as 2d image paint */ 03202 if(!radial_control_get_path(&ctx_ptr, op, "zoom_path", 03203 &rc->zoom_ptr, &rc->zoom_prop, 2, 03204 RC_PROP_REQUIRE_FLOAT|RC_PROP_ALLOW_MISSING)) 03205 return 0; 03206 03207 if(!radial_control_get_path(&ctx_ptr, op, "image_id", &rc->image_id_ptr, NULL, 0, 0)) 03208 return 0; 03209 else if(rc->image_id_ptr.data) { 03210 /* extra check, pointer must be to an ID */ 03211 if(!RNA_struct_is_ID(rc->image_id_ptr.type)) { 03212 BKE_report(op->reports, RPT_ERROR, 03213 "Pointer from path image_id is not an ID"); 03214 return 0; 03215 } 03216 } 03217 03218 return 1; 03219 } 03220 03221 static int radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) 03222 { 03223 wmWindowManager *wm; 03224 RadialControl *rc; 03225 int min_value_int, max_value_int, step_int; 03226 float step_float, precision; 03227 03228 if(!(op->customdata = rc = MEM_callocN(sizeof(RadialControl), "RadialControl"))) 03229 return OPERATOR_CANCELLED; 03230 03231 if(!radial_control_get_properties(C, op)) { 03232 MEM_freeN(rc); 03233 return OPERATOR_CANCELLED; 03234 } 03235 03236 /* get type, initial, min, and max values of the property */ 03237 switch((rc->type = RNA_property_type(rc->prop))) { 03238 case PROP_INT: 03239 rc->initial_value = RNA_property_int_get(&rc->ptr, rc->prop); 03240 RNA_property_int_ui_range(&rc->ptr, rc->prop, &min_value_int, 03241 &max_value_int, &step_int); 03242 rc->min_value = min_value_int; 03243 rc->max_value = max_value_int; 03244 break; 03245 case PROP_FLOAT: 03246 rc->initial_value = RNA_property_float_get(&rc->ptr, rc->prop); 03247 RNA_property_float_ui_range(&rc->ptr, rc->prop, &rc->min_value, 03248 &rc->max_value, &step_float, &precision); 03249 break; 03250 default: 03251 BKE_report(op->reports, RPT_ERROR, "Property must be an integer or a float"); 03252 MEM_freeN(rc); 03253 return OPERATOR_CANCELLED; 03254 } 03255 03256 /* get subtype of property */ 03257 rc->subtype = RNA_property_subtype(rc->prop); 03258 if(!ELEM3(rc->subtype, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE)) { 03259 BKE_report(op->reports, RPT_ERROR, "Property must be a distance, a factor, or an angle"); 03260 MEM_freeN(rc); 03261 return OPERATOR_CANCELLED; 03262 } 03263 03264 rc->current_value = rc->initial_value; 03265 radial_control_set_initial_mouse(rc, event); 03266 radial_control_set_tex(rc); 03267 03268 /* temporarily disable other paint cursors */ 03269 wm = CTX_wm_manager(C); 03270 rc->orig_paintcursors = wm->paintcursors; 03271 wm->paintcursors.first = wm->paintcursors.last = NULL; 03272 03273 /* add radial control paint cursor */ 03274 rc->cursor = WM_paint_cursor_activate(wm, op->type->poll, 03275 radial_control_paint_cursor, rc); 03276 03277 WM_event_add_modal_handler(C, op); 03278 03279 return OPERATOR_RUNNING_MODAL; 03280 } 03281 03282 static void radial_control_set_value(RadialControl *rc, float val) 03283 { 03284 switch(rc->type) { 03285 case PROP_INT: 03286 RNA_property_int_set(&rc->ptr, rc->prop, val); 03287 break; 03288 case PROP_FLOAT: 03289 RNA_property_float_set(&rc->ptr, rc->prop, val); 03290 break; 03291 default: 03292 break; 03293 } 03294 } 03295 03296 static int radial_control_cancel(bContext *C, wmOperator *op) 03297 { 03298 RadialControl *rc = op->customdata; 03299 wmWindowManager *wm = CTX_wm_manager(C); 03300 03301 WM_paint_cursor_end(wm, rc->cursor); 03302 03303 /* restore original paint cursors */ 03304 wm->paintcursors = rc->orig_paintcursors; 03305 03306 /* not sure if this is a good notifier to use; 03307 intended purpose is to update the UI so that the 03308 new value is displayed in sliders/numfields */ 03309 WM_event_add_notifier(C, NC_WINDOW, NULL); 03310 03311 glDeleteTextures(1, &rc->gltex); 03312 03313 MEM_freeN(rc); 03314 03315 return OPERATOR_CANCELLED; 03316 } 03317 03318 static int radial_control_modal(bContext *C, wmOperator *op, wmEvent *event) 03319 { 03320 RadialControl *rc = op->customdata; 03321 float new_value, dist, zoom[2]; 03322 float delta[2], snap, ret = OPERATOR_RUNNING_MODAL; 03323 03324 /* TODO: fix hardcoded events */ 03325 03326 snap = event->ctrl; 03327 03328 switch(event->type) { 03329 case MOUSEMOVE: 03330 delta[0]= rc->initial_mouse[0] - event->x; 03331 delta[1]= rc->initial_mouse[1] - event->y; 03332 03333 if(rc->zoom_prop) { 03334 RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); 03335 delta[0] /= zoom[0]; 03336 delta[1] /= zoom[1]; 03337 } 03338 03339 dist= sqrt(delta[0]*delta[0]+delta[1]*delta[1]); 03340 03341 /* calculate new value and apply snapping */ 03342 switch(rc->subtype) { 03343 case PROP_DISTANCE: 03344 new_value = dist; 03345 if(snap) new_value = ((int)new_value + 5) / 10*10; 03346 break; 03347 case PROP_FACTOR: 03348 new_value = 1 - dist / WM_RADIAL_CONTROL_DISPLAY_SIZE; 03349 if(snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; 03350 break; 03351 case PROP_ANGLE: 03352 new_value = atan2(delta[1], delta[0]) + M_PI; 03353 if(snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10*10); 03354 break; 03355 default: 03356 new_value = dist; /* dummy value, should this ever happen? - campbell */ 03357 break; 03358 } 03359 03360 /* clamp and update */ 03361 CLAMP(new_value, rc->min_value, rc->max_value); 03362 radial_control_set_value(rc, new_value); 03363 rc->current_value = new_value; 03364 break; 03365 03366 case ESCKEY: 03367 case RIGHTMOUSE: 03368 /* cancelled; restore original value */ 03369 radial_control_set_value(rc, rc->initial_value); 03370 ret = OPERATOR_CANCELLED; 03371 break; 03372 03373 case LEFTMOUSE: 03374 case PADENTER: 03375 /* done; value already set */ 03376 ret = OPERATOR_FINISHED; 03377 break; 03378 } 03379 03380 ED_region_tag_redraw(CTX_wm_region(C)); 03381 03382 if(ret != OPERATOR_RUNNING_MODAL) 03383 radial_control_cancel(C, op); 03384 03385 return ret; 03386 } 03387 03388 static void WM_OT_radial_control(wmOperatorType *ot) 03389 { 03390 ot->name= "Radial Control"; 03391 ot->idname= "WM_OT_radial_control"; 03392 03393 ot->invoke= radial_control_invoke; 03394 ot->modal= radial_control_modal; 03395 ot->cancel= radial_control_cancel; 03396 03397 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 03398 03399 /* all paths relative to the context */ 03400 RNA_def_string(ot->srna, "data_path_primary", "", 0, "Primary Data Path", "Primary path of property to be set by the radial control"); 03401 RNA_def_string(ot->srna, "data_path_secondary", "", 0, "Secondary Data Path", "Secondary path of property to be set by the radial control"); 03402 RNA_def_string(ot->srna, "use_secondary", "", 0, "Use Secondary", "Path of property to select between the primary and secondary data paths"); 03403 RNA_def_string(ot->srna, "rotation_path", "", 0, "Rotation Path", "Path of property used to rotate the texture display"); 03404 RNA_def_string(ot->srna, "color_path", "", 0, "Color Path", "Path of property used to set the color of the control"); 03405 RNA_def_string(ot->srna, "fill_color_path", "", 0, "Fill Color Path", "Path of property used to set the fill color of the control"); 03406 RNA_def_string(ot->srna, "zoom_path", "", 0, "Zoom Path", "Path of property used to set the zoom level for the control"); 03407 RNA_def_string(ot->srna, "image_id", "", 0, "Image ID", "Path of ID that is used to generate an image for the control"); 03408 } 03409 03410 /* ************************** timer for testing ***************** */ 03411 03412 /* uses no type defines, fully local testing function anyway... ;) */ 03413 03414 static void redraw_timer_window_swap(bContext *C) 03415 { 03416 wmWindow *win= CTX_wm_window(C); 03417 ScrArea *sa; 03418 03419 for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) 03420 ED_area_tag_redraw(sa); 03421 wm_draw_update(C); 03422 03423 CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ 03424 } 03425 03426 static EnumPropertyItem redraw_timer_type_items[] = { 03427 {0, "DRAW", 0, "Draw Region", "Draw Region"}, 03428 {1, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"}, 03429 {2, "DRAW_WIN", 0, "Draw Window", "Draw Window"}, 03430 {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"}, 03431 {4, "ANIM_STEP", 0, "Anim Step", "Animation Steps"}, 03432 {5, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"}, 03433 {6, "UNDO", 0, "Undo/Redo", "Undo/Redo"}, 03434 {0, NULL, 0, NULL, NULL}}; 03435 03436 static int redraw_timer_exec(bContext *C, wmOperator *op) 03437 { 03438 ARegion *ar= CTX_wm_region(C); 03439 double stime= PIL_check_seconds_timer(); 03440 int type = RNA_enum_get(op->ptr, "type"); 03441 int iter = RNA_int_get(op->ptr, "iterations"); 03442 int a; 03443 float time; 03444 const char *infostr= ""; 03445 03446 WM_cursor_wait(1); 03447 03448 for(a=0; a<iter; a++) { 03449 if (type==0) { 03450 if(ar) 03451 ED_region_do_draw(C, ar); 03452 } 03453 else if (type==1) { 03454 wmWindow *win= CTX_wm_window(C); 03455 03456 ED_region_tag_redraw(ar); 03457 wm_draw_update(C); 03458 03459 CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ 03460 } 03461 else if (type==2) { 03462 wmWindow *win= CTX_wm_window(C); 03463 ScrArea *sa; 03464 03465 ScrArea *sa_back= CTX_wm_area(C); 03466 ARegion *ar_back= CTX_wm_region(C); 03467 03468 for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) { 03469 ARegion *ar_iter; 03470 CTX_wm_area_set(C, sa); 03471 03472 for(ar_iter= sa->regionbase.first; ar_iter; ar_iter= ar_iter->next) { 03473 if(ar_iter->swinid) { 03474 CTX_wm_region_set(C, ar_iter); 03475 ED_region_do_draw(C, ar_iter); 03476 } 03477 } 03478 } 03479 03480 CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ 03481 03482 CTX_wm_area_set(C, sa_back); 03483 CTX_wm_region_set(C, ar_back); 03484 } 03485 else if (type==3) { 03486 redraw_timer_window_swap(C); 03487 } 03488 else if (type==4) { 03489 Main *bmain= CTX_data_main(C); 03490 Scene *scene= CTX_data_scene(C); 03491 03492 if(a & 1) scene->r.cfra--; 03493 else scene->r.cfra++; 03494 scene_update_for_newframe(bmain, scene, scene->lay); 03495 } 03496 else if (type==5) { 03497 03498 /* play anim, return on same frame as started with */ 03499 Main *bmain= CTX_data_main(C); 03500 Scene *scene= CTX_data_scene(C); 03501 int tot= (scene->r.efra - scene->r.sfra) + 1; 03502 03503 while(tot--) { 03504 /* todo, ability to escape! */ 03505 scene->r.cfra++; 03506 if(scene->r.cfra > scene->r.efra) 03507 scene->r.cfra= scene->r.sfra; 03508 03509 scene_update_for_newframe(bmain, scene, scene->lay); 03510 redraw_timer_window_swap(C); 03511 } 03512 } 03513 else { /* 6 */ 03514 ED_undo_pop(C); 03515 ED_undo_redo(C); 03516 } 03517 } 03518 03519 time= (float)((PIL_check_seconds_timer()-stime)*1000); 03520 03521 RNA_enum_description(redraw_timer_type_items, type, &infostr); 03522 03523 WM_cursor_wait(0); 03524 03525 BKE_reportf(op->reports, RPT_WARNING, "%d x %s: %.2f ms, average: %.4f", iter, infostr, time, time/iter); 03526 03527 return OPERATOR_FINISHED; 03528 } 03529 03530 static void WM_OT_redraw_timer(wmOperatorType *ot) 03531 { 03532 ot->name= "Redraw Timer"; 03533 ot->idname= "WM_OT_redraw_timer"; 03534 ot->description="Simple redraw timer to test the speed of updating the interface"; 03535 03536 ot->invoke= WM_menu_invoke; 03537 ot->exec= redraw_timer_exec; 03538 ot->poll= WM_operator_winactive; 03539 03540 ot->prop= RNA_def_enum(ot->srna, "type", redraw_timer_type_items, 0, "Type", ""); 03541 RNA_def_int(ot->srna, "iterations", 10, 1,INT_MAX, "Iterations", "Number of times to redraw", 1,1000); 03542 03543 } 03544 03545 /* ************************** memory statistics for testing ***************** */ 03546 03547 static int memory_statistics_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) 03548 { 03549 MEM_printmemlist_stats(); 03550 return OPERATOR_FINISHED; 03551 } 03552 03553 static void WM_OT_memory_statistics(wmOperatorType *ot) 03554 { 03555 ot->name= "Memory Statistics"; 03556 ot->idname= "WM_OT_memory_statistics"; 03557 ot->description= "Print memory statistics to the console"; 03558 03559 ot->exec= memory_statistics_exec; 03560 } 03561 03562 /* ************************** memory statistics for testing ***************** */ 03563 03564 static int dependency_relations_exec(bContext *C, wmOperator *UNUSED(op)) 03565 { 03566 Main *bmain= CTX_data_main(C); 03567 Scene *scene= CTX_data_scene(C); 03568 Object *ob= CTX_data_active_object(C); 03569 03570 DAG_print_dependencies(bmain, scene, ob); 03571 03572 return OPERATOR_FINISHED; 03573 } 03574 03575 static void WM_OT_dependency_relations(wmOperatorType *ot) 03576 { 03577 ot->name= "Dependency Relations"; 03578 ot->idname= "WM_OT_dependency_relations"; 03579 ot->description= "Print dependency graph relations to the console"; 03580 03581 ot->exec= dependency_relations_exec; 03582 } 03583 03584 /* ******************************************************* */ 03585 03586 static int wm_ndof_sensitivity_exec(bContext *UNUSED(C), wmOperator *op) 03587 { 03588 const float min = 0.25f, max = 4.f; // TODO: get these from RNA property 03589 float change; 03590 float sensitivity = U.ndof_sensitivity; 03591 03592 if(RNA_boolean_get(op->ptr, "fast")) 03593 change = 0.5f; // 50% change 03594 else 03595 change = 0.1f; // 10% 03596 03597 if(RNA_boolean_get(op->ptr, "decrease")) { 03598 sensitivity -= sensitivity * change; 03599 if (sensitivity < min) 03600 sensitivity = min; 03601 } 03602 else { 03603 sensitivity += sensitivity * change; 03604 if (sensitivity > max) 03605 sensitivity = max; 03606 } 03607 03608 if (sensitivity != U.ndof_sensitivity) { 03609 U.ndof_sensitivity = sensitivity; 03610 } 03611 03612 return OPERATOR_FINISHED; 03613 } 03614 03615 static void WM_OT_ndof_sensitivity_change(wmOperatorType *ot) 03616 { 03617 ot->name= "Change NDOF sensitivity"; 03618 ot->idname= "WM_OT_ndof_sensitivity_change"; 03619 ot->description="Change NDOF sensitivity"; 03620 03621 ot->exec= wm_ndof_sensitivity_exec; 03622 03623 RNA_def_boolean(ot->srna, "decrease", 1, "Decrease NDOF sensitivity", "If true then action decreases NDOF sensitivity instead of increasing"); 03624 RNA_def_boolean(ot->srna, "fast", 0, "Fast NDOF sensitivity change", "If true then sensitivity changes 50%, otherwise 10%"); 03625 } 03626 03627 03628 static void operatortype_ghash_free_cb(wmOperatorType *ot) 03629 { 03630 if(ot->macro.first) 03631 wm_operatortype_free_macro(ot); 03632 03633 if(ot->ext.srna) /* python operator, allocs own string */ 03634 MEM_freeN((void *)ot->idname); 03635 03636 MEM_freeN(ot); 03637 } 03638 03639 /* ******************************************************* */ 03640 /* called on initialize WM_exit() */ 03641 void wm_operatortype_free(void) 03642 { 03643 BLI_ghash_free(global_ops_hash, NULL, (GHashValFreeFP)operatortype_ghash_free_cb); 03644 global_ops_hash= NULL; 03645 } 03646 03647 /* called on initialize WM_init() */ 03648 void wm_operatortype_init(void) 03649 { 03650 global_ops_hash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "wm_operatortype_init gh"); 03651 03652 WM_operatortype_append(WM_OT_window_duplicate); 03653 WM_operatortype_append(WM_OT_read_homefile); 03654 WM_operatortype_append(WM_OT_read_factory_settings); 03655 WM_operatortype_append(WM_OT_save_homefile); 03656 WM_operatortype_append(WM_OT_window_fullscreen_toggle); 03657 WM_operatortype_append(WM_OT_quit_blender); 03658 WM_operatortype_append(WM_OT_open_mainfile); 03659 WM_operatortype_append(WM_OT_link_append); 03660 WM_operatortype_append(WM_OT_recover_last_session); 03661 WM_operatortype_append(WM_OT_recover_auto_save); 03662 WM_operatortype_append(WM_OT_save_as_mainfile); 03663 WM_operatortype_append(WM_OT_save_mainfile); 03664 WM_operatortype_append(WM_OT_redraw_timer); 03665 WM_operatortype_append(WM_OT_memory_statistics); 03666 WM_operatortype_append(WM_OT_dependency_relations); 03667 WM_operatortype_append(WM_OT_debug_menu); 03668 WM_operatortype_append(WM_OT_splash); 03669 WM_operatortype_append(WM_OT_search_menu); 03670 WM_operatortype_append(WM_OT_call_menu); 03671 WM_operatortype_append(WM_OT_radial_control); 03672 WM_operatortype_append(WM_OT_ndof_sensitivity_change); 03673 #if defined(WIN32) 03674 WM_operatortype_append(WM_OT_console_toggle); 03675 #endif 03676 03677 #ifdef WITH_COLLADA 03678 /* XXX: move these */ 03679 WM_operatortype_append(WM_OT_collada_export); 03680 WM_operatortype_append(WM_OT_collada_import); 03681 #endif 03682 } 03683 03684 /* circleselect-like modal operators */ 03685 static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) 03686 { 03687 static EnumPropertyItem modal_items[] = { 03688 {GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 03689 {GESTURE_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, 03690 {GESTURE_MODAL_CIRCLE_ADD, "ADD", 0, "Add", ""}, 03691 {GESTURE_MODAL_CIRCLE_SUB, "SUBTRACT", 0, "Subtract", ""}, 03692 03693 {GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""}, 03694 {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""}, 03695 {GESTURE_MODAL_NOP,"NOP", 0, "No Operation", ""}, 03696 03697 03698 {0, NULL, 0, NULL, NULL}}; 03699 03700 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Gesture Circle"); 03701 03702 /* this function is called for each spacetype, only needs to add map once */ 03703 if(keymap) return; 03704 03705 keymap= WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items); 03706 03707 /* items for modal map */ 03708 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03709 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03710 03711 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CONFIRM); 03712 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, 0, 0, GESTURE_MODAL_CONFIRM); 03713 03714 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_SELECT); 03715 03716 #if 0 // Durien guys like this :S 03717 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_DESELECT); 03718 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_NOP); 03719 #else 03720 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_DESELECT); // default 2.4x 03721 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); // default 2.4x 03722 #endif 03723 03724 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); 03725 03726 WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB); 03727 WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB); 03728 WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD); 03729 WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD); 03730 03731 /* assign map to operators */ 03732 WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle"); 03733 WM_modalkeymap_assign(keymap, "UV_OT_circle_select"); 03734 WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle"); 03735 03736 } 03737 03738 /* straight line modal operators */ 03739 static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) 03740 { 03741 static EnumPropertyItem modal_items[] = { 03742 {GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 03743 {GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""}, 03744 {GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""}, 03745 {0, NULL, 0, NULL, NULL}}; 03746 03747 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Straight Line"); 03748 03749 /* this function is called for each spacetype, only needs to add map once */ 03750 if(keymap) return; 03751 03752 keymap= WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items); 03753 03754 /* items for modal map */ 03755 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03756 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03757 03758 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); 03759 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_SELECT); 03760 03761 /* assign map to operators */ 03762 WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line"); 03763 } 03764 03765 03766 /* borderselect-like modal operators */ 03767 static void gesture_border_modal_keymap(wmKeyConfig *keyconf) 03768 { 03769 static EnumPropertyItem modal_items[] = { 03770 {GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 03771 {GESTURE_MODAL_SELECT, "SELECT", 0, "Select", ""}, 03772 {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""}, 03773 {GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""}, 03774 {0, NULL, 0, NULL, NULL}}; 03775 03776 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Border"); 03777 03778 /* this function is called for each spacetype, only needs to add map once */ 03779 if(keymap) return; 03780 03781 keymap= WM_modalkeymap_add(keyconf, "Gesture Border", modal_items); 03782 03783 /* items for modal map */ 03784 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03785 /* Note: cancel only on press otherwise you cannot map this to RMB-gesture */ 03786 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03787 03788 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); 03789 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); 03790 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); 03791 03792 #if 0 // Durian guys like this 03793 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_BEGIN); 03794 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_DESELECT); 03795 #else 03796 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); 03797 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT); 03798 #endif 03799 03800 /* assign map to operators */ 03801 WM_modalkeymap_assign(keymap, "ACTION_OT_select_border"); 03802 WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border"); 03803 WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set"); 03804 WM_modalkeymap_assign(keymap, "INFO_OT_select_border"); 03805 WM_modalkeymap_assign(keymap, "FILE_OT_select_border"); 03806 WM_modalkeymap_assign(keymap, "GRAPH_OT_select_border"); 03807 WM_modalkeymap_assign(keymap, "MARKER_OT_select_border"); 03808 WM_modalkeymap_assign(keymap, "NLA_OT_select_border"); 03809 WM_modalkeymap_assign(keymap, "NODE_OT_select_border"); 03810 // WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template 03811 WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border"); 03812 WM_modalkeymap_assign(keymap, "SEQUENCER_OT_view_ghost_border"); 03813 WM_modalkeymap_assign(keymap, "UV_OT_select_border"); 03814 WM_modalkeymap_assign(keymap, "CLIP_OT_select_border"); 03815 WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border"); 03816 WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border"); 03817 WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border"); 03818 WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border"); 03819 WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); // XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel 03820 } 03821 03822 /* zoom to border modal operators */ 03823 static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf) 03824 { 03825 static EnumPropertyItem modal_items[] = { 03826 {GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 03827 {GESTURE_MODAL_IN, "IN", 0, "In", ""}, 03828 {GESTURE_MODAL_OUT, "OUT", 0, "Out", ""}, 03829 {GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""}, 03830 {0, NULL, 0, NULL, NULL}}; 03831 03832 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Zoom Border"); 03833 03834 /* this function is called for each spacetype, only needs to add map once */ 03835 if(keymap) return; 03836 03837 keymap= WM_modalkeymap_add(keyconf, "Gesture Zoom Border", modal_items); 03838 03839 /* items for modal map */ 03840 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03841 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); 03842 03843 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); 03844 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN); 03845 03846 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); 03847 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_OUT); 03848 03849 /* assign map to operators */ 03850 WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border"); 03851 WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); 03852 } 03853 03854 /* default keymap for windows and screens, only call once per WM */ 03855 void wm_window_keymap(wmKeyConfig *keyconf) 03856 { 03857 wmKeyMap *keymap= WM_keymap_find(keyconf, "Window", 0, 0); 03858 wmKeyMapItem *kmi; 03859 03860 /* note, this doesn't replace existing keymap items */ 03861 WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); 03862 #ifdef __APPLE__ 03863 WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_OSKEY, 0); 03864 WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0); 03865 WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_OSKEY, 0); 03866 WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_OSKEY, 0); 03867 WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0); 03868 WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_OSKEY, 0); 03869 #endif 03870 WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0); 03871 WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); 03872 WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); 03873 WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0); 03874 WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0); 03875 WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); 03876 kmi= WM_keymap_add_item(keymap, "WM_OT_link_append", F1KEY, KM_PRESS, KM_SHIFT, 0); 03877 RNA_boolean_set(kmi->ptr, "link", FALSE); 03878 RNA_boolean_set(kmi->ptr, "instance_groups", FALSE); 03879 03880 WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0); 03881 WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0); 03882 WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); 03883 WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", F2KEY, KM_PRESS, 0, 0); 03884 kmi= WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); 03885 RNA_boolean_set(kmi->ptr, "copy", TRUE); 03886 03887 WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0); 03888 WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0); 03889 03890 /* debug/testing */ 03891 WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); 03892 WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0); 03893 03894 /* menus that can be accessed anywhere in blender */ 03895 WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0); 03896 WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0); 03897 03898 /* Space switching */ 03899 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */ 03900 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03901 RNA_string_set(kmi->ptr, "value", "LOGIC_EDITOR"); 03902 03903 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F3KEY, KM_PRESS, KM_SHIFT, 0); 03904 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03905 RNA_string_set(kmi->ptr, "value", "NODE_EDITOR"); 03906 03907 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F4KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was data browser */ 03908 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03909 RNA_string_set(kmi->ptr, "value", "CONSOLE"); 03910 03911 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F5KEY, KM_PRESS, KM_SHIFT, 0); 03912 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03913 RNA_string_set(kmi->ptr, "value", "VIEW_3D"); 03914 03915 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F6KEY, KM_PRESS, KM_SHIFT, 0); 03916 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03917 RNA_string_set(kmi->ptr, "value", "GRAPH_EDITOR"); 03918 03919 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F7KEY, KM_PRESS, KM_SHIFT, 0); 03920 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03921 RNA_string_set(kmi->ptr, "value", "PROPERTIES"); 03922 03923 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F8KEY, KM_PRESS, KM_SHIFT, 0); 03924 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03925 RNA_string_set(kmi->ptr, "value", "SEQUENCE_EDITOR"); 03926 03927 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F9KEY, KM_PRESS, KM_SHIFT, 0); 03928 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03929 RNA_string_set(kmi->ptr, "value", "OUTLINER"); 03930 03931 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F10KEY, KM_PRESS, KM_SHIFT, 0); 03932 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03933 RNA_string_set(kmi->ptr, "value", "IMAGE_EDITOR"); 03934 03935 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F11KEY, KM_PRESS, KM_SHIFT, 0); 03936 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03937 RNA_string_set(kmi->ptr, "value", "TEXT_EDITOR"); 03938 03939 kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0); 03940 RNA_string_set(kmi->ptr, "data_path", "area.type"); 03941 RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR"); 03942 03943 /* ndof speed */ 03944 kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, 0, 0); 03945 RNA_boolean_set(kmi->ptr, "decrease", FALSE); 03946 RNA_boolean_set(kmi->ptr, "fast", FALSE); 03947 03948 kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, 0, 0); 03949 RNA_boolean_set(kmi->ptr, "decrease", TRUE); 03950 RNA_boolean_set(kmi->ptr, "fast", FALSE); 03951 03952 kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, KM_SHIFT, 0); 03953 RNA_boolean_set(kmi->ptr, "decrease", FALSE); 03954 RNA_boolean_set(kmi->ptr, "fast", TRUE); 03955 03956 kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, KM_SHIFT, 0); 03957 RNA_boolean_set(kmi->ptr, "decrease", TRUE); 03958 RNA_boolean_set(kmi->ptr, "fast", TRUE); 03959 03960 gesture_circle_modal_keymap(keyconf); 03961 gesture_border_modal_keymap(keyconf); 03962 gesture_zoom_border_modal_keymap(keyconf); 03963 gesture_straightline_modal_keymap(keyconf); 03964 } 03965 03966 /* Generic itemf's for operators that take library args */ 03967 static EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), int *do_free, ID *id, int local) 03968 { 03969 EnumPropertyItem item_tmp= {0}, *item= NULL; 03970 int totitem= 0; 03971 int i= 0; 03972 03973 for( ; id; id= id->next) { 03974 if(local==FALSE || id->lib==NULL) { 03975 item_tmp.identifier= item_tmp.name= id->name+2; 03976 item_tmp.value= i++; 03977 RNA_enum_item_add(&item, &totitem, &item_tmp); 03978 } 03979 } 03980 03981 RNA_enum_item_end(&item, &totitem); 03982 *do_free= 1; 03983 03984 return item; 03985 } 03986 03987 /* can add more as needed */ 03988 EnumPropertyItem *RNA_action_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 03989 { 03990 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->action.first : NULL, FALSE); 03991 } 03992 EnumPropertyItem *RNA_action_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 03993 { 03994 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->action.first : NULL, TRUE); 03995 } 03996 03997 EnumPropertyItem *RNA_group_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 03998 { 03999 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, FALSE); 04000 } 04001 EnumPropertyItem *RNA_group_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 04002 { 04003 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, TRUE); 04004 } 04005 04006 EnumPropertyItem *RNA_image_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 04007 { 04008 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->image.first : NULL, FALSE); 04009 } 04010 EnumPropertyItem *RNA_image_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 04011 { 04012 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->image.first : NULL, TRUE); 04013 } 04014 04015 EnumPropertyItem *RNA_scene_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 04016 { 04017 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->scene.first : NULL, FALSE); 04018 } 04019 EnumPropertyItem *RNA_scene_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *do_free) 04020 { 04021 return rna_id_itemf(C, ptr, do_free, C ? (ID *)CTX_data_main(C)->scene.first : NULL, TRUE); 04022 }