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