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.
This commit is contained in:
Joshua Leung
2009-07-21 13:12:40 +00:00
parent e56287bfc9
commit ea0b015b0a
5 changed files with 139 additions and 58 deletions

View 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;
}

View 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);

View 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);

View 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,88 +780,140 @@ 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;
/* 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;
}
/* ---- */
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;
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;
/* 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
if (autokeyframe_cfra_can_key(ob)) {
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);
@@ -904,7 +957,28 @@ void paste_posebuf (Scene *scene, int flip)
ob->recalc= 0;
}
BIF_undo_push("Paste Action Pose");
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_TRANSFORM, ob);
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", "");
}
/* ********************************************** */

View File

@@ -3175,14 +3175,14 @@ 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);
uiItemMenuF(layout, "Bone Groups", 0, view3d_pose_armature_groupmenu);
@@ -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);