2.5 - Restoring Bone Groups
authorJoshua Leung <aligorith@gmail.com>
Tue, 21 Jul 2009 10:18:08 +0000 (10:18 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 21 Jul 2009 10:18:08 +0000 (10:18 +0000)
* 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.

release/ui/buttons_data_armature.py
source/blender/blenkernel/BKE_action.h
source/blender/blenkernel/intern/action.c
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/poseobject.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_pose.c

index 94fda908e569139e57069471efa954f9c96cfc6c..8eb7ba59c704d702d38f55164085c9475db5d0fa 100644 (file)
@@ -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)
index 0c9bba5e413c1c810a79599f18f16ce88b801421..d35acb5447aae7e82c35fca7a1a2513a70336216 100644 (file)
@@ -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);
index 96896509f601d198ceb4907c445ddb04b9e79d8a..f4d4eb1cc9c3109b4a86100f197142b4082440fc 100644 (file)
@@ -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 ****************** */
 
index d5ad63ca21b63a08483668ea24cb9a8f70dc5b57..9ea7b1174a5c179d9c4fad86daaf7e621d1eaea1 100644 (file)
@@ -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;
index ed98f70818eebecb9b871536be71e151db33ebc2..84bddbf07256b8212b4576eaf72efee8acc51969 100644 (file)
@@ -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);
index 49f13d99af98f6a297dbdaf219fa9a9ebb02729c..68d8ffbc11d86ef7e52927470d5b2337eb6ea473 100644 (file)
@@ -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) {
index 16a9efc90231dc5ee5edf3675e6f0f3db1e157ee..d753cf39f69c09d266aa1ef6678473592a41e785 100644 (file)
@@ -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);
+       /* notifiers for updates */
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
        
-       BIF_undo_push("Add Bone Group");
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_add (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Bone Group";
+       ot->idname= "POSE_OT_group_add";
+       ot->description= "Add a new bone group.";
+       
+       /* api callbacks */
+       ot->exec= pose_group_add_exec;
+       ot->poll= ED_operator_posemode;
        
+       /* flags */
+       ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-/* Remove the active bone-group */
-void pose_remove_posegroup (Scene *scene)
+
+static int pose_group_remove_exec (bContext *C, wmOperator *op)
 {
-       Object *ob= OBACT;
-       bPose *pose= (ob) ? ob->pose : NULL;
-       bActionGroup *grp = NULL;
-       bPoseChannel *pchan;
+       ScrArea *sa= CTX_wm_area(C);
+       Object *ob;
        
-       /* sanity checks */
-       if (ELEM(NULL, ob, pose))
-               return;
-       if (pose->active_group <= 0)
-               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 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");
-       }
+       /* 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;
 }
 
-char *build_posegroups_menustr (bPose *pose, short for_pupmenu)
+void POSE_OT_group_remove (wmOperatorType *ot)
 {
-       DynStr *pupds= BLI_dynstr_new();
+       /* 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);
+               }
+               
+               /* 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);
                
-               if (grp->next)
-                       BLI_dynstr_append(pupds, "|");
+               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;
-                       done= 1;
-               }
+       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)
-               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_assign (wmOperatorType *ot)
 {
-       Object *ob= OBACT;
-       bArmature *arm= (ob) ? ob->data : NULL;
-       bPose *pose= (ob) ? ob->pose : NULL;
-       bPoseChannel *pchan;
+       /* 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;
        
-       /* 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);
        
-       /* 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;
-                       }
+       /* 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("Remove Bones From Groups");
+               return OPERATOR_FINISHED;
+       else
+               return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_group_unassign (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Remove Selected from Bone Groups";
+       ot->idname= "POSE_OT_group_unassign";
+       ot->description= "Add selected bones from all bone groups";
+       
+       /* api callbacks */
+       ot->exec= pose_group_unassign_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* 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
 
 /* ********************************************** */
 
index 1047e8ee7e5a618713b9005c101009474b272d3d..edffa39cb8c89a889d0e6cd4c1eabc66b41a6a4a 100644 (file)
@@ -3040,47 +3040,18 @@ static void view3d_pose_armature_constraintsmenu(bContext *C, uiLayout *layout,
        uiItemO(layout, NULL, 0, "POSE_OT_constraints_clear");
 }
 
-#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)
+static void view3d_pose_armature_groupmenu(bContext *C, uiLayout *layout, void *arg_unused)
 {
-       uiBlock *block;
-       short yco = 20, menuwidth = 120;
+       uiItemO(layout, "Add Selected to Active Group", 0, "POSE_OT_group_assign");
+       //uiItemO(layout, "Add Selected to Group", 0, "POSE_OT_group_assign");
        
-       block= uiBeginBlock(C, ar, "view3d_pose_armature_groupmenu", UI_EMBOSSP);
-       uiBlockSetButmFunc(block, do_view3d_pose_armature_groupmenu, NULL);
+       uiItemO(layout, "Add New Group", 0, "POSE_OT_group_add");
        
-       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;
+       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_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);
        
index f3c2e95451d41d88cfc0fe804ab7dba79cb6a034..33bf1147748fca9c57074e9c48f0132348598c65 100644 (file)
@@ -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;
index c7ee7887aff460a15c1f8365de41870b1402a92b..e15310a02bf97c75ad8211b1ccf1536a80385b28 100644 (file)
@@ -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