diff options
-rw-r--r-- | source/blender/editors/gpencil/gpencil_edit.c | 179 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_ops.c | 10 | ||||
-rw-r--r-- | source/blender/editors/include/ED_gpencil.h | 6 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 2 |
5 files changed, 198 insertions, 1 deletions
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index be4cac666bd..3dae25263e8 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 3bf6355ccd1..56420434494 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 e4776732b23..8955443fd2c 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 cad33c34fe3..b0d1be1bf5d 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 1e100031f11..cb03d022afd 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(); |