2.5
authorTon Roosendaal <ton@blender.org>
Tue, 30 Dec 2008 19:01:12 +0000 (19:01 +0000)
committerTon Roosendaal <ton@blender.org>
Tue, 30 Dec 2008 19:01:12 +0000 (19:01 +0000)
Undo editmode and global undo code back.
It's now called ED_undo_push() btw, but don't worry, for operators
this is going to be a simple operator flag, so you can remove the
old calls from all tools (but keep them when you directly change
data outide modifiers).

Will put undo back functional tomorrow

source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_util.h
source/blender/editors/mesh/editmesh.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/util/editmode_undo.c [new file with mode: 0644]
source/blender/editors/util/undo.c [new file with mode: 0644]

index 2437542..a7fe669 100644 (file)
@@ -73,6 +73,7 @@ EditEdge      *EM_get_edge_for_index(int index);
 EditFace       *EM_get_face_for_index(int index);
 int                    EM_texFaceCheck(struct EditMesh *em);
 int                    EM_vertColorCheck(struct EditMesh *em);
+void           undo_push_mesh(char *name);
 
 
 /* editmesh_lib.c */
index 93bb5ef..49aee46 100644 (file)
 #ifndef ED_UTIL_H
 #define ED_UTIL_H
 
+struct Object;
+struct bContext;
+struct uiMenuBlockHandle;
+struct uiBlock;
+
+/* ************** Undo ************************ */
+
+/* undo.c */
+void   ED_redo                                 (struct bContext *C);
+void   ED_undo                                 (struct bContext *C);
+void   ED_undo_push                    (struct bContext *C, char *str);
+void   ED_undo_menu                    (struct bContext *C);
+
+/* undo_editmode.c */
+void   undo_editmode_push                      (char *name, void (*freedata)(void *), 
+                                                                        void (*to_editmode)(void *),  void *(*from_editmode)(void),
+                                                                        int (*validate_undo)(void *));
+void   *undo_editmode_get_prev         (struct Object *ob);
+struct uiBlock *editmode_undohistorymenu(struct bContext *C, struct uiMenuBlockHandle *handle, void *arg_unused);
+void   undo_editmode_menu                      (void);
+void   undo_editmode_clear                     (void);
+void   undo_editmode_step                      (int step);
+
+
 /* ************** XXX OLD CRUFT WARNING ************* */
 
 void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
index e723fb2..76f7748 100644 (file)
@@ -78,6 +78,7 @@
 #include "BIF_retopo.h"
 
 #include "ED_mesh.h"
+#include "ED_util.h"
 
 /* own include */
 #include "editmesh.h"
@@ -95,11 +96,8 @@ static void waitcursor() {}
 static void error() {}
 static int pupmenu() {return 0;}
 static void key_to_mesh() {}
-static void undo_editmode_clear() {}
 static int multires_test() {return 0;}
 static void adduplicate() {}
-static void *undo_editmode_get_prev() {return NULL;}
-static void undo_editmode_push() {}
 
 
 /* ***************** HASH ********************* */
@@ -1863,8 +1861,10 @@ static void free_undoMesh(void *umv)
        MEM_freeN(um);
 }
 
-static void *editMesh_to_undoMesh(Scene *scene, EditMesh *em)
+static void *editMesh_to_undoMesh(void)
 {
+       EditMesh *em= NULL; // XXX
+       Scene *scene= NULL;
        UndoMesh *um;
        EditVert *eve;
        EditEdge *eed;
@@ -1980,8 +1980,9 @@ static void *editMesh_to_undoMesh(Scene *scene, EditMesh *em)
        return um;
 }
 
-static void undoMesh_to_editMesh(void *umv, EditMesh *em)
+static void undoMesh_to_editMesh(void *umv)
 {
+       EditMesh *em= NULL; // XXX
        UndoMesh *um= (UndoMesh*)umv;
        EditVert *eve, **evar=NULL;
        EditEdge *eed;
index fbf437e..040913d 100644 (file)
@@ -121,7 +121,6 @@ static void toggle_blockhandler(void *x, int y, int z) {}
 static void countall(void) {}
 extern void borderselect();
 static int BIF_snappingSupported() {return 1;}
-static void BIF_undo_push() {}
 static int retopo_mesh_paint_check() {return 0;}
 
 /* view3d handler codes */
@@ -984,7 +983,7 @@ void do_view3d_select_meshmenu(bContext *C, void *arg, int event)
 
                case 16: /* path select */
                        pathselect();
-                       BIF_undo_push("Path Select");
+                       ED_undo_push(C, "Path Select");
                        break;
                case 17: /* edge loop select */
                        loop_multiselect(0);
@@ -1508,15 +1507,15 @@ void do_view3d_edit_snapmenu(bContext *C, void *arg, int event)
        switch (event) {
        case 1: /*Selection to grid*/
            snap_sel_to_grid();
-               BIF_undo_push("Snap selection to grid");
+               ED_undo_push(C, "Snap selection to grid");
            break;
        case 2: /*Selection to cursor*/
            snap_sel_to_curs();
-               BIF_undo_push("Snap selection to cursor");
+               ED_undo_push(C, "Snap selection to cursor");
            break;
        case 3: /*Selection to center of selection*/
            snap_to_center();
-               BIF_undo_push("Snap selection to center");
+               ED_undo_push(C, "Snap selection to center");
            break;
        case 4: /*Cursor to selection*/
            snap_curs_to_sel();
@@ -1526,7 +1525,7 @@ void do_view3d_edit_snapmenu(bContext *C, void *arg, int event)
            break;
        case 6: /*Cursor to Active*/
            snap_curs_to_active();
-               BIF_undo_push("Snap selection to center");
+               ED_undo_push(C, "Snap selection to center");
            break;
        }
        allqueue(REDRAWVIEW3D, 0);
@@ -2667,7 +2666,7 @@ void do_view3d_edit_mesh_verticesmenu(bContext *C, void *arg, int event)
                notice("Removed: %d", count);
                if (count) { /* only undo and redraw if an action is taken */
                        DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
-                       BIF_undo_push("Rem Doubles");
+                       ED_undo_push(C, "Rem Doubles");
                }
                break;
        case 2: /* smooth */
@@ -2735,18 +2734,18 @@ void do_view3d_edit_mesh_edgesmenu(bContext *C, void *arg, int event)
                 
        case 0: /* subdivide smooth */
                esubdivideflag(1, 0.0, scene->toolsettings->editbutflag | B_SMOOTH,1,0);
-               BIF_undo_push("Subdivide Smooth");
+               ED_undo_push(C, "Subdivide Smooth");
                break;
        case 1: /*subdivide fractal */
                randfac= 10;
                if(button(&randfac, 1, 100, "Rand fac:")==0) return;
                fac= -( (float)randfac )/100;
                esubdivideflag(1, fac, scene->toolsettings->editbutflag,1,0);
-               BIF_undo_push("Subdivide Fractal");
+               ED_undo_push(C, "Subdivide Fractal");
                break;
        case 2: /* subdivide */
                esubdivideflag(1, 0.0, scene->toolsettings->editbutflag,1,0);
-               BIF_undo_push("Subdivide");
+               ED_undo_push(C, "Subdivide");
                break;
        case 3: /* knife subdivide */
                KnifeSubdivide(KNIFE_PROMPT);
@@ -2784,22 +2783,22 @@ void do_view3d_edit_mesh_edgesmenu(bContext *C, void *arg, int event)
        case 13: /* Edge Loop Delete */
                if(EdgeLoopDelete()) {
                        countall();
-                       BIF_undo_push("Erase Edge Loop");
+                       ED_undo_push(C, "Erase Edge Loop");
                        DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
                }
                break;
        case 14: /*Collapse Edges*/
                collapseEdges();
-               BIF_undo_push("Collapse");
+               ED_undo_push(C, "Collapse");
                break;
        case 15:
                editmesh_mark_sharp(1);
-               BIF_undo_push("Mark Sharp");
+               ED_undo_push(C, "Mark Sharp");
                DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
                break;
        case 16:
                editmesh_mark_sharp(0);
-               BIF_undo_push("Clear Sharp");
+               ED_undo_push(C, "Clear Sharp");
                DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
                break;
        case 17: /* Adjust Bevel Weight */
@@ -4151,7 +4150,7 @@ static void do_view3d_pose_armature_transformmenu(bContext *C, void *arg, int ev
        case 4: /* clear user transform */
                rest_pose(ob->pose);
                DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-               BIF_undo_push("Pose, Clear User Transform");
+               ED_undo_push(C, "Pose, Clear User Transform");
                break;
        }
        allqueue(REDRAWVIEW3D, 0);
@@ -4723,19 +4722,19 @@ void do_view3d_sculpt_inputmenu(bContext *C, void *arg, int event)
        switch(event) {
        case 0:
                sd->flags ^= SCULPT_INPUT_SMOOTH;
-               BIF_undo_push("Smooth stroke");
+               ED_undo_push(C, "Smooth stroke");
                break;
        case 1:
                val= sd->tablet_size;
                if(button(&val,0,10,"Tablet Size:")==0) return;
                sd->tablet_size= val;
-               BIF_undo_push("Tablet size");
+               ED_undo_push(C, "Tablet size");
                break;
        case 2:
                val= sd->tablet_strength;
                if(button(&val,0,10,"Tablet Strength:")==0) return;
                sd->tablet_strength= val;
-               BIF_undo_push("Tablet strength");
+               ED_undo_push(C, "Tablet strength");
                break;
        }
        
@@ -4762,23 +4761,23 @@ void do_view3d_sculptmenu(bContext *C, void *arg, int event)
        case 5:
        case 6:
                sd->brush_type= event+1;
-               BIF_undo_push("Brush type");
+               ED_undo_push(C, "Brush type");
                break;
        case 7:
                br->flag ^= SCULPT_BRUSH_AIRBRUSH;
-               BIF_undo_push("Airbrush");
+               ED_undo_push(C, "Airbrush");
                break;
        case 8:
                sd->symm ^= SYMM_X;
-               BIF_undo_push("X Symmetry");
+               ED_undo_push(C, "X Symmetry");
                break;
        case 9:
                sd->symm ^= SYMM_Y;
-               BIF_undo_push("Y Symmetry");
+               ED_undo_push(C, "Y Symmetry");
                break;
        case 10:
                sd->symm ^= SYMM_Z;
-               BIF_undo_push("Z Symmetry");
+               ED_undo_push(C, "Z Symmetry");
                break;
        case 11:
                if(v3d)
@@ -4786,11 +4785,11 @@ void do_view3d_sculptmenu(bContext *C, void *arg, int event)
                break;
        case 12:
                sd->flags ^= SCULPT_DRAW_FAST;
-               BIF_undo_push("Partial Redraw");
+               ED_undo_push(C, "Partial Redraw");
                break;
        case 13:
                sd->flags ^= SCULPT_DRAW_BRUSH;
-               BIF_undo_push("Draw Brush");
+               ED_undo_push(C, "Draw Brush");
                break;
        case 14:
                add_blockhandler(sa, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW);
@@ -4806,7 +4805,7 @@ void do_view3d_sculptmenu(bContext *C, void *arg, int event)
                break;
        case 18:
                br->dir= br->dir==1 ? 2 : 1;
-               BIF_undo_push("Add/Sub");
+               ED_undo_push(C, "Add/Sub");
                break;
        }
 
@@ -5364,7 +5363,7 @@ static void do_view3d_buttons(bContext *C, void *arg, int event)
                                v3d->flag &= ~V3D_MODE;
 // XXX                         exit_paint_modes();
 // XXX                         enter_editmode(EM_WAITCURSOR);
-                               BIF_undo_push("Original");      /* here, because all over code enter_editmode is abused */
+                               ED_undo_push(C, "Original");    /* here, because all over code enter_editmode is abused */
                        }
                } 
                else if (v3d->modeselect == V3D_SCULPTMODE_SEL) {
@@ -5434,7 +5433,7 @@ static void do_view3d_buttons(bContext *C, void *arg, int event)
                        scene->selectmode= SCE_SELECT_VERTEX;
 // XXX         EM_selectmode_set();
                countall();
-               BIF_undo_push("Selectmode Set: Vertex");
+               ED_undo_push(C, "Selectmode Set: Vertex");
                allqueue(REDRAWVIEW3D, 1);
                allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
                break;
@@ -5447,7 +5446,7 @@ static void do_view3d_buttons(bContext *C, void *arg, int event)
                }
 // XXX         EM_selectmode_set();
                countall();
-               BIF_undo_push("Selectmode Set: Edge");
+               ED_undo_push(C, "Selectmode Set: Edge");
                allqueue(REDRAWVIEW3D, 1);
                allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
                break;
@@ -5460,24 +5459,24 @@ static void do_view3d_buttons(bContext *C, void *arg, int event)
                }
 // XXX         EM_selectmode_set();
                countall();
-               BIF_undo_push("Selectmode Set: Face");
+               ED_undo_push(C, "Selectmode Set: Face");
                allqueue(REDRAWVIEW3D, 1);
                allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
                break;  
 
        case B_SEL_PATH:
                scene->selectmode= SCE_SELECT_PATH;
-               BIF_undo_push("Selectmode Set: Path");
+               ED_undo_push(C, "Selectmode Set: Path");
                allqueue(REDRAWVIEW3D, 1);
                break;
        case B_SEL_POINT:
                scene->selectmode = SCE_SELECT_POINT;
-               BIF_undo_push("Selectmode Set: Point");
+               ED_undo_push(C, "Selectmode Set: Point");
                allqueue(REDRAWVIEW3D, 1);
                break;
        case B_SEL_END:
                scene->selectmode = SCE_SELECT_END;
-               BIF_undo_push("Selectmode Set: End point");
+               ED_undo_push(C, "Selectmode Set: End point");
                allqueue(REDRAWVIEW3D, 1);
                break;  
        
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
new file mode 100644 (file)
index 0000000..05813b7
--- /dev/null
@@ -0,0 +1,346 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.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_userdef_types.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "BKE_utildefines.h"
+
+#include "ED_util.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+/* ***************** generic editmode undo system ********************* */
+/*
+
+Add this in your local code:
+
+void undo_editmode_push(char *name, 
+               void (*freedata)(void *),                       // pointer to function freeing data
+               void (*to_editmode)(void *),        // data to editmode conversion
+               void * (*from_editmode)(void))      // editmode to data conversion
+               int  (*validate_undo)(void *))      // check if undo data is still valid
+
+
+Further exported for UI is:
+
+void undo_editmode_step(int step);                     // undo and redo
+void undo_editmode_clear(void)                         // free & clear all data
+void undo_editmode_menu(void)                          // history menu
+
+
+*/
+/* ********************************************************************* */
+
+/* ****** XXX ***** */
+void error() {}
+/* ****** XXX ***** */
+
+
+#define MAXUNDONAME    64
+typedef struct UndoElem {
+       struct UndoElem *next, *prev;
+       ID id;                  // copy of editmode object ID
+       Object *ob;             // pointer to edited object
+       int type;               // type of edited object
+       void *undodata;
+       uintptr_t undosize;
+       char name[MAXUNDONAME];
+       void (*freedata)(void *);
+       void (*to_editmode)(void *);
+       void * (*from_editmode)(void);
+       int (*validate_undo)(void *);
+} UndoElem;
+
+static ListBase undobase={NULL, NULL};
+static UndoElem *curundo= NULL;
+
+
+/* ********************* xtern api calls ************* */
+
+static void undo_restore(UndoElem *undo)
+{
+       if(undo) {
+               undo->to_editmode(undo->undodata);      
+       }
+}
+
+/* name can be a dynamic string */
+void undo_editmode_push(char *name, void (*freedata)(void *), 
+               void (*to_editmode)(void *),  void *(*from_editmode)(void),
+               int (*validate_undo)(void *))
+{
+       UndoElem *uel;
+       int nr;
+       uintptr_t memused, totmem, maxmem;
+
+       /* at first here was code to prevent an "original" key to be insterted twice
+          this was giving conflicts for example when mesh changed due to keys or apply */
+       
+       /* remove all undos after (also when curundo==NULL) */
+       while(undobase.last != curundo) {
+               uel= undobase.last;
+               uel->freedata(uel->undodata);
+               BLI_freelinkN(&undobase, uel);
+       }
+       
+       /* make new */
+       curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+       strncpy(uel->name, name, MAXUNDONAME-1);
+       BLI_addtail(&undobase, uel);
+       
+       uel->freedata= freedata;
+       uel->to_editmode= to_editmode;
+       uel->from_editmode= from_editmode;
+       uel->validate_undo= validate_undo;
+       
+       /* limit amount to the maximum amount*/
+       nr= 0;
+       uel= undobase.last;
+       while(uel) {
+               nr++;
+               if(nr==U.undosteps) break;
+               uel= uel->prev;
+       }
+       if(uel) {
+               while(undobase.first!=uel) {
+                       UndoElem *first= undobase.first;
+                       first->freedata(first->undodata);
+                       BLI_freelinkN(&undobase, first);
+               }
+       }
+
+       /* copy  */
+       memused= MEM_get_memory_in_use();
+       curundo->undodata= curundo->from_editmode();
+       curundo->undosize= MEM_get_memory_in_use() - memused;
+       curundo->ob= G.obedit;
+       curundo->id= G.obedit->id;
+       curundo->type= G.obedit->type;
+
+       if(U.undomemory != 0) {
+               /* limit to maximum memory (afterwards, we can't know in advance) */
+               totmem= 0;
+               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
+
+               uel= undobase.last;
+               while(uel && uel->prev) {
+                       totmem+= uel->undosize;
+                       if(totmem>maxmem) break;
+                       uel= uel->prev;
+               }
+
+               if(uel) {
+                       if(uel->prev && uel->prev->prev)
+                               uel= uel->prev;
+
+                       while(undobase.first!=uel) {
+                               UndoElem *first= undobase.first;
+                               first->freedata(first->undodata);
+                               BLI_freelinkN(&undobase, first);
+                       }
+               }
+       }
+}
+
+/* helper to remove clean other objects from undo stack */
+static void undo_clean_stack(void)
+{
+       UndoElem *uel, *next;
+       int mixed= 0;
+       
+       /* global undo changes pointers, so we also allow identical names */
+       /* side effect: when deleting/renaming object and start editing new one with same name */
+       
+       uel= undobase.first; 
+       while(uel) {
+               next= uel->next;
+               
+               /* for when objects are converted, renamed, or global undo changes pointers... */
+               if(uel->type==G.obedit->type && strcmp(uel->id.name, G.obedit->id.name)==0 &&
+                  (!uel->validate_undo || uel->validate_undo(uel->undodata))) {
+                       uel->ob= G.obedit;
+               }
+               else {
+                       mixed= 1;
+                       uel->freedata(uel->undodata);
+                       BLI_freelinkN(&undobase, uel);
+               }
+
+               uel= next;
+       }
+       
+       if(mixed) curundo= undobase.last;
+}
+
+/* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
+void undo_editmode_step(int step)
+{
+       
+       /* prevent undo to happen on wrong object, stack can be a mix */
+       undo_clean_stack();
+       
+       if(step==0) {
+               undo_restore(curundo);
+       }
+       else if(step==1) {
+               
+               if(curundo==NULL || curundo->prev==NULL) error("No more steps to undo");
+               else {
+                       if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
+                       curundo= curundo->prev;
+                       undo_restore(curundo);
+               }
+       }
+       else {
+               /* curundo has to remain current situation! */
+               
+               if(curundo==NULL || curundo->next==NULL) error("No more steps to redo");
+               else {
+                       undo_restore(curundo->next);
+                       curundo= curundo->next;
+                       if(G.f & G_DEBUG) printf("redo %s\n", curundo->name);
+               }
+       }
+
+//     DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+       /* XXX notifiers */
+}
+
+void undo_editmode_clear(void)
+{
+       UndoElem *uel;
+       
+       uel= undobase.first;
+       while(uel) {
+               uel->freedata(uel->undodata);
+               uel= uel->next;
+       }
+       BLI_freelistN(&undobase);
+       curundo= NULL;
+}
+
+/* based on index nr it does a restore */
+static void undo_number(int nr)
+{
+       UndoElem *uel;
+       int a=1;
+       
+       for(uel= undobase.first; uel; uel= uel->next, a++) {
+               if(a==nr) break;
+       }
+       curundo= uel;
+       undo_editmode_step(0);
+}
+
+/* ************** for interaction with menu/pullown */
+
+void undo_editmode_menu(void)
+{
+       UndoElem *uel;
+       DynStr *ds= BLI_dynstr_new();
+       short event;
+       char *menu;
+
+       undo_clean_stack();     // removes other objects from it
+       
+       BLI_dynstr_append(ds, "Editmode Undo History %t");
+       
+       for(uel= undobase.first; uel; uel= uel->next) {
+               BLI_dynstr_append(ds, "|");
+               BLI_dynstr_append(ds, uel->name);
+       }
+       
+       menu= BLI_dynstr_get_cstring(ds);
+       BLI_dynstr_free(ds);
+       
+// XXX event= pupmenu_col(menu, 20);
+       MEM_freeN(menu);
+       
+       if(event>0) undo_number(event);
+}
+
+static void do_editmode_undohistorymenu(bContext *C, void *arg, int event)
+{
+       
+       if(G.obedit==NULL || event<1) return;
+
+       undo_number(event-1);
+       
+}
+
+uiBlock *editmode_undohistorymenu(bContext *C, uiMenuBlockHandle *handle, void *arg_unused)
+{
+       uiBlock *block;
+       UndoElem *uel;
+       short yco = 20, menuwidth = 120;
+       short item= 1;
+       
+       undo_clean_stack();     // removes other objects from it
+
+       block= uiBeginBlock(C, handle->region, "view3d_edit_mesh_undohistorymenu", UI_EMBOSSP, UI_HELV);
+       uiBlockSetButmFunc(block, do_editmode_undohistorymenu, NULL);
+       
+       for(uel= undobase.first; uel; uel= uel->next, item++) {
+               if (uel==curundo) uiDefBut(block, SEPR, 0, "",          0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+               uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, uel->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, (float)item, "");
+               if (uel==curundo) uiDefBut(block, SEPR, 0, "",          0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       }
+       
+       uiBlockSetDirection(block, UI_RIGHT);
+       uiTextBoundsBlock(block, 60);
+       return block;
+}
+
+void *undo_editmode_get_prev(Object *ob)
+{
+       UndoElem *ue= undobase.last;
+       if(ue && ue->prev && ue->prev->ob==ob) return ue->prev->undodata;
+       return NULL;
+}
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
new file mode 100644 (file)
index 0000000..c7d4d1a
--- /dev/null
@@ -0,0 +1,200 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.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 "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_dynstr.h"
+
+#include "BKE_utildefines.h"
+
+#include "ED_util.h"
+#include "ED_mesh.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+/* ***************** generic undo system ********************* */
+
+/* ********* XXX **************** */
+static void undo_push_curve() {}
+static void undo_push_font() {}
+static void undo_push_mball() {}
+static void undo_push_lattice() {}
+static void undo_push_armature() {}
+static void PE_undo_push() {}
+static void PE_undo() {}
+static void PE_redo() {}
+static void PE_undo_menu() {}
+static void undo_imagepaint_step() {}
+static void sound_initialize_sounds() {}
+/* ********* XXX **************** */
+
+void ED_undo_push(bContext *C, char *str)
+{
+       if(G.obedit) {
+               if (U.undosteps == 0) return;
+               
+               if(G.obedit->type==OB_MESH)
+                       undo_push_mesh(str);
+               else if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+                       undo_push_curve(str);
+               else if (G.obedit->type==OB_FONT)
+                       undo_push_font(str);
+               else if (G.obedit->type==OB_MBALL)
+                       undo_push_mball(str);
+               else if (G.obedit->type==OB_LATTICE)
+                       undo_push_lattice(str);
+               else if (G.obedit->type==OB_ARMATURE)
+                       undo_push_armature(str);
+       }
+       else if(G.f & G_PARTICLEEDIT) {
+               if (U.undosteps == 0) return;
+               
+               PE_undo_push(str);
+       }
+       else {
+               if(U.uiflag & USER_GLOBALUNDO) 
+                       BKE_write_undo(C, str);
+       }
+}
+
+static void undo_do(bContext *C)
+{
+       if(U.uiflag & USER_GLOBALUNDO) {
+#ifndef DISABLE_PYTHON
+// XXX         BPY_scripts_clear_pyobjects();
+#endif
+               BKE_undo_step(C, 1);
+               sound_initialize_sounds();
+       }
+       
+}
+
+void ED_undo(bContext *C)
+{      
+       ScrArea *sa= CTX_wm_area(C);
+       
+       if(G.obedit) {
+               if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+                       undo_editmode_step(1);
+       }
+       else {
+               if(G.f & G_TEXTUREPAINT)
+                       undo_imagepaint_step(1);
+               else if(sa->spacetype==SPACE_IMAGE) {
+                       SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
+                       if(sima->flag & SI_DRAWTOOL)
+                               undo_imagepaint_step(1);
+                       else
+                               undo_do(C);
+               }
+               else if(G.f & G_PARTICLEEDIT)
+                       PE_undo();
+               else {
+                       undo_do(C);
+               }
+       }
+}
+
+void ED_redo(bContext *C)
+{
+       ScrArea *sa= CTX_wm_area(C);
+       
+       if(G.obedit) {
+               if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+                       undo_editmode_step(-1);
+       }
+       else {
+               if(G.f & G_TEXTUREPAINT)
+                       undo_imagepaint_step(-1);
+               else if(sa->spacetype==SPACE_IMAGE) {
+                       SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
+                       if(sima->flag & SI_DRAWTOOL)
+                               undo_imagepaint_step(-1);
+                       else {
+                               BKE_undo_step(C, -1);
+                               sound_initialize_sounds();
+                       }
+               }
+               else if(G.f & G_PARTICLEEDIT)
+                       PE_redo();
+               else {
+                       /* includes faceselect now */
+                       if(U.uiflag & USER_GLOBALUNDO) {
+                               BKE_undo_step(C, -1);
+                               sound_initialize_sounds();
+                       }
+               }
+       }
+}
+
+void ED_undo_menu(bContext *C)
+{
+       if(G.obedit) {
+               if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+                       undo_editmode_menu();
+       }
+       else {
+               if(G.f & G_PARTICLEEDIT)
+                       PE_undo_menu();
+               else if(U.uiflag & USER_GLOBALUNDO) {
+                       char *menu= BKE_undo_menu_string();
+                       if(menu) {
+                               short event= 0; // XXX pupmenu_col(menu, 20);
+                               MEM_freeN(menu);
+                               if(event>0) {
+                                       BKE_undo_number(C, event);
+                                       sound_initialize_sounds();
+                               }
+                       }
+               }
+       }
+}
+