[Bf-blender-cvs] [69470e3] master: Implement grouped undo option for operators

Dalai Felinto noreply at git.blender.org
Tue Nov 15 14:25:50 CET 2016


Commit: 69470e36d6b17042260b06f26ca3c2f702747324
Author: Dalai Felinto
Date:   Tue Nov 15 11:50:11 2016 +0100
Branches: master
https://developer.blender.org/rB69470e36d6b17042260b06f26ca3c2f702747324

Implement grouped undo option for operators

This option makes an operator to not push a task to the undo stack if the previous stored elemen is the same operator or part of the same undo group.

The main usage is for animation, so you can change frames to inspect the
poses, and revert the previous pose without having to roll back tons of
"change frame" operator, or even see the undo stack full.

This complements rB13ee9b8e
Design with help by Sergey Sharybin.

Reviewers: sergey, mont29

Reviewed By: mont29, sergey

Subscribers: pyc0d3r, hjalti, Severin, lowercase, brecht, monio, aligorith, hadrien, jbakker

Differential Revision: https://developer.blender.org/D2330

===================================================================

M	source/blender/blenkernel/BKE_blender_undo.h
M	source/blender/blenkernel/intern/blender_undo.c
M	source/blender/editors/animation/anim_ops.c
M	source/blender/editors/include/ED_util.h
M	source/blender/editors/screen/screen_ops.c
M	source/blender/editors/util/undo.c
M	source/blender/makesrna/intern/rna_wm.c
M	source/blender/windowmanager/WM_types.h
M	source/blender/windowmanager/intern/wm_event_system.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 9547eeb..84a6d07 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -42,6 +42,7 @@ extern bool          BKE_undo_is_valid(const char *name);
 extern void          BKE_undo_reset(void);
 extern void          BKE_undo_number(struct bContext *C, int nr);
 extern const char   *BKE_undo_get_name(int nr, bool *r_active);
+extern const char   *BKE_undo_get_name_last(void);
 extern bool          BKE_undo_save_file(const char *filename);
 extern struct Main  *BKE_undo_get_main(struct Scene **r_scene);
 
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index d64bf7e..ce6d29b 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
 	return NULL;
 }
 
+/* return the name of the last item */
+const char *BKE_undo_get_name_last()
+{
+	UndoElem *uel = undobase.last;
+	return (uel ? uel->name : NULL);
+}
+
 /**
  * Saves .blend using undo buffer.
  *
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index d789906..c0d6963 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -57,6 +57,7 @@
 #include "ED_anim_api.h"
 #include "ED_screen.h"
 #include "ED_sequencer.h"
+#include "ED_util.h"
 
 #include "anim_intern.h"
 
@@ -263,7 +264,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
 	ot->poll = change_frame_poll;
 	
 	/* flags */
-	ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
+	ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED;
+	ot->undo_group = "FRAME_CHANGE";
 
 	/* rna */
 	ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index f596839..a4afa95 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -52,6 +52,8 @@ void    ED_OT_flush_edits(struct wmOperatorType *ot);
 /* undo.c */
 void    ED_undo_push(struct bContext *C, const char *str);
 void    ED_undo_push_op(struct bContext *C, struct wmOperator *op);
+void    ED_undo_grouped_push(struct bContext *C, const char *str);
+void    ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op);
 void    ED_undo_pop_op(struct bContext *C, struct wmOperator *op);
 void    ED_undo_pop(struct bContext *C);
 void    ED_undo_redo(struct bContext *C);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 860a865..022b860 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -2136,7 +2136,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
 	ot->exec = frame_offset_exec;
 	
 	ot->poll = ED_operator_screenactive_norender;
-	ot->flag = 0;
+	ot->flag = OPTYPE_UNDO_GROUPED;
+	ot->undo_group = "FRAME_CHANGE";
 	
 	/* rna */
 	RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
@@ -2189,7 +2190,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
 	ot->exec = frame_jump_exec;
 	
 	ot->poll = ED_operator_screenactive_norender;
-	ot->flag = OPTYPE_UNDO;
+	ot->flag = OPTYPE_UNDO_GROUPED;
+	ot->undo_group = "FRAME_CHANGE";
 	
 	/* rna */
 	RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
@@ -2295,7 +2297,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
 	ot->exec = keyframe_jump_exec;
 	
 	ot->poll = ED_operator_screenactive_norender;
-	ot->flag = OPTYPE_UNDO;
+	ot->flag = OPTYPE_UNDO_GROUPED;
+	ot->undo_group = "FRAME_CHANGE";
 	
 	/* properties */
 	RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
@@ -2357,7 +2360,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
 	ot->exec = marker_jump_exec;
 
 	ot->poll = ED_operator_screenactive_norender;
-	ot->flag = OPTYPE_UNDO;
+	ot->flag = OPTYPE_UNDO_GROUPED;
+	ot->undo_group = "FRAME_CHANGE";
 
 	/* properties */
 	RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index ee67006..4a93114 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -217,6 +217,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
 	return OPERATOR_FINISHED;
 }
 
+void ED_undo_grouped_push(bContext *C, const char *str)
+{
+	/* do nothing if previous undo task is the same as this one (or from the same undo group) */
+	const char *last_undo = BKE_undo_get_name_last();
+
+	if (last_undo && STREQ(str, last_undo)) {
+		return;
+	}
+
+	/* push as usual */
+	ED_undo_push(C, str);
+}
+
 void ED_undo_pop(bContext *C)
 {
 	ed_undo_step(C, 1, NULL);
@@ -232,6 +245,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op)
 	ED_undo_push(C, op->type->name);
 }
 
+void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
+{
+	if (op->type->undo_group[0] != '\0') {
+		ED_undo_grouped_push(C, op->type->undo_group);
+	}
+	else {
+		ED_undo_grouped_push(C, op->type->name);
+	}
+}
+
 void ED_undo_pop_op(bContext *C, wmOperator *op)
 {
 	/* search back a couple of undo's, in case something else added pushes */
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 90081a9..35c9c9b 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = {
 static EnumPropertyItem operator_flag_items[] = {
 	{OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"},
 	{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
+	{OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"},
 	{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
 	{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
 	{OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
@@ -1139,6 +1140,7 @@ static char _operator_idname[OP_MAX_TYPENAME];
 static char _operator_name[OP_MAX_TYPENAME];
 static char _operator_descr[RNA_DYN_DESCR_MAX];
 static char _operator_ctxt[RNA_DYN_DESCR_MAX];
+static char _operator_undo_group[OP_MAX_TYPENAME];
 static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                         StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
@@ -1153,10 +1155,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
 	dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
 	dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
 	dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+	dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
 	RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
 
 	/* clear in case they are left unset */
-	_operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+	_operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
 	/* We have to set default op context! */
 	strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
 
@@ -1210,9 +1213,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
 			int namelen = strlen(_operator_name) + 1;
 			int desclen = strlen(_operator_descr) + 1;
 			int ctxtlen = strlen(_operator_ctxt) + 1;
+			int ugrouplen = strlen(_operator_undo_group) + 1;
 			char *ch;
 			/* 2 terminators and 3 to convert a.b -> A_OT_b */
-			ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+			ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
 			WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
 			dummyot.idname = ch;
 			ch += idlen;
@@ -1224,6 +1228,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
 			ch += desclen;
 			strcpy(ch, _operator_ctxt);
 			dummyot.translation_context = ch;
+			ch += ctxtlen;
+			strcpy(ch, _operator_undo_group);
+			dummyot.undo_group = ch;
 		}
 	}
 
@@ -1280,10 +1287,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
 	dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
 	dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
 	dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
+	dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */
 	RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
 
 	/* clear in case they are left unset */
-	_operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+	_operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0';
 	/* We have to set default op context! */
 	strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
 
@@ -1297,9 +1305,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
 		int namelen = strlen(_operator_name) + 1;
 		int desclen = strlen(_operator_descr) + 1;
 		int ctxtlen = strlen(_operator_ctxt) + 1;
+		int ugrouplen = strlen(_operator_undo_group) + 1;
 		char *ch;
 		/* 2 terminators and 3 to convert a.b -> A_OT_b */
-		ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
+		ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname");
 		WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
 		dummyot.id

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list