== Action/Bone Groups - Ctrl-G Hotkey + Bugfixes ==
New Stuff: * When in PoseMode, the Ctrl-G hotkey now presents a menu with options for manipulating Bone Groups. There are options to add/remove all selected bones from a certain group. TODO - add appropriate entries to menus Bugfixes: * Renaming Bone-Groups in the buttons panel could cause segfaults or memory corruption. Wrong maximum-length for button used here (it's far too easy to miss). * In the Action Editor, (re)grouping channels didn't take into account whether a group was expanded or not. This meant that selected channels from inside a collapsed group got added to the new group too.
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
|
||||
|
||||
struct Object;
|
||||
struct bPose;
|
||||
struct bPoseChannel;
|
||||
|
||||
void enter_posemode(void);
|
||||
@@ -60,6 +61,13 @@ void paste_posebuf (int flip);
|
||||
|
||||
void pose_adds_vgroups(struct Object *meshobj, int heatweights);
|
||||
|
||||
void pose_add_posegroup(void);
|
||||
void pose_remove_posegroup(void);
|
||||
char *build_posegroups_menustr(struct bPose *pose, short for_pupmenu);
|
||||
void pose_assign_to_posegroup(void);
|
||||
void pose_remove_from_posegroup(void);
|
||||
void pgroup_operation_with_menu(void);
|
||||
|
||||
void pose_calculate_path(struct Object *ob);
|
||||
void pose_recalculate_paths(struct Object *ob);
|
||||
void pose_clear_paths(struct Object *ob);
|
||||
|
||||
@@ -3854,44 +3854,17 @@ void do_armbuts(unsigned short event)
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO: make these pose-group options proper tools in poseobject.c
|
||||
case B_POSEGRP_RECALC:
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
break;
|
||||
case B_POSEGRP_ADD:
|
||||
if (ob && ob->pose) {
|
||||
bPose *pose= ob->pose;
|
||||
bActionGroup *grp;
|
||||
|
||||
grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
|
||||
strcpy(grp->name, "Group");
|
||||
BLI_addtail(&pose->agroups, grp);
|
||||
BLI_uniquename(&pose->agroups, grp, "Group", offsetof(bActionGroup, name), 32);
|
||||
|
||||
pose->active_group= BLI_countlist(&pose->agroups);
|
||||
|
||||
BIF_undo_push("Add Pose Group");
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
if (ob && ob->pose)
|
||||
pose_add_posegroup();
|
||||
break;
|
||||
case B_POSEGRP_REMOVE:
|
||||
if (ob && ob->pose && ob->pose->active_group) {
|
||||
bPose *pose= ob->pose;
|
||||
bActionGroup *grp= NULL;
|
||||
|
||||
// FIXME: make sure all that referenced it get reset
|
||||
grp= BLI_findlink(&pose->agroups, pose->active_group-1);
|
||||
if (grp) {
|
||||
BLI_freelinkN(&pose->agroups, grp);
|
||||
pose->active_group= 0;
|
||||
}
|
||||
|
||||
BIF_undo_push("Remove Pose Group");
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
if (ob && ob->pose)
|
||||
pose_remove_posegroup();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4323,37 +4296,6 @@ static int ob_arm_bone_pchan_lock(Object *ob, bArmature *arm, Bone *bone, bPoseC
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *build_posegroups_menustr(bPose *pose)
|
||||
{
|
||||
DynStr *pupds= BLI_dynstr_new();
|
||||
bActionGroup *agrp;
|
||||
char *str;
|
||||
char buf[16];
|
||||
int i;
|
||||
|
||||
/* add title first (and the "none" entry) */
|
||||
BLI_dynstr_append(pupds, "Pose Group%t|");
|
||||
BLI_dynstr_append(pupds, "BG: [None]%x0|");
|
||||
|
||||
/* loop through markers, adding them */
|
||||
for (agrp= pose->agroups.first, i=1; agrp; agrp=agrp->next, i++) {
|
||||
BLI_dynstr_append(pupds, "BG: ");
|
||||
BLI_dynstr_append(pupds, agrp->name);
|
||||
|
||||
sprintf(buf, "%%x%d", i);
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
|
||||
if (agrp->next)
|
||||
BLI_dynstr_append(pupds, "|");
|
||||
}
|
||||
|
||||
/* convert to normal MEM_malloc'd string */
|
||||
str= BLI_dynstr_get_cstring(pupds);
|
||||
BLI_dynstr_free(pupds);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||
{
|
||||
uiBlock *block;
|
||||
@@ -4388,7 +4330,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
|
||||
uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
|
||||
|
||||
/* Bone custom drawing */
|
||||
menustr= build_posegroups_menustr(ob->pose);
|
||||
menustr= build_posegroups_menustr(ob->pose, 0);
|
||||
uiDefButS(block, MENU,REDRAWVIEW3D, menustr, 107,by,105,19, &pchan->agrp_index, 0, 0.0, 0.0, 0.0, "Change the Pose Group this Bone belongs to");
|
||||
MEM_freeN(menustr);
|
||||
|
||||
@@ -5211,7 +5153,7 @@ static void editing_panel_links(Object *ob)
|
||||
uiBlockBeginAlign(block);
|
||||
/* currently 'active' group - browse groups */
|
||||
count= BLI_countlist(&pose->agroups);
|
||||
menustr= build_posegroups_menustr(pose);
|
||||
menustr= build_posegroups_menustr(pose, 0);
|
||||
uiDefButI(block, MENU, B_POSEGRP_RECALC, menustr, xco, 85,18,20, &pose->active_group, 1, count, 0, 0, "Browses Pose Groups available for Armature. Click to change.");
|
||||
MEM_freeN(menustr);
|
||||
|
||||
@@ -5220,7 +5162,7 @@ static void editing_panel_links(Object *ob)
|
||||
bActionGroup *grp= (bActionGroup *)BLI_findlink(&pose->agroups, pose->active_group-1);
|
||||
|
||||
/* active group */
|
||||
but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,140-18-20,20, grp->name, 0, 63, 0, 0, "Displays current Pose Group name. Click to change.");
|
||||
but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,140-18-20,20, grp->name, 0, 31, 0, 0, "Displays current Pose Group name. Click to change.");
|
||||
uiButSetFunc(but, verify_posegroup_groupname, pose, grp);
|
||||
uiDefIconBut(block, BUT, B_POSEGRP_REMOVE, VICON_X, xco+140-20, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this Pose Group");
|
||||
|
||||
|
||||
@@ -981,6 +981,7 @@ void action_groups_group (short add_group)
|
||||
|
||||
/* make sure not already in new-group */
|
||||
if (achan->grp != agrp) {
|
||||
if ((achan->grp) && (EXPANDED_AGRP(achan->grp))) {
|
||||
if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
|
||||
/* unlink from everything else */
|
||||
action_groups_removeachan(act, achan);
|
||||
@@ -990,6 +991,7 @@ void action_groups_group (short add_group)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* updates and undo */
|
||||
if (add_group)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
@@ -910,10 +911,213 @@ void pose_adds_vgroups(Object *meshobj, int heatweights)
|
||||
/* ********************************************** */
|
||||
|
||||
/* adds a new pose-group */
|
||||
// TODO...
|
||||
void pose_add_posegroup ()
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bActionGroup *grp;
|
||||
|
||||
if (ELEM(NULL, ob, ob->pose))
|
||||
return;
|
||||
|
||||
grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup");
|
||||
strcpy(grp->name, "Group");
|
||||
BLI_addtail(&pose->agroups, grp);
|
||||
BLI_uniquename(&pose->agroups, grp, "Group", offsetof(bActionGroup, name), 32);
|
||||
|
||||
pose->active_group= BLI_countlist(&pose->agroups);
|
||||
|
||||
BIF_undo_push("Add Bone Group");
|
||||
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
/* Remove the active bone-group */
|
||||
void pose_remove_posegroup ()
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bActionGroup *grp = NULL;
|
||||
bPoseChannel *pchan;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(NULL, ob, pose))
|
||||
return;
|
||||
if (pose->active_group <= 0)
|
||||
return;
|
||||
|
||||
/* get group to remove */
|
||||
grp= BLI_findlink(&pose->agroups, pose->active_group-1);
|
||||
if (grp) {
|
||||
/* firstly, make sure nothing references it */
|
||||
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if (pchan->agrp_index == pose->active_group)
|
||||
pchan->agrp_index= 0;
|
||||
}
|
||||
|
||||
/* now, remove it from the pose */
|
||||
BLI_freelinkN(&pose->agroups, grp);
|
||||
pose->active_group= 0;
|
||||
|
||||
BIF_undo_push("Remove Bone Group");
|
||||
}
|
||||
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
char *build_posegroups_menustr (bPose *pose, short for_pupmenu)
|
||||
{
|
||||
DynStr *pupds= BLI_dynstr_new();
|
||||
bActionGroup *grp;
|
||||
char *str;
|
||||
char buf[16];
|
||||
int i;
|
||||
|
||||
/* add title first (and the "none" entry) */
|
||||
BLI_dynstr_append(pupds, "Bone Group%t|");
|
||||
if (for_pupmenu)
|
||||
BLI_dynstr_append(pupds, "Add New%x0|");
|
||||
else
|
||||
BLI_dynstr_append(pupds, "BG: [None]%x0|");
|
||||
|
||||
/* loop through markers, adding them */
|
||||
for (grp= pose->agroups.first, i=1; grp; grp=grp->next, i++) {
|
||||
if (for_pupmenu == 0)
|
||||
BLI_dynstr_append(pupds, "BG: ");
|
||||
BLI_dynstr_append(pupds, grp->name);
|
||||
|
||||
sprintf(buf, "%%x%d", i);
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
|
||||
if (grp->next)
|
||||
BLI_dynstr_append(pupds, "|");
|
||||
}
|
||||
|
||||
/* convert to normal MEM_malloc'd string */
|
||||
str= BLI_dynstr_get_cstring(pupds);
|
||||
BLI_dynstr_free(pupds);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Assign selected pchans to the bone group that the user selects */
|
||||
void pose_assign_to_posegroup ()
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bArmature *arm= (ob) ? ob->data : NULL;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bPoseChannel *pchan;
|
||||
char *menustr;
|
||||
int nr;
|
||||
short done= 0;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM3(NULL, ob, pose, arm))
|
||||
return;
|
||||
|
||||
/* get group to affect */
|
||||
menustr= build_posegroups_menustr(pose, 1);
|
||||
nr= pupmenu(menustr);
|
||||
MEM_freeN(menustr);
|
||||
|
||||
if (nr < 0)
|
||||
return;
|
||||
else if (nr == 0) {
|
||||
/* add new - note: this does an undo push and sets active group */
|
||||
pose_add_posegroup();
|
||||
}
|
||||
else
|
||||
pose->active_group= nr;
|
||||
|
||||
/* add selected bones to group then */
|
||||
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
|
||||
pchan->agrp_index= pose->active_group;
|
||||
done= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (done)
|
||||
BIF_undo_push("Add Bones To Group");
|
||||
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
/* Remove selected pchans from their bone groups */
|
||||
void pose_remove_from_posegroups ()
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bArmature *arm= (ob) ? ob->data : NULL;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bPoseChannel *pchan;
|
||||
short done= 0;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM3(NULL, ob, pose, arm))
|
||||
return;
|
||||
|
||||
/* remove selected bones from their groups */
|
||||
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
|
||||
if (pchan->agrp_index) {
|
||||
pchan->agrp_index= 0;
|
||||
done= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (done)
|
||||
BIF_undo_push("Remove Bones From Groups");
|
||||
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
/* Ctrl-G in 3D-View while in PoseMode */
|
||||
void pgroup_operation_with_menu (void)
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
bArmature *arm= (ob) ? ob->data : NULL;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bPoseChannel *pchan= NULL;
|
||||
int mode;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM3(NULL, ob, pose, arm))
|
||||
return;
|
||||
|
||||
/* check that something is selected */
|
||||
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer))
|
||||
break;
|
||||
}
|
||||
if (pchan == NULL)
|
||||
return;
|
||||
|
||||
/* get mode of action */
|
||||
if (pchan)
|
||||
mode= pupmenu("Bone Groups%t|Add Selected to Group%x1|Add New Group%x2|Remove Selected From Groups%x3|Remove Active Group%x4");
|
||||
else
|
||||
mode= pupmenu("Bone Groups%t|Add New Group%x2|Remove Active Group%x4");
|
||||
|
||||
/* handle mode */
|
||||
switch (mode) {
|
||||
case 1:
|
||||
pose_assign_to_posegroup();
|
||||
break;
|
||||
case 2:
|
||||
pose_add_posegroup();
|
||||
break;
|
||||
case 3:
|
||||
pose_remove_from_posegroups();
|
||||
break;
|
||||
case 4:
|
||||
pose_remove_posegroup();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
|
||||
@@ -1940,6 +1940,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
|
||||
vgroup_assign_with_menu();
|
||||
}
|
||||
else if(ob && (ob->flag & OB_POSEMODE))
|
||||
pgroup_operation_with_menu();
|
||||
else
|
||||
group_operation_with_menu();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user