Blender V2.61 - r43446

poseobject.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
00022  *               Joshua Leung
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  * support for animation modes - Reevan McKay
00026  */
00027 
00033 #include <stdlib.h>
00034 #include <stddef.h>
00035 #include <string.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "BLI_math.h"
00040 #include "BLI_blenlib.h"
00041 #include "BLI_dynstr.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "DNA_anim_types.h"
00045 #include "DNA_armature_types.h"
00046 #include "DNA_constraint_types.h"
00047 #include "DNA_scene_types.h"
00048 #include "DNA_object_types.h"
00049 
00050 #include "BKE_animsys.h"
00051 #include "BKE_anim.h"
00052 #include "BKE_idprop.h"
00053 #include "BKE_action.h"
00054 #include "BKE_armature.h"
00055 #include "BKE_context.h"
00056 #include "BKE_constraint.h"
00057 #include "BKE_deform.h"
00058 #include "BKE_depsgraph.h"
00059 #include "BKE_fcurve.h"
00060 #include "BKE_modifier.h"
00061 #include "BKE_object.h"
00062 #include "BKE_report.h"
00063 
00064 
00065 #include "RNA_access.h"
00066 #include "RNA_define.h"
00067 #include "RNA_enum_types.h"
00068 
00069 #include "WM_api.h"
00070 #include "WM_types.h"
00071 
00072 #include "ED_armature.h"
00073 #include "ED_keyframing.h"
00074 #include "ED_mesh.h"
00075 #include "ED_screen.h"
00076 #include "ED_object.h"
00077 
00078 #include "UI_interface.h"
00079 #include "UI_resources.h"
00080 
00081 #include "armature_intern.h"
00082 
00083 /* This function is used to process the necessary updates for */
00084 void ED_armature_enter_posemode(bContext *C, Base *base)
00085 {
00086     ReportList *reports= CTX_wm_reports(C);
00087     Object *ob= base->object;
00088     
00089     if (ob->id.lib) {
00090         BKE_report(reports, RPT_WARNING, "Can't pose libdata");
00091         return;
00092     }
00093     
00094     switch (ob->type) {
00095         case OB_ARMATURE:
00096             ob->restore_mode = ob->mode;
00097             ob->mode |= OB_MODE_POSE;
00098             
00099             WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_POSE, NULL);
00100             
00101             break;
00102         default:
00103             return;
00104     }
00105     
00106     // XXX: disabled as this would otherwise cause a nasty loop...
00107     //ED_object_toggle_modes(C, ob->mode);
00108 }
00109 
00110 void ED_armature_exit_posemode(bContext *C, Base *base)
00111 {
00112     if(base) {
00113         Object *ob= base->object;
00114         
00115         ob->restore_mode = ob->mode;
00116         ob->mode &= ~OB_MODE_POSE;
00117         
00118         WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
00119     }   
00120 }
00121 
00122 /* if a selected or active bone is protected, throw error (oonly if warn==1) and return 1 */
00123 /* only_selected==1 : the active bone is allowed to be protected */
00124 #if 0 /* UNUSED 2.5 */
00125 static short pose_has_protected_selected(Object *ob, short warn)
00126 {
00127     /* check protection */
00128     if (ob->proxy) {
00129         bPoseChannel *pchan;
00130         bArmature *arm= ob->data;
00131 
00132         for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00133             if (pchan->bone && (pchan->bone->layer & arm->layer)) {
00134                 if (pchan->bone->layer & arm->layer_protected) {
00135                     if (pchan->bone->flag & BONE_SELECTED)
00136                        break;
00137                 }
00138             }
00139         }
00140         if (pchan) {
00141             if (warn) error("Cannot change Proxy protected bones");
00142             return 1;
00143         }
00144     }
00145     return 0;
00146 }
00147 #endif
00148 
00149 /* only for real IK, not for auto-IK */
00150 static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
00151 {
00152     bConstraint *con;
00153     Bone *bone;
00154     
00155     /* No need to check if constraint is active (has influence),
00156      * since all constraints with CONSTRAINT_IK_AUTO are active */
00157     for(con= pchan->constraints.first; con; con= con->next) {
00158         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
00159             bKinematicConstraint *data= con->data;
00160             if(data->rootbone == 0 || data->rootbone > level) {
00161                 if((data->flag & CONSTRAINT_IK_AUTO)==0)
00162                     return 1;
00163             }
00164         }
00165     }
00166     for(bone= pchan->bone->childbase.first; bone; bone= bone->next) {
00167         pchan= get_pose_channel(ob->pose, bone->name);
00168         if(pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
00169             return 1;
00170     }
00171     return 0;
00172 }
00173 
00174 int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
00175 {
00176     return pose_channel_in_IK_chain(ob, pchan, 0);
00177 }
00178 
00179 /* ********************************************** */
00180 /* Motion Paths */
00181 
00182 /* For the object with pose/action: update paths for those that have got them
00183  * This should selectively update paths that exist...
00184  *
00185  * To be called from various tools that do incremental updates 
00186  */
00187 void ED_pose_recalculate_paths(Scene *scene, Object *ob)
00188 {
00189     ListBase targets = {NULL, NULL};
00190     
00191     /* set flag to force recalc, then grab the relevant bones to target */
00192     ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
00193     animviz_get_object_motionpaths(ob, &targets);
00194     
00195     /* recalculate paths, then free */
00196     animviz_calc_motionpaths(scene, &targets);
00197     BLI_freelistN(&targets);
00198 }
00199 
00200 /* For the object with pose/action: create path curves for selected bones 
00201  * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
00202  */
00203 static int pose_calculate_paths_exec (bContext *C, wmOperator *op)
00204 {
00205     ScrArea *sa= CTX_wm_area(C);
00206     Scene *scene= CTX_data_scene(C);
00207     Object *ob;
00208     
00209     /* since this call may also be used from the buttons window, we need to check for where to get the object */
00210     if (sa->spacetype == SPACE_BUTS) 
00211         ob= ED_object_context(C);
00212     else
00213         ob= object_pose_armature_get(CTX_data_active_object(C));
00214         
00215     if (ELEM(NULL, ob, ob->pose))
00216         return OPERATOR_CANCELLED;
00217     
00218     /* set up path data for bones being calculated */
00219     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
00220     {
00221         /* verify makes sure that the selected bone has a bone with the appropriate settings */
00222         animviz_verify_motionpaths(op->reports, scene, ob, pchan);
00223     }
00224     CTX_DATA_END;
00225     
00226     /* calculate the bones that now have motionpaths... */
00227     // TODO: only make for the selected bones?
00228     ED_pose_recalculate_paths(scene, ob);
00229     
00230     /* notifiers for updates */
00231     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
00232     
00233     return OPERATOR_FINISHED; 
00234 }
00235 
00236 void POSE_OT_paths_calculate (wmOperatorType *ot)
00237 {
00238     /* identifiers */
00239     ot->name= "Calculate Bone Paths";
00240     ot->idname= "POSE_OT_paths_calculate";
00241     ot->description= "Calculate paths for the selected bones";
00242     
00243     /* api callbacks */
00244     ot->exec= pose_calculate_paths_exec;
00245     ot->poll= ED_operator_posemode;
00246     
00247     /* flags */
00248     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00249 }
00250 
00251 /* --------- */
00252 
00253 /* for the object with pose/action: clear path curves for selected bones only */
00254 static void ED_pose_clear_paths(Object *ob)
00255 {
00256     bPoseChannel *pchan;
00257     short skipped = 0;
00258     
00259     if ELEM(NULL, ob, ob->pose)
00260         return;
00261     
00262     /* free the motionpath blocks, but also take note of whether we skipped some... */
00263     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00264         if (pchan->mpath) {
00265             if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
00266                 animviz_free_motionpath(pchan->mpath);
00267                 pchan->mpath= NULL;
00268             }
00269             else 
00270                 skipped = 1;
00271         }
00272     }
00273     
00274     /* if we didn't skip any, we shouldn't have any paths left */
00275     if (skipped == 0)
00276         ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
00277 }
00278 
00279 /* operator callback for this */
00280 static int pose_clear_paths_exec (bContext *C, wmOperator *UNUSED(op))
00281 {
00282     ScrArea *sa= CTX_wm_area(C);
00283     Object *ob;
00284     
00285     /* since this call may also be used from the buttons window, we need to check for where to get the object */
00286     if (sa->spacetype == SPACE_BUTS) 
00287         ob= ED_object_context(C);
00288     else
00289         ob= object_pose_armature_get(CTX_data_active_object(C));
00290         
00291     /* only continue if there's an object */
00292     if ELEM(NULL, ob, ob->pose)
00293         return OPERATOR_CANCELLED;
00294     
00295     /* use the backend function for this */
00296     ED_pose_clear_paths(ob);
00297     
00298     /* notifiers for updates */
00299     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
00300     
00301     return OPERATOR_FINISHED; 
00302 }
00303 
00304 void POSE_OT_paths_clear (wmOperatorType *ot)
00305 {
00306     /* identifiers */
00307     ot->name= "Clear Bone Paths";
00308     ot->idname= "POSE_OT_paths_clear";
00309     ot->description= "Clear path caches for selected bones";
00310     
00311     /* api callbacks */
00312     ot->exec= pose_clear_paths_exec;
00313     ot->poll= ED_operator_posemode;
00314     
00315     /* flags */
00316     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00317 }
00318 
00319 /* ******************* Select Constraint Target Operator ************* */
00320 
00321 static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
00322 {
00323     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
00324     bConstraint *con;
00325     int found= 0;
00326     
00327     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00328     {
00329         if (pchan->bone->flag & BONE_SELECTED) {
00330             for (con= pchan->constraints.first; con; con= con->next) {
00331                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
00332                 ListBase targets = {NULL, NULL};
00333                 bConstraintTarget *ct;
00334                 
00335                 if (cti && cti->get_constraint_targets) {
00336                     cti->get_constraint_targets(con, &targets);
00337                     
00338                     for (ct= targets.first; ct; ct= ct->next) {
00339                         if ((ct->tar == ob) && (ct->subtarget[0])) {
00340                             bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
00341                             if((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
00342                                 pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
00343                                 found= 1;
00344                             }
00345                         }
00346                     }
00347                     
00348                     if (cti->flush_constraint_targets)
00349                         cti->flush_constraint_targets(con, &targets, 1);
00350                 }
00351             }
00352         }
00353     }
00354     CTX_DATA_END;
00355 
00356     if (!found)
00357         return OPERATOR_CANCELLED;
00358 
00359     WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
00360 
00361     return OPERATOR_FINISHED;
00362 }
00363 
00364 void POSE_OT_select_constraint_target(wmOperatorType *ot)
00365 {
00366     /* identifiers */
00367     ot->name= "Select Constraint Target";
00368     ot->idname= "POSE_OT_select_constraint_target";
00369     ot->description= "Select bones used as targets for the currently selected bones";
00370     
00371     /* api callbacks */
00372     ot->exec= pose_select_constraint_target_exec;
00373     ot->poll= ED_operator_posemode;
00374     
00375     /* flags */
00376     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00377 }
00378 
00379 /* ******************* select hierarchy operator ************* */
00380 
00381 static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
00382 {
00383     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
00384     bArmature *arm= ob->data;
00385     Bone *curbone, *pabone, *chbone;
00386     int direction = RNA_enum_get(op->ptr, "direction");
00387     int add_to_sel = RNA_boolean_get(op->ptr, "extend");
00388     int found= 0;
00389     
00390     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00391     {
00392         curbone= pchan->bone;
00393         
00394         if ((curbone->flag & BONE_UNSELECTABLE)==0) {
00395             if (curbone == arm->act_bone) {
00396                 if (direction == BONE_SELECT_PARENT) {
00397                     if (pchan->parent == NULL) continue;
00398                     else pabone= pchan->parent->bone;
00399                     
00400                     if (PBONE_VISIBLE(arm, pabone)) {
00401                         if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
00402                         pabone->flag |= BONE_SELECTED;
00403                         arm->act_bone= pabone;
00404                         
00405                         found= 1;
00406                         break;
00407                     }
00408                 } 
00409                 else { /* direction == BONE_SELECT_CHILD */
00410                     if (pchan->child == NULL) continue;
00411                     else chbone = pchan->child->bone;
00412                     
00413                     if (PBONE_VISIBLE(arm, chbone)) {
00414                         if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
00415                         chbone->flag |= BONE_SELECTED;
00416                         arm->act_bone= chbone;
00417                         
00418                         found= 1;
00419                         break;
00420                     }
00421                 }
00422             }
00423         }
00424     }
00425     CTX_DATA_END;
00426 
00427     if (found == 0)
00428         return OPERATOR_CANCELLED;
00429 
00430     WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
00431 
00432     return OPERATOR_FINISHED;
00433 }
00434 
00435 void POSE_OT_select_hierarchy(wmOperatorType *ot)
00436 {
00437     static EnumPropertyItem direction_items[]= {
00438         {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
00439         {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
00440         {0, NULL, 0, NULL, NULL}
00441     };
00442     
00443     /* identifiers */
00444     ot->name= "Select Hierarchy";
00445     ot->idname= "POSE_OT_select_hierarchy";
00446     ot->description= "Select immediate parent/children of selected bones";
00447     
00448     /* api callbacks */
00449     ot->exec= pose_select_hierarchy_exec;
00450     ot->poll= ED_operator_posemode;
00451     
00452     /* flags */
00453     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00454     
00455     /* props */
00456     ot->prop= RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
00457     RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", "");
00458     
00459 }
00460 
00461 /* ******************* select grouped operator ************* */
00462 
00463 static short pose_select_same_group (bContext *C, Object *ob, short extend)
00464 {
00465     bArmature *arm= (ob)? ob->data : NULL;
00466     bPose *pose= (ob)? ob->pose : NULL;
00467     char *group_flags;
00468     int numGroups = 0;
00469     short changed=0, tagged=0;
00470     
00471     /* sanity checks */
00472     if (ELEM3(NULL, ob, pose, arm))
00473         return 0;
00474         
00475     /* count the number of groups */
00476     numGroups= BLI_countlist(&pose->agroups);
00477     if (numGroups == 0)
00478         return 0;
00479         
00480     /* alloc a small array to keep track of the groups to use 
00481      *  - each cell stores on/off state for whether group should be used
00482      *  - size is numGroups + 1, since index=0 is used for no-group
00483      */
00484     group_flags= MEM_callocN(numGroups+1, "pose_select_same_group");
00485     
00486     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00487     {
00488         /* keep track of group as group to use later? */
00489         if (pchan->bone->flag & BONE_SELECTED) {
00490             group_flags[pchan->agrp_index] = 1;
00491             tagged= 1;
00492         }
00493         
00494         /* deselect all bones before selecting new ones? */
00495         if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0)
00496             pchan->bone->flag &= ~BONE_SELECTED;
00497     }
00498     CTX_DATA_END;
00499     
00500     /* small optimisation: only loop through bones a second time if there are any groups tagged */
00501     if (tagged) {
00502         /* only if group matches (and is not selected or current bone) */
00503         CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00504         {
00505             if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) {
00506                 /* check if the group used by this bone is counted */
00507                 if (group_flags[pchan->agrp_index]) {
00508                     pchan->bone->flag |= BONE_SELECTED;
00509                     changed= 1;
00510                 }
00511             }
00512         }
00513         CTX_DATA_END;
00514     }
00515     
00516     /* free temp info */
00517     MEM_freeN(group_flags);
00518     
00519     return changed;
00520 }
00521 
00522 static short pose_select_same_layer (bContext *C, Object *ob, short extend)
00523 {
00524     bPose *pose= (ob)? ob->pose : NULL;
00525     bArmature *arm= (ob)? ob->data : NULL;
00526     short changed= 0;
00527     int layers= 0;
00528     
00529     if (ELEM3(NULL, ob, pose, arm))
00530         return 0;
00531     
00532     /* figure out what bones are selected */
00533     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00534     {
00535         /* keep track of layers to use later? */
00536         if (pchan->bone->flag & BONE_SELECTED)
00537             layers |= pchan->bone->layer;
00538             
00539         /* deselect all bones before selecting new ones? */
00540         if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0)
00541             pchan->bone->flag &= ~BONE_SELECTED;
00542     }
00543     CTX_DATA_END;
00544     if (layers == 0) 
00545         return 0;
00546         
00547     /* select bones that are on same layers as layers flag */
00548     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00549     {
00550         /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
00551         if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) {
00552             pchan->bone->flag |= BONE_SELECTED;
00553             changed= 1;
00554         }
00555     }
00556     CTX_DATA_END;
00557     
00558     return changed;
00559 }
00560 
00561 static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
00562 {
00563     KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
00564     KS_Path *ksp;
00565     
00566     bArmature *arm = (ob)? ob->data : NULL;
00567     bPose *pose= (ob)? ob->pose : NULL;
00568     short changed= 0;
00569     
00570     /* sanity checks: validate Keying Set and object */
00571     if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
00572         return 0;
00573         
00574     if (ELEM3(NULL, ob, pose, arm))
00575         return 0;
00576         
00577     /* if not extending selection, deselect all selected first */
00578     if (extend == 0) {
00579         CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
00580         {
00581             if ((pchan->bone->flag & BONE_UNSELECTABLE)==0)
00582                 pchan->bone->flag &= ~BONE_SELECTED;
00583         }
00584         CTX_DATA_END;
00585     }
00586         
00587     /* iterate over elements in the Keying Set, setting selection depending on whether 
00588      * that bone is visible or not...
00589      */
00590     for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
00591         /* only items related to this object will be relevant */
00592         if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
00593             if (strstr(ksp->rna_path, "bones")) {
00594                 char *boneName = BLI_getQuotedStr(ksp->rna_path, "bones[");
00595                 
00596                 if (boneName) {
00597                     bPoseChannel *pchan = get_pose_channel(pose, boneName);
00598                     
00599                     if (pchan) {
00600                         /* select if bone is visible and can be affected */
00601                         if ((PBONE_VISIBLE(arm, pchan->bone)) && 
00602                             (pchan->bone->flag & BONE_UNSELECTABLE)==0)
00603                         {
00604                             pchan->bone->flag |= BONE_SELECTED;
00605                             changed = 1;
00606                         }
00607                     }
00608                     
00609                     /* free temp memory */
00610                     MEM_freeN(boneName);
00611                 }
00612             }
00613         }
00614     }
00615     
00616     return changed;
00617 }
00618 
00619 static int pose_select_grouped_exec (bContext *C, wmOperator *op)
00620 {
00621     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
00622     short extend= RNA_boolean_get(op->ptr, "extend");
00623     short changed = 0;
00624     
00625     /* sanity check */
00626     if (ELEM(NULL, ob, ob->pose))
00627         return OPERATOR_CANCELLED;
00628         
00629     /* selection types 
00630      * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
00631      */
00632     switch (RNA_enum_get(op->ptr, "type")) {
00633         case 1: /* group */
00634             changed= pose_select_same_group(C, ob, extend);
00635             break;
00636         case 2: /* Keying Set */
00637             changed= pose_select_same_keyingset(C, ob, extend);
00638             break;
00639         default: /* layer */
00640             changed= pose_select_same_layer(C, ob, extend);
00641             break;
00642     }
00643     
00644     /* notifiers for updates */
00645     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
00646     
00647     /* report done status */
00648     if (changed)
00649         return OPERATOR_FINISHED;
00650     else
00651         return OPERATOR_CANCELLED;
00652 }
00653 
00654 void POSE_OT_select_grouped (wmOperatorType *ot)
00655 {
00656     static EnumPropertyItem prop_select_grouped_types[] = {
00657         {0, "LAYER", 0, "Layer", "Shared layers"},
00658         {1, "GROUP", 0, "Group", "Shared group"},
00659         {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
00660         {0, NULL, 0, NULL, NULL}
00661     };
00662 
00663     /* identifiers */
00664     ot->name= "Select Grouped";
00665     ot->description = "Select all visible bones grouped by similar properties";
00666     ot->idname= "POSE_OT_select_grouped";
00667     
00668     /* api callbacks */
00669     ot->invoke= WM_menu_invoke;
00670     ot->exec= pose_select_grouped_exec;
00671     ot->poll= ED_operator_posemode;
00672     
00673     /* flags */
00674     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00675     
00676     /* properties */
00677     RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
00678     ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
00679 }
00680 
00681 
00682 /* ********************************************** */
00683 
00684 /* context active object, or weightpainted object with armature in posemode */
00685 static int pose_bone_flip_active_exec (bContext *C, wmOperator *UNUSED(op))
00686 {
00687     Object *ob_act= CTX_data_active_object(C);
00688     Object *ob= object_pose_armature_get(ob_act);
00689 
00690     if(ob && (ob->mode & OB_MODE_POSE)) {
00691         bArmature *arm= ob->data;
00692 
00693         if(arm->act_bone) {
00694             bPoseChannel *pchanf;
00695             char name[MAXBONENAME];
00696             flip_side_name(name, arm->act_bone->name, TRUE);
00697 
00698             pchanf= get_pose_channel(ob->pose, name);
00699             if(pchanf && pchanf->bone != arm->act_bone) {
00700                 arm->act_bone->flag &= ~BONE_SELECTED;
00701                 pchanf->bone->flag |= BONE_SELECTED;
00702 
00703                 arm->act_bone= pchanf->bone;
00704 
00705                 /* in weightpaint we select the associated vertex group too */
00706                 if(ob_act->mode & OB_MODE_WEIGHT_PAINT) {
00707                     ED_vgroup_select_by_name(ob_act, name);
00708                     DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
00709                 }
00710 
00711                 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
00712 
00713                 return OPERATOR_FINISHED;
00714             }
00715         }
00716     }
00717 
00718     return OPERATOR_CANCELLED;
00719 }
00720 
00721 void POSE_OT_select_flip_active(wmOperatorType *ot)
00722 {
00723     /* identifiers */
00724     ot->name= "Flip Selected Active Bone";
00725     ot->idname= "POSE_OT_select_flip_active";
00726     ot->description= "Activate the bone with a flipped name";
00727     
00728     /* api callbacks */
00729     ot->exec= pose_bone_flip_active_exec;
00730     ot->poll= ED_operator_posemode;
00731     
00732     /* flags */
00733     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00734 }
00735 
00736 
00737 /* ********************************************** */
00738 #if 0 /* UNUSED 2.5 */
00739 static void pose_copy_menu(Scene *scene)
00740 {
00741     Object *obedit= scene->obedit; // XXX context
00742     Object *ob= OBACT;
00743     bArmature *arm;
00744     bPoseChannel *pchan, *pchanact;
00745     short nr=0;
00746     int i=0;
00747     
00748     /* paranoia checks */
00749     if (ELEM(NULL, ob, ob->pose)) return;
00750     if ((ob==obedit) || (ob->mode & OB_MODE_POSE)==0) return;
00751     
00752     pchan= get_active_posechannel(ob);
00753     
00754     if (pchan==NULL) return;
00755     pchanact= pchan;
00756     arm= ob->data;
00757 
00758     /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changable, 
00759      * but for constraints (just add local constraints)
00760      */
00761     if (pose_has_protected_selected(ob, 0)) {
00762         i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
00763         if (i < 25)
00764             nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5");
00765         else
00766             nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4");
00767     }
00768     else {
00769         i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
00770         if (i < 25)
00771             nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
00772         else
00773             nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
00774     }
00775     
00776     if (nr <= 0) 
00777         return;
00778     
00779     if (nr != 5)  {
00780         for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00781             if ( (arm->layer & pchan->bone->layer) &&
00782                  (pchan->bone->flag & BONE_SELECTED) &&
00783                  (pchan != pchanact) ) 
00784             {
00785                 switch (nr) {
00786                     case 1: /* Local Location */
00787                         copy_v3_v3(pchan->loc, pchanact->loc);
00788                         break;
00789                     case 2: /* Local Rotation */
00790                         copy_qt_qt(pchan->quat, pchanact->quat);
00791                         copy_v3_v3(pchan->eul, pchanact->eul);
00792                         break;
00793                     case 3: /* Local Size */
00794                         copy_v3_v3(pchan->size, pchanact->size);
00795                         break;
00796                     case 4: /* All Constraints */
00797                     {
00798                         ListBase tmp_constraints = {NULL, NULL};
00799                         
00800                         /* copy constraints to tmpbase and apply 'local' tags before 
00801                          * appending to list of constraints for this channel
00802                          */
00803                         copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
00804                         if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
00805                             bConstraint *con;
00806                             
00807                             /* add proxy-local tags */
00808                             for (con= tmp_constraints.first; con; con= con->next)
00809                                 con->flag |= CONSTRAINT_PROXY_LOCAL;
00810                         }
00811                         BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
00812                         
00813                         /* update flags (need to add here, not just copy) */
00814                         pchan->constflag |= pchanact->constflag;
00815                         
00816                         if (ob->pose)
00817                             ob->pose->flag |= POSE_RECALC;
00818                     }
00819                         break;
00820                     case 6: /* Transform Locks */
00821                         pchan->protectflag = pchanact->protectflag;
00822                         break;
00823                     case 7: /* IK (DOF) settings */
00824                     {
00825                         pchan->ikflag = pchanact->ikflag;
00826                         copy_v3_v3(pchan->limitmin, pchanact->limitmin);
00827                         copy_v3_v3(pchan->limitmax, pchanact->limitmax);
00828                         copy_v3_v3(pchan->stiffness, pchanact->stiffness);
00829                         pchan->ikstretch= pchanact->ikstretch;
00830                         pchan->ikrotweight= pchanact->ikrotweight;
00831                         pchan->iklinweight= pchanact->iklinweight;
00832                     }
00833                         break;
00834                     case 8: /* Custom Bone Shape */
00835                         pchan->custom = pchanact->custom;
00836                         break;
00837                     case 9: /* Visual Location */
00838                         armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
00839                         break;
00840                     case 10: /* Visual Rotation */
00841                     {
00842                         float delta_mat[4][4];
00843                         
00844                         armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
00845                         
00846                         if (pchan->rotmode == ROT_MODE_AXISANGLE) {
00847                             float tmp_quat[4];
00848                             
00849                             /* need to convert to quat first (in temp var)... */
00850                             mat4_to_quat( tmp_quat,delta_mat);
00851                             quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,tmp_quat);
00852                         }
00853                         else if (pchan->rotmode == ROT_MODE_QUAT)
00854                             mat4_to_quat( pchan->quat,delta_mat);
00855                         else
00856                             mat4_to_eulO( pchan->eul, pchan->rotmode,delta_mat);
00857                     }
00858                         break;
00859                     case 11: /* Visual Size */
00860                     {
00861                         float delta_mat[4][4], size[4];
00862                         
00863                         armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
00864                         mat4_to_size( size,delta_mat);
00865                         copy_v3_v3(pchan->size, size);
00866                     }
00867                 }
00868             }
00869         }
00870     } 
00871     else { /* constraints, optional (note: max we can have is 24 constraints) */
00872         bConstraint *con, *con_back;
00873         int const_toggle[24]= {0}; /* XXX, initialize as 0 to quiet errors */
00874         ListBase const_copy = {NULL, NULL};
00875         
00876         BLI_duplicatelist(&const_copy, &(pchanact->constraints));
00877         
00878         /* build the puplist of constraints */
00879         for (con = pchanact->constraints.first, i=0; con; con=con->next, i++){
00880             const_toggle[i]= 1;
00881 //          add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
00882         }
00883         
00884 //      if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
00885 //          BLI_freelistN(&const_copy);
00886 //          return;
00887 //      }
00888         
00889         /* now build a new listbase from the options selected */
00890         for (i=0, con=const_copy.first; con; i++) {
00891             /* if not selected, free/remove it from the list */
00892             if (!const_toggle[i]) {
00893                 con_back= con->next;
00894                 BLI_freelinkN(&const_copy, con);
00895                 con= con_back;
00896             } 
00897             else
00898                 con= con->next;
00899         }
00900         
00901         /* Copy the temo listbase to the selected posebones */
00902         for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00903             if ( (arm->layer & pchan->bone->layer) &&
00904                  (pchan->bone->flag & BONE_SELECTED) &&
00905                  (pchan!=pchanact) ) 
00906             {
00907                 ListBase tmp_constraints = {NULL, NULL};
00908                 
00909                 /* copy constraints to tmpbase and apply 'local' tags before 
00910                  * appending to list of constraints for this channel
00911                  */
00912                 copy_constraints(&tmp_constraints, &const_copy, TRUE);
00913                 if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {                   
00914                     /* add proxy-local tags */
00915                     for (con= tmp_constraints.first; con; con= con->next)
00916                         con->flag |= CONSTRAINT_PROXY_LOCAL;
00917                 }
00918                 BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
00919                 
00920                 /* update flags (need to add here, not just copy) */
00921                 pchan->constflag |= pchanact->constflag;
00922             }
00923         }
00924         BLI_freelistN(&const_copy);
00925         update_pose_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
00926         
00927         if (ob->pose)
00928             ob->pose->flag |= POSE_RECALC;
00929     }
00930     
00931     DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
00932     
00933     BIF_undo_push("Copy Pose Attributes");
00934     
00935 }
00936 #endif
00937 
00938 /* ******************** copy/paste pose ********************** */
00939 
00940 /* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
00941 static bPose *g_posebuf = NULL;
00942 
00943 void free_posebuf(void) 
00944 {
00945     if (g_posebuf) {
00946         bPoseChannel *pchan;
00947         
00948         for (pchan= g_posebuf->chanbase.first; pchan; pchan= pchan->next) {
00949             if(pchan->prop) {
00950                 IDP_FreeProperty(pchan->prop);
00951                 MEM_freeN(pchan->prop);
00952             }
00953         }
00954         
00955         /* was copied without constraints */
00956         BLI_freelistN(&g_posebuf->chanbase);
00957         MEM_freeN(g_posebuf);
00958     }
00959     
00960     g_posebuf=NULL;
00961 }
00962 
00963 /* This function is used to indicate that a bone is selected 
00964  * and needs to be included in copy buffer (used to be for inserting keys)
00965  */
00966 static void set_pose_keys (Object *ob)
00967 {
00968     bArmature *arm= ob->data;
00969     bPoseChannel *chan;
00970 
00971     if (ob->pose){
00972         for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
00973             Bone *bone= chan->bone;
00974             if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
00975                 chan->flag |= POSE_KEY; 
00976             else
00977                 chan->flag &= ~POSE_KEY;
00978         }
00979     }
00980 }
00981 
00982 /* perform paste pose, for a single bone 
00983  * < ob: object where bone to paste to lives
00984  * < chan: bone that pose to paste comes from
00985  * < selOnly: only paste on selected bones
00986  * < flip: flip on x-axis
00987  *
00988  * > returns: whether the bone that we pasted to if we succeeded
00989  */
00990 static bPoseChannel *pose_bone_do_paste (Object *ob, bPoseChannel *chan, short selOnly, short flip)
00991 {
00992     bPoseChannel *pchan;
00993     char name[MAXBONENAME];
00994     short paste_ok;
00995     
00996     /* get the name - if flipping, we must flip this first */
00997     if (flip)
00998         flip_side_name(name, chan->name, 0);        /* 0 = don't strip off number extensions */
00999     else
01000         BLI_strncpy(name, chan->name, sizeof(name));
01001     
01002     /* only copy when:
01003      *  1) channel exists - poses are not meant to add random channels to anymore
01004      *  2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
01005      */
01006     pchan= get_pose_channel(ob->pose, name);
01007     
01008     if (selOnly)
01009         paste_ok= ((pchan) && (pchan->bone->flag & BONE_SELECTED));
01010     else
01011         paste_ok= ((pchan != NULL));
01012     
01013     /* continue? */
01014     if (paste_ok) {
01015         /* only loc rot size 
01016          *  - only copies transform info for the pose 
01017          */
01018         copy_v3_v3(pchan->loc, chan->loc);
01019         copy_v3_v3(pchan->size, chan->size);
01020         pchan->flag= chan->flag;
01021         
01022         /* check if rotation modes are compatible (i.e. do they need any conversions) */
01023         if (pchan->rotmode == chan->rotmode) {
01024             /* copy the type of rotation in use */
01025             if (pchan->rotmode > 0) {
01026                 copy_v3_v3(pchan->eul, chan->eul);
01027             }
01028             else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
01029                 copy_v3_v3(pchan->rotAxis, chan->rotAxis);
01030                 pchan->rotAngle = chan->rotAngle;
01031             }
01032             else {
01033                 copy_qt_qt(pchan->quat, chan->quat);
01034             }
01035         }
01036         else if (pchan->rotmode > 0) {
01037             /* quat/axis-angle to euler */
01038             if (chan->rotmode == ROT_MODE_AXISANGLE)
01039                 axis_angle_to_eulO( pchan->eul, pchan->rotmode,chan->rotAxis, chan->rotAngle);
01040             else
01041                 quat_to_eulO( pchan->eul, pchan->rotmode,chan->quat);
01042         }
01043         else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
01044             /* quat/euler to axis angle */
01045             if (chan->rotmode > 0)
01046                 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
01047             else    
01048                 quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
01049         }
01050         else {
01051             /* euler/axis-angle to quat */
01052             if (chan->rotmode > 0)
01053                 eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
01054             else
01055                 axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
01056         }
01057         
01058         /* paste flipped pose? */
01059         if (flip) {
01060             pchan->loc[0]*= -1;
01061             
01062             /* has to be done as eulers... */
01063             if (pchan->rotmode > 0) {
01064                 pchan->eul[1] *= -1;
01065                 pchan->eul[2] *= -1;
01066             }
01067             else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
01068                 float eul[3];
01069                 
01070                 axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
01071                 eul[1]*= -1;
01072                 eul[2]*= -1;
01073                 eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
01074             }
01075             else {
01076                 float eul[3];
01077                 
01078                 normalize_qt(pchan->quat);
01079                 quat_to_eul(eul, pchan->quat);
01080                 eul[1]*= -1;
01081                 eul[2]*= -1;
01082                 eul_to_quat(pchan->quat, eul);
01083             }
01084         }
01085         
01086         /* ID properties */
01087         if (chan->prop) {
01088             if (pchan->prop) {
01089                 /* if we have existing properties on a bone, just copy over the values of 
01090                  * matching properties (i.e. ones which will have some impact) on to the 
01091                  * target instead of just blinding replacing all [
01092                  */
01093                 IDP_SyncGroupValues(pchan->prop, chan->prop);
01094             }
01095             else {
01096                 /* no existing properties, so assume that we want copies too? */
01097                 pchan->prop= IDP_CopyProperty(chan->prop);  
01098             }
01099         }
01100     }
01101     
01102     /* return whether paste went ahead */
01103     return pchan;
01104 }
01105 
01106 /* ---- */
01107 
01108 static int pose_copy_exec (bContext *C, wmOperator *op)
01109 {
01110     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01111     
01112     /* sanity checking */
01113     if ELEM(NULL, ob, ob->pose) {
01114         BKE_report(op->reports, RPT_ERROR, "No Pose to Copy");
01115         return OPERATOR_CANCELLED;
01116     }
01117 
01118     /* free existing pose buffer */
01119     free_posebuf();
01120     
01121     /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
01122     set_pose_keys(ob);  
01123     copy_pose(&g_posebuf, ob->pose, 0);
01124     
01125     
01126     return OPERATOR_FINISHED;
01127 }
01128 
01129 void POSE_OT_copy (wmOperatorType *ot) 
01130 {
01131     /* identifiers */
01132     ot->name= "Copy Pose";
01133     ot->idname= "POSE_OT_copy";
01134     ot->description= "Copies the current pose of the selected bones to copy/paste buffer";
01135     
01136     /* api callbacks */
01137     ot->exec= pose_copy_exec;
01138     ot->poll= ED_operator_posemode;
01139     
01140     /* flag */
01141     ot->flag= OPTYPE_REGISTER;
01142 }
01143 
01144 /* ---- */
01145 
01146 static int pose_paste_exec (bContext *C, wmOperator *op)
01147 {
01148     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01149     Scene *scene= CTX_data_scene(C);
01150     bPoseChannel *chan;
01151     int flip= RNA_boolean_get(op->ptr, "flipped");
01152     int selOnly= RNA_boolean_get(op->ptr, "selected_mask");
01153 
01154     /* get KeyingSet to use */
01155     KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID);
01156 
01157     /* sanity checks */
01158     if ELEM(NULL, ob, ob->pose)
01159         return OPERATOR_CANCELLED;
01160 
01161     if (g_posebuf == NULL) {
01162         BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
01163         return OPERATOR_CANCELLED;
01164     }
01165     
01166     /* if selOnly option is enabled, if user hasn't selected any bones, 
01167      * just go back to default behaviour to be more in line with other pose tools
01168      */
01169     if (selOnly) {
01170         if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
01171             selOnly = 0;
01172     }
01173 
01174     /* Safely merge all of the channels in the buffer pose into any existing pose */
01175     for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) {
01176         if (chan->flag & POSE_KEY) {
01177             /* try to perform paste on this bone */
01178             bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
01179             
01180             if (pchan) {
01181                 /* keyframing tagging for successful paste */
01182                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
01183             }
01184         }
01185     }
01186     
01187     /* Update event for pose and deformation children */
01188     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
01189         
01190     /* notifiers for updates */
01191     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01192 
01193     return OPERATOR_FINISHED;
01194 }
01195 
01196 void POSE_OT_paste (wmOperatorType *ot)
01197 {
01198     /* identifiers */
01199     ot->name= "Paste Pose";
01200     ot->idname= "POSE_OT_paste";
01201     ot->description= "Paste the stored pose on to the current pose";
01202     
01203     /* api callbacks */
01204     ot->exec= pose_paste_exec;
01205     ot->poll= ED_operator_posemode;
01206     
01207     /* flag */
01208     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01209     
01210     /* properties */
01211     RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
01212     RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
01213 }
01214 
01215 /* ********************************************** */
01216 /* Bone Groups */
01217 
01218 static int pose_group_add_exec (bContext *C, wmOperator *UNUSED(op))
01219 {
01220     ScrArea *sa= CTX_wm_area(C);
01221     Object *ob;
01222     
01223     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01224     if (sa->spacetype == SPACE_BUTS) 
01225         ob= ED_object_context(C);
01226     else
01227         ob= object_pose_armature_get(CTX_data_active_object(C));
01228         
01229     /* only continue if there's an object */
01230     if (ob == NULL)
01231         return OPERATOR_CANCELLED;
01232     
01233     /* for now, just call the API function for this */
01234     pose_add_group(ob);
01235     
01236     /* notifiers for updates */
01237     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01238     
01239     return OPERATOR_FINISHED;
01240 }
01241 
01242 void POSE_OT_group_add (wmOperatorType *ot)
01243 {
01244     /* identifiers */
01245     ot->name= "Add Bone Group";
01246     ot->idname= "POSE_OT_group_add";
01247     ot->description= "Add a new bone group";
01248     
01249     /* api callbacks */
01250     ot->exec= pose_group_add_exec;
01251     ot->poll= ED_operator_posemode;
01252     
01253     /* flags */
01254     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01255 }
01256 
01257 
01258 static int pose_group_remove_exec (bContext *C, wmOperator *UNUSED(op))
01259 {
01260     ScrArea *sa= CTX_wm_area(C);
01261     Object *ob;
01262     
01263     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01264     if (sa->spacetype == SPACE_BUTS) 
01265         ob= ED_object_context(C);
01266     else
01267         ob= object_pose_armature_get(CTX_data_active_object(C));
01268     
01269     /* only continue if there's an object */
01270     if (ob == NULL)
01271         return OPERATOR_CANCELLED;
01272     
01273     /* for now, just call the API function for this */
01274     pose_remove_group(ob);
01275     
01276     /* notifiers for updates */
01277     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01278     
01279     return OPERATOR_FINISHED;
01280 }
01281 
01282 void POSE_OT_group_remove (wmOperatorType *ot)
01283 {
01284     /* identifiers */
01285     ot->name= "Remove Bone Group";
01286     ot->idname= "POSE_OT_group_remove";
01287     ot->description= "Removes the active bone group";
01288     
01289     /* api callbacks */
01290     ot->exec= pose_group_remove_exec;
01291     ot->poll= ED_operator_posemode;
01292     
01293     /* flags */
01294     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01295 }
01296 
01297 /* ------------ */
01298 
01299 /* invoke callback which presents a list of bone-groups for the user to choose from */
01300 static int pose_groups_menu_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
01301 {
01302     ScrArea *sa= CTX_wm_area(C);
01303     Object *ob;
01304     bPose *pose;
01305     
01306     uiPopupMenu *pup;
01307     uiLayout *layout;
01308     bActionGroup *grp;
01309     int i;
01310     
01311     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01312     if (sa->spacetype == SPACE_BUTS) 
01313         ob= ED_object_context(C);
01314     else
01315         ob= object_pose_armature_get(CTX_data_active_object(C));
01316     
01317     /* only continue if there's an object, and a pose there too */
01318     if (ELEM(NULL, ob, ob->pose)) 
01319         return OPERATOR_CANCELLED;
01320     pose= ob->pose;
01321     
01322     /* if there's no active group (or active is invalid), create a new menu to find it */
01323     if (pose->active_group <= 0) {
01324         /* create a new menu, and start populating it with group names */
01325         pup= uiPupMenuBegin(C, op->type->name, ICON_NONE);
01326         layout= uiPupMenuLayout(pup);
01327         
01328         /* special entry - allow to create new group, then use that 
01329          *  (not to be used for removing though)
01330          */
01331         if (strstr(op->idname, "assign")) {
01332             uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
01333             uiItemS(layout);
01334         }
01335         
01336         /* add entries for each group */
01337         for (grp= pose->agroups.first, i=1; grp; grp=grp->next, i++)
01338             uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
01339             
01340         /* finish building the menu, and process it (should result in calling self again) */
01341         uiPupMenuEnd(C, pup);
01342         
01343         return OPERATOR_CANCELLED;
01344     }
01345     else {
01346         /* just use the active group index, and call the exec callback for the calling operator */
01347         RNA_int_set(op->ptr, "type", pose->active_group);
01348         return op->type->exec(C, op);
01349     }
01350 }
01351 
01352 /* Assign selected pchans to the bone group that the user selects */
01353 static int pose_group_assign_exec (bContext *C, wmOperator *op)
01354 {
01355     ScrArea *sa= CTX_wm_area(C);
01356     Object *ob;
01357     bPose *pose;
01358     short done= 0;
01359     
01360     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01361     if (sa->spacetype == SPACE_BUTS) 
01362         ob= ED_object_context(C);
01363     else
01364         ob= object_pose_armature_get(CTX_data_active_object(C));
01365     
01366     /* only continue if there's an object, and a pose there too */
01367     if (ELEM(NULL, ob, ob->pose))
01368         return OPERATOR_CANCELLED;
01369 
01370     pose= ob->pose;
01371     
01372     /* set the active group number to the one from operator props 
01373      *  - if 0 after this, make a new group...
01374      */
01375     pose->active_group= RNA_int_get(op->ptr, "type");
01376     if (pose->active_group == 0)
01377         pose_add_group(ob);
01378     
01379     /* add selected bones to group then */
01380     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
01381     {
01382         pchan->agrp_index= pose->active_group;
01383         done= 1;
01384     }
01385     CTX_DATA_END;
01386 
01387     /* notifiers for updates */
01388     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01389     
01390     /* report done status */
01391     if (done)
01392         return OPERATOR_FINISHED;
01393     else
01394         return OPERATOR_CANCELLED;
01395 }
01396 
01397 void POSE_OT_group_assign (wmOperatorType *ot)
01398 {
01399     /* identifiers */
01400     ot->name= "Add Selected to Bone Group";
01401     ot->idname= "POSE_OT_group_assign";
01402     ot->description= "Add selected bones to the chosen bone group";
01403     
01404     /* api callbacks */
01405     ot->invoke= pose_groups_menu_invoke;
01406     ot->exec= pose_group_assign_exec;
01407     ot->poll= ED_operator_posemode;
01408     
01409     /* flags */
01410     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01411     
01412     /* properties */
01413     RNA_def_int(ot->srna, "type", 0, 0, 10, "Bone Group Index", "", 0, INT_MAX);
01414 }
01415 
01416 
01417 static int pose_group_unassign_exec (bContext *C, wmOperator *UNUSED(op))
01418 {
01419     ScrArea *sa= CTX_wm_area(C);
01420     Object *ob;
01421     short done= 0;
01422     
01423     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01424     if (sa->spacetype == SPACE_BUTS) 
01425         ob= ED_object_context(C);
01426     else
01427         ob= object_pose_armature_get(CTX_data_active_object(C));
01428     
01429     /* only continue if there's an object, and a pose there too */
01430     if (ELEM(NULL, ob, ob->pose))
01431         return OPERATOR_CANCELLED;
01432     
01433     /* find selected bones to remove from all bone groups */
01434     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
01435     {
01436         if (pchan->agrp_index) {
01437             pchan->agrp_index= 0;
01438             done= 1;
01439         }
01440     }
01441     CTX_DATA_END;
01442     
01443     /* notifiers for updates */
01444     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01445     
01446     /* report done status */
01447     if (done)
01448         return OPERATOR_FINISHED;
01449     else
01450         return OPERATOR_CANCELLED;
01451 }
01452 
01453 void POSE_OT_group_unassign (wmOperatorType *ot)
01454 {
01455     /* identifiers */
01456     ot->name= "Remove Selected from Bone Groups";
01457     ot->idname= "POSE_OT_group_unassign";
01458     ot->description= "Remove selected bones from all bone groups";
01459     
01460     /* api callbacks */
01461     ot->exec= pose_group_unassign_exec;
01462     ot->poll= ED_operator_posemode;
01463     
01464     /* flags */
01465     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01466 }
01467 
01468 static int group_move_exec(bContext *C, wmOperator *op)
01469 {
01470     Object *ob = ED_object_context(C);
01471     bPose *pose= (ob) ? ob->pose : NULL;
01472     bPoseChannel *pchan;
01473     bActionGroup *grp;
01474     int dir= RNA_enum_get(op->ptr, "direction");
01475     int grpIndexA, grpIndexB;
01476 
01477     if (ELEM(NULL, ob, pose))
01478         return OPERATOR_CANCELLED;
01479     if (pose->active_group <= 0)
01480         return OPERATOR_CANCELLED;
01481 
01482     /* get group to move */
01483     grp= BLI_findlink(&pose->agroups, pose->active_group-1);
01484     if (grp == NULL)
01485         return OPERATOR_CANCELLED;
01486 
01487     /* move bone group */
01488     grpIndexA = pose->active_group;
01489     if (dir == 1) { /* up */
01490         void *prev = grp->prev;
01491         
01492         if (prev == NULL)
01493             return OPERATOR_FINISHED;
01494             
01495         BLI_remlink(&pose->agroups, grp);
01496         BLI_insertlinkbefore(&pose->agroups, prev, grp);
01497         
01498         grpIndexB = grpIndexA - 1;
01499         pose->active_group--;
01500     }
01501     else { /* down */
01502         void *next = grp->next;
01503         
01504         if (next == NULL)
01505             return OPERATOR_FINISHED;
01506             
01507         BLI_remlink(&pose->agroups, grp);
01508         BLI_insertlinkafter(&pose->agroups, next, grp);
01509         
01510         grpIndexB = grpIndexA + 1;
01511         pose->active_group++;
01512     }
01513 
01514     /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
01515     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
01516         if (pchan->agrp_index == grpIndexB)
01517             pchan->agrp_index= grpIndexA;
01518         else if (pchan->agrp_index == grpIndexA)
01519             pchan->agrp_index= grpIndexB;
01520     }
01521 
01522     /* notifiers for updates */
01523     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01524 
01525     return OPERATOR_FINISHED;
01526 }
01527 
01528 void POSE_OT_group_move(wmOperatorType *ot)
01529 {
01530     static EnumPropertyItem group_slot_move[] = {
01531         {1, "UP", 0, "Up", ""},
01532         {-1, "DOWN", 0, "Down", ""},
01533         {0, NULL, 0, NULL, NULL}
01534     };
01535 
01536     /* identifiers */
01537     ot->name= "Move Bone Group";
01538     ot->idname= "POSE_OT_group_move";
01539     ot->description= "Change position of active Bone Group in list of Bone Groups";
01540 
01541     /* api callbacks */
01542     ot->exec= group_move_exec;
01543     ot->poll= ED_operator_posemode;
01544 
01545     /* flags */
01546     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01547 
01548     RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
01549 }
01550 
01551 /* bone group sort element */
01552 typedef struct tSortActionGroup {
01553     bActionGroup *agrp;
01554     int          index;
01555 } tSortActionGroup;
01556 
01557 /* compare bone groups by name */
01558 static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
01559 {
01560     tSortActionGroup *sgrp_a= (tSortActionGroup *)sgrp_a_ptr;
01561     tSortActionGroup *sgrp_b= (tSortActionGroup *)sgrp_b_ptr;
01562 
01563     return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
01564 }
01565 
01566 static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
01567 {
01568     Object *ob = ED_object_context(C);
01569     bPose *pose= (ob) ? ob->pose : NULL;
01570     bPoseChannel *pchan;
01571     tSortActionGroup *agrp_array;
01572     bActionGroup *agrp;
01573     int agrp_count;
01574     int i;
01575 
01576     if (ELEM(NULL, ob, pose))
01577         return OPERATOR_CANCELLED;
01578     if (pose->active_group <= 0)
01579         return OPERATOR_CANCELLED;
01580 
01581     /* create temporary array with bone groups and indices */
01582     agrp_count = BLI_countlist(&pose->agroups);
01583     agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
01584     for (agrp= pose->agroups.first, i= 0; agrp; agrp= agrp->next, i++) {
01585         BLI_assert(i < agrp_count);
01586         agrp_array[i].agrp = agrp;
01587         agrp_array[i].index = i+1;
01588     }
01589 
01590     /* sort bone groups by name */
01591     qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
01592 
01593     /* create sorted bone group list from sorted array */
01594     pose->agroups.first= pose->agroups.last= NULL;
01595     for (i= 0; i < agrp_count; i++) {
01596         BLI_addtail(&pose->agroups, agrp_array[i].agrp);
01597     }
01598 
01599     /* fix changed bone group indizes in bones */
01600     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
01601         for (i= 0; i < agrp_count; i++) {
01602             if (pchan->agrp_index == agrp_array[i].index) {
01603                 pchan->agrp_index= i+1;
01604                 break;
01605             }
01606         }
01607     }
01608 
01609     /* free temp resources */
01610     MEM_freeN(agrp_array);
01611 
01612     /* notifiers for updates */
01613     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01614 
01615     return OPERATOR_FINISHED;
01616 }
01617 
01618 void POSE_OT_group_sort(wmOperatorType *ot)
01619 {
01620     /* identifiers */
01621     ot->name= "Sort Bone Groups";
01622     ot->idname= "POSE_OT_group_sort";
01623     ot->description= "Sort Bone Groups by their names in ascending order";
01624 
01625     /* api callbacks */
01626     ot->exec= group_sort_exec;
01627     ot->poll= ED_operator_posemode;
01628 
01629     /* flags */
01630     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01631 }
01632 
01633 static void pose_group_select(bContext *C, Object *ob, int select)
01634 {
01635     bPose *pose= ob->pose;
01636     
01637     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, visible_pose_bones)
01638     {
01639         if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) {
01640             if (select) {
01641                 if (pchan->agrp_index == pose->active_group) 
01642                     pchan->bone->flag |= BONE_SELECTED;
01643             }
01644             else {
01645                 if (pchan->agrp_index == pose->active_group) 
01646                     pchan->bone->flag &= ~BONE_SELECTED;
01647             }
01648         }
01649     }
01650     CTX_DATA_END;
01651 }
01652 
01653 static int pose_group_select_exec (bContext *C, wmOperator *UNUSED(op))
01654 {
01655     ScrArea *sa= CTX_wm_area(C);
01656     Object *ob;
01657     
01658     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01659     if (sa->spacetype == SPACE_BUTS) 
01660         ob= ED_object_context(C);
01661     else
01662         ob= object_pose_armature_get(CTX_data_active_object(C));
01663     
01664     /* only continue if there's an object, and a pose there too */
01665     if (ELEM(NULL, ob, ob->pose))
01666         return OPERATOR_CANCELLED;
01667     
01668     pose_group_select(C, ob, 1);
01669     
01670     /* notifiers for updates */
01671     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01672     
01673     return OPERATOR_FINISHED;
01674 }
01675 
01676 void POSE_OT_group_select (wmOperatorType *ot)
01677 {
01678     /* identifiers */
01679     ot->name= "Select Bones of Bone Group";
01680     ot->idname= "POSE_OT_group_select";
01681     ot->description= "Select bones in active Bone Group";
01682     
01683     /* api callbacks */
01684     ot->exec= pose_group_select_exec;
01685     ot->poll= ED_operator_posemode;
01686     
01687     /* flags */
01688     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01689 }
01690 
01691 static int pose_group_deselect_exec (bContext *C, wmOperator *UNUSED(op))
01692 {
01693     ScrArea *sa= CTX_wm_area(C);
01694     Object *ob;
01695     
01696     /* since this call may also be used from the buttons window, we need to check for where to get the object */
01697     if (sa->spacetype == SPACE_BUTS) 
01698         ob= ED_object_context(C);
01699     else
01700         ob= object_pose_armature_get(CTX_data_active_object(C));
01701     
01702     /* only continue if there's an object, and a pose there too */
01703     if (ELEM(NULL, ob, ob->pose))
01704         return OPERATOR_CANCELLED;
01705     
01706     pose_group_select(C, ob, 0);
01707     
01708     /* notifiers for updates */
01709     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01710     
01711     return OPERATOR_FINISHED;
01712 }
01713 
01714 void POSE_OT_group_deselect (wmOperatorType *ot)
01715 {
01716     /* identifiers */
01717     ot->name= "Deselect Bone Group";
01718     ot->idname= "POSE_OT_group_deselect";
01719     ot->description= "Deselect bones of active Bone Group";
01720     
01721     /* api callbacks */
01722     ot->exec= pose_group_deselect_exec;
01723     ot->poll= ED_operator_posemode;
01724     
01725     /* flags */
01726     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01727 }
01728 
01729 /* ********************************************** */
01730 
01731 static int pose_flip_names_exec (bContext *C, wmOperator *UNUSED(op))
01732 {
01733     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01734     bArmature *arm;
01735     
01736     /* paranoia checks */
01737     if (ELEM(NULL, ob, ob->pose)) 
01738         return OPERATOR_CANCELLED;
01739     arm= ob->data;
01740     
01741     /* loop through selected bones, auto-naming them */
01742     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
01743     {
01744         char newname[MAXBONENAME];
01745         flip_side_name(newname, pchan->name, TRUE);
01746         ED_armature_bone_rename(arm, pchan->name, newname);
01747     }
01748     CTX_DATA_END;
01749     
01750     /* since we renamed stuff... */
01751     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
01752 
01753     /* note, notifier might evolve */
01754     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01755     
01756     return OPERATOR_FINISHED;
01757 }
01758 
01759 void POSE_OT_flip_names (wmOperatorType *ot)
01760 {
01761     /* identifiers */
01762     ot->name= "Flip Names";
01763     ot->idname= "POSE_OT_flip_names";
01764     ot->description= "Flips (and corrects) the axis suffixes of the the names of selected bones";
01765     
01766     /* api callbacks */
01767     ot->exec= pose_flip_names_exec;
01768     ot->poll= ED_operator_posemode;
01769     
01770     /* flags */
01771     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01772 }
01773 
01774 /* ------------------ */
01775 
01776 static int pose_autoside_names_exec (bContext *C, wmOperator *op)
01777 {
01778     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01779     bArmature *arm;
01780     char newname[MAXBONENAME];
01781     short axis= RNA_enum_get(op->ptr, "axis");
01782     
01783     /* paranoia checks */
01784     if (ELEM(NULL, ob, ob->pose)) 
01785         return OPERATOR_CANCELLED;
01786     arm= ob->data;
01787     
01788     /* loop through selected bones, auto-naming them */
01789     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
01790     {
01791         BLI_strncpy(newname, pchan->name, sizeof(newname));
01792         if(bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
01793             ED_armature_bone_rename(arm, pchan->name, newname);
01794     }
01795     CTX_DATA_END;
01796     
01797     /* since we renamed stuff... */
01798     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
01799 
01800     /* note, notifier might evolve */
01801     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01802     
01803     return OPERATOR_FINISHED;
01804 }
01805 
01806 void POSE_OT_autoside_names (wmOperatorType *ot)
01807 {
01808     static EnumPropertyItem axis_items[]= {
01809         {0, "XAXIS", 0, "X-Axis", "Left/Right"},
01810         {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
01811         {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
01812         {0, NULL, 0, NULL, NULL}};
01813     
01814     /* identifiers */
01815     ot->name= "AutoName by Axis";
01816     ot->idname= "POSE_OT_autoside_names";
01817     ot->description= "Automatically renames the selected bones according to which side of the target axis they fall on";
01818     
01819     /* api callbacks */
01820     ot->invoke= WM_menu_invoke;
01821     ot->exec= pose_autoside_names_exec;
01822     ot->poll= ED_operator_posemode;
01823     
01824     /* flags */
01825     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01826     
01827     /* settings */
01828     ot->prop= RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
01829 }
01830 
01831 /* ********************************************** */
01832 
01833 static int pose_bone_rotmode_exec (bContext *C, wmOperator *op)
01834 {
01835     Object *ob = CTX_data_active_object(C);
01836     int mode = RNA_enum_get(op->ptr, "type");
01837     
01838     /* set rotation mode of selected bones  */  
01839     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 
01840     {
01841         pchan->rotmode = mode;
01842     }
01843     CTX_DATA_END;
01844     
01845     /* notifiers and updates */
01846     DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
01847     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
01848     
01849     return OPERATOR_FINISHED;
01850 }
01851 
01852 void POSE_OT_rotation_mode_set (wmOperatorType *ot)
01853 {
01854     /* identifiers */
01855     ot->name= "Set Rotation Mode";
01856     ot->idname= "POSE_OT_rotation_mode_set";
01857     ot->description= "Set the rotation representation used by selected bones";
01858     
01859     /* callbacks */
01860     ot->invoke= WM_menu_invoke;
01861     ot->exec= pose_bone_rotmode_exec;
01862     ot->poll= ED_operator_posemode;
01863     
01864     /* flags */
01865     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01866     
01867     /* properties */
01868     ot->prop= RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
01869 }
01870 
01871 /* ********************************************** */
01872 
01873 /* Show all armature layers */
01874 static int pose_armature_layers_showall_poll (bContext *C)
01875 {
01876     /* this single operator can be used in posemode OR editmode for armatures */
01877     return ED_operator_posemode(C) || ED_operator_editarmature(C);
01878 }
01879 
01880 static int pose_armature_layers_showall_exec (bContext *C, wmOperator *op)
01881 {
01882     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01883     bArmature *arm = (ob)? ob->data : NULL;
01884     PointerRNA ptr;
01885     int maxLayers = (RNA_boolean_get(op->ptr, "all"))? 32 : 16;
01886     int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
01887     int i;
01888     
01889     /* sanity checking */
01890     if (arm == NULL)
01891         return OPERATOR_CANCELLED;
01892     
01893     /* use RNA to set the layers
01894      *  although it would be faster to just set directly using bitflags, we still
01895      *  need to setup a RNA pointer so that we get the "update" callbacks for free...
01896      */
01897     RNA_id_pointer_create(&arm->id, &ptr);
01898     
01899     for (i = 0; i < maxLayers; i++)
01900         layers[i] = 1;
01901     
01902     RNA_boolean_set_array(&ptr, "layers", layers);
01903     
01904     /* note, notifier might evolve */
01905     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01906     
01907     /* done */
01908     return OPERATOR_FINISHED;
01909 }
01910 
01911 void ARMATURE_OT_layers_show_all (wmOperatorType *ot)
01912 {
01913     /* identifiers */
01914     ot->name= "Show All Layers";
01915     ot->idname= "ARMATURE_OT_layers_show_all";
01916     ot->description= "Make all armature layers visible";
01917     
01918     /* callbacks */
01919     ot->exec= pose_armature_layers_showall_exec;
01920     ot->poll= pose_armature_layers_showall_poll;
01921     
01922     /* flags */
01923     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01924     
01925     /* properties */
01926     ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
01927 }
01928 
01929 /* ------------------- */
01930 
01931 /* Present a popup to get the layers that should be used */
01932 static int pose_armature_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt)
01933 {
01934     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01935     bArmature *arm= (ob)? ob->data : NULL;
01936     PointerRNA ptr;
01937     int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
01938     
01939     /* sanity checking */
01940     if (arm == NULL)
01941         return OPERATOR_CANCELLED;
01942         
01943     /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
01944     RNA_id_pointer_create((ID *)arm, &ptr);
01945     RNA_boolean_get_array(&ptr, "layers", layers);
01946     RNA_boolean_set_array(op->ptr, "layers", layers);
01947     
01948     /* part to sync with other similar operators... */
01949     return WM_operator_props_popup(C, op, evt);
01950 }
01951 
01952 /* Set the visible layers for the active armature (edit and pose modes) */
01953 static int pose_armature_layers_exec (bContext *C, wmOperator *op)
01954 {
01955     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
01956     PointerRNA ptr;
01957     int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
01958 
01959     if (ELEM(NULL, ob, ob->data)) {
01960         return OPERATOR_CANCELLED;
01961     }
01962 
01963     /* get the values set in the operator properties */
01964     RNA_boolean_get_array(op->ptr, "layers", layers);
01965 
01966     /* get pointer for armature, and write data there... */
01967     RNA_id_pointer_create((ID *)ob->data, &ptr);
01968     RNA_boolean_set_array(&ptr, "layers", layers);
01969 
01970     /* note, notifier might evolve */
01971     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
01972 
01973     return OPERATOR_FINISHED;
01974 }
01975 
01976 
01977 void POSE_OT_armature_layers (wmOperatorType *ot)
01978 {
01979     /* identifiers */
01980     ot->name= "Change Armature Layers";
01981     ot->idname= "POSE_OT_armature_layers";
01982     ot->description= "Change the visible armature layers";
01983     
01984     /* callbacks */
01985     ot->invoke= pose_armature_layers_invoke;
01986     ot->exec= pose_armature_layers_exec;
01987     ot->poll= ED_operator_posemode;
01988     
01989     /* flags */
01990     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01991     
01992     /* properties */
01993     RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
01994 }
01995 
01996 void ARMATURE_OT_armature_layers (wmOperatorType *ot)
01997 {
01998     /* identifiers */
01999     ot->name= "Change Armature Layers";
02000     ot->idname= "ARMATURE_OT_armature_layers";
02001     ot->description= "Change the visible armature layers";
02002     
02003     /* callbacks */
02004     ot->invoke= pose_armature_layers_invoke;
02005     ot->exec= pose_armature_layers_exec;
02006     ot->poll= ED_operator_editarmature;
02007     
02008     /* flags */
02009     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02010     
02011     /* properties */
02012     RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
02013 }
02014 
02015 /* ------------------- */
02016 
02017 /* Present a popup to get the layers that should be used */
02018 static int pose_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt)
02019 {
02020     int layers[32]= {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
02021     
02022     /* get layers that are active already */    
02023     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 
02024     {
02025         short bit;
02026         
02027         /* loop over the bits for this pchan's layers, adding layers where they're needed */
02028         for (bit= 0; bit < 32; bit++) {
02029             if (pchan->bone->layer & (1<<bit))
02030                 layers[bit]= 1;
02031         }
02032     }
02033     CTX_DATA_END;
02034     
02035     /* copy layers to operator */
02036     RNA_boolean_set_array(op->ptr, "layers", layers);
02037     
02038         /* part to sync with other similar operators... */
02039     return WM_operator_props_popup(C, op, evt);
02040 }
02041 
02042 /* Set the visible layers for the active armature (edit and pose modes) */
02043 static int pose_bone_layers_exec (bContext *C, wmOperator *op)
02044 {
02045     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
02046     PointerRNA ptr;
02047     int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
02048 
02049     if(ob==NULL || ob->data==NULL) {
02050         return OPERATOR_CANCELLED;
02051     }
02052 
02053     /* get the values set in the operator properties */
02054     RNA_boolean_get_array(op->ptr, "layers", layers);
02055 
02056     /* set layers of pchans based on the values set in the operator props */
02057     CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
02058     {
02059         /* get pointer for pchan, and write flags this way */
02060         RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
02061         RNA_boolean_set_array(&ptr, "layers", layers);
02062     }
02063     CTX_DATA_END;
02064 
02065     /* note, notifier might evolve */
02066     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
02067 
02068     return OPERATOR_FINISHED;
02069 }
02070 
02071 void POSE_OT_bone_layers (wmOperatorType *ot)
02072 {
02073     /* identifiers */
02074     ot->name= "Change Bone Layers";
02075     ot->idname= "POSE_OT_bone_layers";
02076     ot->description= "Change the layers that the selected bones belong to";
02077     
02078     /* callbacks */
02079     ot->invoke= pose_bone_layers_invoke;
02080     ot->exec= pose_bone_layers_exec;
02081     ot->poll= ED_operator_posemode;
02082     
02083     /* flags */
02084     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02085     
02086     /* properties */
02087     RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
02088 }
02089 
02090 /* ------------------- */
02091 
02092 /* Present a popup to get the layers that should be used */
02093 static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt)
02094 {
02095     int layers[32]= {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
02096     
02097     /* get layers that are active already */
02098     CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) 
02099     {
02100         short bit;
02101         
02102         /* loop over the bits for this pchan's layers, adding layers where they're needed */
02103         for (bit= 0; bit < 32; bit++) {
02104             if (ebone->layer & (1<<bit))
02105                 layers[bit]= 1;
02106         }
02107     }
02108     CTX_DATA_END;
02109     
02110     /* copy layers to operator */
02111     RNA_boolean_set_array(op->ptr, "layers", layers);
02112     
02113         /* part to sync with other similar operators... */
02114     return WM_operator_props_popup(C, op, evt);
02115 }
02116 
02117 /* Set the visible layers for the active armature (edit and pose modes) */
02118 static int armature_bone_layers_exec (bContext *C, wmOperator *op)
02119 {
02120     Object *ob= CTX_data_edit_object(C);
02121     bArmature *arm= (ob)? ob->data : NULL;
02122     PointerRNA ptr;
02123     int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
02124     
02125     /* get the values set in the operator properties */
02126     RNA_boolean_get_array(op->ptr, "layers", layers);
02127     
02128     /* set layers of pchans based on the values set in the operator props */
02129     CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) 
02130     {
02131         /* get pointer for pchan, and write flags this way */
02132         RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
02133         RNA_boolean_set_array(&ptr, "layers", layers);
02134     }
02135     CTX_DATA_END;
02136     
02137     /* note, notifier might evolve */
02138     WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
02139     
02140     return OPERATOR_FINISHED;
02141 }
02142 
02143 void ARMATURE_OT_bone_layers (wmOperatorType *ot)
02144 {
02145     /* identifiers */
02146     ot->name= "Change Bone Layers";
02147     ot->idname= "ARMATURE_OT_bone_layers";
02148     ot->description= "Change the layers that the selected bones belong to";
02149     
02150     /* callbacks */
02151     ot->invoke= armature_bone_layers_invoke;
02152     ot->exec= armature_bone_layers_exec;
02153     ot->poll= ED_operator_editarmature;
02154     
02155     /* flags */
02156     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02157     
02158     /* properties */
02159     RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
02160 }
02161 
02162 /* ********************************************** */
02163 /* Flip Quats */
02164 
02165 static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op))
02166 {
02167     Scene *scene= CTX_data_scene(C);
02168     Object *ob= object_pose_armature_get(CTX_data_active_object(C));
02169     KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
02170     
02171     /* loop through all selected pchans, flipping and keying (as needed) */
02172     CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
02173     {
02174         /* only if bone is using quaternion rotation */
02175         if (pchan->rotmode == ROT_MODE_QUAT) {
02176             /* quaternions have 720 degree range */
02177             negate_v4(pchan->quat);
02178 
02179             ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
02180         }
02181     }
02182     CTX_DATA_END;
02183     
02184     /* notifiers and updates */
02185     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02186     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
02187     
02188     return OPERATOR_FINISHED;
02189 }
02190 
02191 void POSE_OT_quaternions_flip (wmOperatorType *ot)
02192 {
02193     /* identifiers */
02194     ot->name = "Flip Quats";
02195     ot->idname= "POSE_OT_quaternions_flip";
02196     ot->description= "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
02197     
02198     /* callbacks */
02199     ot->exec= pose_flip_quats_exec;
02200     ot->poll= ED_operator_posemode;
02201     
02202     /* flags */
02203     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02204 }
02205 
02206 /* ********************************************** */
02207 /* Clear User Transforms */
02208 
02209 static int pose_clear_user_transforms_exec (bContext *C, wmOperator *UNUSED(op))
02210 {
02211     Scene *scene = CTX_data_scene(C);
02212     Object *ob = CTX_data_active_object(C);
02213     float cframe = (float)CFRA;
02214     
02215     if ((ob->adt) && (ob->adt->action)) {
02216         /* XXX: this is just like this to avoid contaminating anything else; 
02217          * just pose values should change, so this should be fine 
02218          */
02219         bPose *dummyPose = NULL;
02220         Object workob = {{0}}; 
02221         bPoseChannel *pchan;
02222         
02223         /* execute animation step for current frame using a dummy copy of the pose */       
02224         copy_pose(&dummyPose, ob->pose, 0);
02225         
02226         BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
02227         workob.type = OB_ARMATURE;
02228         workob.data = ob->data;
02229         workob.adt = ob->adt;
02230         workob.pose = dummyPose;
02231         
02232         BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
02233         
02234         /* copy back values, but on selected bones only  */
02235         for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
02236             pose_bone_do_paste(ob, pchan, 1, 0);
02237         }
02238         
02239         /* free temp data - free manually as was copied without constraints */
02240         if (dummyPose) {
02241             for (pchan= dummyPose->chanbase.first; pchan; pchan= pchan->next) {
02242                 if (pchan->prop) {
02243                     IDP_FreeProperty(pchan->prop);
02244                     MEM_freeN(pchan->prop);
02245                 }
02246             }
02247             
02248             /* was copied without constraints */
02249             BLI_freelistN(&dummyPose->chanbase);
02250             MEM_freeN(dummyPose);
02251         }
02252     }
02253     else {
02254         /* no animation, so just reset whole pose to rest pose 
02255          * (cannot just restore for selected though)
02256          */
02257         rest_pose(ob->pose);
02258     }
02259     
02260     /* notifiers and updates */
02261     DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
02262     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
02263     
02264     return OPERATOR_FINISHED;
02265 }
02266 
02267 void POSE_OT_user_transforms_clear (wmOperatorType *ot)
02268 {
02269     /* identifiers */
02270     ot->name = "Clear User Transforms";
02271     ot->idname= "POSE_OT_user_transforms_clear";
02272     ot->description= "Reset pose on selected bones to keyframed state";
02273     
02274     /* callbacks */
02275     ot->exec= pose_clear_user_transforms_exec;
02276     ot->poll= ED_operator_posemode;
02277     
02278     /* flags */
02279     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02280 }
02281