Fix T50393: Flip names working just on one side when both are selected.

Just store bones that could not get renamed to desired flipped name on the
first try into a temp list, and try to rename them a second time.

This is rather simple solution, will induce 'over numbering' in case you
flip a bone to another unselected bone's name (since number will be
incremented in both rename attempts), but think this is acceptable minor
glitch, for a corner case situation that does not have any good
resolution anyway.

Also, set `strip_numbers` option of `BKE_deform_flip_side_name` to
false, otherwise chains of bones with same names would get their numbers
completely messed up after name flipping.

Based on work by @dfelinto in D2456 (https://developer.blender.org/D2456), thanks.
This commit is contained in:
Bastien Montagne 2017-01-16 14:03:31 +01:00
parent 92fbcbb4bf
commit 702bc5ba26
Notes: blender-bot 2023-02-14 08:45:12 +01:00
Referenced by issue #54189, Armature "flip names" is not removing .001 suffix
Referenced by issue #54074, Armature flip names
Referenced by issue #51543, Bone flip names don't remove suffix
Referenced by issue #50393, Flip names working just on one side
3 changed files with 72 additions and 13 deletions

View File

@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@ -297,6 +298,55 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
}
typedef struct BoneFlipNameData {
struct BoneFlipNameData *next, *prev;
char *name;
char name_flip[MAXBONENAME];
} BoneFlipNameData;
/**
* Renames (by flipping) all selected bones at once.
*
* This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
* all the bones are safely renamed, without conflicting with each other.
*
* \param arm Armature the bones belong to
* \param bones ListBase of BoneConflict elems, populated via ED_armature_bones_flip_names_add
*/
void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names)
{
ListBase bones_names_conflicts = {NULL};
BoneFlipNameData *bfn;
/* First pass: generate flip names, and blindly rename.
* If rename did not yield expected result, store both bone's name and expected flipped one into temp list
* for second pass. */
for (LinkData *link = bones_names->first; link; link = link->next) {
char name_flip[MAXBONENAME];
char *name = link->data;
/* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like
* Bone.R, Bone.R.001, Bone.R.002, etc. */
BKE_deform_flip_side_name(name_flip, name, false);
ED_armature_bone_rename(arm, name, name_flip);
if (!STREQ(name, name_flip)) {
bfn = alloca(sizeof(BoneFlipNameData));
bfn->name = name;
BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip));
BLI_addtail(&bones_names_conflicts, bfn);
}
}
/* Second pass to handle the bones that have naming conflicts with other bones.
* Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
* rename simply generates a new numbered alternative name. */
for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
ED_armature_bone_rename(arm, bfn->name, bfn->name_flip);
}
}
/* ************************************************** */
/* Bone Renaming - EditMode */
@ -304,20 +354,24 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
/* paranoia checks */
if (ELEM(NULL, ob, ob->pose))
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
arm = ob->data;
/* loop through selected bones, auto-naming them */
ListBase bones_names= {NULL};
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
{
char name_flip[MAXBONENAME];
BKE_deform_flip_side_name(name_flip, ebone->name, true);
ED_armature_bone_rename(arm, ebone->name, name_flip);
BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
}
CTX_DATA_END;
ED_armature_bones_flip_names(arm, &bones_names);
BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

View File

@ -593,20 +593,24 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm;
/* paranoia checks */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
arm = ob->data;
/* loop through selected bones, auto-naming them */
ListBase bones_names = {NULL};
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
{
char name_flip[MAXBONENAME];
BKE_deform_flip_side_name(name_flip, pchan->name, true);
ED_armature_bone_rename(arm, pchan->name, name_flip);
BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
}
CTX_DATA_END;
ED_armature_bones_flip_names(arm, &bones_names);
BLI_freelistN(&bones_names);
/* since we renamed stuff... */
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

View File

@ -171,6 +171,7 @@ void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scen
/* if bone is already in list, pass it as param to ignore it */
void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names);
void undo_push_armature(struct bContext *C, const char *name);