[Bf-blender-cvs] [c080572] master: GPencil Editing: Copy and Paste selected stroke segments with Ctrl-C and Ctrl-V

Joshua Leung noreply at git.blender.org
Thu Jan 1 00:53:04 CET 2015


Commit: c0805722ed18167e711cde913b416ec01bd2c7a6
Author: Joshua Leung
Date:   Thu Jan 1 12:36:01 2015 +1300
Branches: master
https://developer.blender.org/rBc0805722ed18167e711cde913b416ec01bd2c7a6

GPencil Editing: Copy and Paste selected stroke segments with Ctrl-C and Ctrl-V

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

M	source/blender/editors/gpencil/gpencil_edit.c
M	source/blender/editors/gpencil/gpencil_intern.h
M	source/blender/editors/gpencil/gpencil_ops.c
M	source/blender/editors/include/ED_gpencil.h
M	source/blender/windowmanager/intern/wm_init_exit.c

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

diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index be4cac6..3dae252 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -673,8 +673,185 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
 }
 
 /* ******************* Copy/Paste Strokes ************************* */
+/* Grease Pencil stroke data copy/paste buffer:
+ * - The copy operation collects all segments of selected strokes,
+ *   dumping "ready to be copied" copies of the strokes into the buffer.
+ * - The paste operation makes a copy of those elements, and adds them
+ *   to the active layer. This effectively flattens down the strokes
+ *   from several different layers into a single layer.
+ */
+
+/* list of bGPDstroke instances */
+static ListBase gp_strokes_copypastebuf = {NULL, NULL};
+
+/* Free copy/paste buffer data */
+void ED_gpencil_strokes_copybuf_free(void)
+{
+	bGPDstroke *gps, *gpsn;
+	
+	for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
+		gpsn = gps->next;
+		
+		MEM_freeN(gps->points);
+		BLI_freelinkN(&gp_strokes_copypastebuf, gps);
+	}
+	
+	gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL;
+}
+
+/* --------------------- */
+/* Copy selected strokes */
+
+static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
+{
+	bGPdata *gpd = ED_gpencil_data_get_active(C);
+	
+	if (gpd == NULL) {
+		BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+		return OPERATOR_CANCELLED;
+	}
+	
+	/* clear the buffer first */
+	ED_gpencil_strokes_copybuf_free();
+	
+	/* for each visible (and editable) layer's selected strokes,
+	 * copy the strokes into a temporary buffer, then append
+	 * once all done
+	 */
+	CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+	{
+		bGPDframe *gpf = gpl->actframe;
+		bGPDstroke *gps;
+		
+		if (gpf == NULL)
+			continue;
+		
+		/* make copies of selected strokes, and deselect these once we're done */
+		for (gps = gpf->strokes.first; gps; gps = gps->next) {
+			if (gps->flag & GP_STROKE_SELECT) {
+				if (gps->totpoints == 1) {
+					/* Special Case: If there's just a single point in this stroke... */
+					bGPDstroke *gpsd;
+					
+					/* make direct copies of the stroke and its points */
+					gpsd = MEM_dupallocN(gps);
+					gpsd->points = MEM_dupallocN(gps->points);
+					
+					/* add to temp buffer */
+					gpsd->next = gpsd->prev = NULL;
+					BLI_addtail(&gp_strokes_copypastebuf, gpsd);
+				}
+				else {
+					/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+					gp_duplicate_points(gps, &gp_strokes_copypastebuf);
+				}
+			}
+		}
+	}
+	CTX_DATA_END;
+	
+	/* done - no updates needed */
+	return OPERATOR_FINISHED;
+}
 
-// TODO:
+void GPENCIL_OT_copy(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Copy Strokes";
+	ot->idname = "GPENCIL_OT_copy";
+	ot->description = "Copy selected Grease Pencil points and strokes";
+	
+	/* callbacks */
+	ot->exec = gp_strokes_copy_exec;
+	ot->poll = gp_stroke_edit_poll;
+	
+	/* flags */
+	//ot->flag = OPTYPE_REGISTER;
+}
+
+/* --------------------- */
+/* Paste selected strokes */
+
+static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
+{
+	Scene *scene = CTX_data_scene(C);
+	bGPdata *gpd = ED_gpencil_data_get_active(C);
+	bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+	bGPDframe *gpf;
+	
+	/* check for various error conditions */
+	if (gpd == NULL) {
+		BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+		return OPERATOR_CANCELLED;
+	}
+	else if (gp_strokes_copypastebuf.first == NULL) {
+		BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
+		return OPERATOR_CANCELLED;
+	}
+	else if (gpl == NULL) {
+		/* no active layer - let's just create one */
+		gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), 1);
+	}
+	else if (gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) {
+		BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
+		return OPERATOR_CANCELLED;
+	}
+	
+	/* Deselect all strokes first */
+	CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+	{
+		bGPDspoint *pt;
+		int i;
+		
+		for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+			pt->flag &= ~GP_SPOINT_SELECT;
+		}
+		
+		gps->flag &= ~GP_STROKE_SELECT;
+	}
+	CTX_DATA_END;
+	
+	/* Ensure we have a frame to draw into
+	 * NOTE: Since this is an op which creates strokes,
+	 *       we are obliged to add a new frame if one
+	 *       doesn't exist already
+	 */
+	gpf = gpencil_layer_getframe(gpl, CFRA, true);
+	
+	if (gpf) {
+		bGPDstroke *gps;
+		
+		/* Copy each stroke into the layer */
+		for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+			bGPDstroke *new_stroke = MEM_dupallocN(gps);
+			
+			new_stroke->points = MEM_dupallocN(gps->points);
+			new_stroke->next = new_stroke->prev = NULL;
+			
+			BLI_addtail(&gpf->strokes, new_stroke);
+		}
+	}
+	
+	/* updates */
+	WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+	
+	return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_paste(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Paste Strokes";
+	ot->idname = "GPENCIL_OT_paste";
+	ot->description = "Paste previously copied strokes into active layer";
+	
+	/* callbacks */
+	ot->exec = gp_strokes_paste_exec;
+	ot->poll = gp_stroke_edit_poll;
+	
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
 
 /* ******************* Delete Active Frame ************************ */
 
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 3bf6355..5642043 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -125,6 +125,8 @@ void GPENCIL_OT_select_less(struct wmOperatorType *ot);
 
 void GPENCIL_OT_duplicate(struct wmOperatorType *ot);
 void GPENCIL_OT_delete(struct wmOperatorType *ot);
+void GPENCIL_OT_copy(struct wmOperatorType *ot);
+void GPENCIL_OT_paste(struct wmOperatorType *ot);
 
 /* buttons editing --- */
 
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index e477673..8955443 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -163,6 +163,14 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
 	/* delete */
 	WM_keymap_add_item(keymap, "GPENCIL_OT_delete", XKEY, KM_PRESS, 0, 0);
 	
+	/* copy + paste */
+	WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
+	WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+	
+#ifdef __APPLE__
+	WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
+	WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
+#endif	
 	
 	/* Transform Tools */
 	kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -224,6 +232,8 @@ void ED_operatortypes_gpencil(void)
 	
 	WM_operatortype_append(GPENCIL_OT_duplicate);
 	WM_operatortype_append(GPENCIL_OT_delete);
+	WM_operatortype_append(GPENCIL_OT_copy);
+	WM_operatortype_append(GPENCIL_OT_paste);
 	
 	/* Editing (Buttons) ------------ */
 	
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index cad33c3..b0d1be1 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -87,6 +87,12 @@ void ED_keymap_gpencil(struct wmKeyConfig *keyconf);
 void ED_operatortypes_gpencil(void);
 void ED_operatormacros_gpencil(void);
 
+/* ------------- Copy-Paste Buffers -------------------- */
+
+/* Strokes copybuf */
+void ED_gpencil_strokes_copybuf_free(void);
+
+
 /* ------------ Grease-Pencil Drawing API ------------------ */
 /* drawgpencil.c */
 
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 1e10003..cb03d02 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -96,6 +96,7 @@
 #include "wm_window.h"
 
 #include "ED_armature.h"
+#include "ED_gpencil.h"
 #include "ED_keyframing.h"
 #include "ED_node.h"
 #include "ED_render.h"
@@ -475,6 +476,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
 	free_anim_copybuf();
 	free_anim_drivers_copybuf();
 	free_fmodifiers_copybuf();
+	ED_gpencil_strokes_copybuf_free();
 	ED_clipboard_posebuf_free();
 	BKE_node_clipboard_clear();




More information about the Bf-blender-cvs mailing list