From ea0b015b0a1c73fb1899a4d9040704a7d85fda9c Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 21 Jul 2009 13:12:40 +0000 Subject: [PATCH] 2.5 - Copy/Paste Operators for Armatures * 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 | 1 + .../editors/armature/armature_intern.h | 3 + .../blender/editors/armature/armature_ops.c | 9 + source/blender/editors/armature/poseobject.c | 154 +++++++++++++----- .../editors/space_view3d/view3d_header.c | 30 ++-- 5 files changed, 139 insertions(+), 58 deletions(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 62194caa658..37130a0e3a0 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -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; } diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 9ea7b1174a5..7b3f9a020e3 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -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); diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 84bddbf0725..bf4ec09f3fb 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -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); diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index eface169387..9814a056b70 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -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 paste_posebuf (Scene *scene, int flip) +void POSE_OT_copy (wmOperatorType *ot) { - Object *ob= OBACT; - bPoseChannel *chan, *pchan; - float eul[4]; - char name[32]; + /* identifiers */ + ot->name= "Copy Pose"; + ot->idname= "POSE_OT_copy"; + ot->description= "Copies the current pose of the selected bones to copy/paste buffer."; - if (!ob || !ob->pose) - return; + /* api callbacks */ + ot->exec= pose_copy_exec; + ot->poll= ED_operator_posemode; + + /* flag */ + ot->flag= OPTYPE_REGISTER; +} - if (!g_posebuf){ - error ("Copy buffer is empty"); - return; +/* ---- */ + +static int pose_paste_exec (bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Object *ob= CTX_data_active_object(C); + bPoseChannel *chan, *pchan; + char name[32]; + int flip= RNA_boolean_get(op->ptr, "flipped"); + + /* sanity checks */ + if ELEM(NULL, ob, ob->pose) + return OPERATOR_CANCELLED; + + 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); - BIF_undo_push("Paste Action Pose"); + return OPERATOR_FINISHED; +} + +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", ""); } /* ********************************************** */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index edffa39cb8c..4781e0e0108 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -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);