diff --git a/release/ui/buttons_data_armature.py b/release/ui/buttons_data_armature.py index 94fda908e56..8eb7ba59c70 100644 --- a/release/ui/buttons_data_armature.py +++ b/release/ui/buttons_data_armature.py @@ -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) diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 0c9bba5e413..d35acb5447a 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -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,9 +111,8 @@ 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. * (Note: Object, not bPose is used here, as we need layer info from Armature) @@ -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); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 96896509f60..f4d4eb1cc9c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -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 #include -#include /* for NULL */ +#include +#include #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 ****************** */ diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index d5ad63ca21b..9ea7b1174a5 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -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; diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index ed98f70818e..84bddbf0725 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -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); diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 49f13d99af9..68d8ffbc11d 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -1598,10 +1598,8 @@ 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) { for (curBone=arm->edbo->first; curBone; curBone=curBone->next) { diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 16a9efc9023..d753cf39f69 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -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); + + /* only continue if there's an object */ + if (ob == NULL) + return OPERATOR_CANCELLED; - 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); + /* for now, just call the API function for this */ + pose_add_group(ob); - pose->active_group= BLI_countlist(&pose->agroups); - - 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; + + /* 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); - sprintf(buf, "%%x%d", i); - BLI_dynstr_append(pupds, buf); + /* 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); + } - if (grp->next) - BLI_dynstr_append(pupds, "|"); + /* 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; - - /* 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); - - 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; - } + /* 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; + + /* 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; - } - } - } - - if (done) - BIF_undo_push("Remove Bones From Groups"); - + /* 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"); + } + + 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 /* ********************************************** */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 1047e8ee7e5..edffa39cb8c 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -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); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f3c2e95451d..33bf1147748 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index c7ee7887aff..e15310a02bf 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -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