Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2008-12-30 22:01:12 +0300
committerTon Roosendaal <ton@blender.org>2008-12-30 22:01:12 +0300
commit47796b75ff5dc43d38d21f6cf091a6c88478e571 (patch)
treee89202ad8bf27f9657bb42a37f7d00f3fda82ed8 /source/blender/editors
parent14d1538941791513be70ef51bd956b425011d17f (diff)
2.5
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
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/ED_mesh.h1
-rw-r--r--source/blender/editors/include/ED_util.h24
-rw-r--r--source/blender/editors/mesh/editmesh.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c65
-rw-r--r--source/blender/editors/util/editmode_undo.c346
-rw-r--r--source/blender/editors/util/undo.c200
6 files changed, 609 insertions, 38 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 2437542a75a..a7fe669e72e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -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 */
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 93bb5ef1208..49aee466562 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -28,6 +28,30 @@
#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);
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
index e723fb2375e..76f7748839f 100644
--- a/source/blender/editors/mesh/editmesh.c
+++ b/source/blender/editors/mesh/editmesh.c
@@ -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;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index fbf437e5599..040913d8e6f 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -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
index 00000000000..05813b72ad0
--- /dev/null
+++ b/source/blender/editors/util/editmode_undo.c
@@ -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
index 00000000000..c7d4d1a2719
--- /dev/null
+++ b/source/blender/editors/util/undo.c
@@ -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();
+ }
+ }
+ }
+ }
+}
+