Fix #104054: Symmetrize visible ebones when nothing selected #107902

Open
Denys Hsu wants to merge 5 commits from cgtinker/blender:symmetrize-unselected into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.

View File

@ -1119,10 +1119,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
const int direction = RNA_enum_get(op->ptr, "direction");
const int axis = 0;
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0) {
return OPERATOR_CANCELLED;
}
const bool is_selection_relevant = CTX_DATA_COUNT(C, selected_bones) > 0;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@ -1139,26 +1136,26 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
preEditBoneDuplicate(arm->edbo);
/* Deselect ebones depending on input axis and direction.
/* (De)select ebones depending on input axis and direction.
* A symmetrizable selection contains selected ebones of the input direction
* and unique selected bones with an unique flippable name.
*
* Storing temp pointers to mirrored unselected ebones. */
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
if (!(EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED))) {
/* Skipping invisible selected bones. */
if (!(EBONE_VISIBLE(arm, ebone_iter))) {
continue;
}
char name_flip[MAXBONENAME];
if (ebone_iter == NULL) {
if (is_selection_relevant && ((ebone_iter->flag & BONE_SELECTED) == 0)) {
continue;
}
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
if (STREQ(name_flip, ebone_iter->name)) {
/* Skipping ebones without flippable as they don't have the potential to be mirrored. */
if (STREQ(name_flip, ebone_iter->name) && (ebone_iter->flag & BONE_SELECTED)) {
/* Skipping and deselecting ebones without flippable as they
* don't have the potential to be mirrored. */
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
}
@ -1166,13 +1163,16 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
if (!ebone) {
/* The ebone_iter is unique and mirrorable. */
/* The ebone_iter is unique and mirrorable. Ensure selection. */
ebone_iter->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
}
if (ebone->flag & BONE_SELECTED) {
/* The mirrored ebone and the ebone_iter are selected.
* Deselect based on the input direction and axis. */
if ((ebone_iter->flag & BONE_SELECTED) && ((ebone->flag & BONE_SELECTED) == 0)) {
/* Iterbone selected, mirrored bone is not, so set temp ptr. */
ebone_iter->temp.ebone = ebone;
}
else if ((ebone->flag & BONE_SELECTED) | (!is_selection_relevant)) {
float axis_delta;
axis_delta = ebone->head[axis] - ebone_iter->head[axis];
@ -1189,19 +1189,27 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
/* Deselect depending on direction. */
EditBone *ebone_src, *ebone_dst;
/* (De)select depending on direction. */
if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
/* Don't store temp ptr if the iter_bone gets deselected.
* In this case, the ebone.temp should point to the ebone_iter. */
ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
continue;
ebone_src = ebone;
ebone_dst = ebone_iter;
}
else {
ebone_src = ebone_iter;
ebone_dst = ebone;
}
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
/* Both bones are selected, or at least the ebone is currently selected. */
ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
if (is_selection_relevant) {
ebone_src->temp.ebone = ebone_dst;
}
else {
ebone_src->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
ebone_src->temp.ebone = ebone_dst;
}
}
/* Set temp pointer to mirrored ebones */
ebone_iter->temp.ebone = ebone;
}
/* Find the selected bones and duplicate them as needed, with mirrored name. */