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