== 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:
2008-01-22 03:16:48 +00:00
parent be95e6b0ca
commit d23bcd8b7f
5 changed files with 230 additions and 72 deletions

View File

@@ -35,6 +35,7 @@
struct Object; struct Object;
struct bPose;
struct bPoseChannel; struct bPoseChannel;
void enter_posemode(void); void enter_posemode(void);
@@ -60,6 +61,13 @@ void paste_posebuf (int flip);
void pose_adds_vgroups(struct Object *meshobj, int heatweights); 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_calculate_path(struct Object *ob);
void pose_recalculate_paths(struct Object *ob); void pose_recalculate_paths(struct Object *ob);
void pose_clear_paths(struct Object *ob); void pose_clear_paths(struct Object *ob);

View File

@@ -3854,44 +3854,17 @@ void do_armbuts(unsigned short event)
} }
break; break;
// TODO: make these pose-group options proper tools in poseobject.c
case B_POSEGRP_RECALC: case B_POSEGRP_RECALC:
allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSEDIT, 0); allqueue(REDRAWBUTSEDIT, 0);
break; break;
case B_POSEGRP_ADD: case B_POSEGRP_ADD:
if (ob && ob->pose) { if (ob && ob->pose)
bPose *pose= ob->pose; pose_add_posegroup();
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);
}
break; break;
case B_POSEGRP_REMOVE: case B_POSEGRP_REMOVE:
if (ob && ob->pose && ob->pose->active_group) { if (ob && ob->pose)
bPose *pose= ob->pose; pose_remove_posegroup();
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);
}
break; break;
} }
} }
@@ -4323,37 +4296,6 @@ static int ob_arm_bone_pchan_lock(Object *ob, bArmature *arm, Bone *bone, bPoseC
return 0; 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) static void editing_panel_pose_bones(Object *ob, bArmature *arm)
{ {
uiBlock *block; uiBlock *block;
@@ -4388,7 +4330,7 @@ static void editing_panel_pose_bones(Object *ob, bArmature *arm)
uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
/* Bone custom drawing */ /* 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"); 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); MEM_freeN(menustr);
@@ -5211,7 +5153,7 @@ static void editing_panel_links(Object *ob)
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
/* currently 'active' group - browse groups */ /* currently 'active' group - browse groups */
count= BLI_countlist(&pose->agroups); 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."); 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); 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); bActionGroup *grp= (bActionGroup *)BLI_findlink(&pose->agroups, pose->active_group-1);
/* active group */ /* 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); 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"); 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");

View File

@@ -981,12 +981,14 @@ void action_groups_group (short add_group)
/* make sure not already in new-group */ /* make sure not already in new-group */
if (achan->grp != agrp) { if (achan->grp != agrp) {
if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) { if ((achan->grp) && (EXPANDED_AGRP(achan->grp))) {
/* unlink from everything else */ if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
action_groups_removeachan(act, achan); /* unlink from everything else */
action_groups_removeachan(act, achan);
/* add to end of group's channels */
action_groups_addachan(act, agrp, achan); /* add to end of group's channels */
action_groups_addachan(act, agrp, achan);
}
} }
} }
} }

View File

@@ -33,6 +33,7 @@
#include "BLI_arithb.h" #include "BLI_arithb.h"
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
#include "BLI_dynstr.h"
#include "DNA_action_types.h" #include "DNA_action_types.h"
#include "DNA_armature_types.h" #include "DNA_armature_types.h"
@@ -910,10 +911,213 @@ void pose_adds_vgroups(Object *meshobj, int heatweights)
/* ********************************************** */ /* ********************************************** */
/* adds a new pose-group */ /* adds a new pose-group */
// TODO...
void pose_add_posegroup () 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;
}
} }
/* ********************************************** */ /* ********************************************** */

View File

@@ -1940,6 +1940,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE)) if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
vgroup_assign_with_menu(); vgroup_assign_with_menu();
} }
else if(ob && (ob->flag & OB_POSEMODE))
pgroup_operation_with_menu();
else else
group_operation_with_menu(); group_operation_with_menu();
} }