Merging r39948 through r39988 from trunk into vgroup_modifiers.
[blender.git] / source / blender / editors / util / undo.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2004 Blender Foundation
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/util/undo.c
31  *  \ingroup edutil
32  */
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "DNA_object_types.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_editVert.h"
46 #include "BLI_dynstr.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_blender.h"
50 #include "BKE_context.h"
51 #include "BKE_global.h"
52 #include "BKE_screen.h"
53
54 #include "ED_armature.h"
55 #include "ED_particle.h"
56 #include "ED_curve.h"
57 #include "ED_gpencil.h"
58 #include "ED_mball.h"
59 #include "ED_mesh.h"
60 #include "ED_object.h"
61 #include "ED_screen.h"
62 #include "ED_sculpt.h"
63 #include "ED_util.h"
64 #include "ED_text.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74
75 #include "util_intern.h"
76
77 #define MAXUNDONAME 64 /* XXX, make common define */
78
79 /* ***************** generic undo system ********************* */
80
81 void ED_undo_push(bContext *C, const char *str)
82 {
83         wmWindowManager *wm= CTX_wm_manager(C);
84         Object *obedit= CTX_data_edit_object(C);
85         Object *obact= CTX_data_active_object(C);
86
87         if (G.f & G_DEBUG)
88                 printf("undo push %s\n", str);
89         
90         if(obedit) {
91                 if (U.undosteps == 0) return;
92                 
93                 if(obedit->type==OB_MESH)
94                         undo_push_mesh(C, str);
95                 else if ELEM(obedit->type, OB_CURVE, OB_SURF)
96                         undo_push_curve(C, str);
97                 else if (obedit->type==OB_FONT)
98                         undo_push_font(C, str);
99                 else if (obedit->type==OB_MBALL)
100                         undo_push_mball(C, str);
101                 else if (obedit->type==OB_LATTICE)
102                         undo_push_lattice(C, str);
103                 else if (obedit->type==OB_ARMATURE)
104                         undo_push_armature(C, str);
105         }
106         else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
107                 if (U.undosteps == 0) return;
108                 
109                 PE_undo_push(CTX_data_scene(C), str);
110         }
111         else {
112                 if(U.uiflag & USER_GLOBALUNDO) 
113                         BKE_write_undo(C, str);
114         }
115         
116         if(wm->file_saved) {
117                 wm->file_saved= 0;
118                 /* notifier that data changed, for save-over warning or header */
119                 WM_event_add_notifier(C, NC_WM|ND_DATACHANGED, NULL);
120         }
121 }
122
123 /* note: also check undo_history_exec() in bottom if you change notifiers */
124 static int ed_undo_step(bContext *C, int step, const char *undoname)
125 {       
126         Object *obedit= CTX_data_edit_object(C);
127         Object *obact= CTX_data_active_object(C);
128         ScrArea *sa= CTX_wm_area(C);
129
130         /* grease pencil can be can be used in plenty of spaces, so check it first */
131         if(ED_gpencil_session_active()) {
132                 return ED_undo_gpencil_step(C, step, undoname);
133         }
134
135         if(sa && sa->spacetype==SPACE_IMAGE) {
136                 SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
137                 
138                 if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
139                         if(!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname)
140                                 if(U.uiflag & USER_GLOBALUNDO)
141                                         BKE_undo_name(C, undoname);
142
143                         WM_event_add_notifier(C, NC_WINDOW, NULL);
144                         return OPERATOR_FINISHED;
145                 }
146         }
147
148         if(sa && sa->spacetype==SPACE_TEXT) {
149                 ED_text_undo_step(C, step);
150         }
151         else if(obedit) {
152                 if ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE) {
153                         if(undoname)
154                                 undo_editmode_name(C, undoname);
155                         else
156                                 undo_editmode_step(C, step);
157
158                         WM_event_add_notifier(C, NC_GEOM|ND_DATA, NULL);
159                 }
160         }
161         else {
162                 int do_glob_undo= 0;
163                 
164                 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
165                         if(!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname))
166                                 do_glob_undo= 1;
167                 }
168                 else if(obact && obact->mode & OB_MODE_SCULPT) {
169                         if(!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname))
170                                 do_glob_undo= 1;
171                 }
172                 else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
173                         if(step==1)
174                                 PE_undo(CTX_data_scene(C));
175                         else
176                                 PE_redo(CTX_data_scene(C));
177                 }
178                 else {
179                         do_glob_undo= 1;
180                 }
181                 
182                 if(do_glob_undo) {
183                         if(U.uiflag & USER_GLOBALUNDO) {
184                                 // note python defines not valid here anymore.
185                                 //#ifdef WITH_PYTHON
186                                 // XXX          BPY_scripts_clear_pyobjects();
187                                 //#endif
188                                 if(undoname)
189                                         BKE_undo_name(C, undoname);
190                                 else
191                                         BKE_undo_step(C, step);
192
193                                 WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, CTX_data_scene(C));
194                         }
195                         
196                 }
197         }
198         
199         WM_event_add_notifier(C, NC_WINDOW, NULL);
200         
201         return OPERATOR_FINISHED;
202 }
203
204 void ED_undo_pop(bContext *C)
205 {
206         ed_undo_step(C, 1, NULL);
207 }
208 void ED_undo_redo(bContext *C)
209 {
210         ed_undo_step(C, -1, NULL);
211 }
212
213 void ED_undo_push_op(bContext *C, wmOperator *op)
214 {
215         /* in future, get undo string info? */
216         ED_undo_push(C, op->type->name);
217 }
218
219 void ED_undo_pop_op(bContext *C, wmOperator *op)
220 {
221         /* search back a couple of undo's, in case something else added pushes */
222         ed_undo_step(C, 0, op->type->name);
223 }
224
225 /* name optionally, function used to check for operator redo panel */
226 int ED_undo_valid(const bContext *C, const char *undoname)
227 {
228         Object *obedit= CTX_data_edit_object(C);
229         Object *obact= CTX_data_active_object(C);
230         ScrArea *sa= CTX_wm_area(C);
231         
232         if(sa && sa->spacetype==SPACE_IMAGE) {
233                 SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
234                 
235                 if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
236                         return 1;
237                 }
238         }
239         
240         if(sa && sa->spacetype==SPACE_TEXT) {
241                 return 1;
242         }
243         else if(obedit) {
244                 if ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE) {
245                         return undo_editmode_valid(undoname);
246                 }
247         }
248         else {
249                 
250                 /* if below tests fail, global undo gets executed */
251                 
252                 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
253                         if( ED_undo_paint_valid(UNDO_PAINT_IMAGE, undoname) )
254                                 return 1;
255                 }
256                 else if(obact && obact->mode & OB_MODE_SCULPT) {
257                         if( ED_undo_paint_valid(UNDO_PAINT_MESH, undoname) )
258                                 return 1;
259                 }
260                 else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
261                         return PE_undo_valid(CTX_data_scene(C));
262                 }
263                 
264                 if(U.uiflag & USER_GLOBALUNDO) {
265                         return BKE_undo_valid(undoname);
266                 }
267         }
268         return 0;
269 }
270
271 static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
272 {
273         /* "last operator" should disappear, later we can tie ths with undo stack nicer */
274         WM_operator_stack_clear(CTX_wm_manager(C));
275         return ed_undo_step(C, 1, NULL);
276 }
277
278 static int ed_undo_push_exec(bContext *C, wmOperator *op)
279 {
280         char str[MAXUNDONAME];
281         RNA_string_get(op->ptr, "message", str);
282         ED_undo_push(C, str);
283         return OPERATOR_FINISHED;
284 }
285
286 static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
287 {
288         return ed_undo_step(C, -1, NULL);
289 }
290
291
292 /* ********************** */
293
294 void ED_OT_undo(wmOperatorType *ot)
295 {
296         /* identifiers */
297         ot->name= "Undo";
298         ot->description= "Undo previous action";
299         ot->idname= "ED_OT_undo";
300         
301         /* api callbacks */
302         ot->exec= ed_undo_exec;
303         ot->poll= ED_operator_screenactive;
304 }
305
306 void ED_OT_undo_push(wmOperatorType *ot)
307 {
308         /* identifiers */
309         ot->name= "Undo Push";
310         ot->description= "Add an undo state (internal use only)";
311         ot->idname= "ED_OT_undo_push";
312         
313         /* api callbacks */
314         ot->exec= ed_undo_push_exec;
315
316         ot->flag= OPTYPE_INTERNAL;
317
318         RNA_def_string(ot->srna, "message", "Add an undo step *function may be moved*", MAXUNDONAME, "Undo Message", "");
319 }
320
321 void ED_OT_redo(wmOperatorType *ot)
322 {
323         /* identifiers */
324         ot->name= "Redo";
325         ot->description= "Redo previous action";
326         ot->idname= "ED_OT_redo";
327         
328         /* api callbacks */
329         ot->exec= ed_redo_exec;
330         ot->poll= ED_operator_screenactive;
331 }
332
333
334 /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
335 int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
336 {
337         int ret= 0;
338
339         if(op) {
340                 ARegion *ar= CTX_wm_region(C);
341                 ARegion *ar1= BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_WINDOW);
342
343                 if(ar1)
344                         CTX_wm_region_set(C, ar1);
345
346                 if(WM_operator_repeat_check(C, op) && WM_operator_poll(C, op->type)) {
347                         int retval;
348
349                         if (G.f & G_DEBUG)
350                                 printf("redo_cb: operator redo %s\n", op->type->name);
351                         ED_undo_pop_op(C, op);
352
353                         if(op->type->check) {
354                                 op->type->check(C, op); /* ignore return value since its running again anyway */
355                         }
356
357                         retval= WM_operator_repeat(C, op);
358                         if((retval & OPERATOR_FINISHED)==0) {
359                                 if (G.f & G_DEBUG)
360                                         printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
361                                 ED_undo_redo(C);
362                         }
363                         else {
364                                 ret= 1;
365                         }
366                 }
367                 else {
368                         if (G.f & G_DEBUG) {
369                                 printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
370                         }
371                 }
372
373                 /* set region back */
374                 CTX_wm_region_set(C, ar);
375         }
376         else {
377                 if (G.f & G_DEBUG) {
378                         printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n");
379                 }
380         }
381
382         return ret;
383 }
384
385
386 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
387 {
388         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
389 }
390
391 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_event))
392 {
393         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
394 }
395
396
397 /* ************************** */
398
399 #define UNDOSYSTEM_GLOBAL       1
400 #define UNDOSYSTEM_EDITMODE     2
401 #define UNDOSYSTEM_PARTICLE     3
402
403 static int get_undo_system(bContext *C)
404 {
405         Object *obedit= CTX_data_edit_object(C);
406         
407         /* find out which undo system */
408         if(obedit) {
409                 if (ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
410                         return UNDOSYSTEM_EDITMODE;
411         }
412         else {
413                 Object *obact= CTX_data_active_object(C);
414                 
415                 if(obact && obact->mode & OB_MODE_PARTICLE_EDIT)
416                         return UNDOSYSTEM_PARTICLE;
417                 else if(U.uiflag & USER_GLOBALUNDO)
418                         return UNDOSYSTEM_GLOBAL;
419         }
420         
421         return 0;
422 }
423
424 /* create enum based on undo items */
425 static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
426 {
427         EnumPropertyItem item_tmp= {0}, *item= NULL;
428         int active, i= 0;
429         
430         while(TRUE) {
431                 char *name= NULL;
432                 
433                 if(undosys==UNDOSYSTEM_PARTICLE) {
434                         name= PE_undo_get_name(CTX_data_scene(C), i, &active);
435                 }
436                 else if(undosys==UNDOSYSTEM_EDITMODE) {
437                         name= undo_editmode_get_name(C, i, &active);
438                 }
439                 else {
440                         name= BKE_undo_get_name(i, &active);
441                 }
442                 
443                 if(name) {
444                         item_tmp.identifier= item_tmp.name= name;
445                         if(active)
446                                 item_tmp.icon= ICON_RESTRICT_VIEW_OFF;
447                         else 
448                                 item_tmp.icon= ICON_NONE;
449                         item_tmp.value= i++;
450                         RNA_enum_item_add(&item, totitem, &item_tmp);
451                 }
452                 else
453                         break;
454         }
455         
456         RNA_enum_item_end(&item, totitem);
457         
458         return item;
459 }
460
461
462 static int undo_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
463 {
464         int undosys, totitem= 0;
465         
466         undosys= get_undo_system(C);
467         
468         if(undosys) {
469                 EnumPropertyItem *item= rna_undo_itemf(C, undosys, &totitem);
470                 
471                 if(totitem > 0) {
472                         uiPopupMenu *pup= uiPupMenuBegin(C, op->type->name, ICON_NONE);
473                         uiLayout *layout= uiPupMenuLayout(pup);
474                         uiLayout *split= uiLayoutSplit(layout, 0, 0), *column;
475                         int i, c;
476                         
477                         for(c=0, i=totitem-1; i >= 0; i--, c++) {
478                                 if( (c % 20)==0 )
479                                         column= uiLayoutColumn(split, 0);
480                                 if(item[i].identifier)
481                                         uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
482                                 
483                         }
484                         
485                         MEM_freeN(item);
486                         
487                         uiPupMenuEnd(C, pup);
488                 }               
489                 
490         }
491         return OPERATOR_CANCELLED;
492 }
493
494 /* note: also check ed_undo_step() in top if you change notifiers */
495 static int undo_history_exec(bContext *C, wmOperator *op)
496 {
497         if(RNA_property_is_set(op->ptr, "item")) {
498                 int undosys= get_undo_system(C);
499                 int item= RNA_int_get(op->ptr, "item");
500                 
501                 if(undosys==UNDOSYSTEM_PARTICLE) {
502                         PE_undo_number(CTX_data_scene(C), item);
503                 }
504                 else if(undosys==UNDOSYSTEM_EDITMODE) {
505                         undo_editmode_number(C, item+1);
506                         WM_event_add_notifier(C, NC_GEOM|ND_DATA, NULL);
507                 }
508                 else {
509                         BKE_undo_number(C, item);
510                         WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, CTX_data_scene(C));
511                 }
512                 WM_event_add_notifier(C, NC_WINDOW, NULL);
513                 
514                 return OPERATOR_FINISHED;
515         }
516         return OPERATOR_CANCELLED;
517 }
518
519 void ED_OT_undo_history(wmOperatorType *ot)
520 {
521         /* identifiers */
522         ot->name= "Undo History";
523         ot->description= "Redo specific action in history";
524         ot->idname= "ED_OT_undo_history";
525         
526         /* api callbacks */
527         ot->invoke= undo_history_invoke;
528         ot->exec= undo_history_exec;
529         ot->poll= ED_operator_screenactive;
530         
531         RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
532
533 }
534
535