doxygen: blender/editors tagged.
[blender-staging.git] / source / blender / editors / util / undo.c
index 4c7831c589cc4d0982e77deb5bad889cae675765..b366a8460fcb71b7927a182cb3a4b044a3d8e685 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/util/undo.c
+ *  \ingroup edutil
+ */
+
+
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_space_types.h"
-#include "DNA_userdef_types.h"
-
-#include "BKE_blender.h"
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_object.h"
-#include "BKE_text.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_editVert.h"
 #include "BLI_dynstr.h"
+#include "BLI_utildefines.h"
 
-#include "BKE_utildefines.h"
+#include "BKE_blender.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
 
 #include "ED_armature.h"
 #include "ED_particle.h"
 #include "WM_api.h"
 #include "WM_types.h"
 
-#include "UI_interface.h"
-#include "UI_resources.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "util_intern.h"
 
+#define MAXUNDONAME 64 /* XXX, make common define */
+
 /* ***************** generic undo system ********************* */
 
-void ED_undo_push(bContext *C, char *str)
+void ED_undo_push(bContext *C, const char *str)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
        Object *obedit= CTX_data_edit_object(C);
@@ -124,7 +122,9 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
                
                if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
-                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
+                       if(!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname)
+                               if(U.uiflag & USER_GLOBALUNDO)
+                                       BKE_undo_name(C, undoname);
 
                        WM_event_add_notifier(C, NC_WINDOW, NULL);
                        return OPERATOR_FINISHED;
@@ -147,10 +147,14 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
        else {
                int do_glob_undo= 0;
                
-               if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
-                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
-               else if(obact && obact->mode & OB_MODE_SCULPT)
-                       ED_undo_paint_step(C, UNDO_PAINT_MESH, step);
+               if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
+                       if(!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname)
+                               do_glob_undo= 1;
+               }
+               else if(obact && obact->mode & OB_MODE_SCULPT) {
+                       if(!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname) && undoname)
+                               do_glob_undo= 1;
+               }
                else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
                        if(step==1)
                                PE_undo(CTX_data_scene(C));
@@ -163,13 +167,16 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                
                if(do_glob_undo) {
                        if(U.uiflag & USER_GLOBALUNDO) {
-#ifndef DISABLE_PYTHON
+                               // note python defines not valid here anymore.
+                               //#ifdef WITH_PYTHON
                                // XXX          BPY_scripts_clear_pyobjects();
-#endif
+                               //#endif
                                if(undoname)
                                        BKE_undo_name(C, undoname);
                                else
                                        BKE_undo_step(C, step);
+
+                               WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, CTX_data_scene(C));
                        }
                        
                }
@@ -201,18 +208,73 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
        ed_undo_step(C, 0, op->type->name);
 }
 
-static int ed_undo_exec(bContext *C, wmOperator *op)
+/* name optionally, function used to check for operator redo panel */
+int ED_undo_valid(const bContext *C, const char *undoname)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       Object *obact= CTX_data_active_object(C);
+       ScrArea *sa= CTX_wm_area(C);
+       
+       if(sa && sa->spacetype==SPACE_IMAGE) {
+               SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
+               
+               if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
+                       return 1;
+               }
+       }
+       
+       if(sa && sa->spacetype==SPACE_TEXT) {
+               return 1;
+       }
+       else if(obedit) {
+               if ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE) {
+                       return undo_editmode_valid(undoname);
+               }
+       }
+       else {
+               
+               /* if below tests fail, global undo gets executed */
+               
+               if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
+                       if( ED_undo_paint_valid(UNDO_PAINT_IMAGE, undoname) )
+                               return 1;
+               }
+               else if(obact && obact->mode & OB_MODE_SCULPT) {
+                       if( ED_undo_paint_valid(UNDO_PAINT_MESH, undoname) )
+                               return 1;
+               }
+               else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
+                       return PE_undo_valid(CTX_data_scene(C));
+               }
+               
+               if(U.uiflag & USER_GLOBALUNDO) {
+                       return BKE_undo_valid(undoname);
+               }
+       }
+       return 0;
+}
+
+static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
 {
        /* "last operator" should disappear, later we can tie ths with undo stack nicer */
        WM_operator_stack_clear(C);
        return ed_undo_step(C, 1, NULL);
 }
 
-static int ed_redo_exec(bContext *C, wmOperator *op)
+static int ed_undo_push_exec(bContext *C, wmOperator *op)
+{
+       char str[MAXUNDONAME];
+       RNA_string_get(op->ptr, "message", str);
+       ED_undo_push(C, str);
+       return OPERATOR_FINISHED;
+}
+
+static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
 {
        return ed_undo_step(C, -1, NULL);
 }
 
+#if 0 /* UNUSED */
 void ED_undo_menu(bContext *C)
 {
        Object *obedit= CTX_data_edit_object(C);
@@ -237,6 +299,7 @@ void ED_undo_menu(bContext *C)
                }
        }
 }
+#endif
 
 /* ********************** */
 
@@ -244,7 +307,7 @@ void ED_OT_undo(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Undo";
-    ot->description= "Undo previous action";
+       ot->description= "Undo previous action";
        ot->idname= "ED_OT_undo";
        
        /* api callbacks */
@@ -252,11 +315,24 @@ void ED_OT_undo(wmOperatorType *ot)
        ot->poll= ED_operator_screenactive;
 }
 
+void ED_OT_undo_push(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Undo Push";
+       ot->description= "Add an undo state (internal use only)";
+       ot->idname= "ED_OT_undo_push";
+       
+       /* api callbacks */
+       ot->exec= ed_undo_push_exec;
+
+       RNA_def_string(ot->srna, "message", "Add an undo step *function may be moved*", MAXUNDONAME, "Undo Message", "");
+}
+
 void ED_OT_redo(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Redo";
-    ot->description= "Redo previous action";
+       ot->description= "Redo previous action";
        ot->idname= "ED_OT_redo";
        
        /* api callbacks */
@@ -265,3 +341,53 @@ void ED_OT_redo(wmOperatorType *ot)
 }
 
 
+/* ui callbacks should call this rather then calling WM_operator_repeat() themselves */
+int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
+{
+       int ret= 0;
+
+       if(op) {
+               ARegion *ar= CTX_wm_region(C);
+               ARegion *ar1= BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_WINDOW);
+
+               if(ar1)
+                       CTX_wm_region_set(C, ar1);
+
+               if(WM_operator_repeat_check(C, op) && WM_operator_poll(C, op->type)) {
+                       int retval;
+
+                       if (G.f & G_DEBUG)
+                               printf("redo_cb: operator redo %s\n", op->type->name);
+                       ED_undo_pop_op(C, op);
+                       retval= WM_operator_repeat(C, op);
+                       if((retval & OPERATOR_FINISHED)==0) {
+                               if (G.f & G_DEBUG)
+                                       printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
+                               ED_undo_redo(C);
+                       }
+                       else {
+                               ret= 1;
+                       }
+               }
+
+               /* set region back */
+               CTX_wm_region_set(C, ar);
+       }
+       else {
+               if (G.f & G_DEBUG) {
+                       printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
+               }
+       }
+
+       return ret;
+}
+
+void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
+{
+       ED_undo_operator_repeat(C, (wmOperator *)arg_op);
+}
+
+void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_event))
+{
+       ED_undo_operator_repeat(C, (wmOperator *)arg_op);
+}