Modeling: new shape key operator Make Basis

Add a new operator "Make Shape Key the Basis Key", shown in the Shape
Key menu as "Make Basis". Effectively this does the same thing as moving
the active shape key to the top of the list of shape keys: applying it
to the mesh.

This operator is added now, because !141930 will prevent moving shape
keys to the top of the list. This hopefully prevents accidentally making
other keys the basis key, which can cause issues that are hard to
recover from.

Pull Request: https://projects.blender.org/blender/blender/pulls/143200
This commit is contained in:
Sybren A. Stüvel
2025-07-28 15:28:21 +02:00
parent 38f867814f
commit 301a86d700
4 changed files with 57 additions and 0 deletions

View File

@@ -79,6 +79,7 @@ class MESH_MT_shape_key_context_menu(Menu):
layout.operator("object.shape_key_lock", icon='LOCKED', text="Lock All").action = 'LOCK'
layout.operator("object.shape_key_lock", icon='UNLOCKED', text="Unlock All").action = 'UNLOCK'
layout.separator()
layout.operator("object.shape_key_make_basis", text="Make Basis")
layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'

View File

@@ -326,6 +326,7 @@ void OBJECT_OT_shape_key_retime(wmOperatorType *ot);
void OBJECT_OT_shape_key_mirror(wmOperatorType *ot);
void OBJECT_OT_shape_key_move(wmOperatorType *ot);
void OBJECT_OT_shape_key_lock(wmOperatorType *ot);
void OBJECT_OT_shape_key_make_basis(wmOperatorType *ot);
/* `object_collection.cc` */

View File

@@ -231,6 +231,7 @@ void operatortypes_object()
WM_operatortype_append(OBJECT_OT_shape_key_mirror);
WM_operatortype_append(OBJECT_OT_shape_key_move);
WM_operatortype_append(OBJECT_OT_shape_key_lock);
WM_operatortype_append(OBJECT_OT_shape_key_make_basis);
WM_operatortype_append(OBJECT_OT_collection_add);
WM_operatortype_append(OBJECT_OT_collection_link);

View File

@@ -811,4 +811,58 @@ void OBJECT_OT_shape_key_lock(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shape Key Make Basis Operator
* \{ */
static bool shape_key_make_basis_poll(bContext *C)
{
if (!shape_key_exists_poll(C)) {
return false;
}
Object *ob = context_object(C);
/* 0 = nothing active, 1 = basis key active. */
return ob->shapenr > 1;
}
static wmOperatorStatus shape_key_make_basis_exec(bContext *C, wmOperator * /*op*/)
{
Object *ob = CTX_data_active_object(C);
/* Make the new basis by moving the active key to index 0. */
const int from_index = -1; /* Interpreted as "the active key". */
const int to_index = 0; /* Offset by 1 compared to ob->shapenr. */
const bool changed = BKE_keyblock_move(ob, from_index, to_index);
if (!changed) {
/* The poll function should have prevented this operator from being called
* on the current basis key. */
BLI_assert_unreachable();
return OPERATOR_CANCELLED;
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void OBJECT_OT_shape_key_make_basis(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Make Shape Key the Basis Key";
ot->idname = "OBJECT_OT_shape_key_make_basis";
ot->description = "Make this shape key the new basis key, effectively applying it to the mesh";
/* API callbacks. */
ot->poll = shape_key_make_basis_poll;
ot->exec = shape_key_make_basis_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
} // namespace blender::ed::object