From 1d12c3fd534b8307ac01f8f0eb6e0ee61c1bd6e4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 27 Jan 2014 15:41:16 +0600 Subject: [PATCH] Implement clipboard for mask splines So now it's possible to copy-paste splines between layers. Implementation is pretty much straightforward and duplicates some logic which we've got in sequencer/tracking clipboards. Will work on a common routine for clipboards later, for now it's not so much crucial to have. --- .../startup/bl_ui/properties_mask_common.py | 4 + source/blender/blenkernel/BKE_mask.h | 6 ++ source/blender/blenkernel/intern/mask.c | 98 +++++++++++++++++++ source/blender/editors/mask/mask_edit.c | 4 + source/blender/editors/mask/mask_intern.h | 2 + source/blender/editors/mask/mask_ops.c | 69 +++++++++++++ .../windowmanager/intern/wm_init_exit.c | 2 + 7 files changed, 185 insertions(+) diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index fb7a3d8b303..5e64129ade0 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -285,6 +285,10 @@ class MASK_MT_mask(Menu): layout.operator("mask.parent_clear") layout.operator("mask.parent_set") + layout.separator() + layout.operator("mask.copy_splines") + layout.operator("mask.paste_splines") + layout.separator() layout.menu("MASK_MT_visibility") layout.menu("MASK_MT_transform") diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index c8b32506a16..de262f98d39 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -168,6 +168,12 @@ void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, i int BKE_mask_get_duration(struct Mask *mask); +/* clipboard */ +void BKE_mask_clipboard_free(void); +void BKE_mask_clipboard_copy_from_layer(struct MaskLayer *mask_layer); +bool BKE_mask_clipboard_is_empty(void); +void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mask_layer); + #define MASKPOINT_ISSEL_ANY(p) ( ((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT) #define MASKPOINT_ISSEL_KNOT(p) ( (p)->bezt.f2 & SELECT) #define MASKPOINT_ISSEL_HANDLE_ONLY(p) ( (((p)->bezt.f1 | (p)->bezt.f3) & SELECT) && (((p)->bezt.f2 & SELECT) == 0) ) diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index a129f724d3e..280093b0d10 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_listbase.h" @@ -61,6 +62,11 @@ #include "NOD_composite.h" +static struct { + ListBase splines; + struct GHash *id_hash; +} mask_clipboard = {{NULL}}; + static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) { if (point == &points_array[spline->tot_point - 1]) { @@ -1935,3 +1941,95 @@ int BKE_mask_get_duration(Mask *mask) { return max_ii(1, mask->efra - mask->sfra); } + +/*********************** clipboard *************************/ + +static void mask_clipboard_free_ex(bool final_free) +{ + BKE_mask_spline_free_list(&mask_clipboard.splines); + mask_clipboard.splines.first = mask_clipboard.splines.last = NULL; + if (mask_clipboard.id_hash) { + if (final_free) { + BLI_ghash_free(mask_clipboard.id_hash, NULL, MEM_freeN); + } + else { + BLI_ghash_clear(mask_clipboard.id_hash, NULL, MEM_freeN); + } + } +} + +/* Free the clipboard. */ +void BKE_mask_clipboard_free(void) +{ + mask_clipboard_free_ex(true); +} + +/* Copy selected visible splines from the given layer to clipboard. */ +void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer) +{ + MaskSpline *spline; + + /* Nothing to do if selection if disabled for the given layer. */ + if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) { + return; + } + + mask_clipboard_free_ex(false); + if (mask_clipboard.id_hash == NULL) { + mask_clipboard.id_hash = BLI_ghash_ptr_new("mask clipboard ID hash"); + } + + for (spline = mask_layer->splines.first; spline; spline = spline->next) { + if (spline->flag & SELECT) { + MaskSpline *spline_new = BKE_mask_spline_copy(spline); + int i; + for (i = 0; i < spline_new->tot_point; i++) { + MaskSplinePoint *point = &spline_new->points[i]; + if (point->parent.id) { + if (!BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id)) { + int len = strlen(point->parent.id->name); + char *name_copy = MEM_mallocN(len + 1, "mask clipboard ID name"); + strcpy(name_copy, point->parent.id->name); + BLI_ghash_insert(mask_clipboard.id_hash, + point->parent.id, + name_copy); + } + } + } + + BLI_addtail(&mask_clipboard.splines, spline_new); + } + } +} + +/* Check clipboard is empty. */ +bool BKE_mask_clipboard_is_empty(void) +{ + return mask_clipboard.splines.first == NULL; +} + +/* Paste the contents of clipboard to given mask layer */ +void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer) +{ + MaskSpline *spline; + + for (spline = mask_clipboard.splines.first; spline; spline = spline->next) { + MaskSpline *spline_new = BKE_mask_spline_copy(spline); + int i; + + for (i = 0; i < spline_new->tot_point; i++) { + MaskSplinePoint *point = &spline_new->points[i]; + if (point->parent.id) { + char *id_name = BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id); + ListBase *listbase; + + BLI_assert(id_name != NULL); + + listbase = which_libbase(bmain, GS(id_name)); + point->parent.id = BLI_findstring(listbase, id_name + 2, offsetof(ID, name) + 2); + } + } + + BLI_addtail(&mask_layer->splines, spline_new); + } +} diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 62eb9cc240a..ad287a3af9f 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -456,6 +456,10 @@ void ED_operatortypes_mask(void) /* duplicate */ WM_operatortype_append(MASK_OT_duplicate); + + /* clipboard */ + WM_operatortype_append(MASK_OT_copy_splines); + WM_operatortype_append(MASK_OT_paste_splines); } void ED_keymap_mask(wmKeyConfig *keyconf) diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index 09ca2290781..9461922ef78 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -79,6 +79,8 @@ struct MaskSplinePoint *ED_mask_point_find_nearest( void MASK_OT_layer_move(struct wmOperatorType *ot); void MASK_OT_duplicate(struct wmOperatorType *ot); +void MASK_OT_copy_splines(struct wmOperatorType *ot); +void MASK_OT_paste_splines(struct wmOperatorType *ot); /* mask_relationships.c */ void MASK_OT_parent_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index f6ba4063e90..c255168d854 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -1599,3 +1599,72 @@ void MASK_OT_duplicate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/********************** copy splines to clipboard operator *********************/ + +static int copy_splines_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer = BKE_mask_layer_active(mask); + + BKE_mask_clipboard_copy_from_layer(mask_layer); + + return OPERATOR_FINISHED; +} + +void MASK_OT_copy_splines(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Copy Splines"; + ot->description = "Copy selected splines to clipboard"; + ot->idname = "MASK_OT_copy_splines"; + + /* api callbacks */ + ot->exec = copy_splines_exec; + ot->poll = ED_maskedit_mask_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER; +} + +/********************** paste tracks from clipboard operator *********************/ + +static int paste_splines_poll(bContext *C) +{ + if (ED_maskedit_mask_poll(C)) { + return BKE_mask_clipboard_is_empty() == false; + } + + return 0; +} + +static int paste_splines_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer = BKE_mask_layer_active(mask); + + BKE_mask_clipboard_paste_to_layer(CTX_data_main(C), mask_layer); + + /* TODO: only update edited splines */ + BKE_mask_update_display(mask, CFRA); + + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + + return OPERATOR_FINISHED; +} + +void MASK_OT_paste_splines(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Paste Splines"; + ot->description = "Paste splines from clipboard"; + ot->idname = "MASK_OT_paste_splines"; + + /* api callbacks */ + ot->exec = paste_splines_exec; + ot->poll = paste_splines_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 5196b584816..e0ec9c994db 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -75,6 +75,7 @@ #include "BKE_sequencer.h" /* free seq clipboard */ #include "BKE_material.h" /* clear_matcopybuf */ #include "BKE_tracking.h" /* free tracking clipboard */ +#include "BKE_mask.h" /* free mask clipboard */ #include "RE_engine.h" #include "RE_pipeline.h" /* RE_ free stuff */ @@ -449,6 +450,7 @@ void WM_exit_ext(bContext *C, const bool do_python) BKE_sequencer_free_clipboard(); /* sequencer.c */ BKE_tracking_clipboard_free(); + BKE_mask_clipboard_free(); #ifdef WITH_COMPOSITOR COM_deinitialize();