Blender V2.61 - r43446

wm_operators.c

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