Blender V2.61 - r43446

action_edit.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  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Joshua Leung
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <math.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <float.h>
00037 
00038 
00039 #include "BLI_blenlib.h"
00040 #include "BLI_math.h"
00041 #include "BLI_utildefines.h"
00042 
00043 #include "DNA_anim_types.h"
00044 #include "DNA_gpencil_types.h"
00045 #include "DNA_object_types.h"
00046 #include "DNA_scene_types.h"
00047 
00048 #include "RNA_access.h"
00049 #include "RNA_define.h"
00050 #include "RNA_enum_types.h"
00051 
00052 #include "BKE_action.h"
00053 #include "BKE_fcurve.h"
00054 #include "BKE_nla.h"
00055 #include "BKE_context.h"
00056 #include "BKE_report.h"
00057 
00058 #include "UI_view2d.h"
00059 
00060 #include "ED_anim_api.h"
00061 #include "ED_gpencil.h"
00062 #include "ED_keyframing.h"
00063 #include "ED_keyframes_edit.h"
00064 #include "ED_screen.h"
00065 #include "ED_transform.h"
00066 #include "ED_markers.h"
00067 
00068 #include "WM_api.h"
00069 #include "WM_types.h"
00070 
00071 #include "UI_interface.h"
00072 
00073 #include "action_intern.h"
00074 
00075 /* ************************************************************************** */
00076 /* ACTION MANAGEMENT */
00077 
00078 /* ******************** New Action Operator *********************** */
00079 
00080 static int act_new_exec(bContext *C, wmOperator *UNUSED(op))
00081 {
00082     PointerRNA ptr, idptr;
00083     PropertyRNA *prop;
00084 
00085     /* hook into UI */
00086     uiIDContextProperty(C, &ptr, &prop);
00087     
00088     if (prop) {
00089         bAction *action=NULL, *oldact=NULL;
00090         PointerRNA oldptr;
00091         
00092         /* create action - the way to do this depends on whether we've got an
00093          * existing one there already, in which case we make a copy of it
00094          * (which is useful for "versioning" actions within the same file)
00095          */
00096         oldptr = RNA_property_pointer_get(&ptr, prop);
00097         oldact = (bAction *)oldptr.id.data;
00098         
00099         if (oldact && GS(oldact->id.name)==ID_AC) {
00100             /* make a copy of the existing action */
00101             action= copy_action(oldact);
00102         }
00103         else {
00104             /* just make a new (empty) action */
00105             action= add_empty_action("Action");
00106         }
00107         
00108         /* when creating new ID blocks, use is already 1 (fake user), 
00109          * but RNA pointer use also increases user, so this compensates it 
00110          */
00111         action->id.us--;
00112         
00113         RNA_id_pointer_create(&action->id, &idptr);
00114         RNA_property_pointer_set(&ptr, prop, idptr);
00115         RNA_property_update(C, &ptr, prop);
00116     }
00117     
00118     /* set notifier that keyframes have changed */
00119     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00120     
00121     return OPERATOR_FINISHED;
00122 }
00123  
00124 void ACTION_OT_new (wmOperatorType *ot)
00125 {
00126     /* identifiers */
00127     ot->name= "New Action";
00128     ot->idname= "ACTION_OT_new";
00129     ot->description= "Create new action";
00130     
00131     /* api callbacks */
00132     ot->exec= act_new_exec;
00133         // NOTE: this is used in the NLA too...
00134     //ot->poll= ED_operator_action_active;
00135     
00136     /* flags */
00137     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00138 }
00139 
00140 /* ************************************************************************** */
00141 /* POSE MARKERS STUFF */
00142 
00143 /* *************************** Localise Markers ***************************** */
00144 
00145 /* ensure that there is:
00146  *  1) an active action editor
00147  *  2) that the mode will have an active action available 
00148  *  3) that the set of markers being shown are the scene markers, not the list we're merging
00149  *  4) that there are some selected markers
00150  */
00151 static int act_markers_make_local_poll(bContext *C)
00152 {
00153     SpaceAction *sact = CTX_wm_space_action(C);
00154     
00155     /* 1) */
00156     if (sact == NULL)
00157         return 0;
00158     
00159     /* 2) */
00160     if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0)
00161         return 0;
00162     if (sact->action == NULL)
00163         return 0;
00164         
00165     /* 3) */
00166     if (sact->flag & SACTION_POSEMARKERS_SHOW)
00167         return 0;
00168         
00169     /* 4) */
00170     return ED_markers_get_first_selected(ED_context_get_markers(C)) != NULL;
00171 }
00172 
00173 static int act_markers_make_local_exec (bContext *C, wmOperator *UNUSED(op))
00174 {   
00175     ListBase *markers = ED_context_get_markers(C);
00176     
00177     SpaceAction *sact = CTX_wm_space_action(C);
00178     bAction *act = (sact)? sact->action : NULL;
00179     
00180     TimeMarker *marker, *markern=NULL;
00181     
00182     /* sanity checks */
00183     if (ELEM(NULL, markers, act))
00184         return OPERATOR_CANCELLED;
00185         
00186     /* migrate markers */
00187     for (marker = markers->first; marker; marker = markern) {
00188         markern = marker->next;
00189         
00190         /* move if marker is selected */
00191         if (marker->flag & SELECT) {
00192             BLI_remlink(markers, marker);
00193             BLI_addtail(&act->markers, marker);
00194         }
00195     }
00196     
00197     /* now enable the "show posemarkers only" setting, so that we can see that something did happen */
00198     sact->flag |= SACTION_POSEMARKERS_SHOW;
00199     
00200     /* notifiers - both sets, as this change affects both */
00201     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00202     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00203     
00204     return OPERATOR_FINISHED;
00205 }
00206 
00207 void ACTION_OT_markers_make_local (wmOperatorType *ot)
00208 {
00209     /* identifiers */
00210     ot->name= "Make Markers Local";
00211     ot->idname= "ACTION_OT_markers_make_local";
00212     ot->description= "Move selected scene markers to the active Action as local 'pose' markers";
00213     
00214     /* callbacks */
00215     ot->exec = act_markers_make_local_exec;
00216     ot->poll = act_markers_make_local_poll;
00217     
00218     /* flags */
00219     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00220 }
00221 
00222 /* ************************************************************************** */
00223 /* KEYFRAME-RANGE STUFF */
00224 
00225 /* *************************** Calculate Range ************************** */
00226 
00227 /* Get the min/max keyframes*/
00228 static void get_keyframe_extents (bAnimContext *ac, float *min, float *max, const short onlySel)
00229 {
00230     ListBase anim_data = {NULL, NULL};
00231     bAnimListElem *ale;
00232     int filter;
00233     
00234     /* get data to filter, from Action or Dopesheet */
00235     // XXX: what is sel doing here?!
00236     //      Commented it, was breaking things (eg. the "auto preview range" tool).
00237     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL *//*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00238     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00239     
00240     /* set large values to try to override */
00241     *min= 999999999.0f;
00242     *max= -999999999.0f;
00243     
00244     /* check if any channels to set range with */
00245     if (anim_data.first) {
00246         /* go through channels, finding max extents */
00247         for (ale= anim_data.first; ale; ale= ale->next) {
00248             AnimData *adt= ANIM_nla_mapping_get(ac, ale);
00249             if (ale->datatype == ALE_GPFRAME) {
00250                 bGPDlayer *gpl= ale->data;
00251                 bGPDframe *gpf;
00252 
00253                 /* find gp-frame which is less than or equal to cframe */
00254                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
00255                     *min= MIN2(*min, gpf->framenum);
00256                     *max= MAX2(*max, gpf->framenum);
00257                 }
00258             }
00259             else {
00260                 FCurve *fcu= (FCurve *)ale->key_data;
00261                 float tmin, tmax;
00262 
00263                 /* get range and apply necessary scaling before processing */
00264                 calc_fcurve_range(fcu, &tmin, &tmax, onlySel, TRUE);
00265 
00266                 if (adt) {
00267                     tmin= BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
00268                     tmax= BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP);
00269                 }
00270 
00271                 /* try to set cur using these values, if they're more extreme than previously set values */
00272                 *min= MIN2(*min, tmin);
00273                 *max= MAX2(*max, tmax);
00274             }
00275         }
00276         
00277         /* free memory */
00278         BLI_freelistN(&anim_data);
00279     }
00280     else {
00281         /* set default range */
00282         if (ac->scene) {
00283             *min= (float)ac->scene->r.sfra;
00284             *max= (float)ac->scene->r.efra;
00285         }
00286         else {
00287             *min= -5;
00288             *max= 100;
00289         }
00290     }
00291 }
00292 
00293 /* ****************** Automatic Preview-Range Operator ****************** */
00294 
00295 static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
00296 {
00297     bAnimContext ac;
00298     Scene *scene;
00299     float min, max;
00300     
00301     /* get editor data */
00302     if (ANIM_animdata_get_context(C, &ac) == 0)
00303         return OPERATOR_CANCELLED;
00304     if (ac.scene == NULL)
00305         return OPERATOR_CANCELLED;
00306     else
00307         scene= ac.scene;
00308     
00309     /* set the range directly */
00310     get_keyframe_extents(&ac, &min, &max, FALSE);
00311     scene->r.flag |= SCER_PRV_RANGE;
00312     scene->r.psfra= (int)floor(min + 0.5f);
00313     scene->r.pefra= (int)floor(max + 0.5f);
00314     
00315     /* set notifier that things have changed */
00316     // XXX err... there's nothing for frame ranges yet, but this should do fine too
00317     WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 
00318     
00319     return OPERATOR_FINISHED;
00320 }
00321  
00322 void ACTION_OT_previewrange_set (wmOperatorType *ot)
00323 {
00324     /* identifiers */
00325     ot->name= "Auto-Set Preview Range";
00326     ot->idname= "ACTION_OT_previewrange_set";
00327     ot->description= "Set Preview Range based on extents of selected Keyframes";
00328     
00329     /* api callbacks */
00330     ot->exec= actkeys_previewrange_exec;
00331     ot->poll= ED_operator_action_active;
00332     
00333     /* flags */
00334     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00335 }
00336 
00337 /* ****************** View-All Operator ****************** */
00338 
00339 static int actkeys_viewall(bContext *C, const short onlySel)
00340 {
00341     bAnimContext ac;
00342     View2D *v2d;
00343     float extra;
00344     
00345     /* get editor data */
00346     if (ANIM_animdata_get_context(C, &ac) == 0)
00347         return OPERATOR_CANCELLED;
00348     v2d= &ac.ar->v2d;
00349     
00350     /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
00351     get_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
00352     
00353     extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
00354     v2d->cur.xmin -= extra;
00355     v2d->cur.xmax += extra;
00356     
00357     /* set vertical range */
00358     v2d->cur.ymax= 0.0f;
00359     v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
00360     
00361     /* do View2D syncing */
00362     UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
00363     
00364     /* just redraw this view */
00365     ED_area_tag_redraw(CTX_wm_area(C));
00366     
00367     return OPERATOR_FINISHED;
00368 }
00369 
00370 /* ......... */
00371 
00372 static int actkeys_viewall_exec(bContext *C, wmOperator *UNUSED(op))
00373 {   
00374     /* whole range */
00375     return actkeys_viewall(C, FALSE);
00376 }
00377 
00378 static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
00379 {
00380     /* only selected */
00381     return actkeys_viewall(C, TRUE);
00382 }
00383  
00384 void ACTION_OT_view_all (wmOperatorType *ot)
00385 {
00386     /* identifiers */
00387     ot->name= "View All";
00388     ot->idname= "ACTION_OT_view_all";
00389     ot->description= "Reset viewable area to show full keyframe range";
00390     
00391     /* api callbacks */
00392     ot->exec= actkeys_viewall_exec;
00393     ot->poll= ED_operator_action_active;
00394     
00395     /* flags */
00396     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00397 }
00398 
00399 void ACTION_OT_view_selected (wmOperatorType *ot)
00400 {
00401     /* identifiers */
00402     ot->name= "View Selected";
00403     ot->idname= "ACTION_OT_view_selected";
00404     ot->description= "Reset viewable area to show selected keyframes range";
00405     
00406     /* api callbacks */
00407     ot->exec= actkeys_viewsel_exec;
00408     ot->poll= ED_operator_action_active;
00409     
00410     /* flags */
00411     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00412 }
00413 
00414 /* ************************************************************************** */
00415 /* GENERAL STUFF */
00416 
00417 /* ******************** Copy/Paste Keyframes Operator ************************* */
00418 /* NOTE: the backend code for this is shared with the graph editor */
00419 
00420 static short copy_action_keys (bAnimContext *ac)
00421 {   
00422     ListBase anim_data = {NULL, NULL};
00423     int filter, ok=0;
00424     
00425     /* clear buffer first */
00426     free_anim_copybuf();
00427     
00428     /* filter data */
00429     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00430     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00431     
00432     /* copy keyframes */
00433     ok= copy_animedit_keys(ac, &anim_data);
00434     
00435     /* clean up */
00436     BLI_freelistN(&anim_data);
00437 
00438     return ok;
00439 }
00440 
00441 
00442 static short paste_action_keys (bAnimContext *ac,
00443     const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
00444 {   
00445     ListBase anim_data = {NULL, NULL};
00446     int filter, ok=0;
00447     
00448     /* filter data */
00449     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00450     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00451     
00452     /* paste keyframes */
00453     ok= paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
00454     
00455     /* clean up */
00456     BLI_freelistN(&anim_data);
00457 
00458     return ok;
00459 }
00460 
00461 /* ------------------- */
00462 
00463 static int actkeys_copy_exec(bContext *C, wmOperator *op)
00464 {
00465     bAnimContext ac;
00466     
00467     /* get editor data */
00468     if (ANIM_animdata_get_context(C, &ac) == 0)
00469         return OPERATOR_CANCELLED;
00470     
00471     /* copy keyframes */
00472     if (ac.datatype == ANIMCONT_GPENCIL) {
00473         // FIXME...
00474         BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for Grease Pencil mode");
00475         return OPERATOR_CANCELLED;
00476     }
00477     else {
00478         if (copy_action_keys(&ac)) {    
00479             BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
00480             return OPERATOR_CANCELLED;
00481         }
00482     }
00483     
00484     return OPERATOR_FINISHED;
00485 }
00486  
00487 void ACTION_OT_copy (wmOperatorType *ot)
00488 {
00489     /* identifiers */
00490     ot->name= "Copy Keyframes";
00491     ot->idname= "ACTION_OT_copy";
00492     ot->description= "Copy selected keyframes to the copy/paste buffer";
00493     
00494     /* api callbacks */
00495     ot->exec= actkeys_copy_exec;
00496     ot->poll= ED_operator_action_active;
00497 
00498     /* flags */
00499     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00500 }
00501 
00502 static int actkeys_paste_exec(bContext *C, wmOperator *op)
00503 {
00504     bAnimContext ac;
00505 
00506     const eKeyPasteOffset offset_mode= RNA_enum_get(op->ptr, "offset");
00507     const eKeyMergeMode merge_mode= RNA_enum_get(op->ptr, "merge");
00508     
00509     /* get editor data */
00510     if (ANIM_animdata_get_context(C, &ac) == 0)
00511         return OPERATOR_CANCELLED;
00512         
00513     /* ac.reports by default will be the global reports list, which won't show warnings */
00514     ac.reports= op->reports;
00515     
00516     /* paste keyframes */
00517     if (ac.datatype == ANIMCONT_GPENCIL) {
00518         // FIXME...
00519         BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for Grease Pencil mode");
00520         return OPERATOR_CANCELLED;
00521     }
00522     else {
00523         /* non-zero return means an error occurred while trying to paste */
00524         if (paste_action_keys(&ac, offset_mode, merge_mode)) {
00525             return OPERATOR_CANCELLED;
00526         }
00527     }
00528     
00529     /* validate keyframes after editing */
00530     ANIM_editkeyframes_refresh(&ac);
00531     
00532     /* set notifier that keyframes have changed */
00533     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00534     
00535     return OPERATOR_FINISHED;
00536 }
00537  
00538 void ACTION_OT_paste (wmOperatorType *ot)
00539 {
00540     /* identifiers */
00541     ot->name= "Paste Keyframes";
00542     ot->idname= "ACTION_OT_paste";
00543     ot->description= "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame";
00544     
00545     /* api callbacks */
00546 //  ot->invoke= WM_operator_props_popup; // better wait for action redo panel
00547     ot->exec= actkeys_paste_exec;
00548     ot->poll= ED_operator_action_active;
00549     
00550     /* flags */
00551     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00552     
00553     /* props */
00554     RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
00555     RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
00556 }
00557 
00558 /* ******************** Insert Keyframes Operator ************************* */
00559 
00560 /* defines for insert keyframes tool */
00561 static EnumPropertyItem prop_actkeys_insertkey_types[] = {
00562     {1, "ALL", 0, "All Channels", ""},
00563     {2, "SEL", 0, "Only Selected Channels", ""},
00564     {3, "GROUP", 0, "In Active Group", ""}, // xxx not in all cases
00565     {0, NULL, 0, NULL, NULL}
00566 };
00567 
00568 /* this function is responsible for snapping keyframes to frame-times */
00569 static void insert_action_keys(bAnimContext *ac, short mode) 
00570 {
00571     ListBase anim_data = {NULL, NULL};
00572     bAnimListElem *ale;
00573     int filter;
00574     
00575     ReportList *reports = ac->reports;
00576     Scene *scene= ac->scene;
00577     short flag = 0;
00578     
00579     /* filter data */
00580     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00581     if (mode == 2)          filter |= ANIMFILTER_SEL;
00582     else if (mode == 3)     filter |= ANIMFILTER_ACTGROUPED;
00583     
00584     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00585     
00586     /* init keyframing flag */
00587     flag = ANIM_get_keyframing_flags(scene, 1);
00588     
00589     /* insert keyframes */
00590     for (ale= anim_data.first; ale; ale= ale->next) {
00591         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
00592         FCurve *fcu= (FCurve *)ale->key_data;
00593         float cfra;
00594         
00595         /* adjust current frame for NLA-scaling */
00596         if (adt)
00597             cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
00598         else 
00599             cfra= (float)CFRA;
00600             
00601         /* if there's an id */
00602         if (ale->id)
00603             insert_keyframe(reports, ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
00604         else
00605             insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
00606     }
00607     
00608     BLI_freelistN(&anim_data);
00609 }
00610 
00611 /* ------------------- */
00612 
00613 static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
00614 {
00615     bAnimContext ac;
00616     short mode;
00617     
00618     /* get editor data */
00619     if (ANIM_animdata_get_context(C, &ac) == 0)
00620         return OPERATOR_CANCELLED;
00621     if (ac.datatype == ANIMCONT_GPENCIL)
00622         return OPERATOR_CANCELLED;
00623         
00624     /* what channels to affect? */
00625     mode= RNA_enum_get(op->ptr, "type");
00626     
00627     /* insert keyframes */
00628     insert_action_keys(&ac, mode);
00629     
00630     /* validate keyframes after editing */
00631     ANIM_editkeyframes_refresh(&ac);
00632     
00633     /* set notifier that keyframes have changed */
00634     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00635     
00636     return OPERATOR_FINISHED;
00637 }
00638 
00639 void ACTION_OT_keyframe_insert (wmOperatorType *ot)
00640 {
00641     /* identifiers */
00642     ot->name= "Insert Keyframes";
00643     ot->idname= "ACTION_OT_keyframe_insert";
00644     ot->description= "Insert keyframes for the specified channels";
00645     
00646     /* api callbacks */
00647     ot->invoke= WM_menu_invoke;
00648     ot->exec= actkeys_insertkey_exec;
00649     ot->poll= ED_operator_action_active;
00650     
00651     /* flags */
00652     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00653     
00654     /* id-props */
00655     ot->prop= RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
00656 }
00657 
00658 /* ******************** Duplicate Keyframes Operator ************************* */
00659 
00660 static void duplicate_action_keys (bAnimContext *ac)
00661 {
00662     ListBase anim_data = {NULL, NULL};
00663     bAnimListElem *ale;
00664     int filter;
00665     
00666     /* filter data */
00667     if (ac->datatype == ANIMCONT_GPENCIL)
00668         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
00669     else
00670         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00671     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00672     
00673     /* loop through filtered data and delete selected keys */
00674     for (ale= anim_data.first; ale; ale= ale->next) {
00675         if (ale->type == ANIMTYPE_FCURVE)
00676             duplicate_fcurve_keys((FCurve *)ale->key_data);
00677         else
00678             duplicate_gplayer_frames((bGPDlayer *)ale->data);
00679     }
00680     
00681     /* free filtered list */
00682     BLI_freelistN(&anim_data);
00683 }
00684 
00685 /* ------------------- */
00686 
00687 static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
00688 {
00689     bAnimContext ac;
00690     
00691     /* get editor data */
00692     if (ANIM_animdata_get_context(C, &ac) == 0)
00693         return OPERATOR_CANCELLED;
00694         
00695     /* duplicate keyframes */
00696     duplicate_action_keys(&ac);
00697     
00698     /* validate keyframes after editing */
00699     if (ac.datatype != ANIMCONT_GPENCIL)
00700         ANIM_editkeyframes_refresh(&ac);
00701     
00702     /* set notifier that keyframes have changed */
00703     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00704     
00705     return OPERATOR_FINISHED;
00706 }
00707 
00708 static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
00709 {
00710     actkeys_duplicate_exec(C, op);
00711     
00712     return OPERATOR_FINISHED;
00713 }
00714  
00715 void ACTION_OT_duplicate (wmOperatorType *ot)
00716 {
00717     /* identifiers */
00718     ot->name= "Duplicate Keyframes";
00719     ot->idname= "ACTION_OT_duplicate";
00720     ot->description= "Make a copy of all selected keyframes";
00721     
00722     /* api callbacks */
00723     ot->invoke= actkeys_duplicate_invoke;
00724     ot->exec= actkeys_duplicate_exec;
00725     ot->poll= ED_operator_action_active;
00726     
00727     /* flags */
00728     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00729 }
00730 
00731 /* ******************** Delete Keyframes Operator ************************* */
00732 
00733 static void delete_action_keys (bAnimContext *ac)
00734 {
00735     ListBase anim_data = {NULL, NULL};
00736     bAnimListElem *ale;
00737     int filter;
00738     
00739     /* filter data */
00740     if (ac->datatype == ANIMCONT_GPENCIL)
00741         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
00742     else
00743         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00744     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00745     
00746     /* loop through filtered data and delete selected keys */
00747     for (ale= anim_data.first; ale; ale= ale->next) {
00748         if (ale->type != ANIMTYPE_GPLAYER) {
00749             FCurve *fcu= (FCurve *)ale->key_data;
00750             AnimData *adt= ale->adt;
00751             
00752             /* delete selected keyframes only */
00753             delete_fcurve_keys(fcu); 
00754             
00755             /* Only delete curve too if it won't be doing anything anymore */
00756             if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0))
00757                 ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
00758         }
00759         else
00760             delete_gplayer_frames((bGPDlayer *)ale->data);
00761     }
00762     
00763     /* free filtered list */
00764     BLI_freelistN(&anim_data);
00765 }
00766 
00767 /* ------------------- */
00768 
00769 static int actkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
00770 {
00771     bAnimContext ac;
00772     
00773     /* get editor data */
00774     if (ANIM_animdata_get_context(C, &ac) == 0)
00775         return OPERATOR_CANCELLED;
00776         
00777     /* delete keyframes */
00778     delete_action_keys(&ac);
00779     
00780     /* validate keyframes after editing */
00781     if (ac.datatype != ANIMCONT_GPENCIL)
00782         ANIM_editkeyframes_refresh(&ac);
00783     
00784     /* set notifier that keyframes have changed */
00785     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00786     
00787     return OPERATOR_FINISHED;
00788 }
00789  
00790 void ACTION_OT_delete (wmOperatorType *ot)
00791 {
00792     /* identifiers */
00793     ot->name= "Delete Keyframes";
00794     ot->idname= "ACTION_OT_delete";
00795     ot->description= "Remove all selected keyframes";
00796     
00797     /* api callbacks */
00798     ot->invoke= WM_operator_confirm;
00799     ot->exec= actkeys_delete_exec;
00800     ot->poll= ED_operator_action_active;
00801     
00802     /* flags */
00803     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00804 }
00805 
00806 /* ******************** Clean Keyframes Operator ************************* */
00807 
00808 static void clean_action_keys (bAnimContext *ac, float thresh)
00809 {   
00810     ListBase anim_data = {NULL, NULL};
00811     bAnimListElem *ale;
00812     int filter;
00813     
00814     /* filter data */
00815     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00816     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00817     
00818     /* loop through filtered data and clean curves */
00819     for (ale= anim_data.first; ale; ale= ale->next)
00820         clean_fcurve((FCurve *)ale->key_data, thresh);
00821     
00822     /* free temp data */
00823     BLI_freelistN(&anim_data);
00824 }
00825 
00826 /* ------------------- */
00827 
00828 static int actkeys_clean_exec(bContext *C, wmOperator *op)
00829 {
00830     bAnimContext ac;
00831     float thresh;
00832     
00833     /* get editor data */
00834     if (ANIM_animdata_get_context(C, &ac) == 0)
00835         return OPERATOR_CANCELLED;
00836     if (ac.datatype == ANIMCONT_GPENCIL)
00837         return OPERATOR_PASS_THROUGH;
00838         
00839     /* get cleaning threshold */
00840     thresh= RNA_float_get(op->ptr, "threshold");
00841     
00842     /* clean keyframes */
00843     clean_action_keys(&ac, thresh);
00844     
00845     /* validate keyframes after editing */
00846     ANIM_editkeyframes_refresh(&ac);
00847     
00848     /* set notifier that keyframes have changed */
00849     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00850     
00851     return OPERATOR_FINISHED;
00852 }
00853  
00854 void ACTION_OT_clean (wmOperatorType *ot)
00855 {
00856     /* identifiers */
00857     ot->name= "Clean Keyframes";
00858     ot->idname= "ACTION_OT_clean";
00859     ot->description= "Simplify F-Curves by removing closely spaced keyframes";
00860     
00861     /* api callbacks */
00862     //ot->invoke=  // XXX we need that number popup for this! 
00863     ot->exec= actkeys_clean_exec;
00864     ot->poll= ED_operator_action_active;
00865     
00866     /* flags */
00867     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00868     
00869     /* properties */
00870     ot->prop= RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
00871 }
00872 
00873 /* ******************** Sample Keyframes Operator *********************** */
00874 
00875 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
00876 static void sample_action_keys (bAnimContext *ac)
00877 {   
00878     ListBase anim_data = {NULL, NULL};
00879     bAnimListElem *ale;
00880     int filter;
00881     
00882     /* filter data */
00883     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00884     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00885     
00886     /* loop through filtered data and add keys between selected keyframes on every frame  */
00887     for (ale= anim_data.first; ale; ale= ale->next)
00888         sample_fcurve((FCurve *)ale->key_data);
00889     
00890     /* admin and redraws */
00891     BLI_freelistN(&anim_data);
00892 }
00893 
00894 /* ------------------- */
00895 
00896 static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
00897 {
00898     bAnimContext ac;
00899     
00900     /* get editor data */
00901     if (ANIM_animdata_get_context(C, &ac) == 0)
00902         return OPERATOR_CANCELLED;
00903     if (ac.datatype == ANIMCONT_GPENCIL)
00904         return OPERATOR_PASS_THROUGH;
00905     
00906     /* sample keyframes */
00907     sample_action_keys(&ac);
00908     
00909     /* validate keyframes after editing */
00910     ANIM_editkeyframes_refresh(&ac);
00911     
00912     /* set notifier that keyframes have changed */
00913     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00914     
00915     return OPERATOR_FINISHED;
00916 }
00917  
00918 void ACTION_OT_sample (wmOperatorType *ot)
00919 {
00920     /* identifiers */
00921     ot->name= "Sample Keyframes";
00922     ot->idname= "ACTION_OT_sample";
00923     ot->description= "Add keyframes on every frame between the selected keyframes";
00924     
00925     /* api callbacks */
00926     ot->exec= actkeys_sample_exec;
00927     ot->poll= ED_operator_action_active;
00928     
00929     /* flags */
00930     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00931 }
00932 
00933 /* ************************************************************************** */
00934 /* SETTINGS STUFF */
00935 
00936 /* ******************** Set Extrapolation-Type Operator *********************** */
00937 
00938 /* defines for make/clear cyclic extrapolation tools */
00939 #define MAKE_CYCLIC_EXPO    -1
00940 #define CLEAR_CYCLIC_EXPO   -2
00941 
00942 /* defines for set extrapolation-type for selected keyframes tool */
00943 static EnumPropertyItem prop_actkeys_expo_types[] = {
00944     {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", ""},
00945     {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", ""},
00946     
00947     {MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"},
00948     {CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"},
00949     {0, NULL, 0, NULL, NULL}
00950 };
00951 
00952 /* this function is responsible for setting extrapolation mode for keyframes */
00953 static void setexpo_action_keys(bAnimContext *ac, short mode) 
00954 {
00955     ListBase anim_data = {NULL, NULL};
00956     bAnimListElem *ale;
00957     int filter;
00958     
00959     /* filter data */
00960     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
00961     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00962     
00963     /* loop through setting mode per F-Curve */
00964     for (ale= anim_data.first; ale; ale= ale->next) {
00965         FCurve *fcu= (FCurve *)ale->data;
00966         
00967         if (mode >= 0) {
00968             /* just set mode setting */
00969             fcu->extend= mode;
00970         }
00971         else {
00972             /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation 
00973              * without having to go through FModifier UI in Graph Editor to do so
00974              */
00975             if (mode == MAKE_CYCLIC_EXPO) {
00976                 /* only add if one doesn't exist */
00977                 if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) {
00978                     // TODO: add some more preset versions which set different extrapolation options?
00979                     add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
00980                 }
00981             }
00982             else if (mode == CLEAR_CYCLIC_EXPO) {
00983                 /* remove all the modifiers fitting this description */
00984                 FModifier *fcm, *fcn=NULL;
00985                 
00986                 for (fcm = fcu->modifiers.first; fcm; fcm = fcn) {
00987                     fcn = fcm->next;
00988                     
00989                     if (fcm->type == FMODIFIER_TYPE_CYCLES)
00990                         remove_fmodifier(&fcu->modifiers, fcm);
00991                 }
00992             }
00993         }
00994     }
00995     
00996     /* cleanup */
00997     BLI_freelistN(&anim_data);
00998 }
00999 
01000 /* ------------------- */
01001 
01002 static int actkeys_expo_exec(bContext *C, wmOperator *op)
01003 {
01004     bAnimContext ac;
01005     short mode;
01006     
01007     /* get editor data */
01008     if (ANIM_animdata_get_context(C, &ac) == 0)
01009         return OPERATOR_CANCELLED;
01010     if (ac.datatype == ANIMCONT_GPENCIL) 
01011         return OPERATOR_PASS_THROUGH;
01012         
01013     /* get handle setting mode */
01014     mode= RNA_enum_get(op->ptr, "type");
01015     
01016     /* set handle type */
01017     setexpo_action_keys(&ac, mode);
01018     
01019     /* validate keyframes after editing */
01020     ANIM_editkeyframes_refresh(&ac);
01021     
01022     /* set notifier that keyframe properties have changed */
01023     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
01024     
01025     return OPERATOR_FINISHED;
01026 }
01027  
01028 void ACTION_OT_extrapolation_type (wmOperatorType *ot)
01029 {
01030     /* identifiers */
01031     ot->name= "Set Keyframe Extrapolation";
01032     ot->idname= "ACTION_OT_extrapolation_type";
01033     ot->description= "Set extrapolation mode for selected F-Curves";
01034     
01035     /* api callbacks */
01036     ot->invoke= WM_menu_invoke;
01037     ot->exec= actkeys_expo_exec;
01038     ot->poll= ED_operator_action_active;
01039     
01040     /* flags */
01041     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01042     
01043     /* id-props */
01044     ot->prop= RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
01045 }
01046 
01047 /* ******************** Set Interpolation-Type Operator *********************** */
01048 
01049 /* this function is responsible for setting interpolation mode for keyframes */
01050 static void setipo_action_keys(bAnimContext *ac, short mode) 
01051 {
01052     ListBase anim_data = {NULL, NULL};
01053     bAnimListElem *ale;
01054     int filter;
01055     KeyframeEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
01056     
01057     /* filter data */
01058     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
01059     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
01060     
01061     /* loop through setting BezTriple interpolation
01062      * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
01063      */
01064     for (ale= anim_data.first; ale; ale= ale->next)
01065         ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
01066     
01067     /* cleanup */
01068     BLI_freelistN(&anim_data);
01069 }
01070 
01071 /* ------------------- */
01072 
01073 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
01074 {
01075     bAnimContext ac;
01076     short mode;
01077     
01078     /* get editor data */
01079     if (ANIM_animdata_get_context(C, &ac) == 0)
01080         return OPERATOR_CANCELLED;
01081     if (ac.datatype == ANIMCONT_GPENCIL) 
01082         return OPERATOR_PASS_THROUGH;
01083         
01084     /* get handle setting mode */
01085     mode= RNA_enum_get(op->ptr, "type");
01086     
01087     /* set handle type */
01088     setipo_action_keys(&ac, mode);
01089     
01090     /* validate keyframes after editing */
01091     ANIM_editkeyframes_refresh(&ac);
01092     
01093     /* set notifier that keyframe properties have changed */
01094     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
01095     
01096     return OPERATOR_FINISHED;
01097 }
01098  
01099 void ACTION_OT_interpolation_type (wmOperatorType *ot)
01100 {
01101     /* identifiers */
01102     ot->name= "Set Keyframe Interpolation";
01103     ot->idname= "ACTION_OT_interpolation_type";
01104     ot->description= "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
01105     
01106     /* api callbacks */
01107     ot->invoke= WM_menu_invoke;
01108     ot->exec= actkeys_ipo_exec;
01109     ot->poll= ED_operator_action_active;
01110     
01111     /* flags */
01112     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01113     
01114     /* id-props */
01115     ot->prop= RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
01116 }
01117 
01118 /* ******************** Set Handle-Type Operator *********************** */
01119 
01120 /* this function is responsible for setting handle-type of selected keyframes */
01121 static void sethandles_action_keys(bAnimContext *ac, short mode) 
01122 {
01123     ListBase anim_data = {NULL, NULL};
01124     bAnimListElem *ale;
01125     int filter;
01126     
01127     KeyframeEditFunc edit_cb= ANIM_editkeyframes_handles(mode);
01128     KeyframeEditFunc sel_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
01129     
01130     /* filter data */
01131     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
01132     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
01133     
01134     /* loop through setting flags for handles 
01135      * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
01136      */
01137     for (ale= anim_data.first; ale; ale= ale->next) {
01138         FCurve *fcu= (FCurve *)ale->key_data;
01139         
01140         /* any selected keyframes for editing? */
01141         if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
01142             /* change type of selected handles */
01143             ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
01144         }
01145     }
01146     
01147     /* cleanup */
01148     BLI_freelistN(&anim_data);
01149 }
01150 
01151 /* ------------------- */
01152 
01153 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
01154 {
01155     bAnimContext ac;
01156     short mode;
01157     
01158     /* get editor data */
01159     if (ANIM_animdata_get_context(C, &ac) == 0)
01160         return OPERATOR_CANCELLED;
01161     if (ac.datatype == ANIMCONT_GPENCIL) 
01162         return OPERATOR_PASS_THROUGH;
01163         
01164     /* get handle setting mode */
01165     mode= RNA_enum_get(op->ptr, "type");
01166     
01167     /* set handle type */
01168     sethandles_action_keys(&ac, mode);
01169     
01170     /* validate keyframes after editing */
01171     ANIM_editkeyframes_refresh(&ac);
01172     
01173     /* set notifier that keyframe properties have changed */
01174     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
01175     
01176     return OPERATOR_FINISHED;
01177 }
01178  
01179 void ACTION_OT_handle_type (wmOperatorType *ot)
01180 {
01181     /* identifiers */
01182     ot->name= "Set Keyframe Handle Type";
01183     ot->idname= "ACTION_OT_handle_type";
01184     ot->description= "Set type of handle for selected keyframes";
01185     
01186     /* api callbacks */
01187     ot->invoke= WM_menu_invoke;
01188     ot->exec= actkeys_handletype_exec;
01189     ot->poll= ED_operator_action_active;
01190     
01191     /* flags */
01192     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01193     
01194     /* id-props */
01195     ot->prop= RNA_def_enum(ot->srna, "type", keyframe_handle_type_items, 0, "Type", "");
01196 }
01197 
01198 /* ******************** Set Keyframe-Type Operator *********************** */
01199 
01200 /* this function is responsible for setting interpolation mode for keyframes */
01201 static void setkeytype_action_keys(bAnimContext *ac, short mode) 
01202 {
01203     ListBase anim_data = {NULL, NULL};
01204     bAnimListElem *ale;
01205     int filter;
01206     KeyframeEditFunc set_cb= ANIM_editkeyframes_keytype(mode);
01207     
01208     /* filter data */
01209     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
01210     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
01211     
01212     /* loop through setting BezTriple interpolation
01213      * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
01214      */
01215     for (ale= anim_data.first; ale; ale= ale->next)
01216         ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
01217     
01218     /* cleanup */
01219     BLI_freelistN(&anim_data);
01220 }
01221 
01222 /* ------------------- */
01223 
01224 static int actkeys_keytype_exec(bContext *C, wmOperator *op)
01225 {
01226     bAnimContext ac;
01227     short mode;
01228     
01229     /* get editor data */
01230     if (ANIM_animdata_get_context(C, &ac) == 0)
01231         return OPERATOR_CANCELLED;
01232     if (ac.datatype == ANIMCONT_GPENCIL) 
01233         return OPERATOR_PASS_THROUGH;
01234         
01235     /* get handle setting mode */
01236     mode= RNA_enum_get(op->ptr, "type");
01237     
01238     /* set handle type */
01239     setkeytype_action_keys(&ac, mode);
01240     
01241     /* validate keyframes after editing */
01242     ANIM_editkeyframes_refresh(&ac);
01243     
01244     /* set notifier that keyframe properties have changed */
01245     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
01246     
01247     return OPERATOR_FINISHED;
01248 }
01249  
01250 void ACTION_OT_keyframe_type (wmOperatorType *ot)
01251 {
01252     /* identifiers */
01253     ot->name= "Set Keyframe Type";
01254     ot->idname= "ACTION_OT_keyframe_type";
01255     ot->description= "Set type of keyframe for the selected keyframes";
01256     
01257     /* api callbacks */
01258     ot->invoke= WM_menu_invoke;
01259     ot->exec= actkeys_keytype_exec;
01260     ot->poll= ED_operator_action_active;
01261     
01262     /* flags */
01263     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01264     
01265     /* id-props */
01266     ot->prop= RNA_def_enum(ot->srna, "type", beztriple_keyframe_type_items, 0, "Type", "");
01267 }
01268 
01269 /* ************************************************************************** */
01270 /* TRANSFORM STUFF */
01271 
01272 /* ***************** Jump to Selected Frames Operator *********************** */
01273 
01274 /* snap current-frame indicator to 'average time' of selected keyframe */
01275 static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
01276 {
01277     bAnimContext ac;
01278     ListBase anim_data= {NULL, NULL};
01279     bAnimListElem *ale;
01280     int filter;
01281     KeyframeEditData ked= {{NULL}};
01282     
01283     /* get editor data */
01284     if (ANIM_animdata_get_context(C, &ac) == 0)
01285         return OPERATOR_CANCELLED;
01286     
01287     /* init edit data */    
01288     /* loop over action data, averaging values */
01289     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
01290     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01291     
01292     for (ale= anim_data.first; ale; ale= ale->next) {
01293         AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
01294         if (adt) {
01295             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
01296             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
01297             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
01298         }
01299         else
01300             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
01301     }
01302     
01303     BLI_freelistN(&anim_data);
01304     
01305     /* set the new current frame value, based on the average time */
01306     if (ked.i1) {
01307         Scene *scene= ac.scene;
01308         CFRA= (int)floor((ked.f1 / ked.i1) + 0.5f);
01309         SUBFRA= 0.f;
01310     }
01311     
01312     /* set notifier that things have changed */
01313     WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
01314     
01315     return OPERATOR_FINISHED;
01316 }
01317 
01318 void ACTION_OT_frame_jump (wmOperatorType *ot)
01319 {
01320     /* identifiers */
01321     ot->name= "Jump to Frame";
01322     ot->idname= "ACTION_OT_frame_jump";
01323     ot->description= "Set the current frame to the average frame of the selected keyframes";
01324     
01325     /* api callbacks */
01326     ot->exec= actkeys_framejump_exec;
01327     ot->poll= ED_operator_action_active;
01328     
01329     /* flags */
01330     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01331 }
01332 
01333 /* ******************** Snap Keyframes Operator *********************** */
01334 
01335 /* defines for snap keyframes tool */
01336 static EnumPropertyItem prop_actkeys_snap_types[] = {
01337     {ACTKEYS_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
01338     {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
01339     {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
01340     {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
01341     {0, NULL, 0, NULL, NULL}
01342 };
01343 
01344 /* this function is responsible for snapping keyframes to frame-times */
01345 static void snap_action_keys(bAnimContext *ac, short mode) 
01346 {
01347     ListBase anim_data = {NULL, NULL};
01348     bAnimListElem *ale;
01349     int filter;
01350     
01351     KeyframeEditData ked= {{NULL}};
01352     KeyframeEditFunc edit_cb;
01353     
01354     /* filter data */
01355     if (ac->datatype == ANIMCONT_GPENCIL)
01356         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01357     else
01358         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
01359     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
01360     
01361     /* get beztriple editing callbacks */
01362     edit_cb= ANIM_editkeyframes_snap(mode);
01363 
01364     ked.scene= ac->scene;
01365     if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
01366         ked.list.first= (ac->markers) ? ac->markers->first : NULL;
01367         ked.list.last= (ac->markers) ? ac->markers->last : NULL;
01368     }
01369     
01370     /* snap keyframes */
01371     for (ale= anim_data.first; ale; ale= ale->next) {
01372         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
01373         
01374         if (adt) {
01375             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
01376             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
01377             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
01378         }
01379         //else if (ale->type == ACTTYPE_GPLAYER)
01380         //  snap_gplayer_frames(ale->data, mode);
01381         else 
01382             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
01383     }
01384     
01385     BLI_freelistN(&anim_data);
01386 }
01387 
01388 /* ------------------- */
01389 
01390 static int actkeys_snap_exec(bContext *C, wmOperator *op)
01391 {
01392     bAnimContext ac;
01393     short mode;
01394     
01395     /* get editor data */
01396     if (ANIM_animdata_get_context(C, &ac) == 0)
01397         return OPERATOR_CANCELLED;
01398         
01399     // XXX...
01400     if (ac.datatype == ANIMCONT_GPENCIL)
01401         return OPERATOR_PASS_THROUGH;
01402         
01403     /* get snapping mode */
01404     mode= RNA_enum_get(op->ptr, "type");
01405     
01406     /* snap keyframes */
01407     snap_action_keys(&ac, mode);
01408     
01409     /* validate keyframes after editing */
01410     ANIM_editkeyframes_refresh(&ac);
01411     
01412     /* set notifier that keyframes have changed */
01413     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
01414     
01415     return OPERATOR_FINISHED;
01416 }
01417  
01418 void ACTION_OT_snap (wmOperatorType *ot)
01419 {
01420     /* identifiers */
01421     ot->name= "Snap Keys";
01422     ot->idname= "ACTION_OT_snap";
01423     ot->description= "Snap selected keyframes to the times specified";
01424     
01425     /* api callbacks */
01426     ot->invoke= WM_menu_invoke;
01427     ot->exec= actkeys_snap_exec;
01428     ot->poll= ED_operator_action_active;
01429     
01430     /* flags */
01431     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01432     
01433     /* id-props */
01434     ot->prop= RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
01435 }
01436 
01437 /* ******************** Mirror Keyframes Operator *********************** */
01438 
01439 /* defines for mirror keyframes tool */
01440 static EnumPropertyItem prop_actkeys_mirror_types[] = {
01441     {ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame", ""},
01442     {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
01443     {ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
01444     {0, NULL, 0, NULL, NULL}
01445 };
01446 
01447 /* this function is responsible for mirroring keyframes */
01448 static void mirror_action_keys(bAnimContext *ac, short mode) 
01449 {
01450     ListBase anim_data = {NULL, NULL};
01451     bAnimListElem *ale;
01452     int filter;
01453     
01454     KeyframeEditData ked= {{NULL}};
01455     KeyframeEditFunc edit_cb;
01456     
01457     /* get beztriple editing callbacks */
01458     edit_cb= ANIM_editkeyframes_mirror(mode);
01459 
01460     ked.scene= ac->scene;
01461     
01462     /* for 'first selected marker' mode, need to find first selected marker first! */
01463     // XXX should this be made into a helper func in the API?
01464     if (mode == ACTKEYS_MIRROR_MARKER) {
01465         TimeMarker *marker= NULL;
01466         
01467         /* find first selected marker */
01468         marker= ED_markers_get_first_selected(ac->markers);
01469         
01470         /* store marker's time (if available) */
01471         if (marker)
01472             ked.f1= (float)marker->frame;
01473         else
01474             return;
01475     }
01476     
01477     /* filter data */
01478     if (ac->datatype == ANIMCONT_GPENCIL)
01479         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
01480     else
01481         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
01482     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
01483     
01484     /* mirror keyframes */
01485     for (ale= anim_data.first; ale; ale= ale->next) {
01486         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
01487         
01488         if (adt) {
01489             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
01490             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
01491             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
01492         }
01493         //else if (ale->type == ACTTYPE_GPLAYER)
01494         //  snap_gplayer_frames(ale->data, mode);
01495         else 
01496             ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
01497     }
01498     
01499     BLI_freelistN(&anim_data);
01500 }
01501 
01502 /* ------------------- */
01503 
01504 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
01505 {
01506     bAnimContext ac;
01507     short mode;
01508     
01509     /* get editor data */
01510     if (ANIM_animdata_get_context(C, &ac) == 0)
01511         return OPERATOR_CANCELLED;
01512         
01513     // XXX...
01514     if (ac.datatype == ANIMCONT_GPENCIL)
01515         return OPERATOR_PASS_THROUGH;
01516         
01517     /* get mirroring mode */
01518     mode= RNA_enum_get(op->ptr, "type");
01519     
01520     /* mirror keyframes */
01521     mirror_action_keys(&ac, mode);
01522     
01523     /* validate keyframes after editing */
01524     ANIM_editkeyframes_refresh(&ac);
01525     
01526     /* set notifier that keyframes have changed */
01527     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
01528     
01529     return OPERATOR_FINISHED;
01530 }
01531  
01532 void ACTION_OT_mirror (wmOperatorType *ot)
01533 {
01534     /* identifiers */
01535     ot->name= "Mirror Keys";
01536     ot->idname= "ACTION_OT_mirror";
01537     ot->description= "Flip selected keyframes over the selected mirror line";
01538     
01539     /* api callbacks */
01540     ot->invoke= WM_menu_invoke;
01541     ot->exec= actkeys_mirror_exec;
01542     ot->poll= ED_operator_action_active;
01543     
01544     /* flags */
01545     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01546     
01547     /* id-props */
01548     ot->prop= RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
01549 }
01550 
01551 /* ************************************************************************** */