2.5 - Restoring Bone Groups

* Added Bone Groups UI to 'Armature' context buttons for now. Later, it may be more convenient to have these with bones instead?

* Added operators for the operations that can be performed on these groups. Moved the core adding/removing functions to blenkernel so that they can be used elsewhere in future if need be.

* Properly wrapped bone groups in RNA. Copied the way that Vertex Groups are wrapped, since they share some similarities. Setting colours for bone groups still needs more work though.
This commit is contained in:
Joshua Leung 2009-07-21 10:18:08 +00:00
parent 8c9ade81e8
commit 6d074526f2
10 changed files with 539 additions and 198 deletions

@ -79,6 +79,38 @@ class DATA_PT_display(DataButtonsPanel):
sub.itemR(arm, "draw_group_colors", text="Colors")
sub.itemR(arm, "delay_deform", text="Delay Refresh")
class DATA_PT_bone_groups(DataButtonsPanel):
__idname__ = "DATA_PT_bone_groups"
__label__ = "Bone Groups"
def poll(self, context):
return (context.object and context.object.type=='ARMATURE' and context.object.pose)
def draw(self, context):
layout = self.layout
ob = context.object
pose= ob.pose
row = layout.row()
row.template_list(pose, "bone_groups", pose, "active_bone_group_index")
col = row.column(align=True)
col.itemO("pose.group_add", icon="ICON_ZOOMIN", text="")
col.itemO("pose.group_remove", icon="ICON_ZOOMOUT", text="")
group = pose.active_bone_group
if group:
row = layout.row()
row.itemR(group, "name")
row = layout.row(align=True)
row.itemO("pose.group_assign", text="Assign")
row.itemO("pose.group_remove", text="Remove") #row.itemO("pose.bone_group_remove_from", text="Remove")
#row.itemO("object.bone_group_select", text="Select")
#row.itemO("object.bone_group_deselect", text="Deselect")
class DATA_PT_paths(DataButtonsPanel):
__idname__ = "DATA_PT_paths"
__label__ = "Paths"
@ -136,5 +168,6 @@ class DATA_PT_ghost(DataButtonsPanel):
bpy.types.register(DATA_PT_context_arm)
bpy.types.register(DATA_PT_skeleton)
bpy.types.register(DATA_PT_display)
bpy.types.register(DATA_PT_bone_groups)
bpy.types.register(DATA_PT_paths)
bpy.types.register(DATA_PT_ghost)

@ -1,6 +1,6 @@
/* BKE_action.h May 2001
*
* Blender kernel action functionality
* Blender kernel action and pose functionality
*
* Reevan McKay
*
@ -26,7 +26,7 @@
* All rights reserved.
*
* Contributor(s): Full recode, Ton Roosendaal, Crete 2005
* Full recode, Joshua Leung, 2009
* Full recode, Joshua Leung, 2009
*
* ***** END GPL LICENSE BLOCK *****
*/
@ -103,8 +103,7 @@ void free_pose(struct bPose *pose);
* Allocate a new pose on the heap, and copy the src pose and it's channels
* into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
*/
void copy_pose(struct bPose **dst, struct bPose *src,
int copyconstraints);
void copy_pose(struct bPose **dst, struct bPose *src, int copyconstraints);
@ -112,8 +111,7 @@ void copy_pose(struct bPose **dst, struct bPose *src,
* Return a pointer to the pose channel of the given name
* from this pose.
*/
struct bPoseChannel *get_pose_channel(const struct bPose *pose,
const char *name);
struct bPoseChannel *get_pose_channel(const struct bPose *pose, const char *name);
/**
* Return a pointer to the active pose channel from this Object.
@ -126,8 +124,9 @@ struct bPoseChannel *get_active_posechannel(struct Object *ob);
* already exists in this pose - if not a new one is
* allocated and initialized.
*/
struct bPoseChannel *verify_pose_channel(struct bPose* pose,
const char* name);
struct bPoseChannel *verify_pose_channel(struct bPose* pose, const char* name);
/* sets constraint flags */
void update_pose_constraint_flags(struct bPose *pose);
@ -136,18 +135,30 @@ void update_pose_constraint_flags(struct bPose *pose);
// XXX to be depreceated for a more general solution in animsys...
void framechange_poses_clear_unkeyed(void);
/* Bone Groups API --------------------- */
/* Adds a new bone-group */
void pose_add_group(struct Object *ob);
/* Remove the active bone-group */
void pose_remove_group(struct Object *ob);
/* Assorted Evaluation ----------------- */
/* Used for the Action Constraint */
void what_does_obaction(struct Scene *scene, struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe);
/* exported for game engine */
void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */
void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* for proxy */
void copy_pose_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void rest_pose(struct bPose *pose);
/* Game Engine ------------------------- */
/* exported for game engine */
void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */
void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* functions used by the game engine */
void game_copy_pose(struct bPose **dst, struct bPose *src);
void game_free_pose(struct bPose *pose);

@ -21,6 +21,7 @@
* All rights reserved.
*
* Contributor(s): Full recode, Ton Roosendaal, Crete 2005
* Full recode, Joshua Leung, 2009
*
* ***** END GPL LICENSE BLOCK *****
*/
@ -31,7 +32,8 @@
#include <string.h>
#include <math.h>
#include <stdlib.h> /* for NULL */
#include <stdlib.h>
#include <stddef.h>
#include "MEM_guardedalloc.h"
@ -68,8 +70,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
//XXX #include "nla.h"
/* *********************** NOTE ON POSE AND ACTION **********************
- Pose is the local (object level) component of armature. The current
@ -765,7 +765,57 @@ void framechange_poses_clear_unkeyed(void)
}
}
/* ************************ END Pose channels *************** */
/* ************************** Bone Groups ************************** */
/* Adds a new bone-group */
void pose_add_group (Object *ob)
{
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);
}
/* Remove the active bone-group */
void pose_remove_group (Object *ob)
{
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) {
/* adjust group references (the trouble of using indices!):
* - firstly, make sure nothing references it
* - also, make sure that those after this item get corrected
*/
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
if (pchan->agrp_index == pose->active_group)
pchan->agrp_index= 0;
else if (pchan->agrp_index > pose->active_group)
pchan->agrp_index--;
}
/* now, remove it from the pose */
BLI_freelinkN(&pose->agroups, grp);
pose->active_group= 0;
}
}
/* ************** time ****************** */

@ -33,28 +33,37 @@ struct wmOperatorType;
/* editarmature.c operators */
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_bones_align(struct wmOperatorType *ot);
void ARMATURE_OT_calculate_roll(struct wmOperatorType *ot);
void ARMATURE_OT_switch_direction(struct wmOperatorType *ot);
void ARMATURE_OT_subdivs(struct wmOperatorType *ot);
void ARMATURE_OT_subdivide_simple(struct wmOperatorType *ot);
void ARMATURE_OT_subdivide_multi(struct wmOperatorType *ot);
void ARMATURE_OT_parent_set(struct wmOperatorType *ot);
void ARMATURE_OT_parent_clear(struct wmOperatorType *ot);
void ARMATURE_OT_select_all_toggle(struct wmOperatorType *ot);
void ARMATURE_OT_select_inverse(struct wmOperatorType *ot);
void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
void ARMATURE_OT_select_linked(struct wmOperatorType *ot);
void ARMATURE_OT_delete(struct wmOperatorType *ot);
void ARMATURE_OT_duplicate_selected(struct wmOperatorType *ot);
void ARMATURE_OT_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_click_extrude(struct wmOperatorType *ot);
/* ******************************************************* */
/* Pose-Mode Operators */
void POSE_OT_hide(struct wmOperatorType *ot);
void POSE_OT_reveal(struct wmOperatorType *ot);
void POSE_OT_rot_clear(struct wmOperatorType *ot);
void POSE_OT_loc_clear(struct wmOperatorType *ot);
void POSE_OT_scale_clear(struct wmOperatorType *ot);
void POSE_OT_select_all_toggle(struct wmOperatorType *ot);
void POSE_OT_select_inverse(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);
@ -62,6 +71,16 @@ void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(struct wmOperatorType *ot);
void POSE_OT_groups_menu(struct wmOperatorType *ot);
void POSE_OT_group_add(struct wmOperatorType *ot);
void POSE_OT_group_remove(struct wmOperatorType *ot);
void POSE_OT_group_remove(struct wmOperatorType *ot);
void POSE_OT_group_assign(struct wmOperatorType *ot);
void POSE_OT_group_unassign(struct wmOperatorType *ot);
/* ******************************************************* */
/* Etch-A-Ton */
void SKETCH_OT_gesture(struct wmOperatorType *ot);
void SKETCH_OT_delete(struct wmOperatorType *ot);
void SKETCH_OT_draw_stroke(struct wmOperatorType *ot);
@ -70,12 +89,14 @@ void SKETCH_OT_finish_stroke(struct wmOperatorType *ot);
void SKETCH_OT_cancel_stroke(struct wmOperatorType *ot);
void SKETCH_OT_select(struct wmOperatorType *ot);
/* ******************************************************* */
/* PoseLib */
void POSELIB_OT_pose_add(struct wmOperatorType *ot);
void POSELIB_OT_pose_remove(struct wmOperatorType *ot);
void POSELIB_OT_pose_rename(struct wmOperatorType *ot);
void POSELIB_OT_browse_interactive(struct wmOperatorType *ot);
/* ******************************************************* */
/* editarmature.c */
struct bArmature;
struct EditBone;

@ -155,6 +155,12 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_select_linked);
WM_operatortype_append(POSE_OT_select_constraint_target);
WM_operatortype_append(POSE_OT_groups_menu);
WM_operatortype_append(POSE_OT_group_add);
WM_operatortype_append(POSE_OT_group_remove);
WM_operatortype_append(POSE_OT_group_assign);
WM_operatortype_append(POSE_OT_group_unassign);
/* POSELIB */
WM_operatortype_append(POSELIB_OT_browse_interactive);
@ -256,6 +262,8 @@ void ED_keymap_armature(wmWindowManager *wm)
WM_keymap_add_item(keymap, "POSE_OT_ik_add", IKEY, KM_PRESS, /*KM_CTRL|*/KM_SHIFT, 0);
WM_keymap_add_item(keymap, "POSE_OT_ik_clear", IKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
WM_keymap_add_item(keymap, "POSE_OT_groups_menu", GKEY, KM_PRESS, KM_CTRL, 0);
// XXX this should probably be in screen instead... here for testing purposes in the meantime... - Aligorith
WM_keymap_verify_item(keymap, "ANIM_OT_insert_keyframe_menu", IKEY, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "ANIM_OT_delete_keyframe_old", IKEY, KM_PRESS, KM_ALT, 0);

@ -1598,9 +1598,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *op)
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
/* if (okee("Erase selected bone(s)")==0) return; */
return OPERATOR_CANCELLED;
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {

@ -81,6 +81,8 @@
#include "ED_transform.h" /* for autokey TFM_TRANSLATION, etc */
#include "ED_view3d.h"
#include "UI_interface.h"
#include "armature_intern.h"
/* ************* XXX *************** */
@ -397,7 +399,7 @@ void pose_clear_paths(Object *ob)
}
// XXX this function is to be removed when the other stuff is recoded
void pose_select_constraint_target(Scene *scene)
{
Object *obedit= scene->obedit; // XXX context
@ -932,171 +934,301 @@ void pose_adds_vgroups(Scene *scene, Object *meshobj, int heatweights)
/* ********************************************** */
/* adds a new pose-group */
void pose_add_posegroup (Scene *scene)
static int pose_group_add_exec (bContext *C, wmOperator *op)
{
Object *ob= OBACT;
bPose *pose= (ob) ? ob->pose : NULL;
bActionGroup *grp;
ScrArea *sa= CTX_wm_area(C);
Object *ob;
if (ELEM(NULL, ob, ob->pose))
return;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
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);
/* only continue if there's an object */
if (ob == NULL)
return OPERATOR_CANCELLED;
pose->active_group= BLI_countlist(&pose->agroups);
/* for now, just call the API function for this */
pose_add_group(ob);
BIF_undo_push("Add Bone Group");
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
return OPERATOR_FINISHED;
}
/* Remove the active bone-group */
void pose_remove_posegroup (Scene *scene)
void POSE_OT_group_add (wmOperatorType *ot)
{
Object *ob= OBACT;
bPose *pose= (ob) ? ob->pose : NULL;
bActionGroup *grp = NULL;
bPoseChannel *pchan;
/* identifiers */
ot->name= "Add Bone Group";
ot->idname= "POSE_OT_group_add";
ot->description= "Add a new bone group.";
/* 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) {
/* adjust group references (the trouble of using indices!):
* - firstly, make sure nothing references it
* - also, make sure that those after this item get corrected
*/
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
if (pchan->agrp_index == pose->active_group)
pchan->agrp_index= 0;
else if (pchan->agrp_index > pose->active_group)
pchan->agrp_index--;
}
/* now, remove it from the pose */
BLI_freelinkN(&pose->agroups, grp);
pose->active_group= 0;
BIF_undo_push("Remove Bone Group");
}
/* api callbacks */
ot->exec= pose_group_add_exec;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
char *build_posegroups_menustr (bPose *pose, short for_pupmenu)
static int pose_group_remove_exec (bContext *C, wmOperator *op)
{
DynStr *pupds= BLI_dynstr_new();
ScrArea *sa= CTX_wm_area(C);
Object *ob;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
/* only continue if there's an object */
if (ob == NULL)
return OPERATOR_CANCELLED;
/* for now, just call the API function for this */
pose_remove_group(ob);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
return OPERATOR_FINISHED;
}
void POSE_OT_group_remove (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Remove Bone Group";
ot->idname= "POSE_OT_group_remove";
ot->description= "Removes the active bone group.";
/* api callbacks */
ot->exec= pose_group_remove_exec;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ------------ */
/* invoke callback which presents a list of bone-groups for the user to choose from */
static int pose_groups_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
ScrArea *sa= CTX_wm_area(C);
Object *ob;
bPose *pose;
uiPopupMenu *pup;
uiLayout *layout;
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|");
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
BLI_dynstr_append(pupds, "BG: [None]%x0|");
ob= CTX_data_active_object(C);
/* loop through groups, 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);
/* only continue if there's an object, and a pose there too */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose= ob->pose;
sprintf(buf, "%%x%d", i);
BLI_dynstr_append(pupds, buf);
/* if there's no active group (or active is invalid), create a new menu to find it */
if (pose->active_group <= 0) {
/* create a new menu, and start populating it with group names */
pup= uiPupMenuBegin(C, op->type->name, 0);
layout= uiPupMenuLayout(pup);
if (grp->next)
BLI_dynstr_append(pupds, "|");
/* special entry - allow to create new group, then use that
* (not to be used for removing though)
*/
if (strstr(op->idname, "assign")) {
uiItemIntO(layout, "New Group", 0, op->idname, "type", 0);
uiItemS(layout);
}
/* add entries for each group */
for (grp= pose->agroups.first, i=1; grp; grp=grp->next, i++)
uiItemIntO(layout, grp->name, 0, op->idname, "type", i);
/* finish building the menu, and process it (should result in calling self again) */
uiPupMenuEnd(C, pup);
return OPERATOR_CANCELLED;
}
else {
/* just use the active group index, and call the exec callback for the calling operator */
RNA_int_set(op->ptr, "type", pose->active_group);
return op->type->exec;
}
/* 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 (Scene *scene, short active)
static int pose_group_assign_exec (bContext *C, wmOperator *op)
{
Object *ob= OBACT;
bArmature *arm= (ob) ? ob->data : NULL;
bPose *pose= (ob) ? ob->pose : NULL;
bPoseChannel *pchan;
char *menustr;
int nr;
ScrArea *sa= CTX_wm_area(C);
Object *ob;
bPose *pose;
short done= 0;
/* sanity checks */
if (ELEM3(NULL, ob, pose, arm))
return;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
/* get group to affect */
if ((active==0) || (pose->active_group <= 0)) {
menustr= build_posegroups_menustr(pose, 1);
nr= 0; // XXX pupmenu_col(menustr, 20);
MEM_freeN(menustr);
/* only continue if there's an object, and a pose there too */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose= ob->pose;
if (nr < 0)
return;
else if (nr == 0) {
/* add new - note: this does an undo push and sets active group */
pose_add_posegroup(scene);
}
else
pose->active_group= nr;
}
/* set the active group number to the one from operator props */
pose->active_group= RNA_int_get(op->ptr, "type");
/* 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;
CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
{
pchan->agrp_index= pose->active_group;
done= 1;
}
CTX_DATA_END;
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
/* report done status */
if (done)
return OPERATOR_FINISHED;
else
return OPERATOR_CANCELLED;
}
void POSE_OT_group_assign (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Add Selected to Bone Group";
ot->idname= "POSE_OT_group_assign";
ot->description= "Add selected bones to the chosen bone group.";
/* api callbacks */
ot->invoke= pose_groups_menu_invoke;
ot->exec= pose_group_assign_exec;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna, "type", 0, 0, 10, "Bone Group Index", "", 0, INT_MAX);
}
static int pose_group_unassign_exec (bContext *C, wmOperator *op)
{
ScrArea *sa= CTX_wm_area(C);
Object *ob;
bPose *pose;
short done= 0;
/* since this call may also be used from the buttons window, we need to check for where to get the object */
if (sa->spacetype == SPACE_BUTS)
ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
else
ob= CTX_data_active_object(C);
/* only continue if there's an object, and a pose there too */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose= ob->pose;
/* add selected bones to ungroup then */
CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
{
if (pchan->agrp_index) {
pchan->agrp_index= 0;
done= 1;
}
}
CTX_DATA_END;
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
/* report done status */
if (done)
BIF_undo_push("Add Bones To Group");
return OPERATOR_FINISHED;
else
return OPERATOR_CANCELLED;
}
/* Remove selected pchans from their bone groups */
void pose_remove_from_posegroups (Scene *scene)
void POSE_OT_group_unassign (wmOperatorType *ot)
{
Object *ob= OBACT;
bArmature *arm= (ob) ? ob->data : NULL;
bPose *pose= (ob) ? ob->pose : NULL;
bPoseChannel *pchan;
short done= 0;
/* identifiers */
ot->name= "Remove Selected from Bone Groups";
ot->idname= "POSE_OT_group_unassign";
ot->description= "Add selected bones from all bone groups";
/* sanity checks */
if (ELEM3(NULL, ob, pose, arm))
return;
/* api callbacks */
ot->exec= pose_group_unassign_exec;
ot->poll= ED_operator_posemode;
/* 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;
}
}
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ----------------- */
static int pose_groupOps_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
Object *ob= CTX_data_active_object(C);
uiPopupMenu *pup= uiPupMenuBegin(C, op->type->name, 0);
uiLayout *layout= uiPupMenuLayout(pup);
/* sanity check - must have object with pose */
if ELEM(NULL, ob, ob->pose)
return OPERATOR_CANCELLED;
/* get mode of action */
if (CTX_DATA_COUNT(C, selected_pchans)) {
/* if selected bone(s), include options to add/remove to active group */
uiItemO(layout, "Add Selected to Active Group", 0, "POSE_OT_group_assign");
uiItemS(layout);
uiItemO(layout, "Remove Selected from All Groups", 0, "POSE_OT_group_unassign");
uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
}
else {
/* no selected bones - so just options for groups management */
uiItemO(layout, "Add New Group", 0, "POSE_OT_group_add");
uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
}
if (done)
BIF_undo_push("Remove Bones From Groups");
return OPERATOR_CANCELLED;
}
void POSE_OT_groups_menu (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Bone Group Tools";
ot->idname= "POSE_OT_groups_menu";
ot->description= "Menu displaying available tools for Bone Groups.";
/* api callbacks (only invoke needed) */
ot->invoke= pose_groupOps_menu_invoke;
ot->poll= ED_operator_posemode;
/* flags */
ot->flag= OPTYPE_REGISTER;
}
#if 0
/* Ctrl-G in 3D-View while in PoseMode */
void pgroup_operation_with_menu (Scene *scene)
{
@ -1143,6 +1275,7 @@ void pgroup_operation_with_menu (Scene *scene)
break;
}
}
#endif
/* ********************************************** */

@ -3040,47 +3040,18 @@ static void view3d_pose_armature_constraintsmenu(bContext *C, uiLayout *layout,
uiItemO(layout, NULL, 0, "POSE_OT_constraints_clear");
}
static void view3d_pose_armature_groupmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemO(layout, "Add Selected to Active Group", 0, "POSE_OT_group_assign");
//uiItemO(layout, "Add Selected to Group", 0, "POSE_OT_group_assign");
uiItemO(layout, "Add New Group", 0, "POSE_OT_group_add");
uiItemO(layout, "Remove from All Groups", 0, "POSE_OT_group_unassign");
uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
}
#if 0
static void do_view3d_pose_armature_groupmenu(bContext *C, void *arg, int event)
{
switch (event) {
case 1:
pose_assign_to_posegroup(1);
break;
case 2:
pose_assign_to_posegroup(0);
break;
case 3:
pose_add_posegroup();
break;
case 4:
pose_remove_from_posegroups();
break;
case 5:
pose_remove_posegroup();
break;
}
}
static uiBlock *view3d_pose_armature_groupmenu(bContext *C, ARegion *ar, void *arg_unused)
{
uiBlock *block;
short yco = 20, menuwidth = 120;
block= uiBeginBlock(C, ar, "view3d_pose_armature_groupmenu", UI_EMBOSSP);
uiBlockSetButmFunc(block, do_view3d_pose_armature_groupmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Selected to Active Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Selected to Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add New Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remove from All Groups|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remove Active Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60);
return block;
}
static void do_view3d_pose_armature_motionpathsmenu(bContext *C, void *arg, int event)
{
switch(event) {
@ -3214,7 +3185,7 @@ static void view3d_pose_armaturemenu(bContext *C, uiLayout *layout, void *arg_un
uiItemMenuF(layout, "Pose Library", 0, view3d_pose_armature_poselibmenu);
//uiItemMenuF(layout, "Motion Paths", 0, view3d_pose_armature_motionpathsmenu);
//uiItemMenuF(layout, "Bone Groups", 0, view3d_pose_armature_groupmenu);
uiItemMenuF(layout, "Bone Groups", 0, view3d_pose_armature_groupmenu);
uiItemS(layout);

@ -63,6 +63,7 @@ extern StructRNA RNA_BezierCurvePoint;
extern StructRNA RNA_BlendTexture;
extern StructRNA RNA_BlenderRNA;
extern StructRNA RNA_Bone;
extern StructRNA RNA_BoneGroup;
extern StructRNA RNA_BooleanModifier;
extern StructRNA RNA_BooleanProperty;
extern StructRNA RNA_Brush;

@ -107,11 +107,106 @@ static int rna_PoseChannel_has_ik_get(PointerRNA *ptr)
return ED_pose_channel_in_IK_chain(ob, pchan);
}
static PointerRNA rna_Pose_active_bone_group_get(PointerRNA *ptr)
{
bPose *pose= (bPose*)ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_BoneGroup, BLI_findlink(&pose->agroups, pose->active_group-1));
}
static int rna_Pose_active_bone_group_index_get(PointerRNA *ptr)
{
bPose *pose= (bPose*)ptr->data;
return MAX2(pose->active_group-1, 0);
}
static void rna_Pose_active_bone_group_index_set(PointerRNA *ptr, int value)
{
bPose *pose= (bPose*)ptr->data;
pose->active_group= value+1;
}
static void rna_Pose_active_bone_group_index_range(PointerRNA *ptr, int *min, int *max)
{
bPose *pose= (bPose*)ptr->data;
*min= 0;
*max= BLI_countlist(&pose->agroups)-1;
*max= MAX2(0, *max);
}
void rna_pose_bgroup_name_index_get(PointerRNA *ptr, char *value, int index)
{
bPose *pose= (bPose*)ptr->data;
bActionGroup *grp;
grp= BLI_findlink(&pose->agroups, index-1);
if(grp) BLI_strncpy(value, grp->name, sizeof(grp->name));
else BLI_strncpy(value, "", sizeof(grp->name)); // XXX if invalid pointer, won't this crash?
}
int rna_pose_bgroup_name_index_length(PointerRNA *ptr, int index)
{
bPose *pose= (bPose*)ptr->data;
bActionGroup *grp;
grp= BLI_findlink(&pose->agroups, index-1);
return (grp)? strlen(grp->name): 0;
}
void rna_pose_bgroup_name_index_set(PointerRNA *ptr, const char *value, short *index)
{
bPose *pose= (bPose*)ptr->data;
bActionGroup *grp;
int a;
for (a=1, grp=pose->agroups.first; grp; grp=grp->next, a++) {
if (strcmp(grp->name, value) == 0) {
*index= a;
return;
}
}
*index= 0;
}
void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen)
{
bPose *pose= (bPose*)ptr->data;
bActionGroup *grp;
for (grp= pose->agroups.first; grp; grp= grp->next) {
if (strcmp(grp->name, value) == 0) {
BLI_strncpy(result, value, maxlen);
return;
}
}
BLI_strncpy(result, "", maxlen);
}
#else
/* users shouldn't be editing pose channel data directly -- better to set ipos and let blender calc pose_channel stuff */
/* it's going to be weird for users to find IK flags and other such here, instead of in bone where they would expect them
-- is there any way to put a doc in bone, pointing them here? */
static void rna_def_bone_group(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "BoneGroup", NULL);
RNA_def_struct_sdna(srna, "bActionGroup");
RNA_def_struct_ui_text(srna, "Bone Group", "Groups of Pose Channels (Bones).");
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
// TODO: add some runtime-collections stuff to access grouped bones
// FIXME: this needs more work - probably a custom template?
prop= RNA_def_property(srna, "custom_color", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "customCol");
RNA_def_property_ui_text(prop, "Custom Color", "Index of custom color set.");
}
static void rna_def_pose_channel(BlenderRNA *brna)
{
@ -341,27 +436,47 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Lock Scale", "Lock editing of scale in the interface.");
}
void RNA_def_pose(BlenderRNA *brna)
static void rna_def_pose(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
rna_def_pose_channel(brna);
/* struct definition */
srna= RNA_def_struct(brna, "Pose", NULL);
RNA_def_struct_sdna(srna, "bPose");
RNA_def_struct_ui_text(srna, "Pose", "A collection of pose channels, including settings for animating bones.");
/* pose channels */
prop= RNA_def_property(srna, "pose_channels", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL);
RNA_def_property_struct_type(prop, "PoseChannel");
RNA_def_property_ui_text(prop, "Pose Channels", "Individual pose channels for the armature.");
/* commented for now... missing info... */
/*prop= RNA_def_property(srna, "action_groups", PROP_COLLECTION, PROP_NONE);
/* bone groups */
prop= RNA_def_property(srna, "bone_groups", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "agroups", NULL);
RNA_def_property_struct_type(prop, "ActionGroup");
RNA_def_property_ui_text(prop, "Action Groups", "Groups of bones.");*/
RNA_def_property_struct_type(prop, "BoneGroup");
RNA_def_property_ui_text(prop, "Bone Groups", "Groups of the bones.");
prop= RNA_def_property(srna, "active_bone_group", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BoneGroup");
RNA_def_property_pointer_funcs(prop, "rna_Pose_active_bone_group_get", "rna_Pose_active_bone_group_set", NULL);
RNA_def_property_ui_text(prop, "Active Bone Group", "Bone groups of the pose.");
RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update");
prop= RNA_def_property(srna, "active_bone_group_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "active_group");
RNA_def_property_int_funcs(prop, "rna_Pose_active_bone_group_index_get", "rna_Pose_active_bone_group_index_set", "rna_Pose_active_bone_group_index_range");
RNA_def_property_ui_text(prop, "Active Bone Group Index", "Active index in bone groups array.");
RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update");
}
void RNA_def_pose(BlenderRNA *brna)
{
rna_def_pose(brna);
rna_def_pose_channel(brna);
rna_def_bone_group(brna);
}
#endif