| 
									
										
										
										
											2011-02-23 10:52:22 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  |  * ***** 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, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 ***** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 20:29:51 +00:00
										 |  |  | /** \file blender/editors/util/editmode_undo.c
 | 
					
						
							|  |  |  |  *  \ingroup edutil | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <math.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DNA_object_types.h"
 | 
					
						
							|  |  |  | #include "DNA_screen_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h"
 | 
					
						
							|  |  |  | #include "BLI_dynstr.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 18:36:47 +00:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-10 01:55:58 +00:00
										 |  |  | #include "BKE_blender.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | #include "BKE_context.h"
 | 
					
						
							|  |  |  | #include "BKE_depsgraph.h"
 | 
					
						
							|  |  |  | #include "BKE_global.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-14 17:55:27 +00:00
										 |  |  | #include "ED_util.h"
 | 
					
						
							| 
									
										
										
										
											2010-02-02 18:24:10 +00:00
										 |  |  | #include "ED_mesh.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "UI_interface.h"
 | 
					
						
							|  |  |  | #include "UI_resources.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-14 17:55:27 +00:00
										 |  |  | #include "util_intern.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | /* ***************** generic editmode undo system ********************* */ | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2012-03-03 16:31:46 +00:00
										 |  |  |  * Add this in your local code: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * void undo_editmode_push(bContext *C, const char *name,  | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  |  *      void * (*getdata)(bContext *C),     // use context to retrieve current editdata
 | 
					
						
							|  |  |  |  *      void (*freedata)(void *),           // pointer to function freeing data
 | 
					
						
							|  |  |  |  *      void (*to_editmode)(void *, void *),        // data to editmode conversion
 | 
					
						
							|  |  |  |  *      void * (*from_editmode)(void *))      // editmode to data conversion
 | 
					
						
							|  |  |  |  *      int  (*validate_undo)(void *, void *))      // check if undo data is still valid
 | 
					
						
							| 
									
										
										
										
											2012-03-03 16:31:46 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Further exported for UI is: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * void undo_editmode_step(bContext *C, int step);	 // undo and redo
 | 
					
						
							|  |  |  |  * void undo_editmode_clear(void)				// free & clear all data
 | 
					
						
							|  |  |  |  * void undo_editmode_menu(void)				// history menu
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* ********************************************************************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ****** XXX ***** */ | 
					
						
							| 
									
										
										
										
											2011-02-14 17:55:27 +00:00
										 |  |  | static void error(const char *UNUSED(arg)) {} | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | /* ****** XXX ***** */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct UndoElem { | 
					
						
							|  |  |  | 	struct UndoElem *next, *prev; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	ID id;          // copy of editmode object ID
 | 
					
						
							|  |  |  | 	Object *ob;     // pointer to edited object
 | 
					
						
							|  |  |  | 	int type;       // type of edited object
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	void *undodata; | 
					
						
							|  |  |  | 	uintptr_t undosize; | 
					
						
							| 
									
										
										
										
											2012-09-10 01:55:58 +00:00
										 |  |  | 	char name[BKE_UNDO_STR_MAX]; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	void * (*getdata)(bContext * C); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	void (*freedata)(void *); | 
					
						
							| 
									
										
										
										
											2009-11-02 16:01:24 +00:00
										 |  |  | 	void (*to_editmode)(void *, void *, void *); | 
					
						
							|  |  |  | 	void * (*from_editmode)(void *, void *); | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 	int (*validate_undo)(void *, void *); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | } UndoElem; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | static ListBase undobase = {NULL, NULL}; | 
					
						
							|  |  |  | static UndoElem *curundo = NULL; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ********************* xtern api calls ************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 16:01:24 +00:00
										 |  |  | static void undo_restore(UndoElem *undo, void *editdata, void *obdata) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (undo) { | 
					
						
							| 
									
										
										
										
											2012-10-21 05:46:41 +00:00
										 |  |  | 		undo->to_editmode(undo->undodata, editdata, obdata); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* name can be a dynamic string */ | 
					
						
							| 
									
										
										
										
											2010-11-17 09:45:45 +00:00
										 |  |  | void undo_editmode_push(bContext *C, const char *name,  | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  |                         void * (*getdata)(bContext * C), | 
					
						
							|  |  |  |                         void (*freedata)(void *), | 
					
						
							|  |  |  |                         void (*to_editmode)(void *, void *, void *), | 
					
						
							|  |  |  |                         void *(*from_editmode)(void *, void *), | 
					
						
							|  |  |  |                         int (*validate_undo)(void *, void *)) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 	void *editdata; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	int nr; | 
					
						
							|  |  |  | 	uintptr_t memused, totmem, maxmem; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-04 04:35:12 +00:00
										 |  |  | 	/* at first here was code to prevent an "original" key to be inserted twice
 | 
					
						
							| 
									
										
										
										
											2012-03-03 16:31:46 +00:00
										 |  |  | 	 * this was giving conflicts for example when mesh changed due to keys or apply */ | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-05-25 09:51:53 +00:00
										 |  |  | 	/* remove all undos after (also when curundo == NULL) */ | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	while (undobase.last != curundo) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		uel = undobase.last; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		uel->freedata(uel->undodata); | 
					
						
							|  |  |  | 		BLI_freelinkN(&undobase, uel); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* make new */ | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode"); | 
					
						
							| 
									
										
										
										
											2011-09-26 18:51:10 +00:00
										 |  |  | 	BLI_strncpy(uel->name, name, sizeof(uel->name)); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	BLI_addtail(&undobase, uel); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	uel->getdata = getdata; | 
					
						
							|  |  |  | 	uel->freedata = freedata; | 
					
						
							|  |  |  | 	uel->to_editmode = to_editmode; | 
					
						
							|  |  |  | 	uel->from_editmode = from_editmode; | 
					
						
							|  |  |  | 	uel->validate_undo = validate_undo; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	/* limit amount to the maximum amount*/ | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	nr = 0; | 
					
						
							|  |  |  | 	uel = undobase.last; | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	while (uel) { | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		nr++; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		if (nr == U.undosteps) break; | 
					
						
							|  |  |  | 		uel = uel->prev; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (uel) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		while (undobase.first != uel) { | 
					
						
							|  |  |  | 			UndoElem *first = undobase.first; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 			first->freedata(first->undodata); | 
					
						
							|  |  |  | 			BLI_freelinkN(&undobase, first); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* copy  */ | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	memused = MEM_get_memory_in_use(); | 
					
						
							|  |  |  | 	editdata = getdata(C); | 
					
						
							|  |  |  | 	curundo->undodata = curundo->from_editmode(editdata, obedit->data); | 
					
						
							|  |  |  | 	curundo->undosize = MEM_get_memory_in_use() - memused; | 
					
						
							|  |  |  | 	curundo->ob = obedit; | 
					
						
							|  |  |  | 	curundo->id = obedit->id; | 
					
						
							|  |  |  | 	curundo->type = obedit->type; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (U.undomemory != 0) { | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		/* limit to maximum memory (afterwards, we can't know in advance) */ | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		totmem = 0; | 
					
						
							|  |  |  | 		maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		uel = undobase.last; | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 		while (uel && uel->prev) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 			totmem += uel->undosize; | 
					
						
							|  |  |  | 			if (totmem > maxmem) break; | 
					
						
							|  |  |  | 			uel = uel->prev; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 		if (uel) { | 
					
						
							|  |  |  | 			if (uel->prev && uel->prev->prev) | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 				uel = uel->prev; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 			while (undobase.first != uel) { | 
					
						
							|  |  |  | 				UndoElem *first = undobase.first; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 				first->freedata(first->undodata); | 
					
						
							|  |  |  | 				BLI_freelinkN(&undobase, first); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* helper to remove clean other objects from undo stack */ | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | static void undo_clean_stack(bContext *C) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel, *next; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	/* global undo changes pointers, so we also allow identical names */ | 
					
						
							|  |  |  | 	/* side effect: when deleting/renaming object and start editing new one with same name */ | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	uel = undobase.first; | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	while (uel) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		void *editdata = uel->getdata(C); | 
					
						
							| 
									
										
										
										
											2012-05-19 13:28:19 +00:00
										 |  |  | 		int is_valid = FALSE; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		next = uel->next; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		/* for when objects are converted, renamed, or global undo changes pointers... */ | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		if (uel->type == obedit->type) { | 
					
						
							|  |  |  | 			if (strcmp(uel->id.name, obedit->id.name) == 0) { | 
					
						
							|  |  |  | 				if (uel->validate_undo == NULL) | 
					
						
							| 
									
										
										
										
											2012-05-19 13:28:19 +00:00
										 |  |  | 					is_valid = TRUE; | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 				else if (uel->validate_undo(uel->undodata, editdata)) | 
					
						
							| 
									
										
										
										
											2012-05-19 13:28:19 +00:00
										 |  |  | 					is_valid = TRUE; | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-05-19 13:28:19 +00:00
										 |  |  | 		if (is_valid) | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 			uel->ob = obedit; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 			if (uel == curundo) | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 				curundo = NULL; | 
					
						
							| 
									
										
										
										
											2010-01-26 15:54:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 			uel->freedata(uel->undodata); | 
					
						
							|  |  |  | 			BLI_freelinkN(&undobase, uel); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		uel = next; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	if (curundo == NULL) curundo = undobase.last; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | void undo_editmode_step(bContext *C, int step) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	/* prevent undo to happen on wrong object, stack can be a mix */ | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 	undo_clean_stack(C); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	if (step == 0) { | 
					
						
							| 
									
										
										
										
											2009-11-07 23:10:18 +00:00
										 |  |  | 		undo_restore(curundo, curundo->getdata(C), obedit->data); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	else if (step == 1) { | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		if (curundo == NULL || curundo->prev == NULL) error("No more steps to undo"); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2012-03-31 00:59:17 +00:00
										 |  |  | 			if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name); | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 			curundo = curundo->prev; | 
					
						
							| 
									
										
										
										
											2009-11-07 23:10:18 +00:00
										 |  |  | 			undo_restore(curundo, curundo->getdata(C), obedit->data); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		/* curundo has to remain current situation! */ | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		if (curundo == NULL || curundo->next == NULL) error("No more steps to redo"); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2009-11-07 23:10:18 +00:00
										 |  |  | 			undo_restore(curundo->next, curundo->getdata(C), obedit->data); | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 			curundo = curundo->next; | 
					
						
							| 
									
										
										
										
											2012-03-31 00:59:17 +00:00
										 |  |  | 			if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-05 09:57:43 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-01-30 16:09:56 +00:00
										 |  |  | 	/* special case for editmesh, mode must be copied back to the scene */ | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (obedit->type == OB_MESH) { | 
					
						
							| 
									
										
										
										
											2011-10-15 14:47:37 +00:00
										 |  |  | 		EDBM_selectmode_to_scene(C); | 
					
						
							| 
									
										
										
										
											2010-01-30 16:09:56 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-05 18:59:23 +00:00
										 |  |  | 	DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* XXX notifiers */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void undo_editmode_clear(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	uel = undobase.first; | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	while (uel) { | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 		uel->freedata(uel->undodata); | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		uel = uel->next; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	BLI_freelistN(&undobase); | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	curundo = NULL; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* based on index nr it does a restore */ | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | void undo_editmode_number(bContext *C, int nr) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel; | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	int a = 1; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	for (uel = undobase.first; uel; uel = uel->next, a++) { | 
					
						
							|  |  |  | 		if (a == nr) break; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	curundo = uel; | 
					
						
							| 
									
										
										
										
											2009-01-01 13:15:35 +00:00
										 |  |  | 	undo_editmode_step(C, 0); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												2.5
Operator goodies!
--- Macro operators
Operators now can consist of multiple operators. Such a macro operator
is identical and behaves identical to other opererators. Macros can
also be constructed of macros even! Currently only hardcoded macros are
implemented, this to solve combined operators such as 'add duplicate' or
'extrude' (both want a transform appended).
Usage is simple:
- WM_operatortype_append_macro() : add new operatortype, name, flags
- WM_operatortype_macro_define() : add existing operator to macro
(Note: macro_define will also allow properties to be set, doesnt work
 right now)
On converting the macro wmOperatorType to a real operator, it makes a
list of all operators, and the standard macro callbacks (exec, invoke,
modal, poll) just will use all.
Important note; switching to a modal operator only works as last in the
chain now!
Macros implemented for duplicate, extrude and rip. Tool menu works fine
for it, also the redo hotkey F4 works properly.
--- Operator redo fix
The operators use the undo system to switch back, but this could give
errors if other actions added undo pushes (buttons, outliner). Now the
redo for operator searches back for the correct undo level.
This fixes issues with many redos.
Note for brecht: removed the ED_undo_push for buttons... it was called
on *every* button now, which is probably too much? For example, using
the 'toolbar' redo also caused this...
											
										 
											2009-07-29 17:56:38 +00:00
										 |  |  | void undo_editmode_name(bContext *C, const char *undoname) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	for (uel = undobase.last; uel; uel = uel->prev) { | 
					
						
							|  |  |  | 		if (strcmp(undoname, uel->name) == 0) | 
					
						
							| 
									
										
											  
											
												2.5
Operator goodies!
--- Macro operators
Operators now can consist of multiple operators. Such a macro operator
is identical and behaves identical to other opererators. Macros can
also be constructed of macros even! Currently only hardcoded macros are
implemented, this to solve combined operators such as 'add duplicate' or
'extrude' (both want a transform appended).
Usage is simple:
- WM_operatortype_append_macro() : add new operatortype, name, flags
- WM_operatortype_macro_define() : add existing operator to macro
(Note: macro_define will also allow properties to be set, doesnt work
 right now)
On converting the macro wmOperatorType to a real operator, it makes a
list of all operators, and the standard macro callbacks (exec, invoke,
modal, poll) just will use all.
Important note; switching to a modal operator only works as last in the
chain now!
Macros implemented for duplicate, extrude and rip. Tool menu works fine
for it, also the redo hotkey F4 works properly.
--- Operator redo fix
The operators use the undo system to switch back, but this could give
errors if other actions added undo pushes (buttons, outliner). Now the
redo for operator searches back for the correct undo level.
This fixes issues with many redos.
Note for brecht: removed the ED_undo_push for buttons... it was called
on *every* button now, which is probably too much? For example, using
the 'toolbar' redo also caused this...
											
										 
											2009-07-29 17:56:38 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (uel && uel->prev) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		curundo = uel->prev; | 
					
						
							| 
									
										
											  
											
												2.5
Operator goodies!
--- Macro operators
Operators now can consist of multiple operators. Such a macro operator
is identical and behaves identical to other opererators. Macros can
also be constructed of macros even! Currently only hardcoded macros are
implemented, this to solve combined operators such as 'add duplicate' or
'extrude' (both want a transform appended).
Usage is simple:
- WM_operatortype_append_macro() : add new operatortype, name, flags
- WM_operatortype_macro_define() : add existing operator to macro
(Note: macro_define will also allow properties to be set, doesnt work
 right now)
On converting the macro wmOperatorType to a real operator, it makes a
list of all operators, and the standard macro callbacks (exec, invoke,
modal, poll) just will use all.
Important note; switching to a modal operator only works as last in the
chain now!
Macros implemented for duplicate, extrude and rip. Tool menu works fine
for it, also the redo hotkey F4 works properly.
--- Operator redo fix
The operators use the undo system to switch back, but this could give
errors if other actions added undo pushes (buttons, outliner). Now the
redo for operator searches back for the correct undo level.
This fixes issues with many redos.
Note for brecht: removed the ED_undo_push for buttons... it was called
on *every* button now, which is probably too much? For example, using
the 'toolbar' redo also caused this...
											
										 
											2009-07-29 17:56:38 +00:00
										 |  |  | 		undo_editmode_step(C, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-12 18:00:23 +00:00
										 |  |  | /* undoname optionally, if NULL it just checks for existing undo steps */ | 
					
						
							|  |  |  | int undo_editmode_valid(const char *undoname) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (undoname) { | 
					
						
							| 
									
										
										
										
											2011-01-12 18:00:23 +00:00
										 |  |  | 		UndoElem *uel; | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		for (uel = undobase.last; uel; uel = uel->prev) { | 
					
						
							|  |  |  | 			if (strcmp(undoname, uel->name) == 0) | 
					
						
							| 
									
										
										
										
											2011-01-12 18:00:23 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return uel != NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return undobase.last != undobase.first; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
											  
											
												2.5
Operator goodies!
--- Macro operators
Operators now can consist of multiple operators. Such a macro operator
is identical and behaves identical to other opererators. Macros can
also be constructed of macros even! Currently only hardcoded macros are
implemented, this to solve combined operators such as 'add duplicate' or
'extrude' (both want a transform appended).
Usage is simple:
- WM_operatortype_append_macro() : add new operatortype, name, flags
- WM_operatortype_macro_define() : add existing operator to macro
(Note: macro_define will also allow properties to be set, doesnt work
 right now)
On converting the macro wmOperatorType to a real operator, it makes a
list of all operators, and the standard macro callbacks (exec, invoke,
modal, poll) just will use all.
Important note; switching to a modal operator only works as last in the
chain now!
Macros implemented for duplicate, extrude and rip. Tool menu works fine
for it, also the redo hotkey F4 works properly.
--- Operator redo fix
The operators use the undo system to switch back, but this could give
errors if other actions added undo pushes (buttons, outliner). Now the
redo for operator searches back for the correct undo level.
This fixes issues with many redos.
Note for brecht: removed the ED_undo_push for buttons... it was called
on *every* button now, which is probably too much? For example, using
the 'toolbar' redo also caused this...
											
										 
											2009-07-29 17:56:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | /* get name of undo item, return null if no item with this index */ | 
					
						
							|  |  |  | /* if active pointer, set it to 1 if true */ | 
					
						
							| 
									
										
										
										
											2011-11-05 11:04:28 +00:00
										 |  |  | const char *undo_editmode_get_name(bContext *C, int nr, int *active) | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	UndoElem *uel; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | 	/* prevent wrong numbers to be returned */ | 
					
						
							|  |  |  | 	undo_clean_stack(C); | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	if (active) *active = 0; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	uel = BLI_findlink(&undobase, nr); | 
					
						
							| 
									
										
										
										
											2012-03-24 06:38:07 +00:00
										 |  |  | 	if (uel) { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 		if (active && uel == curundo) | 
					
						
							|  |  |  | 			*active = 1; | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | 		return uel->name; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | 	return NULL; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												Code holiday commit:
- fix: user pref, window title was reset to 'Blender' on tab usage
- Undo history menu back:
  - name "Undo History"
  - hotkey alt+ctrl+z (alt+apple+z for mac)
  - works like 2.4x, only for global undo, editmode and particle edit.
- Menu scroll
  - for small windows or screens, popup menus now allow to display
    all items, using internal scrolling
  - works with a timer, scrolling 10 items per second when mouse 
    is over the top or bottom arrow
  - if menu is too big to display, it now draws to top or bottom, 
    based on largest available space.
  - also works for hotkey driven pop up menus.
- User pref "DPI" follows widget/layout size
  - widgets & headers now become bigger and smaller, to match 
    'dpi' font sizes. Works well to match UI to monitor size.
  - note that icons can get fuzzy, we need better mipmaps for it
											
										 
											2011-06-04 17:03:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | void *undo_editmode_get_prev(Object *ob) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-30 10:00:20 +00:00
										 |  |  | 	UndoElem *ue = undobase.last; | 
					
						
							|  |  |  | 	if (ue && ue->prev && ue->prev->ob == ob) return ue->prev->undodata; | 
					
						
							| 
									
										
										
										
											2008-12-30 19:01:12 +00:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | } |