Shape Keys: Add "Duplicate Shape Key" operator

Part of #135095.

This operator just adds a copy the active shape key, including its
data and settings.

Pull Request: https://projects.blender.org/blender/blender/pulls/136785
This commit is contained in:
Hans Goudey
2025-04-01 18:24:00 +02:00
committed by Hans Goudey
parent a7e78dccb9
commit 7a4ce4184d
6 changed files with 46 additions and 0 deletions

View File

@@ -60,6 +60,7 @@ class MESH_MT_shape_key_context_menu(Menu):
layout = self.layout
layout.operator("object.shape_key_add", icon='ADD', text="New Shape from Mix").from_mix = True
layout.operator("object.shape_key_copy", icon='DUPLICATE', text="Duplicate Shape Key")
layout.separator()
layout.operator("object.shape_key_mirror", icon='ARROW_LEFTRIGHT').use_topology = False
layout.operator("object.shape_key_mirror", text="Mirror Shape Key (Topology)").use_topology = True

View File

@@ -81,6 +81,10 @@ KeyBlock *BKE_keyblock_from_object(Object *ob);
KeyBlock *BKE_keyblock_from_object_reference(Object *ob);
KeyBlock *BKE_keyblock_add(Key *key, const char *name);
/** Add a copy of the source key-block with a copy of its data array. */
KeyBlock *BKE_keyblock_duplicate(Key *key, const KeyBlock *kb_src);
/**
* \note sorting is a problematic side effect in some cases,
* better only do this explicitly by having its own function,

View File

@@ -1878,6 +1878,16 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
return kb;
}
KeyBlock *BKE_keyblock_duplicate(Key *key, const KeyBlock *kb_src)
{
BLI_assert(BLI_findindex(&key->block, kb_src) != -1);
KeyBlock *kb_dst = BKE_keyblock_add(key, kb_src->name);
kb_dst->totelem = kb_src->totelem;
kb_dst->data = MEM_dupallocN(kb_src->data);
BKE_keyblock_copy_settings(kb_dst, kb_src);
return kb_dst;
}
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
KeyBlock *kb = BKE_keyblock_add(key, name);

View File

@@ -312,6 +312,7 @@ void TRANSFORM_OT_vertex_warp(wmOperatorType *ot);
/* `object_shapekey.cc` */
void OBJECT_OT_shape_key_add(wmOperatorType *ot);
void OBJECT_OT_shape_key_copy(wmOperatorType *ot);
void OBJECT_OT_shape_key_remove(wmOperatorType *ot);
void OBJECT_OT_shape_key_clear(wmOperatorType *ot);
void OBJECT_OT_shape_key_retime(wmOperatorType *ot);

View File

@@ -221,6 +221,7 @@ void operatortypes_object()
WM_operatortype_append(OBJECT_OT_link_to_collection);
WM_operatortype_append(OBJECT_OT_shape_key_add);
WM_operatortype_append(OBJECT_OT_shape_key_copy);
WM_operatortype_append(OBJECT_OT_shape_key_remove);
WM_operatortype_append(OBJECT_OT_shape_key_clear);
WM_operatortype_append(OBJECT_OT_shape_key_retime);

View File

@@ -376,6 +376,35 @@ void OBJECT_OT_shape_key_add(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shape Key Duplicate Operator
* \{ */
static wmOperatorStatus shape_key_copy_exec(bContext *C, wmOperator * /*op*/)
{
Object *ob = context_object(C);
Key *key = BKE_key_from_object(ob);
BKE_keyblock_duplicate(key, BKE_keyblock_from_object(ob));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
void OBJECT_OT_shape_key_copy(wmOperatorType *ot)
{
ot->name = "Duplicate Shape Key";
ot->idname = "OBJECT_OT_shape_key_copy";
ot->description = "Duplicate the acive shape key";
ot->poll = shape_key_mode_exists_poll;
ot->exec = shape_key_copy_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shape Key Remove Operator
* \{ */