doxygen: blender/editors tagged.
[blender-staging.git] / source / blender / editors / util / undo.c
index 283e2b49f0d68de7b9928bdc668efcb846a98052..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 "DNA_object_types.h"
 
-#include "BKE_blender.h"
-#include "BKE_context.h"
-
 #include "BLI_blenlib.h"
 #include "BLI_editVert.h"
 #include "BLI_dynstr.h"
+#include "BLI_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 "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);
@@ -156,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));
                        }
                        
                }
@@ -194,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);
@@ -230,6 +299,7 @@ void ED_undo_menu(bContext *C)
                }
        }
 }
+#endif
 
 /* ********************** */
 
@@ -245,6 +315,19 @@ 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 */
@@ -258,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);
+}