Fix #20327: uv smart project options can't be tweaked.
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 29 Jan 2010 13:06:50 +0000 (13:06 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 29 Jan 2010 13:06:50 +0000 (13:06 +0000)
Python operators calling C operators would get too many undo pushes,
causing redo of the python operator not to work. Now the depth of
operator callbacks is counted to detected nested calls, and in that
case skip the undo/register here, and only do a single undo/register
for the mother operator.

source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/windowmanager/intern/wm_event_system.c

index b0e68c81c73642a30091741f394484b48651f828..26492ed490c4d8d93e09f249e2f49a306a3c2b26 100644 (file)
@@ -4540,6 +4540,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
        
        wm->windrawable= NULL;
        wm->initialized= 0;
        
        wm->windrawable= NULL;
        wm->initialized= 0;
+       wm->op_undo_depth= 0;
 }
 
 static void lib_link_windowmanager(FileData *fd, Main *main)
 }
 
 static void lib_link_windowmanager(FileData *fd, Main *main)
index 4a7080034ee82d293ff79b03533c1cd089eed433..f520a3d5fb25305e384620bd5977075d743f0592 100644 (file)
@@ -109,7 +109,7 @@ typedef struct wmWindowManager {
        
        int initialized;                /* set on file read */
        short file_saved;               /* indicator whether data was saved */
        
        int initialized;                /* set on file read */
        short file_saved;               /* indicator whether data was saved */
-       short pad;
+       short op_undo_depth;    /* operator stack depth to avoid nested undo pushes */
        
        ListBase operators;             /* operator registry */
        
        
        ListBase operators;             /* operator registry */
        
index f508062f7020f0029bee0c991fc543ade0626500..dc4eec7f5e684f04e800250ad911ff6f50b90c81 100644 (file)
@@ -303,9 +303,37 @@ int WM_operator_poll(bContext *C, wmOperatorType *ot)
        return 1;
 }
 
        return 1;
 }
 
+static void wm_operator_finished(bContext *C, wmOperator *op, int repeat)
+{
+       wmWindowManager *wm= CTX_wm_manager(C);
+
+       op->customdata= NULL;
+
+       /* we don't want to do undo pushes for operators that are being
+          called from operators that already do an undo push. usually
+          this will happen for python operators that call C operators */
+       if(wm->op_undo_depth == 0)
+               if(op->type->flag & OPTYPE_UNDO)
+                       ED_undo_push_op(C, op);
+       
+       if(repeat==0) {
+               if(G.f & G_DEBUG) {
+                       char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
+                       BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
+                       MEM_freeN(buf);
+               }
+
+               if((wm->op_undo_depth == 0) && (op->type->flag & OPTYPE_REGISTER))
+                       wm_operator_register(C, op);
+               else
+                       WM_operator_free(op);
+       }
+}
+
 /* if repeat is true, it doesn't register again, nor does it free */
 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
 {
 /* if repeat is true, it doesn't register again, nor does it free */
 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        int retval= OPERATOR_CANCELLED;
        
        if(op==NULL || op->type==NULL)
        int retval= OPERATOR_CANCELLED;
        
        if(op==NULL || op->type==NULL)
@@ -314,32 +342,22 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        if(0==WM_operator_poll(C, op->type))
                return retval;
        
        if(0==WM_operator_poll(C, op->type))
                return retval;
        
-       if(op->type->exec)
+       if(op->type->exec) {
+               if(op->type->flag & OPTYPE_UNDO)
+                       wm->op_undo_depth++;
+
                retval= op->type->exec(C, op);
                retval= op->type->exec(C, op);
+
+               if(op->type->flag & OPTYPE_UNDO)
+                       wm->op_undo_depth--;
+       }
        
        if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
                if(op->reports->list.first)
                        uiPupMenuReports(C, op->reports);
        
        
        if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
                if(op->reports->list.first)
                        uiPupMenuReports(C, op->reports);
        
-       if(retval & OPERATOR_FINISHED) {
-               op->customdata= NULL;
-
-               if(op->type->flag & OPTYPE_UNDO)
-                       ED_undo_push_op(C, op);
-               
-               if(repeat==0) {
-                       if(G.f & G_DEBUG) {
-                               char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
-                               BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
-                               MEM_freeN(buf);
-                       }
-
-                       if((op->type->flag & OPTYPE_REGISTER))
-                               wm_operator_register(C, op);
-                       else
-                               WM_operator_free(op);
-               }
-       }
+       if(retval & OPERATOR_FINISHED)
+               wm_operator_finished(C, op, repeat);
        else if(repeat==0)
                WM_operator_free(op);
        
        else if(repeat==0)
                WM_operator_free(op);
        
@@ -472,10 +490,24 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                
                if(op->type->invoke && event) {
                        wm_region_mouse_co(C, event);
                
                if(op->type->invoke && event) {
                        wm_region_mouse_co(C, event);
+
+                       if(op->type->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth++;
+
                        retval= op->type->invoke(C, op, event);
                        retval= op->type->invoke(C, op, event);
+
+                       if(op->type->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth--;
                }
                }
-               else if(op->type->exec)
+               else if(op->type->exec) {
+                       if(op->type->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth++;
+
                        retval= op->type->exec(C, op);
                        retval= op->type->exec(C, op);
+
+                       if(op->type->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth--;
+               }
                else
                        printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
 
                else
                        printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
 
@@ -493,21 +525,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                if(retval & OPERATOR_HANDLED)
                        ; /* do nothing, wm_operator_exec() has been called somewhere */
                else if(retval & OPERATOR_FINISHED) {
                if(retval & OPERATOR_HANDLED)
                        ; /* do nothing, wm_operator_exec() has been called somewhere */
                else if(retval & OPERATOR_FINISHED) {
-                       op->customdata= NULL;
-
-                       if(ot->flag & OPTYPE_UNDO)
-                               ED_undo_push_op(C, op);
-                       
-                       if(G.f & G_DEBUG) {
-                               char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
-                               BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
-                               MEM_freeN(buf);
-                       }
-                       
-                       if((ot->flag & OPTYPE_REGISTER))
-                               wm_operator_register(C, op);
-                       else
-                               WM_operator_free(op);
+                       wm_operator_finished(C, op, 0);
                }
                else if(retval & OPERATOR_RUNNING_MODAL) {
                        /* grab cursor during blocking modal ops (X11)
                }
                else if(retval & OPERATOR_RUNNING_MODAL) {
                        /* grab cursor during blocking modal ops (X11)
@@ -657,8 +675,15 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA
        wmWindowManager *wm=    CTX_wm_manager(C);
        op= wm_operator_create(wm, ot, properties, reports);
 
        wmWindowManager *wm=    CTX_wm_manager(C);
        op= wm_operator_create(wm, ot, properties, reports);
 
-       if (op->type->exec)
+       if (op->type->exec) {
+               if(op->type->flag & OPTYPE_UNDO)
+                       wm->op_undo_depth++;
+
                retval= op->type->exec(C, op);
                retval= op->type->exec(C, op);
+
+               if(op->type->flag & OPTYPE_UNDO)
+                       wm->op_undo_depth--;
+       }
        else
                printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
 #endif
        else
                printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
 #endif
@@ -721,6 +746,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
 {
        wmEventHandler *handler;
 void WM_event_remove_handlers(bContext *C, ListBase *handlers)
 {
        wmEventHandler *handler;
+       wmWindowManager *wm= CTX_wm_manager(C);
        
        /* C is zero on freeing database, modal handlers then already were freed */
        while((handler=handlers->first)) {
        
        /* C is zero on freeing database, modal handlers then already were freed */
        while((handler=handlers->first)) {
@@ -733,8 +759,14 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                                
                                wm_handler_op_context(C, handler);
 
                                
                                wm_handler_op_context(C, handler);
 
+                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                       wm->op_undo_depth++;
+
                                handler->op->type->cancel(C, handler->op);
 
                                handler->op->type->cancel(C, handler->op);
 
+                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                       wm->op_undo_depth--;
+
                                CTX_wm_area_set(C, area);
                                CTX_wm_region_set(C, region);
                        }
                                CTX_wm_area_set(C, area);
                                CTX_wm_region_set(C, region);
                        }
@@ -926,6 +958,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
 
                if(ot->modal) {
                        /* we set context to where modal handler came from */
 
                if(ot->modal) {
                        /* we set context to where modal handler came from */
+                       wmWindowManager *wm= CTX_wm_manager(C);
                        ScrArea *area= CTX_wm_area(C);
                        ARegion *region= CTX_wm_region(C);
                        
                        ScrArea *area= CTX_wm_area(C);
                        ARegion *region= CTX_wm_region(C);
                        
@@ -933,8 +966,14 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        wm_region_mouse_co(C, event);
                        wm_event_modalkeymap(C, op, event);
                        
                        wm_region_mouse_co(C, event);
                        wm_event_modalkeymap(C, op, event);
                        
+                       if(ot->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth++;
+
                        retval= ot->modal(C, op, event);
 
                        retval= ot->modal(C, op, event);
 
+                       if(ot->flag & OPTYPE_UNDO)
+                               wm->op_undo_depth--;
+
                        /* putting back screen context, reval can pass trough after modal failures! */
                        if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
                                CTX_wm_area_set(C, area);
                        /* putting back screen context, reval can pass trough after modal failures! */
                        if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
                                CTX_wm_area_set(C, area);
@@ -956,21 +995,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        }                       
 
                        if(retval & OPERATOR_FINISHED) {
                        }                       
 
                        if(retval & OPERATOR_FINISHED) {
-                               op->customdata= NULL;
-
-                               if(ot->flag & OPTYPE_UNDO)
-                                       ED_undo_push_op(C, op);
-                               
-                               if(G.f & G_DEBUG) {
-                                       char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
-                                       BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
-                                       MEM_freeN(buf);
-                               }
-                               
-                               if((ot->flag & OPTYPE_REGISTER))
-                                       wm_operator_register(C, op);
-                               else
-                                       WM_operator_free(op);
+                               wm_operator_finished(C, op, 0);
                                handler->op= NULL;
                        }
                        else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
                                handler->op= NULL;
                        }
                        else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
@@ -1053,6 +1078,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
 {
 /* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
 static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        SpaceFile *sfile;
        int action= WM_HANDLER_CONTINUE;
        
        SpaceFile *sfile;
        int action= WM_HANDLER_CONTINUE;
        
@@ -1119,7 +1145,15 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                                uiPupMenuSaveOver(C, handler->op, (path)? path: "");
                                        }
                                        else {
                                                uiPupMenuSaveOver(C, handler->op, (path)? path: "");
                                        }
                                        else {
-                                               int retval= handler->op->type->exec(C, handler->op);
+                                               int retval;
+                                               
+                                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                                       wm->op_undo_depth++;
+
+                                               retval= handler->op->type->exec(C, handler->op);
+
+                                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                                       wm->op_undo_depth--;
                                                
                                                if (retval & OPERATOR_FINISHED)
                                                        if(G.f & G_DEBUG)
                                                
                                                if (retval & OPERATOR_FINISHED)
                                                        if(G.f & G_DEBUG)
@@ -1144,9 +1178,16 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                        }
                                }
                                else {
                                        }
                                }
                                else {
-                                       if(handler->op->type->cancel)
+                                       if(handler->op->type->cancel) {
+                                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                                       wm->op_undo_depth++;
+
                                                handler->op->type->cancel(C, handler->op);
 
                                                handler->op->type->cancel(C, handler->op);
 
+                                               if(handler->op->type->flag & OPTYPE_UNDO)
+                                                       wm->op_undo_depth--;
+                                       }
+
                                        WM_operator_free(handler->op);
                                }
 
                                        WM_operator_free(handler->op);
                                }