fix for error in last commit - don't overwrite options in the new operator which...
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index 074151c9abe52300716214735a951e6be2738c66..079833f693ff3362a61fac85f13126ca4658fed9 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +31,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <math.h>
 
 #include "DNA_listBase.h"
 #include "DNA_screen_types.h"
@@ -47,6 +44,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
+#include "BLI_math.h"
 
 #include "BKE_blender.h"
 #include "BKE_context.h"
@@ -61,6 +59,7 @@
 
 #include "ED_fileselect.h"
 #include "ED_info.h"
+#include "ED_render.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
 #include "ED_util.h"
 #include "wm_event_types.h"
 #include "wm_draw.h"
 
+#ifndef NDEBUG
+#  include "RNA_enum_types.h"
+#endif
+
 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only);
 
 /* ************ event management ************** */
@@ -183,7 +186,7 @@ void wm_event_do_notifiers(bContext *C)
        wmWindowManager *wm= CTX_wm_manager(C);
        wmNotifier *note, *next;
        wmWindow *win;
-       unsigned int win_combine_v3d_datamask= 0;
+       uint64_t win_combine_v3d_datamask= 0;
        
        if(wm==NULL)
                return;
@@ -222,20 +225,8 @@ void wm_event_do_notifiers(bContext *C)
 
                        if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
                                if(note->category==NC_SCENE) {
-                                       if(note->data==ND_SCENEBROWSE) {
-                                               ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene set %p\n", note->reference);
-                                       }
-                                       else if(note->data==ND_FRAME)
+                                       if(note->data==ND_FRAME)
                                                do_anim= 1;
-                                       
-                                       if(note->action == NA_REMOVED) {
-                                               ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene delete %p\n", note->reference);
-                                       }
-                                               
                                }
                        }
                        if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
@@ -291,7 +282,7 @@ void wm_event_do_notifiers(bContext *C)
        
        /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
        for(win= wm->windows.first; win; win= win->next) {
-               win_combine_v3d_datamask |= ED_viewedit_datamask(win->screen);
+               win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
        }
 
        /* cached: editor refresh callbacks now, they get context */
@@ -309,6 +300,7 @@ void wm_event_do_notifiers(bContext *C)
                /* XXX make lock in future, or separated derivedmesh users in scene */
                if(!G.rendering) {
                        /* depsgraph & animation: update tagged datablocks */
+                       Main *bmain = CTX_data_main(C);
 
                        /* copied to set's in scene_update_tagged_recursive() */
                        win->screen->scene->customdata_mask= win_combine_v3d_datamask;
@@ -316,7 +308,7 @@ void wm_event_do_notifiers(bContext *C)
                        /* XXX, hack so operators can enforce datamasks [#26482], gl render */
                        win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
 
-                       scene_update_tagged(CTX_data_main(C), win->screen->scene);
+                       scene_update_tagged(bmain, win->screen->scene);
                }
        }
 
@@ -435,6 +427,36 @@ static void wm_operator_print(bContext *C, wmOperator *op)
        MEM_freeN(buf);
 }
 
+/* for debugging only, getting inspecting events manually is tedious */
+#ifndef NDEBUG
+
+void WM_event_print(wmEvent *event)
+{
+       if(event) {
+               const char *unknown= "UNKNOWN";
+               const char *type_id= unknown;
+               const char *val_id= unknown;
+
+               RNA_enum_identifier(event_type_items, event->type, &type_id);
+               RNA_enum_identifier(event_value_items, event->val, &val_id);
+
+               printf("wmEvent - type:%d/%s, val:%d/%s, "
+                      "shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, "
+                      "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', "
+                      "keymap_idname:%s, pointer:%p\n",
+                      event->type, type_id, event->val, val_id,
+                      event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
+                      event->x, event->y, event->ascii,
+                      BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
+                      event->keymap_idname, (void *)event);
+       }
+       else {
+               printf("wmEvent - NULL\n");
+       }
+}
+
+#endif /* NDEBUG */
+
 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup)
 {
        if(popup) {
@@ -563,12 +585,36 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        
 }
 
-/* for running operators with frozen context (modal handlers, menus) */
+/* simply calls exec with basic checks */
+static int wm_operator_exec_notest(bContext *C, wmOperator *op)
+{
+       int retval= OPERATOR_CANCELLED;
+
+       if(op==NULL || op->type==NULL || op->type->exec==NULL)
+               return retval;
+
+       retval= op->type->exec(C, op);
+       OPERATOR_RETVAL_CHECK(retval);
+
+       return retval;
+}
+
+/* for running operators with frozen context (modal handlers, menus)
+ *
+ * warning: do not use this within an operator to call its self! [#29537] */
 int WM_operator_call(bContext *C, wmOperator *op)
 {
        return wm_operator_exec(C, op, 0);
 }
 
+/* this is intended to be used when an invoke operator wants to call exec on its self
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invokle will take care of that */
+int WM_operator_call_notest(bContext *C, wmOperator *op)
+{
+       return wm_operator_exec_notest(C, op);
+}
+
 /* do this operator again, put here so it can share above code */
 int WM_operator_repeat(bContext *C, wmOperator *op)
 {
@@ -598,7 +644,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
        }
        else {
                IDPropertyTemplate val = {0};
-               op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
+               op->properties= IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
        }
        RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
 
@@ -683,6 +729,47 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
        }
 }
 
+static int wm_operator_init_from_last(wmWindowManager *wm, wmOperator *op)
+{
+       int change= FALSE;
+       wmOperator *lastop;
+
+       for(lastop= wm->operators.last; lastop; lastop= lastop->prev) {
+               /* equality check is a bit paranoid but just incase */
+               if((op != lastop) && (op->type == (lastop->type))) {
+                       break;
+               }
+       }
+
+       if (lastop && op != lastop) {
+               PropertyRNA *iterprop;
+               iterprop= RNA_struct_iterator_property(op->type->srna);
+
+               RNA_PROP_BEGIN(op->ptr, itemptr, iterprop) {
+                       PropertyRNA *prop= itemptr.data;
+                       if((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+                               if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
+                                       const char *identifier= RNA_property_identifier(prop);
+                                       IDProperty *idp_src= IDP_GetPropertyFromGroup(lastop->properties, identifier);
+                                       if(idp_src) {
+                                               IDProperty *idp_dst = IDP_CopyProperty(idp_src);
+
+                                               /* note - in the future this may need to be done recursively,
+                                                * but for now RNA doesn't access nested operators */
+                                               idp_dst->flag |= IDP_FLAG_GHOST;
+
+                                               IDP_ReplaceInGroup(op->properties, idp_dst);
+                                               change= TRUE;
+                                       }
+                               }
+                       }
+               }
+               RNA_PROP_END;
+       }
+
+       return change;
+}
+
 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
@@ -695,6 +782,11 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        if(WM_operator_poll(C, ot)) {
                wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
                
+               /* initialize setting from previous run */
+               if(wm->op_undo_depth == 0 && (ot->flag & OPTYPE_REGISTER)) { /* not called by py script */
+                       wm_operator_init_from_last(wm, op);
+               }
+
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
                        printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
                
@@ -1146,7 +1238,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
 
        /* the matching rules */
        if(kmitype==KM_TEXTINPUT)
-               if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
+               if(ISTEXTINPUT(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1;
        if(kmitype!=KM_ANY)
                if(winevent->type!=kmitype) return 0;
        
@@ -1921,8 +2013,9 @@ void wm_event_do_handlers(bContext *C)
                                        win->eventstate->prevy= event->y;
                                        //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
                                }
-                               else
-                                       ;//printf("not setting prev to %d %d\n", event->x, event->y);
+                               else {
+                                       //printf("not setting prev to %d %d\n", event->x, event->y);
+                               }
                        }
                        
                        /* store last event for this window */
@@ -2578,38 +2671,52 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                        GHOST_TEventKeyData *kd= customdata;
                        event.type= convert_key(kd->key);
                        event.ascii= kd->ascii;
+                       memcpy(event.utf8_buf, kd->utf8_buf,sizeof(event.utf8_buf));/* might be not null terminated*/
                        event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
                        
                        /* exclude arrow keys, esc, etc from text input */
-                       if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
+                       if(type==GHOST_kEventKeyUp) {
                                event.ascii= '\0';
-                       
-                       /* modifiers */
-                       if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
-                               event.shift= evt->shift= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
-                                  event.shift= evt->shift = 3;         // define?
-                       } 
-                       else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
-                               event.ctrl= evt->ctrl= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
-                                  event.ctrl= evt->ctrl = 3;           // define?
-                       } 
-                       else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
-                               event.alt= evt->alt= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
-                                  event.alt= evt->alt = 3;             // define?
-                       } 
-                       else if (event.type==OSKEY) {
-                               event.oskey= evt->oskey= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
-                                  event.oskey= evt->oskey = 3;         // define?
+
+                               /* ghost should do this already for key up */
+                               if (event.utf8_buf[0]) {
+                                       printf("%s: ghost on your platform is misbehaving, utf8 events on key up!\n", __func__);
+                               }
+                               event.utf8_buf[0]= '\0';
                        }
-                       else {
+                       else if (event.ascii<32 && event.ascii > 0) {
+                               event.ascii= '\0';
+                               /* TODO. should this also zero utf8?, dont for now, campbell */
+                       }
+
+                       if (event.utf8_buf[0]) {
+                               if (BLI_str_utf8_size(event.utf8_buf) == -1) {
+                                       printf("%s: ghost detected an invalid unicode character '%d'!\n", __func__, (int)(unsigned char)event.utf8_buf[0]);
+                                       event.utf8_buf[0]= '\0';
+                               }
+                       }
+
+                       /* modifiers */
+                       /* assigning both first and second is strange - campbell */
+                       switch(event.type) {
+                       case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
+                               event.shift= evt->shift= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTCTRLKEY: case RIGHTCTRLKEY:
+                               event.ctrl= evt->ctrl= (event.val==KM_PRESS) ? ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTALTKEY: case RIGHTALTKEY:
+                               event.alt= evt->alt= (event.val==KM_PRESS) ? ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case OSKEY:
+                               event.oskey= evt->oskey= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       default:
                                if(event.val==KM_PRESS && event.keymodifier==0)
                                        evt->keymodifier= event.type; /* only set in eventstate, for next event */
                                else if(event.val==KM_RELEASE && event.keymodifier==event.type)
                                        event.keymodifier= evt->keymodifier= 0;
+                               break;
                        }
 
                        /* this case happens on some systems that on holding a key pressed,
@@ -2618,6 +2725,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                           key we don't want the key modifier */
                        if(event.keymodifier == event.type)
                                event.keymodifier= 0;
+                       /* this case happened with an external numpad, it's not really clear
+                          why, but it's also impossible to map a key modifier to an unknwon
+                          key, so it shouldn't harm */
+                       if(event.keymodifier == UNKNOWNKEY)
+                               event.keymodifier= 0;
                        
                        /* if test_break set, it catches this. XXX Keep global for now? */
                        if(event.type==ESCKEY)
@@ -2695,4 +2807,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                }
 
        }
+
+       /* Handy when debugging checking events */
+       /* WM_event_print(&event); */
+
 }