2.5 - Copy/Paste Operators for Armatures
authorJoshua Leung <aligorith@gmail.com>
Tue, 21 Jul 2009 13:12:40 +0000 (13:12 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 21 Jul 2009 13:12:40 +0000 (13:12 +0000)
* Buttons in header now use operators too. The paste-flipped button needs attention though, since the flipped argument isn't set yet

* Assigned Ctrl-C, Ctrl-V, and Ctrl-Shift-V to Copy/Paste/Paste-Flipped respectively for now.

* Auto-Keying for this doesn't work again yet. On todo for later...

---

* Also, new armatures now get the flag to show custom bone colours enabled by default.

source/blender/blenkernel/intern/armature.c
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/poseobject.c
source/blender/editors/space_view3d/view3d_header.c

index 62194caa6583908a7b678fe6b5f1eec9df14a01a..37130a0e3a0a418d96a52dfb82359c1ecaf0626c 100644 (file)
@@ -83,6 +83,7 @@ bArmature *add_armature(char *name)
        
        arm= alloc_libblock (&G.main->armature, ID_AR, name);
        arm->deformflag = ARM_DEF_VGROUP|ARM_DEF_ENVELOPE;
+       arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
        arm->layer= 1;
        return arm;
 }
index 9ea7b1174a5c179d9c4fad86daaf7e621d1eaea1..7b3f9a020e3626544d0f5db9f7bf9a28c50f6b82 100644 (file)
@@ -64,6 +64,9 @@ 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_copy(struct wmOperatorType *ot);
+void POSE_OT_paste(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);
index 84bddbf07256b8212b4576eaf72efee8acc51969..bf4ec09f3fbdc26e2241b1ba06269f263825096d 100644 (file)
@@ -147,6 +147,9 @@ void ED_operatortypes_armature(void)
        WM_operatortype_append(POSE_OT_loc_clear);
        WM_operatortype_append(POSE_OT_scale_clear);
        
+       WM_operatortype_append(POSE_OT_copy);
+       WM_operatortype_append(POSE_OT_paste);
+       
        WM_operatortype_append(POSE_OT_select_all_toggle);
        WM_operatortype_append(POSE_OT_select_inverse);
 
@@ -238,6 +241,12 @@ void ED_keymap_armature(wmWindowManager *wm)
        WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0);
        WM_keymap_add_item(keymap, "POSE_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
        
+               // for now, we include hotkeys for copy/paste
+       WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+       kmi= WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
+               RNA_boolean_set(kmi->ptr, "flipped", 1);
+       
        WM_keymap_add_item(keymap, "POSE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "POSE_OT_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
 
index eface1693876553fa4a5f900d6e0aceb8011d7d8..9814a056b703d9f0ff787276967a39425bc13bb6 100644 (file)
@@ -63,6 +63,7 @@
 #include "BKE_modifier.h"
 #include "BKE_object.h"
 #include "BKE_utildefines.h"
+#include "BKE_report.h"
 
 #include "BIF_gl.h"
 
@@ -779,81 +780,132 @@ void pose_copy_menu(Scene *scene)
 
 /* ******************** copy/paste pose ********************** */
 
-static bPose   *g_posebuf=NULL;
+/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
+static bPose *g_posebuf = NULL;
 
 void free_posebuf(void) 
 {
        if (g_posebuf) {
-               // was copied without constraints
-               BLI_freelistN (&g_posebuf->chanbase);
-               MEM_freeN (g_posebuf);
+               /* was copied without constraints */
+               BLI_freelistN(&g_posebuf->chanbase);
+               MEM_freeN(g_posebuf);
        }
+       
        g_posebuf=NULL;
 }
 
-void copy_posebuf (Scene *scene)
-{
-       Object *ob= OBACT;
+/* ---- */
 
-       if (!ob || !ob->pose){
-               error ("No Pose");
-               return;
+static int pose_copy_exec (bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       
+       /* sanity checking */
+       if ELEM(NULL, ob, ob->pose) {
+               BKE_report(op->reports, RPT_ERROR, "No Pose to Copy");
+               return OPERATOR_CANCELLED;
        }
 
+       /* free existing pose buffer */
        free_posebuf();
        
-       set_pose_keys(ob);  // sets chan->flag to POSE_KEY if bone selected
+       /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
+       set_pose_keys(ob);  
        copy_pose(&g_posebuf, ob->pose, 0);
+       
+       
+       return OPERATOR_FINISHED;
+}
 
+void POSE_OT_copy (wmOperatorType *ot) 
+{
+       /* identifiers */
+       ot->name= "Copy Pose";
+       ot->idname= "POSE_OT_copy";
+       ot->description= "Copies the current pose of the selected bones to copy/paste buffer.";
+       
+       /* api callbacks */
+       ot->exec= pose_copy_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flag */
+       ot->flag= OPTYPE_REGISTER;
 }
 
-void paste_posebuf (Scene *scene, int flip)
+/* ---- */
+
+static int pose_paste_exec (bContext *C, wmOperator *op)
 {
-       Object *ob= OBACT;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
        bPoseChannel *chan, *pchan;
-       float eul[4];
        char name[32];
+       int flip= RNA_boolean_get(op->ptr, "flipped");
        
-       if (!ob || !ob->pose)
-               return;
+       /* sanity checks */
+       if ELEM(NULL, ob, ob->pose)
+               return OPERATOR_CANCELLED;
 
-       if (!g_posebuf){
-               error ("Copy buffer is empty");
-               return;
+       if (g_posebuf == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+               return OPERATOR_CANCELLED;
        }
        
-       /*
-       // disabled until protected bones in proxies follow the rules everywhere else!
-       if(pose_has_protected_selected(ob, 1, 1))
-               return;
-       */
-       
-       /* Safely merge all of the channels in this pose into
-       any existing pose */
-       for (chan=g_posebuf->chanbase.first; chan; chan=chan->next) {
+       /* Safely merge all of the channels in the buffer pose into any existing pose */
+       for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) {
                if (chan->flag & POSE_KEY) {
+                       /* get the name - if flipping, we must flip this first */
                        BLI_strncpy(name, chan->name, sizeof(name));
                        if (flip)
-                               bone_flip_name (name, 0);               // 0 = don't strip off number extensions
+                               bone_flip_name(name, 0);                /* 0 = don't strip off number extensions */
                                
                        /* only copy when channel exists, poses are not meant to add random channels to anymore */
                        pchan= get_pose_channel(ob->pose, name);
                        
                        if (pchan) {
-                               /* only loc rot size */
-                               /* only copies transform info for the pose */
+                               /* only loc rot size 
+                                *      - only copies transform info for the pose 
+                                */
                                VECCOPY(pchan->loc, chan->loc);
                                VECCOPY(pchan->size, chan->size);
-                               QUATCOPY(pchan->quat, chan->quat);
                                pchan->flag= chan->flag;
                                
+                               /* check if rotation modes are compatible (i.e. do they need any conversions) */
+                               if (pchan->rotmode == chan->rotmode) {
+                                       /* copy the type of rotation in use */
+                                       if (pchan->rotmode) {
+                                               VECCOPY(pchan->eul, chan->eul);
+                                       }
+                                       else {
+                                               QUATCOPY(pchan->quat, chan->quat);
+                                       }
+                               }
+                               else if (pchan->rotmode) {
+                                       /* quat to euler */
+                                       QuatToEul(chan->quat, pchan->eul);
+                               }
+                               else {
+                                       /* euler to quat */
+                                       EulToQuat(chan->eul, pchan->quat);
+                               }
+                               
+                               /* paste flipped pose? */
                                if (flip) {
                                        pchan->loc[0]*= -1;
                                        
-                                       QuatToEul(pchan->quat, eul);
-                                       eul[1]*= -1;
-                                       eul[2]*= -1;
-                                       EulToQuat(eul, pchan->quat);
+                                       /* has to be done as eulers... */
+                                       if (pchan->rotmode) {
+                                               pchan->eul[1] *= -1;
+                                               pchan->eul[2] *= -1;
+                                       }
+                                       else {
+                                               float eul[3];
+                                               
+                                               QuatToEul(pchan->quat, eul);
+                                               eul[1]*= -1;
+                                               eul[2]*= -1;
+                                               EulToQuat(eul, pchan->quat);
+                                       }
                                }
                                
 #if 0 // XXX old animation system
@@ -861,6 +913,7 @@ void paste_posebuf (Scene *scene, int flip)
                                        ID *id= &ob->id;
                                        
                                        /* Set keys on pose */
+                                       // TODO: make these use keyingsets....
                                        if (chan->flag & POSE_ROT) {
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
                                                insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
@@ -903,8 +956,29 @@ void paste_posebuf (Scene *scene, int flip)
                where_is_pose(scene, ob);
                ob->recalc= 0;
        }
+       
+       /* notifiers for updates */
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_TRANSFORM, ob);
+
+       return OPERATOR_FINISHED;
+}
 
-       BIF_undo_push("Paste Action Pose");
+void POSE_OT_paste (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Paste Pose";
+       ot->idname= "POSE_OT_paste";
+       ot->description= "Pastes the stored pose on to the current pose.";
+       
+       /* api callbacks */
+       ot->exec= pose_paste_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flag */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "flipped", 0, "Flipped on X-Axis", "");
 }
 
 /* ********************************************** */
index edffa39cb8c89a889d0e6cd4c1eabc66b41a6a4a..4781e0e010841290fd82f93df6c107c091de024c 100644 (file)
@@ -3175,13 +3175,13 @@ static void view3d_pose_armaturemenu(bContext *C, uiLayout *layout, void *arg_un
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Pose as Restpose|Ctrl A",          0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
 
        uiDefBut(block, SEPR, 0, "",                            0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
-
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copy Current Pose",                              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste Pose",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
-       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste Flipped Pose",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");   
-       
-       uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
 #endif
+       
+       uiItemO(layout, "Copy Current Pose", 0, "POSE_OT_copy");
+       uiItemO(layout, "Paste Pose", 0, "POSE_OT_paste");
+       uiItemBooleanO(layout, "Paste X-Flipped Pose", 0, "POSE_OT_paste", "flipped", 1);
+       
+       uiItemS(layout);
 
        uiItemMenuF(layout, "Pose Library", 0, view3d_pose_armature_poselibmenu);
        //uiItemMenuF(layout, "Motion Paths", 0, view3d_pose_armature_motionpathsmenu);
@@ -4492,24 +4492,18 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
 
                uiDefIconBut(block, BUT, B_VIEWRENDER, ICON_SCENE, xco,yco,XIC,YIC, NULL, 0, 1.0, 0, 0, "Render this window (Ctrl Click for anim)");
                
-               
                if (ob && (ob->flag & OB_POSEMODE)) {
-                       xco+= XIC/2;
+                       xco+= XIC;
                        uiBlockBeginAlign(block);
                        
-                       uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYDOWN,
-                                        xco,yco,XIC,YIC, 0, 0, 0, 0, 0, 
-                                        "Copies the current pose to the buffer");
+                       uiDefIconButO(block, BUT, "POSE_OT_copy", WM_OP_INVOKE_REGION_WIN, ICON_COPYDOWN, xco,yco,XIC,YIC, NULL);
                        uiBlockSetButLock(block, object_data_is_libdata(ob), "Can't edit external libdata");
                        xco+= XIC;
-
-                       uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEDOWN,
-                                        xco,yco,XIC,YIC, 0, 0, 0, 0, 0, 
-                                        "Pastes the pose from the buffer");
+                       
+                       uiDefIconButO(block, BUT, "POSE_OT_paste", WM_OP_INVOKE_REGION_WIN, ICON_PASTEDOWN, xco,yco,XIC,YIC, NULL);
                        xco+= XIC;
-                       uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPDOWN, 
-                                        xco,yco,XIC,YIC, 0, 0, 0, 0, 0, 
-                                        "Pastes the mirrored pose from the buffer");
+                               // FIXME: this needs an extra arg...
+                       uiDefIconButO(block, BUT, "POSE_OT_paste", WM_OP_INVOKE_REGION_WIN, ICON_PASTEFLIPDOWN, xco,yco,XIC,YIC, NULL);
                        uiBlockEndAlign(block);
                        header_xco_step(ar, &xco, &yco, &maxco, XIC);